summaryrefslogtreecommitdiff
path: root/lib/prado/framework/Web
diff options
context:
space:
mode:
authoremkael <emkael@tlen.pl>2016-02-24 23:18:07 +0100
committeremkael <emkael@tlen.pl>2016-02-24 23:18:07 +0100
commit6f7fdef0f500cd4bb540affd3bc1482243f337c1 (patch)
tree4853eecd0769a903e6130c1896e1d070848150dd /lib/prado/framework/Web
parent61f2ea48a4e11cb5fb941b3783e19c9e9ef38a45 (diff)
* Prado 3.3.0
Diffstat (limited to 'lib/prado/framework/Web')
-rw-r--r--lib/prado/framework/Web/Javascripts/JSMin.php290
-rw-r--r--lib/prado/framework/Web/Javascripts/TJavaScript.php309
-rw-r--r--lib/prado/framework/Web/Javascripts/packages.php146
-rw-r--r--lib/prado/framework/Web/Javascripts/source/.htaccess16
-rw-r--r--lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap-theme.css587
-rw-r--r--lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap-theme.css.map1
-rw-r--r--lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap-theme.min.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap.css6800
-rw-r--r--lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap.css.map1
-rw-r--r--lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap.min.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.eotbin0 -> 20127 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.svg288
-rw-r--r--lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.ttfbin0 -> 45404 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.woffbin0 -> 23424 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.woff2bin0 -> 18028 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/bootstrap3/js/bootstrap.js2363
-rw-r--r--lib/prado/framework/Web/Javascripts/source/bootstrap3/js/bootstrap.min.js7
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/animated-overlay.gifbin0 -> 1738 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_flat_0_aaaaaa_40x100.pngbin0 -> 180 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_flat_75_ffffff_40x100.pngbin0 -> 178 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_55_fbf9ee_1x400.pngbin0 -> 120 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_65_ffffff_1x400.pngbin0 -> 105 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_75_dadada_1x400.pngbin0 -> 111 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_75_e6e6e6_1x400.pngbin0 -> 110 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_95_fef1ec_1x400.pngbin0 -> 119 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_highlight-soft_75_cccccc_1x100.pngbin0 -> 101 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_222222_256x240.pngbin0 -> 4369 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_2e83ff_256x240.pngbin0 -> 4369 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_454545_256x240.pngbin0 -> 4369 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_888888_256x240.pngbin0 -> 4369 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_cd0a0a_256x240.pngbin0 -> 4369 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery-ui.css7
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.accordion.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.autocomplete.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.button.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.core.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.datepicker.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.dialog.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.menu.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.progressbar.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.resizable.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.selectable.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.slider.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.spinner.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.tabs.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.theme.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.tooltip.css5
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/jquery-ui-i18n.min.js6
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/jquery-ui.js15040
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/jquery-ui.min.js12
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/jquery.js10337
-rw-r--r--lib/prado/framework/Web/Javascripts/source/jquery/jquery.min.js4
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/activecontrols/activecontrols3.js421
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/prado/activecontrols/activedatepicker.js87
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/activecontrols/ajax3.js996
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/activecontrols/autocomplete.js83
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/prado/activecontrols/dragdrop.js63
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/activecontrols/dragdropextra.js233
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/activecontrols/inlineeditor.js306
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadBlank.html1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadComplete.pngbin0 -> 663 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadError.pngbin0 -> 589 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadIndicator.gifbin0 -> 1553 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/prado/activefileupload/activefileupload.js104
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/colorpicker/background.pngbin0 -> 14501 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/colorpicker/button.gifbin0 -> 58 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/colorpicker/colorpicker.js829
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/colorpicker/default.css249
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/colorpicker/hue.gifbin0 -> 2793 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/colorpicker/slider.gifbin0 -> 81 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/prado/colorpicker/spacer.gifbin0 -> 43 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/colorpicker/target_black.gifbin0 -> 56 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/colorpicker/target_white.gifbin0 -> 56 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/controls/accordion.js109
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/controls/controls.js531
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/controls/htmlarea.js148
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/controls/htmlarea4.js58
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/controls/keyboard.js161
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/controls/slider.js235
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/controls/tabpanel.js60
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/datepicker/calendar.pngbin0 -> 775 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/datepicker/datepicker.js759
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/datepicker/default.css98
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/prado/datepicker/spacer.gifbin0 -> 43 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/logger/logger.js748
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/prado.js1238
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks.css29
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks.pngbin0 -> 29885 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_blank.gifbin0 -> 72 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_half.gifbin0 -> 94 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_hover.gifbin0 -> 75 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_selected.gifbin0 -> 75 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/ratings/default.css29
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/ratings/default_blank.gifbin0 -> 271 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/ratings/default_half.gifbin0 -> 619 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/ratings/default_hover.gifbin0 -> 618 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/ratings/default_selected.gifbin0 -> 614 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/ratings/ratings.js179
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/ratings/stars1.pngbin0 -> 53016 bytes
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/scriptaculous-adapter.js1399
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prado/validator/validation3.js1996
-rw-r--r--lib/prado/framework/Web/Javascripts/source/prototype-1.7/prototype.js7039
-rw-r--r--lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/CHANGELOG1205
-rw-r--r--lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/MIT-LICENSE20
-rw-r--r--lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/builder.js136
-rw-r--r--lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/controls.js965
-rw-r--r--lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/dragdrop.js974
-rw-r--r--lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/effects.js1123
-rw-r--r--lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/scriptaculous.js68
-rw-r--r--lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/slider.js275
-rw-r--r--lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/sound.js59
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/changelog.txt213
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ar.js156
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/bg_BG.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/bs.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ca.js118
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/cs.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/cy.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/da.js156
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/de.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/de_AT.js156
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/el.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/es.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/et.js173
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/eu.js174
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fa.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fi.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fo.js156
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fr_FR.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/gl.js156
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/he_IL.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/hr.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/hu_HU.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/id.js71
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/it.js174
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ja.js174
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ka_GE.js172
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ko_KR.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/lb.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/lt.js76
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/lv.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/nb_NO.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/nl.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/pl.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/pt_BR.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/pt_PT.js173
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ro.js174
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ru.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/si_LK.js156
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sk.js174
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sl_SI.js152
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sr.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sv_SE.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ta.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ta_IN.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/th_TH.js156
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/tr_TR.js174
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ug.js156
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/uk.js159
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/uk_UA.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/vi.js96
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/vi_VN.js173
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/zh_CN.js173
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/langs/zh_TW.js175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/license.txt504
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/advlist/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/anchor/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/autolink/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/autoresize/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/autosave/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/bbcode/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/charmap/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/code/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/editable_selects.js70
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/form_utils.js210
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/mctabs.js162
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/tiny_mce_popup.js435
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/validate.js252
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/contextmenu/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/directionality/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-cool.gifbin0 -> 354 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-cry.gifbin0 -> 329 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-embarassed.gifbin0 -> 331 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-foot-in-mouth.gifbin0 -> 342 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-frown.gifbin0 -> 340 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-innocent.gifbin0 -> 336 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-kiss.gifbin0 -> 338 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-laughing.gifbin0 -> 343 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-money-mouth.gifbin0 -> 321 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-sealed.gifbin0 -> 323 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-smile.gifbin0 -> 344 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-surprised.gifbin0 -> 338 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-tongue-out.gifbin0 -> 328 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-undecided.gifbin0 -> 337 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-wink.gifbin0 -> 350 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-yell.gifbin0 -> 336 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/example/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/example_dependency/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/fullpage/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/fullscreen/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/hr/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/image/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/importcss/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/insertdatetime/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/layer/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/legacyoutput/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/link/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/lists/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/media/moxieplayer.swfbin0 -> 20017 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/media/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/nonbreaking/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/noneditable/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/pagebreak/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/paste/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/preview/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/print/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/save/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/searchreplace/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/spellchecker/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/tabfocus/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/table/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/template/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/textcolor/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/visualblocks/css/visualblocks.css136
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/visualblocks/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/visualchars/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/wordcount/plugin.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/content.inline.min.css1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/content.min.css1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.eotbin0 -> 8344 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.svg175
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.ttfbin0 -> 8160 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.woffbin0 -> 8336 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.eotbin0 -> 8268 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.svg153
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.ttfbin0 -> 8104 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.woffbin0 -> 8400 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/readme.md1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/anchor.gifbin0 -> 53 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/loader.gifbin0 -> 2608 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/object.gifbin0 -> 152 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/trans.gifbin0 -> 43 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/wline.gifbin0 -> 46 bytes
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/skin.ie7.min.css1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/skin.min.css1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/themes/modern/theme.min.js1
-rwxr-xr-xlib/prado/framework/Web/Javascripts/source/tinymce-405/tinymce.min.js10
-rw-r--r--lib/prado/framework/Web/Services/TFeedService.php187
-rw-r--r--lib/prado/framework/Web/Services/TJsonService.php209
-rw-r--r--lib/prado/framework/Web/Services/TPageService.php890
-rw-r--r--lib/prado/framework/Web/Services/TRpcService.php722
-rw-r--r--lib/prado/framework/Web/Services/TSoapService.php622
-rw-r--r--lib/prado/framework/Web/TAssetManager.php354
-rw-r--r--lib/prado/framework/Web/TCacheHttpSession.php148
-rw-r--r--lib/prado/framework/Web/THttpRequest.php1406
-rw-r--r--lib/prado/framework/Web/THttpResponse.php722
-rw-r--r--lib/prado/framework/Web/THttpResponseAdapter.php77
-rw-r--r--lib/prado/framework/Web/THttpSession.php737
-rw-r--r--lib/prado/framework/Web/THttpUtility.php60
-rw-r--r--lib/prado/framework/Web/TUrlManager.php161
-rw-r--r--lib/prado/framework/Web/TUrlMapping.php1035
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveButton.php130
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveCheckBox.php179
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveCheckBoxList.php148
-rwxr-xr-xlib/prado/framework/Web/UI/ActiveControls/TActiveClientScript.php80
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveControlAdapter.php561
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveCustomValidator.php262
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveDataGrid.php851
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveDataList.php116
-rwxr-xr-xlib/prado/framework/Web/UI/ActiveControls/TActiveDatePicker.php198
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveDropDownList.php143
-rwxr-xr-xlib/prado/framework/Web/UI/ActiveControls/TActiveFileUpload.php461
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveHiddenField.php116
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveHyperLink.php100
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveImage.php90
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveImageButton.php154
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveLabel.php88
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveLinkButton.php159
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveListBox.php152
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveListControlAdapter.php255
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveMultiView.php112
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActivePageAdapter.php415
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActivePager.php207
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActivePanel.php98
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveRadioButton.php174
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveRadioButtonList.php145
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveRatingList.php144
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveRepeater.php133
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveTableCell.php252
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveTableRow.php270
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TActiveTextBox.php123
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TAutoComplete.php438
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TBaseActiveControl.php394
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TCallback.php99
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TCallbackClientScript.php826
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TCallbackClientSide.php320
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TCallbackEventParameter.php86
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TCallbackOptions.php51
-rwxr-xr-xlib/prado/framework/Web/UI/ActiveControls/TCallbackResponseAdapter.php159
-rwxr-xr-xlib/prado/framework/Web/UI/ActiveControls/TDraggable.php246
-rwxr-xr-xlib/prado/framework/Web/UI/ActiveControls/TDropContainer.php317
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php93
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TInPlaceTextBox.php288
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TTimeTriggeredCallback.php126
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TTriggeredCallback.php69
-rw-r--r--lib/prado/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php118
-rw-r--r--lib/prado/framework/Web/UI/JuiControls/TJuiAutoComplete.php495
-rw-r--r--lib/prado/framework/Web/UI/JuiControls/TJuiControlAdapter.php203
-rw-r--r--lib/prado/framework/Web/UI/JuiControls/TJuiControlOptions.php181
-rw-r--r--lib/prado/framework/Web/UI/JuiControls/TJuiDatePicker.php287
-rw-r--r--lib/prado/framework/Web/UI/JuiControls/TJuiDialog.php283
-rw-r--r--lib/prado/framework/Web/UI/JuiControls/TJuiDraggable.php169
-rw-r--r--lib/prado/framework/Web/UI/JuiControls/TJuiDroppable.php220
-rw-r--r--lib/prado/framework/Web/UI/JuiControls/TJuiProgressbar.php156
-rw-r--r--lib/prado/framework/Web/UI/JuiControls/TJuiResizable.php172
-rw-r--r--lib/prado/framework/Web/UI/JuiControls/TJuiSelectable.php280
-rw-r--r--lib/prado/framework/Web/UI/JuiControls/TJuiSortable.php333
-rw-r--r--lib/prado/framework/Web/UI/TCachePageStatePersister.php198
-rw-r--r--lib/prado/framework/Web/UI/TClientScriptManager.php849
-rw-r--r--lib/prado/framework/Web/UI/TCompositeControl.php36
-rw-r--r--lib/prado/framework/Web/UI/TControl.php2367
-rw-r--r--lib/prado/framework/Web/UI/TControlAdapter.php141
-rw-r--r--lib/prado/framework/Web/UI/TForm.php169
-rw-r--r--lib/prado/framework/Web/UI/THtmlWriter.php227
-rw-r--r--lib/prado/framework/Web/UI/TPage.php1318
-rw-r--r--lib/prado/framework/Web/UI/TPageStatePersister.php69
-rw-r--r--lib/prado/framework/Web/UI/TSessionPageStatePersister.php129
-rw-r--r--lib/prado/framework/Web/UI/TTemplateControl.php327
-rw-r--r--lib/prado/framework/Web/UI/TTemplateControlInheritable.php116
-rw-r--r--lib/prado/framework/Web/UI/TTemplateManager.php1096
-rw-r--r--lib/prado/framework/Web/UI/TThemeManager.php513
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TAccordion.php740
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TBaseDataList.php188
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TBaseValidator.php747
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TBoundColumn.php247
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TBulletedList.php487
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TButton.php404
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TButtonColumn.php277
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TCaptcha.php493
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TCaptchaValidator.php125
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TCheckBox.php536
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TCheckBoxColumn.php121
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TCheckBoxList.php509
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TClientScript.php155
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TColorPicker.php286
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TCompareValidator.php262
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TConditional.php141
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TContent.php45
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TContentPlaceHolder.php46
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TCustomValidator.php204
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TDataBoundControl.php582
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TDataGrid.php2244
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TDataGridColumn.php564
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TDataGridItemRenderer.php28
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TDataGridPagerStyle.php253
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TDataList.php1760
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TDataListItemRenderer.php170
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TDataRenderer.php50
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TDataSourceControl.php114
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TDataSourceView.php202
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TDataTypeValidator.php139
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TDatePicker.php978
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TDropDownList.php152
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TDropDownListColumn.php319
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TEditCommandColumn.php263
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TEmailAddressValidator.php98
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TExpression.php60
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TFileUpload.php279
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TFlushOutput.php83
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TFont.php316
-rw-r--r--lib/prado/framework/Web/UI/WebControls/THead.php372
-rw-r--r--lib/prado/framework/Web/UI/WebControls/THeader1.php34
-rw-r--r--lib/prado/framework/Web/UI/WebControls/THeader2.php34
-rw-r--r--lib/prado/framework/Web/UI/WebControls/THeader3.php34
-rw-r--r--lib/prado/framework/Web/UI/WebControls/THeader4.php34
-rw-r--r--lib/prado/framework/Web/UI/WebControls/THeader5.php34
-rw-r--r--lib/prado/framework/Web/UI/WebControls/THeader6.php34
-rw-r--r--lib/prado/framework/Web/UI/WebControls/THiddenField.php222
-rw-r--r--lib/prado/framework/Web/UI/WebControls/THtmlArea.php535
-rw-r--r--lib/prado/framework/Web/UI/WebControls/THtmlArea4.php479
-rw-r--r--lib/prado/framework/Web/UI/WebControls/THtmlElement.php66
-rw-r--r--lib/prado/framework/Web/UI/WebControls/THyperLink.php250
-rw-r--r--lib/prado/framework/Web/UI/WebControls/THyperLinkColumn.php271
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TImage.php155
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TImageButton.php438
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TImageMap.php828
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TInlineFrame.php314
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TItemDataRenderer.php81
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TJavascriptLogger.php91
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TKeyboard.php187
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TLabel.php152
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TLinkButton.php332
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TListBox.php259
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TListControl.php923
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TListControlValidator.php223
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TListItem.php182
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TLiteral.php110
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TLiteralColumn.php147
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TMarkdown.php72
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TMultiView.php374
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TOutputCache.php616
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TPager.php810
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TPanel.php239
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TPanelStyle.php274
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TPlaceHolder.php26
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TRadioButton.php304
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TRadioButtonList.php107
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TRangeValidator.php357
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TRatingList.php359
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TReCaptcha.php271
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TReCaptchaValidator.php135
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TRegularExpressionValidator.php142
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TRepeatInfo.php555
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TRepeater.php1019
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TRepeaterItemRenderer.php48
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TRequiredFieldValidator.php152
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TSafeHtml.php83
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TSlider.php570
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TStatements.php61
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TStyle.php885
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TStyleSheet.php89
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TTabPanel.php728
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TTable.php406
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TTableCell.php220
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TTableFooterRow.php45
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TTableHeaderCell.php121
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TTableHeaderRow.php45
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TTableRow.php204
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TTemplateColumn.php254
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TTextBox.php648
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TTextHighlighter.php210
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TTextProcessor.php84
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TValidationSummary.php531
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TWebControl.php498
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TWebControlAdapter.php69
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TWebControlDecorator.php382
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TWizard.php2145
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TWizardNavigationButtonStyle.php154
-rw-r--r--lib/prado/framework/Web/UI/WebControls/TXmlTransform.php193
-rwxr-xr-xlib/prado/framework/Web/UI/WebControls/assets/TSlider/TSlider.css96
-rw-r--r--lib/prado/framework/Web/UI/WebControls/assets/TSlider/TSliderHandleHorizontal.pngbin0 -> 286 bytes
-rw-r--r--lib/prado/framework/Web/UI/WebControls/assets/TSlider/TSliderHandleVertical.pngbin0 -> 249 bytes
-rw-r--r--lib/prado/framework/Web/UI/WebControls/assets/accordion.css28
-rw-r--r--lib/prado/framework/Web/UI/WebControls/assets/captcha.php223
-rw-r--r--lib/prado/framework/Web/UI/WebControls/assets/keyboard.css80
-rw-r--r--lib/prado/framework/Web/UI/WebControls/assets/tabpanel.css71
-rw-r--r--lib/prado/framework/Web/UI/WebControls/assets/verase.ttfbin0 -> 60280 bytes
448 files changed, 134312 insertions, 0 deletions
diff --git a/lib/prado/framework/Web/Javascripts/JSMin.php b/lib/prado/framework/Web/Javascripts/JSMin.php
new file mode 100644
index 0000000..95beff3
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/JSMin.php
@@ -0,0 +1,290 @@
+<?php
+/**
+ * jsmin.php - PHP implementation of Douglas Crockford's JSMin.
+ *
+ * This is pretty much a direct port of jsmin.c to PHP with just a few
+ * PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and
+ * outputs to stdout, this library accepts a string as input and returns another
+ * string as output.
+ *
+ * PHP 5 or higher is required.
+ *
+ * Permission is hereby granted to use this version of the library under the
+ * same terms as jsmin.c, which has the following license:
+ *
+ * --
+ * Copyright (c) 2002 Douglas Crockford (www.crockford.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * The Software shall be used for Good, not Evil.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * --
+ *
+ * @package JSMin
+ * @author Ryan Grove <ryan@wonko.com>
+ * @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)
+ * @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)
+ * @license http://opensource.org/licenses/mit-license.php MIT License
+ * @version 1.1.1 (2008-03-02)
+ * @link http://code.google.com/p/jsmin-php/
+ */
+
+class JSMin {
+ const ORD_LF = 10;
+ const ORD_SPACE = 32;
+
+ protected $a = '';
+ protected $b = '';
+ protected $input = '';
+ protected $inputIndex = 0;
+ protected $inputLength = 0;
+ protected $lookAhead = null;
+ protected $output = '';
+
+ // -- Public Static Methods --------------------------------------------------
+
+ public static function minify($js) {
+ $jsmin = new JSMin($js);
+ return $jsmin->min();
+ }
+
+ // -- Public Instance Methods ------------------------------------------------
+
+ public function __construct($input) {
+ $this->input = str_replace("\r\n", "\n", $input);
+ $this->inputLength = strlen($this->input);
+ }
+
+ // -- Protected Instance Methods ---------------------------------------------
+
+ protected function action($d) {
+ switch($d) {
+ case 1:
+ $this->output .= $this->a;
+
+ case 2:
+ $this->a = $this->b;
+
+ if ($this->a === "'" || $this->a === '"') {
+ for (;;) {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+
+ if ($this->a === $this->b) {
+ break;
+ }
+
+ if (ord($this->a) <= self::ORD_LF) {
+ throw new JSMinException('Unterminated string literal.');
+ }
+
+ if ($this->a === '\\') {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+ }
+ }
+ }
+
+ case 3:
+ $this->b = $this->next();
+
+ if ($this->b === '/' && (
+ $this->a === '(' || $this->a === ',' || $this->a === '=' ||
+ $this->a === ':' || $this->a === '[' || $this->a === '!' ||
+ $this->a === '&' || $this->a === '|' || $this->a === '?')) {
+
+ $this->output .= $this->a . $this->b;
+
+ for (;;) {
+ $this->a = $this->get();
+
+ if ($this->a === '/') {
+ break;
+ } elseif ($this->a === '\\') {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+ } elseif (ord($this->a) <= self::ORD_LF) {
+ throw new JSMinException('Unterminated regular expression '.
+ 'literal.');
+ }
+
+ $this->output .= $this->a;
+ }
+
+ $this->b = $this->next();
+ }
+ }
+ }
+
+ protected function get() {
+ $c = $this->lookAhead;
+ $this->lookAhead = null;
+
+ if ($c === null) {
+ if ($this->inputIndex < $this->inputLength) {
+ $c = $this->input[$this->inputIndex];
+ $this->inputIndex += 1;
+ } else {
+ $c = null;
+ }
+ }
+
+ if ($c === "\r") {
+ return "\n";
+ }
+
+ if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
+ return $c;
+ }
+
+ return ' ';
+ }
+
+ protected function isAlphaNum($c) {
+ return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
+ }
+
+ protected function min() {
+ $this->a = "\n";
+ $this->action(3);
+
+ while ($this->a !== null) {
+ switch ($this->a) {
+ case ' ':
+ if ($this->isAlphaNum($this->b)) {
+ $this->action(1);
+ } else {
+ $this->action(2);
+ }
+ break;
+
+ case "\n":
+ switch ($this->b) {
+ case '{':
+ case '[':
+ case '(':
+ case '+':
+ case '-':
+ $this->action(1);
+ break;
+
+ case ' ':
+ $this->action(3);
+ break;
+
+ default:
+ if ($this->isAlphaNum($this->b)) {
+ $this->action(1);
+ }
+ else {
+ $this->action(2);
+ }
+ }
+ break;
+
+ default:
+ switch ($this->b) {
+ case ' ':
+ if ($this->isAlphaNum($this->a)) {
+ $this->action(1);
+ break;
+ }
+
+ $this->action(3);
+ break;
+
+ case "\n":
+ switch ($this->a) {
+ case '}':
+ case ']':
+ case ')':
+ case '+':
+ case '-':
+ case '"':
+ case "'":
+ $this->action(1);
+ break;
+
+ default:
+ if ($this->isAlphaNum($this->a)) {
+ $this->action(1);
+ }
+ else {
+ $this->action(3);
+ }
+ }
+ break;
+
+ default:
+ $this->action(1);
+ break;
+ }
+ }
+ }
+
+ return $this->output;
+ }
+
+ protected function next() {
+ $c = $this->get();
+
+ if ($c === '/') {
+ switch($this->peek()) {
+ case '/':
+ for (;;) {
+ $c = $this->get();
+
+ if (ord($c) <= self::ORD_LF) {
+ return $c;
+ }
+ }
+
+ case '*':
+ $this->get();
+
+ for (;;) {
+ switch($this->get()) {
+ case '*':
+ if ($this->peek() === '/') {
+ $this->get();
+ return ' ';
+ }
+ break;
+
+ case null:
+ throw new JSMinException('Unterminated comment.');
+ }
+ }
+
+ default:
+ return $c;
+ }
+ }
+
+ return $c;
+ }
+
+ protected function peek() {
+ $this->lookAhead = $this->get();
+ return $this->lookAhead;
+ }
+}
+
+// -- Exceptions ---------------------------------------------------------------
+class JSMinException extends Exception {}
diff --git a/lib/prado/framework/Web/Javascripts/TJavaScript.php b/lib/prado/framework/Web/Javascripts/TJavaScript.php
new file mode 100644
index 0000000..b92b0c3
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/TJavaScript.php
@@ -0,0 +1,309 @@
+<?php
+/**
+ * TJavaScript class file
+ *
+ * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.Javascripts
+ */
+
+/**
+ * TJavaScript class.
+ *
+ * TJavaScript is a utility class containing commonly-used javascript-related
+ * functions.
+ *
+ * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
+ * @package System.Web.Javascripts
+ * @since 3.0
+ */
+class TJavaScript
+{
+ /**
+ * Renders a list of javascript files
+ * @param array URLs to the javascript files
+ * @return string rendering result
+ */
+ public static function renderScriptFiles($files)
+ {
+ $str='';
+ foreach($files as $file)
+ $str.= self::renderScriptFile($file);
+ return $str;
+ }
+
+ /**
+ * Renders a javascript file
+ * @param string URL to the javascript file
+ * @return string rendering result
+ */
+ public static function renderScriptFile($file)
+ {
+ return '<script type="text/javascript" src="'.THttpUtility::htmlEncode($file)."\"></script>\n";
+ }
+
+ /**
+ * Renders a list of javascript blocks
+ * @param array javascript blocks
+ * @return string rendering result
+ */
+ public static function renderScriptBlocks($scripts)
+ {
+ if(count($scripts))
+ return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n".implode("\n",$scripts)."\n/*]]>*/\n</script>\n";
+ else
+ return '';
+ }
+
+ /**
+ * Renders a list of javascript code
+ * @param array javascript blocks
+ * @return string rendering result
+ */
+ public static function renderScriptBlocksCallback($scripts)
+ {
+ if(count($scripts))
+ return implode("\n",$scripts)."\n";
+ else
+ return '';
+ }
+
+ /**
+ * Renders javascript block
+ * @param string javascript block
+ * @return string rendering result
+ */
+ public static function renderScriptBlock($script)
+ {
+ return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$script}\n/*]]>*/\n</script>\n";
+ }
+
+ /**
+ * Quotes a javascript string.
+ * After processing, the string is safely enclosed within a pair of
+ * quotation marks and can serve as a javascript string.
+ * @param string string to be quoted
+ * @return string the quoted string
+ */
+ public static function quoteString($js)
+ {
+ return self::jsonEncode($js,JSON_HEX_QUOT | JSON_HEX_APOS | JSON_HEX_TAG);
+ }
+
+ /**
+ * @return Marks a string as a javascript function. Once marke, the string is considered as a
+ * raw javascript function that is not supposed to be encoded by {@link encode}
+ */
+ public static function quoteJsLiteral($js)
+ {
+ if($js instanceof TJavaScriptLiteral)
+ return $js;
+ else
+ return new TJavaScriptLiteral($js);
+ }
+
+ /**
+ * Deprecated, use {@link quoteJsLiteral} instead
+ */
+ public static function quoteFunction($js)
+ {
+ return self::quoteJsLiteral($js);
+ }
+
+ /**
+ * @return boolean true if the parameter is marked as a javascript function, i.e. if it's considered as a
+ * raw javascript function that is not supposed to be encoded by {@link encode}
+ */
+ public static function isJsLiteral($js)
+ {
+ return ($js instanceof TJavaScriptLiteral);
+ }
+
+ /**
+ * Deprecated, use {@link isJsLiteral} instead
+ */
+ public static function isFunction($js)
+ {
+ return self::isJsLiteral($js);
+ }
+
+ /**
+ * Encodes a PHP variable into javascript representation.
+ *
+ * Example:
+ * <code>
+ * $options['onLoading'] = "doit";
+ * $options['onComplete'] = "more";
+ * echo TJavaScript::encode($options);
+ * //expects the following javascript code
+ * // {'onLoading':'doit','onComplete':'more'}
+ * </code>
+ *
+ * For higher complexity data structures use {@link jsonEncode} and {@link jsonDecode}
+ * to serialize and unserialize.
+ *
+ * @param mixed PHP variable to be encoded
+ * @param boolean whether the output is a map or a list.
+ * @since 3.1.5
+ * @param boolean wether to encode empty strings too. Default to false for BC.
+ * @return string the encoded string
+ */
+ public static function encode($value,$toMap=true,$encodeEmptyStrings=false)
+ {
+ if(is_string($value))
+ return self::quoteString($value);
+ else if(is_bool($value))
+ return $value?'true':'false';
+ else if(is_array($value))
+ {
+ $results='';
+ if(($n=count($value))>0 && array_keys($value)!==range(0,$n-1))
+ {
+ foreach($value as $k=>$v)
+ {
+ if($v!=='' || $encodeEmptyStrings)
+ {
+ if($results!=='')
+ $results.=',';
+ $results.="'$k':".self::encode($v,$toMap,$encodeEmptyStrings);
+ }
+ }
+ return '{'.$results.'}';
+ }
+ else
+ {
+ foreach($value as $v)
+ {
+ if($v!=='' || $encodeEmptyStrings)
+ {
+ if($results!=='')
+ $results.=',';
+ $results.=self::encode($v,$toMap, $encodeEmptyStrings);
+ }
+ }
+ return '['.$results.']';
+ }
+ }
+ else if(is_integer($value))
+ return "$value";
+ else if(is_float($value))
+ {
+ switch($value)
+ {
+ case -INF:
+ return 'Number.NEGATIVE_INFINITY';
+ break;
+ case INF:
+ return 'Number.POSITIVE_INFINITY';
+ break;
+ default:
+ $locale=localeConv();
+ if($locale['decimal_point']=='.')
+ return "$value";
+ else
+ return str_replace($locale['decimal_point'], '.', "$value");
+ break;
+ }
+ }
+ else if(is_object($value))
+ if ($value instanceof TJavaScriptLiteral)
+ return $value->toJavaScriptLiteral();
+ else
+ return self::encode(get_object_vars($value),$toMap);
+ else if($value===null)
+ return 'null';
+ else
+ return '';
+ }
+ /**
+ * Encodes a PHP variable into javascript string.
+ * This method invokes json_encode to perform the encoding.
+ * @param mixed variable to be encoded
+ * @return string encoded string
+ */
+ public static function jsonEncode($value, $options = 0)
+ {
+ if (($g=Prado::getApplication()->getGlobalization(false))!==null &&
+ strtoupper($enc=$g->getCharset())!='UTF-8') {
+ self::convertToUtf8($value, $enc);
+ }
+
+ $s = @json_encode($value,$options);
+ self::checkJsonError();
+ return $s;
+ }
+
+ /**
+ * Encodes an string or the content of an array to UTF8
+ * @param string|array|mixed $value
+ * @param string $sourceEncoding
+ */
+ private static function convertToUtf8(&$value, $sourceEncoding) {
+ if(is_string($value))
+ $value=iconv($sourceEncoding, 'UTF-8', $value);
+ else if (is_array($value))
+ {
+ foreach($value as &$element)
+ self::convertToUtf8($element, $sourceEncoding);
+ }
+ }
+
+ /**
+ * Decodes a javascript string into PHP variable.
+ * This method invokes json_decode to perform the decoding.
+ * @param string string to be decoded
+ * @param bool whether to convert returned objects to associative arrays
+ * @param int recursion depth
+ * @return mixed decoded variable
+ */
+ public static function jsonDecode($value, $assoc = false, $depth = 512)
+ {
+ $s= @json_decode($value, $assoc, $depth);
+ self::checkJsonError();
+ return $s;
+ }
+
+ private static function checkJsonError()
+ {
+ switch ($err = json_last_error())
+ {
+ case JSON_ERROR_NONE:
+ return;
+ break;
+ case JSON_ERROR_DEPTH:
+ $msg = 'Maximum stack depth exceeded';
+ break;
+ case JSON_ERROR_STATE_MISMATCH:
+ $msg = 'Underflow or the modes mismatch';
+ break;
+ case JSON_ERROR_CTRL_CHAR:
+ $msg = 'Unexpected control character found';
+ break;
+ case JSON_ERROR_SYNTAX:
+ $msg = 'Syntax error, malformed JSON';
+ break;
+ case JSON_ERROR_UTF8:
+ $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
+ break;
+ default:
+ $msg = 'Unknown error';
+ break;
+ }
+ throw new Exception("JSON error ($err): $msg");
+ }
+
+ /**
+ * Minimize the size of a javascript script.
+ * This method is based on Douglas Crockford's JSMin.
+ * @param string code that you want to minimzie
+ * @return minimized version of the code
+ */
+ public static function JSMin($code)
+ {
+ Prado::using('System.Web.Javascripts.JSMin');
+ return JSMin::minify($code);
+ }
+}
+
diff --git a/lib/prado/framework/Web/Javascripts/packages.php b/lib/prado/framework/Web/Javascripts/packages.php
new file mode 100644
index 0000000..fe16d97
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/packages.php
@@ -0,0 +1,146 @@
+<?php
+
+//$Id: packages.php 3319 2013-09-08 20:59:44Z ctrlaltca $
+
+// To make future upgrades easier
+if (!defined('PROTOTYPE_DIR')) define ('PROTOTYPE_DIR', 'prototype-1.7');
+if (!defined('JQUERY_DIR')) define ('JQUERY_DIR', 'jquery');
+if (!defined('BOOTSTRAP_DIR')) define ('BOOTSTRAP_DIR', 'bootstrap3');
+if (!defined('SCRIPTACULOUS_DIR')) define ('SCRIPTACULOUS_DIR', 'scriptaculous-1.9.0');
+
+//package names and its contents (files relative to the current directory)
+$packages = array(
+ // base prado scripts
+ 'prado' => array(
+ 'prado/prado.js',
+ 'prado/controls/controls.js'
+ ),
+
+ 'logger' => array(
+ 'prado/logger/logger.js',
+ ),
+
+ 'validator' => array(
+ 'prado/validator/validation3.js'
+ ),
+
+ 'datepicker' => array(
+ 'prado/datepicker/datepicker.js'
+ ),
+
+ 'colorpicker' => array(
+ 'prado/colorpicker/colorpicker.js'
+ ),
+
+ 'ajax' => array(
+ 'prado/activecontrols/ajax3.js',
+ 'prado/activecontrols/activecontrols3.js',
+ ),
+
+ 'slider'=>array(
+ 'prado/controls/slider.js'
+ ),
+
+ 'keyboard'=>array(
+ 'prado/controls/keyboard.js'
+ ),
+
+ 'tabpanel'=>array(
+ 'prado/controls/tabpanel.js'
+ ),
+
+ 'activedatepicker' => array(
+ 'prado/activecontrols/activedatepicker.js'
+ ),
+
+ 'activefileupload' => array(
+ 'prado/activefileupload/activefileupload.js'
+ ),
+
+ 'htmlarea'=>array(
+ 'prado/controls/htmlarea.js'
+ ),
+
+ 'htmlarea4'=>array(
+ 'prado/controls/htmlarea4.js'
+ ),
+
+ 'accordion'=>array(
+ 'prado/controls/accordion.js'
+ ),
+
+ 'inlineeditor' => array(
+ 'prado/activecontrols/inlineeditor.js'
+ ),
+
+ 'ratings' => array(
+ 'prado/ratings/ratings.js',
+ ),
+
+ // jquery
+ 'jquery' => array(
+ JQUERY_DIR.'/jquery.js',
+ ),
+ 'jqueryui' => array(
+ JQUERY_DIR.'/jquery-ui.js',
+ JQUERY_DIR.'/jquery-ui-i18n.min.js',
+ ),
+
+ // prototype + scriptaculous
+ 'prototype' => array(
+ PROTOTYPE_DIR.'/prototype.js',
+ SCRIPTACULOUS_DIR.'/builder.js',
+ SCRIPTACULOUS_DIR.'/effects.js'
+ ),
+
+ //bootstrap
+ 'bootstrap' => array(
+ BOOTSTRAP_DIR.'/js/bootstrap.js',
+ ),
+
+ 'dragdrop'=>array(
+ SCRIPTACULOUS_DIR.'/dragdrop.js',
+ 'prado/activecontrols/dragdrop.js'
+ ),
+
+ 'dragdropextra'=>array(
+ 'prado/activecontrols/dragdropextra.js',
+ ),
+
+ 'autocomplete' => array(
+ SCRIPTACULOUS_DIR.'/controls.js',
+ 'prado/activecontrols/autocomplete.js'
+ ),
+);
+
+
+//package names and their dependencies
+$dependencies = array(
+ 'jquery' => array('jquery'),
+ 'prado' => array('jquery', 'prado'),
+ 'bootstrap' => array('jquery', 'bootstrap'),
+ 'validator' => array('jquery', 'prado', 'validator'),
+ 'tabpanel' => array('jquery', 'prado', 'tabpanel'),
+ 'ajax' => array('jquery', 'prado', 'ajax'),
+ 'logger' => array('jquery', 'prado', 'logger'),
+ 'activefileupload' => array('jquery', 'prado', 'ajax', 'activefileupload'),
+ 'effects' => array('jquery', 'jqueryui'),
+ 'datepicker' => array('jquery', 'prado', 'datepicker'),
+ 'activedatepicker' => array('jquery', 'prado', 'datepicker', 'ajax', 'activedatepicker'),
+ 'colorpicker' => array('jquery', 'prado', 'colorpicker'),
+ 'htmlarea' => array('jquery', 'prado', 'htmlarea'),
+ 'htmlarea4' => array('jquery', 'prado', 'htmlarea4'),
+ 'keyboard' => array('jquery', 'prado', 'keyboard'),
+ 'slider' => array('jquery', 'prado', 'slider'),
+ 'inlineeditor' => array('jquery', 'prado', 'ajax', 'inlineeditor'),
+ 'accordion' => array('jquery', 'prado', 'accordion'),
+ 'ratings' => array('jquery', 'prado', 'ajax', 'ratings'),
+ 'jqueryui' => array('jquery', 'jqueryui'),
+ 'prototype' => array('prototype'),
+ 'dragdrop' => array('prototype', 'jquery', 'prado', 'ajax', 'dragdrop'),
+ 'dragdropextra' => array('prototype', 'jquery', 'prado', 'ajax', 'dragdrop','dragdropextra'),
+ 'autocomplete' => array('prototype', 'jquery', 'prado', 'ajax', 'autocomplete'),
+);
+
+return array($packages, $dependencies);
+
diff --git a/lib/prado/framework/Web/Javascripts/source/.htaccess b/lib/prado/framework/Web/Javascripts/source/.htaccess
new file mode 100644
index 0000000..9ec9634
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/.htaccess
@@ -0,0 +1,16 @@
+<ifModule mod_gzip.c>
+ mod_gzip_on Yes
+ mod_gzip_dechunk Yes
+ mod_gzip_item_include file \.js$
+ mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
+</ifModule>
+
+<ifModule mod_expires.c>
+ ExpiresActive On
+ ExpiresDefault "access plus 864000 seconds"
+</ifModule>
+
+<ifModule mod_headers.c>
+ Header set Cache-Control "max-age=864000, private"
+</ifModule>
+
diff --git a/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap-theme.css b/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap-theme.css
new file mode 100644
index 0000000..c19cd5c
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap-theme.css
@@ -0,0 +1,587 @@
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+.btn-default,
+.btn-primary,
+.btn-success,
+.btn-info,
+.btn-warning,
+.btn-danger {
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+}
+.btn-default:active,
+.btn-primary:active,
+.btn-success:active,
+.btn-info:active,
+.btn-warning:active,
+.btn-danger:active,
+.btn-default.active,
+.btn-primary.active,
+.btn-success.active,
+.btn-info.active,
+.btn-warning.active,
+.btn-danger.active {
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn-default.disabled,
+.btn-primary.disabled,
+.btn-success.disabled,
+.btn-info.disabled,
+.btn-warning.disabled,
+.btn-danger.disabled,
+.btn-default[disabled],
+.btn-primary[disabled],
+.btn-success[disabled],
+.btn-info[disabled],
+.btn-warning[disabled],
+.btn-danger[disabled],
+fieldset[disabled] .btn-default,
+fieldset[disabled] .btn-primary,
+fieldset[disabled] .btn-success,
+fieldset[disabled] .btn-info,
+fieldset[disabled] .btn-warning,
+fieldset[disabled] .btn-danger {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.btn-default .badge,
+.btn-primary .badge,
+.btn-success .badge,
+.btn-info .badge,
+.btn-warning .badge,
+.btn-danger .badge {
+ text-shadow: none;
+}
+.btn:active,
+.btn.active {
+ background-image: none;
+}
+.btn-default {
+ text-shadow: 0 1px 0 #fff;
+ background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+ background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
+ background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #dbdbdb;
+ border-color: #ccc;
+}
+.btn-default:hover,
+.btn-default:focus {
+ background-color: #e0e0e0;
+ background-position: 0 -15px;
+}
+.btn-default:active,
+.btn-default.active {
+ background-color: #e0e0e0;
+ border-color: #dbdbdb;
+}
+.btn-default.disabled,
+.btn-default[disabled],
+fieldset[disabled] .btn-default,
+.btn-default.disabled:hover,
+.btn-default[disabled]:hover,
+fieldset[disabled] .btn-default:hover,
+.btn-default.disabled:focus,
+.btn-default[disabled]:focus,
+fieldset[disabled] .btn-default:focus,
+.btn-default.disabled.focus,
+.btn-default[disabled].focus,
+fieldset[disabled] .btn-default.focus,
+.btn-default.disabled:active,
+.btn-default[disabled]:active,
+fieldset[disabled] .btn-default:active,
+.btn-default.disabled.active,
+.btn-default[disabled].active,
+fieldset[disabled] .btn-default.active {
+ background-color: #e0e0e0;
+ background-image: none;
+}
+.btn-primary {
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #245580;
+}
+.btn-primary:hover,
+.btn-primary:focus {
+ background-color: #265a88;
+ background-position: 0 -15px;
+}
+.btn-primary:active,
+.btn-primary.active {
+ background-color: #265a88;
+ border-color: #245580;
+}
+.btn-primary.disabled,
+.btn-primary[disabled],
+fieldset[disabled] .btn-primary,
+.btn-primary.disabled:hover,
+.btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover,
+.btn-primary.disabled:focus,
+.btn-primary[disabled]:focus,
+fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus,
+.btn-primary[disabled].focus,
+fieldset[disabled] .btn-primary.focus,
+.btn-primary.disabled:active,
+.btn-primary[disabled]:active,
+fieldset[disabled] .btn-primary:active,
+.btn-primary.disabled.active,
+.btn-primary[disabled].active,
+fieldset[disabled] .btn-primary.active {
+ background-color: #265a88;
+ background-image: none;
+}
+.btn-success {
+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
+ background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #3e8f3e;
+}
+.btn-success:hover,
+.btn-success:focus {
+ background-color: #419641;
+ background-position: 0 -15px;
+}
+.btn-success:active,
+.btn-success.active {
+ background-color: #419641;
+ border-color: #3e8f3e;
+}
+.btn-success.disabled,
+.btn-success[disabled],
+fieldset[disabled] .btn-success,
+.btn-success.disabled:hover,
+.btn-success[disabled]:hover,
+fieldset[disabled] .btn-success:hover,
+.btn-success.disabled:focus,
+.btn-success[disabled]:focus,
+fieldset[disabled] .btn-success:focus,
+.btn-success.disabled.focus,
+.btn-success[disabled].focus,
+fieldset[disabled] .btn-success.focus,
+.btn-success.disabled:active,
+.btn-success[disabled]:active,
+fieldset[disabled] .btn-success:active,
+.btn-success.disabled.active,
+.btn-success[disabled].active,
+fieldset[disabled] .btn-success.active {
+ background-color: #419641;
+ background-image: none;
+}
+.btn-info {
+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
+ background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #28a4c9;
+}
+.btn-info:hover,
+.btn-info:focus {
+ background-color: #2aabd2;
+ background-position: 0 -15px;
+}
+.btn-info:active,
+.btn-info.active {
+ background-color: #2aabd2;
+ border-color: #28a4c9;
+}
+.btn-info.disabled,
+.btn-info[disabled],
+fieldset[disabled] .btn-info,
+.btn-info.disabled:hover,
+.btn-info[disabled]:hover,
+fieldset[disabled] .btn-info:hover,
+.btn-info.disabled:focus,
+.btn-info[disabled]:focus,
+fieldset[disabled] .btn-info:focus,
+.btn-info.disabled.focus,
+.btn-info[disabled].focus,
+fieldset[disabled] .btn-info.focus,
+.btn-info.disabled:active,
+.btn-info[disabled]:active,
+fieldset[disabled] .btn-info:active,
+.btn-info.disabled.active,
+.btn-info[disabled].active,
+fieldset[disabled] .btn-info.active {
+ background-color: #2aabd2;
+ background-image: none;
+}
+.btn-warning {
+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
+ background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #e38d13;
+}
+.btn-warning:hover,
+.btn-warning:focus {
+ background-color: #eb9316;
+ background-position: 0 -15px;
+}
+.btn-warning:active,
+.btn-warning.active {
+ background-color: #eb9316;
+ border-color: #e38d13;
+}
+.btn-warning.disabled,
+.btn-warning[disabled],
+fieldset[disabled] .btn-warning,
+.btn-warning.disabled:hover,
+.btn-warning[disabled]:hover,
+fieldset[disabled] .btn-warning:hover,
+.btn-warning.disabled:focus,
+.btn-warning[disabled]:focus,
+fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled.focus,
+.btn-warning[disabled].focus,
+fieldset[disabled] .btn-warning.focus,
+.btn-warning.disabled:active,
+.btn-warning[disabled]:active,
+fieldset[disabled] .btn-warning:active,
+.btn-warning.disabled.active,
+.btn-warning[disabled].active,
+fieldset[disabled] .btn-warning.active {
+ background-color: #eb9316;
+ background-image: none;
+}
+.btn-danger {
+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
+ background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #b92c28;
+}
+.btn-danger:hover,
+.btn-danger:focus {
+ background-color: #c12e2a;
+ background-position: 0 -15px;
+}
+.btn-danger:active,
+.btn-danger.active {
+ background-color: #c12e2a;
+ border-color: #b92c28;
+}
+.btn-danger.disabled,
+.btn-danger[disabled],
+fieldset[disabled] .btn-danger,
+.btn-danger.disabled:hover,
+.btn-danger[disabled]:hover,
+fieldset[disabled] .btn-danger:hover,
+.btn-danger.disabled:focus,
+.btn-danger[disabled]:focus,
+fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled.focus,
+.btn-danger[disabled].focus,
+fieldset[disabled] .btn-danger.focus,
+.btn-danger.disabled:active,
+.btn-danger[disabled]:active,
+fieldset[disabled] .btn-danger:active,
+.btn-danger.disabled.active,
+.btn-danger[disabled].active,
+fieldset[disabled] .btn-danger.active {
+ background-color: #c12e2a;
+ background-image: none;
+}
+.thumbnail,
+.img-thumbnail {
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+ background-color: #e8e8e8;
+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+ background-repeat: repeat-x;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+ background-color: #2e6da4;
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+ background-repeat: repeat-x;
+}
+.navbar-default {
+ background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+ background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
+ background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .active > a {
+ background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
+ background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
+ background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
+ background-repeat: repeat-x;
+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+}
+.navbar-brand,
+.navbar-nav > li > a {
+ text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
+}
+.navbar-inverse {
+ background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
+ background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
+ background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-radius: 4px;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .active > a {
+ background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
+ background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
+ background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
+ background-repeat: repeat-x;
+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+}
+.navbar-inverse .navbar-brand,
+.navbar-inverse .navbar-nav > li > a {
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
+}
+.navbar-static-top,
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ border-radius: 0;
+}
+@media (max-width: 767px) {
+ .navbar .navbar-nav .open .dropdown-menu > .active > a,
+ .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
+ .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
+ color: #fff;
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+ background-repeat: repeat-x;
+ }
+}
+.alert {
+ text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+}
+.alert-success {
+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
+ background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #b2dba1;
+}
+.alert-info {
+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
+ background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #9acfea;
+}
+.alert-warning {
+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
+ background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #f5e79e;
+}
+.alert-danger {
+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
+ background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
+ background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #dca7a7;
+}
+.progress {
+ background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+ background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
+ background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar {
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-success {
+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
+ background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-info {
+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
+ background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-warning {
+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
+ background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-danger {
+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
+ background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-striped {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.list-group {
+ border-radius: 4px;
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+ text-shadow: 0 -1px 0 #286090;
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #2b669a;
+}
+.list-group-item.active .badge,
+.list-group-item.active:hover .badge,
+.list-group-item.active:focus .badge {
+ text-shadow: none;
+}
+.panel {
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+}
+.panel-default > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-primary > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-success > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
+ background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-info > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
+ background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-warning > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
+ background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-danger > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
+ background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
+ background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
+ background-repeat: repeat-x;
+}
+.well {
+ background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+ background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
+ background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #dcdcdc;
+ -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+}
+/*# sourceMappingURL=bootstrap-theme.css.map */
diff --git a/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap-theme.css.map b/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap-theme.css.map
new file mode 100644
index 0000000..7535311
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap-theme.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["bootstrap-theme.css","less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"AAAA;;;;GAIG;ACeH;;;;;;EAME,yCAAA;EC2CA,4FAAA;EACQ,oFAAA;CFvDT;ACgBC;;;;;;;;;;;;ECsCA,yDAAA;EACQ,iDAAA;CFxCT;ACMC;;;;;;;;;;;;;;;;;;ECiCA,yBAAA;EACQ,iBAAA;CFnBT;AC/BD;;;;;;EAuBI,kBAAA;CDgBH;ACyBC;;EAEE,uBAAA;CDvBH;AC4BD;EErEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;EAuC2C,0BAAA;EAA2B,mBAAA;CDjBvE;ACpBC;;EAEE,0BAAA;EACA,6BAAA;CDsBH;ACnBC;;EAEE,0BAAA;EACA,sBAAA;CDqBH;ACfG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CD6BL;ACbD;EEtEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CD8DD;AC5DC;;EAEE,0BAAA;EACA,6BAAA;CD8DH;AC3DC;;EAEE,0BAAA;EACA,sBAAA;CD6DH;ACvDG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CDqEL;ACpDD;EEvEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CDsGD;ACpGC;;EAEE,0BAAA;EACA,6BAAA;CDsGH;ACnGC;;EAEE,0BAAA;EACA,sBAAA;CDqGH;AC/FG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CD6GL;AC3FD;EExEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CD8ID;AC5IC;;EAEE,0BAAA;EACA,6BAAA;CD8IH;AC3IC;;EAEE,0BAAA;EACA,sBAAA;CD6IH;ACvIG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CDqJL;AClID;EEzEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CDsLD;ACpLC;;EAEE,0BAAA;EACA,6BAAA;CDsLH;ACnLC;;EAEE,0BAAA;EACA,sBAAA;CDqLH;AC/KG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CD6LL;ACzKD;EE1EI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CD8ND;AC5NC;;EAEE,0BAAA;EACA,6BAAA;CD8NH;AC3NC;;EAEE,0BAAA;EACA,sBAAA;CD6NH;ACvNG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CDqOL;AC1MD;;EClCE,mDAAA;EACQ,2CAAA;CFgPT;ACrMD;;EE3FI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF0FF,0BAAA;CD2MD;ACzMD;;;EEhGI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EFgGF,0BAAA;CD+MD;ACtMD;EE7GI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ECnBF,oEAAA;EH+HA,mBAAA;ECjEA,4FAAA;EACQ,oFAAA;CF8QT;ACjND;;EE7GI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ED2CF,yDAAA;EACQ,iDAAA;CFwRT;AC9MD;;EAEE,+CAAA;CDgND;AC5MD;EEhII,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ECnBF,oEAAA;EHkJA,mBAAA;CDkND;ACrND;;EEhII,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ED2CF,wDAAA;EACQ,gDAAA;CF+ST;AC/ND;;EAYI,0CAAA;CDuNH;AClND;;;EAGE,iBAAA;CDoND;AC/LD;EAfI;;;IAGE,YAAA;IE7JF,yEAAA;IACA,oEAAA;IACA,8FAAA;IAAA,uEAAA;IACA,4BAAA;IACA,uHAAA;GH+WD;CACF;AC3MD;EACE,8CAAA;EC3HA,2FAAA;EACQ,mFAAA;CFyUT;ACnMD;EEtLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CD+MD;AC1MD;EEvLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CDuND;ACjND;EExLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CD+ND;ACxND;EEzLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CDuOD;ACxND;EEjMI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH4ZH;ACrND;EE3MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHmaH;AC3ND;EE5MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH0aH;ACjOD;EE7MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHibH;ACvOD;EE9MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHwbH;AC7OD;EE/MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH+bH;AChPD;EElLI,8MAAA;EACA,yMAAA;EACA,sMAAA;CHqaH;AC5OD;EACE,mBAAA;EC9KA,mDAAA;EACQ,2CAAA;CF6ZT;AC7OD;;;EAGE,8BAAA;EEnOE,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EFiOF,sBAAA;CDmPD;ACxPD;;;EAQI,kBAAA;CDqPH;AC3OD;ECnME,kDAAA;EACQ,0CAAA;CFibT;ACrOD;EE5PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHoeH;AC3OD;EE7PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH2eH;ACjPD;EE9PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHkfH;ACvPD;EE/PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHyfH;AC7PD;EEhQI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHggBH;ACnQD;EEjQI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHugBH;ACnQD;EExQI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EFsQF,sBAAA;EC3NA,0FAAA;EACQ,kFAAA;CFqeT","file":"bootstrap-theme.css","sourcesContent":["/*!\n * Bootstrap v3.3.5 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-default.disabled,\n.btn-primary.disabled,\n.btn-success.disabled,\n.btn-info.disabled,\n.btn-warning.disabled,\n.btn-danger.disabled,\n.btn-default[disabled],\n.btn-primary[disabled],\n.btn-success[disabled],\n.btn-info[disabled],\n.btn-warning[disabled],\n.btn-danger[disabled],\nfieldset[disabled] .btn-default,\nfieldset[disabled] .btn-primary,\nfieldset[disabled] .btn-success,\nfieldset[disabled] .btn-info,\nfieldset[disabled] .btn-warning,\nfieldset[disabled] .btn-danger {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n text-shadow: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n}\n.btn-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #dbdbdb;\n text-shadow: 0 1px 0 #fff;\n border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n background-color: #e0e0e0;\n background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n background-color: #e0e0e0;\n border-color: #dbdbdb;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n background-color: #e0e0e0;\n background-image: none;\n}\n.btn-primary {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #245580;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n background-color: #265a88;\n background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n background-color: #265a88;\n border-color: #245580;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n background-color: #265a88;\n background-image: none;\n}\n.btn-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #3e8f3e;\n}\n.btn-success:hover,\n.btn-success:focus {\n background-color: #419641;\n background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n background-color: #419641;\n border-color: #3e8f3e;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n background-color: #419641;\n background-image: none;\n}\n.btn-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #28a4c9;\n}\n.btn-info:hover,\n.btn-info:focus {\n background-color: #2aabd2;\n background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n background-color: #2aabd2;\n border-color: #28a4c9;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n background-color: #2aabd2;\n background-image: none;\n}\n.btn-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #e38d13;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n background-color: #eb9316;\n background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n background-color: #eb9316;\n border-color: #e38d13;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n background-color: #eb9316;\n background-image: none;\n}\n.btn-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #b92c28;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n background-color: #c12e2a;\n background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n background-color: #c12e2a;\n border-color: #b92c28;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n background-color: #c12e2a;\n background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n background-color: #e8e8e8;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n background-color: #2e6da4;\n}\n.navbar-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);\n}\n.navbar-inverse {\n background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%);\n background-image: -o-linear-gradient(top, #3c3c3c 0%, #222222 100%);\n background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n@media (max-width: 767px) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n }\n}\n.alert {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.alert-success {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);\n border-color: #b2dba1;\n}\n.alert-info {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);\n border-color: #9acfea;\n}\n.alert-warning {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);\n border-color: #f5e79e;\n}\n.alert-danger {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);\n border-color: #dca7a7;\n}\n.progress {\n background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n}\n.progress-bar {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);\n}\n.progress-bar-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);\n}\n.progress-bar-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);\n}\n.progress-bar-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);\n}\n.progress-bar-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);\n}\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.list-group {\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 #286090;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);\n border-color: #2b669a;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n text-shadow: none;\n}\n.panel {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.panel-default > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n}\n.panel-primary > .panel-heading {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n}\n.panel-success > .panel-heading {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);\n}\n.panel-info > .panel-heading {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);\n}\n.panel-warning > .panel-heading {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);\n}\n.panel-danger > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);\n}\n.well {\n background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n border-color: #dcdcdc;\n -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */","/*!\n * Bootstrap v3.3.5 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n .box-shadow(none);\n }\n\n .badge {\n text-shadow: none;\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n border-radius: @navbar-border-radius;\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: #fff;\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n }\n }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n\n .badge {\n text-shadow: none;\n }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap-theme.min.css b/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap-theme.min.css
new file mode 100644
index 0000000..61358b1
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap-theme.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap.css b/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap.css
new file mode 100644
index 0000000..680e768
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap.css
@@ -0,0 +1,6800 @@
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+html {
+ font-family: sans-serif;
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+}
+body {
+ margin: 0;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+ display: block;
+}
+audio,
+canvas,
+progress,
+video {
+ display: inline-block;
+ vertical-align: baseline;
+}
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+[hidden],
+template {
+ display: none;
+}
+a {
+ background-color: transparent;
+}
+a:active,
+a:hover {
+ outline: 0;
+}
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+b,
+strong {
+ font-weight: bold;
+}
+dfn {
+ font-style: italic;
+}
+h1 {
+ margin: .67em 0;
+ font-size: 2em;
+}
+mark {
+ color: #000;
+ background: #ff0;
+}
+small {
+ font-size: 80%;
+}
+sub,
+sup {
+ position: relative;
+ font-size: 75%;
+ line-height: 0;
+ vertical-align: baseline;
+}
+sup {
+ top: -.5em;
+}
+sub {
+ bottom: -.25em;
+}
+img {
+ border: 0;
+}
+svg:not(:root) {
+ overflow: hidden;
+}
+figure {
+ margin: 1em 40px;
+}
+hr {
+ height: 0;
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+pre {
+ overflow: auto;
+}
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, monospace;
+ font-size: 1em;
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+ margin: 0;
+ font: inherit;
+ color: inherit;
+}
+button {
+ overflow: visible;
+}
+button,
+select {
+ text-transform: none;
+}
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button;
+ cursor: pointer;
+}
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+input {
+ line-height: normal;
+}
+input[type="checkbox"],
+input[type="radio"] {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 0;
+}
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+input[type="search"] {
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ -webkit-appearance: textfield;
+}
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+fieldset {
+ padding: .35em .625em .75em;
+ margin: 0 2px;
+ border: 1px solid #c0c0c0;
+}
+legend {
+ padding: 0;
+ border: 0;
+}
+textarea {
+ overflow: auto;
+}
+optgroup {
+ font-weight: bold;
+}
+table {
+ border-spacing: 0;
+ border-collapse: collapse;
+}
+td,
+th {
+ padding: 0;
+}
+/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
+@media print {
+ *,
+ *:before,
+ *:after {
+ color: #000 !important;
+ text-shadow: none !important;
+ background: transparent !important;
+ -webkit-box-shadow: none !important;
+ box-shadow: none !important;
+ }
+ a,
+ a:visited {
+ text-decoration: underline;
+ }
+ a[href]:after {
+ content: " (" attr(href) ")";
+ }
+ abbr[title]:after {
+ content: " (" attr(title) ")";
+ }
+ a[href^="#"]:after,
+ a[href^="javascript:"]:after {
+ content: "";
+ }
+ pre,
+ blockquote {
+ border: 1px solid #999;
+
+ page-break-inside: avoid;
+ }
+ thead {
+ display: table-header-group;
+ }
+ tr,
+ img {
+ page-break-inside: avoid;
+ }
+ img {
+ max-width: 100% !important;
+ }
+ p,
+ h2,
+ h3 {
+ orphans: 3;
+ widows: 3;
+ }
+ h2,
+ h3 {
+ page-break-after: avoid;
+ }
+ .navbar {
+ display: none;
+ }
+ .btn > .caret,
+ .dropup > .btn > .caret {
+ border-top-color: #000 !important;
+ }
+ .label {
+ border: 1px solid #000;
+ }
+ .table {
+ border-collapse: collapse !important;
+ }
+ .table td,
+ .table th {
+ background-color: #fff !important;
+ }
+ .table-bordered th,
+ .table-bordered td {
+ border: 1px solid #ddd !important;
+ }
+}
+@font-face {
+ font-family: 'Glyphicons Halflings';
+
+ src: url('../fonts/glyphicons-halflings-regular.eot');
+ src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
+}
+.glyphicon {
+ position: relative;
+ top: 1px;
+ display: inline-block;
+ font-family: 'Glyphicons Halflings';
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+.glyphicon-asterisk:before {
+ content: "\2a";
+}
+.glyphicon-plus:before {
+ content: "\2b";
+}
+.glyphicon-euro:before,
+.glyphicon-eur:before {
+ content: "\20ac";
+}
+.glyphicon-minus:before {
+ content: "\2212";
+}
+.glyphicon-cloud:before {
+ content: "\2601";
+}
+.glyphicon-envelope:before {
+ content: "\2709";
+}
+.glyphicon-pencil:before {
+ content: "\270f";
+}
+.glyphicon-glass:before {
+ content: "\e001";
+}
+.glyphicon-music:before {
+ content: "\e002";
+}
+.glyphicon-search:before {
+ content: "\e003";
+}
+.glyphicon-heart:before {
+ content: "\e005";
+}
+.glyphicon-star:before {
+ content: "\e006";
+}
+.glyphicon-star-empty:before {
+ content: "\e007";
+}
+.glyphicon-user:before {
+ content: "\e008";
+}
+.glyphicon-film:before {
+ content: "\e009";
+}
+.glyphicon-th-large:before {
+ content: "\e010";
+}
+.glyphicon-th:before {
+ content: "\e011";
+}
+.glyphicon-th-list:before {
+ content: "\e012";
+}
+.glyphicon-ok:before {
+ content: "\e013";
+}
+.glyphicon-remove:before {
+ content: "\e014";
+}
+.glyphicon-zoom-in:before {
+ content: "\e015";
+}
+.glyphicon-zoom-out:before {
+ content: "\e016";
+}
+.glyphicon-off:before {
+ content: "\e017";
+}
+.glyphicon-signal:before {
+ content: "\e018";
+}
+.glyphicon-cog:before {
+ content: "\e019";
+}
+.glyphicon-trash:before {
+ content: "\e020";
+}
+.glyphicon-home:before {
+ content: "\e021";
+}
+.glyphicon-file:before {
+ content: "\e022";
+}
+.glyphicon-time:before {
+ content: "\e023";
+}
+.glyphicon-road:before {
+ content: "\e024";
+}
+.glyphicon-download-alt:before {
+ content: "\e025";
+}
+.glyphicon-download:before {
+ content: "\e026";
+}
+.glyphicon-upload:before {
+ content: "\e027";
+}
+.glyphicon-inbox:before {
+ content: "\e028";
+}
+.glyphicon-play-circle:before {
+ content: "\e029";
+}
+.glyphicon-repeat:before {
+ content: "\e030";
+}
+.glyphicon-refresh:before {
+ content: "\e031";
+}
+.glyphicon-list-alt:before {
+ content: "\e032";
+}
+.glyphicon-lock:before {
+ content: "\e033";
+}
+.glyphicon-flag:before {
+ content: "\e034";
+}
+.glyphicon-headphones:before {
+ content: "\e035";
+}
+.glyphicon-volume-off:before {
+ content: "\e036";
+}
+.glyphicon-volume-down:before {
+ content: "\e037";
+}
+.glyphicon-volume-up:before {
+ content: "\e038";
+}
+.glyphicon-qrcode:before {
+ content: "\e039";
+}
+.glyphicon-barcode:before {
+ content: "\e040";
+}
+.glyphicon-tag:before {
+ content: "\e041";
+}
+.glyphicon-tags:before {
+ content: "\e042";
+}
+.glyphicon-book:before {
+ content: "\e043";
+}
+.glyphicon-bookmark:before {
+ content: "\e044";
+}
+.glyphicon-print:before {
+ content: "\e045";
+}
+.glyphicon-camera:before {
+ content: "\e046";
+}
+.glyphicon-font:before {
+ content: "\e047";
+}
+.glyphicon-bold:before {
+ content: "\e048";
+}
+.glyphicon-italic:before {
+ content: "\e049";
+}
+.glyphicon-text-height:before {
+ content: "\e050";
+}
+.glyphicon-text-width:before {
+ content: "\e051";
+}
+.glyphicon-align-left:before {
+ content: "\e052";
+}
+.glyphicon-align-center:before {
+ content: "\e053";
+}
+.glyphicon-align-right:before {
+ content: "\e054";
+}
+.glyphicon-align-justify:before {
+ content: "\e055";
+}
+.glyphicon-list:before {
+ content: "\e056";
+}
+.glyphicon-indent-left:before {
+ content: "\e057";
+}
+.glyphicon-indent-right:before {
+ content: "\e058";
+}
+.glyphicon-facetime-video:before {
+ content: "\e059";
+}
+.glyphicon-picture:before {
+ content: "\e060";
+}
+.glyphicon-map-marker:before {
+ content: "\e062";
+}
+.glyphicon-adjust:before {
+ content: "\e063";
+}
+.glyphicon-tint:before {
+ content: "\e064";
+}
+.glyphicon-edit:before {
+ content: "\e065";
+}
+.glyphicon-share:before {
+ content: "\e066";
+}
+.glyphicon-check:before {
+ content: "\e067";
+}
+.glyphicon-move:before {
+ content: "\e068";
+}
+.glyphicon-step-backward:before {
+ content: "\e069";
+}
+.glyphicon-fast-backward:before {
+ content: "\e070";
+}
+.glyphicon-backward:before {
+ content: "\e071";
+}
+.glyphicon-play:before {
+ content: "\e072";
+}
+.glyphicon-pause:before {
+ content: "\e073";
+}
+.glyphicon-stop:before {
+ content: "\e074";
+}
+.glyphicon-forward:before {
+ content: "\e075";
+}
+.glyphicon-fast-forward:before {
+ content: "\e076";
+}
+.glyphicon-step-forward:before {
+ content: "\e077";
+}
+.glyphicon-eject:before {
+ content: "\e078";
+}
+.glyphicon-chevron-left:before {
+ content: "\e079";
+}
+.glyphicon-chevron-right:before {
+ content: "\e080";
+}
+.glyphicon-plus-sign:before {
+ content: "\e081";
+}
+.glyphicon-minus-sign:before {
+ content: "\e082";
+}
+.glyphicon-remove-sign:before {
+ content: "\e083";
+}
+.glyphicon-ok-sign:before {
+ content: "\e084";
+}
+.glyphicon-question-sign:before {
+ content: "\e085";
+}
+.glyphicon-info-sign:before {
+ content: "\e086";
+}
+.glyphicon-screenshot:before {
+ content: "\e087";
+}
+.glyphicon-remove-circle:before {
+ content: "\e088";
+}
+.glyphicon-ok-circle:before {
+ content: "\e089";
+}
+.glyphicon-ban-circle:before {
+ content: "\e090";
+}
+.glyphicon-arrow-left:before {
+ content: "\e091";
+}
+.glyphicon-arrow-right:before {
+ content: "\e092";
+}
+.glyphicon-arrow-up:before {
+ content: "\e093";
+}
+.glyphicon-arrow-down:before {
+ content: "\e094";
+}
+.glyphicon-share-alt:before {
+ content: "\e095";
+}
+.glyphicon-resize-full:before {
+ content: "\e096";
+}
+.glyphicon-resize-small:before {
+ content: "\e097";
+}
+.glyphicon-exclamation-sign:before {
+ content: "\e101";
+}
+.glyphicon-gift:before {
+ content: "\e102";
+}
+.glyphicon-leaf:before {
+ content: "\e103";
+}
+.glyphicon-fire:before {
+ content: "\e104";
+}
+.glyphicon-eye-open:before {
+ content: "\e105";
+}
+.glyphicon-eye-close:before {
+ content: "\e106";
+}
+.glyphicon-warning-sign:before {
+ content: "\e107";
+}
+.glyphicon-plane:before {
+ content: "\e108";
+}
+.glyphicon-calendar:before {
+ content: "\e109";
+}
+.glyphicon-random:before {
+ content: "\e110";
+}
+.glyphicon-comment:before {
+ content: "\e111";
+}
+.glyphicon-magnet:before {
+ content: "\e112";
+}
+.glyphicon-chevron-up:before {
+ content: "\e113";
+}
+.glyphicon-chevron-down:before {
+ content: "\e114";
+}
+.glyphicon-retweet:before {
+ content: "\e115";
+}
+.glyphicon-shopping-cart:before {
+ content: "\e116";
+}
+.glyphicon-folder-close:before {
+ content: "\e117";
+}
+.glyphicon-folder-open:before {
+ content: "\e118";
+}
+.glyphicon-resize-vertical:before {
+ content: "\e119";
+}
+.glyphicon-resize-horizontal:before {
+ content: "\e120";
+}
+.glyphicon-hdd:before {
+ content: "\e121";
+}
+.glyphicon-bullhorn:before {
+ content: "\e122";
+}
+.glyphicon-bell:before {
+ content: "\e123";
+}
+.glyphicon-certificate:before {
+ content: "\e124";
+}
+.glyphicon-thumbs-up:before {
+ content: "\e125";
+}
+.glyphicon-thumbs-down:before {
+ content: "\e126";
+}
+.glyphicon-hand-right:before {
+ content: "\e127";
+}
+.glyphicon-hand-left:before {
+ content: "\e128";
+}
+.glyphicon-hand-up:before {
+ content: "\e129";
+}
+.glyphicon-hand-down:before {
+ content: "\e130";
+}
+.glyphicon-circle-arrow-right:before {
+ content: "\e131";
+}
+.glyphicon-circle-arrow-left:before {
+ content: "\e132";
+}
+.glyphicon-circle-arrow-up:before {
+ content: "\e133";
+}
+.glyphicon-circle-arrow-down:before {
+ content: "\e134";
+}
+.glyphicon-globe:before {
+ content: "\e135";
+}
+.glyphicon-wrench:before {
+ content: "\e136";
+}
+.glyphicon-tasks:before {
+ content: "\e137";
+}
+.glyphicon-filter:before {
+ content: "\e138";
+}
+.glyphicon-briefcase:before {
+ content: "\e139";
+}
+.glyphicon-fullscreen:before {
+ content: "\e140";
+}
+.glyphicon-dashboard:before {
+ content: "\e141";
+}
+.glyphicon-paperclip:before {
+ content: "\e142";
+}
+.glyphicon-heart-empty:before {
+ content: "\e143";
+}
+.glyphicon-link:before {
+ content: "\e144";
+}
+.glyphicon-phone:before {
+ content: "\e145";
+}
+.glyphicon-pushpin:before {
+ content: "\e146";
+}
+.glyphicon-usd:before {
+ content: "\e148";
+}
+.glyphicon-gbp:before {
+ content: "\e149";
+}
+.glyphicon-sort:before {
+ content: "\e150";
+}
+.glyphicon-sort-by-alphabet:before {
+ content: "\e151";
+}
+.glyphicon-sort-by-alphabet-alt:before {
+ content: "\e152";
+}
+.glyphicon-sort-by-order:before {
+ content: "\e153";
+}
+.glyphicon-sort-by-order-alt:before {
+ content: "\e154";
+}
+.glyphicon-sort-by-attributes:before {
+ content: "\e155";
+}
+.glyphicon-sort-by-attributes-alt:before {
+ content: "\e156";
+}
+.glyphicon-unchecked:before {
+ content: "\e157";
+}
+.glyphicon-expand:before {
+ content: "\e158";
+}
+.glyphicon-collapse-down:before {
+ content: "\e159";
+}
+.glyphicon-collapse-up:before {
+ content: "\e160";
+}
+.glyphicon-log-in:before {
+ content: "\e161";
+}
+.glyphicon-flash:before {
+ content: "\e162";
+}
+.glyphicon-log-out:before {
+ content: "\e163";
+}
+.glyphicon-new-window:before {
+ content: "\e164";
+}
+.glyphicon-record:before {
+ content: "\e165";
+}
+.glyphicon-save:before {
+ content: "\e166";
+}
+.glyphicon-open:before {
+ content: "\e167";
+}
+.glyphicon-saved:before {
+ content: "\e168";
+}
+.glyphicon-import:before {
+ content: "\e169";
+}
+.glyphicon-export:before {
+ content: "\e170";
+}
+.glyphicon-send:before {
+ content: "\e171";
+}
+.glyphicon-floppy-disk:before {
+ content: "\e172";
+}
+.glyphicon-floppy-saved:before {
+ content: "\e173";
+}
+.glyphicon-floppy-remove:before {
+ content: "\e174";
+}
+.glyphicon-floppy-save:before {
+ content: "\e175";
+}
+.glyphicon-floppy-open:before {
+ content: "\e176";
+}
+.glyphicon-credit-card:before {
+ content: "\e177";
+}
+.glyphicon-transfer:before {
+ content: "\e178";
+}
+.glyphicon-cutlery:before {
+ content: "\e179";
+}
+.glyphicon-header:before {
+ content: "\e180";
+}
+.glyphicon-compressed:before {
+ content: "\e181";
+}
+.glyphicon-earphone:before {
+ content: "\e182";
+}
+.glyphicon-phone-alt:before {
+ content: "\e183";
+}
+.glyphicon-tower:before {
+ content: "\e184";
+}
+.glyphicon-stats:before {
+ content: "\e185";
+}
+.glyphicon-sd-video:before {
+ content: "\e186";
+}
+.glyphicon-hd-video:before {
+ content: "\e187";
+}
+.glyphicon-subtitles:before {
+ content: "\e188";
+}
+.glyphicon-sound-stereo:before {
+ content: "\e189";
+}
+.glyphicon-sound-dolby:before {
+ content: "\e190";
+}
+.glyphicon-sound-5-1:before {
+ content: "\e191";
+}
+.glyphicon-sound-6-1:before {
+ content: "\e192";
+}
+.glyphicon-sound-7-1:before {
+ content: "\e193";
+}
+.glyphicon-copyright-mark:before {
+ content: "\e194";
+}
+.glyphicon-registration-mark:before {
+ content: "\e195";
+}
+.glyphicon-cloud-download:before {
+ content: "\e197";
+}
+.glyphicon-cloud-upload:before {
+ content: "\e198";
+}
+.glyphicon-tree-conifer:before {
+ content: "\e199";
+}
+.glyphicon-tree-deciduous:before {
+ content: "\e200";
+}
+.glyphicon-cd:before {
+ content: "\e201";
+}
+.glyphicon-save-file:before {
+ content: "\e202";
+}
+.glyphicon-open-file:before {
+ content: "\e203";
+}
+.glyphicon-level-up:before {
+ content: "\e204";
+}
+.glyphicon-copy:before {
+ content: "\e205";
+}
+.glyphicon-paste:before {
+ content: "\e206";
+}
+.glyphicon-alert:before {
+ content: "\e209";
+}
+.glyphicon-equalizer:before {
+ content: "\e210";
+}
+.glyphicon-king:before {
+ content: "\e211";
+}
+.glyphicon-queen:before {
+ content: "\e212";
+}
+.glyphicon-pawn:before {
+ content: "\e213";
+}
+.glyphicon-bishop:before {
+ content: "\e214";
+}
+.glyphicon-knight:before {
+ content: "\e215";
+}
+.glyphicon-baby-formula:before {
+ content: "\e216";
+}
+.glyphicon-tent:before {
+ content: "\26fa";
+}
+.glyphicon-blackboard:before {
+ content: "\e218";
+}
+.glyphicon-bed:before {
+ content: "\e219";
+}
+.glyphicon-apple:before {
+ content: "\f8ff";
+}
+.glyphicon-erase:before {
+ content: "\e221";
+}
+.glyphicon-hourglass:before {
+ content: "\231b";
+}
+.glyphicon-lamp:before {
+ content: "\e223";
+}
+.glyphicon-duplicate:before {
+ content: "\e224";
+}
+.glyphicon-piggy-bank:before {
+ content: "\e225";
+}
+.glyphicon-scissors:before {
+ content: "\e226";
+}
+.glyphicon-bitcoin:before {
+ content: "\e227";
+}
+.glyphicon-btc:before {
+ content: "\e227";
+}
+.glyphicon-xbt:before {
+ content: "\e227";
+}
+.glyphicon-yen:before {
+ content: "\00a5";
+}
+.glyphicon-jpy:before {
+ content: "\00a5";
+}
+.glyphicon-ruble:before {
+ content: "\20bd";
+}
+.glyphicon-rub:before {
+ content: "\20bd";
+}
+.glyphicon-scale:before {
+ content: "\e230";
+}
+.glyphicon-ice-lolly:before {
+ content: "\e231";
+}
+.glyphicon-ice-lolly-tasted:before {
+ content: "\e232";
+}
+.glyphicon-education:before {
+ content: "\e233";
+}
+.glyphicon-option-horizontal:before {
+ content: "\e234";
+}
+.glyphicon-option-vertical:before {
+ content: "\e235";
+}
+.glyphicon-menu-hamburger:before {
+ content: "\e236";
+}
+.glyphicon-modal-window:before {
+ content: "\e237";
+}
+.glyphicon-oil:before {
+ content: "\e238";
+}
+.glyphicon-grain:before {
+ content: "\e239";
+}
+.glyphicon-sunglasses:before {
+ content: "\e240";
+}
+.glyphicon-text-size:before {
+ content: "\e241";
+}
+.glyphicon-text-color:before {
+ content: "\e242";
+}
+.glyphicon-text-background:before {
+ content: "\e243";
+}
+.glyphicon-object-align-top:before {
+ content: "\e244";
+}
+.glyphicon-object-align-bottom:before {
+ content: "\e245";
+}
+.glyphicon-object-align-horizontal:before {
+ content: "\e246";
+}
+.glyphicon-object-align-left:before {
+ content: "\e247";
+}
+.glyphicon-object-align-vertical:before {
+ content: "\e248";
+}
+.glyphicon-object-align-right:before {
+ content: "\e249";
+}
+.glyphicon-triangle-right:before {
+ content: "\e250";
+}
+.glyphicon-triangle-left:before {
+ content: "\e251";
+}
+.glyphicon-triangle-bottom:before {
+ content: "\e252";
+}
+.glyphicon-triangle-top:before {
+ content: "\e253";
+}
+.glyphicon-console:before {
+ content: "\e254";
+}
+.glyphicon-superscript:before {
+ content: "\e255";
+}
+.glyphicon-subscript:before {
+ content: "\e256";
+}
+.glyphicon-menu-left:before {
+ content: "\e257";
+}
+.glyphicon-menu-right:before {
+ content: "\e258";
+}
+.glyphicon-menu-down:before {
+ content: "\e259";
+}
+.glyphicon-menu-up:before {
+ content: "\e260";
+}
+* {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+*:before,
+*:after {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+html {
+ font-size: 10px;
+
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+body {
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ line-height: 1.42857143;
+ color: #333;
+ background-color: #fff;
+}
+input,
+button,
+select,
+textarea {
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+}
+a {
+ color: #337ab7;
+ text-decoration: none;
+}
+a:hover,
+a:focus {
+ color: #23527c;
+ text-decoration: underline;
+}
+a:focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+figure {
+ margin: 0;
+}
+img {
+ vertical-align: middle;
+}
+.img-responsive,
+.thumbnail > img,
+.thumbnail a > img,
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+ display: block;
+ max-width: 100%;
+ height: auto;
+}
+.img-rounded {
+ border-radius: 6px;
+}
+.img-thumbnail {
+ display: inline-block;
+ max-width: 100%;
+ height: auto;
+ padding: 4px;
+ line-height: 1.42857143;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ -webkit-transition: all .2s ease-in-out;
+ -o-transition: all .2s ease-in-out;
+ transition: all .2s ease-in-out;
+}
+.img-circle {
+ border-radius: 50%;
+}
+hr {
+ margin-top: 20px;
+ margin-bottom: 20px;
+ border: 0;
+ border-top: 1px solid #eee;
+}
+.sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ border: 0;
+}
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+ position: static;
+ width: auto;
+ height: auto;
+ margin: 0;
+ overflow: visible;
+ clip: auto;
+}
+[role="button"] {
+ cursor: pointer;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6 {
+ font-family: inherit;
+ font-weight: 500;
+ line-height: 1.1;
+ color: inherit;
+}
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small,
+.h1 small,
+.h2 small,
+.h3 small,
+.h4 small,
+.h5 small,
+.h6 small,
+h1 .small,
+h2 .small,
+h3 .small,
+h4 .small,
+h5 .small,
+h6 .small,
+.h1 .small,
+.h2 .small,
+.h3 .small,
+.h4 .small,
+.h5 .small,
+.h6 .small {
+ font-weight: normal;
+ line-height: 1;
+ color: #777;
+}
+h1,
+.h1,
+h2,
+.h2,
+h3,
+.h3 {
+ margin-top: 20px;
+ margin-bottom: 10px;
+}
+h1 small,
+.h1 small,
+h2 small,
+.h2 small,
+h3 small,
+.h3 small,
+h1 .small,
+.h1 .small,
+h2 .small,
+.h2 .small,
+h3 .small,
+.h3 .small {
+ font-size: 65%;
+}
+h4,
+.h4,
+h5,
+.h5,
+h6,
+.h6 {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+h4 small,
+.h4 small,
+h5 small,
+.h5 small,
+h6 small,
+.h6 small,
+h4 .small,
+.h4 .small,
+h5 .small,
+.h5 .small,
+h6 .small,
+.h6 .small {
+ font-size: 75%;
+}
+h1,
+.h1 {
+ font-size: 36px;
+}
+h2,
+.h2 {
+ font-size: 30px;
+}
+h3,
+.h3 {
+ font-size: 24px;
+}
+h4,
+.h4 {
+ font-size: 18px;
+}
+h5,
+.h5 {
+ font-size: 14px;
+}
+h6,
+.h6 {
+ font-size: 12px;
+}
+p {
+ margin: 0 0 10px;
+}
+.lead {
+ margin-bottom: 20px;
+ font-size: 16px;
+ font-weight: 300;
+ line-height: 1.4;
+}
+@media (min-width: 768px) {
+ .lead {
+ font-size: 21px;
+ }
+}
+small,
+.small {
+ font-size: 85%;
+}
+mark,
+.mark {
+ padding: .2em;
+ background-color: #fcf8e3;
+}
+.text-left {
+ text-align: left;
+}
+.text-right {
+ text-align: right;
+}
+.text-center {
+ text-align: center;
+}
+.text-justify {
+ text-align: justify;
+}
+.text-nowrap {
+ white-space: nowrap;
+}
+.text-lowercase {
+ text-transform: lowercase;
+}
+.text-uppercase {
+ text-transform: uppercase;
+}
+.text-capitalize {
+ text-transform: capitalize;
+}
+.text-muted {
+ color: #777;
+}
+.text-primary {
+ color: #337ab7;
+}
+a.text-primary:hover,
+a.text-primary:focus {
+ color: #286090;
+}
+.text-success {
+ color: #3c763d;
+}
+a.text-success:hover,
+a.text-success:focus {
+ color: #2b542c;
+}
+.text-info {
+ color: #31708f;
+}
+a.text-info:hover,
+a.text-info:focus {
+ color: #245269;
+}
+.text-warning {
+ color: #8a6d3b;
+}
+a.text-warning:hover,
+a.text-warning:focus {
+ color: #66512c;
+}
+.text-danger {
+ color: #a94442;
+}
+a.text-danger:hover,
+a.text-danger:focus {
+ color: #843534;
+}
+.bg-primary {
+ color: #fff;
+ background-color: #337ab7;
+}
+a.bg-primary:hover,
+a.bg-primary:focus {
+ background-color: #286090;
+}
+.bg-success {
+ background-color: #dff0d8;
+}
+a.bg-success:hover,
+a.bg-success:focus {
+ background-color: #c1e2b3;
+}
+.bg-info {
+ background-color: #d9edf7;
+}
+a.bg-info:hover,
+a.bg-info:focus {
+ background-color: #afd9ee;
+}
+.bg-warning {
+ background-color: #fcf8e3;
+}
+a.bg-warning:hover,
+a.bg-warning:focus {
+ background-color: #f7ecb5;
+}
+.bg-danger {
+ background-color: #f2dede;
+}
+a.bg-danger:hover,
+a.bg-danger:focus {
+ background-color: #e4b9b9;
+}
+.page-header {
+ padding-bottom: 9px;
+ margin: 40px 0 20px;
+ border-bottom: 1px solid #eee;
+}
+ul,
+ol {
+ margin-top: 0;
+ margin-bottom: 10px;
+}
+ul ul,
+ol ul,
+ul ol,
+ol ol {
+ margin-bottom: 0;
+}
+.list-unstyled {
+ padding-left: 0;
+ list-style: none;
+}
+.list-inline {
+ padding-left: 0;
+ margin-left: -5px;
+ list-style: none;
+}
+.list-inline > li {
+ display: inline-block;
+ padding-right: 5px;
+ padding-left: 5px;
+}
+dl {
+ margin-top: 0;
+ margin-bottom: 20px;
+}
+dt,
+dd {
+ line-height: 1.42857143;
+}
+dt {
+ font-weight: bold;
+}
+dd {
+ margin-left: 0;
+}
+@media (min-width: 768px) {
+ .dl-horizontal dt {
+ float: left;
+ width: 160px;
+ overflow: hidden;
+ clear: left;
+ text-align: right;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ .dl-horizontal dd {
+ margin-left: 180px;
+ }
+}
+abbr[title],
+abbr[data-original-title] {
+ cursor: help;
+ border-bottom: 1px dotted #777;
+}
+.initialism {
+ font-size: 90%;
+ text-transform: uppercase;
+}
+blockquote {
+ padding: 10px 20px;
+ margin: 0 0 20px;
+ font-size: 17.5px;
+ border-left: 5px solid #eee;
+}
+blockquote p:last-child,
+blockquote ul:last-child,
+blockquote ol:last-child {
+ margin-bottom: 0;
+}
+blockquote footer,
+blockquote small,
+blockquote .small {
+ display: block;
+ font-size: 80%;
+ line-height: 1.42857143;
+ color: #777;
+}
+blockquote footer:before,
+blockquote small:before,
+blockquote .small:before {
+ content: '\2014 \00A0';
+}
+.blockquote-reverse,
+blockquote.pull-right {
+ padding-right: 15px;
+ padding-left: 0;
+ text-align: right;
+ border-right: 5px solid #eee;
+ border-left: 0;
+}
+.blockquote-reverse footer:before,
+blockquote.pull-right footer:before,
+.blockquote-reverse small:before,
+blockquote.pull-right small:before,
+.blockquote-reverse .small:before,
+blockquote.pull-right .small:before {
+ content: '';
+}
+.blockquote-reverse footer:after,
+blockquote.pull-right footer:after,
+.blockquote-reverse small:after,
+blockquote.pull-right small:after,
+.blockquote-reverse .small:after,
+blockquote.pull-right .small:after {
+ content: '\00A0 \2014';
+}
+address {
+ margin-bottom: 20px;
+ font-style: normal;
+ line-height: 1.42857143;
+}
+code,
+kbd,
+pre,
+samp {
+ font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+}
+code {
+ padding: 2px 4px;
+ font-size: 90%;
+ color: #c7254e;
+ background-color: #f9f2f4;
+ border-radius: 4px;
+}
+kbd {
+ padding: 2px 4px;
+ font-size: 90%;
+ color: #fff;
+ background-color: #333;
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
+}
+kbd kbd {
+ padding: 0;
+ font-size: 100%;
+ font-weight: bold;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+pre {
+ display: block;
+ padding: 9.5px;
+ margin: 0 0 10px;
+ font-size: 13px;
+ line-height: 1.42857143;
+ color: #333;
+ word-break: break-all;
+ word-wrap: break-word;
+ background-color: #f5f5f5;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+}
+pre code {
+ padding: 0;
+ font-size: inherit;
+ color: inherit;
+ white-space: pre-wrap;
+ background-color: transparent;
+ border-radius: 0;
+}
+.pre-scrollable {
+ max-height: 340px;
+ overflow-y: scroll;
+}
+.container {
+ padding-right: 15px;
+ padding-left: 15px;
+ margin-right: auto;
+ margin-left: auto;
+}
+@media (min-width: 768px) {
+ .container {
+ width: 750px;
+ }
+}
+@media (min-width: 992px) {
+ .container {
+ width: 970px;
+ }
+}
+@media (min-width: 1200px) {
+ .container {
+ width: 1170px;
+ }
+}
+.container-fluid {
+ padding-right: 15px;
+ padding-left: 15px;
+ margin-right: auto;
+ margin-left: auto;
+}
+.row {
+ margin-right: -15px;
+ margin-left: -15px;
+}
+.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
+ position: relative;
+ min-height: 1px;
+ padding-right: 15px;
+ padding-left: 15px;
+}
+.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
+ float: left;
+}
+.col-xs-12 {
+ width: 100%;
+}
+.col-xs-11 {
+ width: 91.66666667%;
+}
+.col-xs-10 {
+ width: 83.33333333%;
+}
+.col-xs-9 {
+ width: 75%;
+}
+.col-xs-8 {
+ width: 66.66666667%;
+}
+.col-xs-7 {
+ width: 58.33333333%;
+}
+.col-xs-6 {
+ width: 50%;
+}
+.col-xs-5 {
+ width: 41.66666667%;
+}
+.col-xs-4 {
+ width: 33.33333333%;
+}
+.col-xs-3 {
+ width: 25%;
+}
+.col-xs-2 {
+ width: 16.66666667%;
+}
+.col-xs-1 {
+ width: 8.33333333%;
+}
+.col-xs-pull-12 {
+ right: 100%;
+}
+.col-xs-pull-11 {
+ right: 91.66666667%;
+}
+.col-xs-pull-10 {
+ right: 83.33333333%;
+}
+.col-xs-pull-9 {
+ right: 75%;
+}
+.col-xs-pull-8 {
+ right: 66.66666667%;
+}
+.col-xs-pull-7 {
+ right: 58.33333333%;
+}
+.col-xs-pull-6 {
+ right: 50%;
+}
+.col-xs-pull-5 {
+ right: 41.66666667%;
+}
+.col-xs-pull-4 {
+ right: 33.33333333%;
+}
+.col-xs-pull-3 {
+ right: 25%;
+}
+.col-xs-pull-2 {
+ right: 16.66666667%;
+}
+.col-xs-pull-1 {
+ right: 8.33333333%;
+}
+.col-xs-pull-0 {
+ right: auto;
+}
+.col-xs-push-12 {
+ left: 100%;
+}
+.col-xs-push-11 {
+ left: 91.66666667%;
+}
+.col-xs-push-10 {
+ left: 83.33333333%;
+}
+.col-xs-push-9 {
+ left: 75%;
+}
+.col-xs-push-8 {
+ left: 66.66666667%;
+}
+.col-xs-push-7 {
+ left: 58.33333333%;
+}
+.col-xs-push-6 {
+ left: 50%;
+}
+.col-xs-push-5 {
+ left: 41.66666667%;
+}
+.col-xs-push-4 {
+ left: 33.33333333%;
+}
+.col-xs-push-3 {
+ left: 25%;
+}
+.col-xs-push-2 {
+ left: 16.66666667%;
+}
+.col-xs-push-1 {
+ left: 8.33333333%;
+}
+.col-xs-push-0 {
+ left: auto;
+}
+.col-xs-offset-12 {
+ margin-left: 100%;
+}
+.col-xs-offset-11 {
+ margin-left: 91.66666667%;
+}
+.col-xs-offset-10 {
+ margin-left: 83.33333333%;
+}
+.col-xs-offset-9 {
+ margin-left: 75%;
+}
+.col-xs-offset-8 {
+ margin-left: 66.66666667%;
+}
+.col-xs-offset-7 {
+ margin-left: 58.33333333%;
+}
+.col-xs-offset-6 {
+ margin-left: 50%;
+}
+.col-xs-offset-5 {
+ margin-left: 41.66666667%;
+}
+.col-xs-offset-4 {
+ margin-left: 33.33333333%;
+}
+.col-xs-offset-3 {
+ margin-left: 25%;
+}
+.col-xs-offset-2 {
+ margin-left: 16.66666667%;
+}
+.col-xs-offset-1 {
+ margin-left: 8.33333333%;
+}
+.col-xs-offset-0 {
+ margin-left: 0;
+}
+@media (min-width: 768px) {
+ .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
+ float: left;
+ }
+ .col-sm-12 {
+ width: 100%;
+ }
+ .col-sm-11 {
+ width: 91.66666667%;
+ }
+ .col-sm-10 {
+ width: 83.33333333%;
+ }
+ .col-sm-9 {
+ width: 75%;
+ }
+ .col-sm-8 {
+ width: 66.66666667%;
+ }
+ .col-sm-7 {
+ width: 58.33333333%;
+ }
+ .col-sm-6 {
+ width: 50%;
+ }
+ .col-sm-5 {
+ width: 41.66666667%;
+ }
+ .col-sm-4 {
+ width: 33.33333333%;
+ }
+ .col-sm-3 {
+ width: 25%;
+ }
+ .col-sm-2 {
+ width: 16.66666667%;
+ }
+ .col-sm-1 {
+ width: 8.33333333%;
+ }
+ .col-sm-pull-12 {
+ right: 100%;
+ }
+ .col-sm-pull-11 {
+ right: 91.66666667%;
+ }
+ .col-sm-pull-10 {
+ right: 83.33333333%;
+ }
+ .col-sm-pull-9 {
+ right: 75%;
+ }
+ .col-sm-pull-8 {
+ right: 66.66666667%;
+ }
+ .col-sm-pull-7 {
+ right: 58.33333333%;
+ }
+ .col-sm-pull-6 {
+ right: 50%;
+ }
+ .col-sm-pull-5 {
+ right: 41.66666667%;
+ }
+ .col-sm-pull-4 {
+ right: 33.33333333%;
+ }
+ .col-sm-pull-3 {
+ right: 25%;
+ }
+ .col-sm-pull-2 {
+ right: 16.66666667%;
+ }
+ .col-sm-pull-1 {
+ right: 8.33333333%;
+ }
+ .col-sm-pull-0 {
+ right: auto;
+ }
+ .col-sm-push-12 {
+ left: 100%;
+ }
+ .col-sm-push-11 {
+ left: 91.66666667%;
+ }
+ .col-sm-push-10 {
+ left: 83.33333333%;
+ }
+ .col-sm-push-9 {
+ left: 75%;
+ }
+ .col-sm-push-8 {
+ left: 66.66666667%;
+ }
+ .col-sm-push-7 {
+ left: 58.33333333%;
+ }
+ .col-sm-push-6 {
+ left: 50%;
+ }
+ .col-sm-push-5 {
+ left: 41.66666667%;
+ }
+ .col-sm-push-4 {
+ left: 33.33333333%;
+ }
+ .col-sm-push-3 {
+ left: 25%;
+ }
+ .col-sm-push-2 {
+ left: 16.66666667%;
+ }
+ .col-sm-push-1 {
+ left: 8.33333333%;
+ }
+ .col-sm-push-0 {
+ left: auto;
+ }
+ .col-sm-offset-12 {
+ margin-left: 100%;
+ }
+ .col-sm-offset-11 {
+ margin-left: 91.66666667%;
+ }
+ .col-sm-offset-10 {
+ margin-left: 83.33333333%;
+ }
+ .col-sm-offset-9 {
+ margin-left: 75%;
+ }
+ .col-sm-offset-8 {
+ margin-left: 66.66666667%;
+ }
+ .col-sm-offset-7 {
+ margin-left: 58.33333333%;
+ }
+ .col-sm-offset-6 {
+ margin-left: 50%;
+ }
+ .col-sm-offset-5 {
+ margin-left: 41.66666667%;
+ }
+ .col-sm-offset-4 {
+ margin-left: 33.33333333%;
+ }
+ .col-sm-offset-3 {
+ margin-left: 25%;
+ }
+ .col-sm-offset-2 {
+ margin-left: 16.66666667%;
+ }
+ .col-sm-offset-1 {
+ margin-left: 8.33333333%;
+ }
+ .col-sm-offset-0 {
+ margin-left: 0;
+ }
+}
+@media (min-width: 992px) {
+ .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
+ float: left;
+ }
+ .col-md-12 {
+ width: 100%;
+ }
+ .col-md-11 {
+ width: 91.66666667%;
+ }
+ .col-md-10 {
+ width: 83.33333333%;
+ }
+ .col-md-9 {
+ width: 75%;
+ }
+ .col-md-8 {
+ width: 66.66666667%;
+ }
+ .col-md-7 {
+ width: 58.33333333%;
+ }
+ .col-md-6 {
+ width: 50%;
+ }
+ .col-md-5 {
+ width: 41.66666667%;
+ }
+ .col-md-4 {
+ width: 33.33333333%;
+ }
+ .col-md-3 {
+ width: 25%;
+ }
+ .col-md-2 {
+ width: 16.66666667%;
+ }
+ .col-md-1 {
+ width: 8.33333333%;
+ }
+ .col-md-pull-12 {
+ right: 100%;
+ }
+ .col-md-pull-11 {
+ right: 91.66666667%;
+ }
+ .col-md-pull-10 {
+ right: 83.33333333%;
+ }
+ .col-md-pull-9 {
+ right: 75%;
+ }
+ .col-md-pull-8 {
+ right: 66.66666667%;
+ }
+ .col-md-pull-7 {
+ right: 58.33333333%;
+ }
+ .col-md-pull-6 {
+ right: 50%;
+ }
+ .col-md-pull-5 {
+ right: 41.66666667%;
+ }
+ .col-md-pull-4 {
+ right: 33.33333333%;
+ }
+ .col-md-pull-3 {
+ right: 25%;
+ }
+ .col-md-pull-2 {
+ right: 16.66666667%;
+ }
+ .col-md-pull-1 {
+ right: 8.33333333%;
+ }
+ .col-md-pull-0 {
+ right: auto;
+ }
+ .col-md-push-12 {
+ left: 100%;
+ }
+ .col-md-push-11 {
+ left: 91.66666667%;
+ }
+ .col-md-push-10 {
+ left: 83.33333333%;
+ }
+ .col-md-push-9 {
+ left: 75%;
+ }
+ .col-md-push-8 {
+ left: 66.66666667%;
+ }
+ .col-md-push-7 {
+ left: 58.33333333%;
+ }
+ .col-md-push-6 {
+ left: 50%;
+ }
+ .col-md-push-5 {
+ left: 41.66666667%;
+ }
+ .col-md-push-4 {
+ left: 33.33333333%;
+ }
+ .col-md-push-3 {
+ left: 25%;
+ }
+ .col-md-push-2 {
+ left: 16.66666667%;
+ }
+ .col-md-push-1 {
+ left: 8.33333333%;
+ }
+ .col-md-push-0 {
+ left: auto;
+ }
+ .col-md-offset-12 {
+ margin-left: 100%;
+ }
+ .col-md-offset-11 {
+ margin-left: 91.66666667%;
+ }
+ .col-md-offset-10 {
+ margin-left: 83.33333333%;
+ }
+ .col-md-offset-9 {
+ margin-left: 75%;
+ }
+ .col-md-offset-8 {
+ margin-left: 66.66666667%;
+ }
+ .col-md-offset-7 {
+ margin-left: 58.33333333%;
+ }
+ .col-md-offset-6 {
+ margin-left: 50%;
+ }
+ .col-md-offset-5 {
+ margin-left: 41.66666667%;
+ }
+ .col-md-offset-4 {
+ margin-left: 33.33333333%;
+ }
+ .col-md-offset-3 {
+ margin-left: 25%;
+ }
+ .col-md-offset-2 {
+ margin-left: 16.66666667%;
+ }
+ .col-md-offset-1 {
+ margin-left: 8.33333333%;
+ }
+ .col-md-offset-0 {
+ margin-left: 0;
+ }
+}
+@media (min-width: 1200px) {
+ .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
+ float: left;
+ }
+ .col-lg-12 {
+ width: 100%;
+ }
+ .col-lg-11 {
+ width: 91.66666667%;
+ }
+ .col-lg-10 {
+ width: 83.33333333%;
+ }
+ .col-lg-9 {
+ width: 75%;
+ }
+ .col-lg-8 {
+ width: 66.66666667%;
+ }
+ .col-lg-7 {
+ width: 58.33333333%;
+ }
+ .col-lg-6 {
+ width: 50%;
+ }
+ .col-lg-5 {
+ width: 41.66666667%;
+ }
+ .col-lg-4 {
+ width: 33.33333333%;
+ }
+ .col-lg-3 {
+ width: 25%;
+ }
+ .col-lg-2 {
+ width: 16.66666667%;
+ }
+ .col-lg-1 {
+ width: 8.33333333%;
+ }
+ .col-lg-pull-12 {
+ right: 100%;
+ }
+ .col-lg-pull-11 {
+ right: 91.66666667%;
+ }
+ .col-lg-pull-10 {
+ right: 83.33333333%;
+ }
+ .col-lg-pull-9 {
+ right: 75%;
+ }
+ .col-lg-pull-8 {
+ right: 66.66666667%;
+ }
+ .col-lg-pull-7 {
+ right: 58.33333333%;
+ }
+ .col-lg-pull-6 {
+ right: 50%;
+ }
+ .col-lg-pull-5 {
+ right: 41.66666667%;
+ }
+ .col-lg-pull-4 {
+ right: 33.33333333%;
+ }
+ .col-lg-pull-3 {
+ right: 25%;
+ }
+ .col-lg-pull-2 {
+ right: 16.66666667%;
+ }
+ .col-lg-pull-1 {
+ right: 8.33333333%;
+ }
+ .col-lg-pull-0 {
+ right: auto;
+ }
+ .col-lg-push-12 {
+ left: 100%;
+ }
+ .col-lg-push-11 {
+ left: 91.66666667%;
+ }
+ .col-lg-push-10 {
+ left: 83.33333333%;
+ }
+ .col-lg-push-9 {
+ left: 75%;
+ }
+ .col-lg-push-8 {
+ left: 66.66666667%;
+ }
+ .col-lg-push-7 {
+ left: 58.33333333%;
+ }
+ .col-lg-push-6 {
+ left: 50%;
+ }
+ .col-lg-push-5 {
+ left: 41.66666667%;
+ }
+ .col-lg-push-4 {
+ left: 33.33333333%;
+ }
+ .col-lg-push-3 {
+ left: 25%;
+ }
+ .col-lg-push-2 {
+ left: 16.66666667%;
+ }
+ .col-lg-push-1 {
+ left: 8.33333333%;
+ }
+ .col-lg-push-0 {
+ left: auto;
+ }
+ .col-lg-offset-12 {
+ margin-left: 100%;
+ }
+ .col-lg-offset-11 {
+ margin-left: 91.66666667%;
+ }
+ .col-lg-offset-10 {
+ margin-left: 83.33333333%;
+ }
+ .col-lg-offset-9 {
+ margin-left: 75%;
+ }
+ .col-lg-offset-8 {
+ margin-left: 66.66666667%;
+ }
+ .col-lg-offset-7 {
+ margin-left: 58.33333333%;
+ }
+ .col-lg-offset-6 {
+ margin-left: 50%;
+ }
+ .col-lg-offset-5 {
+ margin-left: 41.66666667%;
+ }
+ .col-lg-offset-4 {
+ margin-left: 33.33333333%;
+ }
+ .col-lg-offset-3 {
+ margin-left: 25%;
+ }
+ .col-lg-offset-2 {
+ margin-left: 16.66666667%;
+ }
+ .col-lg-offset-1 {
+ margin-left: 8.33333333%;
+ }
+ .col-lg-offset-0 {
+ margin-left: 0;
+ }
+}
+table {
+ background-color: transparent;
+}
+caption {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ color: #777;
+ text-align: left;
+}
+th {
+ text-align: left;
+}
+.table {
+ width: 100%;
+ max-width: 100%;
+ margin-bottom: 20px;
+}
+.table > thead > tr > th,
+.table > tbody > tr > th,
+.table > tfoot > tr > th,
+.table > thead > tr > td,
+.table > tbody > tr > td,
+.table > tfoot > tr > td {
+ padding: 8px;
+ line-height: 1.42857143;
+ vertical-align: top;
+ border-top: 1px solid #ddd;
+}
+.table > thead > tr > th {
+ vertical-align: bottom;
+ border-bottom: 2px solid #ddd;
+}
+.table > caption + thead > tr:first-child > th,
+.table > colgroup + thead > tr:first-child > th,
+.table > thead:first-child > tr:first-child > th,
+.table > caption + thead > tr:first-child > td,
+.table > colgroup + thead > tr:first-child > td,
+.table > thead:first-child > tr:first-child > td {
+ border-top: 0;
+}
+.table > tbody + tbody {
+ border-top: 2px solid #ddd;
+}
+.table .table {
+ background-color: #fff;
+}
+.table-condensed > thead > tr > th,
+.table-condensed > tbody > tr > th,
+.table-condensed > tfoot > tr > th,
+.table-condensed > thead > tr > td,
+.table-condensed > tbody > tr > td,
+.table-condensed > tfoot > tr > td {
+ padding: 5px;
+}
+.table-bordered {
+ border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > tbody > tr > th,
+.table-bordered > tfoot > tr > th,
+.table-bordered > thead > tr > td,
+.table-bordered > tbody > tr > td,
+.table-bordered > tfoot > tr > td {
+ border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > thead > tr > td {
+ border-bottom-width: 2px;
+}
+.table-striped > tbody > tr:nth-of-type(odd) {
+ background-color: #f9f9f9;
+}
+.table-hover > tbody > tr:hover {
+ background-color: #f5f5f5;
+}
+table col[class*="col-"] {
+ position: static;
+ display: table-column;
+ float: none;
+}
+table td[class*="col-"],
+table th[class*="col-"] {
+ position: static;
+ display: table-cell;
+ float: none;
+}
+.table > thead > tr > td.active,
+.table > tbody > tr > td.active,
+.table > tfoot > tr > td.active,
+.table > thead > tr > th.active,
+.table > tbody > tr > th.active,
+.table > tfoot > tr > th.active,
+.table > thead > tr.active > td,
+.table > tbody > tr.active > td,
+.table > tfoot > tr.active > td,
+.table > thead > tr.active > th,
+.table > tbody > tr.active > th,
+.table > tfoot > tr.active > th {
+ background-color: #f5f5f5;
+}
+.table-hover > tbody > tr > td.active:hover,
+.table-hover > tbody > tr > th.active:hover,
+.table-hover > tbody > tr.active:hover > td,
+.table-hover > tbody > tr:hover > .active,
+.table-hover > tbody > tr.active:hover > th {
+ background-color: #e8e8e8;
+}
+.table > thead > tr > td.success,
+.table > tbody > tr > td.success,
+.table > tfoot > tr > td.success,
+.table > thead > tr > th.success,
+.table > tbody > tr > th.success,
+.table > tfoot > tr > th.success,
+.table > thead > tr.success > td,
+.table > tbody > tr.success > td,
+.table > tfoot > tr.success > td,
+.table > thead > tr.success > th,
+.table > tbody > tr.success > th,
+.table > tfoot > tr.success > th {
+ background-color: #dff0d8;
+}
+.table-hover > tbody > tr > td.success:hover,
+.table-hover > tbody > tr > th.success:hover,
+.table-hover > tbody > tr.success:hover > td,
+.table-hover > tbody > tr:hover > .success,
+.table-hover > tbody > tr.success:hover > th {
+ background-color: #d0e9c6;
+}
+.table > thead > tr > td.info,
+.table > tbody > tr > td.info,
+.table > tfoot > tr > td.info,
+.table > thead > tr > th.info,
+.table > tbody > tr > th.info,
+.table > tfoot > tr > th.info,
+.table > thead > tr.info > td,
+.table > tbody > tr.info > td,
+.table > tfoot > tr.info > td,
+.table > thead > tr.info > th,
+.table > tbody > tr.info > th,
+.table > tfoot > tr.info > th {
+ background-color: #d9edf7;
+}
+.table-hover > tbody > tr > td.info:hover,
+.table-hover > tbody > tr > th.info:hover,
+.table-hover > tbody > tr.info:hover > td,
+.table-hover > tbody > tr:hover > .info,
+.table-hover > tbody > tr.info:hover > th {
+ background-color: #c4e3f3;
+}
+.table > thead > tr > td.warning,
+.table > tbody > tr > td.warning,
+.table > tfoot > tr > td.warning,
+.table > thead > tr > th.warning,
+.table > tbody > tr > th.warning,
+.table > tfoot > tr > th.warning,
+.table > thead > tr.warning > td,
+.table > tbody > tr.warning > td,
+.table > tfoot > tr.warning > td,
+.table > thead > tr.warning > th,
+.table > tbody > tr.warning > th,
+.table > tfoot > tr.warning > th {
+ background-color: #fcf8e3;
+}
+.table-hover > tbody > tr > td.warning:hover,
+.table-hover > tbody > tr > th.warning:hover,
+.table-hover > tbody > tr.warning:hover > td,
+.table-hover > tbody > tr:hover > .warning,
+.table-hover > tbody > tr.warning:hover > th {
+ background-color: #faf2cc;
+}
+.table > thead > tr > td.danger,
+.table > tbody > tr > td.danger,
+.table > tfoot > tr > td.danger,
+.table > thead > tr > th.danger,
+.table > tbody > tr > th.danger,
+.table > tfoot > tr > th.danger,
+.table > thead > tr.danger > td,
+.table > tbody > tr.danger > td,
+.table > tfoot > tr.danger > td,
+.table > thead > tr.danger > th,
+.table > tbody > tr.danger > th,
+.table > tfoot > tr.danger > th {
+ background-color: #f2dede;
+}
+.table-hover > tbody > tr > td.danger:hover,
+.table-hover > tbody > tr > th.danger:hover,
+.table-hover > tbody > tr.danger:hover > td,
+.table-hover > tbody > tr:hover > .danger,
+.table-hover > tbody > tr.danger:hover > th {
+ background-color: #ebcccc;
+}
+.table-responsive {
+ min-height: .01%;
+ overflow-x: auto;
+}
+@media screen and (max-width: 767px) {
+ .table-responsive {
+ width: 100%;
+ margin-bottom: 15px;
+ overflow-y: hidden;
+ -ms-overflow-style: -ms-autohiding-scrollbar;
+ border: 1px solid #ddd;
+ }
+ .table-responsive > .table {
+ margin-bottom: 0;
+ }
+ .table-responsive > .table > thead > tr > th,
+ .table-responsive > .table > tbody > tr > th,
+ .table-responsive > .table > tfoot > tr > th,
+ .table-responsive > .table > thead > tr > td,
+ .table-responsive > .table > tbody > tr > td,
+ .table-responsive > .table > tfoot > tr > td {
+ white-space: nowrap;
+ }
+ .table-responsive > .table-bordered {
+ border: 0;
+ }
+ .table-responsive > .table-bordered > thead > tr > th:first-child,
+ .table-responsive > .table-bordered > tbody > tr > th:first-child,
+ .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+ .table-responsive > .table-bordered > thead > tr > td:first-child,
+ .table-responsive > .table-bordered > tbody > tr > td:first-child,
+ .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+ border-left: 0;
+ }
+ .table-responsive > .table-bordered > thead > tr > th:last-child,
+ .table-responsive > .table-bordered > tbody > tr > th:last-child,
+ .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+ .table-responsive > .table-bordered > thead > tr > td:last-child,
+ .table-responsive > .table-bordered > tbody > tr > td:last-child,
+ .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+ border-right: 0;
+ }
+ .table-responsive > .table-bordered > tbody > tr:last-child > th,
+ .table-responsive > .table-bordered > tfoot > tr:last-child > th,
+ .table-responsive > .table-bordered > tbody > tr:last-child > td,
+ .table-responsive > .table-bordered > tfoot > tr:last-child > td {
+ border-bottom: 0;
+ }
+}
+fieldset {
+ min-width: 0;
+ padding: 0;
+ margin: 0;
+ border: 0;
+}
+legend {
+ display: block;
+ width: 100%;
+ padding: 0;
+ margin-bottom: 20px;
+ font-size: 21px;
+ line-height: inherit;
+ color: #333;
+ border: 0;
+ border-bottom: 1px solid #e5e5e5;
+}
+label {
+ display: inline-block;
+ max-width: 100%;
+ margin-bottom: 5px;
+ font-weight: bold;
+}
+input[type="search"] {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+input[type="radio"],
+input[type="checkbox"] {
+ margin: 4px 0 0;
+ margin-top: 1px \9;
+ line-height: normal;
+}
+input[type="file"] {
+ display: block;
+}
+input[type="range"] {
+ display: block;
+ width: 100%;
+}
+select[multiple],
+select[size] {
+ height: auto;
+}
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+output {
+ display: block;
+ padding-top: 7px;
+ font-size: 14px;
+ line-height: 1.42857143;
+ color: #555;
+}
+.form-control {
+ display: block;
+ width: 100%;
+ height: 34px;
+ padding: 6px 12px;
+ font-size: 14px;
+ line-height: 1.42857143;
+ color: #555;
+ background-color: #fff;
+ background-image: none;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
+ -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+ transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+}
+.form-control:focus {
+ border-color: #66afe9;
+ outline: 0;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
+}
+.form-control::-moz-placeholder {
+ color: #999;
+ opacity: 1;
+}
+.form-control:-ms-input-placeholder {
+ color: #999;
+}
+.form-control::-webkit-input-placeholder {
+ color: #999;
+}
+.form-control[disabled],
+.form-control[readonly],
+fieldset[disabled] .form-control {
+ background-color: #eee;
+ opacity: 1;
+}
+.form-control[disabled],
+fieldset[disabled] .form-control {
+ cursor: not-allowed;
+}
+textarea.form-control {
+ height: auto;
+}
+input[type="search"] {
+ -webkit-appearance: none;
+}
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+ input[type="date"].form-control,
+ input[type="time"].form-control,
+ input[type="datetime-local"].form-control,
+ input[type="month"].form-control {
+ line-height: 34px;
+ }
+ input[type="date"].input-sm,
+ input[type="time"].input-sm,
+ input[type="datetime-local"].input-sm,
+ input[type="month"].input-sm,
+ .input-group-sm input[type="date"],
+ .input-group-sm input[type="time"],
+ .input-group-sm input[type="datetime-local"],
+ .input-group-sm input[type="month"] {
+ line-height: 30px;
+ }
+ input[type="date"].input-lg,
+ input[type="time"].input-lg,
+ input[type="datetime-local"].input-lg,
+ input[type="month"].input-lg,
+ .input-group-lg input[type="date"],
+ .input-group-lg input[type="time"],
+ .input-group-lg input[type="datetime-local"],
+ .input-group-lg input[type="month"] {
+ line-height: 46px;
+ }
+}
+.form-group {
+ margin-bottom: 15px;
+}
+.radio,
+.checkbox {
+ position: relative;
+ display: block;
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+.radio label,
+.checkbox label {
+ min-height: 20px;
+ padding-left: 20px;
+ margin-bottom: 0;
+ font-weight: normal;
+ cursor: pointer;
+}
+.radio input[type="radio"],
+.radio-inline input[type="radio"],
+.checkbox input[type="checkbox"],
+.checkbox-inline input[type="checkbox"] {
+ position: absolute;
+ margin-top: 4px \9;
+ margin-left: -20px;
+}
+.radio + .radio,
+.checkbox + .checkbox {
+ margin-top: -5px;
+}
+.radio-inline,
+.checkbox-inline {
+ position: relative;
+ display: inline-block;
+ padding-left: 20px;
+ margin-bottom: 0;
+ font-weight: normal;
+ vertical-align: middle;
+ cursor: pointer;
+}
+.radio-inline + .radio-inline,
+.checkbox-inline + .checkbox-inline {
+ margin-top: 0;
+ margin-left: 10px;
+}
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"].disabled,
+input[type="checkbox"].disabled,
+fieldset[disabled] input[type="radio"],
+fieldset[disabled] input[type="checkbox"] {
+ cursor: not-allowed;
+}
+.radio-inline.disabled,
+.checkbox-inline.disabled,
+fieldset[disabled] .radio-inline,
+fieldset[disabled] .checkbox-inline {
+ cursor: not-allowed;
+}
+.radio.disabled label,
+.checkbox.disabled label,
+fieldset[disabled] .radio label,
+fieldset[disabled] .checkbox label {
+ cursor: not-allowed;
+}
+.form-control-static {
+ min-height: 34px;
+ padding-top: 7px;
+ padding-bottom: 7px;
+ margin-bottom: 0;
+}
+.form-control-static.input-lg,
+.form-control-static.input-sm {
+ padding-right: 0;
+ padding-left: 0;
+}
+.input-sm {
+ height: 30px;
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+select.input-sm {
+ height: 30px;
+ line-height: 30px;
+}
+textarea.input-sm,
+select[multiple].input-sm {
+ height: auto;
+}
+.form-group-sm .form-control {
+ height: 30px;
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+.form-group-sm select.form-control {
+ height: 30px;
+ line-height: 30px;
+}
+.form-group-sm textarea.form-control,
+.form-group-sm select[multiple].form-control {
+ height: auto;
+}
+.form-group-sm .form-control-static {
+ height: 30px;
+ min-height: 32px;
+ padding: 6px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+}
+.input-lg {
+ height: 46px;
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+ border-radius: 6px;
+}
+select.input-lg {
+ height: 46px;
+ line-height: 46px;
+}
+textarea.input-lg,
+select[multiple].input-lg {
+ height: auto;
+}
+.form-group-lg .form-control {
+ height: 46px;
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+ border-radius: 6px;
+}
+.form-group-lg select.form-control {
+ height: 46px;
+ line-height: 46px;
+}
+.form-group-lg textarea.form-control,
+.form-group-lg select[multiple].form-control {
+ height: auto;
+}
+.form-group-lg .form-control-static {
+ height: 46px;
+ min-height: 38px;
+ padding: 11px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+}
+.has-feedback {
+ position: relative;
+}
+.has-feedback .form-control {
+ padding-right: 42.5px;
+}
+.form-control-feedback {
+ position: absolute;
+ top: 0;
+ right: 0;
+ z-index: 2;
+ display: block;
+ width: 34px;
+ height: 34px;
+ line-height: 34px;
+ text-align: center;
+ pointer-events: none;
+}
+.input-lg + .form-control-feedback,
+.input-group-lg + .form-control-feedback,
+.form-group-lg .form-control + .form-control-feedback {
+ width: 46px;
+ height: 46px;
+ line-height: 46px;
+}
+.input-sm + .form-control-feedback,
+.input-group-sm + .form-control-feedback,
+.form-group-sm .form-control + .form-control-feedback {
+ width: 30px;
+ height: 30px;
+ line-height: 30px;
+}
+.has-success .help-block,
+.has-success .control-label,
+.has-success .radio,
+.has-success .checkbox,
+.has-success .radio-inline,
+.has-success .checkbox-inline,
+.has-success.radio label,
+.has-success.checkbox label,
+.has-success.radio-inline label,
+.has-success.checkbox-inline label {
+ color: #3c763d;
+}
+.has-success .form-control {
+ border-color: #3c763d;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-success .form-control:focus {
+ border-color: #2b542c;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
+}
+.has-success .input-group-addon {
+ color: #3c763d;
+ background-color: #dff0d8;
+ border-color: #3c763d;
+}
+.has-success .form-control-feedback {
+ color: #3c763d;
+}
+.has-warning .help-block,
+.has-warning .control-label,
+.has-warning .radio,
+.has-warning .checkbox,
+.has-warning .radio-inline,
+.has-warning .checkbox-inline,
+.has-warning.radio label,
+.has-warning.checkbox label,
+.has-warning.radio-inline label,
+.has-warning.checkbox-inline label {
+ color: #8a6d3b;
+}
+.has-warning .form-control {
+ border-color: #8a6d3b;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-warning .form-control:focus {
+ border-color: #66512c;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
+}
+.has-warning .input-group-addon {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+ border-color: #8a6d3b;
+}
+.has-warning .form-control-feedback {
+ color: #8a6d3b;
+}
+.has-error .help-block,
+.has-error .control-label,
+.has-error .radio,
+.has-error .checkbox,
+.has-error .radio-inline,
+.has-error .checkbox-inline,
+.has-error.radio label,
+.has-error.checkbox label,
+.has-error.radio-inline label,
+.has-error.checkbox-inline label {
+ color: #a94442;
+}
+.has-error .form-control {
+ border-color: #a94442;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-error .form-control:focus {
+ border-color: #843534;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
+}
+.has-error .input-group-addon {
+ color: #a94442;
+ background-color: #f2dede;
+ border-color: #a94442;
+}
+.has-error .form-control-feedback {
+ color: #a94442;
+}
+.has-feedback label ~ .form-control-feedback {
+ top: 25px;
+}
+.has-feedback label.sr-only ~ .form-control-feedback {
+ top: 0;
+}
+.help-block {
+ display: block;
+ margin-top: 5px;
+ margin-bottom: 10px;
+ color: #737373;
+}
+@media (min-width: 768px) {
+ .form-inline .form-group {
+ display: inline-block;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .form-inline .form-control {
+ display: inline-block;
+ width: auto;
+ vertical-align: middle;
+ }
+ .form-inline .form-control-static {
+ display: inline-block;
+ }
+ .form-inline .input-group {
+ display: inline-table;
+ vertical-align: middle;
+ }
+ .form-inline .input-group .input-group-addon,
+ .form-inline .input-group .input-group-btn,
+ .form-inline .input-group .form-control {
+ width: auto;
+ }
+ .form-inline .input-group > .form-control {
+ width: 100%;
+ }
+ .form-inline .control-label {
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .form-inline .radio,
+ .form-inline .checkbox {
+ display: inline-block;
+ margin-top: 0;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .form-inline .radio label,
+ .form-inline .checkbox label {
+ padding-left: 0;
+ }
+ .form-inline .radio input[type="radio"],
+ .form-inline .checkbox input[type="checkbox"] {
+ position: relative;
+ margin-left: 0;
+ }
+ .form-inline .has-feedback .form-control-feedback {
+ top: 0;
+ }
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox,
+.form-horizontal .radio-inline,
+.form-horizontal .checkbox-inline {
+ padding-top: 7px;
+ margin-top: 0;
+ margin-bottom: 0;
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox {
+ min-height: 27px;
+}
+.form-horizontal .form-group {
+ margin-right: -15px;
+ margin-left: -15px;
+}
+@media (min-width: 768px) {
+ .form-horizontal .control-label {
+ padding-top: 7px;
+ margin-bottom: 0;
+ text-align: right;
+ }
+}
+.form-horizontal .has-feedback .form-control-feedback {
+ right: 15px;
+}
+@media (min-width: 768px) {
+ .form-horizontal .form-group-lg .control-label {
+ padding-top: 14.333333px;
+ font-size: 18px;
+ }
+}
+@media (min-width: 768px) {
+ .form-horizontal .form-group-sm .control-label {
+ padding-top: 6px;
+ font-size: 12px;
+ }
+}
+.btn {
+ display: inline-block;
+ padding: 6px 12px;
+ margin-bottom: 0;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 1.42857143;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
+ -ms-touch-action: manipulation;
+ touch-action: manipulation;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ background-image: none;
+ border: 1px solid transparent;
+ border-radius: 4px;
+}
+.btn:focus,
+.btn:active:focus,
+.btn.active:focus,
+.btn.focus,
+.btn:active.focus,
+.btn.active.focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+.btn:hover,
+.btn:focus,
+.btn.focus {
+ color: #333;
+ text-decoration: none;
+}
+.btn:active,
+.btn.active {
+ background-image: none;
+ outline: 0;
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn.disabled,
+.btn[disabled],
+fieldset[disabled] .btn {
+ cursor: not-allowed;
+ filter: alpha(opacity=65);
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ opacity: .65;
+}
+a.btn.disabled,
+fieldset[disabled] a.btn {
+ pointer-events: none;
+}
+.btn-default {
+ color: #333;
+ background-color: #fff;
+ border-color: #ccc;
+}
+.btn-default:focus,
+.btn-default.focus {
+ color: #333;
+ background-color: #e6e6e6;
+ border-color: #8c8c8c;
+}
+.btn-default:hover {
+ color: #333;
+ background-color: #e6e6e6;
+ border-color: #adadad;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+ color: #333;
+ background-color: #e6e6e6;
+ border-color: #adadad;
+}
+.btn-default:active:hover,
+.btn-default.active:hover,
+.open > .dropdown-toggle.btn-default:hover,
+.btn-default:active:focus,
+.btn-default.active:focus,
+.open > .dropdown-toggle.btn-default:focus,
+.btn-default:active.focus,
+.btn-default.active.focus,
+.open > .dropdown-toggle.btn-default.focus {
+ color: #333;
+ background-color: #d4d4d4;
+ border-color: #8c8c8c;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+ background-image: none;
+}
+.btn-default.disabled,
+.btn-default[disabled],
+fieldset[disabled] .btn-default,
+.btn-default.disabled:hover,
+.btn-default[disabled]:hover,
+fieldset[disabled] .btn-default:hover,
+.btn-default.disabled:focus,
+.btn-default[disabled]:focus,
+fieldset[disabled] .btn-default:focus,
+.btn-default.disabled.focus,
+.btn-default[disabled].focus,
+fieldset[disabled] .btn-default.focus,
+.btn-default.disabled:active,
+.btn-default[disabled]:active,
+fieldset[disabled] .btn-default:active,
+.btn-default.disabled.active,
+.btn-default[disabled].active,
+fieldset[disabled] .btn-default.active {
+ background-color: #fff;
+ border-color: #ccc;
+}
+.btn-default .badge {
+ color: #fff;
+ background-color: #333;
+}
+.btn-primary {
+ color: #fff;
+ background-color: #337ab7;
+ border-color: #2e6da4;
+}
+.btn-primary:focus,
+.btn-primary.focus {
+ color: #fff;
+ background-color: #286090;
+ border-color: #122b40;
+}
+.btn-primary:hover {
+ color: #fff;
+ background-color: #286090;
+ border-color: #204d74;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+ color: #fff;
+ background-color: #286090;
+ border-color: #204d74;
+}
+.btn-primary:active:hover,
+.btn-primary.active:hover,
+.open > .dropdown-toggle.btn-primary:hover,
+.btn-primary:active:focus,
+.btn-primary.active:focus,
+.open > .dropdown-toggle.btn-primary:focus,
+.btn-primary:active.focus,
+.btn-primary.active.focus,
+.open > .dropdown-toggle.btn-primary.focus {
+ color: #fff;
+ background-color: #204d74;
+ border-color: #122b40;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+ background-image: none;
+}
+.btn-primary.disabled,
+.btn-primary[disabled],
+fieldset[disabled] .btn-primary,
+.btn-primary.disabled:hover,
+.btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover,
+.btn-primary.disabled:focus,
+.btn-primary[disabled]:focus,
+fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus,
+.btn-primary[disabled].focus,
+fieldset[disabled] .btn-primary.focus,
+.btn-primary.disabled:active,
+.btn-primary[disabled]:active,
+fieldset[disabled] .btn-primary:active,
+.btn-primary.disabled.active,
+.btn-primary[disabled].active,
+fieldset[disabled] .btn-primary.active {
+ background-color: #337ab7;
+ border-color: #2e6da4;
+}
+.btn-primary .badge {
+ color: #337ab7;
+ background-color: #fff;
+}
+.btn-success {
+ color: #fff;
+ background-color: #5cb85c;
+ border-color: #4cae4c;
+}
+.btn-success:focus,
+.btn-success.focus {
+ color: #fff;
+ background-color: #449d44;
+ border-color: #255625;
+}
+.btn-success:hover {
+ color: #fff;
+ background-color: #449d44;
+ border-color: #398439;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+ color: #fff;
+ background-color: #449d44;
+ border-color: #398439;
+}
+.btn-success:active:hover,
+.btn-success.active:hover,
+.open > .dropdown-toggle.btn-success:hover,
+.btn-success:active:focus,
+.btn-success.active:focus,
+.open > .dropdown-toggle.btn-success:focus,
+.btn-success:active.focus,
+.btn-success.active.focus,
+.open > .dropdown-toggle.btn-success.focus {
+ color: #fff;
+ background-color: #398439;
+ border-color: #255625;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+ background-image: none;
+}
+.btn-success.disabled,
+.btn-success[disabled],
+fieldset[disabled] .btn-success,
+.btn-success.disabled:hover,
+.btn-success[disabled]:hover,
+fieldset[disabled] .btn-success:hover,
+.btn-success.disabled:focus,
+.btn-success[disabled]:focus,
+fieldset[disabled] .btn-success:focus,
+.btn-success.disabled.focus,
+.btn-success[disabled].focus,
+fieldset[disabled] .btn-success.focus,
+.btn-success.disabled:active,
+.btn-success[disabled]:active,
+fieldset[disabled] .btn-success:active,
+.btn-success.disabled.active,
+.btn-success[disabled].active,
+fieldset[disabled] .btn-success.active {
+ background-color: #5cb85c;
+ border-color: #4cae4c;
+}
+.btn-success .badge {
+ color: #5cb85c;
+ background-color: #fff;
+}
+.btn-info {
+ color: #fff;
+ background-color: #5bc0de;
+ border-color: #46b8da;
+}
+.btn-info:focus,
+.btn-info.focus {
+ color: #fff;
+ background-color: #31b0d5;
+ border-color: #1b6d85;
+}
+.btn-info:hover {
+ color: #fff;
+ background-color: #31b0d5;
+ border-color: #269abc;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+ color: #fff;
+ background-color: #31b0d5;
+ border-color: #269abc;
+}
+.btn-info:active:hover,
+.btn-info.active:hover,
+.open > .dropdown-toggle.btn-info:hover,
+.btn-info:active:focus,
+.btn-info.active:focus,
+.open > .dropdown-toggle.btn-info:focus,
+.btn-info:active.focus,
+.btn-info.active.focus,
+.open > .dropdown-toggle.btn-info.focus {
+ color: #fff;
+ background-color: #269abc;
+ border-color: #1b6d85;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+ background-image: none;
+}
+.btn-info.disabled,
+.btn-info[disabled],
+fieldset[disabled] .btn-info,
+.btn-info.disabled:hover,
+.btn-info[disabled]:hover,
+fieldset[disabled] .btn-info:hover,
+.btn-info.disabled:focus,
+.btn-info[disabled]:focus,
+fieldset[disabled] .btn-info:focus,
+.btn-info.disabled.focus,
+.btn-info[disabled].focus,
+fieldset[disabled] .btn-info.focus,
+.btn-info.disabled:active,
+.btn-info[disabled]:active,
+fieldset[disabled] .btn-info:active,
+.btn-info.disabled.active,
+.btn-info[disabled].active,
+fieldset[disabled] .btn-info.active {
+ background-color: #5bc0de;
+ border-color: #46b8da;
+}
+.btn-info .badge {
+ color: #5bc0de;
+ background-color: #fff;
+}
+.btn-warning {
+ color: #fff;
+ background-color: #f0ad4e;
+ border-color: #eea236;
+}
+.btn-warning:focus,
+.btn-warning.focus {
+ color: #fff;
+ background-color: #ec971f;
+ border-color: #985f0d;
+}
+.btn-warning:hover {
+ color: #fff;
+ background-color: #ec971f;
+ border-color: #d58512;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+ color: #fff;
+ background-color: #ec971f;
+ border-color: #d58512;
+}
+.btn-warning:active:hover,
+.btn-warning.active:hover,
+.open > .dropdown-toggle.btn-warning:hover,
+.btn-warning:active:focus,
+.btn-warning.active:focus,
+.open > .dropdown-toggle.btn-warning:focus,
+.btn-warning:active.focus,
+.btn-warning.active.focus,
+.open > .dropdown-toggle.btn-warning.focus {
+ color: #fff;
+ background-color: #d58512;
+ border-color: #985f0d;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+ background-image: none;
+}
+.btn-warning.disabled,
+.btn-warning[disabled],
+fieldset[disabled] .btn-warning,
+.btn-warning.disabled:hover,
+.btn-warning[disabled]:hover,
+fieldset[disabled] .btn-warning:hover,
+.btn-warning.disabled:focus,
+.btn-warning[disabled]:focus,
+fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled.focus,
+.btn-warning[disabled].focus,
+fieldset[disabled] .btn-warning.focus,
+.btn-warning.disabled:active,
+.btn-warning[disabled]:active,
+fieldset[disabled] .btn-warning:active,
+.btn-warning.disabled.active,
+.btn-warning[disabled].active,
+fieldset[disabled] .btn-warning.active {
+ background-color: #f0ad4e;
+ border-color: #eea236;
+}
+.btn-warning .badge {
+ color: #f0ad4e;
+ background-color: #fff;
+}
+.btn-danger {
+ color: #fff;
+ background-color: #d9534f;
+ border-color: #d43f3a;
+}
+.btn-danger:focus,
+.btn-danger.focus {
+ color: #fff;
+ background-color: #c9302c;
+ border-color: #761c19;
+}
+.btn-danger:hover {
+ color: #fff;
+ background-color: #c9302c;
+ border-color: #ac2925;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+ color: #fff;
+ background-color: #c9302c;
+ border-color: #ac2925;
+}
+.btn-danger:active:hover,
+.btn-danger.active:hover,
+.open > .dropdown-toggle.btn-danger:hover,
+.btn-danger:active:focus,
+.btn-danger.active:focus,
+.open > .dropdown-toggle.btn-danger:focus,
+.btn-danger:active.focus,
+.btn-danger.active.focus,
+.open > .dropdown-toggle.btn-danger.focus {
+ color: #fff;
+ background-color: #ac2925;
+ border-color: #761c19;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+ background-image: none;
+}
+.btn-danger.disabled,
+.btn-danger[disabled],
+fieldset[disabled] .btn-danger,
+.btn-danger.disabled:hover,
+.btn-danger[disabled]:hover,
+fieldset[disabled] .btn-danger:hover,
+.btn-danger.disabled:focus,
+.btn-danger[disabled]:focus,
+fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled.focus,
+.btn-danger[disabled].focus,
+fieldset[disabled] .btn-danger.focus,
+.btn-danger.disabled:active,
+.btn-danger[disabled]:active,
+fieldset[disabled] .btn-danger:active,
+.btn-danger.disabled.active,
+.btn-danger[disabled].active,
+fieldset[disabled] .btn-danger.active {
+ background-color: #d9534f;
+ border-color: #d43f3a;
+}
+.btn-danger .badge {
+ color: #d9534f;
+ background-color: #fff;
+}
+.btn-link {
+ font-weight: normal;
+ color: #337ab7;
+ border-radius: 0;
+}
+.btn-link,
+.btn-link:active,
+.btn-link.active,
+.btn-link[disabled],
+fieldset[disabled] .btn-link {
+ background-color: transparent;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.btn-link,
+.btn-link:hover,
+.btn-link:focus,
+.btn-link:active {
+ border-color: transparent;
+}
+.btn-link:hover,
+.btn-link:focus {
+ color: #23527c;
+ text-decoration: underline;
+ background-color: transparent;
+}
+.btn-link[disabled]:hover,
+fieldset[disabled] .btn-link:hover,
+.btn-link[disabled]:focus,
+fieldset[disabled] .btn-link:focus {
+ color: #777;
+ text-decoration: none;
+}
+.btn-lg,
+.btn-group-lg > .btn {
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+ border-radius: 6px;
+}
+.btn-sm,
+.btn-group-sm > .btn {
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+.btn-xs,
+.btn-group-xs > .btn {
+ padding: 1px 5px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+.btn-block {
+ display: block;
+ width: 100%;
+}
+.btn-block + .btn-block {
+ margin-top: 5px;
+}
+input[type="submit"].btn-block,
+input[type="reset"].btn-block,
+input[type="button"].btn-block {
+ width: 100%;
+}
+.fade {
+ opacity: 0;
+ -webkit-transition: opacity .15s linear;
+ -o-transition: opacity .15s linear;
+ transition: opacity .15s linear;
+}
+.fade.in {
+ opacity: 1;
+}
+.collapse {
+ display: none;
+}
+.collapse.in {
+ display: block;
+}
+tr.collapse.in {
+ display: table-row;
+}
+tbody.collapse.in {
+ display: table-row-group;
+}
+.collapsing {
+ position: relative;
+ height: 0;
+ overflow: hidden;
+ -webkit-transition-timing-function: ease;
+ -o-transition-timing-function: ease;
+ transition-timing-function: ease;
+ -webkit-transition-duration: .35s;
+ -o-transition-duration: .35s;
+ transition-duration: .35s;
+ -webkit-transition-property: height, visibility;
+ -o-transition-property: height, visibility;
+ transition-property: height, visibility;
+}
+.caret {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ margin-left: 2px;
+ vertical-align: middle;
+ border-top: 4px dashed;
+ border-top: 4px solid \9;
+ border-right: 4px solid transparent;
+ border-left: 4px solid transparent;
+}
+.dropup,
+.dropdown {
+ position: relative;
+}
+.dropdown-toggle:focus {
+ outline: 0;
+}
+.dropdown-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ z-index: 1000;
+ display: none;
+ float: left;
+ min-width: 160px;
+ padding: 5px 0;
+ margin: 2px 0 0;
+ font-size: 14px;
+ text-align: left;
+ list-style: none;
+ background-color: #fff;
+ -webkit-background-clip: padding-box;
+ background-clip: padding-box;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, .15);
+ border-radius: 4px;
+ -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+ box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+}
+.dropdown-menu.pull-right {
+ right: 0;
+ left: auto;
+}
+.dropdown-menu .divider {
+ height: 1px;
+ margin: 9px 0;
+ overflow: hidden;
+ background-color: #e5e5e5;
+}
+.dropdown-menu > li > a {
+ display: block;
+ padding: 3px 20px;
+ clear: both;
+ font-weight: normal;
+ line-height: 1.42857143;
+ color: #333;
+ white-space: nowrap;
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+ color: #262626;
+ text-decoration: none;
+ background-color: #f5f5f5;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+ color: #fff;
+ text-decoration: none;
+ background-color: #337ab7;
+ outline: 0;
+}
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ color: #777;
+}
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ text-decoration: none;
+ cursor: not-allowed;
+ background-color: transparent;
+ background-image: none;
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
+.open > .dropdown-menu {
+ display: block;
+}
+.open > a {
+ outline: 0;
+}
+.dropdown-menu-right {
+ right: 0;
+ left: auto;
+}
+.dropdown-menu-left {
+ right: auto;
+ left: 0;
+}
+.dropdown-header {
+ display: block;
+ padding: 3px 20px;
+ font-size: 12px;
+ line-height: 1.42857143;
+ color: #777;
+ white-space: nowrap;
+}
+.dropdown-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 990;
+}
+.pull-right > .dropdown-menu {
+ right: 0;
+ left: auto;
+}
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+ content: "";
+ border-top: 0;
+ border-bottom: 4px dashed;
+ border-bottom: 4px solid \9;
+}
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+ top: auto;
+ bottom: 100%;
+ margin-bottom: 2px;
+}
+@media (min-width: 768px) {
+ .navbar-right .dropdown-menu {
+ right: 0;
+ left: auto;
+ }
+ .navbar-right .dropdown-menu-left {
+ right: auto;
+ left: 0;
+ }
+}
+.btn-group,
+.btn-group-vertical {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+}
+.btn-group > .btn,
+.btn-group-vertical > .btn {
+ position: relative;
+ float: left;
+}
+.btn-group > .btn:hover,
+.btn-group-vertical > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group-vertical > .btn:focus,
+.btn-group > .btn:active,
+.btn-group-vertical > .btn:active,
+.btn-group > .btn.active,
+.btn-group-vertical > .btn.active {
+ z-index: 2;
+}
+.btn-group .btn + .btn,
+.btn-group .btn + .btn-group,
+.btn-group .btn-group + .btn,
+.btn-group .btn-group + .btn-group {
+ margin-left: -1px;
+}
+.btn-toolbar {
+ margin-left: -5px;
+}
+.btn-toolbar .btn,
+.btn-toolbar .btn-group,
+.btn-toolbar .input-group {
+ float: left;
+}
+.btn-toolbar > .btn,
+.btn-toolbar > .btn-group,
+.btn-toolbar > .input-group {
+ margin-left: 5px;
+}
+.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
+ border-radius: 0;
+}
+.btn-group > .btn:first-child {
+ margin-left: 0;
+}
+.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.btn-group > .btn:last-child:not(:first-child),
+.btn-group > .dropdown-toggle:not(:first-child) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group > .btn-group {
+ float: left;
+}
+.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
+ border-radius: 0;
+}
+.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+ outline: 0;
+}
+.btn-group > .btn + .dropdown-toggle {
+ padding-right: 8px;
+ padding-left: 8px;
+}
+.btn-group > .btn-lg + .dropdown-toggle {
+ padding-right: 12px;
+ padding-left: 12px;
+}
+.btn-group.open .dropdown-toggle {
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn-group.open .dropdown-toggle.btn-link {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.btn .caret {
+ margin-left: 0;
+}
+.btn-lg .caret {
+ border-width: 5px 5px 0;
+ border-bottom-width: 0;
+}
+.dropup .btn-lg .caret {
+ border-width: 0 5px 5px;
+}
+.btn-group-vertical > .btn,
+.btn-group-vertical > .btn-group,
+.btn-group-vertical > .btn-group > .btn {
+ display: block;
+ float: none;
+ width: 100%;
+ max-width: 100%;
+}
+.btn-group-vertical > .btn-group > .btn {
+ float: none;
+}
+.btn-group-vertical > .btn + .btn,
+.btn-group-vertical > .btn + .btn-group,
+.btn-group-vertical > .btn-group + .btn,
+.btn-group-vertical > .btn-group + .btn-group {
+ margin-top: -1px;
+ margin-left: 0;
+}
+.btn-group-vertical > .btn:not(:first-child):not(:last-child) {
+ border-radius: 0;
+}
+.btn-group-vertical > .btn:first-child:not(:last-child) {
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn:last-child:not(:first-child) {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-left-radius: 4px;
+}
+.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
+ border-radius: 0;
+}
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+.btn-group-justified {
+ display: table;
+ width: 100%;
+ table-layout: fixed;
+ border-collapse: separate;
+}
+.btn-group-justified > .btn,
+.btn-group-justified > .btn-group {
+ display: table-cell;
+ float: none;
+ width: 1%;
+}
+.btn-group-justified > .btn-group .btn {
+ width: 100%;
+}
+.btn-group-justified > .btn-group .dropdown-menu {
+ left: auto;
+}
+[data-toggle="buttons"] > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn input[type="checkbox"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
+ position: absolute;
+ clip: rect(0, 0, 0, 0);
+ pointer-events: none;
+}
+.input-group {
+ position: relative;
+ display: table;
+ border-collapse: separate;
+}
+.input-group[class*="col-"] {
+ float: none;
+ padding-right: 0;
+ padding-left: 0;
+}
+.input-group .form-control {
+ position: relative;
+ z-index: 2;
+ float: left;
+ width: 100%;
+ margin-bottom: 0;
+}
+.input-group-lg > .form-control,
+.input-group-lg > .input-group-addon,
+.input-group-lg > .input-group-btn > .btn {
+ height: 46px;
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+ border-radius: 6px;
+}
+select.input-group-lg > .form-control,
+select.input-group-lg > .input-group-addon,
+select.input-group-lg > .input-group-btn > .btn {
+ height: 46px;
+ line-height: 46px;
+}
+textarea.input-group-lg > .form-control,
+textarea.input-group-lg > .input-group-addon,
+textarea.input-group-lg > .input-group-btn > .btn,
+select[multiple].input-group-lg > .form-control,
+select[multiple].input-group-lg > .input-group-addon,
+select[multiple].input-group-lg > .input-group-btn > .btn {
+ height: auto;
+}
+.input-group-sm > .form-control,
+.input-group-sm > .input-group-addon,
+.input-group-sm > .input-group-btn > .btn {
+ height: 30px;
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+select.input-group-sm > .form-control,
+select.input-group-sm > .input-group-addon,
+select.input-group-sm > .input-group-btn > .btn {
+ height: 30px;
+ line-height: 30px;
+}
+textarea.input-group-sm > .form-control,
+textarea.input-group-sm > .input-group-addon,
+textarea.input-group-sm > .input-group-btn > .btn,
+select[multiple].input-group-sm > .form-control,
+select[multiple].input-group-sm > .input-group-addon,
+select[multiple].input-group-sm > .input-group-btn > .btn {
+ height: auto;
+}
+.input-group-addon,
+.input-group-btn,
+.input-group .form-control {
+ display: table-cell;
+}
+.input-group-addon:not(:first-child):not(:last-child),
+.input-group-btn:not(:first-child):not(:last-child),
+.input-group .form-control:not(:first-child):not(:last-child) {
+ border-radius: 0;
+}
+.input-group-addon,
+.input-group-btn {
+ width: 1%;
+ white-space: nowrap;
+ vertical-align: middle;
+}
+.input-group-addon {
+ padding: 6px 12px;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 1;
+ color: #555;
+ text-align: center;
+ background-color: #eee;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+}
+.input-group-addon.input-sm {
+ padding: 5px 10px;
+ font-size: 12px;
+ border-radius: 3px;
+}
+.input-group-addon.input-lg {
+ padding: 10px 16px;
+ font-size: 18px;
+ border-radius: 6px;
+}
+.input-group-addon input[type="radio"],
+.input-group-addon input[type="checkbox"] {
+ margin-top: 0;
+}
+.input-group .form-control:first-child,
+.input-group-addon:first-child,
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group > .btn,
+.input-group-btn:first-child > .dropdown-toggle,
+.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.input-group-addon:first-child {
+ border-right: 0;
+}
+.input-group .form-control:last-child,
+.input-group-addon:last-child,
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group > .btn,
+.input-group-btn:last-child > .dropdown-toggle,
+.input-group-btn:first-child > .btn:not(:first-child),
+.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.input-group-addon:last-child {
+ border-left: 0;
+}
+.input-group-btn {
+ position: relative;
+ font-size: 0;
+ white-space: nowrap;
+}
+.input-group-btn > .btn {
+ position: relative;
+}
+.input-group-btn > .btn + .btn {
+ margin-left: -1px;
+}
+.input-group-btn > .btn:hover,
+.input-group-btn > .btn:focus,
+.input-group-btn > .btn:active {
+ z-index: 2;
+}
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group {
+ margin-right: -1px;
+}
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group {
+ z-index: 2;
+ margin-left: -1px;
+}
+.nav {
+ padding-left: 0;
+ margin-bottom: 0;
+ list-style: none;
+}
+.nav > li {
+ position: relative;
+ display: block;
+}
+.nav > li > a {
+ position: relative;
+ display: block;
+ padding: 10px 15px;
+}
+.nav > li > a:hover,
+.nav > li > a:focus {
+ text-decoration: none;
+ background-color: #eee;
+}
+.nav > li.disabled > a {
+ color: #777;
+}
+.nav > li.disabled > a:hover,
+.nav > li.disabled > a:focus {
+ color: #777;
+ text-decoration: none;
+ cursor: not-allowed;
+ background-color: transparent;
+}
+.nav .open > a,
+.nav .open > a:hover,
+.nav .open > a:focus {
+ background-color: #eee;
+ border-color: #337ab7;
+}
+.nav .nav-divider {
+ height: 1px;
+ margin: 9px 0;
+ overflow: hidden;
+ background-color: #e5e5e5;
+}
+.nav > li > a > img {
+ max-width: none;
+}
+.nav-tabs {
+ border-bottom: 1px solid #ddd;
+}
+.nav-tabs > li {
+ float: left;
+ margin-bottom: -1px;
+}
+.nav-tabs > li > a {
+ margin-right: 2px;
+ line-height: 1.42857143;
+ border: 1px solid transparent;
+ border-radius: 4px 4px 0 0;
+}
+.nav-tabs > li > a:hover {
+ border-color: #eee #eee #ddd;
+}
+.nav-tabs > li.active > a,
+.nav-tabs > li.active > a:hover,
+.nav-tabs > li.active > a:focus {
+ color: #555;
+ cursor: default;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ border-bottom-color: transparent;
+}
+.nav-tabs.nav-justified {
+ width: 100%;
+ border-bottom: 0;
+}
+.nav-tabs.nav-justified > li {
+ float: none;
+}
+.nav-tabs.nav-justified > li > a {
+ margin-bottom: 5px;
+ text-align: center;
+}
+.nav-tabs.nav-justified > .dropdown .dropdown-menu {
+ top: auto;
+ left: auto;
+}
+@media (min-width: 768px) {
+ .nav-tabs.nav-justified > li {
+ display: table-cell;
+ width: 1%;
+ }
+ .nav-tabs.nav-justified > li > a {
+ margin-bottom: 0;
+ }
+}
+.nav-tabs.nav-justified > li > a {
+ margin-right: 0;
+ border-radius: 4px;
+}
+.nav-tabs.nav-justified > .active > a,
+.nav-tabs.nav-justified > .active > a:hover,
+.nav-tabs.nav-justified > .active > a:focus {
+ border: 1px solid #ddd;
+}
+@media (min-width: 768px) {
+ .nav-tabs.nav-justified > li > a {
+ border-bottom: 1px solid #ddd;
+ border-radius: 4px 4px 0 0;
+ }
+ .nav-tabs.nav-justified > .active > a,
+ .nav-tabs.nav-justified > .active > a:hover,
+ .nav-tabs.nav-justified > .active > a:focus {
+ border-bottom-color: #fff;
+ }
+}
+.nav-pills > li {
+ float: left;
+}
+.nav-pills > li > a {
+ border-radius: 4px;
+}
+.nav-pills > li + li {
+ margin-left: 2px;
+}
+.nav-pills > li.active > a,
+.nav-pills > li.active > a:hover,
+.nav-pills > li.active > a:focus {
+ color: #fff;
+ background-color: #337ab7;
+}
+.nav-stacked > li {
+ float: none;
+}
+.nav-stacked > li + li {
+ margin-top: 2px;
+ margin-left: 0;
+}
+.nav-justified {
+ width: 100%;
+}
+.nav-justified > li {
+ float: none;
+}
+.nav-justified > li > a {
+ margin-bottom: 5px;
+ text-align: center;
+}
+.nav-justified > .dropdown .dropdown-menu {
+ top: auto;
+ left: auto;
+}
+@media (min-width: 768px) {
+ .nav-justified > li {
+ display: table-cell;
+ width: 1%;
+ }
+ .nav-justified > li > a {
+ margin-bottom: 0;
+ }
+}
+.nav-tabs-justified {
+ border-bottom: 0;
+}
+.nav-tabs-justified > li > a {
+ margin-right: 0;
+ border-radius: 4px;
+}
+.nav-tabs-justified > .active > a,
+.nav-tabs-justified > .active > a:hover,
+.nav-tabs-justified > .active > a:focus {
+ border: 1px solid #ddd;
+}
+@media (min-width: 768px) {
+ .nav-tabs-justified > li > a {
+ border-bottom: 1px solid #ddd;
+ border-radius: 4px 4px 0 0;
+ }
+ .nav-tabs-justified > .active > a,
+ .nav-tabs-justified > .active > a:hover,
+ .nav-tabs-justified > .active > a:focus {
+ border-bottom-color: #fff;
+ }
+}
+.tab-content > .tab-pane {
+ display: none;
+}
+.tab-content > .active {
+ display: block;
+}
+.nav-tabs .dropdown-menu {
+ margin-top: -1px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+.navbar {
+ position: relative;
+ min-height: 50px;
+ margin-bottom: 20px;
+ border: 1px solid transparent;
+}
+@media (min-width: 768px) {
+ .navbar {
+ border-radius: 4px;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-header {
+ float: left;
+ }
+}
+.navbar-collapse {
+ padding-right: 15px;
+ padding-left: 15px;
+ overflow-x: visible;
+ -webkit-overflow-scrolling: touch;
+ border-top: 1px solid transparent;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
+}
+.navbar-collapse.in {
+ overflow-y: auto;
+}
+@media (min-width: 768px) {
+ .navbar-collapse {
+ width: auto;
+ border-top: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ }
+ .navbar-collapse.collapse {
+ display: block !important;
+ height: auto !important;
+ padding-bottom: 0;
+ overflow: visible !important;
+ }
+ .navbar-collapse.in {
+ overflow-y: visible;
+ }
+ .navbar-fixed-top .navbar-collapse,
+ .navbar-static-top .navbar-collapse,
+ .navbar-fixed-bottom .navbar-collapse {
+ padding-right: 0;
+ padding-left: 0;
+ }
+}
+.navbar-fixed-top .navbar-collapse,
+.navbar-fixed-bottom .navbar-collapse {
+ max-height: 340px;
+}
+@media (max-device-width: 480px) and (orientation: landscape) {
+ .navbar-fixed-top .navbar-collapse,
+ .navbar-fixed-bottom .navbar-collapse {
+ max-height: 200px;
+ }
+}
+.container > .navbar-header,
+.container-fluid > .navbar-header,
+.container > .navbar-collapse,
+.container-fluid > .navbar-collapse {
+ margin-right: -15px;
+ margin-left: -15px;
+}
+@media (min-width: 768px) {
+ .container > .navbar-header,
+ .container-fluid > .navbar-header,
+ .container > .navbar-collapse,
+ .container-fluid > .navbar-collapse {
+ margin-right: 0;
+ margin-left: 0;
+ }
+}
+.navbar-static-top {
+ z-index: 1000;
+ border-width: 0 0 1px;
+}
+@media (min-width: 768px) {
+ .navbar-static-top {
+ border-radius: 0;
+ }
+}
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ position: fixed;
+ right: 0;
+ left: 0;
+ z-index: 1030;
+}
+@media (min-width: 768px) {
+ .navbar-fixed-top,
+ .navbar-fixed-bottom {
+ border-radius: 0;
+ }
+}
+.navbar-fixed-top {
+ top: 0;
+ border-width: 0 0 1px;
+}
+.navbar-fixed-bottom {
+ bottom: 0;
+ margin-bottom: 0;
+ border-width: 1px 0 0;
+}
+.navbar-brand {
+ float: left;
+ height: 50px;
+ padding: 15px 15px;
+ font-size: 18px;
+ line-height: 20px;
+}
+.navbar-brand:hover,
+.navbar-brand:focus {
+ text-decoration: none;
+}
+.navbar-brand > img {
+ display: block;
+}
+@media (min-width: 768px) {
+ .navbar > .container .navbar-brand,
+ .navbar > .container-fluid .navbar-brand {
+ margin-left: -15px;
+ }
+}
+.navbar-toggle {
+ position: relative;
+ float: right;
+ padding: 9px 10px;
+ margin-top: 8px;
+ margin-right: 15px;
+ margin-bottom: 8px;
+ background-color: transparent;
+ background-image: none;
+ border: 1px solid transparent;
+ border-radius: 4px;
+}
+.navbar-toggle:focus {
+ outline: 0;
+}
+.navbar-toggle .icon-bar {
+ display: block;
+ width: 22px;
+ height: 2px;
+ border-radius: 1px;
+}
+.navbar-toggle .icon-bar + .icon-bar {
+ margin-top: 4px;
+}
+@media (min-width: 768px) {
+ .navbar-toggle {
+ display: none;
+ }
+}
+.navbar-nav {
+ margin: 7.5px -15px;
+}
+.navbar-nav > li > a {
+ padding-top: 10px;
+ padding-bottom: 10px;
+ line-height: 20px;
+}
+@media (max-width: 767px) {
+ .navbar-nav .open .dropdown-menu {
+ position: static;
+ float: none;
+ width: auto;
+ margin-top: 0;
+ background-color: transparent;
+ border: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ }
+ .navbar-nav .open .dropdown-menu > li > a,
+ .navbar-nav .open .dropdown-menu .dropdown-header {
+ padding: 5px 15px 5px 25px;
+ }
+ .navbar-nav .open .dropdown-menu > li > a {
+ line-height: 20px;
+ }
+ .navbar-nav .open .dropdown-menu > li > a:hover,
+ .navbar-nav .open .dropdown-menu > li > a:focus {
+ background-image: none;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-nav {
+ float: left;
+ margin: 0;
+ }
+ .navbar-nav > li {
+ float: left;
+ }
+ .navbar-nav > li > a {
+ padding-top: 15px;
+ padding-bottom: 15px;
+ }
+}
+.navbar-form {
+ padding: 10px 15px;
+ margin-top: 8px;
+ margin-right: -15px;
+ margin-bottom: 8px;
+ margin-left: -15px;
+ border-top: 1px solid transparent;
+ border-bottom: 1px solid transparent;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
+}
+@media (min-width: 768px) {
+ .navbar-form .form-group {
+ display: inline-block;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .navbar-form .form-control {
+ display: inline-block;
+ width: auto;
+ vertical-align: middle;
+ }
+ .navbar-form .form-control-static {
+ display: inline-block;
+ }
+ .navbar-form .input-group {
+ display: inline-table;
+ vertical-align: middle;
+ }
+ .navbar-form .input-group .input-group-addon,
+ .navbar-form .input-group .input-group-btn,
+ .navbar-form .input-group .form-control {
+ width: auto;
+ }
+ .navbar-form .input-group > .form-control {
+ width: 100%;
+ }
+ .navbar-form .control-label {
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .navbar-form .radio,
+ .navbar-form .checkbox {
+ display: inline-block;
+ margin-top: 0;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .navbar-form .radio label,
+ .navbar-form .checkbox label {
+ padding-left: 0;
+ }
+ .navbar-form .radio input[type="radio"],
+ .navbar-form .checkbox input[type="checkbox"] {
+ position: relative;
+ margin-left: 0;
+ }
+ .navbar-form .has-feedback .form-control-feedback {
+ top: 0;
+ }
+}
+@media (max-width: 767px) {
+ .navbar-form .form-group {
+ margin-bottom: 5px;
+ }
+ .navbar-form .form-group:last-child {
+ margin-bottom: 0;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-form {
+ width: auto;
+ padding-top: 0;
+ padding-bottom: 0;
+ margin-right: 0;
+ margin-left: 0;
+ border: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ }
+}
+.navbar-nav > li > .dropdown-menu {
+ margin-top: 0;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
+ margin-bottom: 0;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.navbar-btn {
+ margin-top: 8px;
+ margin-bottom: 8px;
+}
+.navbar-btn.btn-sm {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+.navbar-btn.btn-xs {
+ margin-top: 14px;
+ margin-bottom: 14px;
+}
+.navbar-text {
+ margin-top: 15px;
+ margin-bottom: 15px;
+}
+@media (min-width: 768px) {
+ .navbar-text {
+ float: left;
+ margin-right: 15px;
+ margin-left: 15px;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-left {
+ float: left !important;
+ }
+ .navbar-right {
+ float: right !important;
+ margin-right: -15px;
+ }
+ .navbar-right ~ .navbar-right {
+ margin-right: 0;
+ }
+}
+.navbar-default {
+ background-color: #f8f8f8;
+ border-color: #e7e7e7;
+}
+.navbar-default .navbar-brand {
+ color: #777;
+}
+.navbar-default .navbar-brand:hover,
+.navbar-default .navbar-brand:focus {
+ color: #5e5e5e;
+ background-color: transparent;
+}
+.navbar-default .navbar-text {
+ color: #777;
+}
+.navbar-default .navbar-nav > li > a {
+ color: #777;
+}
+.navbar-default .navbar-nav > li > a:hover,
+.navbar-default .navbar-nav > li > a:focus {
+ color: #333;
+ background-color: transparent;
+}
+.navbar-default .navbar-nav > .active > a,
+.navbar-default .navbar-nav > .active > a:hover,
+.navbar-default .navbar-nav > .active > a:focus {
+ color: #555;
+ background-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .disabled > a,
+.navbar-default .navbar-nav > .disabled > a:hover,
+.navbar-default .navbar-nav > .disabled > a:focus {
+ color: #ccc;
+ background-color: transparent;
+}
+.navbar-default .navbar-toggle {
+ border-color: #ddd;
+}
+.navbar-default .navbar-toggle:hover,
+.navbar-default .navbar-toggle:focus {
+ background-color: #ddd;
+}
+.navbar-default .navbar-toggle .icon-bar {
+ background-color: #888;
+}
+.navbar-default .navbar-collapse,
+.navbar-default .navbar-form {
+ border-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .open > a:hover,
+.navbar-default .navbar-nav > .open > a:focus {
+ color: #555;
+ background-color: #e7e7e7;
+}
+@media (max-width: 767px) {
+ .navbar-default .navbar-nav .open .dropdown-menu > li > a {
+ color: #777;
+ }
+ .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
+ .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
+ color: #333;
+ background-color: transparent;
+ }
+ .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
+ .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
+ .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
+ color: #555;
+ background-color: #e7e7e7;
+ }
+ .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
+ .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+ .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+ color: #ccc;
+ background-color: transparent;
+ }
+}
+.navbar-default .navbar-link {
+ color: #777;
+}
+.navbar-default .navbar-link:hover {
+ color: #333;
+}
+.navbar-default .btn-link {
+ color: #777;
+}
+.navbar-default .btn-link:hover,
+.navbar-default .btn-link:focus {
+ color: #333;
+}
+.navbar-default .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-default .btn-link:hover,
+.navbar-default .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-default .btn-link:focus {
+ color: #ccc;
+}
+.navbar-inverse {
+ background-color: #222;
+ border-color: #080808;
+}
+.navbar-inverse .navbar-brand {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-brand:hover,
+.navbar-inverse .navbar-brand:focus {
+ color: #fff;
+ background-color: transparent;
+}
+.navbar-inverse .navbar-text {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a:hover,
+.navbar-inverse .navbar-nav > li > a:focus {
+ color: #fff;
+ background-color: transparent;
+}
+.navbar-inverse .navbar-nav > .active > a,
+.navbar-inverse .navbar-nav > .active > a:hover,
+.navbar-inverse .navbar-nav > .active > a:focus {
+ color: #fff;
+ background-color: #080808;
+}
+.navbar-inverse .navbar-nav > .disabled > a,
+.navbar-inverse .navbar-nav > .disabled > a:hover,
+.navbar-inverse .navbar-nav > .disabled > a:focus {
+ color: #444;
+ background-color: transparent;
+}
+.navbar-inverse .navbar-toggle {
+ border-color: #333;
+}
+.navbar-inverse .navbar-toggle:hover,
+.navbar-inverse .navbar-toggle:focus {
+ background-color: #333;
+}
+.navbar-inverse .navbar-toggle .icon-bar {
+ background-color: #fff;
+}
+.navbar-inverse .navbar-collapse,
+.navbar-inverse .navbar-form {
+ border-color: #101010;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .open > a:hover,
+.navbar-inverse .navbar-nav > .open > a:focus {
+ color: #fff;
+ background-color: #080808;
+}
+@media (max-width: 767px) {
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
+ border-color: #080808;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
+ background-color: #080808;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
+ color: #9d9d9d;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
+ color: #fff;
+ background-color: transparent;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
+ color: #fff;
+ background-color: #080808;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+ color: #444;
+ background-color: transparent;
+ }
+}
+.navbar-inverse .navbar-link {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-link:hover {
+ color: #fff;
+}
+.navbar-inverse .btn-link {
+ color: #9d9d9d;
+}
+.navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link:focus {
+ color: #fff;
+}
+.navbar-inverse .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-inverse .btn-link:focus {
+ color: #444;
+}
+.breadcrumb {
+ padding: 8px 15px;
+ margin-bottom: 20px;
+ list-style: none;
+ background-color: #f5f5f5;
+ border-radius: 4px;
+}
+.breadcrumb > li {
+ display: inline-block;
+}
+.breadcrumb > li + li:before {
+ padding: 0 5px;
+ color: #ccc;
+ content: "/\00a0";
+}
+.breadcrumb > .active {
+ color: #777;
+}
+.pagination {
+ display: inline-block;
+ padding-left: 0;
+ margin: 20px 0;
+ border-radius: 4px;
+}
+.pagination > li {
+ display: inline;
+}
+.pagination > li > a,
+.pagination > li > span {
+ position: relative;
+ float: left;
+ padding: 6px 12px;
+ margin-left: -1px;
+ line-height: 1.42857143;
+ color: #337ab7;
+ text-decoration: none;
+ background-color: #fff;
+ border: 1px solid #ddd;
+}
+.pagination > li:first-child > a,
+.pagination > li:first-child > span {
+ margin-left: 0;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+.pagination > li:last-child > a,
+.pagination > li:last-child > span {
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+}
+.pagination > li > a:hover,
+.pagination > li > span:hover,
+.pagination > li > a:focus,
+.pagination > li > span:focus {
+ z-index: 3;
+ color: #23527c;
+ background-color: #eee;
+ border-color: #ddd;
+}
+.pagination > .active > a,
+.pagination > .active > span,
+.pagination > .active > a:hover,
+.pagination > .active > span:hover,
+.pagination > .active > a:focus,
+.pagination > .active > span:focus {
+ z-index: 2;
+ color: #fff;
+ cursor: default;
+ background-color: #337ab7;
+ border-color: #337ab7;
+}
+.pagination > .disabled > span,
+.pagination > .disabled > span:hover,
+.pagination > .disabled > span:focus,
+.pagination > .disabled > a,
+.pagination > .disabled > a:hover,
+.pagination > .disabled > a:focus {
+ color: #777;
+ cursor: not-allowed;
+ background-color: #fff;
+ border-color: #ddd;
+}
+.pagination-lg > li > a,
+.pagination-lg > li > span {
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+}
+.pagination-lg > li:first-child > a,
+.pagination-lg > li:first-child > span {
+ border-top-left-radius: 6px;
+ border-bottom-left-radius: 6px;
+}
+.pagination-lg > li:last-child > a,
+.pagination-lg > li:last-child > span {
+ border-top-right-radius: 6px;
+ border-bottom-right-radius: 6px;
+}
+.pagination-sm > li > a,
+.pagination-sm > li > span {
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+}
+.pagination-sm > li:first-child > a,
+.pagination-sm > li:first-child > span {
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.pagination-sm > li:last-child > a,
+.pagination-sm > li:last-child > span {
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+.pager {
+ padding-left: 0;
+ margin: 20px 0;
+ text-align: center;
+ list-style: none;
+}
+.pager li {
+ display: inline;
+}
+.pager li > a,
+.pager li > span {
+ display: inline-block;
+ padding: 5px 14px;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ border-radius: 15px;
+}
+.pager li > a:hover,
+.pager li > a:focus {
+ text-decoration: none;
+ background-color: #eee;
+}
+.pager .next > a,
+.pager .next > span {
+ float: right;
+}
+.pager .previous > a,
+.pager .previous > span {
+ float: left;
+}
+.pager .disabled > a,
+.pager .disabled > a:hover,
+.pager .disabled > a:focus,
+.pager .disabled > span {
+ color: #777;
+ cursor: not-allowed;
+ background-color: #fff;
+}
+.label {
+ display: inline;
+ padding: .2em .6em .3em;
+ font-size: 75%;
+ font-weight: bold;
+ line-height: 1;
+ color: #fff;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ border-radius: .25em;
+}
+a.label:hover,
+a.label:focus {
+ color: #fff;
+ text-decoration: none;
+ cursor: pointer;
+}
+.label:empty {
+ display: none;
+}
+.btn .label {
+ position: relative;
+ top: -1px;
+}
+.label-default {
+ background-color: #777;
+}
+.label-default[href]:hover,
+.label-default[href]:focus {
+ background-color: #5e5e5e;
+}
+.label-primary {
+ background-color: #337ab7;
+}
+.label-primary[href]:hover,
+.label-primary[href]:focus {
+ background-color: #286090;
+}
+.label-success {
+ background-color: #5cb85c;
+}
+.label-success[href]:hover,
+.label-success[href]:focus {
+ background-color: #449d44;
+}
+.label-info {
+ background-color: #5bc0de;
+}
+.label-info[href]:hover,
+.label-info[href]:focus {
+ background-color: #31b0d5;
+}
+.label-warning {
+ background-color: #f0ad4e;
+}
+.label-warning[href]:hover,
+.label-warning[href]:focus {
+ background-color: #ec971f;
+}
+.label-danger {
+ background-color: #d9534f;
+}
+.label-danger[href]:hover,
+.label-danger[href]:focus {
+ background-color: #c9302c;
+}
+.badge {
+ display: inline-block;
+ min-width: 10px;
+ padding: 3px 7px;
+ font-size: 12px;
+ font-weight: bold;
+ line-height: 1;
+ color: #fff;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
+ background-color: #777;
+ border-radius: 10px;
+}
+.badge:empty {
+ display: none;
+}
+.btn .badge {
+ position: relative;
+ top: -1px;
+}
+.btn-xs .badge,
+.btn-group-xs > .btn .badge {
+ top: 0;
+ padding: 1px 5px;
+}
+a.badge:hover,
+a.badge:focus {
+ color: #fff;
+ text-decoration: none;
+ cursor: pointer;
+}
+.list-group-item.active > .badge,
+.nav-pills > .active > a > .badge {
+ color: #337ab7;
+ background-color: #fff;
+}
+.list-group-item > .badge {
+ float: right;
+}
+.list-group-item > .badge + .badge {
+ margin-right: 5px;
+}
+.nav-pills > li > a > .badge {
+ margin-left: 3px;
+}
+.jumbotron {
+ padding-top: 30px;
+ padding-bottom: 30px;
+ margin-bottom: 30px;
+ color: inherit;
+ background-color: #eee;
+}
+.jumbotron h1,
+.jumbotron .h1 {
+ color: inherit;
+}
+.jumbotron p {
+ margin-bottom: 15px;
+ font-size: 21px;
+ font-weight: 200;
+}
+.jumbotron > hr {
+ border-top-color: #d5d5d5;
+}
+.container .jumbotron,
+.container-fluid .jumbotron {
+ border-radius: 6px;
+}
+.jumbotron .container {
+ max-width: 100%;
+}
+@media screen and (min-width: 768px) {
+ .jumbotron {
+ padding-top: 48px;
+ padding-bottom: 48px;
+ }
+ .container .jumbotron,
+ .container-fluid .jumbotron {
+ padding-right: 60px;
+ padding-left: 60px;
+ }
+ .jumbotron h1,
+ .jumbotron .h1 {
+ font-size: 63px;
+ }
+}
+.thumbnail {
+ display: block;
+ padding: 4px;
+ margin-bottom: 20px;
+ line-height: 1.42857143;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ -webkit-transition: border .2s ease-in-out;
+ -o-transition: border .2s ease-in-out;
+ transition: border .2s ease-in-out;
+}
+.thumbnail > img,
+.thumbnail a > img {
+ margin-right: auto;
+ margin-left: auto;
+}
+a.thumbnail:hover,
+a.thumbnail:focus,
+a.thumbnail.active {
+ border-color: #337ab7;
+}
+.thumbnail .caption {
+ padding: 9px;
+ color: #333;
+}
+.alert {
+ padding: 15px;
+ margin-bottom: 20px;
+ border: 1px solid transparent;
+ border-radius: 4px;
+}
+.alert h4 {
+ margin-top: 0;
+ color: inherit;
+}
+.alert .alert-link {
+ font-weight: bold;
+}
+.alert > p,
+.alert > ul {
+ margin-bottom: 0;
+}
+.alert > p + p {
+ margin-top: 5px;
+}
+.alert-dismissable,
+.alert-dismissible {
+ padding-right: 35px;
+}
+.alert-dismissable .close,
+.alert-dismissible .close {
+ position: relative;
+ top: -2px;
+ right: -21px;
+ color: inherit;
+}
+.alert-success {
+ color: #3c763d;
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+}
+.alert-success hr {
+ border-top-color: #c9e2b3;
+}
+.alert-success .alert-link {
+ color: #2b542c;
+}
+.alert-info {
+ color: #31708f;
+ background-color: #d9edf7;
+ border-color: #bce8f1;
+}
+.alert-info hr {
+ border-top-color: #a6e1ec;
+}
+.alert-info .alert-link {
+ color: #245269;
+}
+.alert-warning {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+ border-color: #faebcc;
+}
+.alert-warning hr {
+ border-top-color: #f7e1b5;
+}
+.alert-warning .alert-link {
+ color: #66512c;
+}
+.alert-danger {
+ color: #a94442;
+ background-color: #f2dede;
+ border-color: #ebccd1;
+}
+.alert-danger hr {
+ border-top-color: #e4b9c0;
+}
+.alert-danger .alert-link {
+ color: #843534;
+}
+@-webkit-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+@-o-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+@keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+.progress {
+ height: 20px;
+ margin-bottom: 20px;
+ overflow: hidden;
+ background-color: #f5f5f5;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+}
+.progress-bar {
+ float: left;
+ width: 0;
+ height: 100%;
+ font-size: 12px;
+ line-height: 20px;
+ color: #fff;
+ text-align: center;
+ background-color: #337ab7;
+ -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
+ -webkit-transition: width .6s ease;
+ -o-transition: width .6s ease;
+ transition: width .6s ease;
+}
+.progress-striped .progress-bar,
+.progress-bar-striped {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ -webkit-background-size: 40px 40px;
+ background-size: 40px 40px;
+}
+.progress.active .progress-bar,
+.progress-bar.active {
+ -webkit-animation: progress-bar-stripes 2s linear infinite;
+ -o-animation: progress-bar-stripes 2s linear infinite;
+ animation: progress-bar-stripes 2s linear infinite;
+}
+.progress-bar-success {
+ background-color: #5cb85c;
+}
+.progress-striped .progress-bar-success {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-info {
+ background-color: #5bc0de;
+}
+.progress-striped .progress-bar-info {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-warning {
+ background-color: #f0ad4e;
+}
+.progress-striped .progress-bar-warning {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-danger {
+ background-color: #d9534f;
+}
+.progress-striped .progress-bar-danger {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.media {
+ margin-top: 15px;
+}
+.media:first-child {
+ margin-top: 0;
+}
+.media,
+.media-body {
+ overflow: hidden;
+ zoom: 1;
+}
+.media-body {
+ width: 10000px;
+}
+.media-object {
+ display: block;
+}
+.media-object.img-thumbnail {
+ max-width: none;
+}
+.media-right,
+.media > .pull-right {
+ padding-left: 10px;
+}
+.media-left,
+.media > .pull-left {
+ padding-right: 10px;
+}
+.media-left,
+.media-right,
+.media-body {
+ display: table-cell;
+ vertical-align: top;
+}
+.media-middle {
+ vertical-align: middle;
+}
+.media-bottom {
+ vertical-align: bottom;
+}
+.media-heading {
+ margin-top: 0;
+ margin-bottom: 5px;
+}
+.media-list {
+ padding-left: 0;
+ list-style: none;
+}
+.list-group {
+ padding-left: 0;
+ margin-bottom: 20px;
+}
+.list-group-item {
+ position: relative;
+ display: block;
+ padding: 10px 15px;
+ margin-bottom: -1px;
+ background-color: #fff;
+ border: 1px solid #ddd;
+}
+.list-group-item:first-child {
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+}
+.list-group-item:last-child {
+ margin-bottom: 0;
+ border-bottom-right-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+a.list-group-item,
+button.list-group-item {
+ color: #555;
+}
+a.list-group-item .list-group-item-heading,
+button.list-group-item .list-group-item-heading {
+ color: #333;
+}
+a.list-group-item:hover,
+button.list-group-item:hover,
+a.list-group-item:focus,
+button.list-group-item:focus {
+ color: #555;
+ text-decoration: none;
+ background-color: #f5f5f5;
+}
+button.list-group-item {
+ width: 100%;
+ text-align: left;
+}
+.list-group-item.disabled,
+.list-group-item.disabled:hover,
+.list-group-item.disabled:focus {
+ color: #777;
+ cursor: not-allowed;
+ background-color: #eee;
+}
+.list-group-item.disabled .list-group-item-heading,
+.list-group-item.disabled:hover .list-group-item-heading,
+.list-group-item.disabled:focus .list-group-item-heading {
+ color: inherit;
+}
+.list-group-item.disabled .list-group-item-text,
+.list-group-item.disabled:hover .list-group-item-text,
+.list-group-item.disabled:focus .list-group-item-text {
+ color: #777;
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+ z-index: 2;
+ color: #fff;
+ background-color: #337ab7;
+ border-color: #337ab7;
+}
+.list-group-item.active .list-group-item-heading,
+.list-group-item.active:hover .list-group-item-heading,
+.list-group-item.active:focus .list-group-item-heading,
+.list-group-item.active .list-group-item-heading > small,
+.list-group-item.active:hover .list-group-item-heading > small,
+.list-group-item.active:focus .list-group-item-heading > small,
+.list-group-item.active .list-group-item-heading > .small,
+.list-group-item.active:hover .list-group-item-heading > .small,
+.list-group-item.active:focus .list-group-item-heading > .small {
+ color: inherit;
+}
+.list-group-item.active .list-group-item-text,
+.list-group-item.active:hover .list-group-item-text,
+.list-group-item.active:focus .list-group-item-text {
+ color: #c7ddef;
+}
+.list-group-item-success {
+ color: #3c763d;
+ background-color: #dff0d8;
+}
+a.list-group-item-success,
+button.list-group-item-success {
+ color: #3c763d;
+}
+a.list-group-item-success .list-group-item-heading,
+button.list-group-item-success .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-success:hover,
+button.list-group-item-success:hover,
+a.list-group-item-success:focus,
+button.list-group-item-success:focus {
+ color: #3c763d;
+ background-color: #d0e9c6;
+}
+a.list-group-item-success.active,
+button.list-group-item-success.active,
+a.list-group-item-success.active:hover,
+button.list-group-item-success.active:hover,
+a.list-group-item-success.active:focus,
+button.list-group-item-success.active:focus {
+ color: #fff;
+ background-color: #3c763d;
+ border-color: #3c763d;
+}
+.list-group-item-info {
+ color: #31708f;
+ background-color: #d9edf7;
+}
+a.list-group-item-info,
+button.list-group-item-info {
+ color: #31708f;
+}
+a.list-group-item-info .list-group-item-heading,
+button.list-group-item-info .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-info:hover,
+button.list-group-item-info:hover,
+a.list-group-item-info:focus,
+button.list-group-item-info:focus {
+ color: #31708f;
+ background-color: #c4e3f3;
+}
+a.list-group-item-info.active,
+button.list-group-item-info.active,
+a.list-group-item-info.active:hover,
+button.list-group-item-info.active:hover,
+a.list-group-item-info.active:focus,
+button.list-group-item-info.active:focus {
+ color: #fff;
+ background-color: #31708f;
+ border-color: #31708f;
+}
+.list-group-item-warning {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+}
+a.list-group-item-warning,
+button.list-group-item-warning {
+ color: #8a6d3b;
+}
+a.list-group-item-warning .list-group-item-heading,
+button.list-group-item-warning .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-warning:hover,
+button.list-group-item-warning:hover,
+a.list-group-item-warning:focus,
+button.list-group-item-warning:focus {
+ color: #8a6d3b;
+ background-color: #faf2cc;
+}
+a.list-group-item-warning.active,
+button.list-group-item-warning.active,
+a.list-group-item-warning.active:hover,
+button.list-group-item-warning.active:hover,
+a.list-group-item-warning.active:focus,
+button.list-group-item-warning.active:focus {
+ color: #fff;
+ background-color: #8a6d3b;
+ border-color: #8a6d3b;
+}
+.list-group-item-danger {
+ color: #a94442;
+ background-color: #f2dede;
+}
+a.list-group-item-danger,
+button.list-group-item-danger {
+ color: #a94442;
+}
+a.list-group-item-danger .list-group-item-heading,
+button.list-group-item-danger .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-danger:hover,
+button.list-group-item-danger:hover,
+a.list-group-item-danger:focus,
+button.list-group-item-danger:focus {
+ color: #a94442;
+ background-color: #ebcccc;
+}
+a.list-group-item-danger.active,
+button.list-group-item-danger.active,
+a.list-group-item-danger.active:hover,
+button.list-group-item-danger.active:hover,
+a.list-group-item-danger.active:focus,
+button.list-group-item-danger.active:focus {
+ color: #fff;
+ background-color: #a94442;
+ border-color: #a94442;
+}
+.list-group-item-heading {
+ margin-top: 0;
+ margin-bottom: 5px;
+}
+.list-group-item-text {
+ margin-bottom: 0;
+ line-height: 1.3;
+}
+.panel {
+ margin-bottom: 20px;
+ background-color: #fff;
+ border: 1px solid transparent;
+ border-radius: 4px;
+ -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+ box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+}
+.panel-body {
+ padding: 15px;
+}
+.panel-heading {
+ padding: 10px 15px;
+ border-bottom: 1px solid transparent;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.panel-heading > .dropdown .dropdown-toggle {
+ color: inherit;
+}
+.panel-title {
+ margin-top: 0;
+ margin-bottom: 0;
+ font-size: 16px;
+ color: inherit;
+}
+.panel-title > a,
+.panel-title > small,
+.panel-title > .small,
+.panel-title > small > a,
+.panel-title > .small > a {
+ color: inherit;
+}
+.panel-footer {
+ padding: 10px 15px;
+ background-color: #f5f5f5;
+ border-top: 1px solid #ddd;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel > .list-group,
+.panel > .panel-collapse > .list-group {
+ margin-bottom: 0;
+}
+.panel > .list-group .list-group-item,
+.panel > .panel-collapse > .list-group .list-group-item {
+ border-width: 1px 0;
+ border-radius: 0;
+}
+.panel > .list-group:first-child .list-group-item:first-child,
+.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {
+ border-top: 0;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.panel > .list-group:last-child .list-group-item:last-child,
+.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {
+ border-bottom: 0;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+.panel-heading + .list-group .list-group-item:first-child {
+ border-top-width: 0;
+}
+.list-group + .panel-footer {
+ border-top-width: 0;
+}
+.panel > .table,
+.panel > .table-responsive > .table,
+.panel > .panel-collapse > .table {
+ margin-bottom: 0;
+}
+.panel > .table caption,
+.panel > .table-responsive > .table caption,
+.panel > .panel-collapse > .table caption {
+ padding-right: 15px;
+ padding-left: 15px;
+}
+.panel > .table:first-child,
+.panel > .table-responsive:first-child > .table:first-child {
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
+ border-top-left-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
+ border-top-right-radius: 3px;
+}
+.panel > .table:last-child,
+.panel > .table-responsive:last-child > .table:last-child {
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
+ border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
+ border-bottom-right-radius: 3px;
+}
+.panel > .panel-body + .table,
+.panel > .panel-body + .table-responsive,
+.panel > .table + .panel-body,
+.panel > .table-responsive + .panel-body {
+ border-top: 1px solid #ddd;
+}
+.panel > .table > tbody:first-child > tr:first-child th,
+.panel > .table > tbody:first-child > tr:first-child td {
+ border-top: 0;
+}
+.panel > .table-bordered,
+.panel > .table-responsive > .table-bordered {
+ border: 0;
+}
+.panel > .table-bordered > thead > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
+.panel > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-bordered > thead > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
+.panel > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-bordered > tfoot > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+ border-left: 0;
+}
+.panel > .table-bordered > thead > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
+.panel > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-bordered > thead > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
+.panel > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-bordered > tfoot > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+ border-right: 0;
+}
+.panel > .table-bordered > thead > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
+.panel > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-bordered > thead > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
+.panel > .table-bordered > tbody > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
+ border-bottom: 0;
+}
+.panel > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-bordered > tfoot > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
+ border-bottom: 0;
+}
+.panel > .table-responsive {
+ margin-bottom: 0;
+ border: 0;
+}
+.panel-group {
+ margin-bottom: 20px;
+}
+.panel-group .panel {
+ margin-bottom: 0;
+ border-radius: 4px;
+}
+.panel-group .panel + .panel {
+ margin-top: 5px;
+}
+.panel-group .panel-heading {
+ border-bottom: 0;
+}
+.panel-group .panel-heading + .panel-collapse > .panel-body,
+.panel-group .panel-heading + .panel-collapse > .list-group {
+ border-top: 1px solid #ddd;
+}
+.panel-group .panel-footer {
+ border-top: 0;
+}
+.panel-group .panel-footer + .panel-collapse .panel-body {
+ border-bottom: 1px solid #ddd;
+}
+.panel-default {
+ border-color: #ddd;
+}
+.panel-default > .panel-heading {
+ color: #333;
+ background-color: #f5f5f5;
+ border-color: #ddd;
+}
+.panel-default > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #ddd;
+}
+.panel-default > .panel-heading .badge {
+ color: #f5f5f5;
+ background-color: #333;
+}
+.panel-default > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #ddd;
+}
+.panel-primary {
+ border-color: #337ab7;
+}
+.panel-primary > .panel-heading {
+ color: #fff;
+ background-color: #337ab7;
+ border-color: #337ab7;
+}
+.panel-primary > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #337ab7;
+}
+.panel-primary > .panel-heading .badge {
+ color: #337ab7;
+ background-color: #fff;
+}
+.panel-primary > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #337ab7;
+}
+.panel-success {
+ border-color: #d6e9c6;
+}
+.panel-success > .panel-heading {
+ color: #3c763d;
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+}
+.panel-success > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #d6e9c6;
+}
+.panel-success > .panel-heading .badge {
+ color: #dff0d8;
+ background-color: #3c763d;
+}
+.panel-success > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #d6e9c6;
+}
+.panel-info {
+ border-color: #bce8f1;
+}
+.panel-info > .panel-heading {
+ color: #31708f;
+ background-color: #d9edf7;
+ border-color: #bce8f1;
+}
+.panel-info > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #bce8f1;
+}
+.panel-info > .panel-heading .badge {
+ color: #d9edf7;
+ background-color: #31708f;
+}
+.panel-info > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #bce8f1;
+}
+.panel-warning {
+ border-color: #faebcc;
+}
+.panel-warning > .panel-heading {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+ border-color: #faebcc;
+}
+.panel-warning > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #faebcc;
+}
+.panel-warning > .panel-heading .badge {
+ color: #fcf8e3;
+ background-color: #8a6d3b;
+}
+.panel-warning > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #faebcc;
+}
+.panel-danger {
+ border-color: #ebccd1;
+}
+.panel-danger > .panel-heading {
+ color: #a94442;
+ background-color: #f2dede;
+ border-color: #ebccd1;
+}
+.panel-danger > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #ebccd1;
+}
+.panel-danger > .panel-heading .badge {
+ color: #f2dede;
+ background-color: #a94442;
+}
+.panel-danger > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #ebccd1;
+}
+.embed-responsive {
+ position: relative;
+ display: block;
+ height: 0;
+ padding: 0;
+ overflow: hidden;
+}
+.embed-responsive .embed-responsive-item,
+.embed-responsive iframe,
+.embed-responsive embed,
+.embed-responsive object,
+.embed-responsive video {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border: 0;
+}
+.embed-responsive-16by9 {
+ padding-bottom: 56.25%;
+}
+.embed-responsive-4by3 {
+ padding-bottom: 75%;
+}
+.well {
+ min-height: 20px;
+ padding: 19px;
+ margin-bottom: 20px;
+ background-color: #f5f5f5;
+ border: 1px solid #e3e3e3;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
+}
+.well blockquote {
+ border-color: #ddd;
+ border-color: rgba(0, 0, 0, .15);
+}
+.well-lg {
+ padding: 24px;
+ border-radius: 6px;
+}
+.well-sm {
+ padding: 9px;
+ border-radius: 3px;
+}
+.close {
+ float: right;
+ font-size: 21px;
+ font-weight: bold;
+ line-height: 1;
+ color: #000;
+ text-shadow: 0 1px 0 #fff;
+ filter: alpha(opacity=20);
+ opacity: .2;
+}
+.close:hover,
+.close:focus {
+ color: #000;
+ text-decoration: none;
+ cursor: pointer;
+ filter: alpha(opacity=50);
+ opacity: .5;
+}
+button.close {
+ -webkit-appearance: none;
+ padding: 0;
+ cursor: pointer;
+ background: transparent;
+ border: 0;
+}
+.modal-open {
+ overflow: hidden;
+}
+.modal {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1050;
+ display: none;
+ overflow: hidden;
+ -webkit-overflow-scrolling: touch;
+ outline: 0;
+}
+.modal.fade .modal-dialog {
+ -webkit-transition: -webkit-transform .3s ease-out;
+ -o-transition: -o-transform .3s ease-out;
+ transition: transform .3s ease-out;
+ -webkit-transform: translate(0, -25%);
+ -ms-transform: translate(0, -25%);
+ -o-transform: translate(0, -25%);
+ transform: translate(0, -25%);
+}
+.modal.in .modal-dialog {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ -o-transform: translate(0, 0);
+ transform: translate(0, 0);
+}
+.modal-open .modal {
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+.modal-dialog {
+ position: relative;
+ width: auto;
+ margin: 10px;
+}
+.modal-content {
+ position: relative;
+ background-color: #fff;
+ -webkit-background-clip: padding-box;
+ background-clip: padding-box;
+ border: 1px solid #999;
+ border: 1px solid rgba(0, 0, 0, .2);
+ border-radius: 6px;
+ outline: 0;
+ -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
+ box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
+}
+.modal-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1040;
+ background-color: #000;
+}
+.modal-backdrop.fade {
+ filter: alpha(opacity=0);
+ opacity: 0;
+}
+.modal-backdrop.in {
+ filter: alpha(opacity=50);
+ opacity: .5;
+}
+.modal-header {
+ min-height: 16.42857143px;
+ padding: 15px;
+ border-bottom: 1px solid #e5e5e5;
+}
+.modal-header .close {
+ margin-top: -2px;
+}
+.modal-title {
+ margin: 0;
+ line-height: 1.42857143;
+}
+.modal-body {
+ position: relative;
+ padding: 15px;
+}
+.modal-footer {
+ padding: 15px;
+ text-align: right;
+ border-top: 1px solid #e5e5e5;
+}
+.modal-footer .btn + .btn {
+ margin-bottom: 0;
+ margin-left: 5px;
+}
+.modal-footer .btn-group .btn + .btn {
+ margin-left: -1px;
+}
+.modal-footer .btn-block + .btn-block {
+ margin-left: 0;
+}
+.modal-scrollbar-measure {
+ position: absolute;
+ top: -9999px;
+ width: 50px;
+ height: 50px;
+ overflow: scroll;
+}
+@media (min-width: 768px) {
+ .modal-dialog {
+ width: 600px;
+ margin: 30px auto;
+ }
+ .modal-content {
+ -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
+ box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
+ }
+ .modal-sm {
+ width: 300px;
+ }
+}
+@media (min-width: 992px) {
+ .modal-lg {
+ width: 900px;
+ }
+}
+.tooltip {
+ position: absolute;
+ z-index: 1070;
+ display: block;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1.42857143;
+ text-align: left;
+ text-align: start;
+ text-decoration: none;
+ text-shadow: none;
+ text-transform: none;
+ letter-spacing: normal;
+ word-break: normal;
+ word-spacing: normal;
+ word-wrap: normal;
+ white-space: normal;
+ filter: alpha(opacity=0);
+ opacity: 0;
+
+ line-break: auto;
+}
+.tooltip.in {
+ filter: alpha(opacity=90);
+ opacity: .9;
+}
+.tooltip.top {
+ padding: 5px 0;
+ margin-top: -3px;
+}
+.tooltip.right {
+ padding: 0 5px;
+ margin-left: 3px;
+}
+.tooltip.bottom {
+ padding: 5px 0;
+ margin-top: 3px;
+}
+.tooltip.left {
+ padding: 0 5px;
+ margin-left: -3px;
+}
+.tooltip-inner {
+ max-width: 200px;
+ padding: 3px 8px;
+ color: #fff;
+ text-align: center;
+ background-color: #000;
+ border-radius: 4px;
+}
+.tooltip-arrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+.tooltip.top .tooltip-arrow {
+ bottom: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000;
+}
+.tooltip.top-left .tooltip-arrow {
+ right: 5px;
+ bottom: 0;
+ margin-bottom: -5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000;
+}
+.tooltip.top-right .tooltip-arrow {
+ bottom: 0;
+ left: 5px;
+ margin-bottom: -5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000;
+}
+.tooltip.right .tooltip-arrow {
+ top: 50%;
+ left: 0;
+ margin-top: -5px;
+ border-width: 5px 5px 5px 0;
+ border-right-color: #000;
+}
+.tooltip.left .tooltip-arrow {
+ top: 50%;
+ right: 0;
+ margin-top: -5px;
+ border-width: 5px 0 5px 5px;
+ border-left-color: #000;
+}
+.tooltip.bottom .tooltip-arrow {
+ top: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000;
+}
+.tooltip.bottom-left .tooltip-arrow {
+ top: 0;
+ right: 5px;
+ margin-top: -5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000;
+}
+.tooltip.bottom-right .tooltip-arrow {
+ top: 0;
+ left: 5px;
+ margin-top: -5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000;
+}
+.popover {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1060;
+ display: none;
+ max-width: 276px;
+ padding: 1px;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1.42857143;
+ text-align: left;
+ text-align: start;
+ text-decoration: none;
+ text-shadow: none;
+ text-transform: none;
+ letter-spacing: normal;
+ word-break: normal;
+ word-spacing: normal;
+ word-wrap: normal;
+ white-space: normal;
+ background-color: #fff;
+ -webkit-background-clip: padding-box;
+ background-clip: padding-box;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, .2);
+ border-radius: 6px;
+ -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+ box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+
+ line-break: auto;
+}
+.popover.top {
+ margin-top: -10px;
+}
+.popover.right {
+ margin-left: 10px;
+}
+.popover.bottom {
+ margin-top: 10px;
+}
+.popover.left {
+ margin-left: -10px;
+}
+.popover-title {
+ padding: 8px 14px;
+ margin: 0;
+ font-size: 14px;
+ background-color: #f7f7f7;
+ border-bottom: 1px solid #ebebeb;
+ border-radius: 5px 5px 0 0;
+}
+.popover-content {
+ padding: 9px 14px;
+}
+.popover > .arrow,
+.popover > .arrow:after {
+ position: absolute;
+ display: block;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+.popover > .arrow {
+ border-width: 11px;
+}
+.popover > .arrow:after {
+ content: "";
+ border-width: 10px;
+}
+.popover.top > .arrow {
+ bottom: -11px;
+ left: 50%;
+ margin-left: -11px;
+ border-top-color: #999;
+ border-top-color: rgba(0, 0, 0, .25);
+ border-bottom-width: 0;
+}
+.popover.top > .arrow:after {
+ bottom: 1px;
+ margin-left: -10px;
+ content: " ";
+ border-top-color: #fff;
+ border-bottom-width: 0;
+}
+.popover.right > .arrow {
+ top: 50%;
+ left: -11px;
+ margin-top: -11px;
+ border-right-color: #999;
+ border-right-color: rgba(0, 0, 0, .25);
+ border-left-width: 0;
+}
+.popover.right > .arrow:after {
+ bottom: -10px;
+ left: 1px;
+ content: " ";
+ border-right-color: #fff;
+ border-left-width: 0;
+}
+.popover.bottom > .arrow {
+ top: -11px;
+ left: 50%;
+ margin-left: -11px;
+ border-top-width: 0;
+ border-bottom-color: #999;
+ border-bottom-color: rgba(0, 0, 0, .25);
+}
+.popover.bottom > .arrow:after {
+ top: 1px;
+ margin-left: -10px;
+ content: " ";
+ border-top-width: 0;
+ border-bottom-color: #fff;
+}
+.popover.left > .arrow {
+ top: 50%;
+ right: -11px;
+ margin-top: -11px;
+ border-right-width: 0;
+ border-left-color: #999;
+ border-left-color: rgba(0, 0, 0, .25);
+}
+.popover.left > .arrow:after {
+ right: 1px;
+ bottom: -10px;
+ content: " ";
+ border-right-width: 0;
+ border-left-color: #fff;
+}
+.carousel {
+ position: relative;
+}
+.carousel-inner {
+ position: relative;
+ width: 100%;
+ overflow: hidden;
+}
+.carousel-inner > .item {
+ position: relative;
+ display: none;
+ -webkit-transition: .6s ease-in-out left;
+ -o-transition: .6s ease-in-out left;
+ transition: .6s ease-in-out left;
+}
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+ line-height: 1;
+}
+@media all and (transform-3d), (-webkit-transform-3d) {
+ .carousel-inner > .item {
+ -webkit-transition: -webkit-transform .6s ease-in-out;
+ -o-transition: -o-transform .6s ease-in-out;
+ transition: transform .6s ease-in-out;
+
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+ -webkit-perspective: 1000px;
+ perspective: 1000px;
+ }
+ .carousel-inner > .item.next,
+ .carousel-inner > .item.active.right {
+ left: 0;
+ -webkit-transform: translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0);
+ }
+ .carousel-inner > .item.prev,
+ .carousel-inner > .item.active.left {
+ left: 0;
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+ }
+ .carousel-inner > .item.next.left,
+ .carousel-inner > .item.prev.right,
+ .carousel-inner > .item.active {
+ left: 0;
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+}
+.carousel-inner > .active,
+.carousel-inner > .next,
+.carousel-inner > .prev {
+ display: block;
+}
+.carousel-inner > .active {
+ left: 0;
+}
+.carousel-inner > .next,
+.carousel-inner > .prev {
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+.carousel-inner > .next {
+ left: 100%;
+}
+.carousel-inner > .prev {
+ left: -100%;
+}
+.carousel-inner > .next.left,
+.carousel-inner > .prev.right {
+ left: 0;
+}
+.carousel-inner > .active.left {
+ left: -100%;
+}
+.carousel-inner > .active.right {
+ left: 100%;
+}
+.carousel-control {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ width: 15%;
+ font-size: 20px;
+ color: #fff;
+ text-align: center;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
+ filter: alpha(opacity=50);
+ opacity: .5;
+}
+.carousel-control.left {
+ background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+ background-image: -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+ background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));
+ background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
+ background-repeat: repeat-x;
+}
+.carousel-control.right {
+ right: 0;
+ left: auto;
+ background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+ background-image: -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+ background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));
+ background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
+ background-repeat: repeat-x;
+}
+.carousel-control:hover,
+.carousel-control:focus {
+ color: #fff;
+ text-decoration: none;
+ filter: alpha(opacity=90);
+ outline: 0;
+ opacity: .9;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-left,
+.carousel-control .glyphicon-chevron-right {
+ position: absolute;
+ top: 50%;
+ z-index: 5;
+ display: inline-block;
+ margin-top: -10px;
+}
+.carousel-control .icon-prev,
+.carousel-control .glyphicon-chevron-left {
+ left: 50%;
+ margin-left: -10px;
+}
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-right {
+ right: 50%;
+ margin-right: -10px;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next {
+ width: 20px;
+ height: 20px;
+ font-family: serif;
+ line-height: 1;
+}
+.carousel-control .icon-prev:before {
+ content: '\2039';
+}
+.carousel-control .icon-next:before {
+ content: '\203a';
+}
+.carousel-indicators {
+ position: absolute;
+ bottom: 10px;
+ left: 50%;
+ z-index: 15;
+ width: 60%;
+ padding-left: 0;
+ margin-left: -30%;
+ text-align: center;
+ list-style: none;
+}
+.carousel-indicators li {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ margin: 1px;
+ text-indent: -999px;
+ cursor: pointer;
+ background-color: #000 \9;
+ background-color: rgba(0, 0, 0, 0);
+ border: 1px solid #fff;
+ border-radius: 10px;
+}
+.carousel-indicators .active {
+ width: 12px;
+ height: 12px;
+ margin: 0;
+ background-color: #fff;
+}
+.carousel-caption {
+ position: absolute;
+ right: 15%;
+ bottom: 20px;
+ left: 15%;
+ z-index: 10;
+ padding-top: 20px;
+ padding-bottom: 20px;
+ color: #fff;
+ text-align: center;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
+}
+.carousel-caption .btn {
+ text-shadow: none;
+}
+@media screen and (min-width: 768px) {
+ .carousel-control .glyphicon-chevron-left,
+ .carousel-control .glyphicon-chevron-right,
+ .carousel-control .icon-prev,
+ .carousel-control .icon-next {
+ width: 30px;
+ height: 30px;
+ margin-top: -15px;
+ font-size: 30px;
+ }
+ .carousel-control .glyphicon-chevron-left,
+ .carousel-control .icon-prev {
+ margin-left: -15px;
+ }
+ .carousel-control .glyphicon-chevron-right,
+ .carousel-control .icon-next {
+ margin-right: -15px;
+ }
+ .carousel-caption {
+ right: 20%;
+ left: 20%;
+ padding-bottom: 30px;
+ }
+ .carousel-indicators {
+ bottom: 20px;
+ }
+}
+.clearfix:before,
+.clearfix:after,
+.dl-horizontal dd:before,
+.dl-horizontal dd:after,
+.container:before,
+.container:after,
+.container-fluid:before,
+.container-fluid:after,
+.row:before,
+.row:after,
+.form-horizontal .form-group:before,
+.form-horizontal .form-group:after,
+.btn-toolbar:before,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:before,
+.btn-group-vertical > .btn-group:after,
+.nav:before,
+.nav:after,
+.navbar:before,
+.navbar:after,
+.navbar-header:before,
+.navbar-header:after,
+.navbar-collapse:before,
+.navbar-collapse:after,
+.pager:before,
+.pager:after,
+.panel-body:before,
+.panel-body:after,
+.modal-footer:before,
+.modal-footer:after {
+ display: table;
+ content: " ";
+}
+.clearfix:after,
+.dl-horizontal dd:after,
+.container:after,
+.container-fluid:after,
+.row:after,
+.form-horizontal .form-group:after,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:after,
+.nav:after,
+.navbar:after,
+.navbar-header:after,
+.navbar-collapse:after,
+.pager:after,
+.panel-body:after,
+.modal-footer:after {
+ clear: both;
+}
+.center-block {
+ display: block;
+ margin-right: auto;
+ margin-left: auto;
+}
+.pull-right {
+ float: right !important;
+}
+.pull-left {
+ float: left !important;
+}
+.hide {
+ display: none !important;
+}
+.show {
+ display: block !important;
+}
+.invisible {
+ visibility: hidden;
+}
+.text-hide {
+ font: 0/0 a;
+ color: transparent;
+ text-shadow: none;
+ background-color: transparent;
+ border: 0;
+}
+.hidden {
+ display: none !important;
+}
+.affix {
+ position: fixed;
+}
+@-ms-viewport {
+ width: device-width;
+}
+.visible-xs,
+.visible-sm,
+.visible-md,
+.visible-lg {
+ display: none !important;
+}
+.visible-xs-block,
+.visible-xs-inline,
+.visible-xs-inline-block,
+.visible-sm-block,
+.visible-sm-inline,
+.visible-sm-inline-block,
+.visible-md-block,
+.visible-md-inline,
+.visible-md-inline-block,
+.visible-lg-block,
+.visible-lg-inline,
+.visible-lg-inline-block {
+ display: none !important;
+}
+@media (max-width: 767px) {
+ .visible-xs {
+ display: block !important;
+ }
+ table.visible-xs {
+ display: table !important;
+ }
+ tr.visible-xs {
+ display: table-row !important;
+ }
+ th.visible-xs,
+ td.visible-xs {
+ display: table-cell !important;
+ }
+}
+@media (max-width: 767px) {
+ .visible-xs-block {
+ display: block !important;
+ }
+}
+@media (max-width: 767px) {
+ .visible-xs-inline {
+ display: inline !important;
+ }
+}
+@media (max-width: 767px) {
+ .visible-xs-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm {
+ display: block !important;
+ }
+ table.visible-sm {
+ display: table !important;
+ }
+ tr.visible-sm {
+ display: table-row !important;
+ }
+ th.visible-sm,
+ td.visible-sm {
+ display: table-cell !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm-block {
+ display: block !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm-inline {
+ display: inline !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md {
+ display: block !important;
+ }
+ table.visible-md {
+ display: table !important;
+ }
+ tr.visible-md {
+ display: table-row !important;
+ }
+ th.visible-md,
+ td.visible-md {
+ display: table-cell !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md-block {
+ display: block !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md-inline {
+ display: inline !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg {
+ display: block !important;
+ }
+ table.visible-lg {
+ display: table !important;
+ }
+ tr.visible-lg {
+ display: table-row !important;
+ }
+ th.visible-lg,
+ td.visible-lg {
+ display: table-cell !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg-block {
+ display: block !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg-inline {
+ display: inline !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (max-width: 767px) {
+ .hidden-xs {
+ display: none !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .hidden-sm {
+ display: none !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .hidden-md {
+ display: none !important;
+ }
+}
+@media (min-width: 1200px) {
+ .hidden-lg {
+ display: none !important;
+ }
+}
+.visible-print {
+ display: none !important;
+}
+@media print {
+ .visible-print {
+ display: block !important;
+ }
+ table.visible-print {
+ display: table !important;
+ }
+ tr.visible-print {
+ display: table-row !important;
+ }
+ th.visible-print,
+ td.visible-print {
+ display: table-cell !important;
+ }
+}
+.visible-print-block {
+ display: none !important;
+}
+@media print {
+ .visible-print-block {
+ display: block !important;
+ }
+}
+.visible-print-inline {
+ display: none !important;
+}
+@media print {
+ .visible-print-inline {
+ display: inline !important;
+ }
+}
+.visible-print-inline-block {
+ display: none !important;
+}
+@media print {
+ .visible-print-inline-block {
+ display: inline-block !important;
+ }
+}
+@media print {
+ .hidden-print {
+ display: none !important;
+ }
+}
+/*# sourceMappingURL=bootstrap.css.map */
diff --git a/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap.css.map b/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap.css.map
new file mode 100644
index 0000000..9f60ed2
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["bootstrap.css","less/normalize.less","less/print.less","less/glyphicons.less","less/scaffolding.less","less/mixins/vendor-prefixes.less","less/mixins/tab-focus.less","less/mixins/image.less","less/type.less","less/mixins/text-emphasis.less","less/mixins/background-variant.less","less/mixins/text-overflow.less","less/code.less","less/grid.less","less/mixins/grid.less","less/mixins/grid-framework.less","less/tables.less","less/mixins/table-row.less","less/forms.less","less/mixins/forms.less","less/buttons.less","less/mixins/buttons.less","less/mixins/opacity.less","less/component-animations.less","less/dropdowns.less","less/mixins/nav-divider.less","less/mixins/reset-filter.less","less/button-groups.less","less/mixins/border-radius.less","less/input-groups.less","less/navs.less","less/navbar.less","less/mixins/nav-vertical-align.less","less/utilities.less","less/breadcrumbs.less","less/pagination.less","less/mixins/pagination.less","less/pager.less","less/labels.less","less/mixins/labels.less","less/badges.less","less/jumbotron.less","less/thumbnails.less","less/alerts.less","less/mixins/alerts.less","less/progress-bars.less","less/mixins/gradients.less","less/mixins/progress-bar.less","less/media.less","less/list-group.less","less/mixins/list-group.less","less/panels.less","less/mixins/panels.less","less/responsive-embed.less","less/wells.less","less/close.less","less/modals.less","less/tooltip.less","less/mixins/reset-text.less","less/popovers.less","less/carousel.less","less/mixins/clearfix.less","less/mixins/center-block.less","less/mixins/hide-text.less","less/responsive-utilities.less","less/mixins/responsive-visibility.less"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,4EAA4E;ACG5E;EACE,wBAAA;EACA,2BAAA;EACA,+BAAA;CDDD;ACQD;EACE,UAAA;CDND;ACmBD;;;;;;;;;;;;;EAaE,eAAA;CDjBD;ACyBD;;;;EAIE,sBAAA;EACA,yBAAA;CDvBD;AC+BD;EACE,cAAA;EACA,UAAA;CD7BD;ACqCD;;EAEE,cAAA;CDnCD;AC6CD;EACE,8BAAA;CD3CD;ACmDD;;EAEE,WAAA;CDjDD;AC2DD;EACE,0BAAA;CDzDD;ACgED;;EAEE,kBAAA;CD9DD;ACqED;EACE,mBAAA;CDnED;AC2ED;EACE,eAAA;EACA,iBAAA;CDzED;ACgFD;EACE,iBAAA;EACA,YAAA;CD9ED;ACqFD;EACE,eAAA;CDnFD;AC0FD;;EAEE,eAAA;EACA,eAAA;EACA,mBAAA;EACA,yBAAA;CDxFD;AC2FD;EACE,YAAA;CDzFD;AC4FD;EACE,gBAAA;CD1FD;ACoGD;EACE,UAAA;CDlGD;ACyGD;EACE,iBAAA;CDvGD;ACiHD;EACE,iBAAA;CD/GD;ACsHD;EACE,gCAAA;KAAA,6BAAA;UAAA,wBAAA;EACA,UAAA;CDpHD;AC2HD;EACE,eAAA;CDzHD;ACgID;;;;EAIE,kCAAA;EACA,eAAA;CD9HD;ACgJD;;;;;EAKE,eAAA;EACA,cAAA;EACA,UAAA;CD9ID;ACqJD;EACE,kBAAA;CDnJD;AC6JD;;EAEE,qBAAA;CD3JD;ACsKD;;;;EAIE,2BAAA;EACA,gBAAA;CDpKD;AC2KD;;EAEE,gBAAA;CDzKD;ACgLD;;EAEE,UAAA;EACA,WAAA;CD9KD;ACsLD;EACE,oBAAA;CDpLD;AC+LD;;EAEE,+BAAA;KAAA,4BAAA;UAAA,uBAAA;EACA,WAAA;CD7LD;ACsMD;;EAEE,aAAA;CDpMD;AC4MD;EACE,8BAAA;EACA,gCAAA;KAAA,6BAAA;UAAA,wBAAA;CD1MD;ACmND;;EAEE,yBAAA;CDjND;ACwND;EACE,0BAAA;EACA,cAAA;EACA,+BAAA;CDtND;AC8ND;EACE,UAAA;EACA,WAAA;CD5ND;ACmOD;EACE,eAAA;CDjOD;ACyOD;EACE,kBAAA;CDvOD;ACiPD;EACE,0BAAA;EACA,kBAAA;CD/OD;ACkPD;;EAEE,WAAA;CDhPD;AACD,qFAAqF;AElFrF;EA7FI;;;IAGI,mCAAA;IACA,uBAAA;IACA,oCAAA;YAAA,4BAAA;IACA,6BAAA;GFkLL;EE/KC;;IAEI,2BAAA;GFiLL;EE9KC;IACI,6BAAA;GFgLL;EE7KC;IACI,8BAAA;GF+KL;EE1KC;;IAEI,YAAA;GF4KL;EEzKC;;IAEI,uBAAA;IACA,yBAAA;GF2KL;EExKC;IACI,4BAAA;GF0KL;EEvKC;;IAEI,yBAAA;GFyKL;EEtKC;IACI,2BAAA;GFwKL;EErKC;;;IAGI,WAAA;IACA,UAAA;GFuKL;EEpKC;;IAEI,wBAAA;GFsKL;EEhKC;IACI,cAAA;GFkKL;EEhKC;;IAGQ,kCAAA;GFiKT;EE9JC;IACI,uBAAA;GFgKL;EE7JC;IACI,qCAAA;GF+JL;EEhKC;;IAKQ,kCAAA;GF+JT;EE5JC;;IAGQ,kCAAA;GF6JT;CACF;AGnPD;EACE,oCAAA;EACA,sDAAA;EACA,gYAAA;CHqPD;AG7OD;EACE,mBAAA;EACA,SAAA;EACA,sBAAA;EACA,oCAAA;EACA,mBAAA;EACA,oBAAA;EACA,eAAA;EACA,oCAAA;EACA,mCAAA;CH+OD;AG3OmC;EAAW,eAAA;CH8O9C;AG7OmC;EAAW,eAAA;CHgP9C;AG9OmC;;EAAW,iBAAA;CHkP9C;AGjPmC;EAAW,iBAAA;CHoP9C;AGnPmC;EAAW,iBAAA;CHsP9C;AGrPmC;EAAW,iBAAA;CHwP9C;AGvPmC;EAAW,iBAAA;CH0P9C;AGzPmC;EAAW,iBAAA;CH4P9C;AG3PmC;EAAW,iBAAA;CH8P9C;AG7PmC;EAAW,iBAAA;CHgQ9C;AG/PmC;EAAW,iBAAA;CHkQ9C;AGjQmC;EAAW,iBAAA;CHoQ9C;AGnQmC;EAAW,iBAAA;CHsQ9C;AGrQmC;EAAW,iBAAA;CHwQ9C;AGvQmC;EAAW,iBAAA;CH0Q9C;AGzQmC;EAAW,iBAAA;CH4Q9C;AG3QmC;EAAW,iBAAA;CH8Q9C;AG7QmC;EAAW,iBAAA;CHgR9C;AG/QmC;EAAW,iBAAA;CHkR9C;AGjRmC;EAAW,iBAAA;CHoR9C;AGnRmC;EAAW,iBAAA;CHsR9C;AGrRmC;EAAW,iBAAA;CHwR9C;AGvRmC;EAAW,iBAAA;CH0R9C;AGzRmC;EAAW,iBAAA;CH4R9C;AG3RmC;EAAW,iBAAA;CH8R9C;AG7RmC;EAAW,iBAAA;CHgS9C;AG/RmC;EAAW,iBAAA;CHkS9C;AGjSmC;EAAW,iBAAA;CHoS9C;AGnSmC;EAAW,iBAAA;CHsS9C;AGrSmC;EAAW,iBAAA;CHwS9C;AGvSmC;EAAW,iBAAA;CH0S9C;AGzSmC;EAAW,iBAAA;CH4S9C;AG3SmC;EAAW,iBAAA;CH8S9C;AG7SmC;EAAW,iBAAA;CHgT9C;AG/SmC;EAAW,iBAAA;CHkT9C;AGjTmC;EAAW,iBAAA;CHoT9C;AGnTmC;EAAW,iBAAA;CHsT9C;AGrTmC;EAAW,iBAAA;CHwT9C;AGvTmC;EAAW,iBAAA;CH0T9C;AGzTmC;EAAW,iBAAA;CH4T9C;AG3TmC;EAAW,iBAAA;CH8T9C;AG7TmC;EAAW,iBAAA;CHgU9C;AG/TmC;EAAW,iBAAA;CHkU9C;AGjUmC;EAAW,iBAAA;CHoU9C;AGnUmC;EAAW,iBAAA;CHsU9C;AGrUmC;EAAW,iBAAA;CHwU9C;AGvUmC;EAAW,iBAAA;CH0U9C;AGzUmC;EAAW,iBAAA;CH4U9C;AG3UmC;EAAW,iBAAA;CH8U9C;AG7UmC;EAAW,iBAAA;CHgV9C;AG/UmC;EAAW,iBAAA;CHkV9C;AGjVmC;EAAW,iBAAA;CHoV9C;AGnVmC;EAAW,iBAAA;CHsV9C;AGrVmC;EAAW,iBAAA;CHwV9C;AGvVmC;EAAW,iBAAA;CH0V9C;AGzVmC;EAAW,iBAAA;CH4V9C;AG3VmC;EAAW,iBAAA;CH8V9C;AG7VmC;EAAW,iBAAA;CHgW9C;AG/VmC;EAAW,iBAAA;CHkW9C;AGjWmC;EAAW,iBAAA;CHoW9C;AGnWmC;EAAW,iBAAA;CHsW9C;AGrWmC;EAAW,iBAAA;CHwW9C;AGvWmC;EAAW,iBAAA;CH0W9C;AGzWmC;EAAW,iBAAA;CH4W9C;AG3WmC;EAAW,iBAAA;CH8W9C;AG7WmC;EAAW,iBAAA;CHgX9C;AG/WmC;EAAW,iBAAA;CHkX9C;AGjXmC;EAAW,iBAAA;CHoX9C;AGnXmC;EAAW,iBAAA;CHsX9C;AGrXmC;EAAW,iBAAA;CHwX9C;AGvXmC;EAAW,iBAAA;CH0X9C;AGzXmC;EAAW,iBAAA;CH4X9C;AG3XmC;EAAW,iBAAA;CH8X9C;AG7XmC;EAAW,iBAAA;CHgY9C;AG/XmC;EAAW,iBAAA;CHkY9C;AGjYmC;EAAW,iBAAA;CHoY9C;AGnYmC;EAAW,iBAAA;CHsY9C;AGrYmC;EAAW,iBAAA;CHwY9C;AGvYmC;EAAW,iBAAA;CH0Y9C;AGzYmC;EAAW,iBAAA;CH4Y9C;AG3YmC;EAAW,iBAAA;CH8Y9C;AG7YmC;EAAW,iBAAA;CHgZ9C;AG/YmC;EAAW,iBAAA;CHkZ9C;AGjZmC;EAAW,iBAAA;CHoZ9C;AGnZmC;EAAW,iBAAA;CHsZ9C;AGrZmC;EAAW,iBAAA;CHwZ9C;AGvZmC;EAAW,iBAAA;CH0Z9C;AGzZmC;EAAW,iBAAA;CH4Z9C;AG3ZmC;EAAW,iBAAA;CH8Z9C;AG7ZmC;EAAW,iBAAA;CHga9C;AG/ZmC;EAAW,iBAAA;CHka9C;AGjamC;EAAW,iBAAA;CHoa9C;AGnamC;EAAW,iBAAA;CHsa9C;AGramC;EAAW,iBAAA;CHwa9C;AGvamC;EAAW,iBAAA;CH0a9C;AGzamC;EAAW,iBAAA;CH4a9C;AG3amC;EAAW,iBAAA;CH8a9C;AG7amC;EAAW,iBAAA;CHgb9C;AG/amC;EAAW,iBAAA;CHkb9C;AGjbmC;EAAW,iBAAA;CHob9C;AGnbmC;EAAW,iBAAA;CHsb9C;AGrbmC;EAAW,iBAAA;CHwb9C;AGvbmC;EAAW,iBAAA;CH0b9C;AGzbmC;EAAW,iBAAA;CH4b9C;AG3bmC;EAAW,iBAAA;CH8b9C;AG7bmC;EAAW,iBAAA;CHgc9C;AG/bmC;EAAW,iBAAA;CHkc9C;AGjcmC;EAAW,iBAAA;CHoc9C;AGncmC;EAAW,iBAAA;CHsc9C;AGrcmC;EAAW,iBAAA;CHwc9C;AGvcmC;EAAW,iBAAA;CH0c9C;AGzcmC;EAAW,iBAAA;CH4c9C;AG3cmC;EAAW,iBAAA;CH8c9C;AG7cmC;EAAW,iBAAA;CHgd9C;AG/cmC;EAAW,iBAAA;CHkd9C;AGjdmC;EAAW,iBAAA;CHod9C;AGndmC;EAAW,iBAAA;CHsd9C;AGrdmC;EAAW,iBAAA;CHwd9C;AGvdmC;EAAW,iBAAA;CH0d9C;AGzdmC;EAAW,iBAAA;CH4d9C;AG3dmC;EAAW,iBAAA;CH8d9C;AG7dmC;EAAW,iBAAA;CHge9C;AG/dmC;EAAW,iBAAA;CHke9C;AGjemC;EAAW,iBAAA;CHoe9C;AGnemC;EAAW,iBAAA;CHse9C;AGremC;EAAW,iBAAA;CHwe9C;AGvemC;EAAW,iBAAA;CH0e9C;AGzemC;EAAW,iBAAA;CH4e9C;AG3emC;EAAW,iBAAA;CH8e9C;AG7emC;EAAW,iBAAA;CHgf9C;AG/emC;EAAW,iBAAA;CHkf9C;AGjfmC;EAAW,iBAAA;CHof9C;AGnfmC;EAAW,iBAAA;CHsf9C;AGrfmC;EAAW,iBAAA;CHwf9C;AGvfmC;EAAW,iBAAA;CH0f9C;AGzfmC;EAAW,iBAAA;CH4f9C;AG3fmC;EAAW,iBAAA;CH8f9C;AG7fmC;EAAW,iBAAA;CHggB9C;AG/fmC;EAAW,iBAAA;CHkgB9C;AGjgBmC;EAAW,iBAAA;CHogB9C;AGngBmC;EAAW,iBAAA;CHsgB9C;AGrgBmC;EAAW,iBAAA;CHwgB9C;AGvgBmC;EAAW,iBAAA;CH0gB9C;AGzgBmC;EAAW,iBAAA;CH4gB9C;AG3gBmC;EAAW,iBAAA;CH8gB9C;AG7gBmC;EAAW,iBAAA;CHghB9C;AG/gBmC;EAAW,iBAAA;CHkhB9C;AGjhBmC;EAAW,iBAAA;CHohB9C;AGnhBmC;EAAW,iBAAA;CHshB9C;AGrhBmC;EAAW,iBAAA;CHwhB9C;AGvhBmC;EAAW,iBAAA;CH0hB9C;AGzhBmC;EAAW,iBAAA;CH4hB9C;AG3hBmC;EAAW,iBAAA;CH8hB9C;AG7hBmC;EAAW,iBAAA;CHgiB9C;AG/hBmC;EAAW,iBAAA;CHkiB9C;AGjiBmC;EAAW,iBAAA;CHoiB9C;AGniBmC;EAAW,iBAAA;CHsiB9C;AGriBmC;EAAW,iBAAA;CHwiB9C;AGviBmC;EAAW,iBAAA;CH0iB9C;AGziBmC;EAAW,iBAAA;CH4iB9C;AG3iBmC;EAAW,iBAAA;CH8iB9C;AG7iBmC;EAAW,iBAAA;CHgjB9C;AG/iBmC;EAAW,iBAAA;CHkjB9C;AGjjBmC;EAAW,iBAAA;CHojB9C;AGnjBmC;EAAW,iBAAA;CHsjB9C;AGrjBmC;EAAW,iBAAA;CHwjB9C;AGvjBmC;EAAW,iBAAA;CH0jB9C;AGzjBmC;EAAW,iBAAA;CH4jB9C;AG3jBmC;EAAW,iBAAA;CH8jB9C;AG7jBmC;EAAW,iBAAA;CHgkB9C;AG/jBmC;EAAW,iBAAA;CHkkB9C;AGjkBmC;EAAW,iBAAA;CHokB9C;AGnkBmC;EAAW,iBAAA;CHskB9C;AGrkBmC;EAAW,iBAAA;CHwkB9C;AGvkBmC;EAAW,iBAAA;CH0kB9C;AGzkBmC;EAAW,iBAAA;CH4kB9C;AG3kBmC;EAAW,iBAAA;CH8kB9C;AG7kBmC;EAAW,iBAAA;CHglB9C;AG/kBmC;EAAW,iBAAA;CHklB9C;AGjlBmC;EAAW,iBAAA;CHolB9C;AGnlBmC;EAAW,iBAAA;CHslB9C;AGrlBmC;EAAW,iBAAA;CHwlB9C;AGvlBmC;EAAW,iBAAA;CH0lB9C;AGzlBmC;EAAW,iBAAA;CH4lB9C;AG3lBmC;EAAW,iBAAA;CH8lB9C;AG7lBmC;EAAW,iBAAA;CHgmB9C;AG/lBmC;EAAW,iBAAA;CHkmB9C;AGjmBmC;EAAW,iBAAA;CHomB9C;AGnmBmC;EAAW,iBAAA;CHsmB9C;AGrmBmC;EAAW,iBAAA;CHwmB9C;AGvmBmC;EAAW,iBAAA;CH0mB9C;AGzmBmC;EAAW,iBAAA;CH4mB9C;AG3mBmC;EAAW,iBAAA;CH8mB9C;AG7mBmC;EAAW,iBAAA;CHgnB9C;AG/mBmC;EAAW,iBAAA;CHknB9C;AGjnBmC;EAAW,iBAAA;CHonB9C;AGnnBmC;EAAW,iBAAA;CHsnB9C;AGrnBmC;EAAW,iBAAA;CHwnB9C;AGvnBmC;EAAW,iBAAA;CH0nB9C;AGznBmC;EAAW,iBAAA;CH4nB9C;AG3nBmC;EAAW,iBAAA;CH8nB9C;AG7nBmC;EAAW,iBAAA;CHgoB9C;AG/nBmC;EAAW,iBAAA;CHkoB9C;AGjoBmC;EAAW,iBAAA;CHooB9C;AGnoBmC;EAAW,iBAAA;CHsoB9C;AGroBmC;EAAW,iBAAA;CHwoB9C;AG/nBmC;EAAW,iBAAA;CHkoB9C;AGjoBmC;EAAW,iBAAA;CHooB9C;AGnoBmC;EAAW,iBAAA;CHsoB9C;AGroBmC;EAAW,iBAAA;CHwoB9C;AGvoBmC;EAAW,iBAAA;CH0oB9C;AGzoBmC;EAAW,iBAAA;CH4oB9C;AG3oBmC;EAAW,iBAAA;CH8oB9C;AG7oBmC;EAAW,iBAAA;CHgpB9C;AG/oBmC;EAAW,iBAAA;CHkpB9C;AGjpBmC;EAAW,iBAAA;CHopB9C;AGnpBmC;EAAW,iBAAA;CHspB9C;AGrpBmC;EAAW,iBAAA;CHwpB9C;AGvpBmC;EAAW,iBAAA;CH0pB9C;AGzpBmC;EAAW,iBAAA;CH4pB9C;AG3pBmC;EAAW,iBAAA;CH8pB9C;AG7pBmC;EAAW,iBAAA;CHgqB9C;AG/pBmC;EAAW,iBAAA;CHkqB9C;AGjqBmC;EAAW,iBAAA;CHoqB9C;AGnqBmC;EAAW,iBAAA;CHsqB9C;AGrqBmC;EAAW,iBAAA;CHwqB9C;AGvqBmC;EAAW,iBAAA;CH0qB9C;AGzqBmC;EAAW,iBAAA;CH4qB9C;AG3qBmC;EAAW,iBAAA;CH8qB9C;AG7qBmC;EAAW,iBAAA;CHgrB9C;AG/qBmC;EAAW,iBAAA;CHkrB9C;AGjrBmC;EAAW,iBAAA;CHorB9C;AGnrBmC;EAAW,iBAAA;CHsrB9C;AGrrBmC;EAAW,iBAAA;CHwrB9C;AGvrBmC;EAAW,iBAAA;CH0rB9C;AGzrBmC;EAAW,iBAAA;CH4rB9C;AG3rBmC;EAAW,iBAAA;CH8rB9C;AG7rBmC;EAAW,iBAAA;CHgsB9C;AG/rBmC;EAAW,iBAAA;CHksB9C;AGjsBmC;EAAW,iBAAA;CHosB9C;AGnsBmC;EAAW,iBAAA;CHssB9C;AGrsBmC;EAAW,iBAAA;CHwsB9C;AGvsBmC;EAAW,iBAAA;CH0sB9C;AGzsBmC;EAAW,iBAAA;CH4sB9C;AG3sBmC;EAAW,iBAAA;CH8sB9C;AG7sBmC;EAAW,iBAAA;CHgtB9C;AG/sBmC;EAAW,iBAAA;CHktB9C;AGjtBmC;EAAW,iBAAA;CHotB9C;AGntBmC;EAAW,iBAAA;CHstB9C;AGrtBmC;EAAW,iBAAA;CHwtB9C;AGvtBmC;EAAW,iBAAA;CH0tB9C;AGztBmC;EAAW,iBAAA;CH4tB9C;AG3tBmC;EAAW,iBAAA;CH8tB9C;AG7tBmC;EAAW,iBAAA;CHguB9C;AG/tBmC;EAAW,iBAAA;CHkuB9C;AGjuBmC;EAAW,iBAAA;CHouB9C;AGnuBmC;EAAW,iBAAA;CHsuB9C;AGruBmC;EAAW,iBAAA;CHwuB9C;AGvuBmC;EAAW,iBAAA;CH0uB9C;AGzuBmC;EAAW,iBAAA;CH4uB9C;AG3uBmC;EAAW,iBAAA;CH8uB9C;AG7uBmC;EAAW,iBAAA;CHgvB9C;AIthCD;ECgEE,+BAAA;EACG,4BAAA;EACK,uBAAA;CLy9BT;AIxhCD;;EC6DE,+BAAA;EACG,4BAAA;EACK,uBAAA;CL+9BT;AIthCD;EACE,gBAAA;EACA,8CAAA;CJwhCD;AIrhCD;EACE,4DAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,0BAAA;CJuhCD;AInhCD;;;;EAIE,qBAAA;EACA,mBAAA;EACA,qBAAA;CJqhCD;AI/gCD;EACE,eAAA;EACA,sBAAA;CJihCD;AI/gCC;;EAEE,eAAA;EACA,2BAAA;CJihCH;AI9gCC;EErDA,qBAAA;EAEA,2CAAA;EACA,qBAAA;CNqkCD;AIxgCD;EACE,UAAA;CJ0gCD;AIpgCD;EACE,uBAAA;CJsgCD;AIlgCD;;;;;EGvEE,eAAA;EACA,gBAAA;EACA,aAAA;CPglCD;AItgCD;EACE,mBAAA;CJwgCD;AIlgCD;EACE,aAAA;EACA,wBAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;EC6FA,yCAAA;EACK,oCAAA;EACG,iCAAA;EEvLR,sBAAA;EACA,gBAAA;EACA,aAAA;CPgmCD;AIlgCD;EACE,mBAAA;CJogCD;AI9/BD;EACE,iBAAA;EACA,oBAAA;EACA,UAAA;EACA,8BAAA;CJggCD;AIx/BD;EACE,mBAAA;EACA,WAAA;EACA,YAAA;EACA,aAAA;EACA,WAAA;EACA,iBAAA;EACA,uBAAA;EACA,UAAA;CJ0/BD;AIl/BC;;EAEE,iBAAA;EACA,YAAA;EACA,aAAA;EACA,UAAA;EACA,kBAAA;EACA,WAAA;CJo/BH;AIz+BD;EACE,gBAAA;CJ2+BD;AQloCD;;;;;;;;;;;;EAEE,qBAAA;EACA,iBAAA;EACA,iBAAA;EACA,eAAA;CR8oCD;AQnpCD;;;;;;;;;;;;;;;;;;;;;;;;EASI,oBAAA;EACA,eAAA;EACA,eAAA;CRoqCH;AQhqCD;;;;;;EAGE,iBAAA;EACA,oBAAA;CRqqCD;AQzqCD;;;;;;;;;;;;EAQI,eAAA;CR+qCH;AQ5qCD;;;;;;EAGE,iBAAA;EACA,oBAAA;CRirCD;AQrrCD;;;;;;;;;;;;EAQI,eAAA;CR2rCH;AQvrCD;;EAAU,gBAAA;CR2rCT;AQ1rCD;;EAAU,gBAAA;CR8rCT;AQ7rCD;;EAAU,gBAAA;CRisCT;AQhsCD;;EAAU,gBAAA;CRosCT;AQnsCD;;EAAU,gBAAA;CRusCT;AQtsCD;;EAAU,gBAAA;CR0sCT;AQpsCD;EACE,iBAAA;CRssCD;AQnsCD;EACE,oBAAA;EACA,gBAAA;EACA,iBAAA;EACA,iBAAA;CRqsCD;AQhsCD;EAAA;IAFI,gBAAA;GRssCD;CACF;AQ9rCD;;EAEE,eAAA;CRgsCD;AQ7rCD;;EAEE,0BAAA;EACA,cAAA;CR+rCD;AQ3rCD;EAAuB,iBAAA;CR8rCtB;AQ7rCD;EAAuB,kBAAA;CRgsCtB;AQ/rCD;EAAuB,mBAAA;CRksCtB;AQjsCD;EAAuB,oBAAA;CRosCtB;AQnsCD;EAAuB,oBAAA;CRssCtB;AQnsCD;EAAuB,0BAAA;CRssCtB;AQrsCD;EAAuB,0BAAA;CRwsCtB;AQvsCD;EAAuB,2BAAA;CR0sCtB;AQvsCD;EACE,eAAA;CRysCD;AQvsCD;ECrGE,eAAA;CT+yCD;AS9yCC;;EAEE,eAAA;CTgzCH;AQ3sCD;ECxGE,eAAA;CTszCD;ASrzCC;;EAEE,eAAA;CTuzCH;AQ/sCD;EC3GE,eAAA;CT6zCD;AS5zCC;;EAEE,eAAA;CT8zCH;AQntCD;EC9GE,eAAA;CTo0CD;ASn0CC;;EAEE,eAAA;CTq0CH;AQvtCD;ECjHE,eAAA;CT20CD;AS10CC;;EAEE,eAAA;CT40CH;AQvtCD;EAGE,YAAA;EE3HA,0BAAA;CVm1CD;AUl1CC;;EAEE,0BAAA;CVo1CH;AQztCD;EE9HE,0BAAA;CV01CD;AUz1CC;;EAEE,0BAAA;CV21CH;AQ7tCD;EEjIE,0BAAA;CVi2CD;AUh2CC;;EAEE,0BAAA;CVk2CH;AQjuCD;EEpIE,0BAAA;CVw2CD;AUv2CC;;EAEE,0BAAA;CVy2CH;AQruCD;EEvIE,0BAAA;CV+2CD;AU92CC;;EAEE,0BAAA;CVg3CH;AQpuCD;EACE,oBAAA;EACA,oBAAA;EACA,iCAAA;CRsuCD;AQ9tCD;;EAEE,cAAA;EACA,oBAAA;CRguCD;AQnuCD;;;;EAMI,iBAAA;CRmuCH;AQ5tCD;EACE,gBAAA;EACA,iBAAA;CR8tCD;AQ1tCD;EALE,gBAAA;EACA,iBAAA;EAMA,kBAAA;CR6tCD;AQ/tCD;EAKI,sBAAA;EACA,kBAAA;EACA,mBAAA;CR6tCH;AQxtCD;EACE,cAAA;EACA,oBAAA;CR0tCD;AQxtCD;;EAEE,wBAAA;CR0tCD;AQxtCD;EACE,kBAAA;CR0tCD;AQxtCD;EACE,eAAA;CR0tCD;AQjsCD;EAAA;IAVM,YAAA;IACA,aAAA;IACA,YAAA;IACA,kBAAA;IGtNJ,iBAAA;IACA,wBAAA;IACA,oBAAA;GXs6CC;EQ3sCH;IAHM,mBAAA;GRitCH;CACF;AQxsCD;;EAGE,aAAA;EACA,kCAAA;CRysCD;AQvsCD;EACE,eAAA;EA9IqB,0BAAA;CRw1CtB;AQrsCD;EACE,mBAAA;EACA,iBAAA;EACA,kBAAA;EACA,+BAAA;CRusCD;AQlsCG;;;EACE,iBAAA;CRssCL;AQhtCD;;;EAmBI,eAAA;EACA,eAAA;EACA,wBAAA;EACA,eAAA;CRksCH;AQhsCG;;;EACE,uBAAA;CRosCL;AQ5rCD;;EAEE,oBAAA;EACA,gBAAA;EACA,gCAAA;EACA,eAAA;EACA,kBAAA;CR8rCD;AQxrCG;;;;;;EAAW,YAAA;CRgsCd;AQ/rCG;;;;;;EACE,uBAAA;CRssCL;AQhsCD;EACE,oBAAA;EACA,mBAAA;EACA,wBAAA;CRksCD;AYx+CD;;;;EAIE,+DAAA;CZ0+CD;AYt+CD;EACE,iBAAA;EACA,eAAA;EACA,eAAA;EACA,0BAAA;EACA,mBAAA;CZw+CD;AYp+CD;EACE,iBAAA;EACA,eAAA;EACA,eAAA;EACA,0BAAA;EACA,mBAAA;EACA,uDAAA;UAAA,+CAAA;CZs+CD;AY5+CD;EASI,WAAA;EACA,gBAAA;EACA,kBAAA;EACA,yBAAA;UAAA,iBAAA;CZs+CH;AYj+CD;EACE,eAAA;EACA,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,wBAAA;EACA,sBAAA;EACA,sBAAA;EACA,eAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;CZm+CD;AY9+CD;EAeI,WAAA;EACA,mBAAA;EACA,eAAA;EACA,sBAAA;EACA,8BAAA;EACA,iBAAA;CZk+CH;AY79CD;EACE,kBAAA;EACA,mBAAA;CZ+9CD;AazhDD;ECHE,mBAAA;EACA,kBAAA;EACA,mBAAA;EACA,oBAAA;Cd+hDD;AazhDC;EAAA;IAFE,aAAA;Gb+hDD;CACF;Aa3hDC;EAAA;IAFE,aAAA;GbiiDD;CACF;Aa7hDD;EAAA;IAFI,cAAA;GbmiDD;CACF;Aa1hDD;ECvBE,mBAAA;EACA,kBAAA;EACA,mBAAA;EACA,oBAAA;CdojDD;AavhDD;ECvBE,mBAAA;EACA,oBAAA;CdijDD;AejjDG;EACE,mBAAA;EAEA,gBAAA;EAEA,mBAAA;EACA,oBAAA;CfijDL;AejiDG;EACE,YAAA;CfmiDL;Ae5hDC;EACE,YAAA;Cf8hDH;Ae/hDC;EACE,oBAAA;CfiiDH;AeliDC;EACE,oBAAA;CfoiDH;AeriDC;EACE,WAAA;CfuiDH;AexiDC;EACE,oBAAA;Cf0iDH;Ae3iDC;EACE,oBAAA;Cf6iDH;Ae9iDC;EACE,WAAA;CfgjDH;AejjDC;EACE,oBAAA;CfmjDH;AepjDC;EACE,oBAAA;CfsjDH;AevjDC;EACE,WAAA;CfyjDH;Ae1jDC;EACE,oBAAA;Cf4jDH;Ae7jDC;EACE,mBAAA;Cf+jDH;AejjDC;EACE,YAAA;CfmjDH;AepjDC;EACE,oBAAA;CfsjDH;AevjDC;EACE,oBAAA;CfyjDH;Ae1jDC;EACE,WAAA;Cf4jDH;Ae7jDC;EACE,oBAAA;Cf+jDH;AehkDC;EACE,oBAAA;CfkkDH;AenkDC;EACE,WAAA;CfqkDH;AetkDC;EACE,oBAAA;CfwkDH;AezkDC;EACE,oBAAA;Cf2kDH;Ae5kDC;EACE,WAAA;Cf8kDH;Ae/kDC;EACE,oBAAA;CfilDH;AellDC;EACE,mBAAA;CfolDH;AehlDC;EACE,YAAA;CfklDH;AelmDC;EACE,WAAA;CfomDH;AermDC;EACE,mBAAA;CfumDH;AexmDC;EACE,mBAAA;Cf0mDH;Ae3mDC;EACE,UAAA;Cf6mDH;Ae9mDC;EACE,mBAAA;CfgnDH;AejnDC;EACE,mBAAA;CfmnDH;AepnDC;EACE,UAAA;CfsnDH;AevnDC;EACE,mBAAA;CfynDH;Ae1nDC;EACE,mBAAA;Cf4nDH;Ae7nDC;EACE,UAAA;Cf+nDH;AehoDC;EACE,mBAAA;CfkoDH;AenoDC;EACE,kBAAA;CfqoDH;AejoDC;EACE,WAAA;CfmoDH;AernDC;EACE,kBAAA;CfunDH;AexnDC;EACE,0BAAA;Cf0nDH;Ae3nDC;EACE,0BAAA;Cf6nDH;Ae9nDC;EACE,iBAAA;CfgoDH;AejoDC;EACE,0BAAA;CfmoDH;AepoDC;EACE,0BAAA;CfsoDH;AevoDC;EACE,iBAAA;CfyoDH;Ae1oDC;EACE,0BAAA;Cf4oDH;Ae7oDC;EACE,0BAAA;Cf+oDH;AehpDC;EACE,iBAAA;CfkpDH;AenpDC;EACE,0BAAA;CfqpDH;AetpDC;EACE,yBAAA;CfwpDH;AezpDC;EACE,gBAAA;Cf2pDH;Aa3pDD;EElCI;IACE,YAAA;GfgsDH;EezrDD;IACE,YAAA;Gf2rDD;Ee5rDD;IACE,oBAAA;Gf8rDD;Ee/rDD;IACE,oBAAA;GfisDD;EelsDD;IACE,WAAA;GfosDD;EersDD;IACE,oBAAA;GfusDD;EexsDD;IACE,oBAAA;Gf0sDD;Ee3sDD;IACE,WAAA;Gf6sDD;Ee9sDD;IACE,oBAAA;GfgtDD;EejtDD;IACE,oBAAA;GfmtDD;EeptDD;IACE,WAAA;GfstDD;EevtDD;IACE,oBAAA;GfytDD;Ee1tDD;IACE,mBAAA;Gf4tDD;Ee9sDD;IACE,YAAA;GfgtDD;EejtDD;IACE,oBAAA;GfmtDD;EeptDD;IACE,oBAAA;GfstDD;EevtDD;IACE,WAAA;GfytDD;Ee1tDD;IACE,oBAAA;Gf4tDD;Ee7tDD;IACE,oBAAA;Gf+tDD;EehuDD;IACE,WAAA;GfkuDD;EenuDD;IACE,oBAAA;GfquDD;EetuDD;IACE,oBAAA;GfwuDD;EezuDD;IACE,WAAA;Gf2uDD;Ee5uDD;IACE,oBAAA;Gf8uDD;Ee/uDD;IACE,mBAAA;GfivDD;Ee7uDD;IACE,YAAA;Gf+uDD;Ee/vDD;IACE,WAAA;GfiwDD;EelwDD;IACE,mBAAA;GfowDD;EerwDD;IACE,mBAAA;GfuwDD;EexwDD;IACE,UAAA;Gf0wDD;Ee3wDD;IACE,mBAAA;Gf6wDD;Ee9wDD;IACE,mBAAA;GfgxDD;EejxDD;IACE,UAAA;GfmxDD;EepxDD;IACE,mBAAA;GfsxDD;EevxDD;IACE,mBAAA;GfyxDD;Ee1xDD;IACE,UAAA;Gf4xDD;Ee7xDD;IACE,mBAAA;Gf+xDD;EehyDD;IACE,kBAAA;GfkyDD;Ee9xDD;IACE,WAAA;GfgyDD;EelxDD;IACE,kBAAA;GfoxDD;EerxDD;IACE,0BAAA;GfuxDD;EexxDD;IACE,0BAAA;Gf0xDD;Ee3xDD;IACE,iBAAA;Gf6xDD;Ee9xDD;IACE,0BAAA;GfgyDD;EejyDD;IACE,0BAAA;GfmyDD;EepyDD;IACE,iBAAA;GfsyDD;EevyDD;IACE,0BAAA;GfyyDD;Ee1yDD;IACE,0BAAA;Gf4yDD;Ee7yDD;IACE,iBAAA;Gf+yDD;EehzDD;IACE,0BAAA;GfkzDD;EenzDD;IACE,yBAAA;GfqzDD;EetzDD;IACE,gBAAA;GfwzDD;CACF;AahzDD;EE3CI;IACE,YAAA;Gf81DH;Eev1DD;IACE,YAAA;Gfy1DD;Ee11DD;IACE,oBAAA;Gf41DD;Ee71DD;IACE,oBAAA;Gf+1DD;Eeh2DD;IACE,WAAA;Gfk2DD;Een2DD;IACE,oBAAA;Gfq2DD;Eet2DD;IACE,oBAAA;Gfw2DD;Eez2DD;IACE,WAAA;Gf22DD;Ee52DD;IACE,oBAAA;Gf82DD;Ee/2DD;IACE,oBAAA;Gfi3DD;Eel3DD;IACE,WAAA;Gfo3DD;Eer3DD;IACE,oBAAA;Gfu3DD;Eex3DD;IACE,mBAAA;Gf03DD;Ee52DD;IACE,YAAA;Gf82DD;Ee/2DD;IACE,oBAAA;Gfi3DD;Eel3DD;IACE,oBAAA;Gfo3DD;Eer3DD;IACE,WAAA;Gfu3DD;Eex3DD;IACE,oBAAA;Gf03DD;Ee33DD;IACE,oBAAA;Gf63DD;Ee93DD;IACE,WAAA;Gfg4DD;Eej4DD;IACE,oBAAA;Gfm4DD;Eep4DD;IACE,oBAAA;Gfs4DD;Eev4DD;IACE,WAAA;Gfy4DD;Ee14DD;IACE,oBAAA;Gf44DD;Ee74DD;IACE,mBAAA;Gf+4DD;Ee34DD;IACE,YAAA;Gf64DD;Ee75DD;IACE,WAAA;Gf+5DD;Eeh6DD;IACE,mBAAA;Gfk6DD;Een6DD;IACE,mBAAA;Gfq6DD;Eet6DD;IACE,UAAA;Gfw6DD;Eez6DD;IACE,mBAAA;Gf26DD;Ee56DD;IACE,mBAAA;Gf86DD;Ee/6DD;IACE,UAAA;Gfi7DD;Eel7DD;IACE,mBAAA;Gfo7DD;Eer7DD;IACE,mBAAA;Gfu7DD;Eex7DD;IACE,UAAA;Gf07DD;Ee37DD;IACE,mBAAA;Gf67DD;Ee97DD;IACE,kBAAA;Gfg8DD;Ee57DD;IACE,WAAA;Gf87DD;Eeh7DD;IACE,kBAAA;Gfk7DD;Een7DD;IACE,0BAAA;Gfq7DD;Eet7DD;IACE,0BAAA;Gfw7DD;Eez7DD;IACE,iBAAA;Gf27DD;Ee57DD;IACE,0BAAA;Gf87DD;Ee/7DD;IACE,0BAAA;Gfi8DD;Eel8DD;IACE,iBAAA;Gfo8DD;Eer8DD;IACE,0BAAA;Gfu8DD;Eex8DD;IACE,0BAAA;Gf08DD;Ee38DD;IACE,iBAAA;Gf68DD;Ee98DD;IACE,0BAAA;Gfg9DD;Eej9DD;IACE,yBAAA;Gfm9DD;Eep9DD;IACE,gBAAA;Gfs9DD;CACF;Aa38DD;EE9CI;IACE,YAAA;Gf4/DH;Eer/DD;IACE,YAAA;Gfu/DD;Eex/DD;IACE,oBAAA;Gf0/DD;Ee3/DD;IACE,oBAAA;Gf6/DD;Ee9/DD;IACE,WAAA;GfggED;EejgED;IACE,oBAAA;GfmgED;EepgED;IACE,oBAAA;GfsgED;EevgED;IACE,WAAA;GfygED;Ee1gED;IACE,oBAAA;Gf4gED;Ee7gED;IACE,oBAAA;Gf+gED;EehhED;IACE,WAAA;GfkhED;EenhED;IACE,oBAAA;GfqhED;EethED;IACE,mBAAA;GfwhED;Ee1gED;IACE,YAAA;Gf4gED;Ee7gED;IACE,oBAAA;Gf+gED;EehhED;IACE,oBAAA;GfkhED;EenhED;IACE,WAAA;GfqhED;EethED;IACE,oBAAA;GfwhED;EezhED;IACE,oBAAA;Gf2hED;Ee5hED;IACE,WAAA;Gf8hED;Ee/hED;IACE,oBAAA;GfiiED;EeliED;IACE,oBAAA;GfoiED;EeriED;IACE,WAAA;GfuiED;EexiED;IACE,oBAAA;Gf0iED;Ee3iED;IACE,mBAAA;Gf6iED;EeziED;IACE,YAAA;Gf2iED;Ee3jED;IACE,WAAA;Gf6jED;Ee9jED;IACE,mBAAA;GfgkED;EejkED;IACE,mBAAA;GfmkED;EepkED;IACE,UAAA;GfskED;EevkED;IACE,mBAAA;GfykED;Ee1kED;IACE,mBAAA;Gf4kED;Ee7kED;IACE,UAAA;Gf+kED;EehlED;IACE,mBAAA;GfklED;EenlED;IACE,mBAAA;GfqlED;EetlED;IACE,UAAA;GfwlED;EezlED;IACE,mBAAA;Gf2lED;Ee5lED;IACE,kBAAA;Gf8lED;Ee1lED;IACE,WAAA;Gf4lED;Ee9kED;IACE,kBAAA;GfglED;EejlED;IACE,0BAAA;GfmlED;EeplED;IACE,0BAAA;GfslED;EevlED;IACE,iBAAA;GfylED;Ee1lED;IACE,0BAAA;Gf4lED;Ee7lED;IACE,0BAAA;Gf+lED;EehmED;IACE,iBAAA;GfkmED;EenmED;IACE,0BAAA;GfqmED;EetmED;IACE,0BAAA;GfwmED;EezmED;IACE,iBAAA;Gf2mED;Ee5mED;IACE,0BAAA;Gf8mED;Ee/mED;IACE,yBAAA;GfinED;EelnED;IACE,gBAAA;GfonED;CACF;AgBxrED;EACE,8BAAA;ChB0rED;AgBxrED;EACE,iBAAA;EACA,oBAAA;EACA,eAAA;EACA,iBAAA;ChB0rED;AgBxrED;EACE,iBAAA;ChB0rED;AgBprED;EACE,YAAA;EACA,gBAAA;EACA,oBAAA;ChBsrED;AgBzrED;;;;;;EAWQ,aAAA;EACA,wBAAA;EACA,oBAAA;EACA,8BAAA;ChBsrEP;AgBpsED;EAoBI,uBAAA;EACA,iCAAA;ChBmrEH;AgBxsED;;;;;;EA8BQ,cAAA;ChBkrEP;AgBhtED;EAoCI,8BAAA;ChB+qEH;AgBntED;EAyCI,0BAAA;ChB6qEH;AgBtqED;;;;;;EAOQ,aAAA;ChBuqEP;AgB5pED;EACE,0BAAA;ChB8pED;AgB/pED;;;;;;EAQQ,0BAAA;ChB+pEP;AgBvqED;;EAeM,yBAAA;ChB4pEL;AgBlpED;EAEI,0BAAA;ChBmpEH;AgB1oED;EAEI,0BAAA;ChB2oEH;AgBloED;EACE,iBAAA;EACA,YAAA;EACA,sBAAA;ChBooED;AgB/nEG;;EACE,iBAAA;EACA,YAAA;EACA,oBAAA;ChBkoEL;AiB9wEC;;;;;;;;;;;;EAOI,0BAAA;CjBqxEL;AiB/wEC;;;;;EAMI,0BAAA;CjBgxEL;AiBnyEC;;;;;;;;;;;;EAOI,0BAAA;CjB0yEL;AiBpyEC;;;;;EAMI,0BAAA;CjBqyEL;AiBxzEC;;;;;;;;;;;;EAOI,0BAAA;CjB+zEL;AiBzzEC;;;;;EAMI,0BAAA;CjB0zEL;AiB70EC;;;;;;;;;;;;EAOI,0BAAA;CjBo1EL;AiB90EC;;;;;EAMI,0BAAA;CjB+0EL;AiBl2EC;;;;;;;;;;;;EAOI,0BAAA;CjBy2EL;AiBn2EC;;;;;EAMI,0BAAA;CjBo2EL;AgBltED;EACE,iBAAA;EACA,kBAAA;ChBotED;AgBvpED;EAAA;IA1DI,YAAA;IACA,oBAAA;IACA,mBAAA;IACA,6CAAA;IACA,0BAAA;GhBqtED;EgB/pEH;IAlDM,iBAAA;GhBotEH;EgBlqEH;;;;;;IAzCY,oBAAA;GhBmtET;EgB1qEH;IAjCM,UAAA;GhB8sEH;EgB7qEH;;;;;;IAxBY,eAAA;GhB6sET;EgBrrEH;;;;;;IApBY,gBAAA;GhBitET;EgB7rEH;;;;IAPY,iBAAA;GhB0sET;CACF;AkBp6ED;EACE,WAAA;EACA,UAAA;EACA,UAAA;EAIA,aAAA;ClBm6ED;AkBh6ED;EACE,eAAA;EACA,YAAA;EACA,WAAA;EACA,oBAAA;EACA,gBAAA;EACA,qBAAA;EACA,eAAA;EACA,UAAA;EACA,iCAAA;ClBk6ED;AkB/5ED;EACE,sBAAA;EACA,gBAAA;EACA,mBAAA;EACA,kBAAA;ClBi6ED;AkBt5ED;Eb4BE,+BAAA;EACG,4BAAA;EACK,uBAAA;CL63ET;AkBt5ED;;EAEE,gBAAA;EACA,mBAAA;EACA,oBAAA;ClBw5ED;AkBr5ED;EACE,eAAA;ClBu5ED;AkBn5ED;EACE,eAAA;EACA,YAAA;ClBq5ED;AkBj5ED;;EAEE,aAAA;ClBm5ED;AkB/4ED;;;EZvEE,qBAAA;EAEA,2CAAA;EACA,qBAAA;CN09ED;AkB/4ED;EACE,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;ClBi5ED;AkBv3ED;EACE,eAAA;EACA,YAAA;EACA,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,0BAAA;EACA,uBAAA;EACA,0BAAA;EACA,mBAAA;EbxDA,yDAAA;EACQ,iDAAA;EAyHR,uFAAA;EACK,0EAAA;EACG,uEAAA;CL0zET;AmBl8EC;EACE,sBAAA;EACA,WAAA;EdUF,uFAAA;EACQ,+EAAA;CL27ET;AK15EC;EACE,eAAA;EACA,WAAA;CL45EH;AK15EC;EAA0B,eAAA;CL65E3B;AK55EC;EAAgC,eAAA;CL+5EjC;AkB/3EC;;;EAGE,0BAAA;EACA,WAAA;ClBi4EH;AkB93EC;;EAEE,oBAAA;ClBg4EH;AkB53EC;EACE,aAAA;ClB83EH;AkBl3ED;EACE,yBAAA;ClBo3ED;AkB50ED;EAtBI;;;;IACE,kBAAA;GlBw2EH;EkBr2EC;;;;;;;;IAEE,kBAAA;GlB62EH;EkB12EC;;;;;;;;IAEE,kBAAA;GlBk3EH;CACF;AkBx2ED;EACE,oBAAA;ClB02ED;AkBl2ED;;EAEE,mBAAA;EACA,eAAA;EACA,iBAAA;EACA,oBAAA;ClBo2ED;AkBz2ED;;EAQI,iBAAA;EACA,mBAAA;EACA,iBAAA;EACA,oBAAA;EACA,gBAAA;ClBq2EH;AkBl2ED;;;;EAIE,mBAAA;EACA,mBAAA;EACA,mBAAA;ClBo2ED;AkBj2ED;;EAEE,iBAAA;ClBm2ED;AkB/1ED;;EAEE,mBAAA;EACA,sBAAA;EACA,mBAAA;EACA,iBAAA;EACA,uBAAA;EACA,oBAAA;EACA,gBAAA;ClBi2ED;AkB/1ED;;EAEE,cAAA;EACA,kBAAA;ClBi2ED;AkBx1EC;;;;;;EAGE,oBAAA;ClB61EH;AkBv1EC;;;;EAEE,oBAAA;ClB21EH;AkBr1EC;;;;EAGI,oBAAA;ClBw1EL;AkB70ED;EAEE,iBAAA;EACA,oBAAA;EAEA,iBAAA;EACA,iBAAA;ClB60ED;AkB30EC;;EAEE,gBAAA;EACA,iBAAA;ClB60EH;AkBh0ED;EC7PE,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CnBgkFD;AmB9jFC;EACE,aAAA;EACA,kBAAA;CnBgkFH;AmB7jFC;;EAEE,aAAA;CnB+jFH;AkB50ED;EAEI,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;ClB60EH;AkBn1ED;EASI,aAAA;EACA,kBAAA;ClB60EH;AkBv1ED;;EAcI,aAAA;ClB60EH;AkB31ED;EAiBI,aAAA;EACA,iBAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;ClB60EH;AkBz0ED;ECzRE,aAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;CnBqmFD;AmBnmFC;EACE,aAAA;EACA,kBAAA;CnBqmFH;AmBlmFC;;EAEE,aAAA;CnBomFH;AkBr1ED;EAEI,aAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;ClBs1EH;AkB51ED;EASI,aAAA;EACA,kBAAA;ClBs1EH;AkBh2ED;;EAcI,aAAA;ClBs1EH;AkBp2ED;EAiBI,aAAA;EACA,iBAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;ClBs1EH;AkB70ED;EAEE,mBAAA;ClB80ED;AkBh1ED;EAMI,sBAAA;ClB60EH;AkBz0ED;EACE,mBAAA;EACA,OAAA;EACA,SAAA;EACA,WAAA;EACA,eAAA;EACA,YAAA;EACA,aAAA;EACA,kBAAA;EACA,mBAAA;EACA,qBAAA;ClB20ED;AkBz0ED;;;EAGE,YAAA;EACA,aAAA;EACA,kBAAA;ClB20ED;AkBz0ED;;;EAGE,YAAA;EACA,aAAA;EACA,kBAAA;ClB20ED;AkBv0ED;;;;;;;;;;ECpZI,eAAA;CnBuuFH;AkBn1ED;EChZI,sBAAA;Ed+CF,yDAAA;EACQ,iDAAA;CLwrFT;AmBtuFG;EACE,sBAAA;Ed4CJ,0EAAA;EACQ,kEAAA;CL6rFT;AkB71ED;ECtYI,eAAA;EACA,sBAAA;EACA,0BAAA;CnBsuFH;AkBl2ED;EChYI,eAAA;CnBquFH;AkBl2ED;;;;;;;;;;ECvZI,eAAA;CnBqwFH;AkB92ED;ECnZI,sBAAA;Ed+CF,yDAAA;EACQ,iDAAA;CLstFT;AmBpwFG;EACE,sBAAA;Ed4CJ,0EAAA;EACQ,kEAAA;CL2tFT;AkBx3ED;ECzYI,eAAA;EACA,sBAAA;EACA,0BAAA;CnBowFH;AkB73ED;ECnYI,eAAA;CnBmwFH;AkB73ED;;;;;;;;;;EC1ZI,eAAA;CnBmyFH;AkBz4ED;ECtZI,sBAAA;Ed+CF,yDAAA;EACQ,iDAAA;CLovFT;AmBlyFG;EACE,sBAAA;Ed4CJ,0EAAA;EACQ,kEAAA;CLyvFT;AkBn5ED;EC5YI,eAAA;EACA,sBAAA;EACA,0BAAA;CnBkyFH;AkBx5ED;ECtYI,eAAA;CnBiyFH;AkBp5EC;EACG,UAAA;ClBs5EJ;AkBp5EC;EACG,OAAA;ClBs5EJ;AkB54ED;EACE,eAAA;EACA,gBAAA;EACA,oBAAA;EACA,eAAA;ClB84ED;AkB3zED;EAAA;IA9DM,sBAAA;IACA,iBAAA;IACA,uBAAA;GlB63EH;EkBj0EH;IAvDM,sBAAA;IACA,YAAA;IACA,uBAAA;GlB23EH;EkBt0EH;IAhDM,sBAAA;GlBy3EH;EkBz0EH;IA5CM,sBAAA;IACA,uBAAA;GlBw3EH;EkB70EH;;;IAtCQ,YAAA;GlBw3EL;EkBl1EH;IAhCM,YAAA;GlBq3EH;EkBr1EH;IA5BM,iBAAA;IACA,uBAAA;GlBo3EH;EkBz1EH;;IApBM,sBAAA;IACA,cAAA;IACA,iBAAA;IACA,uBAAA;GlBi3EH;EkBh2EH;;IAdQ,gBAAA;GlBk3EL;EkBp2EH;;IATM,mBAAA;IACA,eAAA;GlBi3EH;EkBz2EH;IAHM,OAAA;GlB+2EH;CACF;AkBr2ED;;;;EASI,cAAA;EACA,iBAAA;EACA,iBAAA;ClBk2EH;AkB72ED;;EAiBI,iBAAA;ClBg2EH;AkBj3ED;EJhhBE,mBAAA;EACA,oBAAA;Cdo4FD;AkB90EC;EAAA;IAVI,kBAAA;IACA,iBAAA;IACA,iBAAA;GlB41EH;CACF;AkB53ED;EAwCI,YAAA;ClBu1EH;AkBz0EC;EAAA;IAJM,yBAAA;IACA,gBAAA;GlBi1EL;CACF;AkBv0EC;EAAA;IAJM,iBAAA;IACA,gBAAA;GlB+0EL;CACF;AoBl6FD;EACE,sBAAA;EACA,iBAAA;EACA,oBAAA;EACA,mBAAA;EACA,uBAAA;EACA,+BAAA;MAAA,2BAAA;EACA,gBAAA;EACA,uBAAA;EACA,8BAAA;EACA,oBAAA;EC6CA,kBAAA;EACA,gBAAA;EACA,wBAAA;EACA,mBAAA;EhB4JA,0BAAA;EACG,uBAAA;EACC,sBAAA;EACI,kBAAA;CL6tFT;AoBr6FG;;;;;;EdrBF,qBAAA;EAEA,2CAAA;EACA,qBAAA;CNi8FD;AoBz6FC;;;EAGE,eAAA;EACA,sBAAA;CpB26FH;AoBx6FC;;EAEE,WAAA;EACA,uBAAA;Ef2BF,yDAAA;EACQ,iDAAA;CLg5FT;AoBx6FC;;;EAGE,oBAAA;EE7CF,cAAA;EAGA,0BAAA;EjB8DA,yBAAA;EACQ,iBAAA;CLy5FT;AoBx6FG;;EAEE,qBAAA;CpB06FL;AoBj6FD;EC3DE,eAAA;EACA,0BAAA;EACA,sBAAA;CrB+9FD;AqB79FC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB+9FP;AqB79FC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB+9FP;AqB79FC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB+9FP;AqB79FG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBq+FT;AqBl+FC;;;EAGE,uBAAA;CrBo+FH;AqB/9FG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrB6+FT;AoB/9FD;ECTI,eAAA;EACA,0BAAA;CrB2+FH;AoBh+FD;EC9DE,eAAA;EACA,0BAAA;EACA,sBAAA;CrBiiGD;AqB/hGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBiiGP;AqB/hGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBiiGP;AqB/hGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBiiGP;AqB/hGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBuiGT;AqBpiGC;;;EAGE,uBAAA;CrBsiGH;AqBjiGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrB+iGT;AoB9hGD;ECZI,eAAA;EACA,0BAAA;CrB6iGH;AoB9hGD;EClEE,eAAA;EACA,0BAAA;EACA,sBAAA;CrBmmGD;AqBjmGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBmmGP;AqBjmGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBmmGP;AqBjmGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBmmGP;AqBjmGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBymGT;AqBtmGC;;;EAGE,uBAAA;CrBwmGH;AqBnmGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrBinGT;AoB5lGD;EChBI,eAAA;EACA,0BAAA;CrB+mGH;AoB5lGD;ECtEE,eAAA;EACA,0BAAA;EACA,sBAAA;CrBqqGD;AqBnqGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBqqGP;AqBnqGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBqqGP;AqBnqGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBqqGP;AqBnqGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB2qGT;AqBxqGC;;;EAGE,uBAAA;CrB0qGH;AqBrqGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrBmrGT;AoB1pGD;ECpBI,eAAA;EACA,0BAAA;CrBirGH;AoB1pGD;EC1EE,eAAA;EACA,0BAAA;EACA,sBAAA;CrBuuGD;AqBruGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBuuGP;AqBruGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBuuGP;AqBruGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBuuGP;AqBruGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB6uGT;AqB1uGC;;;EAGE,uBAAA;CrB4uGH;AqBvuGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrBqvGT;AoBxtGD;ECxBI,eAAA;EACA,0BAAA;CrBmvGH;AoBxtGD;EC9EE,eAAA;EACA,0BAAA;EACA,sBAAA;CrByyGD;AqBvyGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrByyGP;AqBvyGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrByyGP;AqBvyGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrByyGP;AqBvyGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB+yGT;AqB5yGC;;;EAGE,uBAAA;CrB8yGH;AqBzyGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrBuzGT;AoBtxGD;EC5BI,eAAA;EACA,0BAAA;CrBqzGH;AoBjxGD;EACE,eAAA;EACA,oBAAA;EACA,iBAAA;CpBmxGD;AoBjxGC;;;;;EAKE,8BAAA;EfnCF,yBAAA;EACQ,iBAAA;CLuzGT;AoBlxGC;;;;EAIE,0BAAA;CpBoxGH;AoBlxGC;;EAEE,eAAA;EACA,2BAAA;EACA,8BAAA;CpBoxGH;AoBhxGG;;;;EAEE,eAAA;EACA,sBAAA;CpBoxGL;AoB3wGD;;ECrEE,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;CrBo1GD;AoB9wGD;;ECzEE,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CrB21GD;AoBjxGD;;EC7EE,iBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CrBk2GD;AoBhxGD;EACE,eAAA;EACA,YAAA;CpBkxGD;AoB9wGD;EACE,gBAAA;CpBgxGD;AoBzwGC;;;EACE,YAAA;CpB6wGH;AuBv6GD;EACE,WAAA;ElBoLA,yCAAA;EACK,oCAAA;EACG,iCAAA;CLsvGT;AuB16GC;EACE,WAAA;CvB46GH;AuBx6GD;EACE,cAAA;CvB06GD;AuBx6GC;EAAY,eAAA;CvB26Gb;AuB16GC;EAAY,mBAAA;CvB66Gb;AuB56GC;EAAY,yBAAA;CvB+6Gb;AuB56GD;EACE,mBAAA;EACA,UAAA;EACA,iBAAA;ElBuKA,gDAAA;EACQ,2CAAA;KAAA,wCAAA;EAOR,mCAAA;EACQ,8BAAA;KAAA,2BAAA;EAGR,yCAAA;EACQ,oCAAA;KAAA,iCAAA;CLgwGT;AwB18GD;EACE,sBAAA;EACA,SAAA;EACA,UAAA;EACA,iBAAA;EACA,uBAAA;EACA,uBAAA;EACA,yBAAA;EACA,oCAAA;EACA,mCAAA;CxB48GD;AwBx8GD;;EAEE,mBAAA;CxB08GD;AwBt8GD;EACE,WAAA;CxBw8GD;AwBp8GD;EACE,mBAAA;EACA,UAAA;EACA,QAAA;EACA,cAAA;EACA,cAAA;EACA,YAAA;EACA,iBAAA;EACA,eAAA;EACA,gBAAA;EACA,iBAAA;EACA,gBAAA;EACA,iBAAA;EACA,0BAAA;EACA,0BAAA;EACA,sCAAA;EACA,mBAAA;EnBsBA,oDAAA;EACQ,4CAAA;EmBrBR,qCAAA;UAAA,6BAAA;CxBu8GD;AwBl8GC;EACE,SAAA;EACA,WAAA;CxBo8GH;AwB79GD;ECzBE,YAAA;EACA,cAAA;EACA,iBAAA;EACA,0BAAA;CzBy/GD;AwBn+GD;EAmCI,eAAA;EACA,kBAAA;EACA,YAAA;EACA,oBAAA;EACA,wBAAA;EACA,eAAA;EACA,oBAAA;CxBm8GH;AwB77GC;;EAEE,sBAAA;EACA,eAAA;EACA,0BAAA;CxB+7GH;AwBz7GC;;;EAGE,eAAA;EACA,sBAAA;EACA,WAAA;EACA,0BAAA;CxB27GH;AwBl7GC;;;EAGE,eAAA;CxBo7GH;AwBh7GC;;EAEE,sBAAA;EACA,8BAAA;EACA,uBAAA;EE3GF,oEAAA;EF6GE,oBAAA;CxBk7GH;AwB76GD;EAGI,eAAA;CxB66GH;AwBh7GD;EAQI,WAAA;CxB26GH;AwBn6GD;EACE,WAAA;EACA,SAAA;CxBq6GD;AwB75GD;EACE,QAAA;EACA,YAAA;CxB+5GD;AwB35GD;EACE,eAAA;EACA,kBAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,oBAAA;CxB65GD;AwBz5GD;EACE,gBAAA;EACA,QAAA;EACA,SAAA;EACA,UAAA;EACA,OAAA;EACA,aAAA;CxB25GD;AwBv5GD;EACE,SAAA;EACA,WAAA;CxBy5GD;AwBj5GD;;EAII,cAAA;EACA,0BAAA;EACA,4BAAA;EACA,YAAA;CxBi5GH;AwBx5GD;;EAWI,UAAA;EACA,aAAA;EACA,mBAAA;CxBi5GH;AwB53GD;EAXE;IApEA,WAAA;IACA,SAAA;GxB+8GC;EwB54GD;IA1DA,QAAA;IACA,YAAA;GxBy8GC;CACF;A2BzlHD;;EAEE,mBAAA;EACA,sBAAA;EACA,uBAAA;C3B2lHD;A2B/lHD;;EAMI,mBAAA;EACA,YAAA;C3B6lHH;A2B3lHG;;;;;;;;EAIE,WAAA;C3BimHL;A2B3lHD;;;;EAKI,kBAAA;C3B4lHH;A2BvlHD;EACE,kBAAA;C3BylHD;A2B1lHD;;;EAOI,YAAA;C3BwlHH;A2B/lHD;;;EAYI,iBAAA;C3BwlHH;A2BplHD;EACE,iBAAA;C3BslHD;A2BllHD;EACE,eAAA;C3BolHD;A2BnlHC;EClDA,8BAAA;EACG,2BAAA;C5BwoHJ;A2BllHD;;EC/CE,6BAAA;EACG,0BAAA;C5BqoHJ;A2BjlHD;EACE,YAAA;C3BmlHD;A2BjlHD;EACE,iBAAA;C3BmlHD;A2BjlHD;;ECnEE,8BAAA;EACG,2BAAA;C5BwpHJ;A2BhlHD;ECjEE,6BAAA;EACG,0BAAA;C5BopHJ;A2B/kHD;;EAEE,WAAA;C3BilHD;A2BhkHD;EACE,kBAAA;EACA,mBAAA;C3BkkHD;A2BhkHD;EACE,mBAAA;EACA,oBAAA;C3BkkHD;A2B7jHD;EtB/CE,yDAAA;EACQ,iDAAA;CL+mHT;A2B7jHC;EtBnDA,yBAAA;EACQ,iBAAA;CLmnHT;A2B1jHD;EACE,eAAA;C3B4jHD;A2BzjHD;EACE,wBAAA;EACA,uBAAA;C3B2jHD;A2BxjHD;EACE,wBAAA;C3B0jHD;A2BnjHD;;;EAII,eAAA;EACA,YAAA;EACA,YAAA;EACA,gBAAA;C3BojHH;A2B3jHD;EAcM,YAAA;C3BgjHL;A2B9jHD;;;;EAsBI,iBAAA;EACA,eAAA;C3B8iHH;A2BziHC;EACE,iBAAA;C3B2iHH;A2BziHC;EACE,6BAAA;ECpKF,8BAAA;EACC,6BAAA;C5BgtHF;A2B1iHC;EACE,+BAAA;EChLF,2BAAA;EACC,0BAAA;C5B6tHF;A2B1iHD;EACE,iBAAA;C3B4iHD;A2B1iHD;;EC/KE,8BAAA;EACC,6BAAA;C5B6tHF;A2BziHD;EC7LE,2BAAA;EACC,0BAAA;C5ByuHF;A2BriHD;EACE,eAAA;EACA,YAAA;EACA,oBAAA;EACA,0BAAA;C3BuiHD;A2B3iHD;;EAOI,YAAA;EACA,oBAAA;EACA,UAAA;C3BwiHH;A2BjjHD;EAYI,YAAA;C3BwiHH;A2BpjHD;EAgBI,WAAA;C3BuiHH;A2BthHD;;;;EAKM,mBAAA;EACA,uBAAA;EACA,qBAAA;C3BuhHL;A6BjwHD;EACE,mBAAA;EACA,eAAA;EACA,0BAAA;C7BmwHD;A6BhwHC;EACE,YAAA;EACA,gBAAA;EACA,iBAAA;C7BkwHH;A6B3wHD;EAeI,mBAAA;EACA,WAAA;EAKA,YAAA;EAEA,YAAA;EACA,iBAAA;C7B0vHH;A6BjvHD;;;EV8BE,aAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;CnBwtHD;AmBttHC;;;EACE,aAAA;EACA,kBAAA;CnB0tHH;AmBvtHC;;;;;;EAEE,aAAA;CnB6tHH;A6BnwHD;;;EVyBE,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CnB+uHD;AmB7uHC;;;EACE,aAAA;EACA,kBAAA;CnBivHH;AmB9uHC;;;;;;EAEE,aAAA;CnBovHH;A6BjxHD;;;EAGE,oBAAA;C7BmxHD;A6BjxHC;;;EACE,iBAAA;C7BqxHH;A6BjxHD;;EAEE,UAAA;EACA,oBAAA;EACA,uBAAA;C7BmxHD;A6B9wHD;EACE,kBAAA;EACA,gBAAA;EACA,oBAAA;EACA,eAAA;EACA,eAAA;EACA,mBAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;C7BgxHD;A6B7wHC;EACE,kBAAA;EACA,gBAAA;EACA,mBAAA;C7B+wHH;A6B7wHC;EACE,mBAAA;EACA,gBAAA;EACA,mBAAA;C7B+wHH;A6BnyHD;;EA0BI,cAAA;C7B6wHH;A6BxwHD;;;;;;;EDhGE,8BAAA;EACG,2BAAA;C5Bi3HJ;A6BzwHD;EACE,gBAAA;C7B2wHD;A6BzwHD;;;;;;;EDpGE,6BAAA;EACG,0BAAA;C5Bs3HJ;A6B1wHD;EACE,eAAA;C7B4wHD;A6BvwHD;EACE,mBAAA;EAGA,aAAA;EACA,oBAAA;C7BuwHD;A6B5wHD;EAUI,mBAAA;C7BqwHH;A6B/wHD;EAYM,kBAAA;C7BswHL;A6BnwHG;;;EAGE,WAAA;C7BqwHL;A6BhwHC;;EAGI,mBAAA;C7BiwHL;A6B9vHC;;EAGI,WAAA;EACA,kBAAA;C7B+vHL;A8B15HD;EACE,iBAAA;EACA,gBAAA;EACA,iBAAA;C9B45HD;A8B/5HD;EAOI,mBAAA;EACA,eAAA;C9B25HH;A8Bn6HD;EAWM,mBAAA;EACA,eAAA;EACA,mBAAA;C9B25HL;A8B15HK;;EAEE,sBAAA;EACA,0BAAA;C9B45HP;A8Bv5HG;EACE,eAAA;C9By5HL;A8Bv5HK;;EAEE,eAAA;EACA,sBAAA;EACA,8BAAA;EACA,oBAAA;C9By5HP;A8Bl5HG;;;EAGE,0BAAA;EACA,sBAAA;C9Bo5HL;A8B77HD;ELHE,YAAA;EACA,cAAA;EACA,iBAAA;EACA,0BAAA;CzBm8HD;A8Bn8HD;EA0DI,gBAAA;C9B44HH;A8Bn4HD;EACE,iCAAA;C9Bq4HD;A8Bt4HD;EAGI,YAAA;EAEA,oBAAA;C9Bq4HH;A8B14HD;EASM,kBAAA;EACA,wBAAA;EACA,8BAAA;EACA,2BAAA;C9Bo4HL;A8Bn4HK;EACE,sCAAA;C9Bq4HP;A8B/3HK;;;EAGE,eAAA;EACA,0BAAA;EACA,0BAAA;EACA,iCAAA;EACA,gBAAA;C9Bi4HP;A8B53HC;EAqDA,YAAA;EA8BA,iBAAA;C9B6yHD;A8Bh4HC;EAwDE,YAAA;C9B20HH;A8Bn4HC;EA0DI,mBAAA;EACA,mBAAA;C9B40HL;A8Bv4HC;EAgEE,UAAA;EACA,WAAA;C9B00HH;A8B9zHD;EAAA;IAPM,oBAAA;IACA,UAAA;G9By0HH;E8Bn0HH;IAJQ,iBAAA;G9B00HL;CACF;A8Bp5HC;EAuFE,gBAAA;EACA,mBAAA;C9Bg0HH;A8Bx5HC;;;EA8FE,0BAAA;C9B+zHH;A8BjzHD;EAAA;IATM,iCAAA;IACA,2BAAA;G9B8zHH;E8BtzHH;;;IAHM,6BAAA;G9B8zHH;CACF;A8B/5HD;EAEI,YAAA;C9Bg6HH;A8Bl6HD;EAMM,mBAAA;C9B+5HL;A8Br6HD;EASM,iBAAA;C9B+5HL;A8B15HK;;;EAGE,eAAA;EACA,0BAAA;C9B45HP;A8Bp5HD;EAEI,YAAA;C9Bq5HH;A8Bv5HD;EAIM,gBAAA;EACA,eAAA;C9Bs5HL;A8B14HD;EACE,YAAA;C9B44HD;A8B74HD;EAII,YAAA;C9B44HH;A8Bh5HD;EAMM,mBAAA;EACA,mBAAA;C9B64HL;A8Bp5HD;EAYI,UAAA;EACA,WAAA;C9B24HH;A8B/3HD;EAAA;IAPM,oBAAA;IACA,UAAA;G9B04HH;E8Bp4HH;IAJQ,iBAAA;G9B24HL;CACF;A8Bn4HD;EACE,iBAAA;C9Bq4HD;A8Bt4HD;EAKI,gBAAA;EACA,mBAAA;C9Bo4HH;A8B14HD;;;EAYI,0BAAA;C9Bm4HH;A8Br3HD;EAAA;IATM,iCAAA;IACA,2BAAA;G9Bk4HH;E8B13HH;;;IAHM,6BAAA;G9Bk4HH;CACF;A8Bz3HD;EAEI,cAAA;C9B03HH;A8B53HD;EAKI,eAAA;C9B03HH;A8Bj3HD;EAEE,iBAAA;EF3OA,2BAAA;EACC,0BAAA;C5B8lIF;A+BxlID;EACE,mBAAA;EACA,iBAAA;EACA,oBAAA;EACA,8BAAA;C/B0lID;A+BllID;EAAA;IAFI,mBAAA;G/BwlID;CACF;A+BzkID;EAAA;IAFI,YAAA;G/B+kID;CACF;A+BjkID;EACE,oBAAA;EACA,oBAAA;EACA,mBAAA;EACA,kCAAA;EACA,2DAAA;UAAA,mDAAA;EAEA,kCAAA;C/BkkID;A+BhkIC;EACE,iBAAA;C/BkkIH;A+BtiID;EAAA;IAxBI,YAAA;IACA,cAAA;IACA,yBAAA;YAAA,iBAAA;G/BkkID;E+BhkIC;IACE,0BAAA;IACA,wBAAA;IACA,kBAAA;IACA,6BAAA;G/BkkIH;E+B/jIC;IACE,oBAAA;G/BikIH;E+B5jIC;;;IAGE,gBAAA;IACA,iBAAA;G/B8jIH;CACF;A+B1jID;;EAGI,kBAAA;C/B2jIH;A+BtjIC;EAAA;;IAFI,kBAAA;G/B6jIH;CACF;A+BpjID;;;;EAII,oBAAA;EACA,mBAAA;C/BsjIH;A+BhjIC;EAAA;;;;IAHI,gBAAA;IACA,eAAA;G/B0jIH;CACF;A+B9iID;EACE,cAAA;EACA,sBAAA;C/BgjID;A+B3iID;EAAA;IAFI,iBAAA;G/BijID;CACF;A+B7iID;;EAEE,gBAAA;EACA,SAAA;EACA,QAAA;EACA,cAAA;C/B+iID;A+BziID;EAAA;;IAFI,iBAAA;G/BgjID;CACF;A+B9iID;EACE,OAAA;EACA,sBAAA;C/BgjID;A+B9iID;EACE,UAAA;EACA,iBAAA;EACA,sBAAA;C/BgjID;A+B1iID;EACE,YAAA;EACA,mBAAA;EACA,gBAAA;EACA,kBAAA;EACA,aAAA;C/B4iID;A+B1iIC;;EAEE,sBAAA;C/B4iIH;A+BrjID;EAaI,eAAA;C/B2iIH;A+BliID;EALI;;IAEE,mBAAA;G/B0iIH;CACF;A+BhiID;EACE,mBAAA;EACA,aAAA;EACA,mBAAA;EACA,kBAAA;EC9LA,gBAAA;EACA,mBAAA;ED+LA,8BAAA;EACA,uBAAA;EACA,8BAAA;EACA,mBAAA;C/BmiID;A+B/hIC;EACE,WAAA;C/BiiIH;A+B/iID;EAmBI,eAAA;EACA,YAAA;EACA,YAAA;EACA,mBAAA;C/B+hIH;A+BrjID;EAyBI,gBAAA;C/B+hIH;A+BzhID;EAAA;IAFI,cAAA;G/B+hID;CACF;A+BthID;EACE,oBAAA;C/BwhID;A+BzhID;EAII,kBAAA;EACA,qBAAA;EACA,kBAAA;C/BwhIH;A+B5/HC;EAAA;IAtBI,iBAAA;IACA,YAAA;IACA,YAAA;IACA,cAAA;IACA,8BAAA;IACA,UAAA;IACA,yBAAA;YAAA,iBAAA;G/BshIH;E+BtgID;;IAbM,2BAAA;G/BuhIL;E+B1gID;IAVM,kBAAA;G/BuhIL;E+BthIK;;IAEE,uBAAA;G/BwhIP;CACF;A+BtgID;EAAA;IAXI,YAAA;IACA,UAAA;G/BqhID;E+B3gIH;IAPM,YAAA;G/BqhIH;E+B9gIH;IALQ,kBAAA;IACA,qBAAA;G/BshIL;CACF;A+B3gID;EACE,mBAAA;EACA,oBAAA;EACA,mBAAA;EACA,kCAAA;EACA,qCAAA;E1B9NA,6FAAA;EACQ,qFAAA;E2B/DR,gBAAA;EACA,mBAAA;ChC4yID;AkB5xHD;EAAA;IA9DM,sBAAA;IACA,iBAAA;IACA,uBAAA;GlB81HH;EkBlyHH;IAvDM,sBAAA;IACA,YAAA;IACA,uBAAA;GlB41HH;EkBvyHH;IAhDM,sBAAA;GlB01HH;EkB1yHH;IA5CM,sBAAA;IACA,uBAAA;GlBy1HH;EkB9yHH;;;IAtCQ,YAAA;GlBy1HL;EkBnzHH;IAhCM,YAAA;GlBs1HH;EkBtzHH;IA5BM,iBAAA;IACA,uBAAA;GlBq1HH;EkB1zHH;;IApBM,sBAAA;IACA,cAAA;IACA,iBAAA;IACA,uBAAA;GlBk1HH;EkBj0HH;;IAdQ,gBAAA;GlBm1HL;EkBr0HH;;IATM,mBAAA;IACA,eAAA;GlBk1HH;EkB10HH;IAHM,OAAA;GlBg1HH;CACF;A+BpjIC;EAAA;IANI,mBAAA;G/B8jIH;E+B5jIG;IACE,iBAAA;G/B8jIL;CACF;A+B7iID;EAAA;IARI,YAAA;IACA,UAAA;IACA,eAAA;IACA,gBAAA;IACA,eAAA;IACA,kBAAA;I1BzPF,yBAAA;IACQ,iBAAA;GLmzIP;CACF;A+BnjID;EACE,cAAA;EHpUA,2BAAA;EACC,0BAAA;C5B03IF;A+BnjID;EACE,iBAAA;EHzUA,6BAAA;EACC,4BAAA;EAOD,8BAAA;EACC,6BAAA;C5By3IF;A+B/iID;EChVE,gBAAA;EACA,mBAAA;ChCk4ID;A+BhjIC;ECnVA,iBAAA;EACA,oBAAA;ChCs4ID;A+BjjIC;ECtVA,iBAAA;EACA,oBAAA;ChC04ID;A+B3iID;EChWE,iBAAA;EACA,oBAAA;ChC84ID;A+BviID;EAAA;IAJI,YAAA;IACA,kBAAA;IACA,mBAAA;G/B+iID;CACF;A+BlhID;EAhBE;IExWA,uBAAA;GjC84IC;E+BriID;IE5WA,wBAAA;IF8WE,oBAAA;G/BuiID;E+BziID;IAKI,gBAAA;G/BuiIH;CACF;A+B9hID;EACE,0BAAA;EACA,sBAAA;C/BgiID;A+BliID;EAKI,eAAA;C/BgiIH;A+B/hIG;;EAEE,eAAA;EACA,8BAAA;C/BiiIL;A+B1iID;EAcI,eAAA;C/B+hIH;A+B7iID;EAmBM,eAAA;C/B6hIL;A+B3hIK;;EAEE,eAAA;EACA,8BAAA;C/B6hIP;A+BzhIK;;;EAGE,eAAA;EACA,0BAAA;C/B2hIP;A+BvhIK;;;EAGE,eAAA;EACA,8BAAA;C/ByhIP;A+BjkID;EA8CI,sBAAA;C/BshIH;A+BrhIG;;EAEE,0BAAA;C/BuhIL;A+BxkID;EAoDM,0BAAA;C/BuhIL;A+B3kID;;EA0DI,sBAAA;C/BqhIH;A+B9gIK;;;EAGE,0BAAA;EACA,eAAA;C/BghIP;A+B/+HC;EAAA;IAzBQ,eAAA;G/B4gIP;E+B3gIO;;IAEE,eAAA;IACA,8BAAA;G/B6gIT;E+BzgIO;;;IAGE,eAAA;IACA,0BAAA;G/B2gIT;E+BvgIO;;;IAGE,eAAA;IACA,8BAAA;G/BygIT;CACF;A+B3mID;EA8GI,eAAA;C/BggIH;A+B//HG;EACE,eAAA;C/BigIL;A+BjnID;EAqHI,eAAA;C/B+/HH;A+B9/HG;;EAEE,eAAA;C/BggIL;A+B5/HK;;;;EAEE,eAAA;C/BggIP;A+Bx/HD;EACE,0BAAA;EACA,sBAAA;C/B0/HD;A+B5/HD;EAKI,eAAA;C/B0/HH;A+Bz/HG;;EAEE,eAAA;EACA,8BAAA;C/B2/HL;A+BpgID;EAcI,eAAA;C/By/HH;A+BvgID;EAmBM,eAAA;C/Bu/HL;A+Br/HK;;EAEE,eAAA;EACA,8BAAA;C/Bu/HP;A+Bn/HK;;;EAGE,eAAA;EACA,0BAAA;C/Bq/HP;A+Bj/HK;;;EAGE,eAAA;EACA,8BAAA;C/Bm/HP;A+B3hID;EA+CI,sBAAA;C/B++HH;A+B9+HG;;EAEE,0BAAA;C/Bg/HL;A+BliID;EAqDM,0BAAA;C/Bg/HL;A+BriID;;EA2DI,sBAAA;C/B8+HH;A+Bx+HK;;;EAGE,0BAAA;EACA,eAAA;C/B0+HP;A+Bn8HC;EAAA;IA/BQ,sBAAA;G/Bs+HP;E+Bv8HD;IA5BQ,0BAAA;G/Bs+HP;E+B18HD;IAzBQ,eAAA;G/Bs+HP;E+Br+HO;;IAEE,eAAA;IACA,8BAAA;G/Bu+HT;E+Bn+HO;;;IAGE,eAAA;IACA,0BAAA;G/Bq+HT;E+Bj+HO;;;IAGE,eAAA;IACA,8BAAA;G/Bm+HT;CACF;A+B3kID;EA+GI,eAAA;C/B+9HH;A+B99HG;EACE,eAAA;C/Bg+HL;A+BjlID;EAsHI,eAAA;C/B89HH;A+B79HG;;EAEE,eAAA;C/B+9HL;A+B39HK;;;;EAEE,eAAA;C/B+9HP;AkCzmJD;EACE,kBAAA;EACA,oBAAA;EACA,iBAAA;EACA,0BAAA;EACA,mBAAA;ClC2mJD;AkChnJD;EAQI,sBAAA;ClC2mJH;AkCnnJD;EAWM,kBAAA;EACA,eAAA;EACA,eAAA;ClC2mJL;AkCxnJD;EAkBI,eAAA;ClCymJH;AmC7nJD;EACE,sBAAA;EACA,gBAAA;EACA,eAAA;EACA,mBAAA;CnC+nJD;AmCnoJD;EAOI,gBAAA;CnC+nJH;AmCtoJD;;EAUM,mBAAA;EACA,YAAA;EACA,kBAAA;EACA,wBAAA;EACA,sBAAA;EACA,eAAA;EACA,0BAAA;EACA,0BAAA;EACA,kBAAA;CnCgoJL;AmC9nJG;;EAGI,eAAA;EPXN,+BAAA;EACG,4BAAA;C5B2oJJ;AmC7nJG;;EPvBF,gCAAA;EACG,6BAAA;C5BwpJJ;AmCxnJG;;;;EAEE,WAAA;EACA,eAAA;EACA,0BAAA;EACA,sBAAA;CnC4nJL;AmCtnJG;;;;;;EAGE,WAAA;EACA,eAAA;EACA,0BAAA;EACA,sBAAA;EACA,gBAAA;CnC2nJL;AmClrJD;;;;;;EAkEM,eAAA;EACA,0BAAA;EACA,sBAAA;EACA,oBAAA;CnCwnJL;AmC/mJD;;EC3EM,mBAAA;EACA,gBAAA;EACA,uBAAA;CpC8rJL;AoC5rJG;;ERKF,+BAAA;EACG,4BAAA;C5B2rJJ;AoC3rJG;;ERTF,gCAAA;EACG,6BAAA;C5BwsJJ;AmC1nJD;;EChFM,kBAAA;EACA,gBAAA;EACA,iBAAA;CpC8sJL;AoC5sJG;;ERKF,+BAAA;EACG,4BAAA;C5B2sJJ;AoC3sJG;;ERTF,gCAAA;EACG,6BAAA;C5BwtJJ;AqC3tJD;EACE,gBAAA;EACA,eAAA;EACA,iBAAA;EACA,mBAAA;CrC6tJD;AqCjuJD;EAOI,gBAAA;CrC6tJH;AqCpuJD;;EAUM,sBAAA;EACA,kBAAA;EACA,0BAAA;EACA,0BAAA;EACA,oBAAA;CrC8tJL;AqC5uJD;;EAmBM,sBAAA;EACA,0BAAA;CrC6tJL;AqCjvJD;;EA2BM,aAAA;CrC0tJL;AqCrvJD;;EAkCM,YAAA;CrCutJL;AqCzvJD;;;;EA2CM,eAAA;EACA,0BAAA;EACA,oBAAA;CrCotJL;AsClwJD;EACE,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,kBAAA;EACA,eAAA;EACA,eAAA;EACA,mBAAA;EACA,oBAAA;EACA,yBAAA;EACA,qBAAA;CtCowJD;AsChwJG;;EAEE,eAAA;EACA,sBAAA;EACA,gBAAA;CtCkwJL;AsC7vJC;EACE,cAAA;CtC+vJH;AsC3vJC;EACE,mBAAA;EACA,UAAA;CtC6vJH;AsCtvJD;ECtCE,0BAAA;CvC+xJD;AuC5xJG;;EAEE,0BAAA;CvC8xJL;AsCzvJD;EC1CE,0BAAA;CvCsyJD;AuCnyJG;;EAEE,0BAAA;CvCqyJL;AsC5vJD;EC9CE,0BAAA;CvC6yJD;AuC1yJG;;EAEE,0BAAA;CvC4yJL;AsC/vJD;EClDE,0BAAA;CvCozJD;AuCjzJG;;EAEE,0BAAA;CvCmzJL;AsClwJD;ECtDE,0BAAA;CvC2zJD;AuCxzJG;;EAEE,0BAAA;CvC0zJL;AsCrwJD;EC1DE,0BAAA;CvCk0JD;AuC/zJG;;EAEE,0BAAA;CvCi0JL;AwCn0JD;EACE,sBAAA;EACA,gBAAA;EACA,iBAAA;EACA,gBAAA;EACA,kBAAA;EACA,eAAA;EACA,eAAA;EACA,uBAAA;EACA,oBAAA;EACA,mBAAA;EACA,0BAAA;EACA,oBAAA;CxCq0JD;AwCl0JC;EACE,cAAA;CxCo0JH;AwCh0JC;EACE,mBAAA;EACA,UAAA;CxCk0JH;AwC/zJC;;EAEE,OAAA;EACA,iBAAA;CxCi0JH;AwC5zJG;;EAEE,eAAA;EACA,sBAAA;EACA,gBAAA;CxC8zJL;AwCzzJC;;EAEE,eAAA;EACA,0BAAA;CxC2zJH;AwCxzJC;EACE,aAAA;CxC0zJH;AwCvzJC;EACE,kBAAA;CxCyzJH;AwCtzJC;EACE,iBAAA;CxCwzJH;AyCl3JD;EACE,kBAAA;EACA,qBAAA;EACA,oBAAA;EACA,eAAA;EACA,0BAAA;CzCo3JD;AyCz3JD;;EASI,eAAA;CzCo3JH;AyC73JD;EAaI,oBAAA;EACA,gBAAA;EACA,iBAAA;CzCm3JH;AyCl4JD;EAmBI,0BAAA;CzCk3JH;AyC/2JC;;EAEE,mBAAA;CzCi3JH;AyCz4JD;EA4BI,gBAAA;CzCg3JH;AyC91JD;EAAA;IAdI,kBAAA;IACA,qBAAA;GzCg3JD;EyC92JC;;IAEE,mBAAA;IACA,oBAAA;GzCg3JH;EyCx2JH;;IAHM,gBAAA;GzC+2JH;CACF;A0C15JD;EACE,eAAA;EACA,aAAA;EACA,oBAAA;EACA,wBAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;ErCiLA,4CAAA;EACK,uCAAA;EACG,oCAAA;CL4uJT;A0Ct6JD;;EAaI,kBAAA;EACA,mBAAA;C1C65JH;A0Cz5JC;;;EAGE,sBAAA;C1C25JH;A0Ch7JD;EA0BI,aAAA;EACA,eAAA;C1Cy5JH;A2Cl7JD;EACE,cAAA;EACA,oBAAA;EACA,8BAAA;EACA,mBAAA;C3Co7JD;A2Cx7JD;EAQI,cAAA;EAEA,eAAA;C3Ck7JH;A2C57JD;EAeI,kBAAA;C3Cg7JH;A2C/7JD;;EAqBI,iBAAA;C3C86JH;A2Cn8JD;EAyBI,gBAAA;C3C66JH;A2Cr6JD;;EAEE,oBAAA;C3Cu6JD;A2Cz6JD;;EAMI,mBAAA;EACA,UAAA;EACA,aAAA;EACA,eAAA;C3Cu6JH;A2C/5JD;ECvDE,0BAAA;EACA,sBAAA;EACA,eAAA;C5Cy9JD;A2Cp6JD;EClDI,0BAAA;C5Cy9JH;A2Cv6JD;EC/CI,eAAA;C5Cy9JH;A2Ct6JD;EC3DE,0BAAA;EACA,sBAAA;EACA,eAAA;C5Co+JD;A2C36JD;ECtDI,0BAAA;C5Co+JH;A2C96JD;ECnDI,eAAA;C5Co+JH;A2C76JD;EC/DE,0BAAA;EACA,sBAAA;EACA,eAAA;C5C++JD;A2Cl7JD;EC1DI,0BAAA;C5C++JH;A2Cr7JD;ECvDI,eAAA;C5C++JH;A2Cp7JD;ECnEE,0BAAA;EACA,sBAAA;EACA,eAAA;C5C0/JD;A2Cz7JD;EC9DI,0BAAA;C5C0/JH;A2C57JD;EC3DI,eAAA;C5C0/JH;A6C5/JD;EACE;IAAQ,4BAAA;G7C+/JP;E6C9/JD;IAAQ,yBAAA;G7CigKP;CACF;A6C9/JD;EACE;IAAQ,4BAAA;G7CigKP;E6ChgKD;IAAQ,yBAAA;G7CmgKP;CACF;A6CtgKD;EACE;IAAQ,4BAAA;G7CigKP;E6ChgKD;IAAQ,yBAAA;G7CmgKP;CACF;A6C5/JD;EACE,iBAAA;EACA,aAAA;EACA,oBAAA;EACA,0BAAA;EACA,mBAAA;ExCsCA,uDAAA;EACQ,+CAAA;CLy9JT;A6C3/JD;EACE,YAAA;EACA,UAAA;EACA,aAAA;EACA,gBAAA;EACA,kBAAA;EACA,eAAA;EACA,mBAAA;EACA,0BAAA;ExCyBA,uDAAA;EACQ,+CAAA;EAyHR,oCAAA;EACK,+BAAA;EACG,4BAAA;CL62JT;A6Cx/JD;;ECCI,8MAAA;EACA,yMAAA;EACA,sMAAA;EDAF,mCAAA;UAAA,2BAAA;C7C4/JD;A6Cr/JD;;ExC5CE,2DAAA;EACK,sDAAA;EACG,mDAAA;CLqiKT;A6Cl/JD;EErEE,0BAAA;C/C0jKD;A+CvjKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9C0gKH;A6Ct/JD;EEzEE,0BAAA;C/CkkKD;A+C/jKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9CkhKH;A6C1/JD;EE7EE,0BAAA;C/C0kKD;A+CvkKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9C0hKH;A6C9/JD;EEjFE,0BAAA;C/CklKD;A+C/kKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9CkiKH;AgD1lKD;EAEE,iBAAA;ChD2lKD;AgDzlKC;EACE,cAAA;ChD2lKH;AgDvlKD;;EAEE,QAAA;EACA,iBAAA;ChDylKD;AgDtlKD;EACE,eAAA;ChDwlKD;AgDrlKD;EACE,eAAA;ChDulKD;AgDplKC;EACE,gBAAA;ChDslKH;AgDllKD;;EAEE,mBAAA;ChDolKD;AgDjlKD;;EAEE,oBAAA;ChDmlKD;AgDhlKD;;;EAGE,oBAAA;EACA,oBAAA;ChDklKD;AgD/kKD;EACE,uBAAA;ChDilKD;AgD9kKD;EACE,uBAAA;ChDglKD;AgD5kKD;EACE,cAAA;EACA,mBAAA;ChD8kKD;AgDxkKD;EACE,gBAAA;EACA,iBAAA;ChD0kKD;AiDjoKD;EAEE,oBAAA;EACA,gBAAA;CjDkoKD;AiD1nKD;EACE,mBAAA;EACA,eAAA;EACA,mBAAA;EAEA,oBAAA;EACA,0BAAA;EACA,0BAAA;CjD2nKD;AiDxnKC;ErB3BA,6BAAA;EACC,4BAAA;C5BspKF;AiDznKC;EACE,iBAAA;ErBvBF,gCAAA;EACC,+BAAA;C5BmpKF;AiDlnKD;;EAEE,eAAA;CjDonKD;AiDtnKD;;EAKI,eAAA;CjDqnKH;AiDjnKC;;;;EAEE,sBAAA;EACA,eAAA;EACA,0BAAA;CjDqnKH;AiDjnKD;EACE,YAAA;EACA,iBAAA;CjDmnKD;AiD9mKC;;;EAGE,0BAAA;EACA,eAAA;EACA,oBAAA;CjDgnKH;AiDrnKC;;;EASI,eAAA;CjDinKL;AiD1nKC;;;EAYI,eAAA;CjDmnKL;AiD9mKC;;;EAGE,WAAA;EACA,eAAA;EACA,0BAAA;EACA,sBAAA;CjDgnKH;AiDtnKC;;;;;;;;;EAYI,eAAA;CjDqnKL;AiDjoKC;;;EAeI,eAAA;CjDunKL;AkDztKC;EACE,eAAA;EACA,0BAAA;ClD2tKH;AkDztKG;;EAEE,eAAA;ClD2tKL;AkD7tKG;;EAKI,eAAA;ClD4tKP;AkDztKK;;;;EAEE,eAAA;EACA,0BAAA;ClD6tKP;AkD3tKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClDguKP;AkDtvKC;EACE,eAAA;EACA,0BAAA;ClDwvKH;AkDtvKG;;EAEE,eAAA;ClDwvKL;AkD1vKG;;EAKI,eAAA;ClDyvKP;AkDtvKK;;;;EAEE,eAAA;EACA,0BAAA;ClD0vKP;AkDxvKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClD6vKP;AkDnxKC;EACE,eAAA;EACA,0BAAA;ClDqxKH;AkDnxKG;;EAEE,eAAA;ClDqxKL;AkDvxKG;;EAKI,eAAA;ClDsxKP;AkDnxKK;;;;EAEE,eAAA;EACA,0BAAA;ClDuxKP;AkDrxKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClD0xKP;AkDhzKC;EACE,eAAA;EACA,0BAAA;ClDkzKH;AkDhzKG;;EAEE,eAAA;ClDkzKL;AkDpzKG;;EAKI,eAAA;ClDmzKP;AkDhzKK;;;;EAEE,eAAA;EACA,0BAAA;ClDozKP;AkDlzKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClDuzKP;AiDttKD;EACE,cAAA;EACA,mBAAA;CjDwtKD;AiDttKD;EACE,iBAAA;EACA,iBAAA;CjDwtKD;AmDl1KD;EACE,oBAAA;EACA,0BAAA;EACA,8BAAA;EACA,mBAAA;E9C0DA,kDAAA;EACQ,0CAAA;CL2xKT;AmDj1KD;EACE,cAAA;CnDm1KD;AmD90KD;EACE,mBAAA;EACA,qCAAA;EvBpBA,6BAAA;EACC,4BAAA;C5Bq2KF;AmDp1KD;EAMI,eAAA;CnDi1KH;AmD50KD;EACE,cAAA;EACA,iBAAA;EACA,gBAAA;EACA,eAAA;CnD80KD;AmDl1KD;;;;;EAWI,eAAA;CnD80KH;AmDz0KD;EACE,mBAAA;EACA,0BAAA;EACA,8BAAA;EvBxCA,gCAAA;EACC,+BAAA;C5Bo3KF;AmDn0KD;;EAGI,iBAAA;CnDo0KH;AmDv0KD;;EAMM,oBAAA;EACA,iBAAA;CnDq0KL;AmDj0KG;;EAEI,cAAA;EvBvEN,6BAAA;EACC,4BAAA;C5B24KF;AmD/zKG;;EAEI,iBAAA;EvBvEN,gCAAA;EACC,+BAAA;C5By4KF;AmDx1KD;EvB1DE,2BAAA;EACC,0BAAA;C5Bq5KF;AmD3zKD;EAEI,oBAAA;CnD4zKH;AmDzzKD;EACE,oBAAA;CnD2zKD;AmDnzKD;;;EAII,iBAAA;CnDozKH;AmDxzKD;;;EAOM,mBAAA;EACA,oBAAA;CnDszKL;AmD9zKD;;EvBzGE,6BAAA;EACC,4BAAA;C5B26KF;AmDn0KD;;;;EAmBQ,4BAAA;EACA,6BAAA;CnDszKP;AmD10KD;;;;;;;;EAwBU,4BAAA;CnD4zKT;AmDp1KD;;;;;;;;EA4BU,6BAAA;CnDk0KT;AmD91KD;;EvBjGE,gCAAA;EACC,+BAAA;C5Bm8KF;AmDn2KD;;;;EAyCQ,+BAAA;EACA,gCAAA;CnDg0KP;AmD12KD;;;;;;;;EA8CU,+BAAA;CnDs0KT;AmDp3KD;;;;;;;;EAkDU,gCAAA;CnD40KT;AmD93KD;;;;EA2DI,8BAAA;CnDy0KH;AmDp4KD;;EA+DI,cAAA;CnDy0KH;AmDx4KD;;EAmEI,UAAA;CnDy0KH;AmD54KD;;;;;;;;;;;;EA0EU,eAAA;CnDg1KT;AmD15KD;;;;;;;;;;;;EA8EU,gBAAA;CnD01KT;AmDx6KD;;;;;;;;EAuFU,iBAAA;CnD21KT;AmDl7KD;;;;;;;;EAgGU,iBAAA;CnD41KT;AmD57KD;EAsGI,UAAA;EACA,iBAAA;CnDy1KH;AmD/0KD;EACE,oBAAA;CnDi1KD;AmDl1KD;EAKI,iBAAA;EACA,mBAAA;CnDg1KH;AmDt1KD;EASM,gBAAA;CnDg1KL;AmDz1KD;EAcI,iBAAA;CnD80KH;AmD51KD;;EAkBM,8BAAA;CnD80KL;AmDh2KD;EAuBI,cAAA;CnD40KH;AmDn2KD;EAyBM,iCAAA;CnD60KL;AmDt0KD;EC1PE,sBAAA;CpDmkLD;AoDjkLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpDmkLH;AoDtkLC;EAMI,0BAAA;CpDmkLL;AoDzkLC;EASI,eAAA;EACA,0BAAA;CpDmkLL;AoDhkLC;EAEI,6BAAA;CpDikLL;AmDr1KD;EC7PE,sBAAA;CpDqlLD;AoDnlLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpDqlLH;AoDxlLC;EAMI,0BAAA;CpDqlLL;AoD3lLC;EASI,eAAA;EACA,0BAAA;CpDqlLL;AoDllLC;EAEI,6BAAA;CpDmlLL;AmDp2KD;EChQE,sBAAA;CpDumLD;AoDrmLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpDumLH;AoD1mLC;EAMI,0BAAA;CpDumLL;AoD7mLC;EASI,eAAA;EACA,0BAAA;CpDumLL;AoDpmLC;EAEI,6BAAA;CpDqmLL;AmDn3KD;ECnQE,sBAAA;CpDynLD;AoDvnLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpDynLH;AoD5nLC;EAMI,0BAAA;CpDynLL;AoD/nLC;EASI,eAAA;EACA,0BAAA;CpDynLL;AoDtnLC;EAEI,6BAAA;CpDunLL;AmDl4KD;ECtQE,sBAAA;CpD2oLD;AoDzoLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpD2oLH;AoD9oLC;EAMI,0BAAA;CpD2oLL;AoDjpLC;EASI,eAAA;EACA,0BAAA;CpD2oLL;AoDxoLC;EAEI,6BAAA;CpDyoLL;AmDj5KD;ECzQE,sBAAA;CpD6pLD;AoD3pLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpD6pLH;AoDhqLC;EAMI,0BAAA;CpD6pLL;AoDnqLC;EASI,eAAA;EACA,0BAAA;CpD6pLL;AoD1pLC;EAEI,6BAAA;CpD2pLL;AqD3qLD;EACE,mBAAA;EACA,eAAA;EACA,UAAA;EACA,WAAA;EACA,iBAAA;CrD6qLD;AqDlrLD;;;;;EAYI,mBAAA;EACA,OAAA;EACA,QAAA;EACA,UAAA;EACA,aAAA;EACA,YAAA;EACA,UAAA;CrD6qLH;AqDxqLD;EACE,uBAAA;CrD0qLD;AqDtqLD;EACE,oBAAA;CrDwqLD;AsDnsLD;EACE,iBAAA;EACA,cAAA;EACA,oBAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;EjDwDA,wDAAA;EACQ,gDAAA;CL8oLT;AsD7sLD;EASI,mBAAA;EACA,kCAAA;CtDusLH;AsDlsLD;EACE,cAAA;EACA,mBAAA;CtDosLD;AsDlsLD;EACE,aAAA;EACA,mBAAA;CtDosLD;AuD1tLD;EACE,aAAA;EACA,gBAAA;EACA,kBAAA;EACA,eAAA;EACA,eAAA;EACA,6BAAA;EjCRA,aAAA;EAGA,0BAAA;CtBmuLD;AuD3tLC;;EAEE,eAAA;EACA,sBAAA;EACA,gBAAA;EjCfF,aAAA;EAGA,0BAAA;CtB2uLD;AuDvtLC;EACE,WAAA;EACA,gBAAA;EACA,wBAAA;EACA,UAAA;EACA,yBAAA;CvDytLH;AwD9uLD;EACE,iBAAA;CxDgvLD;AwD5uLD;EACE,cAAA;EACA,iBAAA;EACA,gBAAA;EACA,OAAA;EACA,SAAA;EACA,UAAA;EACA,QAAA;EACA,cAAA;EACA,kCAAA;EAIA,WAAA;CxD2uLD;AwDxuLC;EnD+GA,sCAAA;EACI,kCAAA;EACC,iCAAA;EACG,8BAAA;EAkER,oDAAA;EAEK,0CAAA;EACG,oCAAA;CL2jLT;AwD9uLC;EnD2GA,mCAAA;EACI,+BAAA;EACC,8BAAA;EACG,2BAAA;CLsoLT;AwDlvLD;EACE,mBAAA;EACA,iBAAA;CxDovLD;AwDhvLD;EACE,mBAAA;EACA,YAAA;EACA,aAAA;CxDkvLD;AwD9uLD;EACE,mBAAA;EACA,0BAAA;EACA,0BAAA;EACA,qCAAA;EACA,mBAAA;EnDaA,iDAAA;EACQ,yCAAA;EmDZR,qCAAA;UAAA,6BAAA;EAEA,WAAA;CxDgvLD;AwD5uLD;EACE,gBAAA;EACA,OAAA;EACA,SAAA;EACA,UAAA;EACA,QAAA;EACA,cAAA;EACA,0BAAA;CxD8uLD;AwD5uLC;ElCrEA,WAAA;EAGA,yBAAA;CtBkzLD;AwD/uLC;ElCtEA,aAAA;EAGA,0BAAA;CtBszLD;AwD9uLD;EACE,cAAA;EACA,iCAAA;EACA,0BAAA;CxDgvLD;AwD7uLD;EACE,iBAAA;CxD+uLD;AwD3uLD;EACE,UAAA;EACA,wBAAA;CxD6uLD;AwDxuLD;EACE,mBAAA;EACA,cAAA;CxD0uLD;AwDtuLD;EACE,cAAA;EACA,kBAAA;EACA,8BAAA;CxDwuLD;AwD3uLD;EAQI,iBAAA;EACA,iBAAA;CxDsuLH;AwD/uLD;EAaI,kBAAA;CxDquLH;AwDlvLD;EAiBI,eAAA;CxDouLH;AwD/tLD;EACE,mBAAA;EACA,aAAA;EACA,YAAA;EACA,aAAA;EACA,iBAAA;CxDiuLD;AwD/sLD;EAZE;IACE,aAAA;IACA,kBAAA;GxD8tLD;EwD5tLD;InDvEA,kDAAA;IACQ,0CAAA;GLsyLP;EwD3tLD;IAAY,aAAA;GxD8tLX;CACF;AwDztLD;EAFE;IAAY,aAAA;GxD+tLX;CACF;AyD92LD;EACE,mBAAA;EACA,cAAA;EACA,eAAA;ECRA,4DAAA;EAEA,mBAAA;EACA,oBAAA;EACA,uBAAA;EACA,iBAAA;EACA,wBAAA;EACA,iBAAA;EACA,kBAAA;EACA,sBAAA;EACA,kBAAA;EACA,qBAAA;EACA,oBAAA;EACA,mBAAA;EACA,qBAAA;EACA,kBAAA;EDHA,gBAAA;EnCVA,WAAA;EAGA,yBAAA;CtBq4LD;AyD13LC;EnCdA,aAAA;EAGA,0BAAA;CtBy4LD;AyD73LC;EAAW,iBAAA;EAAmB,eAAA;CzDi4L/B;AyDh4LC;EAAW,iBAAA;EAAmB,eAAA;CzDo4L/B;AyDn4LC;EAAW,gBAAA;EAAmB,eAAA;CzDu4L/B;AyDt4LC;EAAW,kBAAA;EAAmB,eAAA;CzD04L/B;AyDt4LD;EACE,iBAAA;EACA,iBAAA;EACA,eAAA;EACA,mBAAA;EACA,0BAAA;EACA,mBAAA;CzDw4LD;AyDp4LD;EACE,mBAAA;EACA,SAAA;EACA,UAAA;EACA,0BAAA;EACA,oBAAA;CzDs4LD;AyDl4LC;EACE,UAAA;EACA,UAAA;EACA,kBAAA;EACA,wBAAA;EACA,0BAAA;CzDo4LH;AyDl4LC;EACE,UAAA;EACA,WAAA;EACA,oBAAA;EACA,wBAAA;EACA,0BAAA;CzDo4LH;AyDl4LC;EACE,UAAA;EACA,UAAA;EACA,oBAAA;EACA,wBAAA;EACA,0BAAA;CzDo4LH;AyDl4LC;EACE,SAAA;EACA,QAAA;EACA,iBAAA;EACA,4BAAA;EACA,4BAAA;CzDo4LH;AyDl4LC;EACE,SAAA;EACA,SAAA;EACA,iBAAA;EACA,4BAAA;EACA,2BAAA;CzDo4LH;AyDl4LC;EACE,OAAA;EACA,UAAA;EACA,kBAAA;EACA,wBAAA;EACA,6BAAA;CzDo4LH;AyDl4LC;EACE,OAAA;EACA,WAAA;EACA,iBAAA;EACA,wBAAA;EACA,6BAAA;CzDo4LH;AyDl4LC;EACE,OAAA;EACA,UAAA;EACA,iBAAA;EACA,wBAAA;EACA,6BAAA;CzDo4LH;A2Dj+LD;EACE,mBAAA;EACA,OAAA;EACA,QAAA;EACA,cAAA;EACA,cAAA;EACA,iBAAA;EACA,aAAA;EDXA,4DAAA;EAEA,mBAAA;EACA,oBAAA;EACA,uBAAA;EACA,iBAAA;EACA,wBAAA;EACA,iBAAA;EACA,kBAAA;EACA,sBAAA;EACA,kBAAA;EACA,qBAAA;EACA,oBAAA;EACA,mBAAA;EACA,qBAAA;EACA,kBAAA;ECAA,gBAAA;EAEA,0BAAA;EACA,qCAAA;UAAA,6BAAA;EACA,0BAAA;EACA,qCAAA;EACA,mBAAA;EtD8CA,kDAAA;EACQ,0CAAA;CLi8LT;A2D5+LC;EAAY,kBAAA;C3D++Lb;A2D9+LC;EAAY,kBAAA;C3Di/Lb;A2Dh/LC;EAAY,iBAAA;C3Dm/Lb;A2Dl/LC;EAAY,mBAAA;C3Dq/Lb;A2Dl/LD;EACE,UAAA;EACA,kBAAA;EACA,gBAAA;EACA,0BAAA;EACA,iCAAA;EACA,2BAAA;C3Do/LD;A2Dj/LD;EACE,kBAAA;C3Dm/LD;A2D3+LC;;EAEE,mBAAA;EACA,eAAA;EACA,SAAA;EACA,UAAA;EACA,0BAAA;EACA,oBAAA;C3D6+LH;A2D1+LD;EACE,mBAAA;C3D4+LD;A2D1+LD;EACE,mBAAA;EACA,YAAA;C3D4+LD;A2Dx+LC;EACE,UAAA;EACA,mBAAA;EACA,uBAAA;EACA,0BAAA;EACA,sCAAA;EACA,cAAA;C3D0+LH;A2Dz+LG;EACE,aAAA;EACA,YAAA;EACA,mBAAA;EACA,uBAAA;EACA,0BAAA;C3D2+LL;A2Dx+LC;EACE,SAAA;EACA,YAAA;EACA,kBAAA;EACA,qBAAA;EACA,4BAAA;EACA,wCAAA;C3D0+LH;A2Dz+LG;EACE,aAAA;EACA,UAAA;EACA,cAAA;EACA,qBAAA;EACA,4BAAA;C3D2+LL;A2Dx+LC;EACE,UAAA;EACA,mBAAA;EACA,oBAAA;EACA,6BAAA;EACA,yCAAA;EACA,WAAA;C3D0+LH;A2Dz+LG;EACE,aAAA;EACA,SAAA;EACA,mBAAA;EACA,oBAAA;EACA,6BAAA;C3D2+LL;A2Dv+LC;EACE,SAAA;EACA,aAAA;EACA,kBAAA;EACA,sBAAA;EACA,2BAAA;EACA,uCAAA;C3Dy+LH;A2Dx+LG;EACE,aAAA;EACA,WAAA;EACA,sBAAA;EACA,2BAAA;EACA,cAAA;C3D0+LL;A4DnmMD;EACE,mBAAA;C5DqmMD;A4DlmMD;EACE,mBAAA;EACA,iBAAA;EACA,YAAA;C5DomMD;A4DvmMD;EAMI,cAAA;EACA,mBAAA;EvD6KF,0CAAA;EACK,qCAAA;EACG,kCAAA;CLw7LT;A4D9mMD;;EAcM,eAAA;C5DomML;A4D1kMC;EAAA;IvDiKA,uDAAA;IAEK,6CAAA;IACG,uCAAA;IA7JR,oCAAA;IAEQ,4BAAA;IA+GR,4BAAA;IAEQ,oBAAA;GL69LP;E4DxmMG;;IvDmHJ,2CAAA;IACQ,mCAAA;IuDjHF,QAAA;G5D2mML;E4DzmMG;;IvD8GJ,4CAAA;IACQ,oCAAA;IuD5GF,QAAA;G5D4mML;E4D1mMG;;;IvDyGJ,wCAAA;IACQ,gCAAA;IuDtGF,QAAA;G5D6mML;CACF;A4DnpMD;;;EA6CI,eAAA;C5D2mMH;A4DxpMD;EAiDI,QAAA;C5D0mMH;A4D3pMD;;EAsDI,mBAAA;EACA,OAAA;EACA,YAAA;C5DymMH;A4DjqMD;EA4DI,WAAA;C5DwmMH;A4DpqMD;EA+DI,YAAA;C5DwmMH;A4DvqMD;;EAmEI,QAAA;C5DwmMH;A4D3qMD;EAuEI,YAAA;C5DumMH;A4D9qMD;EA0EI,WAAA;C5DumMH;A4D/lMD;EACE,mBAAA;EACA,OAAA;EACA,QAAA;EACA,UAAA;EACA,WAAA;EtC9FA,aAAA;EAGA,0BAAA;EsC6FA,gBAAA;EACA,eAAA;EACA,mBAAA;EACA,0CAAA;C5DkmMD;A4D7lMC;EdlGE,mGAAA;EACA,8FAAA;EACA,qHAAA;EAAA,+FAAA;EACA,4BAAA;EACA,uHAAA;C9CksMH;A4DjmMC;EACE,WAAA;EACA,SAAA;EdvGA,mGAAA;EACA,8FAAA;EACA,qHAAA;EAAA,+FAAA;EACA,4BAAA;EACA,uHAAA;C9C2sMH;A4DnmMC;;EAEE,WAAA;EACA,eAAA;EACA,sBAAA;EtCtHF,aAAA;EAGA,0BAAA;CtB0tMD;A4DpoMD;;;;EAsCI,mBAAA;EACA,SAAA;EACA,kBAAA;EACA,WAAA;EACA,sBAAA;C5DomMH;A4D9oMD;;EA8CI,UAAA;EACA,mBAAA;C5DomMH;A4DnpMD;;EAmDI,WAAA;EACA,oBAAA;C5DomMH;A4DxpMD;;EAwDI,YAAA;EACA,aAAA;EACA,eAAA;EACA,mBAAA;C5DomMH;A4D/lMG;EACE,iBAAA;C5DimML;A4D7lMG;EACE,iBAAA;C5D+lML;A4DrlMD;EACE,mBAAA;EACA,aAAA;EACA,UAAA;EACA,YAAA;EACA,WAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;C5DulMD;A4DhmMD;EAYI,sBAAA;EACA,YAAA;EACA,aAAA;EACA,YAAA;EACA,oBAAA;EACA,0BAAA;EACA,oBAAA;EACA,gBAAA;EAWA,0BAAA;EACA,mCAAA;C5D6kMH;A4D5mMD;EAkCI,UAAA;EACA,YAAA;EACA,aAAA;EACA,0BAAA;C5D6kMH;A4DtkMD;EACE,mBAAA;EACA,UAAA;EACA,WAAA;EACA,aAAA;EACA,YAAA;EACA,kBAAA;EACA,qBAAA;EACA,eAAA;EACA,mBAAA;EACA,0CAAA;C5DwkMD;A4DvkMC;EACE,kBAAA;C5DykMH;A4DhiMD;EAhCE;;;;IAKI,YAAA;IACA,aAAA;IACA,kBAAA;IACA,gBAAA;G5DkkMH;E4D1kMD;;IAYI,mBAAA;G5DkkMH;E4D9kMD;;IAgBI,oBAAA;G5DkkMH;E4D7jMD;IACE,UAAA;IACA,WAAA;IACA,qBAAA;G5D+jMD;E4D3jMD;IACE,aAAA;G5D6jMD;CACF;A6D3zMC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEE,aAAA;EACA,eAAA;C7Dy1MH;A6Dv1MC;;;;;;;;;;;;;;;EACE,YAAA;C7Du2MH;AiC/2MD;E6BRE,eAAA;EACA,kBAAA;EACA,mBAAA;C9D03MD;AiCj3MD;EACE,wBAAA;CjCm3MD;AiCj3MD;EACE,uBAAA;CjCm3MD;AiC32MD;EACE,yBAAA;CjC62MD;AiC32MD;EACE,0BAAA;CjC62MD;AiC32MD;EACE,mBAAA;CjC62MD;AiC32MD;E8BzBE,YAAA;EACA,mBAAA;EACA,kBAAA;EACA,8BAAA;EACA,UAAA;C/Du4MD;AiCz2MD;EACE,yBAAA;CjC22MD;AiCp2MD;EACE,gBAAA;CjCs2MD;AgEv4MD;EACE,oBAAA;ChEy4MD;AgEn4MD;;;;ECdE,yBAAA;CjEu5MD;AgEl4MD;;;;;;;;;;;;EAYE,yBAAA;ChEo4MD;AgE73MD;EAAA;IChDE,0BAAA;GjEi7MC;EiEh7MD;IAAU,0BAAA;GjEm7MT;EiEl7MD;IAAU,8BAAA;GjEq7MT;EiEp7MD;;IACU,+BAAA;GjEu7MT;CACF;AgEv4MD;EAAA;IAFI,0BAAA;GhE64MD;CACF;AgEv4MD;EAAA;IAFI,2BAAA;GhE64MD;CACF;AgEv4MD;EAAA;IAFI,iCAAA;GhE64MD;CACF;AgEt4MD;EAAA;ICrEE,0BAAA;GjE+8MC;EiE98MD;IAAU,0BAAA;GjEi9MT;EiEh9MD;IAAU,8BAAA;GjEm9MT;EiEl9MD;;IACU,+BAAA;GjEq9MT;CACF;AgEh5MD;EAAA;IAFI,0BAAA;GhEs5MD;CACF;AgEh5MD;EAAA;IAFI,2BAAA;GhEs5MD;CACF;AgEh5MD;EAAA;IAFI,iCAAA;GhEs5MD;CACF;AgE/4MD;EAAA;IC1FE,0BAAA;GjE6+MC;EiE5+MD;IAAU,0BAAA;GjE++MT;EiE9+MD;IAAU,8BAAA;GjEi/MT;EiEh/MD;;IACU,+BAAA;GjEm/MT;CACF;AgEz5MD;EAAA;IAFI,0BAAA;GhE+5MD;CACF;AgEz5MD;EAAA;IAFI,2BAAA;GhE+5MD;CACF;AgEz5MD;EAAA;IAFI,iCAAA;GhE+5MD;CACF;AgEx5MD;EAAA;IC/GE,0BAAA;GjE2gNC;EiE1gND;IAAU,0BAAA;GjE6gNT;EiE5gND;IAAU,8BAAA;GjE+gNT;EiE9gND;;IACU,+BAAA;GjEihNT;CACF;AgEl6MD;EAAA;IAFI,0BAAA;GhEw6MD;CACF;AgEl6MD;EAAA;IAFI,2BAAA;GhEw6MD;CACF;AgEl6MD;EAAA;IAFI,iCAAA;GhEw6MD;CACF;AgEj6MD;EAAA;IC5HE,yBAAA;GjEiiNC;CACF;AgEj6MD;EAAA;ICjIE,yBAAA;GjEsiNC;CACF;AgEj6MD;EAAA;ICtIE,yBAAA;GjE2iNC;CACF;AgEj6MD;EAAA;IC3IE,yBAAA;GjEgjNC;CACF;AgE95MD;ECnJE,yBAAA;CjEojND;AgE35MD;EAAA;ICjKE,0BAAA;GjEgkNC;EiE/jND;IAAU,0BAAA;GjEkkNT;EiEjkND;IAAU,8BAAA;GjEokNT;EiEnkND;;IACU,+BAAA;GjEskNT;CACF;AgEz6MD;EACE,yBAAA;ChE26MD;AgEt6MD;EAAA;IAFI,0BAAA;GhE46MD;CACF;AgE16MD;EACE,yBAAA;ChE46MD;AgEv6MD;EAAA;IAFI,2BAAA;GhE66MD;CACF;AgE36MD;EACE,yBAAA;ChE66MD;AgEx6MD;EAAA;IAFI,iCAAA;GhE86MD;CACF;AgEv6MD;EAAA;ICpLE,yBAAA;GjE+lNC;CACF","file":"bootstrap.css","sourcesContent":["/*!\n * Bootstrap v3.3.5 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n font-family: sans-serif;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n}\nbody {\n margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block;\n vertical-align: baseline;\n}\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n[hidden],\ntemplate {\n display: none;\n}\na {\n background-color: transparent;\n}\na:active,\na:hover {\n outline: 0;\n}\nabbr[title] {\n border-bottom: 1px dotted;\n}\nb,\nstrong {\n font-weight: bold;\n}\ndfn {\n font-style: italic;\n}\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\nmark {\n background: #ff0;\n color: #000;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\nsup {\n top: -0.5em;\n}\nsub {\n bottom: -0.25em;\n}\nimg {\n border: 0;\n}\nsvg:not(:root) {\n overflow: hidden;\n}\nfigure {\n margin: 1em 40px;\n}\nhr {\n box-sizing: content-box;\n height: 0;\n}\npre {\n overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit;\n font: inherit;\n margin: 0;\n}\nbutton {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button;\n cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\ninput {\n line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box;\n padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: textfield;\n box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n border: 0;\n padding: 0;\n}\ntextarea {\n overflow: auto;\n}\noptgroup {\n font-weight: bold;\n}\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\ntd,\nth {\n padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n *,\n *:before,\n *:after {\n background: transparent !important;\n color: #000 !important;\n box-shadow: none !important;\n text-shadow: none !important;\n }\n a,\n a:visited {\n text-decoration: underline;\n }\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n img {\n max-width: 100% !important;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n .navbar {\n display: none;\n }\n .btn > .caret,\n .dropup > .btn > .caret {\n border-top-color: #000 !important;\n }\n .label {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #ddd !important;\n }\n}\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: url('../fonts/glyphicons-halflings-regular.eot');\n src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');\n}\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n content: \"\\2a\";\n}\n.glyphicon-plus:before {\n content: \"\\2b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n content: \"\\270f\";\n}\n.glyphicon-glass:before {\n content: \"\\e001\";\n}\n.glyphicon-music:before {\n content: \"\\e002\";\n}\n.glyphicon-search:before {\n content: \"\\e003\";\n}\n.glyphicon-heart:before {\n content: \"\\e005\";\n}\n.glyphicon-star:before {\n content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n content: \"\\e007\";\n}\n.glyphicon-user:before {\n content: \"\\e008\";\n}\n.glyphicon-film:before {\n content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n content: \"\\e010\";\n}\n.glyphicon-th:before {\n content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n content: \"\\e012\";\n}\n.glyphicon-ok:before {\n content: \"\\e013\";\n}\n.glyphicon-remove:before {\n content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n content: \"\\e016\";\n}\n.glyphicon-off:before {\n content: \"\\e017\";\n}\n.glyphicon-signal:before {\n content: \"\\e018\";\n}\n.glyphicon-cog:before {\n content: \"\\e019\";\n}\n.glyphicon-trash:before {\n content: \"\\e020\";\n}\n.glyphicon-home:before {\n content: \"\\e021\";\n}\n.glyphicon-file:before {\n content: \"\\e022\";\n}\n.glyphicon-time:before {\n content: \"\\e023\";\n}\n.glyphicon-road:before {\n content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n content: \"\\e025\";\n}\n.glyphicon-download:before {\n content: \"\\e026\";\n}\n.glyphicon-upload:before {\n content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n content: \"\\e032\";\n}\n.glyphicon-lock:before {\n content: \"\\e033\";\n}\n.glyphicon-flag:before {\n content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n content: \"\\e040\";\n}\n.glyphicon-tag:before {\n content: \"\\e041\";\n}\n.glyphicon-tags:before {\n content: \"\\e042\";\n}\n.glyphicon-book:before {\n content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n content: \"\\e044\";\n}\n.glyphicon-print:before {\n content: \"\\e045\";\n}\n.glyphicon-camera:before {\n content: \"\\e046\";\n}\n.glyphicon-font:before {\n content: \"\\e047\";\n}\n.glyphicon-bold:before {\n content: \"\\e048\";\n}\n.glyphicon-italic:before {\n content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n content: \"\\e055\";\n}\n.glyphicon-list:before {\n content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n content: \"\\e059\";\n}\n.glyphicon-picture:before {\n content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n content: \"\\e063\";\n}\n.glyphicon-tint:before {\n content: \"\\e064\";\n}\n.glyphicon-edit:before {\n content: \"\\e065\";\n}\n.glyphicon-share:before {\n content: \"\\e066\";\n}\n.glyphicon-check:before {\n content: \"\\e067\";\n}\n.glyphicon-move:before {\n content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n content: \"\\e070\";\n}\n.glyphicon-backward:before {\n content: \"\\e071\";\n}\n.glyphicon-play:before {\n content: \"\\e072\";\n}\n.glyphicon-pause:before {\n content: \"\\e073\";\n}\n.glyphicon-stop:before {\n content: \"\\e074\";\n}\n.glyphicon-forward:before {\n content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n content: \"\\e077\";\n}\n.glyphicon-eject:before {\n content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n content: \"\\e101\";\n}\n.glyphicon-gift:before {\n content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n content: \"\\e103\";\n}\n.glyphicon-fire:before {\n content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n content: \"\\e107\";\n}\n.glyphicon-plane:before {\n content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n content: \"\\e109\";\n}\n.glyphicon-random:before {\n content: \"\\e110\";\n}\n.glyphicon-comment:before {\n content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n content: \"\\e122\";\n}\n.glyphicon-bell:before {\n content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n content: \"\\e134\";\n}\n.glyphicon-globe:before {\n content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n content: \"\\e137\";\n}\n.glyphicon-filter:before {\n content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n content: \"\\e143\";\n}\n.glyphicon-link:before {\n content: \"\\e144\";\n}\n.glyphicon-phone:before {\n content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n content: \"\\e146\";\n}\n.glyphicon-usd:before {\n content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n content: \"\\e149\";\n}\n.glyphicon-sort:before {\n content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n content: \"\\e157\";\n}\n.glyphicon-expand:before {\n content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n content: \"\\e161\";\n}\n.glyphicon-flash:before {\n content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n content: \"\\e164\";\n}\n.glyphicon-record:before {\n content: \"\\e165\";\n}\n.glyphicon-save:before {\n content: \"\\e166\";\n}\n.glyphicon-open:before {\n content: \"\\e167\";\n}\n.glyphicon-saved:before {\n content: \"\\e168\";\n}\n.glyphicon-import:before {\n content: \"\\e169\";\n}\n.glyphicon-export:before {\n content: \"\\e170\";\n}\n.glyphicon-send:before {\n content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n content: \"\\e179\";\n}\n.glyphicon-header:before {\n content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n content: \"\\e183\";\n}\n.glyphicon-tower:before {\n content: \"\\e184\";\n}\n.glyphicon-stats:before {\n content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n content: \"\\e200\";\n}\n.glyphicon-cd:before {\n content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n content: \"\\e204\";\n}\n.glyphicon-copy:before {\n content: \"\\e205\";\n}\n.glyphicon-paste:before {\n content: \"\\e206\";\n}\n.glyphicon-alert:before {\n content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n content: \"\\e210\";\n}\n.glyphicon-king:before {\n content: \"\\e211\";\n}\n.glyphicon-queen:before {\n content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n content: \"\\e214\";\n}\n.glyphicon-knight:before {\n content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n content: \"\\e216\";\n}\n.glyphicon-tent:before {\n content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n content: \"\\e218\";\n}\n.glyphicon-bed:before {\n content: \"\\e219\";\n}\n.glyphicon-apple:before {\n content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n content: \"\\e227\";\n}\n.glyphicon-btc:before {\n content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n content: \"\\e227\";\n}\n.glyphicon-yen:before {\n content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n content: \"\\e232\";\n}\n.glyphicon-education:before {\n content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n content: \"\\e237\";\n}\n.glyphicon-oil:before {\n content: \"\\e238\";\n}\n.glyphicon-grain:before {\n content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n content: \"\\e253\";\n}\n.glyphicon-console:before {\n content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n content: \"\\e260\";\n}\n* {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n*:before,\n*:after {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.42857143;\n color: #333333;\n background-color: #ffffff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\na {\n color: #337ab7;\n text-decoration: none;\n}\na:hover,\na:focus {\n color: #23527c;\n text-decoration: underline;\n}\na:focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\nfigure {\n margin: 0;\n}\nimg {\n vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n display: block;\n max-width: 100%;\n height: auto;\n}\n.img-rounded {\n border-radius: 6px;\n}\n.img-thumbnail {\n padding: 4px;\n line-height: 1.42857143;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 4px;\n -webkit-transition: all 0.2s ease-in-out;\n -o-transition: all 0.2s ease-in-out;\n transition: all 0.2s ease-in-out;\n display: inline-block;\n max-width: 100%;\n height: auto;\n}\n.img-circle {\n border-radius: 50%;\n}\nhr {\n margin-top: 20px;\n margin-bottom: 20px;\n border: 0;\n border-top: 1px solid #eeeeee;\n}\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n}\n[role=\"button\"] {\n cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n font-family: inherit;\n font-weight: 500;\n line-height: 1.1;\n color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n font-weight: normal;\n line-height: 1;\n color: #777777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n margin-top: 20px;\n margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n margin-top: 10px;\n margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n font-size: 75%;\n}\nh1,\n.h1 {\n font-size: 36px;\n}\nh2,\n.h2 {\n font-size: 30px;\n}\nh3,\n.h3 {\n font-size: 24px;\n}\nh4,\n.h4 {\n font-size: 18px;\n}\nh5,\n.h5 {\n font-size: 14px;\n}\nh6,\n.h6 {\n font-size: 12px;\n}\np {\n margin: 0 0 10px;\n}\n.lead {\n margin-bottom: 20px;\n font-size: 16px;\n font-weight: 300;\n line-height: 1.4;\n}\n@media (min-width: 768px) {\n .lead {\n font-size: 21px;\n }\n}\nsmall,\n.small {\n font-size: 85%;\n}\nmark,\n.mark {\n background-color: #fcf8e3;\n padding: .2em;\n}\n.text-left {\n text-align: left;\n}\n.text-right {\n text-align: right;\n}\n.text-center {\n text-align: center;\n}\n.text-justify {\n text-align: justify;\n}\n.text-nowrap {\n white-space: nowrap;\n}\n.text-lowercase {\n text-transform: lowercase;\n}\n.text-uppercase {\n text-transform: uppercase;\n}\n.text-capitalize {\n text-transform: capitalize;\n}\n.text-muted {\n color: #777777;\n}\n.text-primary {\n color: #337ab7;\n}\na.text-primary:hover,\na.text-primary:focus {\n color: #286090;\n}\n.text-success {\n color: #3c763d;\n}\na.text-success:hover,\na.text-success:focus {\n color: #2b542c;\n}\n.text-info {\n color: #31708f;\n}\na.text-info:hover,\na.text-info:focus {\n color: #245269;\n}\n.text-warning {\n color: #8a6d3b;\n}\na.text-warning:hover,\na.text-warning:focus {\n color: #66512c;\n}\n.text-danger {\n color: #a94442;\n}\na.text-danger:hover,\na.text-danger:focus {\n color: #843534;\n}\n.bg-primary {\n color: #fff;\n background-color: #337ab7;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n background-color: #286090;\n}\n.bg-success {\n background-color: #dff0d8;\n}\na.bg-success:hover,\na.bg-success:focus {\n background-color: #c1e2b3;\n}\n.bg-info {\n background-color: #d9edf7;\n}\na.bg-info:hover,\na.bg-info:focus {\n background-color: #afd9ee;\n}\n.bg-warning {\n background-color: #fcf8e3;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n background-color: #f7ecb5;\n}\n.bg-danger {\n background-color: #f2dede;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n background-color: #e4b9b9;\n}\n.page-header {\n padding-bottom: 9px;\n margin: 40px 0 20px;\n border-bottom: 1px solid #eeeeee;\n}\nul,\nol {\n margin-top: 0;\n margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n margin-bottom: 0;\n}\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n.list-inline {\n padding-left: 0;\n list-style: none;\n margin-left: -5px;\n}\n.list-inline > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n}\ndl {\n margin-top: 0;\n margin-bottom: 20px;\n}\ndt,\ndd {\n line-height: 1.42857143;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0;\n}\n@media (min-width: 768px) {\n .dl-horizontal dt {\n float: left;\n width: 160px;\n clear: left;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .dl-horizontal dd {\n margin-left: 180px;\n }\n}\nabbr[title],\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted #777777;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\nblockquote {\n padding: 10px 20px;\n margin: 0 0 20px;\n font-size: 17.5px;\n border-left: 5px solid #eeeeee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n display: block;\n font-size: 80%;\n line-height: 1.42857143;\n color: #777777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid #eeeeee;\n border-left: 0;\n text-align: right;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n content: '\\00A0 \\2014';\n}\naddress {\n margin-bottom: 20px;\n font-style: normal;\n line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: #c7254e;\n background-color: #f9f2f4;\n border-radius: 4px;\n}\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: #ffffff;\n background-color: #333333;\n border-radius: 3px;\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n box-shadow: none;\n}\npre {\n display: block;\n padding: 9.5px;\n margin: 0 0 10px;\n font-size: 13px;\n line-height: 1.42857143;\n word-break: break-all;\n word-wrap: break-word;\n color: #333333;\n background-color: #f5f5f5;\n border: 1px solid #cccccc;\n border-radius: 4px;\n}\npre code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n}\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n.container {\n margin-right: auto;\n margin-left: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n@media (min-width: 768px) {\n .container {\n width: 750px;\n }\n}\n@media (min-width: 992px) {\n .container {\n width: 970px;\n }\n}\n@media (min-width: 1200px) {\n .container {\n width: 1170px;\n }\n}\n.container-fluid {\n margin-right: auto;\n margin-left: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n.row {\n margin-left: -15px;\n margin-right: -15px;\n}\n.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\n position: relative;\n min-height: 1px;\n padding-left: 15px;\n padding-right: 15px;\n}\n.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\n float: left;\n}\n.col-xs-12 {\n width: 100%;\n}\n.col-xs-11 {\n width: 91.66666667%;\n}\n.col-xs-10 {\n width: 83.33333333%;\n}\n.col-xs-9 {\n width: 75%;\n}\n.col-xs-8 {\n width: 66.66666667%;\n}\n.col-xs-7 {\n width: 58.33333333%;\n}\n.col-xs-6 {\n width: 50%;\n}\n.col-xs-5 {\n width: 41.66666667%;\n}\n.col-xs-4 {\n width: 33.33333333%;\n}\n.col-xs-3 {\n width: 25%;\n}\n.col-xs-2 {\n width: 16.66666667%;\n}\n.col-xs-1 {\n width: 8.33333333%;\n}\n.col-xs-pull-12 {\n right: 100%;\n}\n.col-xs-pull-11 {\n right: 91.66666667%;\n}\n.col-xs-pull-10 {\n right: 83.33333333%;\n}\n.col-xs-pull-9 {\n right: 75%;\n}\n.col-xs-pull-8 {\n right: 66.66666667%;\n}\n.col-xs-pull-7 {\n right: 58.33333333%;\n}\n.col-xs-pull-6 {\n right: 50%;\n}\n.col-xs-pull-5 {\n right: 41.66666667%;\n}\n.col-xs-pull-4 {\n right: 33.33333333%;\n}\n.col-xs-pull-3 {\n right: 25%;\n}\n.col-xs-pull-2 {\n right: 16.66666667%;\n}\n.col-xs-pull-1 {\n right: 8.33333333%;\n}\n.col-xs-pull-0 {\n right: auto;\n}\n.col-xs-push-12 {\n left: 100%;\n}\n.col-xs-push-11 {\n left: 91.66666667%;\n}\n.col-xs-push-10 {\n left: 83.33333333%;\n}\n.col-xs-push-9 {\n left: 75%;\n}\n.col-xs-push-8 {\n left: 66.66666667%;\n}\n.col-xs-push-7 {\n left: 58.33333333%;\n}\n.col-xs-push-6 {\n left: 50%;\n}\n.col-xs-push-5 {\n left: 41.66666667%;\n}\n.col-xs-push-4 {\n left: 33.33333333%;\n}\n.col-xs-push-3 {\n left: 25%;\n}\n.col-xs-push-2 {\n left: 16.66666667%;\n}\n.col-xs-push-1 {\n left: 8.33333333%;\n}\n.col-xs-push-0 {\n left: auto;\n}\n.col-xs-offset-12 {\n margin-left: 100%;\n}\n.col-xs-offset-11 {\n margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n margin-left: 75%;\n}\n.col-xs-offset-8 {\n margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n margin-left: 50%;\n}\n.col-xs-offset-5 {\n margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n margin-left: 25%;\n}\n.col-xs-offset-2 {\n margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n margin-left: 0%;\n}\n@media (min-width: 768px) {\n .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {\n float: left;\n }\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666667%;\n }\n .col-sm-10 {\n width: 83.33333333%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666667%;\n }\n .col-sm-7 {\n width: 58.33333333%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666667%;\n }\n .col-sm-4 {\n width: 33.33333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.66666667%;\n }\n .col-sm-1 {\n width: 8.33333333%;\n }\n .col-sm-pull-12 {\n right: 100%;\n }\n .col-sm-pull-11 {\n right: 91.66666667%;\n }\n .col-sm-pull-10 {\n right: 83.33333333%;\n }\n .col-sm-pull-9 {\n right: 75%;\n }\n .col-sm-pull-8 {\n right: 66.66666667%;\n }\n .col-sm-pull-7 {\n right: 58.33333333%;\n }\n .col-sm-pull-6 {\n right: 50%;\n }\n .col-sm-pull-5 {\n right: 41.66666667%;\n }\n .col-sm-pull-4 {\n right: 33.33333333%;\n }\n .col-sm-pull-3 {\n right: 25%;\n }\n .col-sm-pull-2 {\n right: 16.66666667%;\n }\n .col-sm-pull-1 {\n right: 8.33333333%;\n }\n .col-sm-pull-0 {\n right: auto;\n }\n .col-sm-push-12 {\n left: 100%;\n }\n .col-sm-push-11 {\n left: 91.66666667%;\n }\n .col-sm-push-10 {\n left: 83.33333333%;\n }\n .col-sm-push-9 {\n left: 75%;\n }\n .col-sm-push-8 {\n left: 66.66666667%;\n }\n .col-sm-push-7 {\n left: 58.33333333%;\n }\n .col-sm-push-6 {\n left: 50%;\n }\n .col-sm-push-5 {\n left: 41.66666667%;\n }\n .col-sm-push-4 {\n left: 33.33333333%;\n }\n .col-sm-push-3 {\n left: 25%;\n }\n .col-sm-push-2 {\n left: 16.66666667%;\n }\n .col-sm-push-1 {\n left: 8.33333333%;\n }\n .col-sm-push-0 {\n left: auto;\n }\n .col-sm-offset-12 {\n margin-left: 100%;\n }\n .col-sm-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-sm-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-sm-offset-9 {\n margin-left: 75%;\n }\n .col-sm-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-sm-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-sm-offset-6 {\n margin-left: 50%;\n }\n .col-sm-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-sm-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-sm-offset-3 {\n margin-left: 25%;\n }\n .col-sm-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-sm-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-sm-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 992px) {\n .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {\n float: left;\n }\n .col-md-12 {\n width: 100%;\n }\n .col-md-11 {\n width: 91.66666667%;\n }\n .col-md-10 {\n width: 83.33333333%;\n }\n .col-md-9 {\n width: 75%;\n }\n .col-md-8 {\n width: 66.66666667%;\n }\n .col-md-7 {\n width: 58.33333333%;\n }\n .col-md-6 {\n width: 50%;\n }\n .col-md-5 {\n width: 41.66666667%;\n }\n .col-md-4 {\n width: 33.33333333%;\n }\n .col-md-3 {\n width: 25%;\n }\n .col-md-2 {\n width: 16.66666667%;\n }\n .col-md-1 {\n width: 8.33333333%;\n }\n .col-md-pull-12 {\n right: 100%;\n }\n .col-md-pull-11 {\n right: 91.66666667%;\n }\n .col-md-pull-10 {\n right: 83.33333333%;\n }\n .col-md-pull-9 {\n right: 75%;\n }\n .col-md-pull-8 {\n right: 66.66666667%;\n }\n .col-md-pull-7 {\n right: 58.33333333%;\n }\n .col-md-pull-6 {\n right: 50%;\n }\n .col-md-pull-5 {\n right: 41.66666667%;\n }\n .col-md-pull-4 {\n right: 33.33333333%;\n }\n .col-md-pull-3 {\n right: 25%;\n }\n .col-md-pull-2 {\n right: 16.66666667%;\n }\n .col-md-pull-1 {\n right: 8.33333333%;\n }\n .col-md-pull-0 {\n right: auto;\n }\n .col-md-push-12 {\n left: 100%;\n }\n .col-md-push-11 {\n left: 91.66666667%;\n }\n .col-md-push-10 {\n left: 83.33333333%;\n }\n .col-md-push-9 {\n left: 75%;\n }\n .col-md-push-8 {\n left: 66.66666667%;\n }\n .col-md-push-7 {\n left: 58.33333333%;\n }\n .col-md-push-6 {\n left: 50%;\n }\n .col-md-push-5 {\n left: 41.66666667%;\n }\n .col-md-push-4 {\n left: 33.33333333%;\n }\n .col-md-push-3 {\n left: 25%;\n }\n .col-md-push-2 {\n left: 16.66666667%;\n }\n .col-md-push-1 {\n left: 8.33333333%;\n }\n .col-md-push-0 {\n left: auto;\n }\n .col-md-offset-12 {\n margin-left: 100%;\n }\n .col-md-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-md-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-md-offset-9 {\n margin-left: 75%;\n }\n .col-md-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-md-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-md-offset-6 {\n margin-left: 50%;\n }\n .col-md-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-md-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-md-offset-3 {\n margin-left: 25%;\n }\n .col-md-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-md-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-md-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 1200px) {\n .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {\n float: left;\n }\n .col-lg-12 {\n width: 100%;\n }\n .col-lg-11 {\n width: 91.66666667%;\n }\n .col-lg-10 {\n width: 83.33333333%;\n }\n .col-lg-9 {\n width: 75%;\n }\n .col-lg-8 {\n width: 66.66666667%;\n }\n .col-lg-7 {\n width: 58.33333333%;\n }\n .col-lg-6 {\n width: 50%;\n }\n .col-lg-5 {\n width: 41.66666667%;\n }\n .col-lg-4 {\n width: 33.33333333%;\n }\n .col-lg-3 {\n width: 25%;\n }\n .col-lg-2 {\n width: 16.66666667%;\n }\n .col-lg-1 {\n width: 8.33333333%;\n }\n .col-lg-pull-12 {\n right: 100%;\n }\n .col-lg-pull-11 {\n right: 91.66666667%;\n }\n .col-lg-pull-10 {\n right: 83.33333333%;\n }\n .col-lg-pull-9 {\n right: 75%;\n }\n .col-lg-pull-8 {\n right: 66.66666667%;\n }\n .col-lg-pull-7 {\n right: 58.33333333%;\n }\n .col-lg-pull-6 {\n right: 50%;\n }\n .col-lg-pull-5 {\n right: 41.66666667%;\n }\n .col-lg-pull-4 {\n right: 33.33333333%;\n }\n .col-lg-pull-3 {\n right: 25%;\n }\n .col-lg-pull-2 {\n right: 16.66666667%;\n }\n .col-lg-pull-1 {\n right: 8.33333333%;\n }\n .col-lg-pull-0 {\n right: auto;\n }\n .col-lg-push-12 {\n left: 100%;\n }\n .col-lg-push-11 {\n left: 91.66666667%;\n }\n .col-lg-push-10 {\n left: 83.33333333%;\n }\n .col-lg-push-9 {\n left: 75%;\n }\n .col-lg-push-8 {\n left: 66.66666667%;\n }\n .col-lg-push-7 {\n left: 58.33333333%;\n }\n .col-lg-push-6 {\n left: 50%;\n }\n .col-lg-push-5 {\n left: 41.66666667%;\n }\n .col-lg-push-4 {\n left: 33.33333333%;\n }\n .col-lg-push-3 {\n left: 25%;\n }\n .col-lg-push-2 {\n left: 16.66666667%;\n }\n .col-lg-push-1 {\n left: 8.33333333%;\n }\n .col-lg-push-0 {\n left: auto;\n }\n .col-lg-offset-12 {\n margin-left: 100%;\n }\n .col-lg-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-lg-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-lg-offset-9 {\n margin-left: 75%;\n }\n .col-lg-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-lg-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-lg-offset-6 {\n margin-left: 50%;\n }\n .col-lg-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-lg-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-lg-offset-3 {\n margin-left: 25%;\n }\n .col-lg-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-lg-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-lg-offset-0 {\n margin-left: 0%;\n }\n}\ntable {\n background-color: transparent;\n}\ncaption {\n padding-top: 8px;\n padding-bottom: 8px;\n color: #777777;\n text-align: left;\n}\nth {\n text-align: left;\n}\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n padding: 8px;\n line-height: 1.42857143;\n vertical-align: top;\n border-top: 1px solid #dddddd;\n}\n.table > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid #dddddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n border-top: 0;\n}\n.table > tbody + tbody {\n border-top: 2px solid #dddddd;\n}\n.table .table {\n background-color: #ffffff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n padding: 5px;\n}\n.table-bordered {\n border: 1px solid #dddddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n border: 1px solid #dddddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n position: static;\n float: none;\n display: table-column;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n position: static;\n float: none;\n display: table-cell;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n background-color: #ebcccc;\n}\n.table-responsive {\n overflow-x: auto;\n min-height: 0.01%;\n}\n@media screen and (max-width: 767px) {\n .table-responsive {\n width: 100%;\n margin-bottom: 15px;\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid #dddddd;\n }\n .table-responsive > .table {\n margin-bottom: 0;\n }\n .table-responsive > .table > thead > tr > th,\n .table-responsive > .table > tbody > tr > th,\n .table-responsive > .table > tfoot > tr > th,\n .table-responsive > .table > thead > tr > td,\n .table-responsive > .table > tbody > tr > td,\n .table-responsive > .table > tfoot > tr > td {\n white-space: nowrap;\n }\n .table-responsive > .table-bordered {\n border: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:first-child,\n .table-responsive > .table-bordered > tbody > tr > th:first-child,\n .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n .table-responsive > .table-bordered > thead > tr > td:first-child,\n .table-responsive > .table-bordered > tbody > tr > td:first-child,\n .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:last-child,\n .table-responsive > .table-bordered > tbody > tr > th:last-child,\n .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n .table-responsive > .table-bordered > thead > tr > td:last-child,\n .table-responsive > .table-bordered > tbody > tr > td:last-child,\n .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n }\n .table-responsive > .table-bordered > tbody > tr:last-child > th,\n .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n .table-responsive > .table-bordered > tbody > tr:last-child > td,\n .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n border-bottom: 0;\n }\n}\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n min-width: 0;\n}\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: 20px;\n font-size: 21px;\n line-height: inherit;\n color: #333333;\n border: 0;\n border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n display: inline-block;\n max-width: 100%;\n margin-bottom: 5px;\n font-weight: bold;\n}\ninput[type=\"search\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9;\n line-height: normal;\n}\ninput[type=\"file\"] {\n display: block;\n}\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\nselect[multiple],\nselect[size] {\n height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\noutput {\n display: block;\n padding-top: 7px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n}\n.form-control {\n display: block;\n width: 100%;\n height: 34px;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n background-color: #ffffff;\n background-image: none;\n border: 1px solid #cccccc;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n border-color: #66afe9;\n outline: 0;\n -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n color: #999999;\n opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n color: #999999;\n}\n.form-control::-webkit-input-placeholder {\n color: #999999;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n background-color: #eeeeee;\n opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n cursor: not-allowed;\n}\ntextarea.form-control {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"].form-control,\n input[type=\"time\"].form-control,\n input[type=\"datetime-local\"].form-control,\n input[type=\"month\"].form-control {\n line-height: 34px;\n }\n input[type=\"date\"].input-sm,\n input[type=\"time\"].input-sm,\n input[type=\"datetime-local\"].input-sm,\n input[type=\"month\"].input-sm,\n .input-group-sm input[type=\"date\"],\n .input-group-sm input[type=\"time\"],\n .input-group-sm input[type=\"datetime-local\"],\n .input-group-sm input[type=\"month\"] {\n line-height: 30px;\n }\n input[type=\"date\"].input-lg,\n input[type=\"time\"].input-lg,\n input[type=\"datetime-local\"].input-lg,\n input[type=\"month\"].input-lg,\n .input-group-lg input[type=\"date\"],\n .input-group-lg input[type=\"time\"],\n .input-group-lg input[type=\"datetime-local\"],\n .input-group-lg input[type=\"month\"] {\n line-height: 46px;\n }\n}\n.form-group {\n margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n min-height: 20px;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: normal;\n cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-left: -20px;\n margin-top: 4px \\9;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n position: relative;\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n vertical-align: middle;\n font-weight: normal;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n cursor: not-allowed;\n}\n.form-control-static {\n padding-top: 7px;\n padding-bottom: 7px;\n margin-bottom: 0;\n min-height: 34px;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n padding-left: 0;\n padding-right: 0;\n}\n.input-sm {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-sm {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n height: auto;\n}\n.form-group-sm .form-control {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.form-group-sm select.form-control {\n height: 30px;\n line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n height: auto;\n}\n.form-group-sm .form-control-static {\n height: 30px;\n min-height: 32px;\n padding: 6px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.input-lg {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-lg {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n height: auto;\n}\n.form-group-lg .form-control {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.form-group-lg select.form-control {\n height: 46px;\n line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n height: auto;\n}\n.form-group-lg .form-control-static {\n height: 46px;\n min-height: 38px;\n padding: 11px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.has-feedback {\n position: relative;\n}\n.has-feedback .form-control {\n padding-right: 42.5px;\n}\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n width: 46px;\n height: 46px;\n line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n width: 30px;\n height: 30px;\n line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n color: #3c763d;\n}\n.has-success .form-control {\n border-color: #3c763d;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n border-color: #2b542c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n color: #3c763d;\n border-color: #3c763d;\n background-color: #dff0d8;\n}\n.has-success .form-control-feedback {\n color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n color: #8a6d3b;\n}\n.has-warning .form-control {\n border-color: #8a6d3b;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n border-color: #66512c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n color: #8a6d3b;\n border-color: #8a6d3b;\n background-color: #fcf8e3;\n}\n.has-warning .form-control-feedback {\n color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n color: #a94442;\n}\n.has-error .form-control {\n border-color: #a94442;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n border-color: #843534;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n color: #a94442;\n border-color: #a94442;\n background-color: #f2dede;\n}\n.has-error .form-control-feedback {\n color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n top: 0;\n}\n.help-block {\n display: block;\n margin-top: 5px;\n margin-bottom: 10px;\n color: #737373;\n}\n@media (min-width: 768px) {\n .form-inline .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-static {\n display: inline-block;\n }\n .form-inline .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .form-inline .input-group .input-group-addon,\n .form-inline .input-group .input-group-btn,\n .form-inline .input-group .form-control {\n width: auto;\n }\n .form-inline .input-group > .form-control {\n width: 100%;\n }\n .form-inline .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio,\n .form-inline .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio label,\n .form-inline .checkbox label {\n padding-left: 0;\n }\n .form-inline .radio input[type=\"radio\"],\n .form-inline .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .form-inline .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n margin-top: 0;\n margin-bottom: 0;\n padding-top: 7px;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n min-height: 27px;\n}\n.form-horizontal .form-group {\n margin-left: -15px;\n margin-right: -15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .control-label {\n text-align: right;\n margin-bottom: 0;\n padding-top: 7px;\n }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n right: 15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-lg .control-label {\n padding-top: 14.333333px;\n font-size: 18px;\n }\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-sm .control-label {\n padding-top: 6px;\n font-size: 12px;\n }\n}\n.btn {\n display: inline-block;\n margin-bottom: 0;\n font-weight: normal;\n text-align: center;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none;\n border: 1px solid transparent;\n white-space: nowrap;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n border-radius: 4px;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n color: #333333;\n text-decoration: none;\n}\n.btn:active,\n.btn.active {\n outline: 0;\n background-image: none;\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n cursor: not-allowed;\n opacity: 0.65;\n filter: alpha(opacity=65);\n -webkit-box-shadow: none;\n box-shadow: none;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n pointer-events: none;\n}\n.btn-default {\n color: #333333;\n background-color: #ffffff;\n border-color: #cccccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n color: #333333;\n background-color: #e6e6e6;\n border-color: #8c8c8c;\n}\n.btn-default:hover {\n color: #333333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n color: #333333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n color: #333333;\n background-color: #d4d4d4;\n border-color: #8c8c8c;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n background-image: none;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n background-color: #ffffff;\n border-color: #cccccc;\n}\n.btn-default .badge {\n color: #ffffff;\n background-color: #333333;\n}\n.btn-primary {\n color: #ffffff;\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n color: #ffffff;\n background-color: #286090;\n border-color: #122b40;\n}\n.btn-primary:hover {\n color: #ffffff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n color: #ffffff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n color: #ffffff;\n background-color: #204d74;\n border-color: #122b40;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n background-image: none;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary .badge {\n color: #337ab7;\n background-color: #ffffff;\n}\n.btn-success {\n color: #ffffff;\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success:focus,\n.btn-success.focus {\n color: #ffffff;\n background-color: #449d44;\n border-color: #255625;\n}\n.btn-success:hover {\n color: #ffffff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n color: #ffffff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n color: #ffffff;\n background-color: #398439;\n border-color: #255625;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n background-image: none;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success .badge {\n color: #5cb85c;\n background-color: #ffffff;\n}\n.btn-info {\n color: #ffffff;\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info:focus,\n.btn-info.focus {\n color: #ffffff;\n background-color: #31b0d5;\n border-color: #1b6d85;\n}\n.btn-info:hover {\n color: #ffffff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n color: #ffffff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n color: #ffffff;\n background-color: #269abc;\n border-color: #1b6d85;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n background-image: none;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info .badge {\n color: #5bc0de;\n background-color: #ffffff;\n}\n.btn-warning {\n color: #ffffff;\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n color: #ffffff;\n background-color: #ec971f;\n border-color: #985f0d;\n}\n.btn-warning:hover {\n color: #ffffff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n color: #ffffff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n color: #ffffff;\n background-color: #d58512;\n border-color: #985f0d;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n background-image: none;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning .badge {\n color: #f0ad4e;\n background-color: #ffffff;\n}\n.btn-danger {\n color: #ffffff;\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n color: #ffffff;\n background-color: #c9302c;\n border-color: #761c19;\n}\n.btn-danger:hover {\n color: #ffffff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n color: #ffffff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n color: #ffffff;\n background-color: #ac2925;\n border-color: #761c19;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n background-image: none;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger .badge {\n color: #d9534f;\n background-color: #ffffff;\n}\n.btn-link {\n color: #337ab7;\n font-weight: normal;\n border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n background-color: transparent;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n color: #23527c;\n text-decoration: underline;\n background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n color: #777777;\n text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n padding: 1px 5px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-block {\n display: block;\n width: 100%;\n}\n.btn-block + .btn-block {\n margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n.fade {\n opacity: 0;\n -webkit-transition: opacity 0.15s linear;\n -o-transition: opacity 0.15s linear;\n transition: opacity 0.15s linear;\n}\n.fade.in {\n opacity: 1;\n}\n.collapse {\n display: none;\n}\n.collapse.in {\n display: block;\n}\ntr.collapse.in {\n display: table-row;\n}\ntbody.collapse.in {\n display: table-row-group;\n}\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n -webkit-transition-property: height, visibility;\n transition-property: height, visibility;\n -webkit-transition-duration: 0.35s;\n transition-duration: 0.35s;\n -webkit-transition-timing-function: ease;\n transition-timing-function: ease;\n}\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: 4px dashed;\n border-top: 4px solid \\9;\n border-right: 4px solid transparent;\n border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n position: relative;\n}\n.dropdown-toggle:focus {\n outline: 0;\n}\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0;\n list-style: none;\n font-size: 14px;\n text-align: left;\n background-color: #ffffff;\n border: 1px solid #cccccc;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 4px;\n -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n background-clip: padding-box;\n}\n.dropdown-menu.pull-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu .divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: 1.42857143;\n color: #333333;\n white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n text-decoration: none;\n color: #262626;\n background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n color: #ffffff;\n text-decoration: none;\n outline: 0;\n background-color: #337ab7;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n color: #777777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n cursor: not-allowed;\n}\n.open > .dropdown-menu {\n display: block;\n}\n.open > a {\n outline: 0;\n}\n.dropdown-menu-right {\n left: auto;\n right: 0;\n}\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: 12px;\n line-height: 1.42857143;\n color: #777777;\n white-space: nowrap;\n}\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: 990;\n}\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n border-top: 0;\n border-bottom: 4px dashed;\n border-bottom: 4px solid \\9;\n content: \"\";\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n .navbar-right .dropdown-menu {\n left: auto;\n right: 0;\n }\n .navbar-right .dropdown-menu-left {\n left: 0;\n right: auto;\n }\n}\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n margin-left: -1px;\n}\n.btn-toolbar {\n margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n.btn-group > .btn:first-child {\n margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n.btn-group.open .dropdown-toggle {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn .caret {\n margin-left: 0;\n}\n.btn-lg .caret {\n border-width: 5px 5px 0;\n border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n border-bottom-left-radius: 4px;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.input-group {\n position: relative;\n display: table;\n border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n}\n.input-group .form-control {\n position: relative;\n z-index: 2;\n float: left;\n width: 100%;\n margin-bottom: 0;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle;\n}\n.input-group-addon {\n padding: 6px 12px;\n font-size: 14px;\n font-weight: normal;\n line-height: 1;\n color: #555555;\n text-align: center;\n background-color: #eeeeee;\n border: 1px solid #cccccc;\n border-radius: 4px;\n}\n.input-group-addon.input-sm {\n padding: 5px 10px;\n font-size: 12px;\n border-radius: 3px;\n}\n.input-group-addon.input-lg {\n padding: 10px 16px;\n font-size: 18px;\n border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n.input-group-btn {\n position: relative;\n font-size: 0;\n white-space: nowrap;\n}\n.input-group-btn > .btn {\n position: relative;\n}\n.input-group-btn > .btn + .btn {\n margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n z-index: 2;\n margin-left: -1px;\n}\n.nav {\n margin-bottom: 0;\n padding-left: 0;\n list-style: none;\n}\n.nav > li {\n position: relative;\n display: block;\n}\n.nav > li > a {\n position: relative;\n display: block;\n padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.nav > li.disabled > a {\n color: #777777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n color: #777777;\n text-decoration: none;\n background-color: transparent;\n cursor: not-allowed;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n background-color: #eeeeee;\n border-color: #337ab7;\n}\n.nav .nav-divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.nav > li > a > img {\n max-width: none;\n}\n.nav-tabs {\n border-bottom: 1px solid #dddddd;\n}\n.nav-tabs > li {\n float: left;\n margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n margin-right: 2px;\n line-height: 1.42857143;\n border: 1px solid transparent;\n border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n border-color: #eeeeee #eeeeee #dddddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n color: #555555;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-bottom-color: transparent;\n cursor: default;\n}\n.nav-tabs.nav-justified {\n width: 100%;\n border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n float: none;\n}\n.nav-tabs.nav-justified > li > a {\n text-align: center;\n margin-bottom: 5px;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-tabs.nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs.nav-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li > a {\n border-bottom: 1px solid #dddddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs.nav-justified > .active > a,\n .nav-tabs.nav-justified > .active > a:hover,\n .nav-tabs.nav-justified > .active > a:focus {\n border-bottom-color: #ffffff;\n }\n}\n.nav-pills > li {\n float: left;\n}\n.nav-pills > li > a {\n border-radius: 4px;\n}\n.nav-pills > li + li {\n margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n color: #ffffff;\n background-color: #337ab7;\n}\n.nav-stacked > li {\n float: none;\n}\n.nav-stacked > li + li {\n margin-top: 2px;\n margin-left: 0;\n}\n.nav-justified {\n width: 100%;\n}\n.nav-justified > li {\n float: none;\n}\n.nav-justified > li > a {\n text-align: center;\n margin-bottom: 5px;\n}\n.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs-justified {\n border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n .nav-tabs-justified > li > a {\n border-bottom: 1px solid #dddddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs-justified > .active > a,\n .nav-tabs-justified > .active > a:hover,\n .nav-tabs-justified > .active > a:focus {\n border-bottom-color: #ffffff;\n }\n}\n.tab-content > .tab-pane {\n display: none;\n}\n.tab-content > .active {\n display: block;\n}\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.navbar {\n position: relative;\n min-height: 50px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n .navbar {\n border-radius: 4px;\n }\n}\n@media (min-width: 768px) {\n .navbar-header {\n float: left;\n }\n}\n.navbar-collapse {\n overflow-x: visible;\n padding-right: 15px;\n padding-left: 15px;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse.in {\n overflow-y: auto;\n}\n@media (min-width: 768px) {\n .navbar-collapse {\n width: auto;\n border-top: 0;\n box-shadow: none;\n }\n .navbar-collapse.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0;\n overflow: visible !important;\n }\n .navbar-collapse.in {\n overflow-y: visible;\n }\n .navbar-fixed-top .navbar-collapse,\n .navbar-static-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n padding-left: 0;\n padding-right: 0;\n }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n .navbar-fixed-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n max-height: 200px;\n }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .container > .navbar-header,\n .container-fluid > .navbar-header,\n .container > .navbar-collapse,\n .container-fluid > .navbar-collapse {\n margin-right: 0;\n margin-left: 0;\n }\n}\n.navbar-static-top {\n z-index: 1000;\n border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n .navbar-static-top {\n border-radius: 0;\n }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n@media (min-width: 768px) {\n .navbar-fixed-top,\n .navbar-fixed-bottom {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0;\n border-width: 1px 0 0;\n}\n.navbar-brand {\n float: left;\n padding: 15px 15px;\n font-size: 18px;\n line-height: 20px;\n height: 50px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n text-decoration: none;\n}\n.navbar-brand > img {\n display: block;\n}\n@media (min-width: 768px) {\n .navbar > .container .navbar-brand,\n .navbar > .container-fluid .navbar-brand {\n margin-left: -15px;\n }\n}\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: 15px;\n padding: 9px 10px;\n margin-top: 8px;\n margin-bottom: 8px;\n background-color: transparent;\n background-image: none;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.navbar-toggle:focus {\n outline: 0;\n}\n.navbar-toggle .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n margin-top: 4px;\n}\n@media (min-width: 768px) {\n .navbar-toggle {\n display: none;\n }\n}\n.navbar-nav {\n margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: 20px;\n}\n@media (max-width: 767px) {\n .navbar-nav .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n }\n .navbar-nav .open .dropdown-menu > li > a,\n .navbar-nav .open .dropdown-menu .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n .navbar-nav .open .dropdown-menu > li > a {\n line-height: 20px;\n }\n .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-nav .open .dropdown-menu > li > a:focus {\n background-image: none;\n }\n}\n@media (min-width: 768px) {\n .navbar-nav {\n float: left;\n margin: 0;\n }\n .navbar-nav > li {\n float: left;\n }\n .navbar-nav > li > a {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n}\n.navbar-form {\n margin-left: -15px;\n margin-right: -15px;\n padding: 10px 15px;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n margin-top: 8px;\n margin-bottom: 8px;\n}\n@media (min-width: 768px) {\n .navbar-form .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .navbar-form .form-control-static {\n display: inline-block;\n }\n .navbar-form .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .navbar-form .input-group .input-group-addon,\n .navbar-form .input-group .input-group-btn,\n .navbar-form .input-group .form-control {\n width: auto;\n }\n .navbar-form .input-group > .form-control {\n width: 100%;\n }\n .navbar-form .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio,\n .navbar-form .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio label,\n .navbar-form .checkbox label {\n padding-left: 0;\n }\n .navbar-form .radio input[type=\"radio\"],\n .navbar-form .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .navbar-form .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n@media (max-width: 767px) {\n .navbar-form .form-group {\n margin-bottom: 5px;\n }\n .navbar-form .form-group:last-child {\n margin-bottom: 0;\n }\n}\n@media (min-width: 768px) {\n .navbar-form {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n}\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.navbar-btn {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n margin-top: 14px;\n margin-bottom: 14px;\n}\n.navbar-text {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n .navbar-text {\n float: left;\n margin-left: 15px;\n margin-right: 15px;\n }\n}\n@media (min-width: 768px) {\n .navbar-left {\n float: left !important;\n }\n .navbar-right {\n float: right !important;\n margin-right: -15px;\n }\n .navbar-right ~ .navbar-right {\n margin-right: 0;\n }\n}\n.navbar-default {\n background-color: #f8f8f8;\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n color: #777777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n color: #5e5e5e;\n background-color: transparent;\n}\n.navbar-default .navbar-text {\n color: #777777;\n}\n.navbar-default .navbar-nav > li > a {\n color: #777777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n color: #333333;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n color: #555555;\n background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n color: #cccccc;\n background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n border-color: #dddddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n background-color: #dddddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n background-color: #888888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n background-color: #e7e7e7;\n color: #555555;\n}\n@media (max-width: 767px) {\n .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n color: #777777;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #333333;\n background-color: transparent;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #555555;\n background-color: #e7e7e7;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #cccccc;\n background-color: transparent;\n }\n}\n.navbar-default .navbar-link {\n color: #777777;\n}\n.navbar-default .navbar-link:hover {\n color: #333333;\n}\n.navbar-default .btn-link {\n color: #777777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n color: #333333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n color: #cccccc;\n}\n.navbar-inverse {\n background-color: #222222;\n border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n color: #ffffff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n color: #ffffff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n color: #ffffff;\n background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n color: #444444;\n background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n border-color: #333333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n background-color: #333333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n background-color: #ffffff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n background-color: #080808;\n color: #ffffff;\n}\n@media (max-width: 767px) {\n .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n border-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n color: #9d9d9d;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #ffffff;\n background-color: transparent;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #ffffff;\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #444444;\n background-color: transparent;\n }\n}\n.navbar-inverse .navbar-link {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n color: #ffffff;\n}\n.navbar-inverse .btn-link {\n color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n color: #ffffff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n color: #444444;\n}\n.breadcrumb {\n padding: 8px 15px;\n margin-bottom: 20px;\n list-style: none;\n background-color: #f5f5f5;\n border-radius: 4px;\n}\n.breadcrumb > li {\n display: inline-block;\n}\n.breadcrumb > li + li:before {\n content: \"/\\00a0\";\n padding: 0 5px;\n color: #cccccc;\n}\n.breadcrumb > .active {\n color: #777777;\n}\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: 20px 0;\n border-radius: 4px;\n}\n.pagination > li {\n display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n position: relative;\n float: left;\n padding: 6px 12px;\n line-height: 1.42857143;\n text-decoration: none;\n color: #337ab7;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n margin-left: -1px;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n margin-left: 0;\n border-bottom-left-radius: 4px;\n border-top-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n border-bottom-right-radius: 4px;\n border-top-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n z-index: 3;\n color: #23527c;\n background-color: #eeeeee;\n border-color: #dddddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n z-index: 2;\n color: #ffffff;\n background-color: #337ab7;\n border-color: #337ab7;\n cursor: default;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n color: #777777;\n background-color: #ffffff;\n border-color: #dddddd;\n cursor: not-allowed;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n border-bottom-left-radius: 6px;\n border-top-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n border-bottom-right-radius: 6px;\n border-top-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n border-bottom-left-radius: 3px;\n border-top-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n border-bottom-right-radius: 3px;\n border-top-right-radius: 3px;\n}\n.pager {\n padding-left: 0;\n margin: 20px 0;\n list-style: none;\n text-align: center;\n}\n.pager li {\n display: inline;\n}\n.pager li > a,\n.pager li > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.pager .next > a,\n.pager .next > span {\n float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n color: #777777;\n background-color: #ffffff;\n cursor: not-allowed;\n}\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: #ffffff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n color: #ffffff;\n text-decoration: none;\n cursor: pointer;\n}\n.label:empty {\n display: none;\n}\n.btn .label {\n position: relative;\n top: -1px;\n}\n.label-default {\n background-color: #777777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n background-color: #5e5e5e;\n}\n.label-primary {\n background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n background-color: #286090;\n}\n.label-success {\n background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n background-color: #449d44;\n}\n.label-info {\n background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n background-color: #31b0d5;\n}\n.label-warning {\n background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n background-color: #ec971f;\n}\n.label-danger {\n background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n background-color: #c9302c;\n}\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: 12px;\n font-weight: bold;\n color: #ffffff;\n line-height: 1;\n vertical-align: middle;\n white-space: nowrap;\n text-align: center;\n background-color: #777777;\n border-radius: 10px;\n}\n.badge:empty {\n display: none;\n}\n.btn .badge {\n position: relative;\n top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n top: 0;\n padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n color: #ffffff;\n text-decoration: none;\n cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n color: #337ab7;\n background-color: #ffffff;\n}\n.list-group-item > .badge {\n float: right;\n}\n.list-group-item > .badge + .badge {\n margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n margin-left: 3px;\n}\n.jumbotron {\n padding-top: 30px;\n padding-bottom: 30px;\n margin-bottom: 30px;\n color: inherit;\n background-color: #eeeeee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n color: inherit;\n}\n.jumbotron p {\n margin-bottom: 15px;\n font-size: 21px;\n font-weight: 200;\n}\n.jumbotron > hr {\n border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n border-radius: 6px;\n}\n.jumbotron .container {\n max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n .jumbotron {\n padding-top: 48px;\n padding-bottom: 48px;\n }\n .container .jumbotron,\n .container-fluid .jumbotron {\n padding-left: 60px;\n padding-right: 60px;\n }\n .jumbotron h1,\n .jumbotron .h1 {\n font-size: 63px;\n }\n}\n.thumbnail {\n display: block;\n padding: 4px;\n margin-bottom: 20px;\n line-height: 1.42857143;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 4px;\n -webkit-transition: border 0.2s ease-in-out;\n -o-transition: border 0.2s ease-in-out;\n transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n margin-left: auto;\n margin-right: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n border-color: #337ab7;\n}\n.thumbnail .caption {\n padding: 9px;\n color: #333333;\n}\n.alert {\n padding: 15px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.alert h4 {\n margin-top: 0;\n color: inherit;\n}\n.alert .alert-link {\n font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n margin-bottom: 0;\n}\n.alert > p + p {\n margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n}\n.alert-success {\n background-color: #dff0d8;\n border-color: #d6e9c6;\n color: #3c763d;\n}\n.alert-success hr {\n border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n color: #2b542c;\n}\n.alert-info {\n background-color: #d9edf7;\n border-color: #bce8f1;\n color: #31708f;\n}\n.alert-info hr {\n border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n color: #245269;\n}\n.alert-warning {\n background-color: #fcf8e3;\n border-color: #faebcc;\n color: #8a6d3b;\n}\n.alert-warning hr {\n border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n color: #66512c;\n}\n.alert-danger {\n background-color: #f2dede;\n border-color: #ebccd1;\n color: #a94442;\n}\n.alert-danger hr {\n border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n.progress {\n overflow: hidden;\n height: 20px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: 12px;\n line-height: 20px;\n color: #ffffff;\n text-align: center;\n background-color: #337ab7;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n -webkit-transition: width 0.6s ease;\n -o-transition: width 0.6s ease;\n transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n -webkit-animation: progress-bar-stripes 2s linear infinite;\n -o-animation: progress-bar-stripes 2s linear infinite;\n animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.media {\n margin-top: 15px;\n}\n.media:first-child {\n margin-top: 0;\n}\n.media,\n.media-body {\n zoom: 1;\n overflow: hidden;\n}\n.media-body {\n width: 10000px;\n}\n.media-object {\n display: block;\n}\n.media-object.img-thumbnail {\n max-width: none;\n}\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n.media-middle {\n vertical-align: middle;\n}\n.media-bottom {\n vertical-align: bottom;\n}\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n.list-group {\n margin-bottom: 20px;\n padding-left: 0;\n}\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n margin-bottom: -1px;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n}\n.list-group-item:first-child {\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n}\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\na.list-group-item,\nbutton.list-group-item {\n color: #555555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n color: #333333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n text-decoration: none;\n color: #555555;\n background-color: #f5f5f5;\n}\nbutton.list-group-item {\n width: 100%;\n text-align: left;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n background-color: #eeeeee;\n color: #777777;\n cursor: not-allowed;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n color: #777777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n z-index: 2;\n color: #ffffff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n color: #c7ddef;\n}\n.list-group-item-success {\n color: #3c763d;\n background-color: #dff0d8;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n color: #3c763d;\n background-color: #d0e9c6;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n color: #fff;\n background-color: #3c763d;\n border-color: #3c763d;\n}\n.list-group-item-info {\n color: #31708f;\n background-color: #d9edf7;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n color: #31708f;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n color: #31708f;\n background-color: #c4e3f3;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n color: #fff;\n background-color: #31708f;\n border-color: #31708f;\n}\n.list-group-item-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n color: #8a6d3b;\n background-color: #faf2cc;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n color: #fff;\n background-color: #8a6d3b;\n border-color: #8a6d3b;\n}\n.list-group-item-danger {\n color: #a94442;\n background-color: #f2dede;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n color: #a94442;\n background-color: #ebcccc;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n color: #fff;\n background-color: #a94442;\n border-color: #a94442;\n}\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n.panel {\n margin-bottom: 20px;\n background-color: #ffffff;\n border: 1px solid transparent;\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.panel-body {\n padding: 15px;\n}\n.panel-heading {\n padding: 10px 15px;\n border-bottom: 1px solid transparent;\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n color: inherit;\n}\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: 16px;\n color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n color: inherit;\n}\n.panel-footer {\n padding: 10px 15px;\n background-color: #f5f5f5;\n border-top: 1px solid #dddddd;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n border-top: 0;\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n border-bottom: 0;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n border-top-width: 0;\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n padding-left: 15px;\n padding-right: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n border-bottom-left-radius: 3px;\n border-bottom-right-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n border-top: 1px solid #dddddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n border-bottom: 0;\n}\n.panel > .table-responsive {\n border: 0;\n margin-bottom: 0;\n}\n.panel-group {\n margin-bottom: 20px;\n}\n.panel-group .panel {\n margin-bottom: 0;\n border-radius: 4px;\n}\n.panel-group .panel + .panel {\n margin-top: 5px;\n}\n.panel-group .panel-heading {\n border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n border-top: 1px solid #dddddd;\n}\n.panel-group .panel-footer {\n border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n border-bottom: 1px solid #dddddd;\n}\n.panel-default {\n border-color: #dddddd;\n}\n.panel-default > .panel-heading {\n color: #333333;\n background-color: #f5f5f5;\n border-color: #dddddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #dddddd;\n}\n.panel-default > .panel-heading .badge {\n color: #f5f5f5;\n background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #dddddd;\n}\n.panel-primary {\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n color: #ffffff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n color: #337ab7;\n background-color: #ffffff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #337ab7;\n}\n.panel-success {\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n color: #dff0d8;\n background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #d6e9c6;\n}\n.panel-info {\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n color: #d9edf7;\n background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #bce8f1;\n}\n.panel-warning {\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n color: #fcf8e3;\n background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #faebcc;\n}\n.panel-danger {\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n color: #f2dede;\n background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n height: 100%;\n width: 100%;\n border: 0;\n}\n.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border: 1px solid #e3e3e3;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n border-color: #ddd;\n border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n padding: 24px;\n border-radius: 6px;\n}\n.well-sm {\n padding: 9px;\n border-radius: 3px;\n}\n.close {\n float: right;\n font-size: 21px;\n font-weight: bold;\n line-height: 1;\n color: #000000;\n text-shadow: 0 1px 0 #ffffff;\n opacity: 0.2;\n filter: alpha(opacity=20);\n}\n.close:hover,\n.close:focus {\n color: #000000;\n text-decoration: none;\n cursor: pointer;\n opacity: 0.5;\n filter: alpha(opacity=50);\n}\nbutton.close {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n}\n.modal-open {\n overflow: hidden;\n}\n.modal {\n display: none;\n overflow: hidden;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1050;\n -webkit-overflow-scrolling: touch;\n outline: 0;\n}\n.modal.fade .modal-dialog {\n -webkit-transform: translate(0, -25%);\n -ms-transform: translate(0, -25%);\n -o-transform: translate(0, -25%);\n transform: translate(0, -25%);\n -webkit-transition: -webkit-transform 0.3s ease-out;\n -moz-transition: -moz-transform 0.3s ease-out;\n -o-transition: -o-transform 0.3s ease-out;\n transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n -webkit-transform: translate(0, 0);\n -ms-transform: translate(0, 0);\n -o-transform: translate(0, 0);\n transform: translate(0, 0);\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n.modal-content {\n position: relative;\n background-color: #ffffff;\n border: 1px solid #999999;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n background-clip: padding-box;\n outline: 0;\n}\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1040;\n background-color: #000000;\n}\n.modal-backdrop.fade {\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.modal-backdrop.in {\n opacity: 0.5;\n filter: alpha(opacity=50);\n}\n.modal-header {\n padding: 15px;\n border-bottom: 1px solid #e5e5e5;\n min-height: 16.42857143px;\n}\n.modal-header .close {\n margin-top: -2px;\n}\n.modal-title {\n margin: 0;\n line-height: 1.42857143;\n}\n.modal-body {\n position: relative;\n padding: 15px;\n}\n.modal-footer {\n padding: 15px;\n text-align: right;\n border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n margin-left: 5px;\n margin-bottom: 0;\n}\n.modal-footer .btn-group .btn + .btn {\n margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n margin-left: 0;\n}\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n@media (min-width: 768px) {\n .modal-dialog {\n width: 600px;\n margin: 30px auto;\n }\n .modal-content {\n -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n }\n .modal-sm {\n width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg {\n width: 900px;\n }\n}\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: normal;\n letter-spacing: normal;\n line-break: auto;\n line-height: 1.42857143;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n white-space: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n font-size: 12px;\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.tooltip.in {\n opacity: 0.9;\n filter: alpha(opacity=90);\n}\n.tooltip.top {\n margin-top: -3px;\n padding: 5px 0;\n}\n.tooltip.right {\n margin-left: 3px;\n padding: 0 5px;\n}\n.tooltip.bottom {\n margin-top: 3px;\n padding: 5px 0;\n}\n.tooltip.left {\n margin-left: -3px;\n padding: 0 5px;\n}\n.tooltip-inner {\n max-width: 200px;\n padding: 3px 8px;\n color: #ffffff;\n text-align: center;\n background-color: #000000;\n border-radius: 4px;\n}\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.top-left .tooltip-arrow {\n bottom: 0;\n right: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.top-right .tooltip-arrow {\n bottom: 0;\n left: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -5px;\n border-width: 5px 5px 5px 0;\n border-right-color: #000000;\n}\n.tooltip.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -5px;\n border-width: 5px 0 5px 5px;\n border-left-color: #000000;\n}\n.tooltip.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n top: 0;\n right: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n top: 0;\n left: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: none;\n max-width: 276px;\n padding: 1px;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: normal;\n letter-spacing: normal;\n line-break: auto;\n line-height: 1.42857143;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n white-space: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n font-size: 14px;\n background-color: #ffffff;\n background-clip: padding-box;\n border: 1px solid #cccccc;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n}\n.popover.top {\n margin-top: -10px;\n}\n.popover.right {\n margin-left: 10px;\n}\n.popover.bottom {\n margin-top: 10px;\n}\n.popover.left {\n margin-left: -10px;\n}\n.popover-title {\n margin: 0;\n padding: 8px 14px;\n font-size: 14px;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-radius: 5px 5px 0 0;\n}\n.popover-content {\n padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover > .arrow {\n border-width: 11px;\n}\n.popover > .arrow:after {\n border-width: 10px;\n content: \"\";\n}\n.popover.top > .arrow {\n left: 50%;\n margin-left: -11px;\n border-bottom-width: 0;\n border-top-color: #999999;\n border-top-color: rgba(0, 0, 0, 0.25);\n bottom: -11px;\n}\n.popover.top > .arrow:after {\n content: \" \";\n bottom: 1px;\n margin-left: -10px;\n border-bottom-width: 0;\n border-top-color: #ffffff;\n}\n.popover.right > .arrow {\n top: 50%;\n left: -11px;\n margin-top: -11px;\n border-left-width: 0;\n border-right-color: #999999;\n border-right-color: rgba(0, 0, 0, 0.25);\n}\n.popover.right > .arrow:after {\n content: \" \";\n left: 1px;\n bottom: -10px;\n border-left-width: 0;\n border-right-color: #ffffff;\n}\n.popover.bottom > .arrow {\n left: 50%;\n margin-left: -11px;\n border-top-width: 0;\n border-bottom-color: #999999;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n top: -11px;\n}\n.popover.bottom > .arrow:after {\n content: \" \";\n top: 1px;\n margin-left: -10px;\n border-top-width: 0;\n border-bottom-color: #ffffff;\n}\n.popover.left > .arrow {\n top: 50%;\n right: -11px;\n margin-top: -11px;\n border-right-width: 0;\n border-left-color: #999999;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n content: \" \";\n right: 1px;\n border-right-width: 0;\n border-left-color: #ffffff;\n bottom: -10px;\n}\n.carousel {\n position: relative;\n}\n.carousel-inner {\n position: relative;\n overflow: hidden;\n width: 100%;\n}\n.carousel-inner > .item {\n display: none;\n position: relative;\n -webkit-transition: 0.6s ease-in-out left;\n -o-transition: 0.6s ease-in-out left;\n transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n .carousel-inner > .item {\n -webkit-transition: -webkit-transform 0.6s ease-in-out;\n -moz-transition: -moz-transform 0.6s ease-in-out;\n -o-transition: -o-transform 0.6s ease-in-out;\n transition: transform 0.6s ease-in-out;\n -webkit-backface-visibility: hidden;\n -moz-backface-visibility: hidden;\n backface-visibility: hidden;\n -webkit-perspective: 1000px;\n -moz-perspective: 1000px;\n perspective: 1000px;\n }\n .carousel-inner > .item.next,\n .carousel-inner > .item.active.right {\n -webkit-transform: translate3d(100%, 0, 0);\n transform: translate3d(100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.prev,\n .carousel-inner > .item.active.left {\n -webkit-transform: translate3d(-100%, 0, 0);\n transform: translate3d(-100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.next.left,\n .carousel-inner > .item.prev.right,\n .carousel-inner > .item.active {\n -webkit-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n left: 0;\n }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n display: block;\n}\n.carousel-inner > .active {\n left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n}\n.carousel-inner > .next {\n left: 100%;\n}\n.carousel-inner > .prev {\n left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n left: 0;\n}\n.carousel-inner > .active.left {\n left: -100%;\n}\n.carousel-inner > .active.right {\n left: 100%;\n}\n.carousel-control {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n width: 15%;\n opacity: 0.5;\n filter: alpha(opacity=50);\n font-size: 20px;\n color: #ffffff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-control.left {\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n.carousel-control.right {\n left: auto;\n right: 0;\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n.carousel-control:hover,\n.carousel-control:focus {\n outline: 0;\n color: #ffffff;\n text-decoration: none;\n opacity: 0.9;\n filter: alpha(opacity=90);\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n margin-top: -10px;\n z-index: 5;\n display: inline-block;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n width: 20px;\n height: 20px;\n line-height: 1;\n font-family: serif;\n}\n.carousel-control .icon-prev:before {\n content: '\\2039';\n}\n.carousel-control .icon-next:before {\n content: '\\203a';\n}\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n margin-left: -30%;\n padding-left: 0;\n list-style: none;\n text-align: center;\n}\n.carousel-indicators li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n border: 1px solid #ffffff;\n border-radius: 10px;\n cursor: pointer;\n background-color: #000 \\9;\n background-color: rgba(0, 0, 0, 0);\n}\n.carousel-indicators .active {\n margin: 0;\n width: 12px;\n height: 12px;\n background-color: #ffffff;\n}\n.carousel-caption {\n position: absolute;\n left: 15%;\n right: 15%;\n bottom: 20px;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #ffffff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-prev,\n .carousel-control .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -15px;\n font-size: 30px;\n }\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .icon-prev {\n margin-left: -15px;\n }\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-next {\n margin-right: -15px;\n }\n .carousel-caption {\n left: 20%;\n right: 20%;\n padding-bottom: 30px;\n }\n .carousel-indicators {\n bottom: 20px;\n }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-footer:before,\n.modal-footer:after {\n content: \" \";\n display: table;\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-footer:after {\n clear: both;\n}\n.center-block {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n.hidden {\n display: none !important;\n}\n.affix {\n position: fixed;\n}\n@-ms-viewport {\n width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n@media (max-width: 767px) {\n .visible-xs {\n display: block !important;\n }\n table.visible-xs {\n display: table !important;\n }\n tr.visible-xs {\n display: table-row !important;\n }\n th.visible-xs,\n td.visible-xs {\n display: table-cell !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-block {\n display: block !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline {\n display: inline !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm {\n display: block !important;\n }\n table.visible-sm {\n display: table !important;\n }\n tr.visible-sm {\n display: table-row !important;\n }\n th.visible-sm,\n td.visible-sm {\n display: table-cell !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-block {\n display: block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline {\n display: inline !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md {\n display: block !important;\n }\n table.visible-md {\n display: table !important;\n }\n tr.visible-md {\n display: table-row !important;\n }\n th.visible-md,\n td.visible-md {\n display: table-cell !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-block {\n display: block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline {\n display: inline !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg {\n display: block !important;\n }\n table.visible-lg {\n display: table !important;\n }\n tr.visible-lg {\n display: table-row !important;\n }\n th.visible-lg,\n td.visible-lg {\n display: table-cell !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-block {\n display: block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline {\n display: inline !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline-block {\n display: inline-block !important;\n }\n}\n@media (max-width: 767px) {\n .hidden-xs {\n display: none !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .hidden-sm {\n display: none !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .hidden-md {\n display: none !important;\n }\n}\n@media (min-width: 1200px) {\n .hidden-lg {\n display: none !important;\n }\n}\n.visible-print {\n display: none !important;\n}\n@media print {\n .visible-print {\n display: block !important;\n }\n table.visible-print {\n display: table !important;\n }\n tr.visible-print {\n display: table-row !important;\n }\n th.visible-print,\n td.visible-print {\n display: table-cell !important;\n }\n}\n.visible-print-block {\n display: none !important;\n}\n@media print {\n .visible-print-block {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n}\n@media print {\n .visible-print-inline {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n}\n@media print {\n .visible-print-inline-block {\n display: inline-block !important;\n }\n}\n@media print {\n .hidden-print {\n display: none !important;\n }\n}\n/*# sourceMappingURL=bootstrap.css.map */","/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS and IE text size adjust after device orientation change,\n// without disabling user zoom.\n//\n\nhtml {\n font-family: sans-serif; // 1\n -ms-text-size-adjust: 100%; // 2\n -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined for any HTML5 element in IE 8/9.\n// Correct `block` display not defined for `details` or `summary` in IE 10/11\n// and Firefox.\n// Correct `block` display not defined for `main` in IE 11.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block; // 1\n vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9/10.\n// Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n background-color: transparent;\n}\n\n//\n// Improve readability of focused elements when they are also in an\n// active/hover state.\n//\n\na:active,\na:hover {\n outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n//\n\nabbr[title] {\n border-bottom: 1px dotted;\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n//\n\nb,\nstrong {\n font-weight: bold;\n}\n\n//\n// Address styling not present in Safari and Chrome.\n//\n\ndfn {\n font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari, and Chrome.\n//\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n background: #ff0;\n color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsup {\n top: -0.5em;\n}\n\nsub {\n bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9/10.\n//\n\nimg {\n border: 0;\n}\n\n//\n// Correct overflow not hidden in IE 9/10/11.\n//\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari.\n//\n\nfigure {\n margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n box-sizing: content-box;\n height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n// Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit; // 1\n font: inherit; // 2\n margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10/11.\n//\n\nbutton {\n overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n// and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n// `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button; // 2\n cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box; // 1\n padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n//\n\ninput[type=\"search\"] {\n -webkit-appearance: textfield; // 1\n box-sizing: content-box; //2\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9/10/11.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n border: 0; // 1\n padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9/10/11.\n//\n\ntextarea {\n overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\n\ntd,\nth {\n padding: 0;\n}\n","/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n\n// ==========================================================================\n// Print styles.\n// Inlined to avoid the additional HTTP request: h5bp.com/r\n// ==========================================================================\n\n@media print {\n *,\n *:before,\n *:after {\n background: transparent !important;\n color: #000 !important; // Black prints faster: h5bp.com/s\n box-shadow: none !important;\n text-shadow: none !important;\n }\n\n a,\n a:visited {\n text-decoration: underline;\n }\n\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n\n // Don't show links that are fragment identifiers,\n // or use the `javascript:` pseudo protocol\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n\n thead {\n display: table-header-group; // h5bp.com/t\n }\n\n tr,\n img {\n page-break-inside: avoid;\n }\n\n img {\n max-width: 100% !important;\n }\n\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n\n h2,\n h3 {\n page-break-after: avoid;\n }\n\n // Bootstrap specific changes start\n\n // Bootstrap components\n .navbar {\n display: none;\n }\n .btn,\n .dropup > .btn {\n > .caret {\n border-top-color: #000 !important;\n }\n }\n .label {\n border: 1px solid #000;\n }\n\n .table {\n border-collapse: collapse !important;\n\n td,\n th {\n background-color: #fff !important;\n }\n }\n .table-bordered {\n th,\n td {\n border: 1px solid #ddd !important;\n }\n }\n\n // Bootstrap specific changes end\n}\n","//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// <a href=\"#\"><span class=\"glyphicon glyphicon-star\"></span> Star</a>\n\n// Import the fonts\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: url('@{icon-font-path}@{icon-font-name}.eot');\n src: url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype'),\n url('@{icon-font-path}@{icon-font-name}.woff2') format('woff2'),\n url('@{icon-font-path}@{icon-font-name}.woff') format('woff'),\n url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype'),\n url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg');\n}\n\n// Catchall baseclass\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk { &:before { content: \"\\2a\"; } }\n.glyphicon-plus { &:before { content: \"\\2b\"; } }\n.glyphicon-euro,\n.glyphicon-eur { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil { &:before { content: \"\\270f\"; } }\n.glyphicon-glass { &:before { content: \"\\e001\"; } }\n.glyphicon-music { &:before { content: \"\\e002\"; } }\n.glyphicon-search { &:before { content: \"\\e003\"; } }\n.glyphicon-heart { &:before { content: \"\\e005\"; } }\n.glyphicon-star { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty { &:before { content: \"\\e007\"; } }\n.glyphicon-user { &:before { content: \"\\e008\"; } }\n.glyphicon-film { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large { &:before { content: \"\\e010\"; } }\n.glyphicon-th { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list { &:before { content: \"\\e012\"; } }\n.glyphicon-ok { &:before { content: \"\\e013\"; } }\n.glyphicon-remove { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out { &:before { content: \"\\e016\"; } }\n.glyphicon-off { &:before { content: \"\\e017\"; } }\n.glyphicon-signal { &:before { content: \"\\e018\"; } }\n.glyphicon-cog { &:before { content: \"\\e019\"; } }\n.glyphicon-trash { &:before { content: \"\\e020\"; } }\n.glyphicon-home { &:before { content: \"\\e021\"; } }\n.glyphicon-file { &:before { content: \"\\e022\"; } }\n.glyphicon-time { &:before { content: \"\\e023\"; } }\n.glyphicon-road { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt { &:before { content: \"\\e025\"; } }\n.glyphicon-download { &:before { content: \"\\e026\"; } }\n.glyphicon-upload { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt { &:before { content: \"\\e032\"; } }\n.glyphicon-lock { &:before { content: \"\\e033\"; } }\n.glyphicon-flag { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode { &:before { content: \"\\e040\"; } }\n.glyphicon-tag { &:before { content: \"\\e041\"; } }\n.glyphicon-tags { &:before { content: \"\\e042\"; } }\n.glyphicon-book { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark { &:before { content: \"\\e044\"; } }\n.glyphicon-print { &:before { content: \"\\e045\"; } }\n.glyphicon-camera { &:before { content: \"\\e046\"; } }\n.glyphicon-font { &:before { content: \"\\e047\"; } }\n.glyphicon-bold { &:before { content: \"\\e048\"; } }\n.glyphicon-italic { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify { &:before { content: \"\\e055\"; } }\n.glyphicon-list { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video { &:before { content: \"\\e059\"; } }\n.glyphicon-picture { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust { &:before { content: \"\\e063\"; } }\n.glyphicon-tint { &:before { content: \"\\e064\"; } }\n.glyphicon-edit { &:before { content: \"\\e065\"; } }\n.glyphicon-share { &:before { content: \"\\e066\"; } }\n.glyphicon-check { &:before { content: \"\\e067\"; } }\n.glyphicon-move { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward { &:before { content: \"\\e070\"; } }\n.glyphicon-backward { &:before { content: \"\\e071\"; } }\n.glyphicon-play { &:before { content: \"\\e072\"; } }\n.glyphicon-pause { &:before { content: \"\\e073\"; } }\n.glyphicon-stop { &:before { content: \"\\e074\"; } }\n.glyphicon-forward { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward { &:before { content: \"\\e077\"; } }\n.glyphicon-eject { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign { &:before { content: \"\\e101\"; } }\n.glyphicon-gift { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf { &:before { content: \"\\e103\"; } }\n.glyphicon-fire { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign { &:before { content: \"\\e107\"; } }\n.glyphicon-plane { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar { &:before { content: \"\\e109\"; } }\n.glyphicon-random { &:before { content: \"\\e110\"; } }\n.glyphicon-comment { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn { &:before { content: \"\\e122\"; } }\n.glyphicon-bell { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down { &:before { content: \"\\e134\"; } }\n.glyphicon-globe { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks { &:before { content: \"\\e137\"; } }\n.glyphicon-filter { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty { &:before { content: \"\\e143\"; } }\n.glyphicon-link { &:before { content: \"\\e144\"; } }\n.glyphicon-phone { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin { &:before { content: \"\\e146\"; } }\n.glyphicon-usd { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp { &:before { content: \"\\e149\"; } }\n.glyphicon-sort { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked { &:before { content: \"\\e157\"; } }\n.glyphicon-expand { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in { &:before { content: \"\\e161\"; } }\n.glyphicon-flash { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window { &:before { content: \"\\e164\"; } }\n.glyphicon-record { &:before { content: \"\\e165\"; } }\n.glyphicon-save { &:before { content: \"\\e166\"; } }\n.glyphicon-open { &:before { content: \"\\e167\"; } }\n.glyphicon-saved { &:before { content: \"\\e168\"; } }\n.glyphicon-import { &:before { content: \"\\e169\"; } }\n.glyphicon-export { &:before { content: \"\\e170\"; } }\n.glyphicon-send { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery { &:before { content: \"\\e179\"; } }\n.glyphicon-header { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt { &:before { content: \"\\e183\"; } }\n.glyphicon-tower { &:before { content: \"\\e184\"; } }\n.glyphicon-stats { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1 { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1 { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1 { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous { &:before { content: \"\\e200\"; } }\n.glyphicon-cd { &:before { content: \"\\e201\"; } }\n.glyphicon-save-file { &:before { content: \"\\e202\"; } }\n.glyphicon-open-file { &:before { content: \"\\e203\"; } }\n.glyphicon-level-up { &:before { content: \"\\e204\"; } }\n.glyphicon-copy { &:before { content: \"\\e205\"; } }\n.glyphicon-paste { &:before { content: \"\\e206\"; } }\n// The following 2 Glyphicons are omitted for the time being because\n// they currently use Unicode codepoints that are outside the\n// Basic Multilingual Plane (BMP). Older buggy versions of WebKit can't handle\n// non-BMP codepoints in CSS string escapes, and thus can't display these two icons.\n// Notably, the bug affects some older versions of the Android Browser.\n// More info: https://github.com/twbs/bootstrap/issues/10106\n// .glyphicon-door { &:before { content: \"\\1f6aa\"; } }\n// .glyphicon-key { &:before { content: \"\\1f511\"; } }\n.glyphicon-alert { &:before { content: \"\\e209\"; } }\n.glyphicon-equalizer { &:before { content: \"\\e210\"; } }\n.glyphicon-king { &:before { content: \"\\e211\"; } }\n.glyphicon-queen { &:before { content: \"\\e212\"; } }\n.glyphicon-pawn { &:before { content: \"\\e213\"; } }\n.glyphicon-bishop { &:before { content: \"\\e214\"; } }\n.glyphicon-knight { &:before { content: \"\\e215\"; } }\n.glyphicon-baby-formula { &:before { content: \"\\e216\"; } }\n.glyphicon-tent { &:before { content: \"\\26fa\"; } }\n.glyphicon-blackboard { &:before { content: \"\\e218\"; } }\n.glyphicon-bed { &:before { content: \"\\e219\"; } }\n.glyphicon-apple { &:before { content: \"\\f8ff\"; } }\n.glyphicon-erase { &:before { content: \"\\e221\"; } }\n.glyphicon-hourglass { &:before { content: \"\\231b\"; } }\n.glyphicon-lamp { &:before { content: \"\\e223\"; } }\n.glyphicon-duplicate { &:before { content: \"\\e224\"; } }\n.glyphicon-piggy-bank { &:before { content: \"\\e225\"; } }\n.glyphicon-scissors { &:before { content: \"\\e226\"; } }\n.glyphicon-bitcoin { &:before { content: \"\\e227\"; } }\n.glyphicon-btc { &:before { content: \"\\e227\"; } }\n.glyphicon-xbt { &:before { content: \"\\e227\"; } }\n.glyphicon-yen { &:before { content: \"\\00a5\"; } }\n.glyphicon-jpy { &:before { content: \"\\00a5\"; } }\n.glyphicon-ruble { &:before { content: \"\\20bd\"; } }\n.glyphicon-rub { &:before { content: \"\\20bd\"; } }\n.glyphicon-scale { &:before { content: \"\\e230\"; } }\n.glyphicon-ice-lolly { &:before { content: \"\\e231\"; } }\n.glyphicon-ice-lolly-tasted { &:before { content: \"\\e232\"; } }\n.glyphicon-education { &:before { content: \"\\e233\"; } }\n.glyphicon-option-horizontal { &:before { content: \"\\e234\"; } }\n.glyphicon-option-vertical { &:before { content: \"\\e235\"; } }\n.glyphicon-menu-hamburger { &:before { content: \"\\e236\"; } }\n.glyphicon-modal-window { &:before { content: \"\\e237\"; } }\n.glyphicon-oil { &:before { content: \"\\e238\"; } }\n.glyphicon-grain { &:before { content: \"\\e239\"; } }\n.glyphicon-sunglasses { &:before { content: \"\\e240\"; } }\n.glyphicon-text-size { &:before { content: \"\\e241\"; } }\n.glyphicon-text-color { &:before { content: \"\\e242\"; } }\n.glyphicon-text-background { &:before { content: \"\\e243\"; } }\n.glyphicon-object-align-top { &:before { content: \"\\e244\"; } }\n.glyphicon-object-align-bottom { &:before { content: \"\\e245\"; } }\n.glyphicon-object-align-horizontal{ &:before { content: \"\\e246\"; } }\n.glyphicon-object-align-left { &:before { content: \"\\e247\"; } }\n.glyphicon-object-align-vertical { &:before { content: \"\\e248\"; } }\n.glyphicon-object-align-right { &:before { content: \"\\e249\"; } }\n.glyphicon-triangle-right { &:before { content: \"\\e250\"; } }\n.glyphicon-triangle-left { &:before { content: \"\\e251\"; } }\n.glyphicon-triangle-bottom { &:before { content: \"\\e252\"; } }\n.glyphicon-triangle-top { &:before { content: \"\\e253\"; } }\n.glyphicon-console { &:before { content: \"\\e254\"; } }\n.glyphicon-superscript { &:before { content: \"\\e255\"; } }\n.glyphicon-subscript { &:before { content: \"\\e256\"; } }\n.glyphicon-menu-left { &:before { content: \"\\e257\"; } }\n.glyphicon-menu-right { &:before { content: \"\\e258\"; } }\n.glyphicon-menu-down { &:before { content: \"\\e259\"; } }\n.glyphicon-menu-up { &:before { content: \"\\e260\"; } }\n","//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// http://getbootstrap.com/getting-started/#third-box-sizing\n* {\n .box-sizing(border-box);\n}\n*:before,\n*:after {\n .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n\nbody {\n font-family: @font-family-base;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @text-color;\n background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\n\n// Links\n\na {\n color: @link-color;\n text-decoration: none;\n\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n }\n\n &:focus {\n .tab-focus();\n }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n margin: 0;\n}\n\n\n// Images\n\nimg {\n vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n padding: @thumbnail-padding;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(all .2s ease-in-out);\n\n // Keep them at most 100% wide\n .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n margin-top: @line-height-computed;\n margin-bottom: @line-height-computed;\n border: 0;\n border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: http://a11yproject.com/posts/how-to-hide-content/\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0,0,0,0);\n border: 0;\n}\n\n// Use in conjunction with .sr-only to only display content when it's focused.\n// Useful for \"Skip to main content\" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\n// Credit: HTML5 Boilerplate\n\n.sr-only-focusable {\n &:active,\n &:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n }\n}\n\n\n// iOS \"clickable elements\" fix for role=\"button\"\n//\n// Fixes \"clickability\" issue (and more generally, the firing of events such as focus as well)\n// for traditionally non-focusable elements with role=\"button\"\n// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n\n[role=\"button\"] {\n cursor: pointer;\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// WebKit-style focus\n\n.tab-focus() {\n // Default\n outline: thin dotted;\n // WebKit\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n","// Image Mixins\n// - Responsive image\n// - Retina image\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// Retina image\n//\n// Short retina mixin for setting background-image and -size. Note that the\n// spelling of `min--moz-device-pixel-ratio` is intentional.\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n","//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n font-family: @headings-font-family;\n font-weight: @headings-font-weight;\n line-height: @headings-line-height;\n color: @headings-color;\n\n small,\n .small {\n font-weight: normal;\n line-height: 1;\n color: @headings-small-color;\n }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n margin-top: @line-height-computed;\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 65%;\n }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n margin-top: (@line-height-computed / 2);\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 75%;\n }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n margin-bottom: @line-height-computed;\n font-size: floor((@font-size-base * 1.15));\n font-weight: 300;\n line-height: 1.4;\n\n @media (min-width: @screen-sm-min) {\n font-size: (@font-size-base * 1.5);\n }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: (12px small font / 14px base font) * 100% = about 85%\nsmall,\n.small {\n font-size: floor((100% * @font-size-small / @font-size-base));\n}\n\nmark,\n.mark {\n background-color: @state-warning-bg;\n padding: .2em;\n}\n\n// Alignment\n.text-left { text-align: left; }\n.text-right { text-align: right; }\n.text-center { text-align: center; }\n.text-justify { text-align: justify; }\n.text-nowrap { white-space: nowrap; }\n\n// Transformation\n.text-lowercase { text-transform: lowercase; }\n.text-uppercase { text-transform: uppercase; }\n.text-capitalize { text-transform: capitalize; }\n\n// Contextual colors\n.text-muted {\n color: @text-muted;\n}\n.text-primary {\n .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n // Given the contrast here, this is the only class to have its color inverted\n // automatically.\n color: #fff;\n .bg-variant(@brand-primary);\n}\n.bg-success {\n .bg-variant(@state-success-bg);\n}\n.bg-info {\n .bg-variant(@state-info-bg);\n}\n.bg-warning {\n .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n padding-bottom: ((@line-height-computed / 2) - 1);\n margin: (@line-height-computed * 2) 0 @line-height-computed;\n border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// -------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n margin-top: 0;\n margin-bottom: (@line-height-computed / 2);\n ul,\n ol {\n margin-bottom: 0;\n }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n .list-unstyled();\n margin-left: -5px;\n\n > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n }\n}\n\n// Description Lists\ndl {\n margin-top: 0; // Remove browser default\n margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n line-height: @line-height-base;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n.dl-horizontal {\n dd {\n &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n }\n\n @media (min-width: @grid-float-breakpoint) {\n dt {\n float: left;\n width: (@dl-horizontal-offset - 20);\n clear: left;\n text-align: right;\n .text-overflow();\n }\n dd {\n margin-left: @dl-horizontal-offset;\n }\n }\n}\n\n\n// Misc\n// -------------------------\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n font-size: 90%;\n .text-uppercase();\n}\n\n// Blockquotes\nblockquote {\n padding: (@line-height-computed / 2) @line-height-computed;\n margin: 0 0 @line-height-computed;\n font-size: @blockquote-font-size;\n border-left: 5px solid @blockquote-border-color;\n\n p,\n ul,\n ol {\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n // Note: Deprecated small and .small as of v3.1.0\n // Context: https://github.com/twbs/bootstrap/issues/11660\n footer,\n small,\n .small {\n display: block;\n font-size: 80%; // back to default font-size\n line-height: @line-height-base;\n color: @blockquote-small-color;\n\n &:before {\n content: '\\2014 \\00A0'; // em dash, nbsp\n }\n }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid @blockquote-border-color;\n border-left: 0;\n text-align: right;\n\n // Account for citation\n footer,\n small,\n .small {\n &:before { content: ''; }\n &:after {\n content: '\\00A0 \\2014'; // nbsp, em dash\n }\n }\n}\n\n// Addresses\naddress {\n margin-bottom: @line-height-computed;\n font-style: normal;\n line-height: @line-height-base;\n}\n","// Typography\n\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover,\n a&:focus {\n color: darken(@color, 10%);\n }\n}\n","// Contextual backgrounds\n\n.bg-variant(@color) {\n background-color: @color;\n a&:hover,\n a&:focus {\n background-color: darken(@color, 10%);\n }\n}\n","// Text overflow\n// Requires inline-block or block for proper styling\n\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: @code-color;\n background-color: @code-bg;\n border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: @kbd-color;\n background-color: @kbd-bg;\n border-radius: @border-radius-small;\n box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n\n kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n box-shadow: none;\n }\n}\n\n// Blocks of code\npre {\n display: block;\n padding: ((@line-height-computed - 1) / 2);\n margin: 0 0 (@line-height-computed / 2);\n font-size: (@font-size-base - 1); // 14px to 13px\n line-height: @line-height-base;\n word-break: break-all;\n word-wrap: break-word;\n color: @pre-color;\n background-color: @pre-bg;\n border: 1px solid @pre-border-color;\n border-radius: @border-radius-base;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n max-height: @pre-scrollable-max-height;\n overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n .container-fixed();\n\n @media (min-width: @screen-sm-min) {\n width: @container-sm;\n }\n @media (min-width: @screen-md-min) {\n width: @container-md;\n }\n @media (min-width: @screen-lg-min) {\n width: @container-lg;\n }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n .make-grid(lg);\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n// Centered container element\n.container-fixed(@gutter: @grid-gutter-width) {\n margin-right: auto;\n margin-left: auto;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-left: ceil((@gutter / -2));\n margin-right: floor((@gutter / -2));\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n margin-left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-push(@columns) {\n left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-pull(@columns) {\n right: percentage((@columns / @grid-columns));\n}\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n","// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-left: ceil((@grid-gutter-width / 2));\n padding-right: floor((@grid-gutter-width / 2));\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) {\n .col-@{class}-push-0 {\n left: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) {\n .col-@{class}-pull-0 {\n right: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n","//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n background-color: @table-bg;\n}\ncaption {\n padding-top: @table-cell-padding;\n padding-bottom: @table-cell-padding;\n color: @text-muted;\n text-align: left;\n}\nth {\n text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: @line-height-computed;\n // Cells\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-cell-padding;\n line-height: @line-height-base;\n vertical-align: top;\n border-top: 1px solid @table-border-color;\n }\n }\n }\n // Bottom align for column headings\n > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid @table-border-color;\n }\n // Remove top border from thead by default\n > caption + thead,\n > colgroup + thead,\n > thead:first-child {\n > tr:first-child {\n > th,\n > td {\n border-top: 0;\n }\n }\n }\n // Account for multiple tbody instances\n > tbody + tbody {\n border-top: 2px solid @table-border-color;\n }\n\n // Nesting\n .table {\n background-color: @body-bg;\n }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-condensed-cell-padding;\n }\n }\n }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n border: 1px solid @table-border-color;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n border: 1px solid @table-border-color;\n }\n }\n }\n > thead > tr {\n > th,\n > td {\n border-bottom-width: 2px;\n }\n }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n > tbody > tr:nth-of-type(odd) {\n background-color: @table-bg-accent;\n }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n > tbody > tr:hover {\n background-color: @table-bg-hover;\n }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-column;\n}\ntable {\n td,\n th {\n &[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-cell;\n }\n }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n.table-responsive {\n overflow-x: auto;\n min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)\n\n @media screen and (max-width: @screen-xs-max) {\n width: 100%;\n margin-bottom: (@line-height-computed * 0.75);\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid @table-border-color;\n\n // Tighten up spacing\n > .table {\n margin-bottom: 0;\n\n // Ensure the content doesn't wrap\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n white-space: nowrap;\n }\n }\n }\n }\n\n // Special overrides for the bordered tables\n > .table-bordered {\n border: 0;\n\n // Nuke the appropriate borders so that the parent can handle them\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n\n // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n // chances are there will be only one `tr` in a `thead` and that would\n // remove the border altogether.\n > tbody,\n > tfoot {\n > tr:last-child {\n > th,\n > td {\n border-bottom: 0;\n }\n }\n }\n\n }\n }\n}\n","// Tables\n\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &:hover > .@{state},\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n","//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n // Chrome and Firefox set a `min-width: min-content;` on fieldsets,\n // so we reset that to ensure it behaves more like a standard block element.\n // See https://github.com/twbs/bootstrap/issues/12359.\n min-width: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: @line-height-computed;\n font-size: (@font-size-base * 1.5);\n line-height: inherit;\n color: @legend-color;\n border: 0;\n border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n display: inline-block;\n max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)\n margin-bottom: 5px;\n font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9; // IE8-9\n line-height: normal;\n}\n\ninput[type=\"file\"] {\n display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n .tab-focus();\n}\n\n// Adjust output element\noutput {\n display: block;\n padding-top: (@padding-base-vertical + 1);\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n display: block;\n width: 100%;\n height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n background-color: @input-bg;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid @input-border;\n border-radius: @input-border-radius; // Note: This has no effect on <select>s in some browsers, due to the limited stylability of <select>s in CSS.\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n // Customize the `:focus` state to imitate native WebKit styles.\n .form-control-focus();\n\n // Placeholder\n .placeholder();\n\n // Disabled and read-only inputs\n //\n // HTML5 says that controls under a fieldset > legend:first-child won't be\n // disabled if the fieldset is disabled. Due to implementation difficulty, we\n // don't honor that edge case; we style them as disabled anyway.\n &[disabled],\n &[readonly],\n fieldset[disabled] & {\n background-color: @input-bg-disabled;\n opacity: 1; // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655\n }\n\n &[disabled],\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n }\n\n // Reset height for `textarea`s\n textarea& {\n height: auto;\n }\n}\n\n\n// Search inputs in iOS\n//\n// This overrides the extra rounded corners on search inputs in iOS so that our\n// `.form-control` class can properly style them. Note that this cannot simply\n// be added to `.form-control` as it's not specific enough. For details, see\n// https://github.com/twbs/bootstrap/issues/11586.\n\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\n\n\n// Special styles for iOS temporal inputs\n//\n// In Mobile Safari, setting `display: block` on temporal inputs causes the\n// text within the input to become vertically misaligned. As a workaround, we\n// set a pixel line-height that matches the given height of the input, but only\n// for Safari. See https://bugs.webkit.org/show_bug.cgi?id=139848\n//\n// Note that as of 8.3, iOS doesn't support `datetime` or `week`.\n\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"],\n input[type=\"time\"],\n input[type=\"datetime-local\"],\n input[type=\"month\"] {\n &.form-control {\n line-height: @input-height-base;\n }\n\n &.input-sm,\n .input-group-sm & {\n line-height: @input-height-small;\n }\n\n &.input-lg,\n .input-group-lg & {\n line-height: @input-height-large;\n }\n }\n}\n\n\n// Form groups\n//\n// Designed to help with the organization and spacing of vertical forms. For\n// horizontal forms, use the predefined grid classes.\n\n.form-group {\n margin-bottom: @form-group-margin-bottom;\n}\n\n\n// Checkboxes and radios\n//\n// Indent the labels to position radios/checkboxes as hanging controls.\n\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n\n label {\n min-height: @line-height-computed; // Ensure the input doesn't jump when there is no text\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: normal;\n cursor: pointer;\n }\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-left: -20px;\n margin-top: 4px \\9;\n}\n\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing\n}\n\n// Radios and checkboxes on same line\n.radio-inline,\n.checkbox-inline {\n position: relative;\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n vertical-align: middle;\n font-weight: normal;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px; // space out consecutive inline controls\n}\n\n// Apply same disabled cursor tweak as for inputs\n// Some special care is needed because <label>s don't inherit their parent's `cursor`.\n//\n// Note: Neither radios nor checkboxes can be readonly.\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n &[disabled],\n &.disabled,\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n }\n}\n// These classes are used directly on <label>s\n.radio-inline,\n.checkbox-inline {\n &.disabled,\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n }\n}\n// These classes are used on elements with <label> descendants\n.radio,\n.checkbox {\n &.disabled,\n fieldset[disabled] & {\n label {\n cursor: @cursor-disabled;\n }\n }\n}\n\n\n// Static form control text\n//\n// Apply class to a `p` element to make any string of text align with labels in\n// a horizontal form layout.\n\n.form-control-static {\n // Size it appropriately next to real form controls\n padding-top: (@padding-base-vertical + 1);\n padding-bottom: (@padding-base-vertical + 1);\n // Remove default margin from `p`\n margin-bottom: 0;\n min-height: (@line-height-computed + @font-size-base);\n\n &.input-lg,\n &.input-sm {\n padding-left: 0;\n padding-right: 0;\n }\n}\n\n\n// Form control sizing\n//\n// Build on `.form-control` with modifier classes to decrease or increase the\n// height and font-size of form controls.\n//\n// The `.form-group-* form-control` variations are sadly duplicated to avoid the\n// issue documented in https://github.com/twbs/bootstrap/issues/15074.\n\n.input-sm {\n .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @input-border-radius-small);\n}\n.form-group-sm {\n .form-control {\n height: @input-height-small;\n padding: @padding-small-vertical @padding-small-horizontal;\n font-size: @font-size-small;\n line-height: @line-height-small;\n border-radius: @input-border-radius-small;\n }\n select.form-control {\n height: @input-height-small;\n line-height: @input-height-small;\n }\n textarea.form-control,\n select[multiple].form-control {\n height: auto;\n }\n .form-control-static {\n height: @input-height-small;\n min-height: (@line-height-computed + @font-size-small);\n padding: (@padding-small-vertical + 1) @padding-small-horizontal;\n font-size: @font-size-small;\n line-height: @line-height-small;\n }\n}\n\n.input-lg {\n .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @input-border-radius-large);\n}\n.form-group-lg {\n .form-control {\n height: @input-height-large;\n padding: @padding-large-vertical @padding-large-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-large;\n border-radius: @input-border-radius-large;\n }\n select.form-control {\n height: @input-height-large;\n line-height: @input-height-large;\n }\n textarea.form-control,\n select[multiple].form-control {\n height: auto;\n }\n .form-control-static {\n height: @input-height-large;\n min-height: (@line-height-computed + @font-size-large);\n padding: (@padding-large-vertical + 1) @padding-large-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-large;\n }\n}\n\n\n// Form control feedback states\n//\n// Apply contextual and semantic states to individual form controls.\n\n.has-feedback {\n // Enable absolute positioning\n position: relative;\n\n // Ensure icons don't overlap text\n .form-control {\n padding-right: (@input-height-base * 1.25);\n }\n}\n// Feedback icon (requires .glyphicon classes)\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2; // Ensure icon is above input groups\n display: block;\n width: @input-height-base;\n height: @input-height-base;\n line-height: @input-height-base;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n width: @input-height-large;\n height: @input-height-large;\n line-height: @input-height-large;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n width: @input-height-small;\n height: @input-height-small;\n line-height: @input-height-small;\n}\n\n// Feedback states\n.has-success {\n .form-control-validation(@state-success-text; @state-success-text; @state-success-bg);\n}\n.has-warning {\n .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg);\n}\n.has-error {\n .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);\n}\n\n// Reposition feedback icon if input has visible label above\n.has-feedback label {\n\n & ~ .form-control-feedback {\n top: (@line-height-computed + 5); // Height of the `label` and its margin\n }\n &.sr-only ~ .form-control-feedback {\n top: 0;\n }\n}\n\n\n// Help text\n//\n// Apply to any element you wish to create light text for placement immediately\n// below a form control. Use for general help, formatting, or instructional text.\n\n.help-block {\n display: block; // account for any element using help-block\n margin-top: 5px;\n margin-bottom: 10px;\n color: lighten(@text-color, 25%); // lighten the text some for contrast\n}\n\n\n// Inline forms\n//\n// Make forms appear inline(-block) by adding the `.form-inline` class. Inline\n// forms begin stacked on extra small (mobile) devices and then go inline when\n// viewports reach <768px.\n//\n// Requires wrapping inputs and labels with `.form-group` for proper display of\n// default HTML form controls and our custom form controls (e.g., input groups).\n//\n// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.\n\n.form-inline {\n\n // Kick in the inline\n @media (min-width: @screen-sm-min) {\n // Inline-block all the things for \"inline\"\n .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n\n // In navbar-form, allow folks to *not* use `.form-group`\n .form-control {\n display: inline-block;\n width: auto; // Prevent labels from stacking above inputs in `.form-group`\n vertical-align: middle;\n }\n\n // Make static controls behave like regular ones\n .form-control-static {\n display: inline-block;\n }\n\n .input-group {\n display: inline-table;\n vertical-align: middle;\n\n .input-group-addon,\n .input-group-btn,\n .form-control {\n width: auto;\n }\n }\n\n // Input groups need that 100% width though\n .input-group > .form-control {\n width: 100%;\n }\n\n .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n\n // Remove default margin on radios/checkboxes that were used for stacking, and\n // then undo the floating of radios and checkboxes to match.\n .radio,\n .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n\n label {\n padding-left: 0;\n }\n }\n .radio input[type=\"radio\"],\n .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n\n // Re-override the feedback icon.\n .has-feedback .form-control-feedback {\n top: 0;\n }\n }\n}\n\n\n// Horizontal forms\n//\n// Horizontal forms are built on grid classes and allow you to create forms with\n// labels on the left and inputs on the right.\n\n.form-horizontal {\n\n // Consistent vertical alignment of radios and checkboxes\n //\n // Labels also get some reset styles, but that is scoped to a media query below.\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline {\n margin-top: 0;\n margin-bottom: 0;\n padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n }\n // Account for padding we're adding to ensure the alignment and of help text\n // and other content below items\n .radio,\n .checkbox {\n min-height: (@line-height-computed + (@padding-base-vertical + 1));\n }\n\n // Make form groups behave like rows\n .form-group {\n .make-row();\n }\n\n // Reset spacing and right align labels, but scope to media queries so that\n // labels on narrow viewports stack the same as a default form example.\n @media (min-width: @screen-sm-min) {\n .control-label {\n text-align: right;\n margin-bottom: 0;\n padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n }\n }\n\n // Validation states\n //\n // Reposition the icon because it's now within a grid column and columns have\n // `position: relative;` on them. Also accounts for the grid gutter padding.\n .has-feedback .form-control-feedback {\n right: floor((@grid-gutter-width / 2));\n }\n\n // Form group sizes\n //\n // Quick utility class for applying `.input-lg` and `.input-sm` styles to the\n // inputs and labels within a `.form-group`.\n .form-group-lg {\n @media (min-width: @screen-sm-min) {\n .control-label {\n padding-top: ((@padding-large-vertical * @line-height-large) + 1);\n font-size: @font-size-large;\n }\n }\n }\n .form-group-sm {\n @media (min-width: @screen-sm-min) {\n .control-label {\n padding-top: (@padding-small-vertical + 1);\n font-size: @font-size-small;\n }\n }\n }\n}\n","// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n // Color the label and help text\n .help-block,\n .control-label,\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline,\n &.radio label,\n &.checkbox label,\n &.radio-inline label,\n &.checkbox-inline label {\n color: @text-color;\n }\n // Set the border and box shadow on specific inputs to match\n .form-control {\n border-color: @border-color;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n &:focus {\n border-color: darken(@border-color, 10%);\n @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n .box-shadow(@shadow);\n }\n }\n // Set validation states also for addons\n .input-group-addon {\n color: @text-color;\n border-color: @border-color;\n background-color: @background-color;\n }\n // Optional feedback icon\n .form-control-feedback {\n color: @text-color;\n }\n}\n\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-border-focus` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n.form-control-focus(@color: @input-border-focus) {\n @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n &:focus {\n border-color: @color;\n outline: 0;\n .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. `<select>`\n// element gets special love because it's special, and that's a fact!\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n height: @input-height;\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n\n select& {\n height: @input-height;\n line-height: @input-height;\n }\n\n textarea&,\n select[multiple]& {\n height: auto;\n }\n}\n","//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n display: inline-block;\n margin-bottom: 0; // For input.btn\n font-weight: @btn-font-weight;\n text-align: center;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n white-space: nowrap;\n .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @btn-border-radius-base);\n .user-select(none);\n\n &,\n &:active,\n &.active {\n &:focus,\n &.focus {\n .tab-focus();\n }\n }\n\n &:hover,\n &:focus,\n &.focus {\n color: @btn-default-color;\n text-decoration: none;\n }\n\n &:active,\n &.active {\n outline: 0;\n background-image: none;\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n .opacity(.65);\n .box-shadow(none);\n }\n\n a& {\n &.disabled,\n fieldset[disabled] & {\n pointer-events: none; // Future-proof disabling of clicks on `<a>` elements\n }\n }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n color: @link-color;\n font-weight: normal;\n border-radius: 0;\n\n &,\n &:active,\n &.active,\n &[disabled],\n fieldset[disabled] & {\n background-color: transparent;\n .box-shadow(none);\n }\n &,\n &:hover,\n &:focus,\n &:active {\n border-color: transparent;\n }\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n background-color: transparent;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @btn-link-disabled-color;\n text-decoration: none;\n }\n }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n // line-height: ensure even-numbered height of button next to large input\n .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @btn-border-radius-large);\n}\n.btn-sm {\n // line-height: ensure proper height of button next to small input\n .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small);\n}\n.btn-xs {\n .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n display: block;\n width: 100%;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n &.btn-block {\n width: 100%;\n }\n}\n","// Button variants\n//\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n\n.button-variant(@color; @background; @border) {\n color: @color;\n background-color: @background;\n border-color: @border;\n\n &:focus,\n &.focus {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 25%);\n }\n &:hover {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 12%);\n }\n &:active,\n &.active,\n .open > .dropdown-toggle& {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 12%);\n\n &:hover,\n &:focus,\n &.focus {\n color: @color;\n background-color: darken(@background, 17%);\n border-color: darken(@border, 25%);\n }\n }\n &:active,\n &.active,\n .open > .dropdown-toggle& {\n background-image: none;\n }\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: @background;\n border-color: @border;\n }\n }\n\n .badge {\n color: @background;\n background-color: @color;\n }\n}\n\n// Button sizes\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n}\n","// Opacity\n\n.opacity(@opacity) {\n opacity: @opacity;\n // IE8 filter\n @opacity-ie: (@opacity * 100);\n filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n","//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.\n\n.fade {\n opacity: 0;\n .transition(opacity .15s linear);\n &.in {\n opacity: 1;\n }\n}\n\n.collapse {\n display: none;\n\n &.in { display: block; }\n tr&.in { display: table-row; }\n tbody&.in { display: table-row-group; }\n}\n\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n .transition-property(~\"height, visibility\");\n .transition-duration(.35s);\n .transition-timing-function(ease);\n}\n","//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: @caret-width-base dashed;\n border-top: @caret-width-base solid ~\"\\9\"; // IE8\n border-right: @caret-width-base solid transparent;\n border-left: @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropup,\n.dropdown {\n position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: @zindex-dropdown;\n display: none; // none by default, but block on \"open\" of the menu\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0; // override default ul\n list-style: none;\n font-size: @font-size-base;\n text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)\n background-color: @dropdown-bg;\n border: 1px solid @dropdown-fallback-border; // IE8 fallback\n border: 1px solid @dropdown-border;\n border-radius: @border-radius-base;\n .box-shadow(0 6px 12px rgba(0,0,0,.175));\n background-clip: padding-box;\n\n // Aligns the dropdown menu to right\n //\n // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n &.pull-right {\n right: 0;\n left: auto;\n }\n\n // Dividers (basically an hr) within the dropdown\n .divider {\n .nav-divider(@dropdown-divider-bg);\n }\n\n // Links within the dropdown menu\n > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: @line-height-base;\n color: @dropdown-link-color;\n white-space: nowrap; // prevent links from randomly breaking onto new lines\n }\n}\n\n// Hover/Focus state\n.dropdown-menu > li > a {\n &:hover,\n &:focus {\n text-decoration: none;\n color: @dropdown-link-hover-color;\n background-color: @dropdown-link-hover-bg;\n }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-active-color;\n text-decoration: none;\n outline: 0;\n background-color: @dropdown-link-active-bg;\n }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-disabled-color;\n }\n\n // Nuke hover/focus effects\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none; // Remove CSS gradient\n .reset-filter();\n cursor: @cursor-disabled;\n }\n}\n\n// Open state for the dropdown\n.open {\n // Show the menu\n > .dropdown-menu {\n display: block;\n }\n\n // Remove the outline when :focus is triggered\n > a {\n outline: 0;\n }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n left: auto; // Reset the default from `.dropdown-menu`\n right: 0;\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n\n// Dropdown section headers\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: @font-size-small;\n line-height: @line-height-base;\n color: @dropdown-header-color;\n white-space: nowrap; // as with > li > a\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n // Reverse the caret\n .caret {\n border-top: 0;\n border-bottom: @caret-width-base dashed;\n border-bottom: @caret-width-base solid ~\"\\9\"; // IE8\n content: \"\";\n }\n // Different positioning for bottom up menu\n .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-right {\n .dropdown-menu {\n .dropdown-menu-right();\n }\n // Necessary for overrides of the default right aligned menu.\n // Will remove come v4 in all likelihood.\n .dropdown-menu-left {\n .dropdown-menu-left();\n }\n }\n}\n","// Horizontal dividers\n//\n// Dividers (basically an hr) within dropdowns and nav lists\n\n.nav-divider(@color: #e5e5e5) {\n height: 1px;\n margin: ((@line-height-computed / 2) - 1) 0;\n overflow: hidden;\n background-color: @color;\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n","//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle; // match .btn alignment given font-size hack above\n > .btn {\n position: relative;\n float: left;\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active,\n &.active {\n z-index: 2;\n }\n }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n .btn + .btn,\n .btn + .btn-group,\n .btn-group + .btn,\n .btn-group + .btn-group {\n margin-left: -1px;\n }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n margin-left: -5px; // Offset the first child's margin\n &:extend(.clearfix all);\n\n .btn,\n .btn-group,\n .input-group {\n float: left;\n }\n > .btn,\n > .btn-group,\n > .input-group {\n margin-left: 5px;\n }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n margin-left: 0;\n &:not(:last-child):not(.dropdown-toggle) {\n .border-right-radius(0);\n }\n}\n// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-right-radius(0);\n }\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n\n // Show no shadow for `.btn-link` since it has no other button styles.\n &.btn-link {\n .box-shadow(none);\n }\n}\n\n\n// Reposition the caret\n.btn .caret {\n margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n border-width: @caret-width-large @caret-width-large 0;\n border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n > .btn,\n > .btn-group,\n > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n }\n\n // Clear floats so dropdown menus can be properly placed\n > .btn-group {\n &:extend(.clearfix all);\n > .btn {\n float: none;\n }\n }\n\n > .btn + .btn,\n > .btn + .btn-group,\n > .btn-group + .btn,\n > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n }\n}\n\n.btn-group-vertical > .btn {\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n &:first-child:not(:last-child) {\n border-top-right-radius: @btn-border-radius-base;\n .border-bottom-radius(0);\n }\n &:last-child:not(:first-child) {\n border-bottom-left-radius: @btn-border-radius-base;\n .border-top-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-bottom-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-top-radius(0);\n}\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n > .btn,\n > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n }\n > .btn-group .btn {\n width: 100%;\n }\n\n > .btn-group .dropdown-menu {\n left: auto;\n }\n}\n\n\n// Checkbox and radio options\n//\n// In order to support the browser's form validation feedback, powered by the\n// `required` attribute, we have to \"hide\" the inputs via `clip`. We cannot use\n// `display: none;` or `visibility: hidden;` as that also hides the popover.\n// Simply visually hiding the inputs via `opacity` would leave them clickable in\n// certain cases which is prevented by using `clip` and `pointer-events`.\n// This way, we ensure a DOM element is visible to position the popover from.\n//\n// See https://github.com/twbs/bootstrap/pull/12794 and\n// https://github.com/twbs/bootstrap/pull/14559 for more information.\n\n[data-toggle=\"buttons\"] {\n > .btn,\n > .btn-group > .btn {\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0,0,0,0);\n pointer-events: none;\n }\n }\n}\n","// Single side border-radius\n\n.border-top-radius(@radius) {\n border-top-right-radius: @radius;\n border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n border-bottom-left-radius: @radius;\n border-top-left-radius: @radius;\n}\n","//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n position: relative; // For dropdowns\n display: table;\n border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n // Undo padding and float of grid classes\n &[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n }\n\n .form-control {\n // Ensure that the input is always above the *appended* addon button for\n // proper border colors.\n position: relative;\n z-index: 2;\n\n // IE9 fubars the placeholder attribute in text inputs and the arrows on\n // select elements in input groups. To fix it, we float the input. Details:\n // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n float: left;\n\n width: 100%;\n margin-bottom: 0;\n }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n .input-lg();\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n .input-sm();\n}\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n font-weight: normal;\n line-height: 1;\n color: @input-color;\n text-align: center;\n background-color: @input-group-addon-bg;\n border: 1px solid @input-group-addon-border-color;\n border-radius: @border-radius-base;\n\n // Sizing\n &.input-sm {\n padding: @padding-small-vertical @padding-small-horizontal;\n font-size: @font-size-small;\n border-radius: @border-radius-small;\n }\n &.input-lg {\n padding: @padding-large-vertical @padding-large-horizontal;\n font-size: @font-size-large;\n border-radius: @border-radius-large;\n }\n\n // Nuke default margins from checkboxes and radios to vertically center within.\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n margin-top: 0;\n }\n}\n\n// Reset rounded corners\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n .border-right-radius(0);\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n .border-left-radius(0);\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n position: relative;\n // Jankily prevent input button groups from wrapping with `white-space` and\n // `font-size` in combination with `inline-block` on buttons.\n font-size: 0;\n white-space: nowrap;\n\n // Negative margin for spacing, position for bringing hovered/focused/actived\n // element above the siblings.\n > .btn {\n position: relative;\n + .btn {\n margin-left: -1px;\n }\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active {\n z-index: 2;\n }\n }\n\n // Negative margin to only have a 1px border between the two\n &:first-child {\n > .btn,\n > .btn-group {\n margin-right: -1px;\n }\n }\n &:last-child {\n > .btn,\n > .btn-group {\n z-index: 2;\n margin-left: -1px;\n }\n }\n}\n","//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n margin-bottom: 0;\n padding-left: 0; // Override default ul/ol\n list-style: none;\n &:extend(.clearfix all);\n\n > li {\n position: relative;\n display: block;\n\n > a {\n position: relative;\n display: block;\n padding: @nav-link-padding;\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: @nav-link-hover-bg;\n }\n }\n\n // Disabled state sets text to gray and nukes hover/tab effects\n &.disabled > a {\n color: @nav-disabled-link-color;\n\n &:hover,\n &:focus {\n color: @nav-disabled-link-hover-color;\n text-decoration: none;\n background-color: transparent;\n cursor: @cursor-disabled;\n }\n }\n }\n\n // Open dropdowns\n .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @nav-link-hover-bg;\n border-color: @link-color;\n }\n }\n\n // Nav dividers (deprecated with v3.0.1)\n //\n // This should have been removed in v3 with the dropping of `.nav-list`, but\n // we missed it. We don't currently support this anywhere, but in the interest\n // of maintaining backward compatibility in case you use it, it's deprecated.\n .nav-divider {\n .nav-divider();\n }\n\n // Prevent IE8 from misplacing imgs\n //\n // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n > li > a > img {\n max-width: none;\n }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n border-bottom: 1px solid @nav-tabs-border-color;\n > li {\n float: left;\n // Make the list-items overlay the bottom border\n margin-bottom: -1px;\n\n // Actual tabs (as links)\n > a {\n margin-right: 2px;\n line-height: @line-height-base;\n border: 1px solid transparent;\n border-radius: @border-radius-base @border-radius-base 0 0;\n &:hover {\n border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n }\n }\n\n // Active state, and its :hover to override normal :hover\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-tabs-active-link-hover-color;\n background-color: @nav-tabs-active-link-hover-bg;\n border: 1px solid @nav-tabs-active-link-hover-border-color;\n border-bottom-color: transparent;\n cursor: default;\n }\n }\n }\n // pulling this in mainly for less shorthand\n &.nav-justified {\n .nav-justified();\n .nav-tabs-justified();\n }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n > li {\n float: left;\n\n // Links rendered as pills\n > a {\n border-radius: @nav-pills-border-radius;\n }\n + li {\n margin-left: 2px;\n }\n\n // Active state\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-pills-active-link-hover-color;\n background-color: @nav-pills-active-link-hover-bg;\n }\n }\n }\n}\n\n\n// Stacked pills\n.nav-stacked {\n > li {\n float: none;\n + li {\n margin-top: 2px;\n margin-left: 0; // no need for this gap between nav items\n }\n }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n width: 100%;\n\n > li {\n float: none;\n > a {\n text-align: center;\n margin-bottom: 5px;\n }\n }\n\n > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n }\n\n @media (min-width: @screen-sm-min) {\n > li {\n display: table-cell;\n width: 1%;\n > a {\n margin-bottom: 0;\n }\n }\n }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n border-bottom: 0;\n\n > li > a {\n // Override margin from .nav-tabs\n margin-right: 0;\n border-radius: @border-radius-base;\n }\n\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border: 1px solid @nav-tabs-justified-link-border-color;\n }\n\n @media (min-width: @screen-sm-min) {\n > li > a {\n border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n border-radius: @border-radius-base @border-radius-base 0 0;\n }\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border-bottom-color: @nav-tabs-justified-active-link-border-color;\n }\n }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n > .tab-pane {\n display: none;\n }\n > .active {\n display: block;\n }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n // make dropdown border overlap tab border\n margin-top: -1px;\n // Remove the top rounded corners here since there is a hard edge above the menu\n .border-top-radius(0);\n}\n","//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n position: relative;\n min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n margin-bottom: @navbar-margin-bottom;\n border: 1px solid transparent;\n\n // Prevent floats from breaking the navbar\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: @navbar-border-radius;\n }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n overflow-x: visible;\n padding-right: @navbar-padding-horizontal;\n padding-left: @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n &:extend(.clearfix all);\n -webkit-overflow-scrolling: touch;\n\n &.in {\n overflow-y: auto;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border-top: 0;\n box-shadow: none;\n\n &.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0; // Override default setting\n overflow: visible !important;\n }\n\n &.in {\n overflow-y: visible;\n }\n\n // Undo the collapse side padding for navbars with containers to ensure\n // alignment of right-aligned contents.\n .navbar-fixed-top &,\n .navbar-static-top &,\n .navbar-fixed-bottom & {\n padding-left: 0;\n padding-right: 0;\n }\n }\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n .navbar-collapse {\n max-height: @navbar-collapse-max-height;\n\n @media (max-device-width: @screen-xs-min) and (orientation: landscape) {\n max-height: 200px;\n }\n }\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n > .navbar-header,\n > .navbar-collapse {\n margin-right: -@navbar-padding-horizontal;\n margin-left: -@navbar-padding-horizontal;\n\n @media (min-width: @grid-float-breakpoint) {\n margin-right: 0;\n margin-left: 0;\n }\n }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n z-index: @zindex-navbar;\n border-width: 0 0 1px;\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n\n// Fix the top/bottom navbars when screen real estate supports it\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: @zindex-navbar-fixed;\n\n // Undo the rounded corners\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0; // override .navbar defaults\n border-width: 1px 0 0;\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n float: left;\n padding: @navbar-padding-vertical @navbar-padding-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-computed;\n height: @navbar-height;\n\n &:hover,\n &:focus {\n text-decoration: none;\n }\n\n > img {\n display: block;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n .navbar > .container &,\n .navbar > .container-fluid & {\n margin-left: -@navbar-padding-horizontal;\n }\n }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: @navbar-padding-horizontal;\n padding: 9px 10px;\n .navbar-vertical-align(34px);\n background-color: transparent;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n border-radius: @border-radius-base;\n\n // We remove the `outline` here, but later compensate by attaching `:hover`\n // styles to `:focus`.\n &:focus {\n outline: 0;\n }\n\n // Bars\n .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n }\n .icon-bar + .icon-bar {\n margin-top: 4px;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n display: none;\n }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: @line-height-computed;\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n > li > a,\n .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n > li > a {\n line-height: @line-height-computed;\n &:hover,\n &:focus {\n background-image: none;\n }\n }\n }\n }\n\n // Uncollapse the nav\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin: 0;\n\n > li {\n float: left;\n > a {\n padding-top: @navbar-padding-vertical;\n padding-bottom: @navbar-padding-vertical;\n }\n }\n }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n margin-left: -@navbar-padding-horizontal;\n margin-right: -@navbar-padding-horizontal;\n padding: 10px @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n\n // Mixin behavior for optimum display\n .form-inline();\n\n .form-group {\n @media (max-width: @grid-float-breakpoint-max) {\n margin-bottom: 5px;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n }\n\n // Vertically center in expanded, horizontal navbar\n .navbar-vertical-align(@input-height-base);\n\n // Undo 100% width for pull classes\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n .box-shadow(none);\n }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n .border-top-radius(@navbar-border-radius);\n .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n .navbar-vertical-align(@input-height-base);\n\n &.btn-sm {\n .navbar-vertical-align(@input-height-small);\n }\n &.btn-xs {\n .navbar-vertical-align(22);\n }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n .navbar-vertical-align(@line-height-computed);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin-left: @navbar-padding-horizontal;\n margin-right: @navbar-padding-horizontal;\n }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n//\n// Declared after the navbar components to ensure more specificity on the margins.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-left { .pull-left(); }\n .navbar-right {\n .pull-right();\n margin-right: -@navbar-padding-horizontal;\n\n ~ .navbar-right {\n margin-right: 0;\n }\n }\n}\n\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n background-color: @navbar-default-bg;\n border-color: @navbar-default-border;\n\n .navbar-brand {\n color: @navbar-default-brand-color;\n &:hover,\n &:focus {\n color: @navbar-default-brand-hover-color;\n background-color: @navbar-default-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-default-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-default-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n\n .navbar-toggle {\n border-color: @navbar-default-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-default-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-default-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: @navbar-default-border;\n }\n\n // Dropdown menu items\n .navbar-nav {\n // Remove background color from open dropdown\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-default-link-active-bg;\n color: @navbar-default-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n > li > a {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n }\n }\n\n\n // Links in navbars\n //\n // Add a class to ensure links outside the navbar nav are colored correctly.\n\n .navbar-link {\n color: @navbar-default-link-color;\n &:hover {\n color: @navbar-default-link-hover-color;\n }\n }\n\n .btn-link {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n }\n }\n }\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n background-color: @navbar-inverse-bg;\n border-color: @navbar-inverse-border;\n\n .navbar-brand {\n color: @navbar-inverse-brand-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-brand-hover-color;\n background-color: @navbar-inverse-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-inverse-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-inverse-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n\n // Darken the responsive nav toggle\n .navbar-toggle {\n border-color: @navbar-inverse-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-inverse-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-inverse-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: darken(@navbar-inverse-bg, 7%);\n }\n\n // Dropdowns\n .navbar-nav {\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-inverse-link-active-bg;\n color: @navbar-inverse-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display\n .open .dropdown-menu {\n > .dropdown-header {\n border-color: @navbar-inverse-border;\n }\n .divider {\n background-color: @navbar-inverse-border;\n }\n > li > a {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n }\n }\n\n .navbar-link {\n color: @navbar-inverse-link-color;\n &:hover {\n color: @navbar-inverse-link-hover-color;\n }\n }\n\n .btn-link {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n }\n }\n }\n}\n","// Navbar vertical align\n//\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n\n.navbar-vertical-align(@element-height) {\n margin-top: ((@navbar-height - @element-height) / 2);\n margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n","//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n .clearfix();\n}\n.center-block {\n .center-block();\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n display: none !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n position: fixed;\n}\n","//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n margin-bottom: @line-height-computed;\n list-style: none;\n background-color: @breadcrumb-bg;\n border-radius: @border-radius-base;\n\n > li {\n display: inline-block;\n\n + li:before {\n content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n padding: 0 5px;\n color: @breadcrumb-color;\n }\n }\n\n > .active {\n color: @breadcrumb-active-color;\n }\n}\n","//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: @line-height-computed 0;\n border-radius: @border-radius-base;\n\n > li {\n display: inline; // Remove list-style and block-level defaults\n > a,\n > span {\n position: relative;\n float: left; // Collapse white-space\n padding: @padding-base-vertical @padding-base-horizontal;\n line-height: @line-height-base;\n text-decoration: none;\n color: @pagination-color;\n background-color: @pagination-bg;\n border: 1px solid @pagination-border;\n margin-left: -1px;\n }\n &:first-child {\n > a,\n > span {\n margin-left: 0;\n .border-left-radius(@border-radius-base);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius-base);\n }\n }\n }\n\n > li > a,\n > li > span {\n &:hover,\n &:focus {\n z-index: 3;\n color: @pagination-hover-color;\n background-color: @pagination-hover-bg;\n border-color: @pagination-hover-border;\n }\n }\n\n > .active > a,\n > .active > span {\n &,\n &:hover,\n &:focus {\n z-index: 2;\n color: @pagination-active-color;\n background-color: @pagination-active-bg;\n border-color: @pagination-active-border;\n cursor: default;\n }\n }\n\n > .disabled {\n > span,\n > span:hover,\n > span:focus,\n > a,\n > a:hover,\n > a:focus {\n color: @pagination-disabled-color;\n background-color: @pagination-disabled-bg;\n border-color: @pagination-disabled-border;\n cursor: @cursor-disabled;\n }\n }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n","// Pagination\n\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n > li {\n > a,\n > span {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n }\n &:first-child {\n > a,\n > span {\n .border-left-radius(@border-radius);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius);\n }\n }\n }\n}\n","//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n padding-left: 0;\n margin: @line-height-computed 0;\n list-style: none;\n text-align: center;\n &:extend(.clearfix all);\n li {\n display: inline;\n > a,\n > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: @pager-bg;\n border: 1px solid @pager-border;\n border-radius: @pager-border-radius;\n }\n\n > a:hover,\n > a:focus {\n text-decoration: none;\n background-color: @pager-hover-bg;\n }\n }\n\n .next {\n > a,\n > span {\n float: right;\n }\n }\n\n .previous {\n > a,\n > span {\n float: left;\n }\n }\n\n .disabled {\n > a,\n > a:hover,\n > a:focus,\n > span {\n color: @pager-disabled-color;\n background-color: @pager-bg;\n cursor: @cursor-disabled;\n }\n }\n}\n","//\n// Labels\n// --------------------------------------------------\n\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: @label-color;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n\n // Add hover effects, but only for links\n a& {\n &:hover,\n &:focus {\n color: @label-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Empty labels collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for labels in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n .label-variant(@label-default-bg);\n}\n\n.label-primary {\n .label-variant(@label-primary-bg);\n}\n\n.label-success {\n .label-variant(@label-success-bg);\n}\n\n.label-info {\n .label-variant(@label-info-bg);\n}\n\n.label-warning {\n .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n .label-variant(@label-danger-bg);\n}\n","// Labels\n\n.label-variant(@color) {\n background-color: @color;\n\n &[href] {\n &:hover,\n &:focus {\n background-color: darken(@color, 10%);\n }\n }\n}\n","//\n// Badges\n// --------------------------------------------------\n\n\n// Base class\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: @font-size-small;\n font-weight: @badge-font-weight;\n color: @badge-color;\n line-height: @badge-line-height;\n vertical-align: middle;\n white-space: nowrap;\n text-align: center;\n background-color: @badge-bg;\n border-radius: @badge-border-radius;\n\n // Empty badges collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for badges in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n\n .btn-xs &,\n .btn-group-xs > .btn & {\n top: 0;\n padding: 1px 5px;\n }\n\n // Hover state, but only for links\n a& {\n &:hover,\n &:focus {\n color: @badge-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Account for badges in navs\n .list-group-item.active > &,\n .nav-pills > .active > a > & {\n color: @badge-active-color;\n background-color: @badge-active-bg;\n }\n\n .list-group-item > & {\n float: right;\n }\n\n .list-group-item > & + & {\n margin-right: 5px;\n }\n\n .nav-pills > li > a > & {\n margin-left: 3px;\n }\n}\n","//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n padding-top: @jumbotron-padding;\n padding-bottom: @jumbotron-padding;\n margin-bottom: @jumbotron-padding;\n color: @jumbotron-color;\n background-color: @jumbotron-bg;\n\n h1,\n .h1 {\n color: @jumbotron-heading-color;\n }\n\n p {\n margin-bottom: (@jumbotron-padding / 2);\n font-size: @jumbotron-font-size;\n font-weight: 200;\n }\n\n > hr {\n border-top-color: darken(@jumbotron-bg, 10%);\n }\n\n .container &,\n .container-fluid & {\n border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n }\n\n .container {\n max-width: 100%;\n }\n\n @media screen and (min-width: @screen-sm-min) {\n padding-top: (@jumbotron-padding * 1.6);\n padding-bottom: (@jumbotron-padding * 1.6);\n\n .container &,\n .container-fluid & {\n padding-left: (@jumbotron-padding * 2);\n padding-right: (@jumbotron-padding * 2);\n }\n\n h1,\n .h1 {\n font-size: @jumbotron-heading-font-size;\n }\n }\n}\n","//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n display: block;\n padding: @thumbnail-padding;\n margin-bottom: @line-height-computed;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(border .2s ease-in-out);\n\n > img,\n a > img {\n &:extend(.img-responsive);\n margin-left: auto;\n margin-right: auto;\n }\n\n // Add a hover state for linked versions only\n a&:hover,\n a&:focus,\n a&.active {\n border-color: @link-color;\n }\n\n // Image captions\n .caption {\n padding: @thumbnail-caption-padding;\n color: @thumbnail-caption-color;\n }\n}\n","//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n padding: @alert-padding;\n margin-bottom: @line-height-computed;\n border: 1px solid transparent;\n border-radius: @alert-border-radius;\n\n // Headings for larger alerts\n h4 {\n margin-top: 0;\n // Specified for the h4 to prevent conflicts of changing @headings-color\n color: inherit;\n }\n\n // Provide class for links that match alerts\n .alert-link {\n font-weight: @alert-link-font-weight;\n }\n\n // Improve alignment and spacing of inner content\n > p,\n > ul {\n margin-bottom: 0;\n }\n\n > p + p {\n margin-top: 5px;\n }\n}\n\n// Dismissible alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.\n.alert-dismissible {\n padding-right: (@alert-padding + 20);\n\n // Adjust close link position\n .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n\n.alert-info {\n .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n\n.alert-warning {\n .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n\n.alert-danger {\n .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n","// Alerts\n\n.alert-variant(@background; @border; @text-color) {\n background-color: @background;\n border-color: @border;\n color: @text-color;\n\n hr {\n border-top-color: darken(@border, 5%);\n }\n .alert-link {\n color: darken(@text-color, 10%);\n }\n}\n","//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n overflow: hidden;\n height: @line-height-computed;\n margin-bottom: @line-height-computed;\n background-color: @progress-bg;\n border-radius: @progress-border-radius;\n .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));\n}\n\n// Bar of progress\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: @font-size-small;\n line-height: @line-height-computed;\n color: @progress-bar-color;\n text-align: center;\n background-color: @progress-bar-bg;\n .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));\n .transition(width .6s ease);\n}\n\n// Striped bars\n//\n// `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar-striped` class, which you just add to an existing\n// `.progress-bar`.\n.progress-striped .progress-bar,\n.progress-bar-striped {\n #gradient > .striped();\n background-size: 40px 40px;\n}\n\n// Call animation for the active one\n//\n// `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar.active` approach.\n.progress.active .progress-bar,\n.progress-bar.active {\n .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n .progress-bar-variant(@progress-bar-danger-bg);\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Progress bars\n\n.progress-bar-variant(@color) {\n background-color: @color;\n\n // Deprecated parent class requirement as of v3.2.0\n .progress-striped & {\n #gradient > .striped();\n }\n}\n",".media {\n // Proper spacing between instances of .media\n margin-top: 15px;\n\n &:first-child {\n margin-top: 0;\n }\n}\n\n.media,\n.media-body {\n zoom: 1;\n overflow: hidden;\n}\n\n.media-body {\n width: 10000px;\n}\n\n.media-object {\n display: block;\n\n // Fix collapse in webkit from max-width: 100% and display: table-cell.\n &.img-thumbnail {\n max-width: none;\n }\n}\n\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n\n.media-middle {\n vertical-align: middle;\n}\n\n.media-bottom {\n vertical-align: bottom;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n\n// Media list variation\n//\n// Undo default ul/ol styles\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n","//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on <ul>, <ol>, or <div>.\n\n.list-group {\n // No need to set list-style: none; since .list-group-item is block level\n margin-bottom: 20px;\n padding-left: 0; // reset padding because ul and ol\n}\n\n\n// Individual list items\n//\n// Use on `li`s or `div`s within the `.list-group` parent.\n\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n // Place the border on the list items and negative margin up for better styling\n margin-bottom: -1px;\n background-color: @list-group-bg;\n border: 1px solid @list-group-border;\n\n // Round the first and last items\n &:first-child {\n .border-top-radius(@list-group-border-radius);\n }\n &:last-child {\n margin-bottom: 0;\n .border-bottom-radius(@list-group-border-radius);\n }\n}\n\n\n// Interactive list items\n//\n// Use anchor or button elements instead of `li`s or `div`s to create interactive items.\n// Includes an extra `.active` modifier class for showing selected items.\n\na.list-group-item,\nbutton.list-group-item {\n color: @list-group-link-color;\n\n .list-group-item-heading {\n color: @list-group-link-heading-color;\n }\n\n // Hover state\n &:hover,\n &:focus {\n text-decoration: none;\n color: @list-group-link-hover-color;\n background-color: @list-group-hover-bg;\n }\n}\n\nbutton.list-group-item {\n width: 100%;\n text-align: left;\n}\n\n.list-group-item {\n // Disabled state\n &.disabled,\n &.disabled:hover,\n &.disabled:focus {\n background-color: @list-group-disabled-bg;\n color: @list-group-disabled-color;\n cursor: @cursor-disabled;\n\n // Force color to inherit for custom content\n .list-group-item-heading {\n color: inherit;\n }\n .list-group-item-text {\n color: @list-group-disabled-text-color;\n }\n }\n\n // Active class on item itself, not parent\n &.active,\n &.active:hover,\n &.active:focus {\n z-index: 2; // Place active items above their siblings for proper border styling\n color: @list-group-active-color;\n background-color: @list-group-active-bg;\n border-color: @list-group-active-border;\n\n // Force color to inherit for custom content\n .list-group-item-heading,\n .list-group-item-heading > small,\n .list-group-item-heading > .small {\n color: inherit;\n }\n .list-group-item-text {\n color: @list-group-active-text-color;\n }\n }\n}\n\n\n// Contextual variants\n//\n// Add modifier classes to change text and background color on individual items.\n// Organizationally, this must come after the `:hover` states.\n\n.list-group-item-variant(success; @state-success-bg; @state-success-text);\n.list-group-item-variant(info; @state-info-bg; @state-info-text);\n.list-group-item-variant(warning; @state-warning-bg; @state-warning-text);\n.list-group-item-variant(danger; @state-danger-bg; @state-danger-text);\n\n\n// Custom content options\n//\n// Extra classes for creating well-formatted content within `.list-group-item`s.\n\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n","// List Groups\n\n.list-group-item-variant(@state; @background; @color) {\n .list-group-item-@{state} {\n color: @color;\n background-color: @background;\n\n a&,\n button& {\n color: @color;\n\n .list-group-item-heading {\n color: inherit;\n }\n\n &:hover,\n &:focus {\n color: @color;\n background-color: darken(@background, 5%);\n }\n &.active,\n &.active:hover,\n &.active:focus {\n color: #fff;\n background-color: @color;\n border-color: @color;\n }\n }\n }\n}\n","//\n// Panels\n// --------------------------------------------------\n\n\n// Base class\n.panel {\n margin-bottom: @line-height-computed;\n background-color: @panel-bg;\n border: 1px solid transparent;\n border-radius: @panel-border-radius;\n .box-shadow(0 1px 1px rgba(0,0,0,.05));\n}\n\n// Panel contents\n.panel-body {\n padding: @panel-body-padding;\n &:extend(.clearfix all);\n}\n\n// Optional heading\n.panel-heading {\n padding: @panel-heading-padding;\n border-bottom: 1px solid transparent;\n .border-top-radius((@panel-border-radius - 1));\n\n > .dropdown .dropdown-toggle {\n color: inherit;\n }\n}\n\n// Within heading, strip any `h*` tag of its default margins for spacing.\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: ceil((@font-size-base * 1.125));\n color: inherit;\n\n > a,\n > small,\n > .small,\n > small > a,\n > .small > a {\n color: inherit;\n }\n}\n\n// Optional footer (stays gray in every modifier class)\n.panel-footer {\n padding: @panel-footer-padding;\n background-color: @panel-footer-bg;\n border-top: 1px solid @panel-inner-border;\n .border-bottom-radius((@panel-border-radius - 1));\n}\n\n\n// List groups in panels\n//\n// By default, space out list group content from panel headings to account for\n// any kind of custom content between the two.\n\n.panel {\n > .list-group,\n > .panel-collapse > .list-group {\n margin-bottom: 0;\n\n .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n }\n\n // Add border top radius for first one\n &:first-child {\n .list-group-item:first-child {\n border-top: 0;\n .border-top-radius((@panel-border-radius - 1));\n }\n }\n\n // Add border bottom radius for last one\n &:last-child {\n .list-group-item:last-child {\n border-bottom: 0;\n .border-bottom-radius((@panel-border-radius - 1));\n }\n }\n }\n > .panel-heading + .panel-collapse > .list-group {\n .list-group-item:first-child {\n .border-top-radius(0);\n }\n }\n}\n// Collapse space between when there's no additional content.\n.panel-heading + .list-group {\n .list-group-item:first-child {\n border-top-width: 0;\n }\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n\n// Tables in panels\n//\n// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and\n// watch it go full width.\n\n.panel {\n > .table,\n > .table-responsive > .table,\n > .panel-collapse > .table {\n margin-bottom: 0;\n\n caption {\n padding-left: @panel-body-padding;\n padding-right: @panel-body-padding;\n }\n }\n // Add border top radius for first one\n > .table:first-child,\n > .table-responsive:first-child > .table:first-child {\n .border-top-radius((@panel-border-radius - 1));\n\n > thead:first-child,\n > tbody:first-child {\n > tr:first-child {\n border-top-left-radius: (@panel-border-radius - 1);\n border-top-right-radius: (@panel-border-radius - 1);\n\n td:first-child,\n th:first-child {\n border-top-left-radius: (@panel-border-radius - 1);\n }\n td:last-child,\n th:last-child {\n border-top-right-radius: (@panel-border-radius - 1);\n }\n }\n }\n }\n // Add border bottom radius for last one\n > .table:last-child,\n > .table-responsive:last-child > .table:last-child {\n .border-bottom-radius((@panel-border-radius - 1));\n\n > tbody:last-child,\n > tfoot:last-child {\n > tr:last-child {\n border-bottom-left-radius: (@panel-border-radius - 1);\n border-bottom-right-radius: (@panel-border-radius - 1);\n\n td:first-child,\n th:first-child {\n border-bottom-left-radius: (@panel-border-radius - 1);\n }\n td:last-child,\n th:last-child {\n border-bottom-right-radius: (@panel-border-radius - 1);\n }\n }\n }\n }\n > .panel-body + .table,\n > .panel-body + .table-responsive,\n > .table + .panel-body,\n > .table-responsive + .panel-body {\n border-top: 1px solid @table-border-color;\n }\n > .table > tbody:first-child > tr:first-child th,\n > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n }\n > .table-bordered,\n > .table-responsive > .table-bordered {\n border: 0;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n > thead,\n > tbody {\n > tr:first-child {\n > td,\n > th {\n border-bottom: 0;\n }\n }\n }\n > tbody,\n > tfoot {\n > tr:last-child {\n > td,\n > th {\n border-bottom: 0;\n }\n }\n }\n }\n > .table-responsive {\n border: 0;\n margin-bottom: 0;\n }\n}\n\n\n// Collapsable panels (aka, accordion)\n//\n// Wrap a series of panels in `.panel-group` to turn them into an accordion with\n// the help of our collapse JavaScript plugin.\n\n.panel-group {\n margin-bottom: @line-height-computed;\n\n // Tighten up margin so it's only between panels\n .panel {\n margin-bottom: 0;\n border-radius: @panel-border-radius;\n\n + .panel {\n margin-top: 5px;\n }\n }\n\n .panel-heading {\n border-bottom: 0;\n\n + .panel-collapse > .panel-body,\n + .panel-collapse > .list-group {\n border-top: 1px solid @panel-inner-border;\n }\n }\n\n .panel-footer {\n border-top: 0;\n + .panel-collapse .panel-body {\n border-bottom: 1px solid @panel-inner-border;\n }\n }\n}\n\n\n// Contextual variations\n.panel-default {\n .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border);\n}\n.panel-primary {\n .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border);\n}\n.panel-success {\n .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border);\n}\n.panel-info {\n .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border);\n}\n.panel-warning {\n .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border);\n}\n.panel-danger {\n .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border);\n}\n","// Panels\n\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n border-color: @border;\n\n & > .panel-heading {\n color: @heading-text-color;\n background-color: @heading-bg-color;\n border-color: @heading-border;\n\n + .panel-collapse > .panel-body {\n border-top-color: @border;\n }\n .badge {\n color: @heading-bg-color;\n background-color: @heading-text-color;\n }\n }\n & > .panel-footer {\n + .panel-collapse > .panel-body {\n border-bottom-color: @border;\n }\n }\n}\n","// Embeds responsive\n//\n// Credit: Nicolas Gallagher and SUIT CSS.\n\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n\n .embed-responsive-item,\n iframe,\n embed,\n object,\n video {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n height: 100%;\n width: 100%;\n border: 0;\n }\n}\n\n// Modifier class for 16:9 aspect ratio\n.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n\n// Modifier class for 4:3 aspect ratio\n.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n","//\n// Wells\n// --------------------------------------------------\n\n\n// Base class\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: @well-bg;\n border: 1px solid @well-border;\n border-radius: @border-radius-base;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));\n blockquote {\n border-color: #ddd;\n border-color: rgba(0,0,0,.15);\n }\n}\n\n// Sizes\n.well-lg {\n padding: 24px;\n border-radius: @border-radius-large;\n}\n.well-sm {\n padding: 9px;\n border-radius: @border-radius-small;\n}\n","//\n// Close icons\n// --------------------------------------------------\n\n\n.close {\n float: right;\n font-size: (@font-size-base * 1.5);\n font-weight: @close-font-weight;\n line-height: 1;\n color: @close-color;\n text-shadow: @close-text-shadow;\n .opacity(.2);\n\n &:hover,\n &:focus {\n color: @close-color;\n text-decoration: none;\n cursor: pointer;\n .opacity(.5);\n }\n\n // Additional properties for button version\n // iOS requires the button element instead of an anchor tag.\n // If you want the anchor version, it requires `href=\"#\"`.\n // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n button& {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n }\n}\n","//\n// Modals\n// --------------------------------------------------\n\n// .modal-open - body class for killing the scroll\n// .modal - container to scroll within\n// .modal-dialog - positioning shell for the actual modal\n// .modal-content - actual modal w/ bg and corners and shit\n\n// Kill the scroll on the body\n.modal-open {\n overflow: hidden;\n}\n\n// Container that the modal scrolls within\n.modal {\n display: none;\n overflow: hidden;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: @zindex-modal;\n -webkit-overflow-scrolling: touch;\n\n // Prevent Chrome on Windows from adding a focus outline. For details, see\n // https://github.com/twbs/bootstrap/pull/10951.\n outline: 0;\n\n // When fading in the modal, animate it to slide down\n &.fade .modal-dialog {\n .translate(0, -25%);\n .transition-transform(~\"0.3s ease-out\");\n }\n &.in .modal-dialog { .translate(0, 0) }\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n// Shell div to position the modal with bottom padding\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n\n// Actual modal\n.modal-content {\n position: relative;\n background-color: @modal-content-bg;\n border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc)\n border: 1px solid @modal-content-border-color;\n border-radius: @border-radius-large;\n .box-shadow(0 3px 9px rgba(0,0,0,.5));\n background-clip: padding-box;\n // Remove focus outline from opened modal\n outline: 0;\n}\n\n// Modal background\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: @zindex-modal-background;\n background-color: @modal-backdrop-bg;\n // Fade for backdrop\n &.fade { .opacity(0); }\n &.in { .opacity(@modal-backdrop-opacity); }\n}\n\n// Modal header\n// Top section of the modal w/ title and dismiss\n.modal-header {\n padding: @modal-title-padding;\n border-bottom: 1px solid @modal-header-border-color;\n min-height: (@modal-title-padding + @modal-title-line-height);\n}\n// Close icon\n.modal-header .close {\n margin-top: -2px;\n}\n\n// Title text within header\n.modal-title {\n margin: 0;\n line-height: @modal-title-line-height;\n}\n\n// Modal body\n// Where all modal content resides (sibling of .modal-header and .modal-footer)\n.modal-body {\n position: relative;\n padding: @modal-inner-padding;\n}\n\n// Footer (for actions)\n.modal-footer {\n padding: @modal-inner-padding;\n text-align: right; // right align buttons\n border-top: 1px solid @modal-footer-border-color;\n &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons\n\n // Properly space out buttons\n .btn + .btn {\n margin-left: 5px;\n margin-bottom: 0; // account for input[type=\"submit\"] which gets the bottom margin like all other inputs\n }\n // but override that for button groups\n .btn-group .btn + .btn {\n margin-left: -1px;\n }\n // and override it for block buttons as well\n .btn-block + .btn-block {\n margin-left: 0;\n }\n}\n\n// Measure scrollbar width for padding body during modal show/hide\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n\n// Scale up the modal\n@media (min-width: @screen-sm-min) {\n // Automatically set modal's width for larger viewports\n .modal-dialog {\n width: @modal-md;\n margin: 30px auto;\n }\n .modal-content {\n .box-shadow(0 5px 15px rgba(0,0,0,.5));\n }\n\n // Modal sizes\n .modal-sm { width: @modal-sm; }\n}\n\n@media (min-width: @screen-md-min) {\n .modal-lg { width: @modal-lg; }\n}\n","//\n// Tooltips\n// --------------------------------------------------\n\n\n// Base class\n.tooltip {\n position: absolute;\n z-index: @zindex-tooltip;\n display: block;\n // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.\n // So reset our font and text properties to avoid inheriting weird values.\n .reset-text();\n font-size: @font-size-small;\n\n .opacity(0);\n\n &.in { .opacity(@tooltip-opacity); }\n &.top { margin-top: -3px; padding: @tooltip-arrow-width 0; }\n &.right { margin-left: 3px; padding: 0 @tooltip-arrow-width; }\n &.bottom { margin-top: 3px; padding: @tooltip-arrow-width 0; }\n &.left { margin-left: -3px; padding: 0 @tooltip-arrow-width; }\n}\n\n// Wrapper for the tooltip content\n.tooltip-inner {\n max-width: @tooltip-max-width;\n padding: 3px 8px;\n color: @tooltip-color;\n text-align: center;\n background-color: @tooltip-bg;\n border-radius: @border-radius-base;\n}\n\n// Arrows\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n// Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as of v3.3.1\n.tooltip {\n &.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.top-left .tooltip-arrow {\n bottom: 0;\n right: @tooltip-arrow-width;\n margin-bottom: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.top-right .tooltip-arrow {\n bottom: 0;\n left: @tooltip-arrow-width;\n margin-bottom: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;\n border-right-color: @tooltip-arrow-color;\n }\n &.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-left-color: @tooltip-arrow-color;\n }\n &.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n &.bottom-left .tooltip-arrow {\n top: 0;\n right: @tooltip-arrow-width;\n margin-top: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n &.bottom-right .tooltip-arrow {\n top: 0;\n left: @tooltip-arrow-width;\n margin-top: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n}\n",".reset-text() {\n font-family: @font-family-base;\n // We deliberately do NOT reset font-size.\n font-style: normal;\n font-weight: normal;\n letter-spacing: normal;\n line-break: auto;\n line-height: @line-height-base;\n text-align: left; // Fallback for where `start` is not supported\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n white-space: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n}\n","//\n// Popovers\n// --------------------------------------------------\n\n\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: @zindex-popover;\n display: none;\n max-width: @popover-max-width;\n padding: 1px;\n // Our parent element can be arbitrary since popovers are by default inserted as a sibling of their target element.\n // So reset our font and text properties to avoid inheriting weird values.\n .reset-text();\n font-size: @font-size-base;\n\n background-color: @popover-bg;\n background-clip: padding-box;\n border: 1px solid @popover-fallback-border-color;\n border: 1px solid @popover-border-color;\n border-radius: @border-radius-large;\n .box-shadow(0 5px 10px rgba(0,0,0,.2));\n\n // Offset the popover to account for the popover arrow\n &.top { margin-top: -@popover-arrow-width; }\n &.right { margin-left: @popover-arrow-width; }\n &.bottom { margin-top: @popover-arrow-width; }\n &.left { margin-left: -@popover-arrow-width; }\n}\n\n.popover-title {\n margin: 0; // reset heading margin\n padding: 8px 14px;\n font-size: @font-size-base;\n background-color: @popover-title-bg;\n border-bottom: 1px solid darken(@popover-title-bg, 5%);\n border-radius: (@border-radius-large - 1) (@border-radius-large - 1) 0 0;\n}\n\n.popover-content {\n padding: 9px 14px;\n}\n\n// Arrows\n//\n// .arrow is outer, .arrow:after is inner\n\n.popover > .arrow {\n &,\n &:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n }\n}\n.popover > .arrow {\n border-width: @popover-arrow-outer-width;\n}\n.popover > .arrow:after {\n border-width: @popover-arrow-width;\n content: \"\";\n}\n\n.popover {\n &.top > .arrow {\n left: 50%;\n margin-left: -@popover-arrow-outer-width;\n border-bottom-width: 0;\n border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-top-color: @popover-arrow-outer-color;\n bottom: -@popover-arrow-outer-width;\n &:after {\n content: \" \";\n bottom: 1px;\n margin-left: -@popover-arrow-width;\n border-bottom-width: 0;\n border-top-color: @popover-arrow-color;\n }\n }\n &.right > .arrow {\n top: 50%;\n left: -@popover-arrow-outer-width;\n margin-top: -@popover-arrow-outer-width;\n border-left-width: 0;\n border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-right-color: @popover-arrow-outer-color;\n &:after {\n content: \" \";\n left: 1px;\n bottom: -@popover-arrow-width;\n border-left-width: 0;\n border-right-color: @popover-arrow-color;\n }\n }\n &.bottom > .arrow {\n left: 50%;\n margin-left: -@popover-arrow-outer-width;\n border-top-width: 0;\n border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-bottom-color: @popover-arrow-outer-color;\n top: -@popover-arrow-outer-width;\n &:after {\n content: \" \";\n top: 1px;\n margin-left: -@popover-arrow-width;\n border-top-width: 0;\n border-bottom-color: @popover-arrow-color;\n }\n }\n\n &.left > .arrow {\n top: 50%;\n right: -@popover-arrow-outer-width;\n margin-top: -@popover-arrow-outer-width;\n border-right-width: 0;\n border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-left-color: @popover-arrow-outer-color;\n &:after {\n content: \" \";\n right: 1px;\n border-right-width: 0;\n border-left-color: @popover-arrow-color;\n bottom: -@popover-arrow-width;\n }\n }\n}\n","//\n// Carousel\n// --------------------------------------------------\n\n\n// Wrapper for the slide container and indicators\n.carousel {\n position: relative;\n}\n\n.carousel-inner {\n position: relative;\n overflow: hidden;\n width: 100%;\n\n > .item {\n display: none;\n position: relative;\n .transition(.6s ease-in-out left);\n\n // Account for jankitude on images\n > img,\n > a > img {\n &:extend(.img-responsive);\n line-height: 1;\n }\n\n // WebKit CSS3 transforms for supported devices\n @media all and (transform-3d), (-webkit-transform-3d) {\n .transition-transform(~'0.6s ease-in-out');\n .backface-visibility(~'hidden');\n .perspective(1000px);\n\n &.next,\n &.active.right {\n .translate3d(100%, 0, 0);\n left: 0;\n }\n &.prev,\n &.active.left {\n .translate3d(-100%, 0, 0);\n left: 0;\n }\n &.next.left,\n &.prev.right,\n &.active {\n .translate3d(0, 0, 0);\n left: 0;\n }\n }\n }\n\n > .active,\n > .next,\n > .prev {\n display: block;\n }\n\n > .active {\n left: 0;\n }\n\n > .next,\n > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n }\n\n > .next {\n left: 100%;\n }\n > .prev {\n left: -100%;\n }\n > .next.left,\n > .prev.right {\n left: 0;\n }\n\n > .active.left {\n left: -100%;\n }\n > .active.right {\n left: 100%;\n }\n\n}\n\n// Left/right controls for nav\n// ---------------------------\n\n.carousel-control {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n width: @carousel-control-width;\n .opacity(@carousel-control-opacity);\n font-size: @carousel-control-font-size;\n color: @carousel-control-color;\n text-align: center;\n text-shadow: @carousel-text-shadow;\n // We can't have this transition here because WebKit cancels the carousel\n // animation if you trip this while in the middle of another animation.\n\n // Set gradients for backgrounds\n &.left {\n #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001));\n }\n &.right {\n left: auto;\n right: 0;\n #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5));\n }\n\n // Hover/focus state\n &:hover,\n &:focus {\n outline: 0;\n color: @carousel-control-color;\n text-decoration: none;\n .opacity(.9);\n }\n\n // Toggles\n .icon-prev,\n .icon-next,\n .glyphicon-chevron-left,\n .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n margin-top: -10px;\n z-index: 5;\n display: inline-block;\n }\n .icon-prev,\n .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n }\n .icon-next,\n .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n }\n .icon-prev,\n .icon-next {\n width: 20px;\n height: 20px;\n line-height: 1;\n font-family: serif;\n }\n\n\n .icon-prev {\n &:before {\n content: '\\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)\n }\n }\n .icon-next {\n &:before {\n content: '\\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)\n }\n }\n}\n\n// Optional indicator pips\n//\n// Add an unordered list with the following class and add a list item for each\n// slide your carousel holds.\n\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n margin-left: -30%;\n padding-left: 0;\n list-style: none;\n text-align: center;\n\n li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n border: 1px solid @carousel-indicator-border-color;\n border-radius: 10px;\n cursor: pointer;\n\n // IE8-9 hack for event handling\n //\n // Internet Explorer 8-9 does not support clicks on elements without a set\n // `background-color`. We cannot use `filter` since that's not viewed as a\n // background color by the browser. Thus, a hack is needed.\n // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Internet_Explorer\n //\n // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we\n // set alpha transparency for the best results possible.\n background-color: #000 \\9; // IE8\n background-color: rgba(0,0,0,0); // IE9\n }\n .active {\n margin: 0;\n width: 12px;\n height: 12px;\n background-color: @carousel-indicator-active-bg;\n }\n}\n\n// Optional captions\n// -----------------------------\n// Hidden by default for smaller viewports\n.carousel-caption {\n position: absolute;\n left: 15%;\n right: 15%;\n bottom: 20px;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: @carousel-caption-color;\n text-align: center;\n text-shadow: @carousel-text-shadow;\n & .btn {\n text-shadow: none; // No shadow for button elements in carousel-caption\n }\n}\n\n\n// Scale up controls for tablets and up\n@media screen and (min-width: @screen-sm-min) {\n\n // Scale up the controls a smidge\n .carousel-control {\n .glyphicon-chevron-left,\n .glyphicon-chevron-right,\n .icon-prev,\n .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -15px;\n font-size: 30px;\n }\n .glyphicon-chevron-left,\n .icon-prev {\n margin-left: -15px;\n }\n .glyphicon-chevron-right,\n .icon-next {\n margin-right: -15px;\n }\n }\n\n // Show and left align the captions\n .carousel-caption {\n left: 20%;\n right: 20%;\n padding-bottom: 30px;\n }\n\n // Move up the indicators\n .carousel-indicators {\n bottom: 20px;\n }\n}\n","// Clearfix\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n// contenteditable attribute is included anywhere else in the document.\n// Otherwise it causes space to appear at the top and bottom of elements\n// that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n// `:before` to contain the top-margins of child elements.\n//\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n\n.clearfix() {\n &:before,\n &:after {\n content: \" \"; // 1\n display: table; // 2\n }\n &:after {\n clear: both;\n }\n}\n","// Center-align a block level element\n\n.center-block() {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n","// CSS image replacement\n//\n// Heads up! v3 launched with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n font: ~\"0/0\" a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n\n// New mixin to use as of v3.0.1\n.text-hide() {\n .hide-text();\n}\n","//\n// Responsive: Utility classes\n// --------------------------------------------------\n\n\n// IE10 in Windows (Phone) 8\n//\n// Support for responsive views via media queries is kind of borked in IE10, for\n// Surface/desktop in split view and for Windows Phone 8. This particular fix\n// must be accompanied by a snippet of JavaScript to sniff the user agent and\n// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at\n// our Getting Started page for more information on this bug.\n//\n// For more information, see the following:\n//\n// Issue: https://github.com/twbs/bootstrap/issues/10497\n// Docs: http://getbootstrap.com/getting-started/#support-ie10-width\n// Source: http://timkadlec.com/2013/01/windows-phone-8-and-device-width/\n// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/\n\n@-ms-viewport {\n width: device-width;\n}\n\n\n// Visibility utilities\n// Note: Deprecated .visible-xs, .visible-sm, .visible-md, and .visible-lg as of v3.2.0\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n .responsive-invisibility();\n}\n\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n\n.visible-xs {\n @media (max-width: @screen-xs-max) {\n .responsive-visibility();\n }\n}\n.visible-xs-block {\n @media (max-width: @screen-xs-max) {\n display: block !important;\n }\n}\n.visible-xs-inline {\n @media (max-width: @screen-xs-max) {\n display: inline !important;\n }\n}\n.visible-xs-inline-block {\n @media (max-width: @screen-xs-max) {\n display: inline-block !important;\n }\n}\n\n.visible-sm {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n .responsive-visibility();\n }\n}\n.visible-sm-block {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: block !important;\n }\n}\n.visible-sm-inline {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: inline !important;\n }\n}\n.visible-sm-inline-block {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: inline-block !important;\n }\n}\n\n.visible-md {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n .responsive-visibility();\n }\n}\n.visible-md-block {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: block !important;\n }\n}\n.visible-md-inline {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: inline !important;\n }\n}\n.visible-md-inline-block {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: inline-block !important;\n }\n}\n\n.visible-lg {\n @media (min-width: @screen-lg-min) {\n .responsive-visibility();\n }\n}\n.visible-lg-block {\n @media (min-width: @screen-lg-min) {\n display: block !important;\n }\n}\n.visible-lg-inline {\n @media (min-width: @screen-lg-min) {\n display: inline !important;\n }\n}\n.visible-lg-inline-block {\n @media (min-width: @screen-lg-min) {\n display: inline-block !important;\n }\n}\n\n.hidden-xs {\n @media (max-width: @screen-xs-max) {\n .responsive-invisibility();\n }\n}\n.hidden-sm {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n .responsive-invisibility();\n }\n}\n.hidden-md {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n .responsive-invisibility();\n }\n}\n.hidden-lg {\n @media (min-width: @screen-lg-min) {\n .responsive-invisibility();\n }\n}\n\n\n// Print utilities\n//\n// Media queries are placed on the inside to be mixin-friendly.\n\n// Note: Deprecated .visible-print as of v3.2.0\n.visible-print {\n .responsive-invisibility();\n\n @media print {\n .responsive-visibility();\n }\n}\n.visible-print-block {\n display: none !important;\n\n @media print {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n\n @media print {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n\n @media print {\n display: inline-block !important;\n }\n}\n\n.hidden-print {\n @media print {\n .responsive-invisibility();\n }\n}\n","// Responsive utilities\n\n//\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n display: block !important;\n table& { display: table !important; }\n tr& { display: table-row !important; }\n th&,\n td& { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n display: none !important;\n}\n"]} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap.min.css b/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap.min.css
new file mode 100644
index 0000000..d65c66b
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/bootstrap3/css/bootstrap.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:3;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.eot b/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 0000000..b93a495
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.eot
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.svg b/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 0000000..94fb549
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,288 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
+<font-face units-per-em="1200" ascent="960" descent="-240" />
+<missing-glyph horiz-adv-x="500" />
+<glyph horiz-adv-x="0" />
+<glyph horiz-adv-x="400" />
+<glyph unicode=" " />
+<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z" />
+<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xa0;" />
+<glyph unicode="&#xa5;" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" />
+<glyph unicode="&#x2000;" horiz-adv-x="650" />
+<glyph unicode="&#x2001;" horiz-adv-x="1300" />
+<glyph unicode="&#x2002;" horiz-adv-x="650" />
+<glyph unicode="&#x2003;" horiz-adv-x="1300" />
+<glyph unicode="&#x2004;" horiz-adv-x="433" />
+<glyph unicode="&#x2005;" horiz-adv-x="325" />
+<glyph unicode="&#x2006;" horiz-adv-x="216" />
+<glyph unicode="&#x2007;" horiz-adv-x="216" />
+<glyph unicode="&#x2008;" horiz-adv-x="162" />
+<glyph unicode="&#x2009;" horiz-adv-x="260" />
+<glyph unicode="&#x200a;" horiz-adv-x="72" />
+<glyph unicode="&#x202f;" horiz-adv-x="260" />
+<glyph unicode="&#x205f;" horiz-adv-x="325" />
+<glyph unicode="&#x20ac;" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z" />
+<glyph unicode="&#x20bd;" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z" />
+<glyph unicode="&#x2212;" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#x231b;" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#x2601;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" />
+<glyph unicode="&#x26fa;" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " />
+<glyph unicode="&#x2709;" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" />
+<glyph unicode="&#x270f;" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" />
+<glyph unicode="&#xe001;" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" />
+<glyph unicode="&#xe002;" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" />
+<glyph unicode="&#xe003;" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" />
+<glyph unicode="&#xe005;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" />
+<glyph unicode="&#xe006;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" />
+<glyph unicode="&#xe007;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" />
+<glyph unicode="&#xe008;" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" />
+<glyph unicode="&#xe009;" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z" />
+<glyph unicode="&#xe010;" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe011;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z" />
+<glyph unicode="&#xe012;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe013;" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" />
+<glyph unicode="&#xe014;" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" />
+<glyph unicode="&#xe015;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe016;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe017;" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" />
+<glyph unicode="&#xe018;" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe019;" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z" />
+<glyph unicode="&#xe020;" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" />
+<glyph unicode="&#xe021;" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" />
+<glyph unicode="&#xe022;" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" />
+<glyph unicode="&#xe023;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe024;" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" />
+<glyph unicode="&#xe025;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe026;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z " />
+<glyph unicode="&#xe027;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z" />
+<glyph unicode="&#xe028;" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" />
+<glyph unicode="&#xe029;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
+<glyph unicode="&#xe030;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" />
+<glyph unicode="&#xe031;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z" />
+<glyph unicode="&#xe032;" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe033;" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" />
+<glyph unicode="&#xe034;" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" />
+<glyph unicode="&#xe035;" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z" />
+<glyph unicode="&#xe036;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" />
+<glyph unicode="&#xe037;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" />
+<glyph unicode="&#xe038;" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z" />
+<glyph unicode="&#xe039;" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z" />
+<glyph unicode="&#xe040;" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" />
+<glyph unicode="&#xe041;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
+<glyph unicode="&#xe042;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
+<glyph unicode="&#xe043;" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" />
+<glyph unicode="&#xe044;" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe045;" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z" />
+<glyph unicode="&#xe046;" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" />
+<glyph unicode="&#xe047;" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" />
+<glyph unicode="&#xe048;" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z" />
+<glyph unicode="&#xe049;" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" />
+<glyph unicode="&#xe050;" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" />
+<glyph unicode="&#xe051;" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" />
+<glyph unicode="&#xe052;" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe053;" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe054;" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe055;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe056;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe057;" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe058;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe059;" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" />
+<glyph unicode="&#xe060;" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" />
+<glyph unicode="&#xe062;" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" />
+<glyph unicode="&#xe063;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" />
+<glyph unicode="&#xe064;" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z" />
+<glyph unicode="&#xe065;" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" />
+<glyph unicode="&#xe066;" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z" />
+<glyph unicode="&#xe067;" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" />
+<glyph unicode="&#xe068;" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" />
+<glyph unicode="&#xe069;" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe070;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe071;" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" />
+<glyph unicode="&#xe072;" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" />
+<glyph unicode="&#xe073;" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe074;" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" />
+<glyph unicode="&#xe075;" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" />
+<glyph unicode="&#xe076;" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe077;" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe078;" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe079;" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" />
+<glyph unicode="&#xe080;" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" />
+<glyph unicode="&#xe081;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z" />
+<glyph unicode="&#xe082;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" />
+<glyph unicode="&#xe083;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z" />
+<glyph unicode="&#xe084;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" />
+<glyph unicode="&#xe085;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe086;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe087;" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z" />
+<glyph unicode="&#xe088;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="&#xe089;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="&#xe090;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" />
+<glyph unicode="&#xe091;" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" />
+<glyph unicode="&#xe092;" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" />
+<glyph unicode="&#xe093;" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" />
+<glyph unicode="&#xe094;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe095;" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" />
+<glyph unicode="&#xe096;" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" />
+<glyph unicode="&#xe097;" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" />
+<glyph unicode="&#xe101;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe102;" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z" />
+<glyph unicode="&#xe103;" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z" />
+<glyph unicode="&#xe104;" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z" />
+<glyph unicode="&#xe105;" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
+<glyph unicode="&#xe106;" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
+<glyph unicode="&#xe107;" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" />
+<glyph unicode="&#xe108;" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" />
+<glyph unicode="&#xe109;" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z" />
+<glyph unicode="&#xe110;" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" />
+<glyph unicode="&#xe111;" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" />
+<glyph unicode="&#xe112;" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" />
+<glyph unicode="&#xe113;" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" />
+<glyph unicode="&#xe114;" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" />
+<glyph unicode="&#xe115;" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe116;" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" />
+<glyph unicode="&#xe117;" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" />
+<glyph unicode="&#xe118;" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" />
+<glyph unicode="&#xe119;" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe120;" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" />
+<glyph unicode="&#xe121;" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" />
+<glyph unicode="&#xe122;" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" />
+<glyph unicode="&#xe123;" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" />
+<glyph unicode="&#xe124;" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" />
+<glyph unicode="&#xe125;" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe126;" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z" />
+<glyph unicode="&#xe127;" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe128;" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe129;" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe130;" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z" />
+<glyph unicode="&#xe131;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" />
+<glyph unicode="&#xe132;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" />
+<glyph unicode="&#xe133;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" />
+<glyph unicode="&#xe134;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe135;" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z" />
+<glyph unicode="&#xe136;" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" />
+<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " />
+<glyph unicode="&#xe138;" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" />
+<glyph unicode="&#xe139;" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" />
+<glyph unicode="&#xe140;" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z" />
+<glyph unicode="&#xe141;" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z" />
+<glyph unicode="&#xe142;" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z" />
+<glyph unicode="&#xe143;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z" />
+<glyph unicode="&#xe144;" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" />
+<glyph unicode="&#xe145;" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" />
+<glyph unicode="&#xe146;" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" />
+<glyph unicode="&#xe148;" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z" />
+<glyph unicode="&#xe149;" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z" />
+<glyph unicode="&#xe150;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe151;" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " />
+<glyph unicode="&#xe152;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " />
+<glyph unicode="&#xe153;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" />
+<glyph unicode="&#xe154;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" />
+<glyph unicode="&#xe155;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" />
+<glyph unicode="&#xe156;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" />
+<glyph unicode="&#xe157;" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" />
+<glyph unicode="&#xe158;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
+<glyph unicode="&#xe159;" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" />
+<glyph unicode="&#xe160;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" />
+<glyph unicode="&#xe161;" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
+<glyph unicode="&#xe162;" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" />
+<glyph unicode="&#xe163;" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
+<glyph unicode="&#xe164;" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" />
+<glyph unicode="&#xe165;" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" />
+<glyph unicode="&#xe166;" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe167;" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe168;" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" />
+<glyph unicode="&#xe169;" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe170;" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe171;" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" />
+<glyph unicode="&#xe172;" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" />
+<glyph unicode="&#xe173;" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="&#xe174;" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z" />
+<glyph unicode="&#xe175;" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe176;" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe177;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" />
+<glyph unicode="&#xe178;" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" />
+<glyph unicode="&#xe179;" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z" />
+<glyph unicode="&#xe180;" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" />
+<glyph unicode="&#xe181;" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" />
+<glyph unicode="&#xe182;" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" />
+<glyph unicode="&#xe183;" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z" />
+<glyph unicode="&#xe184;" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe185;" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " />
+<glyph unicode="&#xe186;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
+<glyph unicode="&#xe187;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
+<glyph unicode="&#xe188;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" />
+<glyph unicode="&#xe189;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" />
+<glyph unicode="&#xe190;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" />
+<glyph unicode="&#xe191;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" />
+<glyph unicode="&#xe192;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" />
+<glyph unicode="&#xe193;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" />
+<glyph unicode="&#xe194;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" />
+<glyph unicode="&#xe195;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" />
+<glyph unicode="&#xe197;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe198;" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" />
+<glyph unicode="&#xe199;" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" />
+<glyph unicode="&#xe200;" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" />
+<glyph unicode="&#xe201;" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z" />
+<glyph unicode="&#xe202;" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" />
+<glyph unicode="&#xe203;" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" />
+<glyph unicode="&#xe204;" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" />
+<glyph unicode="&#xe205;" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" />
+<glyph unicode="&#xe206;" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" />
+<glyph unicode="&#xe209;" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" />
+<glyph unicode="&#xe210;" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe211;" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe212;" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe213;" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe214;" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe215;" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe216;" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" />
+<glyph unicode="&#xe218;" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" />
+<glyph unicode="&#xe219;" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z" />
+<glyph unicode="&#xe221;" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe223;" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" />
+<glyph unicode="&#xe224;" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " />
+<glyph unicode="&#xe225;" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe226;" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z" />
+<glyph unicode="&#xe227;" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z" />
+<glyph unicode="&#xe230;" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" />
+<glyph unicode="&#xe231;" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
+<glyph unicode="&#xe232;" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
+<glyph unicode="&#xe233;" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" />
+<glyph unicode="&#xe234;" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
+<glyph unicode="&#xe235;" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
+<glyph unicode="&#xe236;" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe237;" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" />
+<glyph unicode="&#xe238;" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe239;" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" />
+<glyph unicode="&#xe240;" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z" />
+<glyph unicode="&#xe241;" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" />
+<glyph unicode="&#xe242;" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" />
+<glyph unicode="&#xe243;" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z" />
+<glyph unicode="&#xe244;" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" />
+<glyph unicode="&#xe245;" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" />
+<glyph unicode="&#xe246;" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" />
+<glyph unicode="&#xe247;" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe248;" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" />
+<glyph unicode="&#xe249;" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe250;" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" />
+<glyph unicode="&#xe251;" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" />
+<glyph unicode="&#xe252;" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" />
+<glyph unicode="&#xe253;" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" />
+<glyph unicode="&#xe254;" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" />
+<glyph unicode="&#xe255;" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" />
+<glyph unicode="&#xe256;" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" />
+<glyph unicode="&#xe257;" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" />
+<glyph unicode="&#xe258;" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" />
+<glyph unicode="&#xe259;" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" />
+<glyph unicode="&#xe260;" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" />
+<glyph unicode="&#xf8ff;" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z" />
+<glyph unicode="&#x1f511;" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" />
+<glyph unicode="&#x1f6aa;" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" />
+</font>
+</defs></svg> \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.ttf b/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 0000000..1413fc6
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.ttf
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.woff b/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 0000000..9e61285
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.woff
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.woff2 b/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.woff2
new file mode 100644
index 0000000..64539b5
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/bootstrap3/fonts/glyphicons-halflings-regular.woff2
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/bootstrap3/js/bootstrap.js b/lib/prado/framework/Web/Javascripts/source/bootstrap3/js/bootstrap.js
new file mode 100644
index 0000000..5debfd7
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/bootstrap3/js/bootstrap.js
@@ -0,0 +1,2363 @@
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under the MIT license
+ */
+
+if (typeof jQuery === 'undefined') {
+ throw new Error('Bootstrap\'s JavaScript requires jQuery')
+}
+
++function ($) {
+ 'use strict';
+ var version = $.fn.jquery.split(' ')[0].split('.')
+ if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) {
+ throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher')
+ }
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: transition.js v3.3.5
+ * http://getbootstrap.com/javascript/#transitions
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
+ // ============================================================
+
+ function transitionEnd() {
+ var el = document.createElement('bootstrap')
+
+ var transEndEventNames = {
+ WebkitTransition : 'webkitTransitionEnd',
+ MozTransition : 'transitionend',
+ OTransition : 'oTransitionEnd otransitionend',
+ transition : 'transitionend'
+ }
+
+ for (var name in transEndEventNames) {
+ if (el.style[name] !== undefined) {
+ return { end: transEndEventNames[name] }
+ }
+ }
+
+ return false // explicit for ie8 ( ._.)
+ }
+
+ // http://blog.alexmaccaw.com/css-transitions
+ $.fn.emulateTransitionEnd = function (duration) {
+ var called = false
+ var $el = this
+ $(this).one('bsTransitionEnd', function () { called = true })
+ var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
+ setTimeout(callback, duration)
+ return this
+ }
+
+ $(function () {
+ $.support.transition = transitionEnd()
+
+ if (!$.support.transition) return
+
+ $.event.special.bsTransitionEnd = {
+ bindType: $.support.transition.end,
+ delegateType: $.support.transition.end,
+ handle: function (e) {
+ if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
+ }
+ }
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: alert.js v3.3.5
+ * http://getbootstrap.com/javascript/#alerts
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // ALERT CLASS DEFINITION
+ // ======================
+
+ var dismiss = '[data-dismiss="alert"]'
+ var Alert = function (el) {
+ $(el).on('click', dismiss, this.close)
+ }
+
+ Alert.VERSION = '3.3.5'
+
+ Alert.TRANSITION_DURATION = 150
+
+ Alert.prototype.close = function (e) {
+ var $this = $(this)
+ var selector = $this.attr('data-target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+ }
+
+ var $parent = $(selector)
+
+ if (e) e.preventDefault()
+
+ if (!$parent.length) {
+ $parent = $this.closest('.alert')
+ }
+
+ $parent.trigger(e = $.Event('close.bs.alert'))
+
+ if (e.isDefaultPrevented()) return
+
+ $parent.removeClass('in')
+
+ function removeElement() {
+ // detach from parent, fire event then clean up data
+ $parent.detach().trigger('closed.bs.alert').remove()
+ }
+
+ $.support.transition && $parent.hasClass('fade') ?
+ $parent
+ .one('bsTransitionEnd', removeElement)
+ .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
+ removeElement()
+ }
+
+
+ // ALERT PLUGIN DEFINITION
+ // =======================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.alert')
+
+ if (!data) $this.data('bs.alert', (data = new Alert(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ var old = $.fn.alert
+
+ $.fn.alert = Plugin
+ $.fn.alert.Constructor = Alert
+
+
+ // ALERT NO CONFLICT
+ // =================
+
+ $.fn.alert.noConflict = function () {
+ $.fn.alert = old
+ return this
+ }
+
+
+ // ALERT DATA-API
+ // ==============
+
+ $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: button.js v3.3.5
+ * http://getbootstrap.com/javascript/#buttons
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // BUTTON PUBLIC CLASS DEFINITION
+ // ==============================
+
+ var Button = function (element, options) {
+ this.$element = $(element)
+ this.options = $.extend({}, Button.DEFAULTS, options)
+ this.isLoading = false
+ }
+
+ Button.VERSION = '3.3.5'
+
+ Button.DEFAULTS = {
+ loadingText: 'loading...'
+ }
+
+ Button.prototype.setState = function (state) {
+ var d = 'disabled'
+ var $el = this.$element
+ var val = $el.is('input') ? 'val' : 'html'
+ var data = $el.data()
+
+ state += 'Text'
+
+ if (data.resetText == null) $el.data('resetText', $el[val]())
+
+ // push to event loop to allow forms to submit
+ setTimeout($.proxy(function () {
+ $el[val](data[state] == null ? this.options[state] : data[state])
+
+ if (state == 'loadingText') {
+ this.isLoading = true
+ $el.addClass(d).attr(d, d)
+ } else if (this.isLoading) {
+ this.isLoading = false
+ $el.removeClass(d).removeAttr(d)
+ }
+ }, this), 0)
+ }
+
+ Button.prototype.toggle = function () {
+ var changed = true
+ var $parent = this.$element.closest('[data-toggle="buttons"]')
+
+ if ($parent.length) {
+ var $input = this.$element.find('input')
+ if ($input.prop('type') == 'radio') {
+ if ($input.prop('checked')) changed = false
+ $parent.find('.active').removeClass('active')
+ this.$element.addClass('active')
+ } else if ($input.prop('type') == 'checkbox') {
+ if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
+ this.$element.toggleClass('active')
+ }
+ $input.prop('checked', this.$element.hasClass('active'))
+ if (changed) $input.trigger('change')
+ } else {
+ this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
+ this.$element.toggleClass('active')
+ }
+ }
+
+
+ // BUTTON PLUGIN DEFINITION
+ // ========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.button')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.button', (data = new Button(this, options)))
+
+ if (option == 'toggle') data.toggle()
+ else if (option) data.setState(option)
+ })
+ }
+
+ var old = $.fn.button
+
+ $.fn.button = Plugin
+ $.fn.button.Constructor = Button
+
+
+ // BUTTON NO CONFLICT
+ // ==================
+
+ $.fn.button.noConflict = function () {
+ $.fn.button = old
+ return this
+ }
+
+
+ // BUTTON DATA-API
+ // ===============
+
+ $(document)
+ .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
+ var $btn = $(e.target)
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
+ Plugin.call($btn, 'toggle')
+ if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault()
+ })
+ .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
+ $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: carousel.js v3.3.5
+ * http://getbootstrap.com/javascript/#carousel
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // CAROUSEL CLASS DEFINITION
+ // =========================
+
+ var Carousel = function (element, options) {
+ this.$element = $(element)
+ this.$indicators = this.$element.find('.carousel-indicators')
+ this.options = options
+ this.paused = null
+ this.sliding = null
+ this.interval = null
+ this.$active = null
+ this.$items = null
+
+ this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
+
+ this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
+ .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
+ .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
+ }
+
+ Carousel.VERSION = '3.3.5'
+
+ Carousel.TRANSITION_DURATION = 600
+
+ Carousel.DEFAULTS = {
+ interval: 5000,
+ pause: 'hover',
+ wrap: true,
+ keyboard: true
+ }
+
+ Carousel.prototype.keydown = function (e) {
+ if (/input|textarea/i.test(e.target.tagName)) return
+ switch (e.which) {
+ case 37: this.prev(); break
+ case 39: this.next(); break
+ default: return
+ }
+
+ e.preventDefault()
+ }
+
+ Carousel.prototype.cycle = function (e) {
+ e || (this.paused = false)
+
+ this.interval && clearInterval(this.interval)
+
+ this.options.interval
+ && !this.paused
+ && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
+
+ return this
+ }
+
+ Carousel.prototype.getItemIndex = function (item) {
+ this.$items = item.parent().children('.item')
+ return this.$items.index(item || this.$active)
+ }
+
+ Carousel.prototype.getItemForDirection = function (direction, active) {
+ var activeIndex = this.getItemIndex(active)
+ var willWrap = (direction == 'prev' && activeIndex === 0)
+ || (direction == 'next' && activeIndex == (this.$items.length - 1))
+ if (willWrap && !this.options.wrap) return active
+ var delta = direction == 'prev' ? -1 : 1
+ var itemIndex = (activeIndex + delta) % this.$items.length
+ return this.$items.eq(itemIndex)
+ }
+
+ Carousel.prototype.to = function (pos) {
+ var that = this
+ var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
+
+ if (pos > (this.$items.length - 1) || pos < 0) return
+
+ if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
+ if (activeIndex == pos) return this.pause().cycle()
+
+ return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
+ }
+
+ Carousel.prototype.pause = function (e) {
+ e || (this.paused = true)
+
+ if (this.$element.find('.next, .prev').length && $.support.transition) {
+ this.$element.trigger($.support.transition.end)
+ this.cycle(true)
+ }
+
+ this.interval = clearInterval(this.interval)
+
+ return this
+ }
+
+ Carousel.prototype.next = function () {
+ if (this.sliding) return
+ return this.slide('next')
+ }
+
+ Carousel.prototype.prev = function () {
+ if (this.sliding) return
+ return this.slide('prev')
+ }
+
+ Carousel.prototype.slide = function (type, next) {
+ var $active = this.$element.find('.item.active')
+ var $next = next || this.getItemForDirection(type, $active)
+ var isCycling = this.interval
+ var direction = type == 'next' ? 'left' : 'right'
+ var that = this
+
+ if ($next.hasClass('active')) return (this.sliding = false)
+
+ var relatedTarget = $next[0]
+ var slideEvent = $.Event('slide.bs.carousel', {
+ relatedTarget: relatedTarget,
+ direction: direction
+ })
+ this.$element.trigger(slideEvent)
+ if (slideEvent.isDefaultPrevented()) return
+
+ this.sliding = true
+
+ isCycling && this.pause()
+
+ if (this.$indicators.length) {
+ this.$indicators.find('.active').removeClass('active')
+ var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
+ $nextIndicator && $nextIndicator.addClass('active')
+ }
+
+ var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
+ if ($.support.transition && this.$element.hasClass('slide')) {
+ $next.addClass(type)
+ $next[0].offsetWidth // force reflow
+ $active.addClass(direction)
+ $next.addClass(direction)
+ $active
+ .one('bsTransitionEnd', function () {
+ $next.removeClass([type, direction].join(' ')).addClass('active')
+ $active.removeClass(['active', direction].join(' '))
+ that.sliding = false
+ setTimeout(function () {
+ that.$element.trigger(slidEvent)
+ }, 0)
+ })
+ .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
+ } else {
+ $active.removeClass('active')
+ $next.addClass('active')
+ this.sliding = false
+ this.$element.trigger(slidEvent)
+ }
+
+ isCycling && this.cycle()
+
+ return this
+ }
+
+
+ // CAROUSEL PLUGIN DEFINITION
+ // ==========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.carousel')
+ var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
+ var action = typeof option == 'string' ? option : options.slide
+
+ if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
+ if (typeof option == 'number') data.to(option)
+ else if (action) data[action]()
+ else if (options.interval) data.pause().cycle()
+ })
+ }
+
+ var old = $.fn.carousel
+
+ $.fn.carousel = Plugin
+ $.fn.carousel.Constructor = Carousel
+
+
+ // CAROUSEL NO CONFLICT
+ // ====================
+
+ $.fn.carousel.noConflict = function () {
+ $.fn.carousel = old
+ return this
+ }
+
+
+ // CAROUSEL DATA-API
+ // =================
+
+ var clickHandler = function (e) {
+ var href
+ var $this = $(this)
+ var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
+ if (!$target.hasClass('carousel')) return
+ var options = $.extend({}, $target.data(), $this.data())
+ var slideIndex = $this.attr('data-slide-to')
+ if (slideIndex) options.interval = false
+
+ Plugin.call($target, options)
+
+ if (slideIndex) {
+ $target.data('bs.carousel').to(slideIndex)
+ }
+
+ e.preventDefault()
+ }
+
+ $(document)
+ .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
+ .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
+
+ $(window).on('load', function () {
+ $('[data-ride="carousel"]').each(function () {
+ var $carousel = $(this)
+ Plugin.call($carousel, $carousel.data())
+ })
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: collapse.js v3.3.5
+ * http://getbootstrap.com/javascript/#collapse
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // COLLAPSE PUBLIC CLASS DEFINITION
+ // ================================
+
+ var Collapse = function (element, options) {
+ this.$element = $(element)
+ this.options = $.extend({}, Collapse.DEFAULTS, options)
+ this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
+ '[data-toggle="collapse"][data-target="#' + element.id + '"]')
+ this.transitioning = null
+
+ if (this.options.parent) {
+ this.$parent = this.getParent()
+ } else {
+ this.addAriaAndCollapsedClass(this.$element, this.$trigger)
+ }
+
+ if (this.options.toggle) this.toggle()
+ }
+
+ Collapse.VERSION = '3.3.5'
+
+ Collapse.TRANSITION_DURATION = 350
+
+ Collapse.DEFAULTS = {
+ toggle: true
+ }
+
+ Collapse.prototype.dimension = function () {
+ var hasWidth = this.$element.hasClass('width')
+ return hasWidth ? 'width' : 'height'
+ }
+
+ Collapse.prototype.show = function () {
+ if (this.transitioning || this.$element.hasClass('in')) return
+
+ var activesData
+ var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
+
+ if (actives && actives.length) {
+ activesData = actives.data('bs.collapse')
+ if (activesData && activesData.transitioning) return
+ }
+
+ var startEvent = $.Event('show.bs.collapse')
+ this.$element.trigger(startEvent)
+ if (startEvent.isDefaultPrevented()) return
+
+ if (actives && actives.length) {
+ Plugin.call(actives, 'hide')
+ activesData || actives.data('bs.collapse', null)
+ }
+
+ var dimension = this.dimension()
+
+ this.$element
+ .removeClass('collapse')
+ .addClass('collapsing')[dimension](0)
+ .attr('aria-expanded', true)
+
+ this.$trigger
+ .removeClass('collapsed')
+ .attr('aria-expanded', true)
+
+ this.transitioning = 1
+
+ var complete = function () {
+ this.$element
+ .removeClass('collapsing')
+ .addClass('collapse in')[dimension]('')
+ this.transitioning = 0
+ this.$element
+ .trigger('shown.bs.collapse')
+ }
+
+ if (!$.support.transition) return complete.call(this)
+
+ var scrollSize = $.camelCase(['scroll', dimension].join('-'))
+
+ this.$element
+ .one('bsTransitionEnd', $.proxy(complete, this))
+ .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
+ }
+
+ Collapse.prototype.hide = function () {
+ if (this.transitioning || !this.$element.hasClass('in')) return
+
+ var startEvent = $.Event('hide.bs.collapse')
+ this.$element.trigger(startEvent)
+ if (startEvent.isDefaultPrevented()) return
+
+ var dimension = this.dimension()
+
+ this.$element[dimension](this.$element[dimension]())[0].offsetHeight
+
+ this.$element
+ .addClass('collapsing')
+ .removeClass('collapse in')
+ .attr('aria-expanded', false)
+
+ this.$trigger
+ .addClass('collapsed')
+ .attr('aria-expanded', false)
+
+ this.transitioning = 1
+
+ var complete = function () {
+ this.transitioning = 0
+ this.$element
+ .removeClass('collapsing')
+ .addClass('collapse')
+ .trigger('hidden.bs.collapse')
+ }
+
+ if (!$.support.transition) return complete.call(this)
+
+ this.$element
+ [dimension](0)
+ .one('bsTransitionEnd', $.proxy(complete, this))
+ .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
+ }
+
+ Collapse.prototype.toggle = function () {
+ this[this.$element.hasClass('in') ? 'hide' : 'show']()
+ }
+
+ Collapse.prototype.getParent = function () {
+ return $(this.options.parent)
+ .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
+ .each($.proxy(function (i, element) {
+ var $element = $(element)
+ this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
+ }, this))
+ .end()
+ }
+
+ Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
+ var isOpen = $element.hasClass('in')
+
+ $element.attr('aria-expanded', isOpen)
+ $trigger
+ .toggleClass('collapsed', !isOpen)
+ .attr('aria-expanded', isOpen)
+ }
+
+ function getTargetFromTrigger($trigger) {
+ var href
+ var target = $trigger.attr('data-target')
+ || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
+
+ return $(target)
+ }
+
+
+ // COLLAPSE PLUGIN DEFINITION
+ // ==========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.collapse')
+ var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+ if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
+ if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.collapse
+
+ $.fn.collapse = Plugin
+ $.fn.collapse.Constructor = Collapse
+
+
+ // COLLAPSE NO CONFLICT
+ // ====================
+
+ $.fn.collapse.noConflict = function () {
+ $.fn.collapse = old
+ return this
+ }
+
+
+ // COLLAPSE DATA-API
+ // =================
+
+ $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
+ var $this = $(this)
+
+ if (!$this.attr('data-target')) e.preventDefault()
+
+ var $target = getTargetFromTrigger($this)
+ var data = $target.data('bs.collapse')
+ var option = data ? 'toggle' : $this.data()
+
+ Plugin.call($target, option)
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: dropdown.js v3.3.5
+ * http://getbootstrap.com/javascript/#dropdowns
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // DROPDOWN CLASS DEFINITION
+ // =========================
+
+ var backdrop = '.dropdown-backdrop'
+ var toggle = '[data-toggle="dropdown"]'
+ var Dropdown = function (element) {
+ $(element).on('click.bs.dropdown', this.toggle)
+ }
+
+ Dropdown.VERSION = '3.3.5'
+
+ function getParent($this) {
+ var selector = $this.attr('data-target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+ }
+
+ var $parent = selector && $(selector)
+
+ return $parent && $parent.length ? $parent : $this.parent()
+ }
+
+ function clearMenus(e) {
+ if (e && e.which === 3) return
+ $(backdrop).remove()
+ $(toggle).each(function () {
+ var $this = $(this)
+ var $parent = getParent($this)
+ var relatedTarget = { relatedTarget: this }
+
+ if (!$parent.hasClass('open')) return
+
+ if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
+
+ $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
+
+ if (e.isDefaultPrevented()) return
+
+ $this.attr('aria-expanded', 'false')
+ $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
+ })
+ }
+
+ Dropdown.prototype.toggle = function (e) {
+ var $this = $(this)
+
+ if ($this.is('.disabled, :disabled')) return
+
+ var $parent = getParent($this)
+ var isActive = $parent.hasClass('open')
+
+ clearMenus()
+
+ if (!isActive) {
+ if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
+ // if mobile we use a backdrop because click events don't delegate
+ $(document.createElement('div'))
+ .addClass('dropdown-backdrop')
+ .insertAfter($(this))
+ .on('click', clearMenus)
+ }
+
+ var relatedTarget = { relatedTarget: this }
+ $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
+
+ if (e.isDefaultPrevented()) return
+
+ $this
+ .trigger('focus')
+ .attr('aria-expanded', 'true')
+
+ $parent
+ .toggleClass('open')
+ .trigger('shown.bs.dropdown', relatedTarget)
+ }
+
+ return false
+ }
+
+ Dropdown.prototype.keydown = function (e) {
+ if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
+
+ var $this = $(this)
+
+ e.preventDefault()
+ e.stopPropagation()
+
+ if ($this.is('.disabled, :disabled')) return
+
+ var $parent = getParent($this)
+ var isActive = $parent.hasClass('open')
+
+ if (!isActive && e.which != 27 || isActive && e.which == 27) {
+ if (e.which == 27) $parent.find(toggle).trigger('focus')
+ return $this.trigger('click')
+ }
+
+ var desc = ' li:not(.disabled):visible a'
+ var $items = $parent.find('.dropdown-menu' + desc)
+
+ if (!$items.length) return
+
+ var index = $items.index(e.target)
+
+ if (e.which == 38 && index > 0) index-- // up
+ if (e.which == 40 && index < $items.length - 1) index++ // down
+ if (!~index) index = 0
+
+ $items.eq(index).trigger('focus')
+ }
+
+
+ // DROPDOWN PLUGIN DEFINITION
+ // ==========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.dropdown')
+
+ if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ var old = $.fn.dropdown
+
+ $.fn.dropdown = Plugin
+ $.fn.dropdown.Constructor = Dropdown
+
+
+ // DROPDOWN NO CONFLICT
+ // ====================
+
+ $.fn.dropdown.noConflict = function () {
+ $.fn.dropdown = old
+ return this
+ }
+
+
+ // APPLY TO STANDARD DROPDOWN ELEMENTS
+ // ===================================
+
+ $(document)
+ .on('click.bs.dropdown.data-api', clearMenus)
+ .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
+ .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+ .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
+ .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: modal.js v3.3.5
+ * http://getbootstrap.com/javascript/#modals
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // MODAL CLASS DEFINITION
+ // ======================
+
+ var Modal = function (element, options) {
+ this.options = options
+ this.$body = $(document.body)
+ this.$element = $(element)
+ this.$dialog = this.$element.find('.modal-dialog')
+ this.$backdrop = null
+ this.isShown = null
+ this.originalBodyPad = null
+ this.scrollbarWidth = 0
+ this.ignoreBackdropClick = false
+
+ if (this.options.remote) {
+ this.$element
+ .find('.modal-content')
+ .load(this.options.remote, $.proxy(function () {
+ this.$element.trigger('loaded.bs.modal')
+ }, this))
+ }
+ }
+
+ Modal.VERSION = '3.3.5'
+
+ Modal.TRANSITION_DURATION = 300
+ Modal.BACKDROP_TRANSITION_DURATION = 150
+
+ Modal.DEFAULTS = {
+ backdrop: true,
+ keyboard: true,
+ show: true
+ }
+
+ Modal.prototype.toggle = function (_relatedTarget) {
+ return this.isShown ? this.hide() : this.show(_relatedTarget)
+ }
+
+ Modal.prototype.show = function (_relatedTarget) {
+ var that = this
+ var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
+
+ this.$element.trigger(e)
+
+ if (this.isShown || e.isDefaultPrevented()) return
+
+ this.isShown = true
+
+ this.checkScrollbar()
+ this.setScrollbar()
+ this.$body.addClass('modal-open')
+
+ this.escape()
+ this.resize()
+
+ this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
+
+ this.$dialog.on('mousedown.dismiss.bs.modal', function () {
+ that.$element.one('mouseup.dismiss.bs.modal', function (e) {
+ if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
+ })
+ })
+
+ this.backdrop(function () {
+ var transition = $.support.transition && that.$element.hasClass('fade')
+
+ if (!that.$element.parent().length) {
+ that.$element.appendTo(that.$body) // don't move modals dom position
+ }
+
+ that.$element
+ .show()
+ .scrollTop(0)
+
+ that.adjustDialog()
+
+ if (transition) {
+ that.$element[0].offsetWidth // force reflow
+ }
+
+ that.$element.addClass('in')
+
+ that.enforceFocus()
+
+ var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
+
+ transition ?
+ that.$dialog // wait for modal to slide in
+ .one('bsTransitionEnd', function () {
+ that.$element.trigger('focus').trigger(e)
+ })
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
+ that.$element.trigger('focus').trigger(e)
+ })
+ }
+
+ Modal.prototype.hide = function (e) {
+ if (e) e.preventDefault()
+
+ e = $.Event('hide.bs.modal')
+
+ this.$element.trigger(e)
+
+ if (!this.isShown || e.isDefaultPrevented()) return
+
+ this.isShown = false
+
+ this.escape()
+ this.resize()
+
+ $(document).off('focusin.bs.modal')
+
+ this.$element
+ .removeClass('in')
+ .off('click.dismiss.bs.modal')
+ .off('mouseup.dismiss.bs.modal')
+
+ this.$dialog.off('mousedown.dismiss.bs.modal')
+
+ $.support.transition && this.$element.hasClass('fade') ?
+ this.$element
+ .one('bsTransitionEnd', $.proxy(this.hideModal, this))
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
+ this.hideModal()
+ }
+
+ Modal.prototype.enforceFocus = function () {
+ $(document)
+ .off('focusin.bs.modal') // guard against infinite focus loop
+ .on('focusin.bs.modal', $.proxy(function (e) {
+ if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
+ this.$element.trigger('focus')
+ }
+ }, this))
+ }
+
+ Modal.prototype.escape = function () {
+ if (this.isShown && this.options.keyboard) {
+ this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
+ e.which == 27 && this.hide()
+ }, this))
+ } else if (!this.isShown) {
+ this.$element.off('keydown.dismiss.bs.modal')
+ }
+ }
+
+ Modal.prototype.resize = function () {
+ if (this.isShown) {
+ $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
+ } else {
+ $(window).off('resize.bs.modal')
+ }
+ }
+
+ Modal.prototype.hideModal = function () {
+ var that = this
+ this.$element.hide()
+ this.backdrop(function () {
+ that.$body.removeClass('modal-open')
+ that.resetAdjustments()
+ that.resetScrollbar()
+ that.$element.trigger('hidden.bs.modal')
+ })
+ }
+
+ Modal.prototype.removeBackdrop = function () {
+ this.$backdrop && this.$backdrop.remove()
+ this.$backdrop = null
+ }
+
+ Modal.prototype.backdrop = function (callback) {
+ var that = this
+ var animate = this.$element.hasClass('fade') ? 'fade' : ''
+
+ if (this.isShown && this.options.backdrop) {
+ var doAnimate = $.support.transition && animate
+
+ this.$backdrop = $(document.createElement('div'))
+ .addClass('modal-backdrop ' + animate)
+ .appendTo(this.$body)
+
+ this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
+ if (this.ignoreBackdropClick) {
+ this.ignoreBackdropClick = false
+ return
+ }
+ if (e.target !== e.currentTarget) return
+ this.options.backdrop == 'static'
+ ? this.$element[0].focus()
+ : this.hide()
+ }, this))
+
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+
+ this.$backdrop.addClass('in')
+
+ if (!callback) return
+
+ doAnimate ?
+ this.$backdrop
+ .one('bsTransitionEnd', callback)
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
+ callback()
+
+ } else if (!this.isShown && this.$backdrop) {
+ this.$backdrop.removeClass('in')
+
+ var callbackRemove = function () {
+ that.removeBackdrop()
+ callback && callback()
+ }
+ $.support.transition && this.$element.hasClass('fade') ?
+ this.$backdrop
+ .one('bsTransitionEnd', callbackRemove)
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
+ callbackRemove()
+
+ } else if (callback) {
+ callback()
+ }
+ }
+
+ // these following methods are used to handle overflowing modals
+
+ Modal.prototype.handleUpdate = function () {
+ this.adjustDialog()
+ }
+
+ Modal.prototype.adjustDialog = function () {
+ var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
+
+ this.$element.css({
+ paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
+ paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
+ })
+ }
+
+ Modal.prototype.resetAdjustments = function () {
+ this.$element.css({
+ paddingLeft: '',
+ paddingRight: ''
+ })
+ }
+
+ Modal.prototype.checkScrollbar = function () {
+ var fullWindowWidth = window.innerWidth
+ if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
+ var documentElementRect = document.documentElement.getBoundingClientRect()
+ fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
+ }
+ this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
+ this.scrollbarWidth = this.measureScrollbar()
+ }
+
+ Modal.prototype.setScrollbar = function () {
+ var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
+ this.originalBodyPad = document.body.style.paddingRight || ''
+ if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
+ }
+
+ Modal.prototype.resetScrollbar = function () {
+ this.$body.css('padding-right', this.originalBodyPad)
+ }
+
+ Modal.prototype.measureScrollbar = function () { // thx walsh
+ var scrollDiv = document.createElement('div')
+ scrollDiv.className = 'modal-scrollbar-measure'
+ this.$body.append(scrollDiv)
+ var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
+ this.$body[0].removeChild(scrollDiv)
+ return scrollbarWidth
+ }
+
+
+ // MODAL PLUGIN DEFINITION
+ // =======================
+
+ function Plugin(option, _relatedTarget) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.modal')
+ var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+ if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
+ if (typeof option == 'string') data[option](_relatedTarget)
+ else if (options.show) data.show(_relatedTarget)
+ })
+ }
+
+ var old = $.fn.modal
+
+ $.fn.modal = Plugin
+ $.fn.modal.Constructor = Modal
+
+
+ // MODAL NO CONFLICT
+ // =================
+
+ $.fn.modal.noConflict = function () {
+ $.fn.modal = old
+ return this
+ }
+
+
+ // MODAL DATA-API
+ // ==============
+
+ $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
+ var $this = $(this)
+ var href = $this.attr('href')
+ var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
+ var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
+
+ if ($this.is('a')) e.preventDefault()
+
+ $target.one('show.bs.modal', function (showEvent) {
+ if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
+ $target.one('hidden.bs.modal', function () {
+ $this.is(':visible') && $this.trigger('focus')
+ })
+ })
+ Plugin.call($target, option, this)
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.3.5
+ * http://getbootstrap.com/javascript/#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // TOOLTIP PUBLIC CLASS DEFINITION
+ // ===============================
+
+ var Tooltip = function (element, options) {
+ this.type = null
+ this.options = null
+ this.enabled = null
+ this.timeout = null
+ this.hoverState = null
+ this.$element = null
+ this.inState = null
+
+ this.init('tooltip', element, options)
+ }
+
+ Tooltip.VERSION = '3.3.5'
+
+ Tooltip.TRANSITION_DURATION = 150
+
+ Tooltip.DEFAULTS = {
+ animation: true,
+ placement: 'top',
+ selector: false,
+ template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
+ trigger: 'hover focus',
+ title: '',
+ delay: 0,
+ html: false,
+ container: false,
+ viewport: {
+ selector: 'body',
+ padding: 0
+ }
+ }
+
+ Tooltip.prototype.init = function (type, element, options) {
+ this.enabled = true
+ this.type = type
+ this.$element = $(element)
+ this.options = this.getOptions(options)
+ this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
+ this.inState = { click: false, hover: false, focus: false }
+
+ if (this.$element[0] instanceof document.constructor && !this.options.selector) {
+ throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
+ }
+
+ var triggers = this.options.trigger.split(' ')
+
+ for (var i = triggers.length; i--;) {
+ var trigger = triggers[i]
+
+ if (trigger == 'click') {
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+ } else if (trigger != 'manual') {
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
+
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+ }
+ }
+
+ this.options.selector ?
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+ this.fixTitle()
+ }
+
+ Tooltip.prototype.getDefaults = function () {
+ return Tooltip.DEFAULTS
+ }
+
+ Tooltip.prototype.getOptions = function (options) {
+ options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+
+ if (options.delay && typeof options.delay == 'number') {
+ options.delay = {
+ show: options.delay,
+ hide: options.delay
+ }
+ }
+
+ return options
+ }
+
+ Tooltip.prototype.getDelegateOptions = function () {
+ var options = {}
+ var defaults = this.getDefaults()
+
+ this._options && $.each(this._options, function (key, value) {
+ if (defaults[key] != value) options[key] = value
+ })
+
+ return options
+ }
+
+ Tooltip.prototype.enter = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget).data('bs.' + this.type)
+
+ if (!self) {
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
+ $(obj.currentTarget).data('bs.' + this.type, self)
+ }
+
+ if (obj instanceof $.Event) {
+ self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
+ }
+
+ if (self.tip().hasClass('in') || self.hoverState == 'in') {
+ self.hoverState = 'in'
+ return
+ }
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'in'
+
+ if (!self.options.delay || !self.options.delay.show) return self.show()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'in') self.show()
+ }, self.options.delay.show)
+ }
+
+ Tooltip.prototype.isInStateTrue = function () {
+ for (var key in this.inState) {
+ if (this.inState[key]) return true
+ }
+
+ return false
+ }
+
+ Tooltip.prototype.leave = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget).data('bs.' + this.type)
+
+ if (!self) {
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
+ $(obj.currentTarget).data('bs.' + this.type, self)
+ }
+
+ if (obj instanceof $.Event) {
+ self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
+ }
+
+ if (self.isInStateTrue()) return
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'out'
+
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'out') self.hide()
+ }, self.options.delay.hide)
+ }
+
+ Tooltip.prototype.show = function () {
+ var e = $.Event('show.bs.' + this.type)
+
+ if (this.hasContent() && this.enabled) {
+ this.$element.trigger(e)
+
+ var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
+ if (e.isDefaultPrevented() || !inDom) return
+ var that = this
+
+ var $tip = this.tip()
+
+ var tipId = this.getUID(this.type)
+
+ this.setContent()
+ $tip.attr('id', tipId)
+ this.$element.attr('aria-describedby', tipId)
+
+ if (this.options.animation) $tip.addClass('fade')
+
+ var placement = typeof this.options.placement == 'function' ?
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
+ this.options.placement
+
+ var autoToken = /\s?auto?\s?/i
+ var autoPlace = autoToken.test(placement)
+ if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+
+ $tip
+ .detach()
+ .css({ top: 0, left: 0, display: 'block' })
+ .addClass(placement)
+ .data('bs.' + this.type, this)
+
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+ this.$element.trigger('inserted.bs.' + this.type)
+
+ var pos = this.getPosition()
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (autoPlace) {
+ var orgPlacement = placement
+ var viewportDim = this.getPosition(this.$viewport)
+
+ placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' :
+ placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' :
+ placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' :
+ placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' :
+ placement
+
+ $tip
+ .removeClass(orgPlacement)
+ .addClass(placement)
+ }
+
+ var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
+
+ this.applyPlacement(calculatedOffset, placement)
+
+ var complete = function () {
+ var prevHoverState = that.hoverState
+ that.$element.trigger('shown.bs.' + that.type)
+ that.hoverState = null
+
+ if (prevHoverState == 'out') that.leave(that)
+ }
+
+ $.support.transition && this.$tip.hasClass('fade') ?
+ $tip
+ .one('bsTransitionEnd', complete)
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
+ complete()
+ }
+ }
+
+ Tooltip.prototype.applyPlacement = function (offset, placement) {
+ var $tip = this.tip()
+ var width = $tip[0].offsetWidth
+ var height = $tip[0].offsetHeight
+
+ // manually read margins because getBoundingClientRect includes difference
+ var marginTop = parseInt($tip.css('margin-top'), 10)
+ var marginLeft = parseInt($tip.css('margin-left'), 10)
+
+ // we must check for NaN for ie 8/9
+ if (isNaN(marginTop)) marginTop = 0
+ if (isNaN(marginLeft)) marginLeft = 0
+
+ offset.top += marginTop
+ offset.left += marginLeft
+
+ // $.fn.offset doesn't round pixel values
+ // so we use setOffset directly with our own function B-0
+ $.offset.setOffset($tip[0], $.extend({
+ using: function (props) {
+ $tip.css({
+ top: Math.round(props.top),
+ left: Math.round(props.left)
+ })
+ }
+ }, offset), 0)
+
+ $tip.addClass('in')
+
+ // check to see if placing tip in new offset caused the tip to resize itself
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (placement == 'top' && actualHeight != height) {
+ offset.top = offset.top + height - actualHeight
+ }
+
+ var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
+
+ if (delta.left) offset.left += delta.left
+ else offset.top += delta.top
+
+ var isVertical = /top|bottom/.test(placement)
+ var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
+ var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
+
+ $tip.offset(offset)
+ this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
+ }
+
+ Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
+ this.arrow()
+ .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
+ .css(isVertical ? 'top' : 'left', '')
+ }
+
+ Tooltip.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
+
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+ $tip.removeClass('fade in top bottom left right')
+ }
+
+ Tooltip.prototype.hide = function (callback) {
+ var that = this
+ var $tip = $(this.$tip)
+ var e = $.Event('hide.bs.' + this.type)
+
+ function complete() {
+ if (that.hoverState != 'in') $tip.detach()
+ that.$element
+ .removeAttr('aria-describedby')
+ .trigger('hidden.bs.' + that.type)
+ callback && callback()
+ }
+
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ $tip.removeClass('in')
+
+ $.support.transition && $tip.hasClass('fade') ?
+ $tip
+ .one('bsTransitionEnd', complete)
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
+ complete()
+
+ this.hoverState = null
+
+ return this
+ }
+
+ Tooltip.prototype.fixTitle = function () {
+ var $e = this.$element
+ if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+ }
+ }
+
+ Tooltip.prototype.hasContent = function () {
+ return this.getTitle()
+ }
+
+ Tooltip.prototype.getPosition = function ($element) {
+ $element = $element || this.$element
+
+ var el = $element[0]
+ var isBody = el.tagName == 'BODY'
+
+ var elRect = el.getBoundingClientRect()
+ if (elRect.width == null) {
+ // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
+ elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
+ }
+ var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
+ var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
+ var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
+
+ return $.extend({}, elRect, scroll, outerDims, elOffset)
+ }
+
+ Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
+
+ }
+
+ Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
+ var delta = { top: 0, left: 0 }
+ if (!this.$viewport) return delta
+
+ var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
+ var viewportDimensions = this.getPosition(this.$viewport)
+
+ if (/right|left/.test(placement)) {
+ var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
+ var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
+ if (topEdgeOffset < viewportDimensions.top) { // top overflow
+ delta.top = viewportDimensions.top - topEdgeOffset
+ } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
+ delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
+ }
+ } else {
+ var leftEdgeOffset = pos.left - viewportPadding
+ var rightEdgeOffset = pos.left + viewportPadding + actualWidth
+ if (leftEdgeOffset < viewportDimensions.left) { // left overflow
+ delta.left = viewportDimensions.left - leftEdgeOffset
+ } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
+ delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
+ }
+ }
+
+ return delta
+ }
+
+ Tooltip.prototype.getTitle = function () {
+ var title
+ var $e = this.$element
+ var o = this.options
+
+ title = $e.attr('data-original-title')
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
+
+ return title
+ }
+
+ Tooltip.prototype.getUID = function (prefix) {
+ do prefix += ~~(Math.random() * 1000000)
+ while (document.getElementById(prefix))
+ return prefix
+ }
+
+ Tooltip.prototype.tip = function () {
+ if (!this.$tip) {
+ this.$tip = $(this.options.template)
+ if (this.$tip.length != 1) {
+ throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
+ }
+ }
+ return this.$tip
+ }
+
+ Tooltip.prototype.arrow = function () {
+ return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
+ }
+
+ Tooltip.prototype.enable = function () {
+ this.enabled = true
+ }
+
+ Tooltip.prototype.disable = function () {
+ this.enabled = false
+ }
+
+ Tooltip.prototype.toggleEnabled = function () {
+ this.enabled = !this.enabled
+ }
+
+ Tooltip.prototype.toggle = function (e) {
+ var self = this
+ if (e) {
+ self = $(e.currentTarget).data('bs.' + this.type)
+ if (!self) {
+ self = new this.constructor(e.currentTarget, this.getDelegateOptions())
+ $(e.currentTarget).data('bs.' + this.type, self)
+ }
+ }
+
+ if (e) {
+ self.inState.click = !self.inState.click
+ if (self.isInStateTrue()) self.enter(self)
+ else self.leave(self)
+ } else {
+ self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+ }
+ }
+
+ Tooltip.prototype.destroy = function () {
+ var that = this
+ clearTimeout(this.timeout)
+ this.hide(function () {
+ that.$element.off('.' + that.type).removeData('bs.' + that.type)
+ if (that.$tip) {
+ that.$tip.detach()
+ }
+ that.$tip = null
+ that.$arrow = null
+ that.$viewport = null
+ })
+ }
+
+
+ // TOOLTIP PLUGIN DEFINITION
+ // =========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tooltip')
+ var options = typeof option == 'object' && option
+
+ if (!data && /destroy|hide/.test(option)) return
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.tooltip
+
+ $.fn.tooltip = Plugin
+ $.fn.tooltip.Constructor = Tooltip
+
+
+ // TOOLTIP NO CONFLICT
+ // ===================
+
+ $.fn.tooltip.noConflict = function () {
+ $.fn.tooltip = old
+ return this
+ }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: popover.js v3.3.5
+ * http://getbootstrap.com/javascript/#popovers
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // POPOVER PUBLIC CLASS DEFINITION
+ // ===============================
+
+ var Popover = function (element, options) {
+ this.init('popover', element, options)
+ }
+
+ if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
+
+ Popover.VERSION = '3.3.5'
+
+ Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
+ placement: 'right',
+ trigger: 'click',
+ content: '',
+ template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
+ })
+
+
+ // NOTE: POPOVER EXTENDS tooltip.js
+ // ================================
+
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+
+ Popover.prototype.constructor = Popover
+
+ Popover.prototype.getDefaults = function () {
+ return Popover.DEFAULTS
+ }
+
+ Popover.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
+ var content = this.getContent()
+
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+ $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
+ this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
+ ](content)
+
+ $tip.removeClass('fade top bottom left right in')
+
+ // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+ // this manually by checking the contents.
+ if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
+ }
+
+ Popover.prototype.hasContent = function () {
+ return this.getTitle() || this.getContent()
+ }
+
+ Popover.prototype.getContent = function () {
+ var $e = this.$element
+ var o = this.options
+
+ return $e.attr('data-content')
+ || (typeof o.content == 'function' ?
+ o.content.call($e[0]) :
+ o.content)
+ }
+
+ Popover.prototype.arrow = function () {
+ return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
+ }
+
+
+ // POPOVER PLUGIN DEFINITION
+ // =========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.popover')
+ var options = typeof option == 'object' && option
+
+ if (!data && /destroy|hide/.test(option)) return
+ if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.popover
+
+ $.fn.popover = Plugin
+ $.fn.popover.Constructor = Popover
+
+
+ // POPOVER NO CONFLICT
+ // ===================
+
+ $.fn.popover.noConflict = function () {
+ $.fn.popover = old
+ return this
+ }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: scrollspy.js v3.3.5
+ * http://getbootstrap.com/javascript/#scrollspy
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // SCROLLSPY CLASS DEFINITION
+ // ==========================
+
+ function ScrollSpy(element, options) {
+ this.$body = $(document.body)
+ this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
+ this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
+ this.selector = (this.options.target || '') + ' .nav li > a'
+ this.offsets = []
+ this.targets = []
+ this.activeTarget = null
+ this.scrollHeight = 0
+
+ this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
+ this.refresh()
+ this.process()
+ }
+
+ ScrollSpy.VERSION = '3.3.5'
+
+ ScrollSpy.DEFAULTS = {
+ offset: 10
+ }
+
+ ScrollSpy.prototype.getScrollHeight = function () {
+ return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
+ }
+
+ ScrollSpy.prototype.refresh = function () {
+ var that = this
+ var offsetMethod = 'offset'
+ var offsetBase = 0
+
+ this.offsets = []
+ this.targets = []
+ this.scrollHeight = this.getScrollHeight()
+
+ if (!$.isWindow(this.$scrollElement[0])) {
+ offsetMethod = 'position'
+ offsetBase = this.$scrollElement.scrollTop()
+ }
+
+ this.$body
+ .find(this.selector)
+ .map(function () {
+ var $el = $(this)
+ var href = $el.data('target') || $el.attr('href')
+ var $href = /^#./.test(href) && $(href)
+
+ return ($href
+ && $href.length
+ && $href.is(':visible')
+ && [[$href[offsetMethod]().top + offsetBase, href]]) || null
+ })
+ .sort(function (a, b) { return a[0] - b[0] })
+ .each(function () {
+ that.offsets.push(this[0])
+ that.targets.push(this[1])
+ })
+ }
+
+ ScrollSpy.prototype.process = function () {
+ var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
+ var scrollHeight = this.getScrollHeight()
+ var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
+ var offsets = this.offsets
+ var targets = this.targets
+ var activeTarget = this.activeTarget
+ var i
+
+ if (this.scrollHeight != scrollHeight) {
+ this.refresh()
+ }
+
+ if (scrollTop >= maxScroll) {
+ return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
+ }
+
+ if (activeTarget && scrollTop < offsets[0]) {
+ this.activeTarget = null
+ return this.clear()
+ }
+
+ for (i = offsets.length; i--;) {
+ activeTarget != targets[i]
+ && scrollTop >= offsets[i]
+ && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
+ && this.activate(targets[i])
+ }
+ }
+
+ ScrollSpy.prototype.activate = function (target) {
+ this.activeTarget = target
+
+ this.clear()
+
+ var selector = this.selector +
+ '[data-target="' + target + '"],' +
+ this.selector + '[href="' + target + '"]'
+
+ var active = $(selector)
+ .parents('li')
+ .addClass('active')
+
+ if (active.parent('.dropdown-menu').length) {
+ active = active
+ .closest('li.dropdown')
+ .addClass('active')
+ }
+
+ active.trigger('activate.bs.scrollspy')
+ }
+
+ ScrollSpy.prototype.clear = function () {
+ $(this.selector)
+ .parentsUntil(this.options.target, '.active')
+ .removeClass('active')
+ }
+
+
+ // SCROLLSPY PLUGIN DEFINITION
+ // ===========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.scrollspy')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.scrollspy
+
+ $.fn.scrollspy = Plugin
+ $.fn.scrollspy.Constructor = ScrollSpy
+
+
+ // SCROLLSPY NO CONFLICT
+ // =====================
+
+ $.fn.scrollspy.noConflict = function () {
+ $.fn.scrollspy = old
+ return this
+ }
+
+
+ // SCROLLSPY DATA-API
+ // ==================
+
+ $(window).on('load.bs.scrollspy.data-api', function () {
+ $('[data-spy="scroll"]').each(function () {
+ var $spy = $(this)
+ Plugin.call($spy, $spy.data())
+ })
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: tab.js v3.3.5
+ * http://getbootstrap.com/javascript/#tabs
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // TAB CLASS DEFINITION
+ // ====================
+
+ var Tab = function (element) {
+ // jscs:disable requireDollarBeforejQueryAssignment
+ this.element = $(element)
+ // jscs:enable requireDollarBeforejQueryAssignment
+ }
+
+ Tab.VERSION = '3.3.5'
+
+ Tab.TRANSITION_DURATION = 150
+
+ Tab.prototype.show = function () {
+ var $this = this.element
+ var $ul = $this.closest('ul:not(.dropdown-menu)')
+ var selector = $this.data('target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+ }
+
+ if ($this.parent('li').hasClass('active')) return
+
+ var $previous = $ul.find('.active:last a')
+ var hideEvent = $.Event('hide.bs.tab', {
+ relatedTarget: $this[0]
+ })
+ var showEvent = $.Event('show.bs.tab', {
+ relatedTarget: $previous[0]
+ })
+
+ $previous.trigger(hideEvent)
+ $this.trigger(showEvent)
+
+ if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
+
+ var $target = $(selector)
+
+ this.activate($this.closest('li'), $ul)
+ this.activate($target, $target.parent(), function () {
+ $previous.trigger({
+ type: 'hidden.bs.tab',
+ relatedTarget: $this[0]
+ })
+ $this.trigger({
+ type: 'shown.bs.tab',
+ relatedTarget: $previous[0]
+ })
+ })
+ }
+
+ Tab.prototype.activate = function (element, container, callback) {
+ var $active = container.find('> .active')
+ var transition = callback
+ && $.support.transition
+ && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
+
+ function next() {
+ $active
+ .removeClass('active')
+ .find('> .dropdown-menu > .active')
+ .removeClass('active')
+ .end()
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', false)
+
+ element
+ .addClass('active')
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', true)
+
+ if (transition) {
+ element[0].offsetWidth // reflow for transition
+ element.addClass('in')
+ } else {
+ element.removeClass('fade')
+ }
+
+ if (element.parent('.dropdown-menu').length) {
+ element
+ .closest('li.dropdown')
+ .addClass('active')
+ .end()
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', true)
+ }
+
+ callback && callback()
+ }
+
+ $active.length && transition ?
+ $active
+ .one('bsTransitionEnd', next)
+ .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
+ next()
+
+ $active.removeClass('in')
+ }
+
+
+ // TAB PLUGIN DEFINITION
+ // =====================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tab')
+
+ if (!data) $this.data('bs.tab', (data = new Tab(this)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.tab
+
+ $.fn.tab = Plugin
+ $.fn.tab.Constructor = Tab
+
+
+ // TAB NO CONFLICT
+ // ===============
+
+ $.fn.tab.noConflict = function () {
+ $.fn.tab = old
+ return this
+ }
+
+
+ // TAB DATA-API
+ // ============
+
+ var clickHandler = function (e) {
+ e.preventDefault()
+ Plugin.call($(this), 'show')
+ }
+
+ $(document)
+ .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
+ .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: affix.js v3.3.5
+ * http://getbootstrap.com/javascript/#affix
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // AFFIX CLASS DEFINITION
+ // ======================
+
+ var Affix = function (element, options) {
+ this.options = $.extend({}, Affix.DEFAULTS, options)
+
+ this.$target = $(this.options.target)
+ .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
+ .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
+
+ this.$element = $(element)
+ this.affixed = null
+ this.unpin = null
+ this.pinnedOffset = null
+
+ this.checkPosition()
+ }
+
+ Affix.VERSION = '3.3.5'
+
+ Affix.RESET = 'affix affix-top affix-bottom'
+
+ Affix.DEFAULTS = {
+ offset: 0,
+ target: window
+ }
+
+ Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
+ var scrollTop = this.$target.scrollTop()
+ var position = this.$element.offset()
+ var targetHeight = this.$target.height()
+
+ if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
+
+ if (this.affixed == 'bottom') {
+ if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
+ return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
+ }
+
+ var initializing = this.affixed == null
+ var colliderTop = initializing ? scrollTop : position.top
+ var colliderHeight = initializing ? targetHeight : height
+
+ if (offsetTop != null && scrollTop <= offsetTop) return 'top'
+ if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
+
+ return false
+ }
+
+ Affix.prototype.getPinnedOffset = function () {
+ if (this.pinnedOffset) return this.pinnedOffset
+ this.$element.removeClass(Affix.RESET).addClass('affix')
+ var scrollTop = this.$target.scrollTop()
+ var position = this.$element.offset()
+ return (this.pinnedOffset = position.top - scrollTop)
+ }
+
+ Affix.prototype.checkPositionWithEventLoop = function () {
+ setTimeout($.proxy(this.checkPosition, this), 1)
+ }
+
+ Affix.prototype.checkPosition = function () {
+ if (!this.$element.is(':visible')) return
+
+ var height = this.$element.height()
+ var offset = this.options.offset
+ var offsetTop = offset.top
+ var offsetBottom = offset.bottom
+ var scrollHeight = Math.max($(document).height(), $(document.body).height())
+
+ if (typeof offset != 'object') offsetBottom = offsetTop = offset
+ if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
+ if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
+
+ var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
+
+ if (this.affixed != affix) {
+ if (this.unpin != null) this.$element.css('top', '')
+
+ var affixType = 'affix' + (affix ? '-' + affix : '')
+ var e = $.Event(affixType + '.bs.affix')
+
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ this.affixed = affix
+ this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
+
+ this.$element
+ .removeClass(Affix.RESET)
+ .addClass(affixType)
+ .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
+ }
+
+ if (affix == 'bottom') {
+ this.$element.offset({
+ top: scrollHeight - height - offsetBottom
+ })
+ }
+ }
+
+
+ // AFFIX PLUGIN DEFINITION
+ // =======================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.affix')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.affix
+
+ $.fn.affix = Plugin
+ $.fn.affix.Constructor = Affix
+
+
+ // AFFIX NO CONFLICT
+ // =================
+
+ $.fn.affix.noConflict = function () {
+ $.fn.affix = old
+ return this
+ }
+
+
+ // AFFIX DATA-API
+ // ==============
+
+ $(window).on('load', function () {
+ $('[data-spy="affix"]').each(function () {
+ var $spy = $(this)
+ var data = $spy.data()
+
+ data.offset = data.offset || {}
+
+ if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
+ if (data.offsetTop != null) data.offset.top = data.offsetTop
+
+ Plugin.call($spy, data)
+ })
+ })
+
+}(jQuery);
diff --git a/lib/prado/framework/Web/Javascripts/source/bootstrap3/js/bootstrap.min.js b/lib/prado/framework/Web/Javascripts/source/bootstrap3/js/bootstrap.min.js
new file mode 100644
index 0000000..133aeec
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/bootstrap3/js/bootstrap.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under the MIT license
+ */
+if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.5",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.5",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.5",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.5",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.5",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",c).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.5",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){d.$element.one("mouseup.dismiss.bs.modal",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in"),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$dialog.one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+e).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.inState=null,this.init("tooltip",a,b)};c.VERSION="3.3.5",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-m<o.top?"bottom":"right"==h&&k.right+l>o.width?"left":"left"==h&&k.left-l<o.left?"right":h,f.removeClass(n).addClass(h)}var p=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(p,h);var q=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",q).emulateTransitionEnd(c.TRANSITION_DURATION):q()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top+=g,b.left+=h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event("hide.bs."+this.type);return this.$element.trigger(g),g.isDefaultPrevented()?void 0:(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=d?{top:0,left:0}:b.offset(),g={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},h=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,g,h,f)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.5",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.5",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),
+d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.5",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.5",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/animated-overlay.gif b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/animated-overlay.gif
new file mode 100644
index 0000000..d441f75
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/animated-overlay.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_flat_0_aaaaaa_40x100.png b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_flat_0_aaaaaa_40x100.png
new file mode 100644
index 0000000..5b5dab2
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_flat_0_aaaaaa_40x100.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_flat_75_ffffff_40x100.png b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_flat_75_ffffff_40x100.png
new file mode 100644
index 0000000..ac8b229
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_flat_75_ffffff_40x100.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_55_fbf9ee_1x400.png b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_55_fbf9ee_1x400.png
new file mode 100644
index 0000000..ad3d634
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_55_fbf9ee_1x400.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_65_ffffff_1x400.png b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_65_ffffff_1x400.png
new file mode 100644
index 0000000..42ccba2
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_65_ffffff_1x400.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_75_dadada_1x400.png b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_75_dadada_1x400.png
new file mode 100644
index 0000000..5a46b47
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_75_dadada_1x400.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_75_e6e6e6_1x400.png b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_75_e6e6e6_1x400.png
new file mode 100644
index 0000000..86c2baa
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_75_e6e6e6_1x400.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_95_fef1ec_1x400.png b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_95_fef1ec_1x400.png
new file mode 100644
index 0000000..4443fdc
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_glass_95_fef1ec_1x400.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png
new file mode 100644
index 0000000..7c9fa6c
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_222222_256x240.png b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_222222_256x240.png
new file mode 100644
index 0000000..ee039dc
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_222222_256x240.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_2e83ff_256x240.png b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_2e83ff_256x240.png
new file mode 100644
index 0000000..45e8928
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_2e83ff_256x240.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_454545_256x240.png b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_454545_256x240.png
new file mode 100644
index 0000000..7ec70d1
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_454545_256x240.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_888888_256x240.png b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_888888_256x240.png
new file mode 100644
index 0000000..5ba708c
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_888888_256x240.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_cd0a0a_256x240.png b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_cd0a0a_256x240.png
new file mode 100644
index 0000000..7930a55
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/images/ui-icons_cd0a0a_256x240.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery-ui.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery-ui.css
new file mode 100644
index 0000000..da013d6
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery-ui.css
@@ -0,0 +1,7 @@
+/*! jQuery UI - v1.10.4 - 2014-02-02
+* http://jqueryui.com
+* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css, jquery.ui.theme.css
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin-top:2px;padding:.5em .5em .5em .7em;min-height:0}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-noicons{padding-left:.7em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:none}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;width:100%;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;min-height:0;font-weight:normal}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px}.ui-menu .ui-state-disabled{font-weight:normal;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("images/animated-overlay.gif");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}
+.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-header .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-state-default .ui-icon{background-image:url(images/ui-icons_888888_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-active .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(images/ui-icons_2e83ff_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(images/ui-icons_cd0a0a_256x240.png)}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.accordion.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.accordion.css
new file mode 100644
index 0000000..bb6198b
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.accordion.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin-top:2px;padding:.5em .5em .5em .7em;min-height:0}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-noicons{padding-left:.7em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.autocomplete.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.autocomplete.css
new file mode 100644
index 0000000..92b453d
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.autocomplete.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-autocomplete{position:absolute;top:0;left:0;cursor:default} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.button.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.button.css
new file mode 100644
index 0000000..ceb823d
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.button.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.core.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.core.css
new file mode 100644
index 0000000..62435c7
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.core.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.datepicker.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.datepicker.css
new file mode 100644
index 0000000..60fc101
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.datepicker.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.dialog.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.dialog.css
new file mode 100644
index 0000000..86a52b3
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.dialog.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.menu.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.menu.css
new file mode 100644
index 0000000..143ae61
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.menu.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:none}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;width:100%;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;min-height:0;font-weight:normal}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px}.ui-menu .ui-state-disabled{font-weight:normal;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.progressbar.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.progressbar.css
new file mode 100644
index 0000000..36f5c83
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.progressbar.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("images/animated-overlay.gif");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.resizable.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.resizable.css
new file mode 100644
index 0000000..79bfa6e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.resizable.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.selectable.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.selectable.css
new file mode 100644
index 0000000..080d9a6
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.selectable.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.slider.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.slider.css
new file mode 100644
index 0000000..2952fb0
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.slider.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.spinner.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.spinner.css
new file mode 100644
index 0000000..4a87beb
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.spinner.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.tabs.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.tabs.css
new file mode 100644
index 0000000..aa25218
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.tabs.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.theme.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.theme.css
new file mode 100644
index 0000000..d0fd110
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.theme.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin-top:2px;padding:.5em .5em .5em .7em;min-height:0}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-noicons{padding-left:.7em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:none}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;width:100%;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;min-height:0;font-weight:normal}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px}.ui-menu .ui-state-disabled{font-weight:normal;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("images/animated-overlay.gif");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.tooltip.css b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.tooltip.css
new file mode 100644
index 0000000..9a36db8
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/css/base/jquery.ui.tooltip.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.4 - 2014-01-29
+* http://jqueryui.com
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/jquery-ui-i18n.min.js b/lib/prado/framework/Web/Javascripts/source/jquery/jquery-ui-i18n.min.js
new file mode 100644
index 0000000..853a18b
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/jquery-ui-i18n.min.js
@@ -0,0 +1,6 @@
+/*! jQuery UI - v1.10.4 - 2014-01-17
+* http://jqueryui.com
+* Includes: jquery.ui.datepicker-af.js, jquery.ui.datepicker-ar-DZ.js, jquery.ui.datepicker-ar.js, jquery.ui.datepicker-az.js, jquery.ui.datepicker-be.js, jquery.ui.datepicker-bg.js, jquery.ui.datepicker-bs.js, jquery.ui.datepicker-ca.js, jquery.ui.datepicker-cs.js, jquery.ui.datepicker-cy-GB.js, jquery.ui.datepicker-da.js, jquery.ui.datepicker-de.js, jquery.ui.datepicker-el.js, jquery.ui.datepicker-en-AU.js, jquery.ui.datepicker-en-GB.js, jquery.ui.datepicker-en-NZ.js, jquery.ui.datepicker-eo.js, jquery.ui.datepicker-es.js, jquery.ui.datepicker-et.js, jquery.ui.datepicker-eu.js, jquery.ui.datepicker-fa.js, jquery.ui.datepicker-fi.js, jquery.ui.datepicker-fo.js, jquery.ui.datepicker-fr-CA.js, jquery.ui.datepicker-fr-CH.js, jquery.ui.datepicker-fr.js, jquery.ui.datepicker-gl.js, jquery.ui.datepicker-he.js, jquery.ui.datepicker-hi.js, jquery.ui.datepicker-hr.js, jquery.ui.datepicker-hu.js, jquery.ui.datepicker-hy.js, jquery.ui.datepicker-id.js, jquery.ui.datepicker-is.js, jquery.ui.datepicker-it.js, jquery.ui.datepicker-ja.js, jquery.ui.datepicker-ka.js, jquery.ui.datepicker-kk.js, jquery.ui.datepicker-km.js, jquery.ui.datepicker-ko.js, jquery.ui.datepicker-ky.js, jquery.ui.datepicker-lb.js, jquery.ui.datepicker-lt.js, jquery.ui.datepicker-lv.js, jquery.ui.datepicker-mk.js, jquery.ui.datepicker-ml.js, jquery.ui.datepicker-ms.js, jquery.ui.datepicker-nb.js, jquery.ui.datepicker-nl-BE.js, jquery.ui.datepicker-nl.js, jquery.ui.datepicker-nn.js, jquery.ui.datepicker-no.js, jquery.ui.datepicker-pl.js, jquery.ui.datepicker-pt-BR.js, jquery.ui.datepicker-pt.js, jquery.ui.datepicker-rm.js, jquery.ui.datepicker-ro.js, jquery.ui.datepicker-ru.js, jquery.ui.datepicker-sk.js, jquery.ui.datepicker-sl.js, jquery.ui.datepicker-sq.js, jquery.ui.datepicker-sr-SR.js, jquery.ui.datepicker-sr.js, jquery.ui.datepicker-sv.js, jquery.ui.datepicker-ta.js, jquery.ui.datepicker-th.js, jquery.ui.datepicker-tj.js, jquery.ui.datepicker-tr.js, jquery.ui.datepicker-uk.js, jquery.ui.datepicker-vi.js, jquery.ui.datepicker-zh-CN.js, jquery.ui.datepicker-zh-HK.js, jquery.ui.datepicker-zh-TW.js
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+jQuery(function(e){e.datepicker.regional.af={closeText:"Selekteer",prevText:"Vorige",nextText:"Volgende",currentText:"Vandag",monthNames:["Januarie","Februarie","Maart","April","Mei","Junie","Julie","Augustus","September","Oktober","November","Desember"],monthNamesShort:["Jan","Feb","Mrt","Apr","Mei","Jun","Jul","Aug","Sep","Okt","Nov","Des"],dayNames:["Sondag","Maandag","Dinsdag","Woensdag","Donderdag","Vrydag","Saterdag"],dayNamesShort:["Son","Maa","Din","Woe","Don","Vry","Sat"],dayNamesMin:["So","Ma","Di","Wo","Do","Vr","Sa"],weekHeader:"Wk",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.af)}),jQuery(function(e){e.datepicker.regional["ar-DZ"]={closeText:"إغلاق",prevText:"&#x3C;السابق",nextText:"التالي&#x3E;",currentText:"اليوم",monthNames:["جانÙÙŠ","ÙÙŠÙØ±ÙŠ","مارس","Ø£ÙØ±ÙŠÙ„","ماي","جوان","جويلية","أوت","سبتمبر","أكتوبر","نوÙمبر","ديسمبر"],monthNamesShort:["1","2","3","4","5","6","7","8","9","10","11","12"],dayNames:["الأحد","الاثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"],dayNamesShort:["الأحد","الاثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"],dayNamesMin:["الأحد","الاثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"],weekHeader:"أسبوع",dateFormat:"dd/mm/yy",firstDay:6,isRTL:!0,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional["ar-DZ"])}),jQuery(function(e){e.datepicker.regional.ar={closeText:"إغلاق",prevText:"&#x3C;السابق",nextText:"التالي&#x3E;",currentText:"اليوم",monthNames:["كانون الثاني","شباط","آذار","نيسان","مايو","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول"],monthNamesShort:["1","2","3","4","5","6","7","8","9","10","11","12"],dayNames:["الأحد","الاثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"],dayNamesShort:["الأحد","الاثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"],dayNamesMin:["Ø­","Ù†","Ø«","ر","Ø®","ج","س"],weekHeader:"أسبوع",dateFormat:"dd/mm/yy",firstDay:6,isRTL:!0,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.ar)}),jQuery(function(e){e.datepicker.regional.az={closeText:"BaÄŸla",prevText:"&#x3C;Geri",nextText:"İrÉ™li&#x3E;",currentText:"Bugün",monthNames:["Yanvar","Fevral","Mart","Aprel","May","İyun","İyul","Avqust","Sentyabr","Oktyabr","Noyabr","Dekabr"],monthNamesShort:["Yan","Fev","Mar","Apr","May","İyun","İyul","Avq","Sen","Okt","Noy","Dek"],dayNames:["Bazar","Bazar ertÉ™si","ÇərÅŸÉ™nbÉ™ axÅŸamı","ÇərÅŸÉ™nbÉ™","CümÉ™ axÅŸamı","CümÉ™","ŞənbÉ™"],dayNamesShort:["B","Be","Ça","Ç","Ca","C","Åž"],dayNamesMin:["B","B","Ç","С","Ç","C","Åž"],weekHeader:"Hf",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.az)}),jQuery(function(e){e.datepicker.regional.be={closeText:"Зачыніць",prevText:"&larr;ПапÑÑ€.",nextText:"ÐаÑÑ‚.&rarr;",currentText:"СёньнÑ",monthNames:["Студзень","Люты","Сакавік","КраÑавік","Травень","ЧÑрвень","Ліпень","Жнівень","ВераÑень","КаÑтрычнік","ЛіÑтапад","Сьнежань"],monthNamesShort:["Сту","Лют","Сак","Кра","Тра","ЧÑÑ€","Ліп","Жні","Вер","КаÑ","ЛіÑ","Сьн"],dayNames:["нÑдзелÑ","панÑдзелак","аўторак","Ñерада","чацьвер","пÑтніца","Ñубота"],dayNamesShort:["ндз","пнд","аўт","Ñрд","чцв","птн","Ñбт"],dayNamesMin:["Ðд","Пн","ÐÑž","Ср","Чц","Пт","Сб"],weekHeader:"Тд",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.be)}),jQuery(function(e){e.datepicker.regional.bg={closeText:"затвори",prevText:"&#x3C;назад",nextText:"напред&#x3E;",nextBigText:"&#x3E;&#x3E;",currentText:"днеÑ",monthNames:["Януари","Февруари","Март","Ðприл","Май","Юни","Юли","ÐвгуÑÑ‚","Септември","Октомври","Ðоември","Декември"],monthNamesShort:["Яну","Фев","Мар","Ðпр","Май","Юни","Юли","Ðвг","Сеп","Окт","Ðов","Дек"],dayNames:["ÐеделÑ","Понеделник","Вторник","СрÑда","Четвъртък","Петък","Събота"],dayNamesShort:["Ðед","Пон","Вто","СрÑ","Чет","Пет","Съб"],dayNamesMin:["Ðе","По","Ð’Ñ‚","Ср","Че","Пе","Съ"],weekHeader:"Wk",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.bg)}),jQuery(function(e){e.datepicker.regional.bs={closeText:"Zatvori",prevText:"&#x3C;",nextText:"&#x3E;",currentText:"Danas",monthNames:["Januar","Februar","Mart","April","Maj","Juni","Juli","August","Septembar","Oktobar","Novembar","Decembar"],monthNamesShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Aug","Sep","Okt","Nov","Dec"],dayNames:["Nedelja","Ponedeljak","Utorak","Srijeda","ÄŒetvrtak","Petak","Subota"],dayNamesShort:["Ned","Pon","Uto","Sri","ÄŒet","Pet","Sub"],dayNamesMin:["Ne","Po","Ut","Sr","ÄŒe","Pe","Su"],weekHeader:"Wk",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.bs)}),jQuery(function(e){e.datepicker.regional.ca={closeText:"Tanca",prevText:"Anterior",nextText:"Següent",currentText:"Avui",monthNames:["gener","febrer","març","abril","maig","juny","juliol","agost","setembre","octubre","novembre","desembre"],monthNamesShort:["gen","feb","març","abr","maig","juny","jul","ag","set","oct","nov","des"],dayNames:["diumenge","dilluns","dimarts","dimecres","dijous","divendres","dissabte"],dayNamesShort:["dg","dl","dt","dc","dj","dv","ds"],dayNamesMin:["dg","dl","dt","dc","dj","dv","ds"],weekHeader:"Set",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.ca)}),jQuery(function(e){e.datepicker.regional.cs={closeText:"Zavřít",prevText:"&#x3C;Dříve",nextText:"PozdÄ›ji&#x3E;",currentText:"Nyní",monthNames:["leden","únor","bÅ™ezen","duben","kvÄ›ten","Äerven","Äervenec","srpen","září","říjen","listopad","prosinec"],monthNamesShort:["led","úno","bÅ™e","dub","kvÄ›","Äer","Ävc","srp","zář","říj","lis","pro"],dayNames:["nedÄ›le","pondÄ›lí","úterý","stÅ™eda","Ätvrtek","pátek","sobota"],dayNamesShort:["ne","po","út","st","Ät","pá","so"],dayNamesMin:["ne","po","út","st","Ät","pá","so"],weekHeader:"Týd",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.cs)}),jQuery(function(e){e.datepicker.regional["cy-GB"]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["Ionawr","Chwefror","Mawrth","Ebrill","Mai","Mehefin","Gorffennaf","Awst","Medi","Hydref","Tachwedd","Rhagfyr"],monthNamesShort:["Ion","Chw","Maw","Ebr","Mai","Meh","Gor","Aws","Med","Hyd","Tac","Rha"],dayNames:["Dydd Sul","Dydd Llun","Dydd Mawrth","Dydd Mercher","Dydd Iau","Dydd Gwener","Dydd Sadwrn"],dayNamesShort:["Sul","Llu","Maw","Mer","Iau","Gwe","Sad"],dayNamesMin:["Su","Ll","Ma","Me","Ia","Gw","Sa"],weekHeader:"Wy",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional["cy-GB"])}),jQuery(function(e){e.datepicker.regional.da={closeText:"Luk",prevText:"&#x3C;Forrige",nextText:"Næste&#x3E;",currentText:"Idag",monthNames:["Januar","Februar","Marts","April","Maj","Juni","Juli","August","September","Oktober","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Aug","Sep","Okt","Nov","Dec"],dayNames:["Søndag","Mandag","Tirsdag","Onsdag","Torsdag","Fredag","Lørdag"],dayNamesShort:["Søn","Man","Tir","Ons","Tor","Fre","Lør"],dayNamesMin:["Sø","Ma","Ti","On","To","Fr","Lø"],weekHeader:"Uge",dateFormat:"dd-mm-yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.da)}),jQuery(function(e){e.datepicker.regional.de={closeText:"Schließen",prevText:"&#x3C;Zurück",nextText:"Vor&#x3E;",currentText:"Heute",monthNames:["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"],monthNamesShort:["Jan","Feb","Mär","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"],dayNames:["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"],dayNamesShort:["So","Mo","Di","Mi","Do","Fr","Sa"],dayNamesMin:["So","Mo","Di","Mi","Do","Fr","Sa"],weekHeader:"KW",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.de)}),jQuery(function(e){e.datepicker.regional.el={closeText:"Κλείσιμο",prevText:"ΠÏοηγοÏμενος",nextText:"Επόμενος",currentText:"ΤÏέχων Μήνας",monthNames:["ΙανουάÏιος","ΦεβÏουάÏιος","ΜάÏτιος","ΑπÏίλιος","Μάιος","ΙοÏνιος","ΙοÏλιος","ΑÏγουστος","ΣεπτέμβÏιος","ΟκτώβÏιος","ÎοέμβÏιος","ΔεκέμβÏιος"],monthNamesShort:["Ιαν","Φεβ","ΜαÏ","ΑπÏ","Μαι","Ιουν","Ιουλ","Αυγ","Σεπ","Οκτ","Îοε","Δεκ"],dayNames:["ΚυÏιακή","ΔευτέÏα","ΤÏίτη","ΤετάÏτη","Πέμπτη","ΠαÏασκευή","Σάββατο"],dayNamesShort:["ΚυÏ","Δευ","ΤÏι","Τετ","Πεμ","ΠαÏ","Σαβ"],dayNamesMin:["Κυ","Δε","ΤÏ","Τε","Πε","Πα","Σα"],weekHeader:"Εβδ",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.el)}),jQuery(function(e){e.datepicker.regional["en-AU"]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional["en-AU"])}),jQuery(function(e){e.datepicker.regional["en-GB"]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional["en-GB"])}),jQuery(function(e){e.datepicker.regional["en-NZ"]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional["en-NZ"])}),jQuery(function(e){e.datepicker.regional.eo={closeText:"Fermi",prevText:"&#x3C;Anta",nextText:"Sekv&#x3E;",currentText:"Nuna",monthNames:["Januaro","Februaro","Marto","Aprilo","Majo","Junio","Julio","AÅ­gusto","Septembro","Oktobro","Novembro","Decembro"],monthNamesShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","AÅ­g","Sep","Okt","Nov","Dec"],dayNames:["Dimanĉo","Lundo","Mardo","Merkredo","Ä´aÅ­do","Vendredo","Sabato"],dayNamesShort:["Dim","Lun","Mar","Mer","Ä´aÅ­","Ven","Sab"],dayNamesMin:["Di","Lu","Ma","Me","Ä´a","Ve","Sa"],weekHeader:"Sb",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.eo)}),jQuery(function(e){e.datepicker.regional.es={closeText:"Cerrar",prevText:"&#x3C;Ant",nextText:"Sig&#x3E;",currentText:"Hoy",monthNames:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],monthNamesShort:["ene","feb","mar","abr","may","jun","jul","ogo","sep","oct","nov","dic"],dayNames:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],dayNamesShort:["dom","lun","mar","mié","juv","vie","sáb"],dayNamesMin:["D","L","M","X","J","V","S"],weekHeader:"Sm",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.es)}),jQuery(function(e){e.datepicker.regional.et={closeText:"Sulge",prevText:"Eelnev",nextText:"Järgnev",currentText:"Täna",monthNames:["Jaanuar","Veebruar","Märts","Aprill","Mai","Juuni","Juuli","August","September","Oktoober","November","Detsember"],monthNamesShort:["Jaan","Veebr","Märts","Apr","Mai","Juuni","Juuli","Aug","Sept","Okt","Nov","Dets"],dayNames:["Pühapäev","Esmaspäev","Teisipäev","Kolmapäev","Neljapäev","Reede","Laupäev"],dayNamesShort:["Pühap","Esmasp","Teisip","Kolmap","Neljap","Reede","Laup"],dayNamesMin:["P","E","T","K","N","R","L"],weekHeader:"näd",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.et)}),jQuery(function(e){e.datepicker.regional.eu={closeText:"Egina",prevText:"&#x3C;Aur",nextText:"Hur&#x3E;",currentText:"Gaur",monthNames:["urtarrila","otsaila","martxoa","apirila","maiatza","ekaina","uztaila","abuztua","iraila","urria","azaroa","abendua"],monthNamesShort:["urt.","ots.","mar.","api.","mai.","eka.","uzt.","abu.","ira.","urr.","aza.","abe."],dayNames:["igandea","astelehena","asteartea","asteazkena","osteguna","ostirala","larunbata"],dayNamesShort:["ig.","al.","ar.","az.","og.","ol.","lr."],dayNamesMin:["ig","al","ar","az","og","ol","lr"],weekHeader:"As",dateFormat:"yy-mm-dd",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.eu)}),jQuery(function(e){e.datepicker.regional.fa={closeText:"بستن",prevText:"&#x3C;قبلی",nextText:"بعدی&#x3E;",currentText:"امروز",monthNames:["ÙØ±ÙˆØ±Ø¯ÙŠÙ†","ارديبهشت","خرداد","تير","مرداد","شهريور","مهر","آبان","آذر","دی","بهمن","اسÙند"],monthNamesShort:["1","2","3","4","5","6","7","8","9","10","11","12"],dayNames:["يکشنبه","دوشنبه","سه‌شنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"],dayNamesShort:["ÛŒ","د","س","Ú†","Ù¾","ج","Ø´"],dayNamesMin:["ÛŒ","د","س","Ú†","Ù¾","ج","Ø´"],weekHeader:"Ù‡Ù",dateFormat:"yy/mm/dd",firstDay:6,isRTL:!0,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.fa)}),jQuery(function(e){e.datepicker.regional.fi={closeText:"Sulje",prevText:"&#xAB;Edellinen",nextText:"Seuraava&#xBB;",currentText:"Tänään",monthNames:["Tammikuu","Helmikuu","Maaliskuu","Huhtikuu","Toukokuu","Kesäkuu","Heinäkuu","Elokuu","Syyskuu","Lokakuu","Marraskuu","Joulukuu"],monthNamesShort:["Tammi","Helmi","Maalis","Huhti","Touko","Kesä","Heinä","Elo","Syys","Loka","Marras","Joulu"],dayNamesShort:["Su","Ma","Ti","Ke","To","Pe","La"],dayNames:["Sunnuntai","Maanantai","Tiistai","Keskiviikko","Torstai","Perjantai","Lauantai"],dayNamesMin:["Su","Ma","Ti","Ke","To","Pe","La"],weekHeader:"Vk",dateFormat:"d.m.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.fi)}),jQuery(function(e){e.datepicker.regional.fo={closeText:"Lat aftur",prevText:"&#x3C;Fyrra",nextText:"Næsta&#x3E;",currentText:"à dag",monthNames:["Januar","Februar","Mars","Apríl","Mei","Juni","Juli","August","September","Oktober","November","Desember"],monthNamesShort:["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Aug","Sep","Okt","Nov","Des"],dayNames:["Sunnudagur","Mánadagur","Týsdagur","Mikudagur","Hósdagur","Fríggjadagur","Leyardagur"],dayNamesShort:["Sun","Mán","Týs","Mik","Hós","Frí","Ley"],dayNamesMin:["Su","Má","Tý","Mi","Hó","Fr","Le"],weekHeader:"Vk",dateFormat:"dd-mm-yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.fo)}),jQuery(function(e){e.datepicker.regional["fr-CA"]={closeText:"Fermer",prevText:"Précédent",nextText:"Suivant",currentText:"Aujourd'hui",monthNames:["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],monthNamesShort:["janv.","févr.","mars","avril","mai","juin","juil.","août","sept.","oct.","nov.","déc."],dayNames:["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],dayNamesShort:["dim.","lun.","mar.","mer.","jeu.","ven.","sam."],dayNamesMin:["D","L","M","M","J","V","S"],weekHeader:"Sem.",dateFormat:"yy-mm-dd",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional["fr-CA"])}),jQuery(function(e){e.datepicker.regional["fr-CH"]={closeText:"Fermer",prevText:"&#x3C;Préc",nextText:"Suiv&#x3E;",currentText:"Courant",monthNames:["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],monthNamesShort:["janv.","févr.","mars","avril","mai","juin","juil.","août","sept.","oct.","nov.","déc."],dayNames:["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],dayNamesShort:["dim.","lun.","mar.","mer.","jeu.","ven.","sam."],dayNamesMin:["D","L","M","M","J","V","S"],weekHeader:"Sm",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional["fr-CH"])}),jQuery(function(e){e.datepicker.regional.fr={closeText:"Fermer",prevText:"Précédent",nextText:"Suivant",currentText:"Aujourd'hui",monthNames:["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],monthNamesShort:["janv.","févr.","mars","avril","mai","juin","juil.","août","sept.","oct.","nov.","déc."],dayNames:["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],dayNamesShort:["dim.","lun.","mar.","mer.","jeu.","ven.","sam."],dayNamesMin:["D","L","M","M","J","V","S"],weekHeader:"Sem.",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.fr)}),jQuery(function(e){e.datepicker.regional.gl={closeText:"Pechar",prevText:"&#x3C;Ant",nextText:"Seg&#x3E;",currentText:"Hoxe",monthNames:["Xaneiro","Febreiro","Marzo","Abril","Maio","Xuño","Xullo","Agosto","Setembro","Outubro","Novembro","Decembro"],monthNamesShort:["Xan","Feb","Mar","Abr","Mai","Xuñ","Xul","Ago","Set","Out","Nov","Dec"],dayNames:["Domingo","Luns","Martes","Mércores","Xoves","Venres","Sábado"],dayNamesShort:["Dom","Lun","Mar","Mér","Xov","Ven","Sáb"],dayNamesMin:["Do","Lu","Ma","Mé","Xo","Ve","Sá"],weekHeader:"Sm",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.gl)}),jQuery(function(e){e.datepicker.regional.he={closeText:"סגור",prevText:"&#x3C;הקוד×",nextText:"הב×&#x3E;",currentText:"היו×",monthNames:["ינו×ר","פברו×ר","מרץ","×פריל","מ××™","יוני","יולי","×וגוסט","ספטמבר","×וקטובר","נובמבר","דצמבר"],monthNamesShort:["ינו","פבר","מרץ","×פר","מ××™","יוני","יולי","×וג","ספט","×וק","נוב","דצמ"],dayNames:["ר×שון","שני","שלישי","רביעי","חמישי","שישי","שבת"],dayNamesShort:["×'","ב'","×’'","ד'","×”'","ו'","שבת"],dayNamesMin:["×'","ב'","×’'","ד'","×”'","ו'","שבת"],weekHeader:"Wk",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!0,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.he)}),jQuery(function(e){e.datepicker.regional.hi={closeText:"बंद",prevText:"पिछला",nextText:"अगला",currentText:"आज",monthNames:["जनवरी ","फरवरी","मारà¥à¤š","अपà¥à¤°à¥‡à¤²","मई","जून","जूलाई","अगसà¥à¤¤ ","सितमà¥à¤¬à¤°","अकà¥à¤Ÿà¥‚बर","नवमà¥à¤¬à¤°","दिसमà¥à¤¬à¤°"],monthNamesShort:["जन","फर","मारà¥à¤š","अपà¥à¤°à¥‡à¤²","मई","जून","जूलाई","अग","सित","अकà¥à¤Ÿ","नव","दि"],dayNames:["रविवार","सोमवार","मंगलवार","बà¥à¤§à¤µà¤¾à¤°","गà¥à¤°à¥à¤µà¤¾à¤°","शà¥à¤•à¥à¤°à¤µà¤¾à¤°","शनिवार"],dayNamesShort:["रवि","सोम","मंगल","बà¥à¤§","गà¥à¤°à¥","शà¥à¤•à¥à¤°","शनि"],dayNamesMin:["रवि","सोम","मंगल","बà¥à¤§","गà¥à¤°à¥","शà¥à¤•à¥à¤°","शनि"],weekHeader:"हफà¥à¤¤à¤¾",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.hi)}),jQuery(function(e){e.datepicker.regional.hr={closeText:"Zatvori",prevText:"&#x3C;",nextText:"&#x3E;",currentText:"Danas",monthNames:["SijeÄanj","VeljaÄa","Ožujak","Travanj","Svibanj","Lipanj","Srpanj","Kolovoz","Rujan","Listopad","Studeni","Prosinac"],monthNamesShort:["Sij","Velj","Ožu","Tra","Svi","Lip","Srp","Kol","Ruj","Lis","Stu","Pro"],dayNames:["Nedjelja","Ponedjeljak","Utorak","Srijeda","ÄŒetvrtak","Petak","Subota"],dayNamesShort:["Ned","Pon","Uto","Sri","ÄŒet","Pet","Sub"],dayNamesMin:["Ne","Po","Ut","Sr","ÄŒe","Pe","Su"],weekHeader:"Tje",dateFormat:"dd.mm.yy.",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.hr)}),jQuery(function(e){e.datepicker.regional.hu={closeText:"bezár",prevText:"vissza",nextText:"elÅ‘re",currentText:"ma",monthNames:["Január","Február","Március","Ãprilis","Május","Június","Július","Augusztus","Szeptember","Október","November","December"],monthNamesShort:["Jan","Feb","Már","Ãpr","Máj","Jún","Júl","Aug","Szep","Okt","Nov","Dec"],dayNames:["Vasárnap","HétfÅ‘","Kedd","Szerda","Csütörtök","Péntek","Szombat"],dayNamesShort:["Vas","Hét","Ked","Sze","Csü","Pén","Szo"],dayNamesMin:["V","H","K","Sze","Cs","P","Szo"],weekHeader:"Hét",dateFormat:"yy.mm.dd.",firstDay:1,isRTL:!1,showMonthAfterYear:!0,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.hu)}),jQuery(function(e){e.datepicker.regional.hy={closeText:"Õ“Õ¡Õ¯Õ¥Õ¬",prevText:"&#x3C;Õ†Õ¡Õ­.",nextText:"Õ€Õ¡Õ».&#x3E;",currentText:"Ô±ÕµÕ½Ö…Ö€",monthNames:["Õ€Õ¸Ö‚Õ¶Õ¾Õ¡Ö€","Õ“Õ¥Õ¿Ö€Õ¾Õ¡Ö€","Õ„Õ¡Ö€Õ¿","Ô±ÕºÖ€Õ«Õ¬","Õ„Õ¡ÕµÕ«Õ½","Õ€Õ¸Ö‚Õ¶Õ«Õ½","Õ€Õ¸Ö‚Õ¬Õ«Õ½","Õ•Õ£Õ¸Õ½Õ¿Õ¸Õ½","ÕÕ¥ÕºÕ¿Õ¥Õ´Õ¢Õ¥Ö€","Õ€Õ¸Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€","Õ†Õ¸ÕµÕ¥Õ´Õ¢Õ¥Ö€","Ô´Õ¥Õ¯Õ¿Õ¥Õ´Õ¢Õ¥Ö€"],monthNamesShort:["Õ€Õ¸Ö‚Õ¶Õ¾","Õ“Õ¥Õ¿Ö€","Õ„Õ¡Ö€Õ¿","Ô±ÕºÖ€","Õ„Õ¡ÕµÕ«Õ½","Õ€Õ¸Ö‚Õ¶Õ«Õ½","Õ€Õ¸Ö‚Õ¬","Õ•Õ£Õ½","ÕÕ¥Õº","Õ€Õ¸Õ¯","Õ†Õ¸Õµ","Ô´Õ¥Õ¯"],dayNames:["Õ¯Õ«Ö€Õ¡Õ¯Õ«","Õ¥Õ¯Õ¸Ö‚Õ·Õ¡Õ¢Õ©Õ«","Õ¥Ö€Õ¥Ö„Õ·Õ¡Õ¢Õ©Õ«","Õ¹Õ¸Ö€Õ¥Ö„Õ·Õ¡Õ¢Õ©Õ«","Õ°Õ«Õ¶Õ£Õ·Õ¡Õ¢Õ©Õ«","Õ¸Ö‚Ö€Õ¢Õ¡Õ©","Õ·Õ¡Õ¢Õ¡Õ©"],dayNamesShort:["Õ¯Õ«Ö€","Õ¥Ö€Õ¯","Õ¥Ö€Ö„","Õ¹Ö€Ö„","Õ°Õ¶Õ£","Õ¸Ö‚Ö€Õ¢","Õ·Õ¢Õ©"],dayNamesMin:["Õ¯Õ«Ö€","Õ¥Ö€Õ¯","Õ¥Ö€Ö„","Õ¹Ö€Ö„","Õ°Õ¶Õ£","Õ¸Ö‚Ö€Õ¢","Õ·Õ¢Õ©"],weekHeader:"Õ‡Ô²Õ",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.hy)}),jQuery(function(e){e.datepicker.regional.id={closeText:"Tutup",prevText:"&#x3C;mundur",nextText:"maju&#x3E;",currentText:"hari ini",monthNames:["Januari","Februari","Maret","April","Mei","Juni","Juli","Agustus","September","Oktober","Nopember","Desember"],monthNamesShort:["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Agus","Sep","Okt","Nop","Des"],dayNames:["Minggu","Senin","Selasa","Rabu","Kamis","Jumat","Sabtu"],dayNamesShort:["Min","Sen","Sel","Rab","kam","Jum","Sab"],dayNamesMin:["Mg","Sn","Sl","Rb","Km","jm","Sb"],weekHeader:"Mg",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.id)}),jQuery(function(e){e.datepicker.regional.is={closeText:"Loka",prevText:"&#x3C; Fyrri",nextText:"Næsti &#x3E;",currentText:"à dag",monthNames:["Janúar","Febrúar","Mars","Apríl","Maí","Júní","Júlí","Ãgúst","September","Október","Nóvember","Desember"],monthNamesShort:["Jan","Feb","Mar","Apr","Maí","Jún","Júl","Ãgú","Sep","Okt","Nóv","Des"],dayNames:["Sunnudagur","Mánudagur","Þriðjudagur","Miðvikudagur","Fimmtudagur","Föstudagur","Laugardagur"],dayNamesShort:["Sun","Mán","Þri","Mið","Fim","Fös","Lau"],dayNamesMin:["Su","Má","Þr","Mi","Fi","Fö","La"],weekHeader:"Vika",dateFormat:"dd.mm.yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.is)}),jQuery(function(e){e.datepicker.regional.it={closeText:"Chiudi",prevText:"&#x3C;Prec",nextText:"Succ&#x3E;",currentText:"Oggi",monthNames:["Gennaio","Febbraio","Marzo","Aprile","Maggio","Giugno","Luglio","Agosto","Settembre","Ottobre","Novembre","Dicembre"],monthNamesShort:["Gen","Feb","Mar","Apr","Mag","Giu","Lug","Ago","Set","Ott","Nov","Dic"],dayNames:["Domenica","Lunedì","Martedì","Mercoledì","Giovedì","Venerdì","Sabato"],dayNamesShort:["Dom","Lun","Mar","Mer","Gio","Ven","Sab"],dayNamesMin:["Do","Lu","Ma","Me","Gi","Ve","Sa"],weekHeader:"Sm",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.it)}),jQuery(function(e){e.datepicker.regional.ja={closeText:"é–‰ã˜ã‚‹",prevText:"&#x3C;å‰",nextText:"次&#x3E;",currentText:"今日",monthNames:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],monthNamesShort:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],dayNames:["日曜日","月曜日","ç«æ›œæ—¥","水曜日","木曜日","金曜日","土曜日"],dayNamesShort:["æ—¥","月","ç«","æ°´","木","金","土"],dayNamesMin:["æ—¥","月","ç«","æ°´","木","金","土"],weekHeader:"週",dateFormat:"yy/mm/dd",firstDay:0,isRTL:!1,showMonthAfterYear:!0,yearSuffix:"å¹´"},e.datepicker.setDefaults(e.datepicker.regional.ja)}),jQuery(function(e){e.datepicker.regional.ka={closeText:"დáƒáƒ®áƒ£áƒ áƒ•áƒ",prevText:"&#x3c; წინáƒ",nextText:"შემდეგი &#x3e;",currentText:"დღეს",monthNames:["იáƒáƒœáƒ•áƒáƒ áƒ˜","თებერვáƒáƒšáƒ˜","მáƒáƒ áƒ¢áƒ˜","áƒáƒžáƒ áƒ˜áƒšáƒ˜","მáƒáƒ˜áƒ¡áƒ˜","ივნისი","ივლისი","áƒáƒ’ვისტáƒ","სექტემბერი","áƒáƒ¥áƒ¢áƒáƒ›áƒ‘ერი","ნáƒáƒ”მბერი","დეკემბერი"],monthNamesShort:["იáƒáƒœ","თებ","მáƒáƒ ","áƒáƒžáƒ ","მáƒáƒ˜","ივნ","ივლ","áƒáƒ’ვ","სექ","áƒáƒ¥áƒ¢","ნáƒáƒ”","დეკ"],dayNames:["კვირáƒ","áƒáƒ áƒ¨áƒáƒ‘áƒáƒ—ი","სáƒáƒ›áƒ¨áƒáƒ‘áƒáƒ—ი","áƒáƒ—ხშáƒáƒ‘áƒáƒ—ი","ხუთშáƒáƒ‘áƒáƒ—ი","პáƒáƒ áƒáƒ¡áƒ™áƒ”ვი","შáƒáƒ‘áƒáƒ—ი"],dayNamesShort:["კვ","áƒáƒ áƒ¨","სáƒáƒ›","áƒáƒ—ხ","ხუთ","პáƒáƒ ","შáƒáƒ‘"],dayNamesMin:["კვ","áƒáƒ áƒ¨","სáƒáƒ›","áƒáƒ—ხ","ხუთ","პáƒáƒ ","შáƒáƒ‘"],weekHeader:"კვირáƒ",dateFormat:"dd-mm-yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.ka)}),jQuery(function(e){e.datepicker.regional.kk={closeText:"Жабу",prevText:"&#x3C;Ðлдыңғы",nextText:"КелеÑÑ–&#x3E;",currentText:"Бүгін",monthNames:["Қаңтар","Ðқпан","Ðаурыз","Сәуір","Мамыр","МауÑым","Шілде","Тамыз","Қыркүйек","Қазан","Қараша","ЖелтоқÑан"],monthNamesShort:["Қаң","Ðқп","Ðау","Сәу","Мам","Мау","Шіл","Там","Қыр","Қаз","Қар","Жел"],dayNames:["ЖекÑенбі","ДүйÑенбі","СейÑенбі","СәрÑенбі","БейÑенбі","Жұма","Сенбі"],dayNamesShort:["жкÑ","дÑн","ÑÑн","ÑÑ€Ñ","бÑн","жма","Ñнб"],dayNamesMin:["Жк","ДÑ","СÑ","Ср","БÑ","Жм","Сн"],weekHeader:"Ðе",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.kk)}),jQuery(function(e){e.datepicker.regional.km={closeText:"ធ្វើ​រួច",prevText:"មុន",nextText:"បន្ទាប់",currentText:"ážáŸ’ងៃ​នáŸáŸ‡",monthNames:["មករា","កុម្ភៈ","មីនា","មáŸážŸáž¶","ឧសភា","មិážáž»áž“áž¶","កក្កដា","សីហា","កញ្ញា","ážáž»áž›áž¶","វិច្ឆិកា","ធ្នូ"],monthNamesShort:["មករា","កុម្ភៈ","មីនា","មáŸážŸáž¶","ឧសភា","មិážáž»áž“áž¶","កក្កដា","សីហា","កញ្ញា","ážáž»áž›áž¶","វិច្ឆិកា","ធ្នូ"],dayNames:["អាទិážáŸ’áž™","ចន្ទ","អង្គារ","ពុធ","ព្រហស្បážáž·áŸ","សុក្រ","សៅរáŸ"],dayNamesShort:["អា","áž…","អ","áž–áž»","ព្រហ","សុ","សៅ"],dayNamesMin:["អា","áž…","អ","áž–áž»","ព្រហ","សុ","សៅ"],weekHeader:"សប្ដាហáŸ",dateFormat:"dd-mm-yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.km)}),jQuery(function(e){e.datepicker.regional.ko={closeText:"닫기",prevText:"ì´ì „달",nextText:"다ìŒë‹¬",currentText:"오늘",monthNames:["1ì›”","2ì›”","3ì›”","4ì›”","5ì›”","6ì›”","7ì›”","8ì›”","9ì›”","10ì›”","11ì›”","12ì›”"],monthNamesShort:["1ì›”","2ì›”","3ì›”","4ì›”","5ì›”","6ì›”","7ì›”","8ì›”","9ì›”","10ì›”","11ì›”","12ì›”"],dayNames:["ì¼ìš”ì¼","월요ì¼","화요ì¼","수요ì¼","목요ì¼","금요ì¼","토요ì¼"],dayNamesShort:["ì¼","ì›”","í™”","수","목","금","토"],dayNamesMin:["ì¼","ì›”","í™”","수","목","금","토"],weekHeader:"Wk",dateFormat:"yy-mm-dd",firstDay:0,isRTL:!1,showMonthAfterYear:!0,yearSuffix:"ë…„"},e.datepicker.setDefaults(e.datepicker.regional.ko)}),jQuery(function(e){e.datepicker.regional.ky={closeText:"Жабуу",prevText:"&#x3c;Мур",nextText:"Кий&#x3e;",currentText:"Бүгүн",monthNames:["Январь","Февраль","Март","Ðпрель","Май","Июнь","Июль","ÐвгуÑÑ‚","СентÑбрь","ОктÑбрь","ÐоÑбрь","Декабрь"],monthNamesShort:["Янв","Фев","Мар","Ðпр","Май","Июн","Июл","Ðвг","Сен","Окт","ÐоÑ","Дек"],dayNames:["жекшемби","дүйшөмбү","шейшемби","шаршемби","бейшемби","жума","ишемби"],dayNamesShort:["жек","дүй","шей","шар","бей","жум","ише"],dayNamesMin:["Жк","Дш","Шш","Шр","Бш","Жм","Иш"],weekHeader:"Жум",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.ky)}),jQuery(function(e){e.datepicker.regional.lb={closeText:"Fäerdeg",prevText:"Zréck",nextText:"Weider",currentText:"Haut",monthNames:["Januar","Februar","Mäerz","Abrëll","Mee","Juni","Juli","August","September","Oktober","November","Dezember"],monthNamesShort:["Jan","Feb","Mäe","Abr","Mee","Jun","Jul","Aug","Sep","Okt","Nov","Dez"],dayNames:["Sonndeg","Méindeg","Dënschdeg","Mëttwoch","Donneschdeg","Freideg","Samschdeg"],dayNamesShort:["Son","Méi","Dën","Mët","Don","Fre","Sam"],dayNamesMin:["So","Mé","Dë","Më","Do","Fr","Sa"],weekHeader:"W",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.lb)}),jQuery(function(e){e.datepicker.regional.lt={closeText:"Uždaryti",prevText:"&#x3C;Atgal",nextText:"Pirmyn&#x3E;",currentText:"Å iandien",monthNames:["Sausis","Vasaris","Kovas","Balandis","Gegužė","Birželis","Liepa","RugpjÅ«tis","RugsÄ—jis","Spalis","Lapkritis","Gruodis"],monthNamesShort:["Sau","Vas","Kov","Bal","Geg","Bir","Lie","Rugp","Rugs","Spa","Lap","Gru"],dayNames:["sekmadienis","pirmadienis","antradienis","treÄiadienis","ketvirtadienis","penktadienis","Å¡eÅ¡tadienis"],dayNamesShort:["sek","pir","ant","tre","ket","pen","Å¡eÅ¡"],dayNamesMin:["Se","Pr","An","Tr","Ke","Pe","Å e"],weekHeader:"SAV",dateFormat:"yy-mm-dd",firstDay:1,isRTL:!1,showMonthAfterYear:!0,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.lt)}),jQuery(function(e){e.datepicker.regional.lv={closeText:"AizvÄ“rt",prevText:"Iepr.",nextText:"NÄk.",currentText:"Å odien",monthNames:["JanvÄris","FebruÄris","Marts","AprÄ«lis","Maijs","JÅ«nijs","JÅ«lijs","Augusts","Septembris","Oktobris","Novembris","Decembris"],monthNamesShort:["Jan","Feb","Mar","Apr","Mai","JÅ«n","JÅ«l","Aug","Sep","Okt","Nov","Dec"],dayNames:["svÄ“tdiena","pirmdiena","otrdiena","treÅ¡diena","ceturtdiena","piektdiena","sestdiena"],dayNamesShort:["svt","prm","otr","tre","ctr","pkt","sst"],dayNamesMin:["Sv","Pr","Ot","Tr","Ct","Pk","Ss"],weekHeader:"Ned.",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.lv)}),jQuery(function(e){e.datepicker.regional.mk={closeText:"Затвори",prevText:"&#x3C;",nextText:"&#x3E;",currentText:"ДенеÑ",monthNames:["Јануари","Февруари","Март","Ðприл","Мај","Јуни","Јули","ÐвгуÑÑ‚","Септември","Октомври","Ðоември","Декември"],monthNamesShort:["Јан","Фев","Мар","Ðпр","Мај","Јун","Јул","Ðвг","Сеп","Окт","Ðое","Дек"],dayNames:["Ðедела","Понеделник","Вторник","Среда","Четврток","Петок","Сабота"],dayNamesShort:["Ðед","Пон","Вто","Сре","Чет","Пет","Саб"],dayNamesMin:["Ðе","По","Ð’Ñ‚","Ср","Че","Пе","Са"],weekHeader:"Сед",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.mk)}),jQuery(function(e){e.datepicker.regional.ml={closeText:"à´¶à´°à´¿",prevText:"à´®àµà´¨àµà´¨à´¤àµà´¤àµ†",nextText:"à´…à´Ÿàµà´¤àµà´¤à´¤àµ ",currentText:"ഇനàµà´¨àµ",monthNames:["ജനàµà´µà´°à´¿","ഫെബàµà´°àµà´µà´°à´¿","മാരàµâ€à´šàµà´šàµ","à´à´ªàµà´°à´¿à´²àµâ€","മേയàµ","ജൂണàµâ€","ജൂലൈ","ആഗസàµà´±àµà´±àµ","സെപàµà´±àµà´±à´‚ബരàµâ€","à´’à´•àµà´Ÿàµ‹à´¬à´°àµâ€","നവംബരàµâ€","ഡിസംബരàµâ€"],monthNamesShort:["ജനàµ","ഫെബàµ","മാരàµâ€","à´à´ªàµà´°à´¿","മേയàµ","ജൂണàµâ€","ജൂലാ","ആഗ","സെപàµ","à´’à´•àµà´Ÿàµ‹","നവം","à´¡à´¿à´¸"],dayNames:["ഞായരàµâ€","തിങàµà´•à´³àµâ€","ചൊവàµà´µ","à´¬àµà´§à´¨àµâ€","à´µàµà´¯à´¾à´´à´‚","വെളàµà´³à´¿","ശനി"],dayNamesShort:["ഞായ","തിങàµà´•","ചൊവàµà´µ","à´¬àµà´§","à´µàµà´¯à´¾à´´à´‚","വെളàµà´³à´¿","ശനി"],dayNamesMin:["à´žà´¾","തി","ചൊ","à´¬àµ","à´µàµà´¯à´¾","വെ","à´¶"],weekHeader:"à´†",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.ml)}),jQuery(function(e){e.datepicker.regional.ms={closeText:"Tutup",prevText:"&#x3C;Sebelum",nextText:"Selepas&#x3E;",currentText:"hari ini",monthNames:["Januari","Februari","Mac","April","Mei","Jun","Julai","Ogos","September","Oktober","November","Disember"],monthNamesShort:["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ogo","Sep","Okt","Nov","Dis"],dayNames:["Ahad","Isnin","Selasa","Rabu","Khamis","Jumaat","Sabtu"],dayNamesShort:["Aha","Isn","Sel","Rab","kha","Jum","Sab"],dayNamesMin:["Ah","Is","Se","Ra","Kh","Ju","Sa"],weekHeader:"Mg",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.ms)}),jQuery(function(e){e.datepicker.regional.nb={closeText:"Lukk",prevText:"&#xAB;Forrige",nextText:"Neste&#xBB;",currentText:"I dag",monthNames:["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember"],monthNamesShort:["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des"],dayNamesShort:["søn","man","tir","ons","tor","fre","lør"],dayNames:["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"],dayNamesMin:["sø","ma","ti","on","to","fr","lø"],weekHeader:"Uke",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.nb)
+}),jQuery(function(e){e.datepicker.regional["nl-BE"]={closeText:"Sluiten",prevText:"â†",nextText:"→",currentText:"Vandaag",monthNames:["januari","februari","maart","april","mei","juni","juli","augustus","september","oktober","november","december"],monthNamesShort:["jan","feb","mrt","apr","mei","jun","jul","aug","sep","okt","nov","dec"],dayNames:["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag"],dayNamesShort:["zon","maa","din","woe","don","vri","zat"],dayNamesMin:["zo","ma","di","wo","do","vr","za"],weekHeader:"Wk",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional["nl-BE"])}),jQuery(function(e){e.datepicker.regional.nl={closeText:"Sluiten",prevText:"â†",nextText:"→",currentText:"Vandaag",monthNames:["januari","februari","maart","april","mei","juni","juli","augustus","september","oktober","november","december"],monthNamesShort:["jan","feb","mrt","apr","mei","jun","jul","aug","sep","okt","nov","dec"],dayNames:["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag"],dayNamesShort:["zon","maa","din","woe","don","vri","zat"],dayNamesMin:["zo","ma","di","wo","do","vr","za"],weekHeader:"Wk",dateFormat:"dd-mm-yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.nl)}),jQuery(function(e){e.datepicker.regional.nn={closeText:"Lukk",prevText:"&#xAB;Førre",nextText:"Neste&#xBB;",currentText:"I dag",monthNames:["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember"],monthNamesShort:["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des"],dayNamesShort:["sun","mÃ¥n","tys","ons","tor","fre","lau"],dayNames:["sundag","mÃ¥ndag","tysdag","onsdag","torsdag","fredag","laurdag"],dayNamesMin:["su","mÃ¥","ty","on","to","fr","la"],weekHeader:"Veke",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.nn)}),jQuery(function(e){e.datepicker.regional.no={closeText:"Lukk",prevText:"&#xAB;Forrige",nextText:"Neste&#xBB;",currentText:"I dag",monthNames:["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember"],monthNamesShort:["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des"],dayNamesShort:["søn","man","tir","ons","tor","fre","lør"],dayNames:["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"],dayNamesMin:["sø","ma","ti","on","to","fr","lø"],weekHeader:"Uke",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.no)}),jQuery(function(e){e.datepicker.regional.pl={closeText:"Zamknij",prevText:"&#x3C;Poprzedni",nextText:"NastÄ™pny&#x3E;",currentText:"DziÅ›",monthNames:["StyczeÅ„","Luty","Marzec","KwiecieÅ„","Maj","Czerwiec","Lipiec","SierpieÅ„","WrzesieÅ„","Październik","Listopad","GrudzieÅ„"],monthNamesShort:["Sty","Lu","Mar","Kw","Maj","Cze","Lip","Sie","Wrz","Pa","Lis","Gru"],dayNames:["Niedziela","PoniedziaÅ‚ek","Wtorek","Åšroda","Czwartek","PiÄ…tek","Sobota"],dayNamesShort:["Nie","Pn","Wt","Åšr","Czw","Pt","So"],dayNamesMin:["N","Pn","Wt","Åšr","Cz","Pt","So"],weekHeader:"Tydz",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.pl)}),jQuery(function(e){e.datepicker.regional["pt-BR"]={closeText:"Fechar",prevText:"&#x3C;Anterior",nextText:"Próximo&#x3E;",currentText:"Hoje",monthNames:["Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"],monthNamesShort:["Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez"],dayNames:["Domingo","Segunda-feira","Terça-feira","Quarta-feira","Quinta-feira","Sexta-feira","Sábado"],dayNamesShort:["Dom","Seg","Ter","Qua","Qui","Sex","Sáb"],dayNamesMin:["Dom","Seg","Ter","Qua","Qui","Sex","Sáb"],weekHeader:"Sm",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional["pt-BR"])}),jQuery(function(e){e.datepicker.regional.pt={closeText:"Fechar",prevText:"Anterior",nextText:"Seguinte",currentText:"Hoje",monthNames:["Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"],monthNamesShort:["Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez"],dayNames:["Domingo","Segunda-feira","Terça-feira","Quarta-feira","Quinta-feira","Sexta-feira","Sábado"],dayNamesShort:["Dom","Seg","Ter","Qua","Qui","Sex","Sáb"],dayNamesMin:["Dom","Seg","Ter","Qua","Qui","Sex","Sáb"],weekHeader:"Sem",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.pt)}),jQuery(function(e){e.datepicker.regional.rm={closeText:"Serrar",prevText:"&#x3C;Suandant",nextText:"Precedent&#x3E;",currentText:"Actual",monthNames:["Schaner","Favrer","Mars","Avrigl","Matg","Zercladur","Fanadur","Avust","Settember","October","November","December"],monthNamesShort:["Scha","Fev","Mar","Avr","Matg","Zer","Fan","Avu","Sett","Oct","Nov","Dec"],dayNames:["Dumengia","Glindesdi","Mardi","Mesemna","Gievgia","Venderdi","Sonda"],dayNamesShort:["Dum","Gli","Mar","Mes","Gie","Ven","Som"],dayNamesMin:["Du","Gl","Ma","Me","Gi","Ve","So"],weekHeader:"emna",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.rm)}),jQuery(function(e){e.datepicker.regional.ro={closeText:"ÃŽnchide",prevText:"&#xAB; Luna precedentă",nextText:"Luna următoare &#xBB;",currentText:"Azi",monthNames:["Ianuarie","Februarie","Martie","Aprilie","Mai","Iunie","Iulie","August","Septembrie","Octombrie","Noiembrie","Decembrie"],monthNamesShort:["Ian","Feb","Mar","Apr","Mai","Iun","Iul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Duminică","Luni","MarÅ£i","Miercuri","Joi","Vineri","Sâmbătă"],dayNamesShort:["Dum","Lun","Mar","Mie","Joi","Vin","Sâm"],dayNamesMin:["Du","Lu","Ma","Mi","Jo","Vi","Sâ"],weekHeader:"Săpt",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.ro)}),jQuery(function(e){e.datepicker.regional.ru={closeText:"Закрыть",prevText:"&#x3C;Пред",nextText:"След&#x3E;",currentText:"СегоднÑ",monthNames:["Январь","Февраль","Март","Ðпрель","Май","Июнь","Июль","ÐвгуÑÑ‚","СентÑбрь","ОктÑбрь","ÐоÑбрь","Декабрь"],monthNamesShort:["Янв","Фев","Мар","Ðпр","Май","Июн","Июл","Ðвг","Сен","Окт","ÐоÑ","Дек"],dayNames:["воÑкреÑенье","понедельник","вторник","Ñреда","четверг","пÑтница","Ñуббота"],dayNamesShort:["вÑк","пнд","втр","Ñрд","чтв","птн","Ñбт"],dayNamesMin:["Ð’Ñ","Пн","Ð’Ñ‚","Ср","Чт","Пт","Сб"],weekHeader:"Ðед",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.ru)}),jQuery(function(e){e.datepicker.regional.sk={closeText:"ZavrieÅ¥",prevText:"&#x3C;Predchádzajúci",nextText:"Nasledujúci&#x3E;",currentText:"Dnes",monthNames:["január","február","marec","apríl","máj","jún","júl","august","september","október","november","december"],monthNamesShort:["Jan","Feb","Mar","Apr","Máj","Jún","Júl","Aug","Sep","Okt","Nov","Dec"],dayNames:["nedeľa","pondelok","utorok","streda","Å¡tvrtok","piatok","sobota"],dayNamesShort:["Ned","Pon","Uto","Str","Å tv","Pia","Sob"],dayNamesMin:["Ne","Po","Ut","St","Å t","Pia","So"],weekHeader:"Ty",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.sk)}),jQuery(function(e){e.datepicker.regional.sl={closeText:"Zapri",prevText:"&#x3C;PrejÅ¡nji",nextText:"Naslednji&#x3E;",currentText:"Trenutni",monthNames:["Januar","Februar","Marec","April","Maj","Junij","Julij","Avgust","September","Oktober","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Avg","Sep","Okt","Nov","Dec"],dayNames:["Nedelja","Ponedeljek","Torek","Sreda","ÄŒetrtek","Petek","Sobota"],dayNamesShort:["Ned","Pon","Tor","Sre","ÄŒet","Pet","Sob"],dayNamesMin:["Ne","Po","To","Sr","ÄŒe","Pe","So"],weekHeader:"Teden",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.sl)}),jQuery(function(e){e.datepicker.regional.sq={closeText:"mbylle",prevText:"&#x3C;mbrapa",nextText:"Përpara&#x3E;",currentText:"sot",monthNames:["Janar","Shkurt","Mars","Prill","Maj","Qershor","Korrik","Gusht","Shtator","Tetor","Nëntor","Dhjetor"],monthNamesShort:["Jan","Shk","Mar","Pri","Maj","Qer","Kor","Gus","Sht","Tet","Nën","Dhj"],dayNames:["E Diel","E Hënë","E Martë","E Mërkurë","E Enjte","E Premte","E Shtune"],dayNamesShort:["Di","Hë","Ma","Më","En","Pr","Sh"],dayNamesMin:["Di","Hë","Ma","Më","En","Pr","Sh"],weekHeader:"Ja",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.sq)}),jQuery(function(e){e.datepicker.regional["sr-SR"]={closeText:"Zatvori",prevText:"&#x3C;",nextText:"&#x3E;",currentText:"Danas",monthNames:["Januar","Februar","Mart","April","Maj","Jun","Jul","Avgust","Septembar","Oktobar","Novembar","Decembar"],monthNamesShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Avg","Sep","Okt","Nov","Dec"],dayNames:["Nedelja","Ponedeljak","Utorak","Sreda","ÄŒetvrtak","Petak","Subota"],dayNamesShort:["Ned","Pon","Uto","Sre","ÄŒet","Pet","Sub"],dayNamesMin:["Ne","Po","Ut","Sr","ÄŒe","Pe","Su"],weekHeader:"Sed",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional["sr-SR"])}),jQuery(function(e){e.datepicker.regional.sr={closeText:"Затвори",prevText:"&#x3C;",nextText:"&#x3E;",currentText:"ДанаÑ",monthNames:["Јануар","Фебруар","Март","Ðприл","Мај","Јун","Јул","ÐвгуÑÑ‚","Септембар","Октобар","Ðовембар","Децембар"],monthNamesShort:["Јан","Феб","Мар","Ðпр","Мај","Јун","Јул","Ðвг","Сеп","Окт","Ðов","Дец"],dayNames:["Ðедеља","Понедељак","Уторак","Среда","Четвртак","Петак","Субота"],dayNamesShort:["Ðед","Пон","Уто","Сре","Чет","Пет","Суб"],dayNamesMin:["Ðе","По","Ут","Ср","Че","Пе","Су"],weekHeader:"Сед",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.sr)}),jQuery(function(e){e.datepicker.regional.sv={closeText:"Stäng",prevText:"&#xAB;Förra",nextText:"Nästa&#xBB;",currentText:"Idag",monthNames:["Januari","Februari","Mars","April","Maj","Juni","Juli","Augusti","September","Oktober","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Aug","Sep","Okt","Nov","Dec"],dayNamesShort:["Sön","MÃ¥n","Tis","Ons","Tor","Fre","Lör"],dayNames:["Söndag","MÃ¥ndag","Tisdag","Onsdag","Torsdag","Fredag","Lördag"],dayNamesMin:["Sö","MÃ¥","Ti","On","To","Fr","Lö"],weekHeader:"Ve",dateFormat:"yy-mm-dd",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.sv)}),jQuery(function(e){e.datepicker.regional.ta={closeText:"மூடà¯",prevText:"à®®à¯à®©à¯à®©à¯ˆà®¯à®¤à¯",nextText:"அடà¯à®¤à¯à®¤à®¤à¯",currentText:"இனà¯à®±à¯",monthNames:["தை","மாசி","பஙà¯à®•à¯à®©à®¿","சிதà¯à®¤à®¿à®°à¯ˆ","வைகாசி","ஆனி","ஆடி","ஆவணி","பà¯à®°à®Ÿà¯à®Ÿà®¾à®šà®¿","à®à®ªà¯à®ªà®šà®¿","காரà¯à®¤à¯à®¤à®¿à®•ை","மாரà¯à®•ழி"],monthNamesShort:["தை","மாசி","பஙà¯","சிதà¯","வைகா","ஆனி","ஆடி","ஆவ","பà¯à®°","à®à®ªà¯","காரà¯","மாரà¯"],dayNames:["ஞாயிறà¯à®±à¯à®•à¯à®•ிழமை","திஙà¯à®•டà¯à®•ிழமை","செவà¯à®µà®¾à®¯à¯à®•à¯à®•ிழமை","பà¯à®¤à®©à¯à®•ிழமை","வியாழகà¯à®•ிழமை","வெளà¯à®³à®¿à®•à¯à®•ிழமை","சனிகà¯à®•ிழமை"],dayNamesShort:["ஞாயிறà¯","திஙà¯à®•ளà¯","செவà¯à®µà®¾à®¯à¯","பà¯à®¤à®©à¯","வியாழனà¯","வெளà¯à®³à®¿","சனி"],dayNamesMin:["ஞா","தி","செ","பà¯","வி","வெ","ச"],weekHeader:"Ðе",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.ta)}),jQuery(function(e){e.datepicker.regional.th={closeText:"ปิด",prevText:"&#xAB;&#xA0;ย้อน",nextText:"ถัดไป&#xA0;&#xBB;",currentText:"วันนี้",monthNames:["มà¸à¸£à¸²à¸„ม","à¸à¸¸à¸¡à¸ à¸²à¸žà¸±à¸™à¸˜à¹Œ","มีนาคม","เมษายน","พฤษภาคม","มิถุนายน","à¸à¸£à¸à¸Žà¸²à¸„ม","สิงหาคม","à¸à¸±à¸™à¸¢à¸²à¸¢à¸™","ตุลาคม","พฤศจิà¸à¸²à¸¢à¸™","ธันวาคม"],monthNamesShort:["ม.ค.","à¸.พ.","มี.ค.","เม.ย.","พ.ค.","มิ.ย.","à¸.ค.","ส.ค.","à¸.ย.","ต.ค.","พ.ย.","ธ.ค."],dayNames:["อาทิตย์","จันทร์","อังคาร","พุธ","พฤหัสบดี","ศุà¸à¸£à¹Œ","เสาร์"],dayNamesShort:["อา.","จ.","อ.","พ.","พฤ.","ศ.","ส."],dayNamesMin:["อา.","จ.","อ.","พ.","พฤ.","ศ.","ส."],weekHeader:"Wk",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.th)}),jQuery(function(e){e.datepicker.regional.tj={closeText:"Идома",prevText:"&#x3c;Қафо",nextText:"Пеш&#x3e;",currentText:"Имрӯз",monthNames:["Январ","Феврал","Март","Ðпрел","Май","Июн","Июл","ÐвгуÑÑ‚","СентÑбр","ОктÑбр","ÐоÑбр","Декабр"],monthNamesShort:["Янв","Фев","Мар","Ðпр","Май","Июн","Июл","Ðвг","Сен","Окт","ÐоÑ","Дек"],dayNames:["Ñкшанбе","душанбе","Ñешанбе","чоршанбе","панҷшанбе","ҷумъа","шанбе"],dayNamesShort:["Ñкш","душ","Ñеш","чор","пан","ҷум","шан"],dayNamesMin:["Як","Дш","Сш","Чш","Пш","Ҷм","Шн"],weekHeader:"Хф",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.tj)}),jQuery(function(e){e.datepicker.regional.tr={closeText:"kapat",prevText:"&#x3C;geri",nextText:"ileri&#x3e",currentText:"bugün",monthNames:["Ocak","Åžubat","Mart","Nisan","Mayıs","Haziran","Temmuz","AÄŸustos","Eylül","Ekim","Kasım","Aralık"],monthNamesShort:["Oca","Åžub","Mar","Nis","May","Haz","Tem","AÄŸu","Eyl","Eki","Kas","Ara"],dayNames:["Pazar","Pazartesi","Salı","ÇarÅŸamba","PerÅŸembe","Cuma","Cumartesi"],dayNamesShort:["Pz","Pt","Sa","Ça","Pe","Cu","Ct"],dayNamesMin:["Pz","Pt","Sa","Ça","Pe","Cu","Ct"],weekHeader:"Hf",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.tr)}),jQuery(function(e){e.datepicker.regional.uk={closeText:"Закрити",prevText:"&#x3C;",nextText:"&#x3E;",currentText:"Сьогодні",monthNames:["Січень","Лютий","Березень","Квітень","Травень","Червень","Липень","Серпень","ВереÑень","Жовтень","ЛиÑтопад","Грудень"],monthNamesShort:["Січ","Лют","Бер","Кві","Тра","Чер","Лип","Сер","Вер","Жов","ЛиÑ","Гру"],dayNames:["неділÑ","понеділок","вівторок","Ñереда","четвер","п’ÑтницÑ","Ñубота"],dayNamesShort:["нед","пнд","вів","Ñрд","чтв","птн","Ñбт"],dayNamesMin:["Ðд","Пн","Ð’Ñ‚","Ср","Чт","Пт","Сб"],weekHeader:"Тиж",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.uk)}),jQuery(function(e){e.datepicker.regional.vi={closeText:"Äóng",prevText:"&#x3C;Trước",nextText:"Tiếp&#x3E;",currentText:"Hôm nay",monthNames:["Tháng Má»™t","Tháng Hai","Tháng Ba","Tháng Tư","Tháng Năm","Tháng Sáu","Tháng Bảy","Tháng Tám","Tháng Chín","Tháng Mưá»i","Tháng Mưá»i Má»™t","Tháng Mưá»i Hai"],monthNamesShort:["Tháng 1","Tháng 2","Tháng 3","Tháng 4","Tháng 5","Tháng 6","Tháng 7","Tháng 8","Tháng 9","Tháng 10","Tháng 11","Tháng 12"],dayNames:["Chá»§ Nhật","Thứ Hai","Thứ Ba","Thứ Tư","Thứ Năm","Thứ Sáu","Thứ Bảy"],dayNamesShort:["CN","T2","T3","T4","T5","T6","T7"],dayNamesMin:["CN","T2","T3","T4","T5","T6","T7"],weekHeader:"Tu",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},e.datepicker.setDefaults(e.datepicker.regional.vi)}),jQuery(function(e){e.datepicker.regional["zh-CN"]={closeText:"关闭",prevText:"&#x3C;上月",nextText:"下月&#x3E;",currentText:"今天",monthNames:["一月","二月","三月","四月","五月","六月","七月","八月","乿œˆ","åæœˆ","å一月","å二月"],monthNamesShort:["一月","二月","三月","四月","五月","六月","七月","八月","乿œˆ","åæœˆ","å一月","å二月"],dayNames:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],dayNamesShort:["周日","周一","周二","周三","周四","周五","周六"],dayNamesMin:["æ—¥","一","二","三","å››","五","å…­"],weekHeader:"周",dateFormat:"yy-mm-dd",firstDay:1,isRTL:!1,showMonthAfterYear:!0,yearSuffix:"å¹´"},e.datepicker.setDefaults(e.datepicker.regional["zh-CN"])}),jQuery(function(e){e.datepicker.regional["zh-HK"]={closeText:"關閉",prevText:"&#x3C;上月",nextText:"下月&#x3E;",currentText:"今天",monthNames:["一月","二月","三月","四月","五月","六月","七月","八月","乿œˆ","åæœˆ","å一月","å二月"],monthNamesShort:["一月","二月","三月","四月","五月","六月","七月","八月","乿œˆ","åæœˆ","å一月","å二月"],dayNames:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],dayNamesShort:["周日","周一","周二","周三","周四","周五","周六"],dayNamesMin:["æ—¥","一","二","三","å››","五","å…­"],weekHeader:"周",dateFormat:"dd-mm-yy",firstDay:0,isRTL:!1,showMonthAfterYear:!0,yearSuffix:"å¹´"},e.datepicker.setDefaults(e.datepicker.regional["zh-HK"])}),jQuery(function(e){e.datepicker.regional["zh-TW"]={closeText:"關閉",prevText:"&#x3C;上月",nextText:"下月&#x3E;",currentText:"今天",monthNames:["一月","二月","三月","四月","五月","六月","七月","八月","乿œˆ","åæœˆ","å一月","å二月"],monthNamesShort:["一月","二月","三月","四月","五月","六月","七月","八月","乿œˆ","åæœˆ","å一月","å二月"],dayNames:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],dayNamesShort:["周日","周一","周二","周三","周四","周五","周六"],dayNamesMin:["æ—¥","一","二","三","å››","五","å…­"],weekHeader:"周",dateFormat:"yy/mm/dd",firstDay:1,isRTL:!1,showMonthAfterYear:!0,yearSuffix:"å¹´"},e.datepicker.setDefaults(e.datepicker.regional["zh-TW"])}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/jquery-ui.js b/lib/prado/framework/Web/Javascripts/source/jquery/jquery-ui.js
new file mode 100644
index 0000000..a5ae96f
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/jquery-ui.js
@@ -0,0 +1,15040 @@
+/*! jQuery UI - v1.10.4 - 2014-01-17
+* http://jqueryui.com
+* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+(function( $, undefined ) {
+
+var uuid = 0,
+ runiqueId = /^ui-id-\d+$/;
+
+// $.ui might exist from components with no dependencies, e.g., $.ui.position
+$.ui = $.ui || {};
+
+$.extend( $.ui, {
+ version: "1.10.4",
+
+ keyCode: {
+ BACKSPACE: 8,
+ COMMA: 188,
+ DELETE: 46,
+ DOWN: 40,
+ END: 35,
+ ENTER: 13,
+ ESCAPE: 27,
+ HOME: 36,
+ LEFT: 37,
+ NUMPAD_ADD: 107,
+ NUMPAD_DECIMAL: 110,
+ NUMPAD_DIVIDE: 111,
+ NUMPAD_ENTER: 108,
+ NUMPAD_MULTIPLY: 106,
+ NUMPAD_SUBTRACT: 109,
+ PAGE_DOWN: 34,
+ PAGE_UP: 33,
+ PERIOD: 190,
+ RIGHT: 39,
+ SPACE: 32,
+ TAB: 9,
+ UP: 38
+ }
+});
+
+// plugins
+$.fn.extend({
+ focus: (function( orig ) {
+ return function( delay, fn ) {
+ return typeof delay === "number" ?
+ this.each(function() {
+ var elem = this;
+ setTimeout(function() {
+ $( elem ).focus();
+ if ( fn ) {
+ fn.call( elem );
+ }
+ }, delay );
+ }) :
+ orig.apply( this, arguments );
+ };
+ })( $.fn.focus ),
+
+ scrollParent: function() {
+ var scrollParent;
+ if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
+ scrollParent = this.parents().filter(function() {
+ return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
+ }).eq(0);
+ } else {
+ scrollParent = this.parents().filter(function() {
+ return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
+ }).eq(0);
+ }
+
+ return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent;
+ },
+
+ zIndex: function( zIndex ) {
+ if ( zIndex !== undefined ) {
+ return this.css( "zIndex", zIndex );
+ }
+
+ if ( this.length ) {
+ var elem = $( this[ 0 ] ), position, value;
+ while ( elem.length && elem[ 0 ] !== document ) {
+ // Ignore z-index if position is set to a value where z-index is ignored by the browser
+ // This makes behavior of this function consistent across browsers
+ // WebKit always returns auto if the element is positioned
+ position = elem.css( "position" );
+ if ( position === "absolute" || position === "relative" || position === "fixed" ) {
+ // IE returns 0 when zIndex is not specified
+ // other browsers return a string
+ // we ignore the case of nested elements with an explicit value of 0
+ // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
+ value = parseInt( elem.css( "zIndex" ), 10 );
+ if ( !isNaN( value ) && value !== 0 ) {
+ return value;
+ }
+ }
+ elem = elem.parent();
+ }
+ }
+
+ return 0;
+ },
+
+ uniqueId: function() {
+ return this.each(function() {
+ if ( !this.id ) {
+ this.id = "ui-id-" + (++uuid);
+ }
+ });
+ },
+
+ removeUniqueId: function() {
+ return this.each(function() {
+ if ( runiqueId.test( this.id ) ) {
+ $( this ).removeAttr( "id" );
+ }
+ });
+ }
+});
+
+// selectors
+function focusable( element, isTabIndexNotNaN ) {
+ var map, mapName, img,
+ nodeName = element.nodeName.toLowerCase();
+ if ( "area" === nodeName ) {
+ map = element.parentNode;
+ mapName = map.name;
+ if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
+ return false;
+ }
+ img = $( "img[usemap=#" + mapName + "]" )[0];
+ return !!img && visible( img );
+ }
+ return ( /input|select|textarea|button|object/.test( nodeName ) ?
+ !element.disabled :
+ "a" === nodeName ?
+ element.href || isTabIndexNotNaN :
+ isTabIndexNotNaN) &&
+ // the element and all of its ancestors must be visible
+ visible( element );
+}
+
+function visible( element ) {
+ return $.expr.filters.visible( element ) &&
+ !$( element ).parents().addBack().filter(function() {
+ return $.css( this, "visibility" ) === "hidden";
+ }).length;
+}
+
+$.extend( $.expr[ ":" ], {
+ data: $.expr.createPseudo ?
+ $.expr.createPseudo(function( dataName ) {
+ return function( elem ) {
+ return !!$.data( elem, dataName );
+ };
+ }) :
+ // support: jQuery <1.8
+ function( elem, i, match ) {
+ return !!$.data( elem, match[ 3 ] );
+ },
+
+ focusable: function( element ) {
+ return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
+ },
+
+ tabbable: function( element ) {
+ var tabIndex = $.attr( element, "tabindex" ),
+ isTabIndexNaN = isNaN( tabIndex );
+ return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
+ }
+});
+
+// support: jQuery <1.8
+if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
+ $.each( [ "Width", "Height" ], function( i, name ) {
+ var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
+ type = name.toLowerCase(),
+ orig = {
+ innerWidth: $.fn.innerWidth,
+ innerHeight: $.fn.innerHeight,
+ outerWidth: $.fn.outerWidth,
+ outerHeight: $.fn.outerHeight
+ };
+
+ function reduce( elem, size, border, margin ) {
+ $.each( side, function() {
+ size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
+ if ( border ) {
+ size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
+ }
+ if ( margin ) {
+ size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
+ }
+ });
+ return size;
+ }
+
+ $.fn[ "inner" + name ] = function( size ) {
+ if ( size === undefined ) {
+ return orig[ "inner" + name ].call( this );
+ }
+
+ return this.each(function() {
+ $( this ).css( type, reduce( this, size ) + "px" );
+ });
+ };
+
+ $.fn[ "outer" + name] = function( size, margin ) {
+ if ( typeof size !== "number" ) {
+ return orig[ "outer" + name ].call( this, size );
+ }
+
+ return this.each(function() {
+ $( this).css( type, reduce( this, size, true, margin ) + "px" );
+ });
+ };
+ });
+}
+
+// support: jQuery <1.8
+if ( !$.fn.addBack ) {
+ $.fn.addBack = function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter( selector )
+ );
+ };
+}
+
+// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
+if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
+ $.fn.removeData = (function( removeData ) {
+ return function( key ) {
+ if ( arguments.length ) {
+ return removeData.call( this, $.camelCase( key ) );
+ } else {
+ return removeData.call( this );
+ }
+ };
+ })( $.fn.removeData );
+}
+
+
+
+
+
+// deprecated
+$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
+
+$.support.selectstart = "onselectstart" in document.createElement( "div" );
+$.fn.extend({
+ disableSelection: function() {
+ return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
+ ".ui-disableSelection", function( event ) {
+ event.preventDefault();
+ });
+ },
+
+ enableSelection: function() {
+ return this.unbind( ".ui-disableSelection" );
+ }
+});
+
+$.extend( $.ui, {
+ // $.ui.plugin is deprecated. Use $.widget() extensions instead.
+ plugin: {
+ add: function( module, option, set ) {
+ var i,
+ proto = $.ui[ module ].prototype;
+ for ( i in set ) {
+ proto.plugins[ i ] = proto.plugins[ i ] || [];
+ proto.plugins[ i ].push( [ option, set[ i ] ] );
+ }
+ },
+ call: function( instance, name, args ) {
+ var i,
+ set = instance.plugins[ name ];
+ if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
+ return;
+ }
+
+ for ( i = 0; i < set.length; i++ ) {
+ if ( instance.options[ set[ i ][ 0 ] ] ) {
+ set[ i ][ 1 ].apply( instance.element, args );
+ }
+ }
+ }
+ },
+
+ // only used by resizable
+ hasScroll: function( el, a ) {
+
+ //If overflow is hidden, the element might have extra content, but the user wants to hide it
+ if ( $( el ).css( "overflow" ) === "hidden") {
+ return false;
+ }
+
+ var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
+ has = false;
+
+ if ( el[ scroll ] > 0 ) {
+ return true;
+ }
+
+ // TODO: determine which cases actually cause this to happen
+ // if the element doesn't have the scroll set, see if it's possible to
+ // set the scroll
+ el[ scroll ] = 1;
+ has = ( el[ scroll ] > 0 );
+ el[ scroll ] = 0;
+ return has;
+ }
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+var uuid = 0,
+ slice = Array.prototype.slice,
+ _cleanData = $.cleanData;
+$.cleanData = function( elems ) {
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ try {
+ $( elem ).triggerHandler( "remove" );
+ // http://bugs.jquery.com/ticket/8235
+ } catch( e ) {}
+ }
+ _cleanData( elems );
+};
+
+$.widget = function( name, base, prototype ) {
+ var fullName, existingConstructor, constructor, basePrototype,
+ // proxiedPrototype allows the provided prototype to remain unmodified
+ // so that it can be used as a mixin for multiple widgets (#8876)
+ proxiedPrototype = {},
+ namespace = name.split( "." )[ 0 ];
+
+ name = name.split( "." )[ 1 ];
+ fullName = namespace + "-" + name;
+
+ if ( !prototype ) {
+ prototype = base;
+ base = $.Widget;
+ }
+
+ // create selector for plugin
+ $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
+ return !!$.data( elem, fullName );
+ };
+
+ $[ namespace ] = $[ namespace ] || {};
+ existingConstructor = $[ namespace ][ name ];
+ constructor = $[ namespace ][ name ] = function( options, element ) {
+ // allow instantiation without "new" keyword
+ if ( !this._createWidget ) {
+ return new constructor( options, element );
+ }
+
+ // allow instantiation without initializing for simple inheritance
+ // must use "new" keyword (the code above always passes args)
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+ };
+ // extend with the existing constructor to carry over any static properties
+ $.extend( constructor, existingConstructor, {
+ version: prototype.version,
+ // copy the object used to create the prototype in case we need to
+ // redefine the widget later
+ _proto: $.extend( {}, prototype ),
+ // track widgets that inherit from this widget in case this widget is
+ // redefined after a widget inherits from it
+ _childConstructors: []
+ });
+
+ basePrototype = new base();
+ // we need to make the options hash a property directly on the new instance
+ // otherwise we'll modify the options hash on the prototype that we're
+ // inheriting from
+ basePrototype.options = $.widget.extend( {}, basePrototype.options );
+ $.each( prototype, function( prop, value ) {
+ if ( !$.isFunction( value ) ) {
+ proxiedPrototype[ prop ] = value;
+ return;
+ }
+ proxiedPrototype[ prop ] = (function() {
+ var _super = function() {
+ return base.prototype[ prop ].apply( this, arguments );
+ },
+ _superApply = function( args ) {
+ return base.prototype[ prop ].apply( this, args );
+ };
+ return function() {
+ var __super = this._super,
+ __superApply = this._superApply,
+ returnValue;
+
+ this._super = _super;
+ this._superApply = _superApply;
+
+ returnValue = value.apply( this, arguments );
+
+ this._super = __super;
+ this._superApply = __superApply;
+
+ return returnValue;
+ };
+ })();
+ });
+ constructor.prototype = $.widget.extend( basePrototype, {
+ // TODO: remove support for widgetEventPrefix
+ // always use the name + a colon as the prefix, e.g., draggable:start
+ // don't prefix for widgets that aren't DOM-based
+ widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
+ }, proxiedPrototype, {
+ constructor: constructor,
+ namespace: namespace,
+ widgetName: name,
+ widgetFullName: fullName
+ });
+
+ // If this widget is being redefined then we need to find all widgets that
+ // are inheriting from it and redefine all of them so that they inherit from
+ // the new version of this widget. We're essentially trying to replace one
+ // level in the prototype chain.
+ if ( existingConstructor ) {
+ $.each( existingConstructor._childConstructors, function( i, child ) {
+ var childPrototype = child.prototype;
+
+ // redefine the child widget using the same prototype that was
+ // originally used, but inherit from the new version of the base
+ $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
+ });
+ // remove the list of existing child constructors from the old constructor
+ // so the old child constructors can be garbage collected
+ delete existingConstructor._childConstructors;
+ } else {
+ base._childConstructors.push( constructor );
+ }
+
+ $.widget.bridge( name, constructor );
+};
+
+$.widget.extend = function( target ) {
+ var input = slice.call( arguments, 1 ),
+ inputIndex = 0,
+ inputLength = input.length,
+ key,
+ value;
+ for ( ; inputIndex < inputLength; inputIndex++ ) {
+ for ( key in input[ inputIndex ] ) {
+ value = input[ inputIndex ][ key ];
+ if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
+ // Clone objects
+ if ( $.isPlainObject( value ) ) {
+ target[ key ] = $.isPlainObject( target[ key ] ) ?
+ $.widget.extend( {}, target[ key ], value ) :
+ // Don't extend strings, arrays, etc. with objects
+ $.widget.extend( {}, value );
+ // Copy everything else by reference
+ } else {
+ target[ key ] = value;
+ }
+ }
+ }
+ }
+ return target;
+};
+
+$.widget.bridge = function( name, object ) {
+ var fullName = object.prototype.widgetFullName || name;
+ $.fn[ name ] = function( options ) {
+ var isMethodCall = typeof options === "string",
+ args = slice.call( arguments, 1 ),
+ returnValue = this;
+
+ // allow multiple hashes to be passed on init
+ options = !isMethodCall && args.length ?
+ $.widget.extend.apply( null, [ options ].concat(args) ) :
+ options;
+
+ if ( isMethodCall ) {
+ this.each(function() {
+ var methodValue,
+ instance = $.data( this, fullName );
+ if ( !instance ) {
+ return $.error( "cannot call methods on " + name + " prior to initialization; " +
+ "attempted to call method '" + options + "'" );
+ }
+ if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
+ return $.error( "no such method '" + options + "' for " + name + " widget instance" );
+ }
+ methodValue = instance[ options ].apply( instance, args );
+ if ( methodValue !== instance && methodValue !== undefined ) {
+ returnValue = methodValue && methodValue.jquery ?
+ returnValue.pushStack( methodValue.get() ) :
+ methodValue;
+ return false;
+ }
+ });
+ } else {
+ this.each(function() {
+ var instance = $.data( this, fullName );
+ if ( instance ) {
+ instance.option( options || {} )._init();
+ } else {
+ $.data( this, fullName, new object( options, this ) );
+ }
+ });
+ }
+
+ return returnValue;
+ };
+};
+
+$.Widget = function( /* options, element */ ) {};
+$.Widget._childConstructors = [];
+
+$.Widget.prototype = {
+ widgetName: "widget",
+ widgetEventPrefix: "",
+ defaultElement: "<div>",
+ options: {
+ disabled: false,
+
+ // callbacks
+ create: null
+ },
+ _createWidget: function( options, element ) {
+ element = $( element || this.defaultElement || this )[ 0 ];
+ this.element = $( element );
+ this.uuid = uuid++;
+ this.eventNamespace = "." + this.widgetName + this.uuid;
+ this.options = $.widget.extend( {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ this.bindings = $();
+ this.hoverable = $();
+ this.focusable = $();
+
+ if ( element !== this ) {
+ $.data( element, this.widgetFullName, this );
+ this._on( true, this.element, {
+ remove: function( event ) {
+ if ( event.target === element ) {
+ this.destroy();
+ }
+ }
+ });
+ this.document = $( element.style ?
+ // element within the document
+ element.ownerDocument :
+ // element is window or document
+ element.document || element );
+ this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
+ }
+
+ this._create();
+ this._trigger( "create", null, this._getCreateEventData() );
+ this._init();
+ },
+ _getCreateOptions: $.noop,
+ _getCreateEventData: $.noop,
+ _create: $.noop,
+ _init: $.noop,
+
+ destroy: function() {
+ this._destroy();
+ // we can probably remove the unbind calls in 2.0
+ // all event bindings should go through this._on()
+ this.element
+ .unbind( this.eventNamespace )
+ // 1.9 BC for #7810
+ // TODO remove dual storage
+ .removeData( this.widgetName )
+ .removeData( this.widgetFullName )
+ // support: jquery <1.6.3
+ // http://bugs.jquery.com/ticket/9413
+ .removeData( $.camelCase( this.widgetFullName ) );
+ this.widget()
+ .unbind( this.eventNamespace )
+ .removeAttr( "aria-disabled" )
+ .removeClass(
+ this.widgetFullName + "-disabled " +
+ "ui-state-disabled" );
+
+ // clean up events and states
+ this.bindings.unbind( this.eventNamespace );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ },
+ _destroy: $.noop,
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key,
+ parts,
+ curOption,
+ i;
+
+ if ( arguments.length === 0 ) {
+ // don't return a reference to the internal hash
+ return $.widget.extend( {}, this.options );
+ }
+
+ if ( typeof key === "string" ) {
+ // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+ options = {};
+ parts = key.split( "." );
+ key = parts.shift();
+ if ( parts.length ) {
+ curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+ for ( i = 0; i < parts.length - 1; i++ ) {
+ curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+ curOption = curOption[ parts[ i ] ];
+ }
+ key = parts.pop();
+ if ( arguments.length === 1 ) {
+ return curOption[ key ] === undefined ? null : curOption[ key ];
+ }
+ curOption[ key ] = value;
+ } else {
+ if ( arguments.length === 1 ) {
+ return this.options[ key ] === undefined ? null : this.options[ key ];
+ }
+ options[ key ] = value;
+ }
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+ _setOptions: function( options ) {
+ var key;
+
+ for ( key in options ) {
+ this._setOption( key, options[ key ] );
+ }
+
+ return this;
+ },
+ _setOption: function( key, value ) {
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this.widget()
+ .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
+ .attr( "aria-disabled", value );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ }
+
+ return this;
+ },
+
+ enable: function() {
+ return this._setOption( "disabled", false );
+ },
+ disable: function() {
+ return this._setOption( "disabled", true );
+ },
+
+ _on: function( suppressDisabledCheck, element, handlers ) {
+ var delegateElement,
+ instance = this;
+
+ // no suppressDisabledCheck flag, shuffle arguments
+ if ( typeof suppressDisabledCheck !== "boolean" ) {
+ handlers = element;
+ element = suppressDisabledCheck;
+ suppressDisabledCheck = false;
+ }
+
+ // no element argument, shuffle and use this.element
+ if ( !handlers ) {
+ handlers = element;
+ element = this.element;
+ delegateElement = this.widget();
+ } else {
+ // accept selectors, DOM elements
+ element = delegateElement = $( element );
+ this.bindings = this.bindings.add( element );
+ }
+
+ $.each( handlers, function( event, handler ) {
+ function handlerProxy() {
+ // allow widgets to customize the disabled handling
+ // - disabled as an array instead of boolean
+ // - disabled class as method for disabling individual parts
+ if ( !suppressDisabledCheck &&
+ ( instance.options.disabled === true ||
+ $( this ).hasClass( "ui-state-disabled" ) ) ) {
+ return;
+ }
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+
+ // copy the guid so direct unbinding works
+ if ( typeof handler !== "string" ) {
+ handlerProxy.guid = handler.guid =
+ handler.guid || handlerProxy.guid || $.guid++;
+ }
+
+ var match = event.match( /^(\w+)\s*(.*)$/ ),
+ eventName = match[1] + instance.eventNamespace,
+ selector = match[2];
+ if ( selector ) {
+ delegateElement.delegate( selector, eventName, handlerProxy );
+ } else {
+ element.bind( eventName, handlerProxy );
+ }
+ });
+ },
+
+ _off: function( element, eventName ) {
+ eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
+ element.unbind( eventName ).undelegate( eventName );
+ },
+
+ _delay: function( handler, delay ) {
+ function handlerProxy() {
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+ var instance = this;
+ return setTimeout( handlerProxy, delay || 0 );
+ },
+
+ _hoverable: function( element ) {
+ this.hoverable = this.hoverable.add( element );
+ this._on( element, {
+ mouseenter: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-hover" );
+ },
+ mouseleave: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-hover" );
+ }
+ });
+ },
+
+ _focusable: function( element ) {
+ this.focusable = this.focusable.add( element );
+ this._on( element, {
+ focusin: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-focus" );
+ },
+ focusout: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-focus" );
+ }
+ });
+ },
+
+ _trigger: function( type, event, data ) {
+ var prop, orig,
+ callback = this.options[ type ];
+
+ data = data || {};
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+ // the original event may come from any element
+ // so we need to reset the target on the new event
+ event.target = this.element[ 0 ];
+
+ // copy original event properties over to the new event
+ orig = event.originalEvent;
+ if ( orig ) {
+ for ( prop in orig ) {
+ if ( !( prop in event ) ) {
+ event[ prop ] = orig[ prop ];
+ }
+ }
+ }
+
+ this.element.trigger( event, data );
+ return !( $.isFunction( callback ) &&
+ callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
+ event.isDefaultPrevented() );
+ }
+};
+
+$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+ if ( typeof options === "string" ) {
+ options = { effect: options };
+ }
+ var hasOptions,
+ effectName = !options ?
+ method :
+ options === true || typeof options === "number" ?
+ defaultEffect :
+ options.effect || defaultEffect;
+ options = options || {};
+ if ( typeof options === "number" ) {
+ options = { duration: options };
+ }
+ hasOptions = !$.isEmptyObject( options );
+ options.complete = callback;
+ if ( options.delay ) {
+ element.delay( options.delay );
+ }
+ if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
+ element[ method ]( options );
+ } else if ( effectName !== method && element[ effectName ] ) {
+ element[ effectName ]( options.duration, options.easing, callback );
+ } else {
+ element.queue(function( next ) {
+ $( this )[ method ]();
+ if ( callback ) {
+ callback.call( element[ 0 ] );
+ }
+ next();
+ });
+ }
+ };
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+var mouseHandled = false;
+$( document ).mouseup( function() {
+ mouseHandled = false;
+});
+
+$.widget("ui.mouse", {
+ version: "1.10.4",
+ options: {
+ cancel: "input,textarea,button,select,option",
+ distance: 1,
+ delay: 0
+ },
+ _mouseInit: function() {
+ var that = this;
+
+ this.element
+ .bind("mousedown."+this.widgetName, function(event) {
+ return that._mouseDown(event);
+ })
+ .bind("click."+this.widgetName, function(event) {
+ if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
+ $.removeData(event.target, that.widgetName + ".preventClickEvent");
+ event.stopImmediatePropagation();
+ return false;
+ }
+ });
+
+ this.started = false;
+ },
+
+ // TODO: make sure destroying one instance of mouse doesn't mess with
+ // other instances of mouse
+ _mouseDestroy: function() {
+ this.element.unbind("."+this.widgetName);
+ if ( this._mouseMoveDelegate ) {
+ $(document)
+ .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+ .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
+ }
+ },
+
+ _mouseDown: function(event) {
+ // don't let more than one widget handle mouseStart
+ if( mouseHandled ) { return; }
+
+ // we may have missed mouseup (out of window)
+ (this._mouseStarted && this._mouseUp(event));
+
+ this._mouseDownEvent = event;
+
+ var that = this,
+ btnIsLeft = (event.which === 1),
+ // event.target.nodeName works around a bug in IE 8 with
+ // disabled inputs (#7620)
+ elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
+ if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
+ return true;
+ }
+
+ this.mouseDelayMet = !this.options.delay;
+ if (!this.mouseDelayMet) {
+ this._mouseDelayTimer = setTimeout(function() {
+ that.mouseDelayMet = true;
+ }, this.options.delay);
+ }
+
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+ this._mouseStarted = (this._mouseStart(event) !== false);
+ if (!this._mouseStarted) {
+ event.preventDefault();
+ return true;
+ }
+ }
+
+ // Click event may never have fired (Gecko & Opera)
+ if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
+ $.removeData(event.target, this.widgetName + ".preventClickEvent");
+ }
+
+ // these delegates are required to keep context
+ this._mouseMoveDelegate = function(event) {
+ return that._mouseMove(event);
+ };
+ this._mouseUpDelegate = function(event) {
+ return that._mouseUp(event);
+ };
+ $(document)
+ .bind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+ .bind("mouseup."+this.widgetName, this._mouseUpDelegate);
+
+ event.preventDefault();
+
+ mouseHandled = true;
+ return true;
+ },
+
+ _mouseMove: function(event) {
+ // IE mouseup check - mouseup happened when mouse was out of window
+ if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
+ return this._mouseUp(event);
+ }
+
+ if (this._mouseStarted) {
+ this._mouseDrag(event);
+ return event.preventDefault();
+ }
+
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+ this._mouseStarted =
+ (this._mouseStart(this._mouseDownEvent, event) !== false);
+ (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
+ }
+
+ return !this._mouseStarted;
+ },
+
+ _mouseUp: function(event) {
+ $(document)
+ .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+ .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
+
+ if (this._mouseStarted) {
+ this._mouseStarted = false;
+
+ if (event.target === this._mouseDownEvent.target) {
+ $.data(event.target, this.widgetName + ".preventClickEvent", true);
+ }
+
+ this._mouseStop(event);
+ }
+
+ return false;
+ },
+
+ _mouseDistanceMet: function(event) {
+ return (Math.max(
+ Math.abs(this._mouseDownEvent.pageX - event.pageX),
+ Math.abs(this._mouseDownEvent.pageY - event.pageY)
+ ) >= this.options.distance
+ );
+ },
+
+ _mouseDelayMet: function(/* event */) {
+ return this.mouseDelayMet;
+ },
+
+ // These are placeholder methods, to be overriden by extending plugin
+ _mouseStart: function(/* event */) {},
+ _mouseDrag: function(/* event */) {},
+ _mouseStop: function(/* event */) {},
+ _mouseCapture: function(/* event */) { return true; }
+});
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.widget("ui.draggable", $.ui.mouse, {
+ version: "1.10.4",
+ widgetEventPrefix: "drag",
+ options: {
+ addClasses: true,
+ appendTo: "parent",
+ axis: false,
+ connectToSortable: false,
+ containment: false,
+ cursor: "auto",
+ cursorAt: false,
+ grid: false,
+ handle: false,
+ helper: "original",
+ iframeFix: false,
+ opacity: false,
+ refreshPositions: false,
+ revert: false,
+ revertDuration: 500,
+ scope: "default",
+ scroll: true,
+ scrollSensitivity: 20,
+ scrollSpeed: 20,
+ snap: false,
+ snapMode: "both",
+ snapTolerance: 20,
+ stack: false,
+ zIndex: false,
+
+ // callbacks
+ drag: null,
+ start: null,
+ stop: null
+ },
+ _create: function() {
+
+ if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) {
+ this.element[0].style.position = "relative";
+ }
+ if (this.options.addClasses){
+ this.element.addClass("ui-draggable");
+ }
+ if (this.options.disabled){
+ this.element.addClass("ui-draggable-disabled");
+ }
+
+ this._mouseInit();
+
+ },
+
+ _destroy: function() {
+ this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
+ this._mouseDestroy();
+ },
+
+ _mouseCapture: function(event) {
+
+ var o = this.options;
+
+ // among others, prevent a drag on a resizable-handle
+ if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
+ return false;
+ }
+
+ //Quit if we're not on a valid handle
+ this.handle = this._getHandle(event);
+ if (!this.handle) {
+ return false;
+ }
+
+ $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
+ $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>")
+ .css({
+ width: this.offsetWidth+"px", height: this.offsetHeight+"px",
+ position: "absolute", opacity: "0.001", zIndex: 1000
+ })
+ .css($(this).offset())
+ .appendTo("body");
+ });
+
+ return true;
+
+ },
+
+ _mouseStart: function(event) {
+
+ var o = this.options;
+
+ //Create and append the visible helper
+ this.helper = this._createHelper(event);
+
+ this.helper.addClass("ui-draggable-dragging");
+
+ //Cache the helper size
+ this._cacheHelperProportions();
+
+ //If ddmanager is used for droppables, set the global draggable
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.current = this;
+ }
+
+ /*
+ * - Position generation -
+ * This block generates everything position related - it's the core of draggables.
+ */
+
+ //Cache the margins of the original element
+ this._cacheMargins();
+
+ //Store the helper's css position
+ this.cssPosition = this.helper.css( "position" );
+ this.scrollParent = this.helper.scrollParent();
+ this.offsetParent = this.helper.offsetParent();
+ this.offsetParentCssPosition = this.offsetParent.css( "position" );
+
+ //The element's absolute position on the page minus margins
+ this.offset = this.positionAbs = this.element.offset();
+ this.offset = {
+ top: this.offset.top - this.margins.top,
+ left: this.offset.left - this.margins.left
+ };
+
+ //Reset scroll cache
+ this.offset.scroll = false;
+
+ $.extend(this.offset, {
+ click: { //Where the click happened, relative to the element
+ left: event.pageX - this.offset.left,
+ top: event.pageY - this.offset.top
+ },
+ parent: this._getParentOffset(),
+ relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+ });
+
+ //Generate the original position
+ this.originalPosition = this.position = this._generatePosition(event);
+ this.originalPageX = event.pageX;
+ this.originalPageY = event.pageY;
+
+ //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
+ (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+ //Set a containment if given in the options
+ this._setContainment();
+
+ //Trigger event + callbacks
+ if(this._trigger("start", event) === false) {
+ this._clear();
+ return false;
+ }
+
+ //Recache the helper size
+ this._cacheHelperProportions();
+
+ //Prepare the droppable offsets
+ if ($.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+
+
+ this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+
+ //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
+ if ( $.ui.ddmanager ) {
+ $.ui.ddmanager.dragStart(this, event);
+ }
+
+ return true;
+ },
+
+ _mouseDrag: function(event, noPropagation) {
+ // reset any necessary cached properties (see #5009)
+ if ( this.offsetParentCssPosition === "fixed" ) {
+ this.offset.parent = this._getParentOffset();
+ }
+
+ //Compute the helpers position
+ this.position = this._generatePosition(event);
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ //Call plugins and callbacks and use the resulting position if something is returned
+ if (!noPropagation) {
+ var ui = this._uiHash();
+ if(this._trigger("drag", event, ui) === false) {
+ this._mouseUp({});
+ return false;
+ }
+ this.position = ui.position;
+ }
+
+ if(!this.options.axis || this.options.axis !== "y") {
+ this.helper[0].style.left = this.position.left+"px";
+ }
+ if(!this.options.axis || this.options.axis !== "x") {
+ this.helper[0].style.top = this.position.top+"px";
+ }
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.drag(this, event);
+ }
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+
+ //If we are using droppables, inform the manager about the drop
+ var that = this,
+ dropped = false;
+ if ($.ui.ddmanager && !this.options.dropBehaviour) {
+ dropped = $.ui.ddmanager.drop(this, event);
+ }
+
+ //if a drop comes from outside (a sortable)
+ if(this.dropped) {
+ dropped = this.dropped;
+ this.dropped = false;
+ }
+
+ //if the original element is no longer in the DOM don't bother to continue (see #8269)
+ if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) {
+ return false;
+ }
+
+ if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
+ $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
+ if(that._trigger("stop", event) !== false) {
+ that._clear();
+ }
+ });
+ } else {
+ if(this._trigger("stop", event) !== false) {
+ this._clear();
+ }
+ }
+
+ return false;
+ },
+
+ _mouseUp: function(event) {
+ //Remove frame helpers
+ $("div.ui-draggable-iframeFix").each(function() {
+ this.parentNode.removeChild(this);
+ });
+
+ //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
+ if( $.ui.ddmanager ) {
+ $.ui.ddmanager.dragStop(this, event);
+ }
+
+ return $.ui.mouse.prototype._mouseUp.call(this, event);
+ },
+
+ cancel: function() {
+
+ if(this.helper.is(".ui-draggable-dragging")) {
+ this._mouseUp({});
+ } else {
+ this._clear();
+ }
+
+ return this;
+
+ },
+
+ _getHandle: function(event) {
+ return this.options.handle ?
+ !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
+ true;
+ },
+
+ _createHelper: function(event) {
+
+ var o = this.options,
+ helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element);
+
+ if(!helper.parents("body").length) {
+ helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
+ }
+
+ if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
+ helper.css("position", "absolute");
+ }
+
+ return helper;
+
+ },
+
+ _adjustOffsetFromHelper: function(obj) {
+ if (typeof obj === "string") {
+ obj = obj.split(" ");
+ }
+ if ($.isArray(obj)) {
+ obj = {left: +obj[0], top: +obj[1] || 0};
+ }
+ if ("left" in obj) {
+ this.offset.click.left = obj.left + this.margins.left;
+ }
+ if ("right" in obj) {
+ this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+ }
+ if ("top" in obj) {
+ this.offset.click.top = obj.top + this.margins.top;
+ }
+ if ("bottom" in obj) {
+ this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+ }
+ },
+
+ _getParentOffset: function() {
+
+ //Get the offsetParent and cache its position
+ var po = this.offsetParent.offset();
+
+ // This is a special case where we need to modify a offset calculated on start, since the following happened:
+ // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+ // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+ if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+ po.left += this.scrollParent.scrollLeft();
+ po.top += this.scrollParent.scrollTop();
+ }
+
+ //This needs to be actually done for all browsers, since pageX/pageY includes this information
+ //Ugly IE fix
+ if((this.offsetParent[0] === document.body) ||
+ (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
+ po = { top: 0, left: 0 };
+ }
+
+ return {
+ top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+ left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+ };
+
+ },
+
+ _getRelativeOffset: function() {
+
+ if(this.cssPosition === "relative") {
+ var p = this.element.position();
+ return {
+ top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+ left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+ };
+ } else {
+ return { top: 0, left: 0 };
+ }
+
+ },
+
+ _cacheMargins: function() {
+ this.margins = {
+ left: (parseInt(this.element.css("marginLeft"),10) || 0),
+ top: (parseInt(this.element.css("marginTop"),10) || 0),
+ right: (parseInt(this.element.css("marginRight"),10) || 0),
+ bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
+ };
+ },
+
+ _cacheHelperProportions: function() {
+ this.helperProportions = {
+ width: this.helper.outerWidth(),
+ height: this.helper.outerHeight()
+ };
+ },
+
+ _setContainment: function() {
+
+ var over, c, ce,
+ o = this.options;
+
+ if ( !o.containment ) {
+ this.containment = null;
+ return;
+ }
+
+ if ( o.containment === "window" ) {
+ this.containment = [
+ $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
+ $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
+ $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
+ $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
+ ];
+ return;
+ }
+
+ if ( o.containment === "document") {
+ this.containment = [
+ 0,
+ 0,
+ $( document ).width() - this.helperProportions.width - this.margins.left,
+ ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
+ ];
+ return;
+ }
+
+ if ( o.containment.constructor === Array ) {
+ this.containment = o.containment;
+ return;
+ }
+
+ if ( o.containment === "parent" ) {
+ o.containment = this.helper[ 0 ].parentNode;
+ }
+
+ c = $( o.containment );
+ ce = c[ 0 ];
+
+ if( !ce ) {
+ return;
+ }
+
+ over = c.css( "overflow" ) !== "hidden";
+
+ this.containment = [
+ ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
+ ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) ,
+ ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right,
+ ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top - this.margins.bottom
+ ];
+ this.relative_container = c;
+ },
+
+ _convertPositionTo: function(d, pos) {
+
+ if(!pos) {
+ pos = this.position;
+ }
+
+ var mod = d === "absolute" ? 1 : -1,
+ scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent;
+
+ //Cache the scroll
+ if (!this.offset.scroll) {
+ this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
+ }
+
+ return {
+ top: (
+ pos.top + // The absolute mouse position
+ this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod )
+ ),
+ left: (
+ pos.left + // The absolute mouse position
+ this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod )
+ )
+ };
+
+ },
+
+ _generatePosition: function(event) {
+
+ var containment, co, top, left,
+ o = this.options,
+ scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent,
+ pageX = event.pageX,
+ pageY = event.pageY;
+
+ //Cache the scroll
+ if (!this.offset.scroll) {
+ this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
+ }
+
+ /*
+ * - Position constraining -
+ * Constrain the position to a mix of grid, containment.
+ */
+
+ // If we are not dragging yet, we won't check for options
+ if ( this.originalPosition ) {
+ if ( this.containment ) {
+ if ( this.relative_container ){
+ co = this.relative_container.offset();
+ containment = [
+ this.containment[ 0 ] + co.left,
+ this.containment[ 1 ] + co.top,
+ this.containment[ 2 ] + co.left,
+ this.containment[ 3 ] + co.top
+ ];
+ }
+ else {
+ containment = this.containment;
+ }
+
+ if(event.pageX - this.offset.click.left < containment[0]) {
+ pageX = containment[0] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top < containment[1]) {
+ pageY = containment[1] + this.offset.click.top;
+ }
+ if(event.pageX - this.offset.click.left > containment[2]) {
+ pageX = containment[2] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top > containment[3]) {
+ pageY = containment[3] + this.offset.click.top;
+ }
+ }
+
+ if(o.grid) {
+ //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
+ top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
+ pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+ left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
+ pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+ }
+
+ }
+
+ return {
+ top: (
+ pageY - // The absolute mouse position
+ this.offset.click.top - // Click offset (relative to the element)
+ this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
+ ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top )
+ ),
+ left: (
+ pageX - // The absolute mouse position
+ this.offset.click.left - // Click offset (relative to the element)
+ this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
+ ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left )
+ )
+ };
+
+ },
+
+ _clear: function() {
+ this.helper.removeClass("ui-draggable-dragging");
+ if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
+ this.helper.remove();
+ }
+ this.helper = null;
+ this.cancelHelperRemoval = false;
+ },
+
+ // From now on bulk stuff - mainly helpers
+
+ _trigger: function(type, event, ui) {
+ ui = ui || this._uiHash();
+ $.ui.plugin.call(this, type, [event, ui]);
+ //The absolute position has to be recalculated after plugins
+ if(type === "drag") {
+ this.positionAbs = this._convertPositionTo("absolute");
+ }
+ return $.Widget.prototype._trigger.call(this, type, event, ui);
+ },
+
+ plugins: {},
+
+ _uiHash: function() {
+ return {
+ helper: this.helper,
+ position: this.position,
+ originalPosition: this.originalPosition,
+ offset: this.positionAbs
+ };
+ }
+
+});
+
+$.ui.plugin.add("draggable", "connectToSortable", {
+ start: function(event, ui) {
+
+ var inst = $(this).data("ui-draggable"), o = inst.options,
+ uiSortable = $.extend({}, ui, { item: inst.element });
+ inst.sortables = [];
+ $(o.connectToSortable).each(function() {
+ var sortable = $.data(this, "ui-sortable");
+ if (sortable && !sortable.options.disabled) {
+ inst.sortables.push({
+ instance: sortable,
+ shouldRevert: sortable.options.revert
+ });
+ sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).
+ sortable._trigger("activate", event, uiSortable);
+ }
+ });
+
+ },
+ stop: function(event, ui) {
+
+ //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
+ var inst = $(this).data("ui-draggable"),
+ uiSortable = $.extend({}, ui, { item: inst.element });
+
+ $.each(inst.sortables, function() {
+ if(this.instance.isOver) {
+
+ this.instance.isOver = 0;
+
+ inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
+ this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
+
+ //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid"
+ if(this.shouldRevert) {
+ this.instance.options.revert = this.shouldRevert;
+ }
+
+ //Trigger the stop of the sortable
+ this.instance._mouseStop(event);
+
+ this.instance.options.helper = this.instance.options._helper;
+
+ //If the helper has been the original item, restore properties in the sortable
+ if(inst.options.helper === "original") {
+ this.instance.currentItem.css({ top: "auto", left: "auto" });
+ }
+
+ } else {
+ this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
+ this.instance._trigger("deactivate", event, uiSortable);
+ }
+
+ });
+
+ },
+ drag: function(event, ui) {
+
+ var inst = $(this).data("ui-draggable"), that = this;
+
+ $.each(inst.sortables, function() {
+
+ var innermostIntersecting = false,
+ thisSortable = this;
+
+ //Copy over some variables to allow calling the sortable's native _intersectsWith
+ this.instance.positionAbs = inst.positionAbs;
+ this.instance.helperProportions = inst.helperProportions;
+ this.instance.offset.click = inst.offset.click;
+
+ if(this.instance._intersectsWith(this.instance.containerCache)) {
+ innermostIntersecting = true;
+ $.each(inst.sortables, function () {
+ this.instance.positionAbs = inst.positionAbs;
+ this.instance.helperProportions = inst.helperProportions;
+ this.instance.offset.click = inst.offset.click;
+ if (this !== thisSortable &&
+ this.instance._intersectsWith(this.instance.containerCache) &&
+ $.contains(thisSortable.instance.element[0], this.instance.element[0])
+ ) {
+ innermostIntersecting = false;
+ }
+ return innermostIntersecting;
+ });
+ }
+
+
+ if(innermostIntersecting) {
+ //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
+ if(!this.instance.isOver) {
+
+ this.instance.isOver = 1;
+ //Now we fake the start of dragging for the sortable instance,
+ //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
+ //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
+ this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true);
+ this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
+ this.instance.options.helper = function() { return ui.helper[0]; };
+
+ event.target = this.instance.currentItem[0];
+ this.instance._mouseCapture(event, true);
+ this.instance._mouseStart(event, true, true);
+
+ //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
+ this.instance.offset.click.top = inst.offset.click.top;
+ this.instance.offset.click.left = inst.offset.click.left;
+ this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
+ this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
+
+ inst._trigger("toSortable", event);
+ inst.dropped = this.instance.element; //draggable revert needs that
+ //hack so receive/update callbacks work (mostly)
+ inst.currentItem = inst.element;
+ this.instance.fromOutside = inst;
+
+ }
+
+ //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
+ if(this.instance.currentItem) {
+ this.instance._mouseDrag(event);
+ }
+
+ } else {
+
+ //If it doesn't intersect with the sortable, and it intersected before,
+ //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
+ if(this.instance.isOver) {
+
+ this.instance.isOver = 0;
+ this.instance.cancelHelperRemoval = true;
+
+ //Prevent reverting on this forced stop
+ this.instance.options.revert = false;
+
+ // The out event needs to be triggered independently
+ this.instance._trigger("out", event, this.instance._uiHash(this.instance));
+
+ this.instance._mouseStop(event, true);
+ this.instance.options.helper = this.instance.options._helper;
+
+ //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
+ this.instance.currentItem.remove();
+ if(this.instance.placeholder) {
+ this.instance.placeholder.remove();
+ }
+
+ inst._trigger("fromSortable", event);
+ inst.dropped = false; //draggable revert needs that
+ }
+
+ }
+
+ });
+
+ }
+});
+
+$.ui.plugin.add("draggable", "cursor", {
+ start: function() {
+ var t = $("body"), o = $(this).data("ui-draggable").options;
+ if (t.css("cursor")) {
+ o._cursor = t.css("cursor");
+ }
+ t.css("cursor", o.cursor);
+ },
+ stop: function() {
+ var o = $(this).data("ui-draggable").options;
+ if (o._cursor) {
+ $("body").css("cursor", o._cursor);
+ }
+ }
+});
+
+$.ui.plugin.add("draggable", "opacity", {
+ start: function(event, ui) {
+ var t = $(ui.helper), o = $(this).data("ui-draggable").options;
+ if(t.css("opacity")) {
+ o._opacity = t.css("opacity");
+ }
+ t.css("opacity", o.opacity);
+ },
+ stop: function(event, ui) {
+ var o = $(this).data("ui-draggable").options;
+ if(o._opacity) {
+ $(ui.helper).css("opacity", o._opacity);
+ }
+ }
+});
+
+$.ui.plugin.add("draggable", "scroll", {
+ start: function() {
+ var i = $(this).data("ui-draggable");
+ if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
+ i.overflowOffset = i.scrollParent.offset();
+ }
+ },
+ drag: function( event ) {
+
+ var i = $(this).data("ui-draggable"), o = i.options, scrolled = false;
+
+ if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
+
+ if(!o.axis || o.axis !== "x") {
+ if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
+ i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
+ } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) {
+ i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
+ }
+ }
+
+ if(!o.axis || o.axis !== "y") {
+ if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
+ i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
+ } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) {
+ i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
+ }
+ }
+
+ } else {
+
+ if(!o.axis || o.axis !== "x") {
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+ } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+ }
+ }
+
+ if(!o.axis || o.axis !== "y") {
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+ } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+ }
+ }
+
+ }
+
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(i, event);
+ }
+
+ }
+});
+
+$.ui.plugin.add("draggable", "snap", {
+ start: function() {
+
+ var i = $(this).data("ui-draggable"),
+ o = i.options;
+
+ i.snapElements = [];
+
+ $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
+ var $t = $(this),
+ $o = $t.offset();
+ if(this !== i.element[0]) {
+ i.snapElements.push({
+ item: this,
+ width: $t.outerWidth(), height: $t.outerHeight(),
+ top: $o.top, left: $o.left
+ });
+ }
+ });
+
+ },
+ drag: function(event, ui) {
+
+ var ts, bs, ls, rs, l, r, t, b, i, first,
+ inst = $(this).data("ui-draggable"),
+ o = inst.options,
+ d = o.snapTolerance,
+ x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
+ y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
+
+ for (i = inst.snapElements.length - 1; i >= 0; i--){
+
+ l = inst.snapElements[i].left;
+ r = l + inst.snapElements[i].width;
+ t = inst.snapElements[i].top;
+ b = t + inst.snapElements[i].height;
+
+ if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
+ if(inst.snapElements[i].snapping) {
+ (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+ }
+ inst.snapElements[i].snapping = false;
+ continue;
+ }
+
+ if(o.snapMode !== "inner") {
+ ts = Math.abs(t - y2) <= d;
+ bs = Math.abs(b - y1) <= d;
+ ls = Math.abs(l - x2) <= d;
+ rs = Math.abs(r - x1) <= d;
+ if(ts) {
+ ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
+ }
+ if(bs) {
+ ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
+ }
+ if(ls) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
+ }
+ if(rs) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
+ }
+ }
+
+ first = (ts || bs || ls || rs);
+
+ if(o.snapMode !== "outer") {
+ ts = Math.abs(t - y1) <= d;
+ bs = Math.abs(b - y2) <= d;
+ ls = Math.abs(l - x1) <= d;
+ rs = Math.abs(r - x2) <= d;
+ if(ts) {
+ ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
+ }
+ if(bs) {
+ ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
+ }
+ if(ls) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
+ }
+ if(rs) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
+ }
+ }
+
+ if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
+ (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+ }
+ inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
+
+ }
+
+ }
+});
+
+$.ui.plugin.add("draggable", "stack", {
+ start: function() {
+ var min,
+ o = this.data("ui-draggable").options,
+ group = $.makeArray($(o.stack)).sort(function(a,b) {
+ return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
+ });
+
+ if (!group.length) { return; }
+
+ min = parseInt($(group[0]).css("zIndex"), 10) || 0;
+ $(group).each(function(i) {
+ $(this).css("zIndex", min + i);
+ });
+ this.css("zIndex", (min + group.length));
+ }
+});
+
+$.ui.plugin.add("draggable", "zIndex", {
+ start: function(event, ui) {
+ var t = $(ui.helper), o = $(this).data("ui-draggable").options;
+ if(t.css("zIndex")) {
+ o._zIndex = t.css("zIndex");
+ }
+ t.css("zIndex", o.zIndex);
+ },
+ stop: function(event, ui) {
+ var o = $(this).data("ui-draggable").options;
+ if(o._zIndex) {
+ $(ui.helper).css("zIndex", o._zIndex);
+ }
+ }
+});
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+function isOverAxis( x, reference, size ) {
+ return ( x > reference ) && ( x < ( reference + size ) );
+}
+
+$.widget("ui.droppable", {
+ version: "1.10.4",
+ widgetEventPrefix: "drop",
+ options: {
+ accept: "*",
+ activeClass: false,
+ addClasses: true,
+ greedy: false,
+ hoverClass: false,
+ scope: "default",
+ tolerance: "intersect",
+
+ // callbacks
+ activate: null,
+ deactivate: null,
+ drop: null,
+ out: null,
+ over: null
+ },
+ _create: function() {
+
+ var proportions,
+ o = this.options,
+ accept = o.accept;
+
+ this.isover = false;
+ this.isout = true;
+
+ this.accept = $.isFunction(accept) ? accept : function(d) {
+ return d.is(accept);
+ };
+
+ this.proportions = function( /* valueToWrite */ ) {
+ if ( arguments.length ) {
+ // Store the droppable's proportions
+ proportions = arguments[ 0 ];
+ } else {
+ // Retrieve or derive the droppable's proportions
+ return proportions ?
+ proportions :
+ proportions = {
+ width: this.element[ 0 ].offsetWidth,
+ height: this.element[ 0 ].offsetHeight
+ };
+ }
+ };
+
+ // Add the reference and positions to the manager
+ $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
+ $.ui.ddmanager.droppables[o.scope].push(this);
+
+ (o.addClasses && this.element.addClass("ui-droppable"));
+
+ },
+
+ _destroy: function() {
+ var i = 0,
+ drop = $.ui.ddmanager.droppables[this.options.scope];
+
+ for ( ; i < drop.length; i++ ) {
+ if ( drop[i] === this ) {
+ drop.splice(i, 1);
+ }
+ }
+
+ this.element.removeClass("ui-droppable ui-droppable-disabled");
+ },
+
+ _setOption: function(key, value) {
+
+ if(key === "accept") {
+ this.accept = $.isFunction(value) ? value : function(d) {
+ return d.is(value);
+ };
+ }
+ $.Widget.prototype._setOption.apply(this, arguments);
+ },
+
+ _activate: function(event) {
+ var draggable = $.ui.ddmanager.current;
+ if(this.options.activeClass) {
+ this.element.addClass(this.options.activeClass);
+ }
+ if(draggable){
+ this._trigger("activate", event, this.ui(draggable));
+ }
+ },
+
+ _deactivate: function(event) {
+ var draggable = $.ui.ddmanager.current;
+ if(this.options.activeClass) {
+ this.element.removeClass(this.options.activeClass);
+ }
+ if(draggable){
+ this._trigger("deactivate", event, this.ui(draggable));
+ }
+ },
+
+ _over: function(event) {
+
+ var draggable = $.ui.ddmanager.current;
+
+ // Bail if draggable and droppable are same element
+ if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
+ return;
+ }
+
+ if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.hoverClass) {
+ this.element.addClass(this.options.hoverClass);
+ }
+ this._trigger("over", event, this.ui(draggable));
+ }
+
+ },
+
+ _out: function(event) {
+
+ var draggable = $.ui.ddmanager.current;
+
+ // Bail if draggable and droppable are same element
+ if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
+ return;
+ }
+
+ if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.hoverClass) {
+ this.element.removeClass(this.options.hoverClass);
+ }
+ this._trigger("out", event, this.ui(draggable));
+ }
+
+ },
+
+ _drop: function(event,custom) {
+
+ var draggable = custom || $.ui.ddmanager.current,
+ childrenIntersection = false;
+
+ // Bail if draggable and droppable are same element
+ if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
+ return false;
+ }
+
+ this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() {
+ var inst = $.data(this, "ui-droppable");
+ if(
+ inst.options.greedy &&
+ !inst.options.disabled &&
+ inst.options.scope === draggable.options.scope &&
+ inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) &&
+ $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
+ ) { childrenIntersection = true; return false; }
+ });
+ if(childrenIntersection) {
+ return false;
+ }
+
+ if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.activeClass) {
+ this.element.removeClass(this.options.activeClass);
+ }
+ if(this.options.hoverClass) {
+ this.element.removeClass(this.options.hoverClass);
+ }
+ this._trigger("drop", event, this.ui(draggable));
+ return this.element;
+ }
+
+ return false;
+
+ },
+
+ ui: function(c) {
+ return {
+ draggable: (c.currentItem || c.element),
+ helper: c.helper,
+ position: c.position,
+ offset: c.positionAbs
+ };
+ }
+
+});
+
+$.ui.intersect = function(draggable, droppable, toleranceMode) {
+
+ if (!droppable.offset) {
+ return false;
+ }
+
+ var draggableLeft, draggableTop,
+ x1 = (draggable.positionAbs || draggable.position.absolute).left,
+ y1 = (draggable.positionAbs || draggable.position.absolute).top,
+ x2 = x1 + draggable.helperProportions.width,
+ y2 = y1 + draggable.helperProportions.height,
+ l = droppable.offset.left,
+ t = droppable.offset.top,
+ r = l + droppable.proportions().width,
+ b = t + droppable.proportions().height;
+
+ switch (toleranceMode) {
+ case "fit":
+ return (l <= x1 && x2 <= r && t <= y1 && y2 <= b);
+ case "intersect":
+ return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half
+ x2 - (draggable.helperProportions.width / 2) < r && // Left Half
+ t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half
+ y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
+ case "pointer":
+ draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left);
+ draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top);
+ return isOverAxis( draggableTop, t, droppable.proportions().height ) && isOverAxis( draggableLeft, l, droppable.proportions().width );
+ case "touch":
+ return (
+ (y1 >= t && y1 <= b) || // Top edge touching
+ (y2 >= t && y2 <= b) || // Bottom edge touching
+ (y1 < t && y2 > b) // Surrounded vertically
+ ) && (
+ (x1 >= l && x1 <= r) || // Left edge touching
+ (x2 >= l && x2 <= r) || // Right edge touching
+ (x1 < l && x2 > r) // Surrounded horizontally
+ );
+ default:
+ return false;
+ }
+
+};
+
+/*
+ This manager tracks offsets of draggables and droppables
+*/
+$.ui.ddmanager = {
+ current: null,
+ droppables: { "default": [] },
+ prepareOffsets: function(t, event) {
+
+ var i, j,
+ m = $.ui.ddmanager.droppables[t.options.scope] || [],
+ type = event ? event.type : null, // workaround for #2317
+ list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack();
+
+ droppablesLoop: for (i = 0; i < m.length; i++) {
+
+ //No disabled and non-accepted
+ if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) {
+ continue;
+ }
+
+ // Filter out elements in the current dragged item
+ for (j=0; j < list.length; j++) {
+ if(list[j] === m[i].element[0]) {
+ m[i].proportions().height = 0;
+ continue droppablesLoop;
+ }
+ }
+
+ m[i].visible = m[i].element.css("display") !== "none";
+ if(!m[i].visible) {
+ continue;
+ }
+
+ //Activate the droppable if used directly from draggables
+ if(type === "mousedown") {
+ m[i]._activate.call(m[i], event);
+ }
+
+ m[ i ].offset = m[ i ].element.offset();
+ m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight });
+
+ }
+
+ },
+ drop: function(draggable, event) {
+
+ var dropped = false;
+ // Create a copy of the droppables in case the list changes during the drop (#9116)
+ $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() {
+
+ if(!this.options) {
+ return;
+ }
+ if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) {
+ dropped = this._drop.call(this, event) || dropped;
+ }
+
+ if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ this.isout = true;
+ this.isover = false;
+ this._deactivate.call(this, event);
+ }
+
+ });
+ return dropped;
+
+ },
+ dragStart: function( draggable, event ) {
+ //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
+ draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
+ if( !draggable.options.refreshPositions ) {
+ $.ui.ddmanager.prepareOffsets( draggable, event );
+ }
+ });
+ },
+ drag: function(draggable, event) {
+
+ //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
+ if(draggable.options.refreshPositions) {
+ $.ui.ddmanager.prepareOffsets(draggable, event);
+ }
+
+ //Run through all droppables and check their positions based on specific tolerance options
+ $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
+
+ if(this.options.disabled || this.greedyChild || !this.visible) {
+ return;
+ }
+
+ var parentInstance, scope, parent,
+ intersects = $.ui.intersect(draggable, this, this.options.tolerance),
+ c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null);
+ if(!c) {
+ return;
+ }
+
+ if (this.options.greedy) {
+ // find droppable parents with same scope
+ scope = this.options.scope;
+ parent = this.element.parents(":data(ui-droppable)").filter(function () {
+ return $.data(this, "ui-droppable").options.scope === scope;
+ });
+
+ if (parent.length) {
+ parentInstance = $.data(parent[0], "ui-droppable");
+ parentInstance.greedyChild = (c === "isover");
+ }
+ }
+
+ // we just moved into a greedy child
+ if (parentInstance && c === "isover") {
+ parentInstance.isover = false;
+ parentInstance.isout = true;
+ parentInstance._out.call(parentInstance, event);
+ }
+
+ this[c] = true;
+ this[c === "isout" ? "isover" : "isout"] = false;
+ this[c === "isover" ? "_over" : "_out"].call(this, event);
+
+ // we just moved out of a greedy child
+ if (parentInstance && c === "isout") {
+ parentInstance.isout = false;
+ parentInstance.isover = true;
+ parentInstance._over.call(parentInstance, event);
+ }
+ });
+
+ },
+ dragStop: function( draggable, event ) {
+ draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
+ //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
+ if( !draggable.options.refreshPositions ) {
+ $.ui.ddmanager.prepareOffsets( draggable, event );
+ }
+ }
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+function num(v) {
+ return parseInt(v, 10) || 0;
+}
+
+function isNumber(value) {
+ return !isNaN(parseInt(value, 10));
+}
+
+$.widget("ui.resizable", $.ui.mouse, {
+ version: "1.10.4",
+ widgetEventPrefix: "resize",
+ options: {
+ alsoResize: false,
+ animate: false,
+ animateDuration: "slow",
+ animateEasing: "swing",
+ aspectRatio: false,
+ autoHide: false,
+ containment: false,
+ ghost: false,
+ grid: false,
+ handles: "e,s,se",
+ helper: false,
+ maxHeight: null,
+ maxWidth: null,
+ minHeight: 10,
+ minWidth: 10,
+ // See #7960
+ zIndex: 90,
+
+ // callbacks
+ resize: null,
+ start: null,
+ stop: null
+ },
+ _create: function() {
+
+ var n, i, handle, axis, hname,
+ that = this,
+ o = this.options;
+ this.element.addClass("ui-resizable");
+
+ $.extend(this, {
+ _aspectRatio: !!(o.aspectRatio),
+ aspectRatio: o.aspectRatio,
+ originalElement: this.element,
+ _proportionallyResizeElements: [],
+ _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
+ });
+
+ //Wrap the element if it cannot hold child nodes
+ if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
+
+ //Create a wrapper element and set the wrapper to the new current internal element
+ this.element.wrap(
+ $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
+ position: this.element.css("position"),
+ width: this.element.outerWidth(),
+ height: this.element.outerHeight(),
+ top: this.element.css("top"),
+ left: this.element.css("left")
+ })
+ );
+
+ //Overwrite the original this.element
+ this.element = this.element.parent().data(
+ "ui-resizable", this.element.data("ui-resizable")
+ );
+
+ this.elementIsWrapper = true;
+
+ //Move margins to the wrapper
+ this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
+ this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
+
+ //Prevent Safari textarea resize
+ this.originalResizeStyle = this.originalElement.css("resize");
+ this.originalElement.css("resize", "none");
+
+ //Push the actual element to our proportionallyResize internal array
+ this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" }));
+
+ // avoid IE jump (hard set the margin)
+ this.originalElement.css({ margin: this.originalElement.css("margin") });
+
+ // fix handlers offset
+ this._proportionallyResize();
+
+ }
+
+ this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" });
+ if(this.handles.constructor === String) {
+
+ if ( this.handles === "all") {
+ this.handles = "n,e,s,w,se,sw,ne,nw";
+ }
+
+ n = this.handles.split(",");
+ this.handles = {};
+
+ for(i = 0; i < n.length; i++) {
+
+ handle = $.trim(n[i]);
+ hname = "ui-resizable-"+handle;
+ axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
+
+ // Apply zIndex to all handles - see #7960
+ axis.css({ zIndex: o.zIndex });
+
+ //TODO : What's going on here?
+ if ("se" === handle) {
+ axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
+ }
+
+ //Insert into internal handles object and append to element
+ this.handles[handle] = ".ui-resizable-"+handle;
+ this.element.append(axis);
+ }
+
+ }
+
+ this._renderAxis = function(target) {
+
+ var i, axis, padPos, padWrapper;
+
+ target = target || this.element;
+
+ for(i in this.handles) {
+
+ if(this.handles[i].constructor === String) {
+ this.handles[i] = $(this.handles[i], this.element).show();
+ }
+
+ //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
+ if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
+
+ axis = $(this.handles[i], this.element);
+
+ //Checking the correct pad and border
+ padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
+
+ //The padding type i have to apply...
+ padPos = [ "padding",
+ /ne|nw|n/.test(i) ? "Top" :
+ /se|sw|s/.test(i) ? "Bottom" :
+ /^e$/.test(i) ? "Right" : "Left" ].join("");
+
+ target.css(padPos, padWrapper);
+
+ this._proportionallyResize();
+
+ }
+
+ //TODO: What's that good for? There's not anything to be executed left
+ if(!$(this.handles[i]).length) {
+ continue;
+ }
+ }
+ };
+
+ //TODO: make renderAxis a prototype function
+ this._renderAxis(this.element);
+
+ this._handles = $(".ui-resizable-handle", this.element)
+ .disableSelection();
+
+ //Matching axis name
+ this._handles.mouseover(function() {
+ if (!that.resizing) {
+ if (this.className) {
+ axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
+ }
+ //Axis, default = se
+ that.axis = axis && axis[1] ? axis[1] : "se";
+ }
+ });
+
+ //If we want to auto hide the elements
+ if (o.autoHide) {
+ this._handles.hide();
+ $(this.element)
+ .addClass("ui-resizable-autohide")
+ .mouseenter(function() {
+ if (o.disabled) {
+ return;
+ }
+ $(this).removeClass("ui-resizable-autohide");
+ that._handles.show();
+ })
+ .mouseleave(function(){
+ if (o.disabled) {
+ return;
+ }
+ if (!that.resizing) {
+ $(this).addClass("ui-resizable-autohide");
+ that._handles.hide();
+ }
+ });
+ }
+
+ //Initialize the mouse interaction
+ this._mouseInit();
+
+ },
+
+ _destroy: function() {
+
+ this._mouseDestroy();
+
+ var wrapper,
+ _destroy = function(exp) {
+ $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
+ .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove();
+ };
+
+ //TODO: Unwrap at same DOM position
+ if (this.elementIsWrapper) {
+ _destroy(this.element);
+ wrapper = this.element;
+ this.originalElement.css({
+ position: wrapper.css("position"),
+ width: wrapper.outerWidth(),
+ height: wrapper.outerHeight(),
+ top: wrapper.css("top"),
+ left: wrapper.css("left")
+ }).insertAfter( wrapper );
+ wrapper.remove();
+ }
+
+ this.originalElement.css("resize", this.originalResizeStyle);
+ _destroy(this.originalElement);
+
+ return this;
+ },
+
+ _mouseCapture: function(event) {
+ var i, handle,
+ capture = false;
+
+ for (i in this.handles) {
+ handle = $(this.handles[i])[0];
+ if (handle === event.target || $.contains(handle, event.target)) {
+ capture = true;
+ }
+ }
+
+ return !this.options.disabled && capture;
+ },
+
+ _mouseStart: function(event) {
+
+ var curleft, curtop, cursor,
+ o = this.options,
+ iniPos = this.element.position(),
+ el = this.element;
+
+ this.resizing = true;
+
+ // bugfix for http://dev.jquery.com/ticket/1749
+ if ( (/absolute/).test( el.css("position") ) ) {
+ el.css({ position: "absolute", top: el.css("top"), left: el.css("left") });
+ } else if (el.is(".ui-draggable")) {
+ el.css({ position: "absolute", top: iniPos.top, left: iniPos.left });
+ }
+
+ this._renderProxy();
+
+ curleft = num(this.helper.css("left"));
+ curtop = num(this.helper.css("top"));
+
+ if (o.containment) {
+ curleft += $(o.containment).scrollLeft() || 0;
+ curtop += $(o.containment).scrollTop() || 0;
+ }
+
+ //Store needed variables
+ this.offset = this.helper.offset();
+ this.position = { left: curleft, top: curtop };
+ this.size = this._helper ? { width: this.helper.width(), height: this.helper.height() } : { width: el.width(), height: el.height() };
+ this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
+ this.originalPosition = { left: curleft, top: curtop };
+ this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
+ this.originalMousePosition = { left: event.pageX, top: event.pageY };
+
+ //Aspect Ratio
+ this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
+
+ cursor = $(".ui-resizable-" + this.axis).css("cursor");
+ $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
+
+ el.addClass("ui-resizable-resizing");
+ this._propagate("start", event);
+ return true;
+ },
+
+ _mouseDrag: function(event) {
+
+ //Increase performance, avoid regex
+ var data,
+ el = this.helper, props = {},
+ smp = this.originalMousePosition,
+ a = this.axis,
+ prevTop = this.position.top,
+ prevLeft = this.position.left,
+ prevWidth = this.size.width,
+ prevHeight = this.size.height,
+ dx = (event.pageX-smp.left)||0,
+ dy = (event.pageY-smp.top)||0,
+ trigger = this._change[a];
+
+ if (!trigger) {
+ return false;
+ }
+
+ // Calculate the attrs that will be change
+ data = trigger.apply(this, [event, dx, dy]);
+
+ // Put this in the mouseDrag handler since the user can start pressing shift while resizing
+ this._updateVirtualBoundaries(event.shiftKey);
+ if (this._aspectRatio || event.shiftKey) {
+ data = this._updateRatio(data, event);
+ }
+
+ data = this._respectSize(data, event);
+
+ this._updateCache(data);
+
+ // plugins callbacks need to be called first
+ this._propagate("resize", event);
+
+ if (this.position.top !== prevTop) {
+ props.top = this.position.top + "px";
+ }
+ if (this.position.left !== prevLeft) {
+ props.left = this.position.left + "px";
+ }
+ if (this.size.width !== prevWidth) {
+ props.width = this.size.width + "px";
+ }
+ if (this.size.height !== prevHeight) {
+ props.height = this.size.height + "px";
+ }
+ el.css(props);
+
+ if (!this._helper && this._proportionallyResizeElements.length) {
+ this._proportionallyResize();
+ }
+
+ // Call the user callback if the element was resized
+ if ( ! $.isEmptyObject(props) ) {
+ this._trigger("resize", event, this.ui());
+ }
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+
+ this.resizing = false;
+ var pr, ista, soffseth, soffsetw, s, left, top,
+ o = this.options, that = this;
+
+ if(this._helper) {
+
+ pr = this._proportionallyResizeElements;
+ ista = pr.length && (/textarea/i).test(pr[0].nodeName);
+ soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height;
+ soffsetw = ista ? 0 : that.sizeDiff.width;
+
+ s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) };
+ left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null;
+ top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
+
+ if (!o.animate) {
+ this.element.css($.extend(s, { top: top, left: left }));
+ }
+
+ that.helper.height(that.size.height);
+ that.helper.width(that.size.width);
+
+ if (this._helper && !o.animate) {
+ this._proportionallyResize();
+ }
+ }
+
+ $("body").css("cursor", "auto");
+
+ this.element.removeClass("ui-resizable-resizing");
+
+ this._propagate("stop", event);
+
+ if (this._helper) {
+ this.helper.remove();
+ }
+
+ return false;
+
+ },
+
+ _updateVirtualBoundaries: function(forceAspectRatio) {
+ var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
+ o = this.options;
+
+ b = {
+ minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
+ maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
+ minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
+ maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
+ };
+
+ if(this._aspectRatio || forceAspectRatio) {
+ // We want to create an enclosing box whose aspect ration is the requested one
+ // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
+ pMinWidth = b.minHeight * this.aspectRatio;
+ pMinHeight = b.minWidth / this.aspectRatio;
+ pMaxWidth = b.maxHeight * this.aspectRatio;
+ pMaxHeight = b.maxWidth / this.aspectRatio;
+
+ if(pMinWidth > b.minWidth) {
+ b.minWidth = pMinWidth;
+ }
+ if(pMinHeight > b.minHeight) {
+ b.minHeight = pMinHeight;
+ }
+ if(pMaxWidth < b.maxWidth) {
+ b.maxWidth = pMaxWidth;
+ }
+ if(pMaxHeight < b.maxHeight) {
+ b.maxHeight = pMaxHeight;
+ }
+ }
+ this._vBoundaries = b;
+ },
+
+ _updateCache: function(data) {
+ this.offset = this.helper.offset();
+ if (isNumber(data.left)) {
+ this.position.left = data.left;
+ }
+ if (isNumber(data.top)) {
+ this.position.top = data.top;
+ }
+ if (isNumber(data.height)) {
+ this.size.height = data.height;
+ }
+ if (isNumber(data.width)) {
+ this.size.width = data.width;
+ }
+ },
+
+ _updateRatio: function( data ) {
+
+ var cpos = this.position,
+ csize = this.size,
+ a = this.axis;
+
+ if (isNumber(data.height)) {
+ data.width = (data.height * this.aspectRatio);
+ } else if (isNumber(data.width)) {
+ data.height = (data.width / this.aspectRatio);
+ }
+
+ if (a === "sw") {
+ data.left = cpos.left + (csize.width - data.width);
+ data.top = null;
+ }
+ if (a === "nw") {
+ data.top = cpos.top + (csize.height - data.height);
+ data.left = cpos.left + (csize.width - data.width);
+ }
+
+ return data;
+ },
+
+ _respectSize: function( data ) {
+
+ var o = this._vBoundaries,
+ a = this.axis,
+ ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
+ isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
+ dw = this.originalPosition.left + this.originalSize.width,
+ dh = this.position.top + this.size.height,
+ cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
+ if (isminw) {
+ data.width = o.minWidth;
+ }
+ if (isminh) {
+ data.height = o.minHeight;
+ }
+ if (ismaxw) {
+ data.width = o.maxWidth;
+ }
+ if (ismaxh) {
+ data.height = o.maxHeight;
+ }
+
+ if (isminw && cw) {
+ data.left = dw - o.minWidth;
+ }
+ if (ismaxw && cw) {
+ data.left = dw - o.maxWidth;
+ }
+ if (isminh && ch) {
+ data.top = dh - o.minHeight;
+ }
+ if (ismaxh && ch) {
+ data.top = dh - o.maxHeight;
+ }
+
+ // fixing jump error on top/left - bug #2330
+ if (!data.width && !data.height && !data.left && data.top) {
+ data.top = null;
+ } else if (!data.width && !data.height && !data.top && data.left) {
+ data.left = null;
+ }
+
+ return data;
+ },
+
+ _proportionallyResize: function() {
+
+ if (!this._proportionallyResizeElements.length) {
+ return;
+ }
+
+ var i, j, borders, paddings, prel,
+ element = this.helper || this.element;
+
+ for ( i=0; i < this._proportionallyResizeElements.length; i++) {
+
+ prel = this._proportionallyResizeElements[i];
+
+ if (!this.borderDif) {
+ this.borderDif = [];
+ borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")];
+ paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")];
+
+ for ( j = 0; j < borders.length; j++ ) {
+ this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 );
+ }
+ }
+
+ prel.css({
+ height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
+ width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
+ });
+
+ }
+
+ },
+
+ _renderProxy: function() {
+
+ var el = this.element, o = this.options;
+ this.elementOffset = el.offset();
+
+ if(this._helper) {
+
+ this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
+
+ this.helper.addClass(this._helper).css({
+ width: this.element.outerWidth() - 1,
+ height: this.element.outerHeight() - 1,
+ position: "absolute",
+ left: this.elementOffset.left +"px",
+ top: this.elementOffset.top +"px",
+ zIndex: ++o.zIndex //TODO: Don't modify option
+ });
+
+ this.helper
+ .appendTo("body")
+ .disableSelection();
+
+ } else {
+ this.helper = this.element;
+ }
+
+ },
+
+ _change: {
+ e: function(event, dx) {
+ return { width: this.originalSize.width + dx };
+ },
+ w: function(event, dx) {
+ var cs = this.originalSize, sp = this.originalPosition;
+ return { left: sp.left + dx, width: cs.width - dx };
+ },
+ n: function(event, dx, dy) {
+ var cs = this.originalSize, sp = this.originalPosition;
+ return { top: sp.top + dy, height: cs.height - dy };
+ },
+ s: function(event, dx, dy) {
+ return { height: this.originalSize.height + dy };
+ },
+ se: function(event, dx, dy) {
+ return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
+ },
+ sw: function(event, dx, dy) {
+ return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
+ },
+ ne: function(event, dx, dy) {
+ return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
+ },
+ nw: function(event, dx, dy) {
+ return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
+ }
+ },
+
+ _propagate: function(n, event) {
+ $.ui.plugin.call(this, n, [event, this.ui()]);
+ (n !== "resize" && this._trigger(n, event, this.ui()));
+ },
+
+ plugins: {},
+
+ ui: function() {
+ return {
+ originalElement: this.originalElement,
+ element: this.element,
+ helper: this.helper,
+ position: this.position,
+ size: this.size,
+ originalSize: this.originalSize,
+ originalPosition: this.originalPosition
+ };
+ }
+
+});
+
+/*
+ * Resizable Extensions
+ */
+
+$.ui.plugin.add("resizable", "animate", {
+
+ stop: function( event ) {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ pr = that._proportionallyResizeElements,
+ ista = pr.length && (/textarea/i).test(pr[0].nodeName),
+ soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height,
+ soffsetw = ista ? 0 : that.sizeDiff.width,
+ style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
+ left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null,
+ top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
+
+ that.element.animate(
+ $.extend(style, top && left ? { top: top, left: left } : {}), {
+ duration: o.animateDuration,
+ easing: o.animateEasing,
+ step: function() {
+
+ var data = {
+ width: parseInt(that.element.css("width"), 10),
+ height: parseInt(that.element.css("height"), 10),
+ top: parseInt(that.element.css("top"), 10),
+ left: parseInt(that.element.css("left"), 10)
+ };
+
+ if (pr && pr.length) {
+ $(pr[0]).css({ width: data.width, height: data.height });
+ }
+
+ // propagating resize, and updating values for each animation step
+ that._updateCache(data);
+ that._propagate("resize", event);
+
+ }
+ }
+ );
+ }
+
+});
+
+$.ui.plugin.add("resizable", "containment", {
+
+ start: function() {
+ var element, p, co, ch, cw, width, height,
+ that = $(this).data("ui-resizable"),
+ o = that.options,
+ el = that.element,
+ oc = o.containment,
+ ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
+
+ if (!ce) {
+ return;
+ }
+
+ that.containerElement = $(ce);
+
+ if (/document/.test(oc) || oc === document) {
+ that.containerOffset = { left: 0, top: 0 };
+ that.containerPosition = { left: 0, top: 0 };
+
+ that.parentData = {
+ element: $(document), left: 0, top: 0,
+ width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
+ };
+ }
+
+ // i'm a node, so compute top, left, right, bottom
+ else {
+ element = $(ce);
+ p = [];
+ $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
+
+ that.containerOffset = element.offset();
+ that.containerPosition = element.position();
+ that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
+
+ co = that.containerOffset;
+ ch = that.containerSize.height;
+ cw = that.containerSize.width;
+ width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw );
+ height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
+
+ that.parentData = {
+ element: ce, left: co.left, top: co.top, width: width, height: height
+ };
+ }
+ },
+
+ resize: function( event ) {
+ var woset, hoset, isParent, isOffsetRelative,
+ that = $(this).data("ui-resizable"),
+ o = that.options,
+ co = that.containerOffset, cp = that.position,
+ pRatio = that._aspectRatio || event.shiftKey,
+ cop = { top:0, left:0 }, ce = that.containerElement;
+
+ if (ce[0] !== document && (/static/).test(ce.css("position"))) {
+ cop = co;
+ }
+
+ if (cp.left < (that._helper ? co.left : 0)) {
+ that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left));
+ if (pRatio) {
+ that.size.height = that.size.width / that.aspectRatio;
+ }
+ that.position.left = o.helper ? co.left : 0;
+ }
+
+ if (cp.top < (that._helper ? co.top : 0)) {
+ that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top);
+ if (pRatio) {
+ that.size.width = that.size.height * that.aspectRatio;
+ }
+ that.position.top = that._helper ? co.top : 0;
+ }
+
+ that.offset.left = that.parentData.left+that.position.left;
+ that.offset.top = that.parentData.top+that.position.top;
+
+ woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width );
+ hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height );
+
+ isParent = that.containerElement.get(0) === that.element.parent().get(0);
+ isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position"));
+
+ if ( isParent && isOffsetRelative ) {
+ woset -= Math.abs( that.parentData.left );
+ }
+
+ if (woset + that.size.width >= that.parentData.width) {
+ that.size.width = that.parentData.width - woset;
+ if (pRatio) {
+ that.size.height = that.size.width / that.aspectRatio;
+ }
+ }
+
+ if (hoset + that.size.height >= that.parentData.height) {
+ that.size.height = that.parentData.height - hoset;
+ if (pRatio) {
+ that.size.width = that.size.height * that.aspectRatio;
+ }
+ }
+ },
+
+ stop: function(){
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ co = that.containerOffset,
+ cop = that.containerPosition,
+ ce = that.containerElement,
+ helper = $(that.helper),
+ ho = helper.offset(),
+ w = helper.outerWidth() - that.sizeDiff.width,
+ h = helper.outerHeight() - that.sizeDiff.height;
+
+ if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) {
+ $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
+ }
+
+ if (that._helper && !o.animate && (/static/).test(ce.css("position"))) {
+ $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
+ }
+
+ }
+});
+
+$.ui.plugin.add("resizable", "alsoResize", {
+
+ start: function () {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ _store = function (exp) {
+ $(exp).each(function() {
+ var el = $(this);
+ el.data("ui-resizable-alsoresize", {
+ width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
+ left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
+ });
+ });
+ };
+
+ if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
+ if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
+ else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
+ }else{
+ _store(o.alsoResize);
+ }
+ },
+
+ resize: function (event, ui) {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ os = that.originalSize,
+ op = that.originalPosition,
+ delta = {
+ height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,
+ top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0
+ },
+
+ _alsoResize = function (exp, c) {
+ $(exp).each(function() {
+ var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
+ css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"];
+
+ $.each(css, function (i, prop) {
+ var sum = (start[prop]||0) + (delta[prop]||0);
+ if (sum && sum >= 0) {
+ style[prop] = sum || null;
+ }
+ });
+
+ el.css(style);
+ });
+ };
+
+ if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
+ $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
+ }else{
+ _alsoResize(o.alsoResize);
+ }
+ },
+
+ stop: function () {
+ $(this).removeData("resizable-alsoresize");
+ }
+});
+
+$.ui.plugin.add("resizable", "ghost", {
+
+ start: function() {
+
+ var that = $(this).data("ui-resizable"), o = that.options, cs = that.size;
+
+ that.ghost = that.originalElement.clone();
+ that.ghost
+ .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
+ .addClass("ui-resizable-ghost")
+ .addClass(typeof o.ghost === "string" ? o.ghost : "");
+
+ that.ghost.appendTo(that.helper);
+
+ },
+
+ resize: function(){
+ var that = $(this).data("ui-resizable");
+ if (that.ghost) {
+ that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width });
+ }
+ },
+
+ stop: function() {
+ var that = $(this).data("ui-resizable");
+ if (that.ghost && that.helper) {
+ that.helper.get(0).removeChild(that.ghost.get(0));
+ }
+ }
+
+});
+
+$.ui.plugin.add("resizable", "grid", {
+
+ resize: function() {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ cs = that.size,
+ os = that.originalSize,
+ op = that.originalPosition,
+ a = that.axis,
+ grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid,
+ gridX = (grid[0]||1),
+ gridY = (grid[1]||1),
+ ox = Math.round((cs.width - os.width) / gridX) * gridX,
+ oy = Math.round((cs.height - os.height) / gridY) * gridY,
+ newWidth = os.width + ox,
+ newHeight = os.height + oy,
+ isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
+ isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
+ isMinWidth = o.minWidth && (o.minWidth > newWidth),
+ isMinHeight = o.minHeight && (o.minHeight > newHeight);
+
+ o.grid = grid;
+
+ if (isMinWidth) {
+ newWidth = newWidth + gridX;
+ }
+ if (isMinHeight) {
+ newHeight = newHeight + gridY;
+ }
+ if (isMaxWidth) {
+ newWidth = newWidth - gridX;
+ }
+ if (isMaxHeight) {
+ newHeight = newHeight - gridY;
+ }
+
+ if (/^(se|s|e)$/.test(a)) {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ } else if (/^(ne)$/.test(a)) {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ that.position.top = op.top - oy;
+ } else if (/^(sw)$/.test(a)) {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ that.position.left = op.left - ox;
+ } else {
+ if ( newHeight - gridY > 0 ) {
+ that.size.height = newHeight;
+ that.position.top = op.top - oy;
+ } else {
+ that.size.height = gridY;
+ that.position.top = op.top + os.height - gridY;
+ }
+ if ( newWidth - gridX > 0 ) {
+ that.size.width = newWidth;
+ that.position.left = op.left - ox;
+ } else {
+ that.size.width = gridX;
+ that.position.left = op.left + os.width - gridX;
+ }
+ }
+ }
+
+});
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.widget("ui.selectable", $.ui.mouse, {
+ version: "1.10.4",
+ options: {
+ appendTo: "body",
+ autoRefresh: true,
+ distance: 0,
+ filter: "*",
+ tolerance: "touch",
+
+ // callbacks
+ selected: null,
+ selecting: null,
+ start: null,
+ stop: null,
+ unselected: null,
+ unselecting: null
+ },
+ _create: function() {
+ var selectees,
+ that = this;
+
+ this.element.addClass("ui-selectable");
+
+ this.dragged = false;
+
+ // cache selectee children based on filter
+ this.refresh = function() {
+ selectees = $(that.options.filter, that.element[0]);
+ selectees.addClass("ui-selectee");
+ selectees.each(function() {
+ var $this = $(this),
+ pos = $this.offset();
+ $.data(this, "selectable-item", {
+ element: this,
+ $element: $this,
+ left: pos.left,
+ top: pos.top,
+ right: pos.left + $this.outerWidth(),
+ bottom: pos.top + $this.outerHeight(),
+ startselected: false,
+ selected: $this.hasClass("ui-selected"),
+ selecting: $this.hasClass("ui-selecting"),
+ unselecting: $this.hasClass("ui-unselecting")
+ });
+ });
+ };
+ this.refresh();
+
+ this.selectees = selectees.addClass("ui-selectee");
+
+ this._mouseInit();
+
+ this.helper = $("<div class='ui-selectable-helper'></div>");
+ },
+
+ _destroy: function() {
+ this.selectees
+ .removeClass("ui-selectee")
+ .removeData("selectable-item");
+ this.element
+ .removeClass("ui-selectable ui-selectable-disabled");
+ this._mouseDestroy();
+ },
+
+ _mouseStart: function(event) {
+ var that = this,
+ options = this.options;
+
+ this.opos = [event.pageX, event.pageY];
+
+ if (this.options.disabled) {
+ return;
+ }
+
+ this.selectees = $(options.filter, this.element[0]);
+
+ this._trigger("start", event);
+
+ $(options.appendTo).append(this.helper);
+ // position helper (lasso)
+ this.helper.css({
+ "left": event.pageX,
+ "top": event.pageY,
+ "width": 0,
+ "height": 0
+ });
+
+ if (options.autoRefresh) {
+ this.refresh();
+ }
+
+ this.selectees.filter(".ui-selected").each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.startselected = true;
+ if (!event.metaKey && !event.ctrlKey) {
+ selectee.$element.removeClass("ui-selected");
+ selectee.selected = false;
+ selectee.$element.addClass("ui-unselecting");
+ selectee.unselecting = true;
+ // selectable UNSELECTING callback
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ });
+
+ $(event.target).parents().addBack().each(function() {
+ var doSelect,
+ selectee = $.data(this, "selectable-item");
+ if (selectee) {
+ doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
+ selectee.$element
+ .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
+ .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
+ selectee.unselecting = !doSelect;
+ selectee.selecting = doSelect;
+ selectee.selected = doSelect;
+ // selectable (UN)SELECTING callback
+ if (doSelect) {
+ that._trigger("selecting", event, {
+ selecting: selectee.element
+ });
+ } else {
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ return false;
+ }
+ });
+
+ },
+
+ _mouseDrag: function(event) {
+
+ this.dragged = true;
+
+ if (this.options.disabled) {
+ return;
+ }
+
+ var tmp,
+ that = this,
+ options = this.options,
+ x1 = this.opos[0],
+ y1 = this.opos[1],
+ x2 = event.pageX,
+ y2 = event.pageY;
+
+ if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
+ if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
+ this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
+
+ this.selectees.each(function() {
+ var selectee = $.data(this, "selectable-item"),
+ hit = false;
+
+ //prevent helper from being selected if appendTo: selectable
+ if (!selectee || selectee.element === that.element[0]) {
+ return;
+ }
+
+ if (options.tolerance === "touch") {
+ hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
+ } else if (options.tolerance === "fit") {
+ hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
+ }
+
+ if (hit) {
+ // SELECT
+ if (selectee.selected) {
+ selectee.$element.removeClass("ui-selected");
+ selectee.selected = false;
+ }
+ if (selectee.unselecting) {
+ selectee.$element.removeClass("ui-unselecting");
+ selectee.unselecting = false;
+ }
+ if (!selectee.selecting) {
+ selectee.$element.addClass("ui-selecting");
+ selectee.selecting = true;
+ // selectable SELECTING callback
+ that._trigger("selecting", event, {
+ selecting: selectee.element
+ });
+ }
+ } else {
+ // UNSELECT
+ if (selectee.selecting) {
+ if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
+ selectee.$element.removeClass("ui-selecting");
+ selectee.selecting = false;
+ selectee.$element.addClass("ui-selected");
+ selectee.selected = true;
+ } else {
+ selectee.$element.removeClass("ui-selecting");
+ selectee.selecting = false;
+ if (selectee.startselected) {
+ selectee.$element.addClass("ui-unselecting");
+ selectee.unselecting = true;
+ }
+ // selectable UNSELECTING callback
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ }
+ if (selectee.selected) {
+ if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
+ selectee.$element.removeClass("ui-selected");
+ selectee.selected = false;
+
+ selectee.$element.addClass("ui-unselecting");
+ selectee.unselecting = true;
+ // selectable UNSELECTING callback
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ }
+ }
+ });
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+ var that = this;
+
+ this.dragged = false;
+
+ $(".ui-unselecting", this.element[0]).each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.$element.removeClass("ui-unselecting");
+ selectee.unselecting = false;
+ selectee.startselected = false;
+ that._trigger("unselected", event, {
+ unselected: selectee.element
+ });
+ });
+ $(".ui-selecting", this.element[0]).each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
+ selectee.selecting = false;
+ selectee.selected = true;
+ selectee.startselected = true;
+ that._trigger("selected", event, {
+ selected: selectee.element
+ });
+ });
+ this._trigger("stop", event);
+
+ this.helper.remove();
+
+ return false;
+ }
+
+});
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+function isOverAxis( x, reference, size ) {
+ return ( x > reference ) && ( x < ( reference + size ) );
+}
+
+function isFloating(item) {
+ return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
+}
+
+$.widget("ui.sortable", $.ui.mouse, {
+ version: "1.10.4",
+ widgetEventPrefix: "sort",
+ ready: false,
+ options: {
+ appendTo: "parent",
+ axis: false,
+ connectWith: false,
+ containment: false,
+ cursor: "auto",
+ cursorAt: false,
+ dropOnEmpty: true,
+ forcePlaceholderSize: false,
+ forceHelperSize: false,
+ grid: false,
+ handle: false,
+ helper: "original",
+ items: "> *",
+ opacity: false,
+ placeholder: false,
+ revert: false,
+ scroll: true,
+ scrollSensitivity: 20,
+ scrollSpeed: 20,
+ scope: "default",
+ tolerance: "intersect",
+ zIndex: 1000,
+
+ // callbacks
+ activate: null,
+ beforeStop: null,
+ change: null,
+ deactivate: null,
+ out: null,
+ over: null,
+ receive: null,
+ remove: null,
+ sort: null,
+ start: null,
+ stop: null,
+ update: null
+ },
+ _create: function() {
+
+ var o = this.options;
+ this.containerCache = {};
+ this.element.addClass("ui-sortable");
+
+ //Get the items
+ this.refresh();
+
+ //Let's determine if the items are being displayed horizontally
+ this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false;
+
+ //Let's determine the parent's offset
+ this.offset = this.element.offset();
+
+ //Initialize mouse events for interaction
+ this._mouseInit();
+
+ //We're ready to go
+ this.ready = true;
+
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass("ui-sortable ui-sortable-disabled");
+ this._mouseDestroy();
+
+ for ( var i = this.items.length - 1; i >= 0; i-- ) {
+ this.items[i].item.removeData(this.widgetName + "-item");
+ }
+
+ return this;
+ },
+
+ _setOption: function(key, value){
+ if ( key === "disabled" ) {
+ this.options[ key ] = value;
+
+ this.widget().toggleClass( "ui-sortable-disabled", !!value );
+ } else {
+ // Don't call widget base _setOption for disable as it adds ui-state-disabled class
+ $.Widget.prototype._setOption.apply(this, arguments);
+ }
+ },
+
+ _mouseCapture: function(event, overrideHandle) {
+ var currentItem = null,
+ validHandle = false,
+ that = this;
+
+ if (this.reverting) {
+ return false;
+ }
+
+ if(this.options.disabled || this.options.type === "static") {
+ return false;
+ }
+
+ //We have to refresh the items data once first
+ this._refreshItems(event);
+
+ //Find out if the clicked node (or one of its parents) is a actual item in this.items
+ $(event.target).parents().each(function() {
+ if($.data(this, that.widgetName + "-item") === that) {
+ currentItem = $(this);
+ return false;
+ }
+ });
+ if($.data(event.target, that.widgetName + "-item") === that) {
+ currentItem = $(event.target);
+ }
+
+ if(!currentItem) {
+ return false;
+ }
+ if(this.options.handle && !overrideHandle) {
+ $(this.options.handle, currentItem).find("*").addBack().each(function() {
+ if(this === event.target) {
+ validHandle = true;
+ }
+ });
+ if(!validHandle) {
+ return false;
+ }
+ }
+
+ this.currentItem = currentItem;
+ this._removeCurrentsFromItems();
+ return true;
+
+ },
+
+ _mouseStart: function(event, overrideHandle, noActivation) {
+
+ var i, body,
+ o = this.options;
+
+ this.currentContainer = this;
+
+ //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
+ this.refreshPositions();
+
+ //Create and append the visible helper
+ this.helper = this._createHelper(event);
+
+ //Cache the helper size
+ this._cacheHelperProportions();
+
+ /*
+ * - Position generation -
+ * This block generates everything position related - it's the core of draggables.
+ */
+
+ //Cache the margins of the original element
+ this._cacheMargins();
+
+ //Get the next scrolling parent
+ this.scrollParent = this.helper.scrollParent();
+
+ //The element's absolute position on the page minus margins
+ this.offset = this.currentItem.offset();
+ this.offset = {
+ top: this.offset.top - this.margins.top,
+ left: this.offset.left - this.margins.left
+ };
+
+ $.extend(this.offset, {
+ click: { //Where the click happened, relative to the element
+ left: event.pageX - this.offset.left,
+ top: event.pageY - this.offset.top
+ },
+ parent: this._getParentOffset(),
+ relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+ });
+
+ // Only after we got the offset, we can change the helper's position to absolute
+ // TODO: Still need to figure out a way to make relative sorting possible
+ this.helper.css("position", "absolute");
+ this.cssPosition = this.helper.css("position");
+
+ //Generate the original position
+ this.originalPosition = this._generatePosition(event);
+ this.originalPageX = event.pageX;
+ this.originalPageY = event.pageY;
+
+ //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
+ (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+ //Cache the former DOM position
+ this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
+
+ //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
+ if(this.helper[0] !== this.currentItem[0]) {
+ this.currentItem.hide();
+ }
+
+ //Create the placeholder
+ this._createPlaceholder();
+
+ //Set a containment if given in the options
+ if(o.containment) {
+ this._setContainment();
+ }
+
+ if( o.cursor && o.cursor !== "auto" ) { // cursor option
+ body = this.document.find( "body" );
+
+ // support: IE
+ this.storedCursor = body.css( "cursor" );
+ body.css( "cursor", o.cursor );
+
+ this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
+ }
+
+ if(o.opacity) { // opacity option
+ if (this.helper.css("opacity")) {
+ this._storedOpacity = this.helper.css("opacity");
+ }
+ this.helper.css("opacity", o.opacity);
+ }
+
+ if(o.zIndex) { // zIndex option
+ if (this.helper.css("zIndex")) {
+ this._storedZIndex = this.helper.css("zIndex");
+ }
+ this.helper.css("zIndex", o.zIndex);
+ }
+
+ //Prepare scrolling
+ if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
+ this.overflowOffset = this.scrollParent.offset();
+ }
+
+ //Call callbacks
+ this._trigger("start", event, this._uiHash());
+
+ //Recache the helper size
+ if(!this._preserveHelperProportions) {
+ this._cacheHelperProportions();
+ }
+
+
+ //Post "activate" events to possible containers
+ if( !noActivation ) {
+ for ( i = this.containers.length - 1; i >= 0; i-- ) {
+ this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
+ }
+ }
+
+ //Prepare possible droppables
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.current = this;
+ }
+
+ if ($.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+
+ this.dragging = true;
+
+ this.helper.addClass("ui-sortable-helper");
+ this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+ return true;
+
+ },
+
+ _mouseDrag: function(event) {
+ var i, item, itemElement, intersection,
+ o = this.options,
+ scrolled = false;
+
+ //Compute the helpers position
+ this.position = this._generatePosition(event);
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ if (!this.lastPositionAbs) {
+ this.lastPositionAbs = this.positionAbs;
+ }
+
+ //Do scrolling
+ if(this.options.scroll) {
+ if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
+
+ if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
+ } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
+ }
+
+ if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
+ } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
+ }
+
+ } else {
+
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+ } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+ }
+
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+ } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+ }
+
+ }
+
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+ }
+
+ //Regenerate the absolute position used for position checks
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ //Set the helper position
+ if(!this.options.axis || this.options.axis !== "y") {
+ this.helper[0].style.left = this.position.left+"px";
+ }
+ if(!this.options.axis || this.options.axis !== "x") {
+ this.helper[0].style.top = this.position.top+"px";
+ }
+
+ //Rearrange
+ for (i = this.items.length - 1; i >= 0; i--) {
+
+ //Cache variables and intersection, continue if no intersection
+ item = this.items[i];
+ itemElement = item.item[0];
+ intersection = this._intersectsWithPointer(item);
+ if (!intersection) {
+ continue;
+ }
+
+ // Only put the placeholder inside the current Container, skip all
+ // items from other containers. This works because when moving
+ // an item from one container to another the
+ // currentContainer is switched before the placeholder is moved.
+ //
+ // Without this, moving items in "sub-sortables" can cause
+ // the placeholder to jitter beetween the outer and inner container.
+ if (item.instance !== this.currentContainer) {
+ continue;
+ }
+
+ // cannot intersect with itself
+ // no useless actions that have been done before
+ // no action if the item moved is the parent of the item checked
+ if (itemElement !== this.currentItem[0] &&
+ this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
+ !$.contains(this.placeholder[0], itemElement) &&
+ (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
+ ) {
+
+ this.direction = intersection === 1 ? "down" : "up";
+
+ if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
+ this._rearrange(event, item);
+ } else {
+ break;
+ }
+
+ this._trigger("change", event, this._uiHash());
+ break;
+ }
+ }
+
+ //Post events to containers
+ this._contactContainers(event);
+
+ //Interconnect with droppables
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.drag(this, event);
+ }
+
+ //Call callbacks
+ this._trigger("sort", event, this._uiHash());
+
+ this.lastPositionAbs = this.positionAbs;
+ return false;
+
+ },
+
+ _mouseStop: function(event, noPropagation) {
+
+ if(!event) {
+ return;
+ }
+
+ //If we are using droppables, inform the manager about the drop
+ if ($.ui.ddmanager && !this.options.dropBehaviour) {
+ $.ui.ddmanager.drop(this, event);
+ }
+
+ if(this.options.revert) {
+ var that = this,
+ cur = this.placeholder.offset(),
+ axis = this.options.axis,
+ animation = {};
+
+ if ( !axis || axis === "x" ) {
+ animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft);
+ }
+ if ( !axis || axis === "y" ) {
+ animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop);
+ }
+ this.reverting = true;
+ $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
+ that._clear(event);
+ });
+ } else {
+ this._clear(event, noPropagation);
+ }
+
+ return false;
+
+ },
+
+ cancel: function() {
+
+ if(this.dragging) {
+
+ this._mouseUp({ target: null });
+
+ if(this.options.helper === "original") {
+ this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+ } else {
+ this.currentItem.show();
+ }
+
+ //Post deactivating events to containers
+ for (var i = this.containers.length - 1; i >= 0; i--){
+ this.containers[i]._trigger("deactivate", null, this._uiHash(this));
+ if(this.containers[i].containerCache.over) {
+ this.containers[i]._trigger("out", null, this._uiHash(this));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ }
+
+ if (this.placeholder) {
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+ if(this.placeholder[0].parentNode) {
+ this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+ }
+ if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
+ this.helper.remove();
+ }
+
+ $.extend(this, {
+ helper: null,
+ dragging: false,
+ reverting: false,
+ _noFinalSort: null
+ });
+
+ if(this.domPosition.prev) {
+ $(this.domPosition.prev).after(this.currentItem);
+ } else {
+ $(this.domPosition.parent).prepend(this.currentItem);
+ }
+ }
+
+ return this;
+
+ },
+
+ serialize: function(o) {
+
+ var items = this._getItemsAsjQuery(o && o.connected),
+ str = [];
+ o = o || {};
+
+ $(items).each(function() {
+ var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
+ if (res) {
+ str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
+ }
+ });
+
+ if(!str.length && o.key) {
+ str.push(o.key + "=");
+ }
+
+ return str.join("&");
+
+ },
+
+ toArray: function(o) {
+
+ var items = this._getItemsAsjQuery(o && o.connected),
+ ret = [];
+
+ o = o || {};
+
+ items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
+ return ret;
+
+ },
+
+ /* Be careful with the following core functions */
+ _intersectsWith: function(item) {
+
+ var x1 = this.positionAbs.left,
+ x2 = x1 + this.helperProportions.width,
+ y1 = this.positionAbs.top,
+ y2 = y1 + this.helperProportions.height,
+ l = item.left,
+ r = l + item.width,
+ t = item.top,
+ b = t + item.height,
+ dyClick = this.offset.click.top,
+ dxClick = this.offset.click.left,
+ isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
+ isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
+ isOverElement = isOverElementHeight && isOverElementWidth;
+
+ if ( this.options.tolerance === "pointer" ||
+ this.options.forcePointerForContainers ||
+ (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
+ ) {
+ return isOverElement;
+ } else {
+
+ return (l < x1 + (this.helperProportions.width / 2) && // Right Half
+ x2 - (this.helperProportions.width / 2) < r && // Left Half
+ t < y1 + (this.helperProportions.height / 2) && // Bottom Half
+ y2 - (this.helperProportions.height / 2) < b ); // Top Half
+
+ }
+ },
+
+ _intersectsWithPointer: function(item) {
+
+ var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
+ isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
+ isOverElement = isOverElementHeight && isOverElementWidth,
+ verticalDirection = this._getDragVerticalDirection(),
+ horizontalDirection = this._getDragHorizontalDirection();
+
+ if (!isOverElement) {
+ return false;
+ }
+
+ return this.floating ?
+ ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
+ : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
+
+ },
+
+ _intersectsWithSides: function(item) {
+
+ var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
+ isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
+ verticalDirection = this._getDragVerticalDirection(),
+ horizontalDirection = this._getDragHorizontalDirection();
+
+ if (this.floating && horizontalDirection) {
+ return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
+ } else {
+ return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
+ }
+
+ },
+
+ _getDragVerticalDirection: function() {
+ var delta = this.positionAbs.top - this.lastPositionAbs.top;
+ return delta !== 0 && (delta > 0 ? "down" : "up");
+ },
+
+ _getDragHorizontalDirection: function() {
+ var delta = this.positionAbs.left - this.lastPositionAbs.left;
+ return delta !== 0 && (delta > 0 ? "right" : "left");
+ },
+
+ refresh: function(event) {
+ this._refreshItems(event);
+ this.refreshPositions();
+ return this;
+ },
+
+ _connectWith: function() {
+ var options = this.options;
+ return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
+ },
+
+ _getItemsAsjQuery: function(connected) {
+
+ var i, j, cur, inst,
+ items = [],
+ queries = [],
+ connectWith = this._connectWith();
+
+ if(connectWith && connected) {
+ for (i = connectWith.length - 1; i >= 0; i--){
+ cur = $(connectWith[i]);
+ for ( j = cur.length - 1; j >= 0; j--){
+ inst = $.data(cur[j], this.widgetFullName);
+ if(inst && inst !== this && !inst.options.disabled) {
+ queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]);
+ }
+ }
+ }
+ }
+
+ queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]);
+
+ function addItems() {
+ items.push( this );
+ }
+ for (i = queries.length - 1; i >= 0; i--){
+ queries[i][0].each( addItems );
+ }
+
+ return $(items);
+
+ },
+
+ _removeCurrentsFromItems: function() {
+
+ var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
+
+ this.items = $.grep(this.items, function (item) {
+ for (var j=0; j < list.length; j++) {
+ if(list[j] === item.item[0]) {
+ return false;
+ }
+ }
+ return true;
+ });
+
+ },
+
+ _refreshItems: function(event) {
+
+ this.items = [];
+ this.containers = [this];
+
+ var i, j, cur, inst, targetData, _queries, item, queriesLength,
+ items = this.items,
+ queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
+ connectWith = this._connectWith();
+
+ if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
+ for (i = connectWith.length - 1; i >= 0; i--){
+ cur = $(connectWith[i]);
+ for (j = cur.length - 1; j >= 0; j--){
+ inst = $.data(cur[j], this.widgetFullName);
+ if(inst && inst !== this && !inst.options.disabled) {
+ queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
+ this.containers.push(inst);
+ }
+ }
+ }
+ }
+
+ for (i = queries.length - 1; i >= 0; i--) {
+ targetData = queries[i][1];
+ _queries = queries[i][0];
+
+ for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
+ item = $(_queries[j]);
+
+ item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
+
+ items.push({
+ item: item,
+ instance: targetData,
+ width: 0, height: 0,
+ left: 0, top: 0
+ });
+ }
+ }
+
+ },
+
+ refreshPositions: function(fast) {
+
+ //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
+ if(this.offsetParent && this.helper) {
+ this.offset.parent = this._getParentOffset();
+ }
+
+ var i, item, t, p;
+
+ for (i = this.items.length - 1; i >= 0; i--){
+ item = this.items[i];
+
+ //We ignore calculating positions of all connected containers when we're not over them
+ if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
+ continue;
+ }
+
+ t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
+
+ if (!fast) {
+ item.width = t.outerWidth();
+ item.height = t.outerHeight();
+ }
+
+ p = t.offset();
+ item.left = p.left;
+ item.top = p.top;
+ }
+
+ if(this.options.custom && this.options.custom.refreshContainers) {
+ this.options.custom.refreshContainers.call(this);
+ } else {
+ for (i = this.containers.length - 1; i >= 0; i--){
+ p = this.containers[i].element.offset();
+ this.containers[i].containerCache.left = p.left;
+ this.containers[i].containerCache.top = p.top;
+ this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
+ this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
+ }
+ }
+
+ return this;
+ },
+
+ _createPlaceholder: function(that) {
+ that = that || this;
+ var className,
+ o = that.options;
+
+ if(!o.placeholder || o.placeholder.constructor === String) {
+ className = o.placeholder;
+ o.placeholder = {
+ element: function() {
+
+ var nodeName = that.currentItem[0].nodeName.toLowerCase(),
+ element = $( "<" + nodeName + ">", that.document[0] )
+ .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
+ .removeClass("ui-sortable-helper");
+
+ if ( nodeName === "tr" ) {
+ that.currentItem.children().each(function() {
+ $( "<td>&#160;</td>", that.document[0] )
+ .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
+ .appendTo( element );
+ });
+ } else if ( nodeName === "img" ) {
+ element.attr( "src", that.currentItem.attr( "src" ) );
+ }
+
+ if ( !className ) {
+ element.css( "visibility", "hidden" );
+ }
+
+ return element;
+ },
+ update: function(container, p) {
+
+ // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
+ // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
+ if(className && !o.forcePlaceholderSize) {
+ return;
+ }
+
+ //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
+ if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
+ if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
+ }
+ };
+ }
+
+ //Create the placeholder
+ that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
+
+ //Append it after the actual current item
+ that.currentItem.after(that.placeholder);
+
+ //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
+ o.placeholder.update(that, that.placeholder);
+
+ },
+
+ _contactContainers: function(event) {
+ var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating,
+ innermostContainer = null,
+ innermostIndex = null;
+
+ // get innermost container that intersects with item
+ for (i = this.containers.length - 1; i >= 0; i--) {
+
+ // never consider a container that's located within the item itself
+ if($.contains(this.currentItem[0], this.containers[i].element[0])) {
+ continue;
+ }
+
+ if(this._intersectsWith(this.containers[i].containerCache)) {
+
+ // if we've already found a container and it's more "inner" than this, then continue
+ if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
+ continue;
+ }
+
+ innermostContainer = this.containers[i];
+ innermostIndex = i;
+
+ } else {
+ // container doesn't intersect. trigger "out" event if necessary
+ if(this.containers[i].containerCache.over) {
+ this.containers[i]._trigger("out", event, this._uiHash(this));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ }
+
+ // if no intersecting containers found, return
+ if(!innermostContainer) {
+ return;
+ }
+
+ // move the item into the container if it's not there already
+ if(this.containers.length === 1) {
+ if (!this.containers[innermostIndex].containerCache.over) {
+ this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+ this.containers[innermostIndex].containerCache.over = 1;
+ }
+ } else {
+
+ //When entering a new container, we will find the item with the least distance and append our item near it
+ dist = 10000;
+ itemWithLeastDistance = null;
+ floating = innermostContainer.floating || isFloating(this.currentItem);
+ posProperty = floating ? "left" : "top";
+ sizeProperty = floating ? "width" : "height";
+ base = this.positionAbs[posProperty] + this.offset.click[posProperty];
+ for (j = this.items.length - 1; j >= 0; j--) {
+ if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
+ continue;
+ }
+ if(this.items[j].item[0] === this.currentItem[0]) {
+ continue;
+ }
+ if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) {
+ continue;
+ }
+ cur = this.items[j].item.offset()[posProperty];
+ nearBottom = false;
+ if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){
+ nearBottom = true;
+ cur += this.items[j][sizeProperty];
+ }
+
+ if(Math.abs(cur - base) < dist) {
+ dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
+ this.direction = nearBottom ? "up": "down";
+ }
+ }
+
+ //Check if dropOnEmpty is enabled
+ if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
+ return;
+ }
+
+ if(this.currentContainer === this.containers[innermostIndex]) {
+ return;
+ }
+
+ itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
+ this._trigger("change", event, this._uiHash());
+ this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
+ this.currentContainer = this.containers[innermostIndex];
+
+ //Update the placeholder
+ this.options.placeholder.update(this.currentContainer, this.placeholder);
+
+ this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+ this.containers[innermostIndex].containerCache.over = 1;
+ }
+
+
+ },
+
+ _createHelper: function(event) {
+
+ var o = this.options,
+ helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
+
+ //Add the helper to the DOM if that didn't happen already
+ if(!helper.parents("body").length) {
+ $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
+ }
+
+ if(helper[0] === this.currentItem[0]) {
+ this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };
+ }
+
+ if(!helper[0].style.width || o.forceHelperSize) {
+ helper.width(this.currentItem.width());
+ }
+ if(!helper[0].style.height || o.forceHelperSize) {
+ helper.height(this.currentItem.height());
+ }
+
+ return helper;
+
+ },
+
+ _adjustOffsetFromHelper: function(obj) {
+ if (typeof obj === "string") {
+ obj = obj.split(" ");
+ }
+ if ($.isArray(obj)) {
+ obj = {left: +obj[0], top: +obj[1] || 0};
+ }
+ if ("left" in obj) {
+ this.offset.click.left = obj.left + this.margins.left;
+ }
+ if ("right" in obj) {
+ this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+ }
+ if ("top" in obj) {
+ this.offset.click.top = obj.top + this.margins.top;
+ }
+ if ("bottom" in obj) {
+ this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+ }
+ },
+
+ _getParentOffset: function() {
+
+
+ //Get the offsetParent and cache its position
+ this.offsetParent = this.helper.offsetParent();
+ var po = this.offsetParent.offset();
+
+ // This is a special case where we need to modify a offset calculated on start, since the following happened:
+ // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+ // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+ if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+ po.left += this.scrollParent.scrollLeft();
+ po.top += this.scrollParent.scrollTop();
+ }
+
+ // This needs to be actually done for all browsers, since pageX/pageY includes this information
+ // with an ugly IE fix
+ if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
+ po = { top: 0, left: 0 };
+ }
+
+ return {
+ top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+ left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+ };
+
+ },
+
+ _getRelativeOffset: function() {
+
+ if(this.cssPosition === "relative") {
+ var p = this.currentItem.position();
+ return {
+ top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+ left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+ };
+ } else {
+ return { top: 0, left: 0 };
+ }
+
+ },
+
+ _cacheMargins: function() {
+ this.margins = {
+ left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
+ top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
+ };
+ },
+
+ _cacheHelperProportions: function() {
+ this.helperProportions = {
+ width: this.helper.outerWidth(),
+ height: this.helper.outerHeight()
+ };
+ },
+
+ _setContainment: function() {
+
+ var ce, co, over,
+ o = this.options;
+ if(o.containment === "parent") {
+ o.containment = this.helper[0].parentNode;
+ }
+ if(o.containment === "document" || o.containment === "window") {
+ this.containment = [
+ 0 - this.offset.relative.left - this.offset.parent.left,
+ 0 - this.offset.relative.top - this.offset.parent.top,
+ $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
+ ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
+ ];
+ }
+
+ if(!(/^(document|window|parent)$/).test(o.containment)) {
+ ce = $(o.containment)[0];
+ co = $(o.containment).offset();
+ over = ($(ce).css("overflow") !== "hidden");
+
+ this.containment = [
+ co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
+ co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
+ co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
+ co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
+ ];
+ }
+
+ },
+
+ _convertPositionTo: function(d, pos) {
+
+ if(!pos) {
+ pos = this.position;
+ }
+ var mod = d === "absolute" ? 1 : -1,
+ scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
+ scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+ return {
+ top: (
+ pos.top + // The absolute mouse position
+ this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
+ ),
+ left: (
+ pos.left + // The absolute mouse position
+ this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
+ )
+ };
+
+ },
+
+ _generatePosition: function(event) {
+
+ var top, left,
+ o = this.options,
+ pageX = event.pageX,
+ pageY = event.pageY,
+ scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+ // This is another very weird special case that only happens for relative elements:
+ // 1. If the css position is relative
+ // 2. and the scroll parent is the document or similar to the offset parent
+ // we have to refresh the relative offset during the scroll so there are no jumps
+ if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {
+ this.offset.relative = this._getRelativeOffset();
+ }
+
+ /*
+ * - Position constraining -
+ * Constrain the position to a mix of grid, containment.
+ */
+
+ if(this.originalPosition) { //If we are not dragging yet, we won't check for options
+
+ if(this.containment) {
+ if(event.pageX - this.offset.click.left < this.containment[0]) {
+ pageX = this.containment[0] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top < this.containment[1]) {
+ pageY = this.containment[1] + this.offset.click.top;
+ }
+ if(event.pageX - this.offset.click.left > this.containment[2]) {
+ pageX = this.containment[2] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top > this.containment[3]) {
+ pageY = this.containment[3] + this.offset.click.top;
+ }
+ }
+
+ if(o.grid) {
+ top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
+ pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+ left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
+ pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+ }
+
+ }
+
+ return {
+ top: (
+ pageY - // The absolute mouse position
+ this.offset.click.top - // Click offset (relative to the element)
+ this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
+ ),
+ left: (
+ pageX - // The absolute mouse position
+ this.offset.click.left - // Click offset (relative to the element)
+ this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
+ )
+ };
+
+ },
+
+ _rearrange: function(event, i, a, hardRefresh) {
+
+ a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling));
+
+ //Various things done here to improve the performance:
+ // 1. we create a setTimeout, that calls refreshPositions
+ // 2. on the instance, we have a counter variable, that get's higher after every append
+ // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
+ // 4. this lets only the last addition to the timeout stack through
+ this.counter = this.counter ? ++this.counter : 1;
+ var counter = this.counter;
+
+ this._delay(function() {
+ if(counter === this.counter) {
+ this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
+ }
+ });
+
+ },
+
+ _clear: function(event, noPropagation) {
+
+ this.reverting = false;
+ // We delay all events that have to be triggered to after the point where the placeholder has been removed and
+ // everything else normalized again
+ var i,
+ delayedTriggers = [];
+
+ // We first have to update the dom position of the actual currentItem
+ // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
+ if(!this._noFinalSort && this.currentItem.parent().length) {
+ this.placeholder.before(this.currentItem);
+ }
+ this._noFinalSort = null;
+
+ if(this.helper[0] === this.currentItem[0]) {
+ for(i in this._storedCSS) {
+ if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
+ this._storedCSS[i] = "";
+ }
+ }
+ this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+ } else {
+ this.currentItem.show();
+ }
+
+ if(this.fromOutside && !noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
+ }
+ if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
+ }
+
+ // Check if the items Container has Changed and trigger appropriate
+ // events.
+ if (this !== this.currentContainer) {
+ if(!noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
+ }
+ }
+
+
+ //Post events to containers
+ function delayEvent( type, instance, container ) {
+ return function( event ) {
+ container._trigger( type, event, instance._uiHash( instance ) );
+ };
+ }
+ for (i = this.containers.length - 1; i >= 0; i--){
+ if (!noPropagation) {
+ delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
+ }
+ if(this.containers[i].containerCache.over) {
+ delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ //Do what was originally in plugins
+ if ( this.storedCursor ) {
+ this.document.find( "body" ).css( "cursor", this.storedCursor );
+ this.storedStylesheet.remove();
+ }
+ if(this._storedOpacity) {
+ this.helper.css("opacity", this._storedOpacity);
+ }
+ if(this._storedZIndex) {
+ this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
+ }
+
+ this.dragging = false;
+ if(this.cancelHelperRemoval) {
+ if(!noPropagation) {
+ this._trigger("beforeStop", event, this._uiHash());
+ for (i=0; i < delayedTriggers.length; i++) {
+ delayedTriggers[i].call(this, event);
+ } //Trigger all delayed events
+ this._trigger("stop", event, this._uiHash());
+ }
+
+ this.fromOutside = false;
+ return false;
+ }
+
+ if(!noPropagation) {
+ this._trigger("beforeStop", event, this._uiHash());
+ }
+
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+ this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+
+ if(this.helper[0] !== this.currentItem[0]) {
+ this.helper.remove();
+ }
+ this.helper = null;
+
+ if(!noPropagation) {
+ for (i=0; i < delayedTriggers.length; i++) {
+ delayedTriggers[i].call(this, event);
+ } //Trigger all delayed events
+ this._trigger("stop", event, this._uiHash());
+ }
+
+ this.fromOutside = false;
+ return true;
+
+ },
+
+ _trigger: function() {
+ if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
+ this.cancel();
+ }
+ },
+
+ _uiHash: function(_inst) {
+ var inst = _inst || this;
+ return {
+ helper: inst.helper,
+ placeholder: inst.placeholder || $([]),
+ position: inst.position,
+ originalPosition: inst.originalPosition,
+ offset: inst.positionAbs,
+ item: inst.currentItem,
+ sender: _inst ? _inst.element : null
+ };
+ }
+
+});
+
+})(jQuery);
+
+(function($, undefined) {
+
+var dataSpace = "ui-effects-";
+
+$.effects = {
+ effect: {}
+};
+
+/*!
+ * jQuery Color Animations v2.1.2
+ * https://github.com/jquery/jquery-color
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * Date: Wed Jan 16 08:47:09 2013 -0600
+ */
+(function( jQuery, undefined ) {
+
+ var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
+
+ // plusequals test for += 100 -= 100
+ rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
+ // a set of RE's that can match strings and generate color tuples.
+ stringParsers = [{
+ re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ],
+ execResult[ 2 ],
+ execResult[ 3 ],
+ execResult[ 4 ]
+ ];
+ }
+ }, {
+ re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ] * 2.55,
+ execResult[ 2 ] * 2.55,
+ execResult[ 3 ] * 2.55,
+ execResult[ 4 ]
+ ];
+ }
+ }, {
+ // this regex ignores A-F because it's compared against an already lowercased string
+ re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
+ parse: function( execResult ) {
+ return [
+ parseInt( execResult[ 1 ], 16 ),
+ parseInt( execResult[ 2 ], 16 ),
+ parseInt( execResult[ 3 ], 16 )
+ ];
+ }
+ }, {
+ // this regex ignores A-F because it's compared against an already lowercased string
+ re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
+ parse: function( execResult ) {
+ return [
+ parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
+ parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
+ parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
+ ];
+ }
+ }, {
+ re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ space: "hsla",
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ],
+ execResult[ 2 ] / 100,
+ execResult[ 3 ] / 100,
+ execResult[ 4 ]
+ ];
+ }
+ }],
+
+ // jQuery.Color( )
+ color = jQuery.Color = function( color, green, blue, alpha ) {
+ return new jQuery.Color.fn.parse( color, green, blue, alpha );
+ },
+ spaces = {
+ rgba: {
+ props: {
+ red: {
+ idx: 0,
+ type: "byte"
+ },
+ green: {
+ idx: 1,
+ type: "byte"
+ },
+ blue: {
+ idx: 2,
+ type: "byte"
+ }
+ }
+ },
+
+ hsla: {
+ props: {
+ hue: {
+ idx: 0,
+ type: "degrees"
+ },
+ saturation: {
+ idx: 1,
+ type: "percent"
+ },
+ lightness: {
+ idx: 2,
+ type: "percent"
+ }
+ }
+ }
+ },
+ propTypes = {
+ "byte": {
+ floor: true,
+ max: 255
+ },
+ "percent": {
+ max: 1
+ },
+ "degrees": {
+ mod: 360,
+ floor: true
+ }
+ },
+ support = color.support = {},
+
+ // element for support tests
+ supportElem = jQuery( "<p>" )[ 0 ],
+
+ // colors = jQuery.Color.names
+ colors,
+
+ // local aliases of functions called often
+ each = jQuery.each;
+
+// determine rgba support immediately
+supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
+support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
+
+// define cache name and alpha properties
+// for rgba and hsla spaces
+each( spaces, function( spaceName, space ) {
+ space.cache = "_" + spaceName;
+ space.props.alpha = {
+ idx: 3,
+ type: "percent",
+ def: 1
+ };
+});
+
+function clamp( value, prop, allowEmpty ) {
+ var type = propTypes[ prop.type ] || {};
+
+ if ( value == null ) {
+ return (allowEmpty || !prop.def) ? null : prop.def;
+ }
+
+ // ~~ is an short way of doing floor for positive numbers
+ value = type.floor ? ~~value : parseFloat( value );
+
+ // IE will pass in empty strings as value for alpha,
+ // which will hit this case
+ if ( isNaN( value ) ) {
+ return prop.def;
+ }
+
+ if ( type.mod ) {
+ // we add mod before modding to make sure that negatives values
+ // get converted properly: -10 -> 350
+ return (value + type.mod) % type.mod;
+ }
+
+ // for now all property types without mod have min and max
+ return 0 > value ? 0 : type.max < value ? type.max : value;
+}
+
+function stringParse( string ) {
+ var inst = color(),
+ rgba = inst._rgba = [];
+
+ string = string.toLowerCase();
+
+ each( stringParsers, function( i, parser ) {
+ var parsed,
+ match = parser.re.exec( string ),
+ values = match && parser.parse( match ),
+ spaceName = parser.space || "rgba";
+
+ if ( values ) {
+ parsed = inst[ spaceName ]( values );
+
+ // if this was an rgba parse the assignment might happen twice
+ // oh well....
+ inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
+ rgba = inst._rgba = parsed._rgba;
+
+ // exit each( stringParsers ) here because we matched
+ return false;
+ }
+ });
+
+ // Found a stringParser that handled it
+ if ( rgba.length ) {
+
+ // if this came from a parsed string, force "transparent" when alpha is 0
+ // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
+ if ( rgba.join() === "0,0,0,0" ) {
+ jQuery.extend( rgba, colors.transparent );
+ }
+ return inst;
+ }
+
+ // named colors
+ return colors[ string ];
+}
+
+color.fn = jQuery.extend( color.prototype, {
+ parse: function( red, green, blue, alpha ) {
+ if ( red === undefined ) {
+ this._rgba = [ null, null, null, null ];
+ return this;
+ }
+ if ( red.jquery || red.nodeType ) {
+ red = jQuery( red ).css( green );
+ green = undefined;
+ }
+
+ var inst = this,
+ type = jQuery.type( red ),
+ rgba = this._rgba = [];
+
+ // more than 1 argument specified - assume ( red, green, blue, alpha )
+ if ( green !== undefined ) {
+ red = [ red, green, blue, alpha ];
+ type = "array";
+ }
+
+ if ( type === "string" ) {
+ return this.parse( stringParse( red ) || colors._default );
+ }
+
+ if ( type === "array" ) {
+ each( spaces.rgba.props, function( key, prop ) {
+ rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
+ });
+ return this;
+ }
+
+ if ( type === "object" ) {
+ if ( red instanceof color ) {
+ each( spaces, function( spaceName, space ) {
+ if ( red[ space.cache ] ) {
+ inst[ space.cache ] = red[ space.cache ].slice();
+ }
+ });
+ } else {
+ each( spaces, function( spaceName, space ) {
+ var cache = space.cache;
+ each( space.props, function( key, prop ) {
+
+ // if the cache doesn't exist, and we know how to convert
+ if ( !inst[ cache ] && space.to ) {
+
+ // if the value was null, we don't need to copy it
+ // if the key was alpha, we don't need to copy it either
+ if ( key === "alpha" || red[ key ] == null ) {
+ return;
+ }
+ inst[ cache ] = space.to( inst._rgba );
+ }
+
+ // this is the only case where we allow nulls for ALL properties.
+ // call clamp with alwaysAllowEmpty
+ inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
+ });
+
+ // everything defined but alpha?
+ if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
+ // use the default of 1
+ inst[ cache ][ 3 ] = 1;
+ if ( space.from ) {
+ inst._rgba = space.from( inst[ cache ] );
+ }
+ }
+ });
+ }
+ return this;
+ }
+ },
+ is: function( compare ) {
+ var is = color( compare ),
+ same = true,
+ inst = this;
+
+ each( spaces, function( _, space ) {
+ var localCache,
+ isCache = is[ space.cache ];
+ if (isCache) {
+ localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
+ each( space.props, function( _, prop ) {
+ if ( isCache[ prop.idx ] != null ) {
+ same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
+ return same;
+ }
+ });
+ }
+ return same;
+ });
+ return same;
+ },
+ _space: function() {
+ var used = [],
+ inst = this;
+ each( spaces, function( spaceName, space ) {
+ if ( inst[ space.cache ] ) {
+ used.push( spaceName );
+ }
+ });
+ return used.pop();
+ },
+ transition: function( other, distance ) {
+ var end = color( other ),
+ spaceName = end._space(),
+ space = spaces[ spaceName ],
+ startColor = this.alpha() === 0 ? color( "transparent" ) : this,
+ start = startColor[ space.cache ] || space.to( startColor._rgba ),
+ result = start.slice();
+
+ end = end[ space.cache ];
+ each( space.props, function( key, prop ) {
+ var index = prop.idx,
+ startValue = start[ index ],
+ endValue = end[ index ],
+ type = propTypes[ prop.type ] || {};
+
+ // if null, don't override start value
+ if ( endValue === null ) {
+ return;
+ }
+ // if null - use end
+ if ( startValue === null ) {
+ result[ index ] = endValue;
+ } else {
+ if ( type.mod ) {
+ if ( endValue - startValue > type.mod / 2 ) {
+ startValue += type.mod;
+ } else if ( startValue - endValue > type.mod / 2 ) {
+ startValue -= type.mod;
+ }
+ }
+ result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
+ }
+ });
+ return this[ spaceName ]( result );
+ },
+ blend: function( opaque ) {
+ // if we are already opaque - return ourself
+ if ( this._rgba[ 3 ] === 1 ) {
+ return this;
+ }
+
+ var rgb = this._rgba.slice(),
+ a = rgb.pop(),
+ blend = color( opaque )._rgba;
+
+ return color( jQuery.map( rgb, function( v, i ) {
+ return ( 1 - a ) * blend[ i ] + a * v;
+ }));
+ },
+ toRgbaString: function() {
+ var prefix = "rgba(",
+ rgba = jQuery.map( this._rgba, function( v, i ) {
+ return v == null ? ( i > 2 ? 1 : 0 ) : v;
+ });
+
+ if ( rgba[ 3 ] === 1 ) {
+ rgba.pop();
+ prefix = "rgb(";
+ }
+
+ return prefix + rgba.join() + ")";
+ },
+ toHslaString: function() {
+ var prefix = "hsla(",
+ hsla = jQuery.map( this.hsla(), function( v, i ) {
+ if ( v == null ) {
+ v = i > 2 ? 1 : 0;
+ }
+
+ // catch 1 and 2
+ if ( i && i < 3 ) {
+ v = Math.round( v * 100 ) + "%";
+ }
+ return v;
+ });
+
+ if ( hsla[ 3 ] === 1 ) {
+ hsla.pop();
+ prefix = "hsl(";
+ }
+ return prefix + hsla.join() + ")";
+ },
+ toHexString: function( includeAlpha ) {
+ var rgba = this._rgba.slice(),
+ alpha = rgba.pop();
+
+ if ( includeAlpha ) {
+ rgba.push( ~~( alpha * 255 ) );
+ }
+
+ return "#" + jQuery.map( rgba, function( v ) {
+
+ // default to 0 when nulls exist
+ v = ( v || 0 ).toString( 16 );
+ return v.length === 1 ? "0" + v : v;
+ }).join("");
+ },
+ toString: function() {
+ return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
+ }
+});
+color.fn.parse.prototype = color.fn;
+
+// hsla conversions adapted from:
+// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
+
+function hue2rgb( p, q, h ) {
+ h = ( h + 1 ) % 1;
+ if ( h * 6 < 1 ) {
+ return p + (q - p) * h * 6;
+ }
+ if ( h * 2 < 1) {
+ return q;
+ }
+ if ( h * 3 < 2 ) {
+ return p + (q - p) * ((2/3) - h) * 6;
+ }
+ return p;
+}
+
+spaces.hsla.to = function ( rgba ) {
+ if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
+ return [ null, null, null, rgba[ 3 ] ];
+ }
+ var r = rgba[ 0 ] / 255,
+ g = rgba[ 1 ] / 255,
+ b = rgba[ 2 ] / 255,
+ a = rgba[ 3 ],
+ max = Math.max( r, g, b ),
+ min = Math.min( r, g, b ),
+ diff = max - min,
+ add = max + min,
+ l = add * 0.5,
+ h, s;
+
+ if ( min === max ) {
+ h = 0;
+ } else if ( r === max ) {
+ h = ( 60 * ( g - b ) / diff ) + 360;
+ } else if ( g === max ) {
+ h = ( 60 * ( b - r ) / diff ) + 120;
+ } else {
+ h = ( 60 * ( r - g ) / diff ) + 240;
+ }
+
+ // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
+ // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
+ if ( diff === 0 ) {
+ s = 0;
+ } else if ( l <= 0.5 ) {
+ s = diff / add;
+ } else {
+ s = diff / ( 2 - add );
+ }
+ return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
+};
+
+spaces.hsla.from = function ( hsla ) {
+ if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
+ return [ null, null, null, hsla[ 3 ] ];
+ }
+ var h = hsla[ 0 ] / 360,
+ s = hsla[ 1 ],
+ l = hsla[ 2 ],
+ a = hsla[ 3 ],
+ q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
+ p = 2 * l - q;
+
+ return [
+ Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
+ Math.round( hue2rgb( p, q, h ) * 255 ),
+ Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
+ a
+ ];
+};
+
+
+each( spaces, function( spaceName, space ) {
+ var props = space.props,
+ cache = space.cache,
+ to = space.to,
+ from = space.from;
+
+ // makes rgba() and hsla()
+ color.fn[ spaceName ] = function( value ) {
+
+ // generate a cache for this space if it doesn't exist
+ if ( to && !this[ cache ] ) {
+ this[ cache ] = to( this._rgba );
+ }
+ if ( value === undefined ) {
+ return this[ cache ].slice();
+ }
+
+ var ret,
+ type = jQuery.type( value ),
+ arr = ( type === "array" || type === "object" ) ? value : arguments,
+ local = this[ cache ].slice();
+
+ each( props, function( key, prop ) {
+ var val = arr[ type === "object" ? key : prop.idx ];
+ if ( val == null ) {
+ val = local[ prop.idx ];
+ }
+ local[ prop.idx ] = clamp( val, prop );
+ });
+
+ if ( from ) {
+ ret = color( from( local ) );
+ ret[ cache ] = local;
+ return ret;
+ } else {
+ return color( local );
+ }
+ };
+
+ // makes red() green() blue() alpha() hue() saturation() lightness()
+ each( props, function( key, prop ) {
+ // alpha is included in more than one space
+ if ( color.fn[ key ] ) {
+ return;
+ }
+ color.fn[ key ] = function( value ) {
+ var vtype = jQuery.type( value ),
+ fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
+ local = this[ fn ](),
+ cur = local[ prop.idx ],
+ match;
+
+ if ( vtype === "undefined" ) {
+ return cur;
+ }
+
+ if ( vtype === "function" ) {
+ value = value.call( this, cur );
+ vtype = jQuery.type( value );
+ }
+ if ( value == null && prop.empty ) {
+ return this;
+ }
+ if ( vtype === "string" ) {
+ match = rplusequals.exec( value );
+ if ( match ) {
+ value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
+ }
+ }
+ local[ prop.idx ] = value;
+ return this[ fn ]( local );
+ };
+ });
+});
+
+// add cssHook and .fx.step function for each named hook.
+// accept a space separated string of properties
+color.hook = function( hook ) {
+ var hooks = hook.split( " " );
+ each( hooks, function( i, hook ) {
+ jQuery.cssHooks[ hook ] = {
+ set: function( elem, value ) {
+ var parsed, curElem,
+ backgroundColor = "";
+
+ if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
+ value = color( parsed || value );
+ if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
+ curElem = hook === "backgroundColor" ? elem.parentNode : elem;
+ while (
+ (backgroundColor === "" || backgroundColor === "transparent") &&
+ curElem && curElem.style
+ ) {
+ try {
+ backgroundColor = jQuery.css( curElem, "backgroundColor" );
+ curElem = curElem.parentNode;
+ } catch ( e ) {
+ }
+ }
+
+ value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
+ backgroundColor :
+ "_default" );
+ }
+
+ value = value.toRgbaString();
+ }
+ try {
+ elem.style[ hook ] = value;
+ } catch( e ) {
+ // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
+ }
+ }
+ };
+ jQuery.fx.step[ hook ] = function( fx ) {
+ if ( !fx.colorInit ) {
+ fx.start = color( fx.elem, hook );
+ fx.end = color( fx.end );
+ fx.colorInit = true;
+ }
+ jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
+ };
+ });
+
+};
+
+color.hook( stepHooks );
+
+jQuery.cssHooks.borderColor = {
+ expand: function( value ) {
+ var expanded = {};
+
+ each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
+ expanded[ "border" + part + "Color" ] = value;
+ });
+ return expanded;
+ }
+};
+
+// Basic color names only.
+// Usage of any of the other color names requires adding yourself or including
+// jquery.color.svg-names.js.
+colors = jQuery.Color.names = {
+ // 4.1. Basic color keywords
+ aqua: "#00ffff",
+ black: "#000000",
+ blue: "#0000ff",
+ fuchsia: "#ff00ff",
+ gray: "#808080",
+ green: "#008000",
+ lime: "#00ff00",
+ maroon: "#800000",
+ navy: "#000080",
+ olive: "#808000",
+ purple: "#800080",
+ red: "#ff0000",
+ silver: "#c0c0c0",
+ teal: "#008080",
+ white: "#ffffff",
+ yellow: "#ffff00",
+
+ // 4.2.3. "transparent" color keyword
+ transparent: [ null, null, null, 0 ],
+
+ _default: "#ffffff"
+};
+
+})( jQuery );
+
+
+/******************************************************************************/
+/****************************** CLASS ANIMATIONS ******************************/
+/******************************************************************************/
+(function() {
+
+var classAnimationActions = [ "add", "remove", "toggle" ],
+ shorthandStyles = {
+ border: 1,
+ borderBottom: 1,
+ borderColor: 1,
+ borderLeft: 1,
+ borderRight: 1,
+ borderTop: 1,
+ borderWidth: 1,
+ margin: 1,
+ padding: 1
+ };
+
+$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
+ $.fx.step[ prop ] = function( fx ) {
+ if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
+ jQuery.style( fx.elem, prop, fx.end );
+ fx.setAttr = true;
+ }
+ };
+});
+
+function getElementStyles( elem ) {
+ var key, len,
+ style = elem.ownerDocument.defaultView ?
+ elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
+ elem.currentStyle,
+ styles = {};
+
+ if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
+ len = style.length;
+ while ( len-- ) {
+ key = style[ len ];
+ if ( typeof style[ key ] === "string" ) {
+ styles[ $.camelCase( key ) ] = style[ key ];
+ }
+ }
+ // support: Opera, IE <9
+ } else {
+ for ( key in style ) {
+ if ( typeof style[ key ] === "string" ) {
+ styles[ key ] = style[ key ];
+ }
+ }
+ }
+
+ return styles;
+}
+
+
+function styleDifference( oldStyle, newStyle ) {
+ var diff = {},
+ name, value;
+
+ for ( name in newStyle ) {
+ value = newStyle[ name ];
+ if ( oldStyle[ name ] !== value ) {
+ if ( !shorthandStyles[ name ] ) {
+ if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
+ diff[ name ] = value;
+ }
+ }
+ }
+ }
+
+ return diff;
+}
+
+// support: jQuery <1.8
+if ( !$.fn.addBack ) {
+ $.fn.addBack = function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter( selector )
+ );
+ };
+}
+
+$.effects.animateClass = function( value, duration, easing, callback ) {
+ var o = $.speed( duration, easing, callback );
+
+ return this.queue( function() {
+ var animated = $( this ),
+ baseClass = animated.attr( "class" ) || "",
+ applyClassChange,
+ allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
+
+ // map the animated objects to store the original styles.
+ allAnimations = allAnimations.map(function() {
+ var el = $( this );
+ return {
+ el: el,
+ start: getElementStyles( this )
+ };
+ });
+
+ // apply class change
+ applyClassChange = function() {
+ $.each( classAnimationActions, function(i, action) {
+ if ( value[ action ] ) {
+ animated[ action + "Class" ]( value[ action ] );
+ }
+ });
+ };
+ applyClassChange();
+
+ // map all animated objects again - calculate new styles and diff
+ allAnimations = allAnimations.map(function() {
+ this.end = getElementStyles( this.el[ 0 ] );
+ this.diff = styleDifference( this.start, this.end );
+ return this;
+ });
+
+ // apply original class
+ animated.attr( "class", baseClass );
+
+ // map all animated objects again - this time collecting a promise
+ allAnimations = allAnimations.map(function() {
+ var styleInfo = this,
+ dfd = $.Deferred(),
+ opts = $.extend({}, o, {
+ queue: false,
+ complete: function() {
+ dfd.resolve( styleInfo );
+ }
+ });
+
+ this.el.animate( this.diff, opts );
+ return dfd.promise();
+ });
+
+ // once all animations have completed:
+ $.when.apply( $, allAnimations.get() ).done(function() {
+
+ // set the final class
+ applyClassChange();
+
+ // for each animated element,
+ // clear all css properties that were animated
+ $.each( arguments, function() {
+ var el = this.el;
+ $.each( this.diff, function(key) {
+ el.css( key, "" );
+ });
+ });
+
+ // this is guarnteed to be there if you use jQuery.speed()
+ // it also handles dequeuing the next anim...
+ o.complete.call( animated[ 0 ] );
+ });
+ });
+};
+
+$.fn.extend({
+ addClass: (function( orig ) {
+ return function( classNames, speed, easing, callback ) {
+ return speed ?
+ $.effects.animateClass.call( this,
+ { add: classNames }, speed, easing, callback ) :
+ orig.apply( this, arguments );
+ };
+ })( $.fn.addClass ),
+
+ removeClass: (function( orig ) {
+ return function( classNames, speed, easing, callback ) {
+ return arguments.length > 1 ?
+ $.effects.animateClass.call( this,
+ { remove: classNames }, speed, easing, callback ) :
+ orig.apply( this, arguments );
+ };
+ })( $.fn.removeClass ),
+
+ toggleClass: (function( orig ) {
+ return function( classNames, force, speed, easing, callback ) {
+ if ( typeof force === "boolean" || force === undefined ) {
+ if ( !speed ) {
+ // without speed parameter
+ return orig.apply( this, arguments );
+ } else {
+ return $.effects.animateClass.call( this,
+ (force ? { add: classNames } : { remove: classNames }),
+ speed, easing, callback );
+ }
+ } else {
+ // without force parameter
+ return $.effects.animateClass.call( this,
+ { toggle: classNames }, force, speed, easing );
+ }
+ };
+ })( $.fn.toggleClass ),
+
+ switchClass: function( remove, add, speed, easing, callback) {
+ return $.effects.animateClass.call( this, {
+ add: add,
+ remove: remove
+ }, speed, easing, callback );
+ }
+});
+
+})();
+
+/******************************************************************************/
+/*********************************** EFFECTS **********************************/
+/******************************************************************************/
+
+(function() {
+
+$.extend( $.effects, {
+ version: "1.10.4",
+
+ // Saves a set of properties in a data storage
+ save: function( element, set ) {
+ for( var i=0; i < set.length; i++ ) {
+ if ( set[ i ] !== null ) {
+ element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
+ }
+ }
+ },
+
+ // Restores a set of previously saved properties from a data storage
+ restore: function( element, set ) {
+ var val, i;
+ for( i=0; i < set.length; i++ ) {
+ if ( set[ i ] !== null ) {
+ val = element.data( dataSpace + set[ i ] );
+ // support: jQuery 1.6.2
+ // http://bugs.jquery.com/ticket/9917
+ // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
+ // We can't differentiate between "" and 0 here, so we just assume
+ // empty string since it's likely to be a more common value...
+ if ( val === undefined ) {
+ val = "";
+ }
+ element.css( set[ i ], val );
+ }
+ }
+ },
+
+ setMode: function( el, mode ) {
+ if (mode === "toggle") {
+ mode = el.is( ":hidden" ) ? "show" : "hide";
+ }
+ return mode;
+ },
+
+ // Translates a [top,left] array into a baseline value
+ // this should be a little more flexible in the future to handle a string & hash
+ getBaseline: function( origin, original ) {
+ var y, x;
+ switch ( origin[ 0 ] ) {
+ case "top": y = 0; break;
+ case "middle": y = 0.5; break;
+ case "bottom": y = 1; break;
+ default: y = origin[ 0 ] / original.height;
+ }
+ switch ( origin[ 1 ] ) {
+ case "left": x = 0; break;
+ case "center": x = 0.5; break;
+ case "right": x = 1; break;
+ default: x = origin[ 1 ] / original.width;
+ }
+ return {
+ x: x,
+ y: y
+ };
+ },
+
+ // Wraps the element around a wrapper that copies position properties
+ createWrapper: function( element ) {
+
+ // if the element is already wrapped, return it
+ if ( element.parent().is( ".ui-effects-wrapper" )) {
+ return element.parent();
+ }
+
+ // wrap the element
+ var props = {
+ width: element.outerWidth(true),
+ height: element.outerHeight(true),
+ "float": element.css( "float" )
+ },
+ wrapper = $( "<div></div>" )
+ .addClass( "ui-effects-wrapper" )
+ .css({
+ fontSize: "100%",
+ background: "transparent",
+ border: "none",
+ margin: 0,
+ padding: 0
+ }),
+ // Store the size in case width/height are defined in % - Fixes #5245
+ size = {
+ width: element.width(),
+ height: element.height()
+ },
+ active = document.activeElement;
+
+ // support: Firefox
+ // Firefox incorrectly exposes anonymous content
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
+ try {
+ active.id;
+ } catch( e ) {
+ active = document.body;
+ }
+
+ element.wrap( wrapper );
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+
+ wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
+
+ // transfer positioning properties to the wrapper
+ if ( element.css( "position" ) === "static" ) {
+ wrapper.css({ position: "relative" });
+ element.css({ position: "relative" });
+ } else {
+ $.extend( props, {
+ position: element.css( "position" ),
+ zIndex: element.css( "z-index" )
+ });
+ $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
+ props[ pos ] = element.css( pos );
+ if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
+ props[ pos ] = "auto";
+ }
+ });
+ element.css({
+ position: "relative",
+ top: 0,
+ left: 0,
+ right: "auto",
+ bottom: "auto"
+ });
+ }
+ element.css(size);
+
+ return wrapper.css( props ).show();
+ },
+
+ removeWrapper: function( element ) {
+ var active = document.activeElement;
+
+ if ( element.parent().is( ".ui-effects-wrapper" ) ) {
+ element.parent().replaceWith( element );
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+ }
+
+
+ return element;
+ },
+
+ setTransition: function( element, list, factor, value ) {
+ value = value || {};
+ $.each( list, function( i, x ) {
+ var unit = element.cssUnit( x );
+ if ( unit[ 0 ] > 0 ) {
+ value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
+ }
+ });
+ return value;
+ }
+});
+
+// return an effect options object for the given parameters:
+function _normalizeArguments( effect, options, speed, callback ) {
+
+ // allow passing all options as the first parameter
+ if ( $.isPlainObject( effect ) ) {
+ options = effect;
+ effect = effect.effect;
+ }
+
+ // convert to an object
+ effect = { effect: effect };
+
+ // catch (effect, null, ...)
+ if ( options == null ) {
+ options = {};
+ }
+
+ // catch (effect, callback)
+ if ( $.isFunction( options ) ) {
+ callback = options;
+ speed = null;
+ options = {};
+ }
+
+ // catch (effect, speed, ?)
+ if ( typeof options === "number" || $.fx.speeds[ options ] ) {
+ callback = speed;
+ speed = options;
+ options = {};
+ }
+
+ // catch (effect, options, callback)
+ if ( $.isFunction( speed ) ) {
+ callback = speed;
+ speed = null;
+ }
+
+ // add options to effect
+ if ( options ) {
+ $.extend( effect, options );
+ }
+
+ speed = speed || options.duration;
+ effect.duration = $.fx.off ? 0 :
+ typeof speed === "number" ? speed :
+ speed in $.fx.speeds ? $.fx.speeds[ speed ] :
+ $.fx.speeds._default;
+
+ effect.complete = callback || options.complete;
+
+ return effect;
+}
+
+function standardAnimationOption( option ) {
+ // Valid standard speeds (nothing, number, named speed)
+ if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
+ return true;
+ }
+
+ // Invalid strings - treat as "normal" speed
+ if ( typeof option === "string" && !$.effects.effect[ option ] ) {
+ return true;
+ }
+
+ // Complete callback
+ if ( $.isFunction( option ) ) {
+ return true;
+ }
+
+ // Options hash (but not naming an effect)
+ if ( typeof option === "object" && !option.effect ) {
+ return true;
+ }
+
+ // Didn't match any standard API
+ return false;
+}
+
+$.fn.extend({
+ effect: function( /* effect, options, speed, callback */ ) {
+ var args = _normalizeArguments.apply( this, arguments ),
+ mode = args.mode,
+ queue = args.queue,
+ effectMethod = $.effects.effect[ args.effect ];
+
+ if ( $.fx.off || !effectMethod ) {
+ // delegate to the original method (e.g., .show()) if possible
+ if ( mode ) {
+ return this[ mode ]( args.duration, args.complete );
+ } else {
+ return this.each( function() {
+ if ( args.complete ) {
+ args.complete.call( this );
+ }
+ });
+ }
+ }
+
+ function run( next ) {
+ var elem = $( this ),
+ complete = args.complete,
+ mode = args.mode;
+
+ function done() {
+ if ( $.isFunction( complete ) ) {
+ complete.call( elem[0] );
+ }
+ if ( $.isFunction( next ) ) {
+ next();
+ }
+ }
+
+ // If the element already has the correct final state, delegate to
+ // the core methods so the internal tracking of "olddisplay" works.
+ if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
+ elem[ mode ]();
+ done();
+ } else {
+ effectMethod.call( elem[0], args, done );
+ }
+ }
+
+ return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
+ },
+
+ show: (function( orig ) {
+ return function( option ) {
+ if ( standardAnimationOption( option ) ) {
+ return orig.apply( this, arguments );
+ } else {
+ var args = _normalizeArguments.apply( this, arguments );
+ args.mode = "show";
+ return this.effect.call( this, args );
+ }
+ };
+ })( $.fn.show ),
+
+ hide: (function( orig ) {
+ return function( option ) {
+ if ( standardAnimationOption( option ) ) {
+ return orig.apply( this, arguments );
+ } else {
+ var args = _normalizeArguments.apply( this, arguments );
+ args.mode = "hide";
+ return this.effect.call( this, args );
+ }
+ };
+ })( $.fn.hide ),
+
+ toggle: (function( orig ) {
+ return function( option ) {
+ if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
+ return orig.apply( this, arguments );
+ } else {
+ var args = _normalizeArguments.apply( this, arguments );
+ args.mode = "toggle";
+ return this.effect.call( this, args );
+ }
+ };
+ })( $.fn.toggle ),
+
+ // helper functions
+ cssUnit: function(key) {
+ var style = this.css( key ),
+ val = [];
+
+ $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
+ if ( style.indexOf( unit ) > 0 ) {
+ val = [ parseFloat( style ), unit ];
+ }
+ });
+ return val;
+ }
+});
+
+})();
+
+/******************************************************************************/
+/*********************************** EASING ***********************************/
+/******************************************************************************/
+
+(function() {
+
+// based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
+
+var baseEasings = {};
+
+$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
+ baseEasings[ name ] = function( p ) {
+ return Math.pow( p, i + 2 );
+ };
+});
+
+$.extend( baseEasings, {
+ Sine: function ( p ) {
+ return 1 - Math.cos( p * Math.PI / 2 );
+ },
+ Circ: function ( p ) {
+ return 1 - Math.sqrt( 1 - p * p );
+ },
+ Elastic: function( p ) {
+ return p === 0 || p === 1 ? p :
+ -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
+ },
+ Back: function( p ) {
+ return p * p * ( 3 * p - 2 );
+ },
+ Bounce: function ( p ) {
+ var pow2,
+ bounce = 4;
+
+ while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
+ return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
+ }
+});
+
+$.each( baseEasings, function( name, easeIn ) {
+ $.easing[ "easeIn" + name ] = easeIn;
+ $.easing[ "easeOut" + name ] = function( p ) {
+ return 1 - easeIn( 1 - p );
+ };
+ $.easing[ "easeInOut" + name ] = function( p ) {
+ return p < 0.5 ?
+ easeIn( p * 2 ) / 2 :
+ 1 - easeIn( p * -2 + 2 ) / 2;
+ };
+});
+
+})();
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+var uid = 0,
+ hideProps = {},
+ showProps = {};
+
+hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
+ hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
+showProps.height = showProps.paddingTop = showProps.paddingBottom =
+ showProps.borderTopWidth = showProps.borderBottomWidth = "show";
+
+$.widget( "ui.accordion", {
+ version: "1.10.4",
+ options: {
+ active: 0,
+ animate: {},
+ collapsible: false,
+ event: "click",
+ header: "> li > :first-child,> :not(li):even",
+ heightStyle: "auto",
+ icons: {
+ activeHeader: "ui-icon-triangle-1-s",
+ header: "ui-icon-triangle-1-e"
+ },
+
+ // callbacks
+ activate: null,
+ beforeActivate: null
+ },
+
+ _create: function() {
+ var options = this.options;
+ this.prevShow = this.prevHide = $();
+ this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
+ // ARIA
+ .attr( "role", "tablist" );
+
+ // don't allow collapsible: false and active: false / null
+ if ( !options.collapsible && (options.active === false || options.active == null) ) {
+ options.active = 0;
+ }
+
+ this._processPanels();
+ // handle negative values
+ if ( options.active < 0 ) {
+ options.active += this.headers.length;
+ }
+ this._refresh();
+ },
+
+ _getCreateEventData: function() {
+ return {
+ header: this.active,
+ panel: !this.active.length ? $() : this.active.next(),
+ content: !this.active.length ? $() : this.active.next()
+ };
+ },
+
+ _createIcons: function() {
+ var icons = this.options.icons;
+ if ( icons ) {
+ $( "<span>" )
+ .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
+ .prependTo( this.headers );
+ this.active.children( ".ui-accordion-header-icon" )
+ .removeClass( icons.header )
+ .addClass( icons.activeHeader );
+ this.headers.addClass( "ui-accordion-icons" );
+ }
+ },
+
+ _destroyIcons: function() {
+ this.headers
+ .removeClass( "ui-accordion-icons" )
+ .children( ".ui-accordion-header-icon" )
+ .remove();
+ },
+
+ _destroy: function() {
+ var contents;
+
+ // clean up main element
+ this.element
+ .removeClass( "ui-accordion ui-widget ui-helper-reset" )
+ .removeAttr( "role" );
+
+ // clean up headers
+ this.headers
+ .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-expanded" )
+ .removeAttr( "aria-selected" )
+ .removeAttr( "aria-controls" )
+ .removeAttr( "tabIndex" )
+ .each(function() {
+ if ( /^ui-accordion/.test( this.id ) ) {
+ this.removeAttribute( "id" );
+ }
+ });
+ this._destroyIcons();
+
+ // clean up content panels
+ contents = this.headers.next()
+ .css( "display", "" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-hidden" )
+ .removeAttr( "aria-labelledby" )
+ .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
+ .each(function() {
+ if ( /^ui-accordion/.test( this.id ) ) {
+ this.removeAttribute( "id" );
+ }
+ });
+ if ( this.options.heightStyle !== "content" ) {
+ contents.css( "height", "" );
+ }
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "active" ) {
+ // _activate() will handle invalid values and update this.options
+ this._activate( value );
+ return;
+ }
+
+ if ( key === "event" ) {
+ if ( this.options.event ) {
+ this._off( this.headers, this.options.event );
+ }
+ this._setupEvents( value );
+ }
+
+ this._super( key, value );
+
+ // setting collapsible: false while collapsed; open first panel
+ if ( key === "collapsible" && !value && this.options.active === false ) {
+ this._activate( 0 );
+ }
+
+ if ( key === "icons" ) {
+ this._destroyIcons();
+ if ( value ) {
+ this._createIcons();
+ }
+ }
+
+ // #5332 - opacity doesn't cascade to positioned elements in IE
+ // so we need to add the disabled class to the headers and panels
+ if ( key === "disabled" ) {
+ this.headers.add( this.headers.next() )
+ .toggleClass( "ui-state-disabled", !!value );
+ }
+ },
+
+ _keydown: function( event ) {
+ if ( event.altKey || event.ctrlKey ) {
+ return;
+ }
+
+ var keyCode = $.ui.keyCode,
+ length = this.headers.length,
+ currentIndex = this.headers.index( event.target ),
+ toFocus = false;
+
+ switch ( event.keyCode ) {
+ case keyCode.RIGHT:
+ case keyCode.DOWN:
+ toFocus = this.headers[ ( currentIndex + 1 ) % length ];
+ break;
+ case keyCode.LEFT:
+ case keyCode.UP:
+ toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
+ break;
+ case keyCode.SPACE:
+ case keyCode.ENTER:
+ this._eventHandler( event );
+ break;
+ case keyCode.HOME:
+ toFocus = this.headers[ 0 ];
+ break;
+ case keyCode.END:
+ toFocus = this.headers[ length - 1 ];
+ break;
+ }
+
+ if ( toFocus ) {
+ $( event.target ).attr( "tabIndex", -1 );
+ $( toFocus ).attr( "tabIndex", 0 );
+ toFocus.focus();
+ event.preventDefault();
+ }
+ },
+
+ _panelKeyDown : function( event ) {
+ if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
+ $( event.currentTarget ).prev().focus();
+ }
+ },
+
+ refresh: function() {
+ var options = this.options;
+ this._processPanels();
+
+ // was collapsed or no panel
+ if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
+ options.active = false;
+ this.active = $();
+ // active false only when collapsible is true
+ } else if ( options.active === false ) {
+ this._activate( 0 );
+ // was active, but active panel is gone
+ } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
+ // all remaining panel are disabled
+ if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
+ options.active = false;
+ this.active = $();
+ // activate previous panel
+ } else {
+ this._activate( Math.max( 0, options.active - 1 ) );
+ }
+ // was active, active panel still exists
+ } else {
+ // make sure active index is correct
+ options.active = this.headers.index( this.active );
+ }
+
+ this._destroyIcons();
+
+ this._refresh();
+ },
+
+ _processPanels: function() {
+ this.headers = this.element.find( this.options.header )
+ .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
+
+ this.headers.next()
+ .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
+ .filter(":not(.ui-accordion-content-active)")
+ .hide();
+ },
+
+ _refresh: function() {
+ var maxHeight,
+ options = this.options,
+ heightStyle = options.heightStyle,
+ parent = this.element.parent(),
+ accordionId = this.accordionId = "ui-accordion-" +
+ (this.element.attr( "id" ) || ++uid);
+
+ this.active = this._findActive( options.active )
+ .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
+ .removeClass( "ui-corner-all" );
+ this.active.next()
+ .addClass( "ui-accordion-content-active" )
+ .show();
+
+ this.headers
+ .attr( "role", "tab" )
+ .each(function( i ) {
+ var header = $( this ),
+ headerId = header.attr( "id" ),
+ panel = header.next(),
+ panelId = panel.attr( "id" );
+ if ( !headerId ) {
+ headerId = accordionId + "-header-" + i;
+ header.attr( "id", headerId );
+ }
+ if ( !panelId ) {
+ panelId = accordionId + "-panel-" + i;
+ panel.attr( "id", panelId );
+ }
+ header.attr( "aria-controls", panelId );
+ panel.attr( "aria-labelledby", headerId );
+ })
+ .next()
+ .attr( "role", "tabpanel" );
+
+ this.headers
+ .not( this.active )
+ .attr({
+ "aria-selected": "false",
+ "aria-expanded": "false",
+ tabIndex: -1
+ })
+ .next()
+ .attr({
+ "aria-hidden": "true"
+ })
+ .hide();
+
+ // make sure at least one header is in the tab order
+ if ( !this.active.length ) {
+ this.headers.eq( 0 ).attr( "tabIndex", 0 );
+ } else {
+ this.active.attr({
+ "aria-selected": "true",
+ "aria-expanded": "true",
+ tabIndex: 0
+ })
+ .next()
+ .attr({
+ "aria-hidden": "false"
+ });
+ }
+
+ this._createIcons();
+
+ this._setupEvents( options.event );
+
+ if ( heightStyle === "fill" ) {
+ maxHeight = parent.height();
+ this.element.siblings( ":visible" ).each(function() {
+ var elem = $( this ),
+ position = elem.css( "position" );
+
+ if ( position === "absolute" || position === "fixed" ) {
+ return;
+ }
+ maxHeight -= elem.outerHeight( true );
+ });
+
+ this.headers.each(function() {
+ maxHeight -= $( this ).outerHeight( true );
+ });
+
+ this.headers.next()
+ .each(function() {
+ $( this ).height( Math.max( 0, maxHeight -
+ $( this ).innerHeight() + $( this ).height() ) );
+ })
+ .css( "overflow", "auto" );
+ } else if ( heightStyle === "auto" ) {
+ maxHeight = 0;
+ this.headers.next()
+ .each(function() {
+ maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
+ })
+ .height( maxHeight );
+ }
+ },
+
+ _activate: function( index ) {
+ var active = this._findActive( index )[ 0 ];
+
+ // trying to activate the already active panel
+ if ( active === this.active[ 0 ] ) {
+ return;
+ }
+
+ // trying to collapse, simulate a click on the currently active header
+ active = active || this.active[ 0 ];
+
+ this._eventHandler({
+ target: active,
+ currentTarget: active,
+ preventDefault: $.noop
+ });
+ },
+
+ _findActive: function( selector ) {
+ return typeof selector === "number" ? this.headers.eq( selector ) : $();
+ },
+
+ _setupEvents: function( event ) {
+ var events = {
+ keydown: "_keydown"
+ };
+ if ( event ) {
+ $.each( event.split(" "), function( index, eventName ) {
+ events[ eventName ] = "_eventHandler";
+ });
+ }
+
+ this._off( this.headers.add( this.headers.next() ) );
+ this._on( this.headers, events );
+ this._on( this.headers.next(), { keydown: "_panelKeyDown" });
+ this._hoverable( this.headers );
+ this._focusable( this.headers );
+ },
+
+ _eventHandler: function( event ) {
+ var options = this.options,
+ active = this.active,
+ clicked = $( event.currentTarget ),
+ clickedIsActive = clicked[ 0 ] === active[ 0 ],
+ collapsing = clickedIsActive && options.collapsible,
+ toShow = collapsing ? $() : clicked.next(),
+ toHide = active.next(),
+ eventData = {
+ oldHeader: active,
+ oldPanel: toHide,
+ newHeader: collapsing ? $() : clicked,
+ newPanel: toShow
+ };
+
+ event.preventDefault();
+
+ if (
+ // click on active header, but not collapsible
+ ( clickedIsActive && !options.collapsible ) ||
+ // allow canceling activation
+ ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
+ return;
+ }
+
+ options.active = collapsing ? false : this.headers.index( clicked );
+
+ // when the call to ._toggle() comes after the class changes
+ // it causes a very odd bug in IE 8 (see #6720)
+ this.active = clickedIsActive ? $() : clicked;
+ this._toggle( eventData );
+
+ // switch classes
+ // corner classes on the previously active header stay after the animation
+ active.removeClass( "ui-accordion-header-active ui-state-active" );
+ if ( options.icons ) {
+ active.children( ".ui-accordion-header-icon" )
+ .removeClass( options.icons.activeHeader )
+ .addClass( options.icons.header );
+ }
+
+ if ( !clickedIsActive ) {
+ clicked
+ .removeClass( "ui-corner-all" )
+ .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
+ if ( options.icons ) {
+ clicked.children( ".ui-accordion-header-icon" )
+ .removeClass( options.icons.header )
+ .addClass( options.icons.activeHeader );
+ }
+
+ clicked
+ .next()
+ .addClass( "ui-accordion-content-active" );
+ }
+ },
+
+ _toggle: function( data ) {
+ var toShow = data.newPanel,
+ toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
+
+ // handle activating a panel during the animation for another activation
+ this.prevShow.add( this.prevHide ).stop( true, true );
+ this.prevShow = toShow;
+ this.prevHide = toHide;
+
+ if ( this.options.animate ) {
+ this._animate( toShow, toHide, data );
+ } else {
+ toHide.hide();
+ toShow.show();
+ this._toggleComplete( data );
+ }
+
+ toHide.attr({
+ "aria-hidden": "true"
+ });
+ toHide.prev().attr( "aria-selected", "false" );
+ // if we're switching panels, remove the old header from the tab order
+ // if we're opening from collapsed state, remove the previous header from the tab order
+ // if we're collapsing, then keep the collapsing header in the tab order
+ if ( toShow.length && toHide.length ) {
+ toHide.prev().attr({
+ "tabIndex": -1,
+ "aria-expanded": "false"
+ });
+ } else if ( toShow.length ) {
+ this.headers.filter(function() {
+ return $( this ).attr( "tabIndex" ) === 0;
+ })
+ .attr( "tabIndex", -1 );
+ }
+
+ toShow
+ .attr( "aria-hidden", "false" )
+ .prev()
+ .attr({
+ "aria-selected": "true",
+ tabIndex: 0,
+ "aria-expanded": "true"
+ });
+ },
+
+ _animate: function( toShow, toHide, data ) {
+ var total, easing, duration,
+ that = this,
+ adjust = 0,
+ down = toShow.length &&
+ ( !toHide.length || ( toShow.index() < toHide.index() ) ),
+ animate = this.options.animate || {},
+ options = down && animate.down || animate,
+ complete = function() {
+ that._toggleComplete( data );
+ };
+
+ if ( typeof options === "number" ) {
+ duration = options;
+ }
+ if ( typeof options === "string" ) {
+ easing = options;
+ }
+ // fall back from options to animation in case of partial down settings
+ easing = easing || options.easing || animate.easing;
+ duration = duration || options.duration || animate.duration;
+
+ if ( !toHide.length ) {
+ return toShow.animate( showProps, duration, easing, complete );
+ }
+ if ( !toShow.length ) {
+ return toHide.animate( hideProps, duration, easing, complete );
+ }
+
+ total = toShow.show().outerHeight();
+ toHide.animate( hideProps, {
+ duration: duration,
+ easing: easing,
+ step: function( now, fx ) {
+ fx.now = Math.round( now );
+ }
+ });
+ toShow
+ .hide()
+ .animate( showProps, {
+ duration: duration,
+ easing: easing,
+ complete: complete,
+ step: function( now, fx ) {
+ fx.now = Math.round( now );
+ if ( fx.prop !== "height" ) {
+ adjust += fx.now;
+ } else if ( that.options.heightStyle !== "content" ) {
+ fx.now = Math.round( total - toHide.outerHeight() - adjust );
+ adjust = 0;
+ }
+ }
+ });
+ },
+
+ _toggleComplete: function( data ) {
+ var toHide = data.oldPanel;
+
+ toHide
+ .removeClass( "ui-accordion-content-active" )
+ .prev()
+ .removeClass( "ui-corner-top" )
+ .addClass( "ui-corner-all" );
+
+ // Work around for rendering bug in IE (#5421)
+ if ( toHide.length ) {
+ toHide.parent()[0].className = toHide.parent()[0].className;
+ }
+ this._trigger( "activate", null, data );
+ }
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.widget( "ui.autocomplete", {
+ version: "1.10.4",
+ defaultElement: "<input>",
+ options: {
+ appendTo: null,
+ autoFocus: false,
+ delay: 300,
+ minLength: 1,
+ position: {
+ my: "left top",
+ at: "left bottom",
+ collision: "none"
+ },
+ source: null,
+
+ // callbacks
+ change: null,
+ close: null,
+ focus: null,
+ open: null,
+ response: null,
+ search: null,
+ select: null
+ },
+
+ requestIndex: 0,
+ pending: 0,
+
+ _create: function() {
+ // Some browsers only repeat keydown events, not keypress events,
+ // so we use the suppressKeyPress flag to determine if we've already
+ // handled the keydown event. #7269
+ // Unfortunately the code for & in keypress is the same as the up arrow,
+ // so we use the suppressKeyPressRepeat flag to avoid handling keypress
+ // events when we know the keydown event was used to modify the
+ // search term. #7799
+ var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
+ nodeName = this.element[0].nodeName.toLowerCase(),
+ isTextarea = nodeName === "textarea",
+ isInput = nodeName === "input";
+
+ this.isMultiLine =
+ // Textareas are always multi-line
+ isTextarea ? true :
+ // Inputs are always single-line, even if inside a contentEditable element
+ // IE also treats inputs as contentEditable
+ isInput ? false :
+ // All other element types are determined by whether or not they're contentEditable
+ this.element.prop( "isContentEditable" );
+
+ this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
+ this.isNewMenu = true;
+
+ this.element
+ .addClass( "ui-autocomplete-input" )
+ .attr( "autocomplete", "off" );
+
+ this._on( this.element, {
+ keydown: function( event ) {
+ if ( this.element.prop( "readOnly" ) ) {
+ suppressKeyPress = true;
+ suppressInput = true;
+ suppressKeyPressRepeat = true;
+ return;
+ }
+
+ suppressKeyPress = false;
+ suppressInput = false;
+ suppressKeyPressRepeat = false;
+ var keyCode = $.ui.keyCode;
+ switch( event.keyCode ) {
+ case keyCode.PAGE_UP:
+ suppressKeyPress = true;
+ this._move( "previousPage", event );
+ break;
+ case keyCode.PAGE_DOWN:
+ suppressKeyPress = true;
+ this._move( "nextPage", event );
+ break;
+ case keyCode.UP:
+ suppressKeyPress = true;
+ this._keyEvent( "previous", event );
+ break;
+ case keyCode.DOWN:
+ suppressKeyPress = true;
+ this._keyEvent( "next", event );
+ break;
+ case keyCode.ENTER:
+ case keyCode.NUMPAD_ENTER:
+ // when menu is open and has focus
+ if ( this.menu.active ) {
+ // #6055 - Opera still allows the keypress to occur
+ // which causes forms to submit
+ suppressKeyPress = true;
+ event.preventDefault();
+ this.menu.select( event );
+ }
+ break;
+ case keyCode.TAB:
+ if ( this.menu.active ) {
+ this.menu.select( event );
+ }
+ break;
+ case keyCode.ESCAPE:
+ if ( this.menu.element.is( ":visible" ) ) {
+ this._value( this.term );
+ this.close( event );
+ // Different browsers have different default behavior for escape
+ // Single press can mean undo or clear
+ // Double press in IE means clear the whole form
+ event.preventDefault();
+ }
+ break;
+ default:
+ suppressKeyPressRepeat = true;
+ // search timeout should be triggered before the input value is changed
+ this._searchTimeout( event );
+ break;
+ }
+ },
+ keypress: function( event ) {
+ if ( suppressKeyPress ) {
+ suppressKeyPress = false;
+ if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
+ event.preventDefault();
+ }
+ return;
+ }
+ if ( suppressKeyPressRepeat ) {
+ return;
+ }
+
+ // replicate some key handlers to allow them to repeat in Firefox and Opera
+ var keyCode = $.ui.keyCode;
+ switch( event.keyCode ) {
+ case keyCode.PAGE_UP:
+ this._move( "previousPage", event );
+ break;
+ case keyCode.PAGE_DOWN:
+ this._move( "nextPage", event );
+ break;
+ case keyCode.UP:
+ this._keyEvent( "previous", event );
+ break;
+ case keyCode.DOWN:
+ this._keyEvent( "next", event );
+ break;
+ }
+ },
+ input: function( event ) {
+ if ( suppressInput ) {
+ suppressInput = false;
+ event.preventDefault();
+ return;
+ }
+ this._searchTimeout( event );
+ },
+ focus: function() {
+ this.selectedItem = null;
+ this.previous = this._value();
+ },
+ blur: function( event ) {
+ if ( this.cancelBlur ) {
+ delete this.cancelBlur;
+ return;
+ }
+
+ clearTimeout( this.searching );
+ this.close( event );
+ this._change( event );
+ }
+ });
+
+ this._initSource();
+ this.menu = $( "<ul>" )
+ .addClass( "ui-autocomplete ui-front" )
+ .appendTo( this._appendTo() )
+ .menu({
+ // disable ARIA support, the live region takes care of that
+ role: null
+ })
+ .hide()
+ .data( "ui-menu" );
+
+ this._on( this.menu.element, {
+ mousedown: function( event ) {
+ // prevent moving focus out of the text field
+ event.preventDefault();
+
+ // IE doesn't prevent moving focus even with event.preventDefault()
+ // so we set a flag to know when we should ignore the blur event
+ this.cancelBlur = true;
+ this._delay(function() {
+ delete this.cancelBlur;
+ });
+
+ // clicking on the scrollbar causes focus to shift to the body
+ // but we can't detect a mouseup or a click immediately afterward
+ // so we have to track the next mousedown and close the menu if
+ // the user clicks somewhere outside of the autocomplete
+ var menuElement = this.menu.element[ 0 ];
+ if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
+ this._delay(function() {
+ var that = this;
+ this.document.one( "mousedown", function( event ) {
+ if ( event.target !== that.element[ 0 ] &&
+ event.target !== menuElement &&
+ !$.contains( menuElement, event.target ) ) {
+ that.close();
+ }
+ });
+ });
+ }
+ },
+ menufocus: function( event, ui ) {
+ // support: Firefox
+ // Prevent accidental activation of menu items in Firefox (#7024 #9118)
+ if ( this.isNewMenu ) {
+ this.isNewMenu = false;
+ if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
+ this.menu.blur();
+
+ this.document.one( "mousemove", function() {
+ $( event.target ).trigger( event.originalEvent );
+ });
+
+ return;
+ }
+ }
+
+ var item = ui.item.data( "ui-autocomplete-item" );
+ if ( false !== this._trigger( "focus", event, { item: item } ) ) {
+ // use value to match what will end up in the input, if it was a key event
+ if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
+ this._value( item.value );
+ }
+ } else {
+ // Normally the input is populated with the item's value as the
+ // menu is navigated, causing screen readers to notice a change and
+ // announce the item. Since the focus event was canceled, this doesn't
+ // happen, so we update the live region so that screen readers can
+ // still notice the change and announce it.
+ this.liveRegion.text( item.value );
+ }
+ },
+ menuselect: function( event, ui ) {
+ var item = ui.item.data( "ui-autocomplete-item" ),
+ previous = this.previous;
+
+ // only trigger when focus was lost (click on menu)
+ if ( this.element[0] !== this.document[0].activeElement ) {
+ this.element.focus();
+ this.previous = previous;
+ // #6109 - IE triggers two focus events and the second
+ // is asynchronous, so we need to reset the previous
+ // term synchronously and asynchronously :-(
+ this._delay(function() {
+ this.previous = previous;
+ this.selectedItem = item;
+ });
+ }
+
+ if ( false !== this._trigger( "select", event, { item: item } ) ) {
+ this._value( item.value );
+ }
+ // reset the term after the select event
+ // this allows custom select handling to work properly
+ this.term = this._value();
+
+ this.close( event );
+ this.selectedItem = item;
+ }
+ });
+
+ this.liveRegion = $( "<span>", {
+ role: "status",
+ "aria-live": "polite"
+ })
+ .addClass( "ui-helper-hidden-accessible" )
+ .insertBefore( this.element );
+
+ // turning off autocomplete prevents the browser from remembering the
+ // value when navigating through history, so we re-enable autocomplete
+ // if the page is unloaded before the widget is destroyed. #7790
+ this._on( this.window, {
+ beforeunload: function() {
+ this.element.removeAttr( "autocomplete" );
+ }
+ });
+ },
+
+ _destroy: function() {
+ clearTimeout( this.searching );
+ this.element
+ .removeClass( "ui-autocomplete-input" )
+ .removeAttr( "autocomplete" );
+ this.menu.element.remove();
+ this.liveRegion.remove();
+ },
+
+ _setOption: function( key, value ) {
+ this._super( key, value );
+ if ( key === "source" ) {
+ this._initSource();
+ }
+ if ( key === "appendTo" ) {
+ this.menu.element.appendTo( this._appendTo() );
+ }
+ if ( key === "disabled" && value && this.xhr ) {
+ this.xhr.abort();
+ }
+ },
+
+ _appendTo: function() {
+ var element = this.options.appendTo;
+
+ if ( element ) {
+ element = element.jquery || element.nodeType ?
+ $( element ) :
+ this.document.find( element ).eq( 0 );
+ }
+
+ if ( !element ) {
+ element = this.element.closest( ".ui-front" );
+ }
+
+ if ( !element.length ) {
+ element = this.document[0].body;
+ }
+
+ return element;
+ },
+
+ _initSource: function() {
+ var array, url,
+ that = this;
+ if ( $.isArray(this.options.source) ) {
+ array = this.options.source;
+ this.source = function( request, response ) {
+ response( $.ui.autocomplete.filter( array, request.term ) );
+ };
+ } else if ( typeof this.options.source === "string" ) {
+ url = this.options.source;
+ this.source = function( request, response ) {
+ if ( that.xhr ) {
+ that.xhr.abort();
+ }
+ that.xhr = $.ajax({
+ url: url,
+ data: request,
+ dataType: "json",
+ success: function( data ) {
+ response( data );
+ },
+ error: function() {
+ response( [] );
+ }
+ });
+ };
+ } else {
+ this.source = this.options.source;
+ }
+ },
+
+ _searchTimeout: function( event ) {
+ clearTimeout( this.searching );
+ this.searching = this._delay(function() {
+ // only search if the value has changed
+ if ( this.term !== this._value() ) {
+ this.selectedItem = null;
+ this.search( null, event );
+ }
+ }, this.options.delay );
+ },
+
+ search: function( value, event ) {
+ value = value != null ? value : this._value();
+
+ // always save the actual value, not the one passed as an argument
+ this.term = this._value();
+
+ if ( value.length < this.options.minLength ) {
+ return this.close( event );
+ }
+
+ if ( this._trigger( "search", event ) === false ) {
+ return;
+ }
+
+ return this._search( value );
+ },
+
+ _search: function( value ) {
+ this.pending++;
+ this.element.addClass( "ui-autocomplete-loading" );
+ this.cancelSearch = false;
+
+ this.source( { term: value }, this._response() );
+ },
+
+ _response: function() {
+ var index = ++this.requestIndex;
+
+ return $.proxy(function( content ) {
+ if ( index === this.requestIndex ) {
+ this.__response( content );
+ }
+
+ this.pending--;
+ if ( !this.pending ) {
+ this.element.removeClass( "ui-autocomplete-loading" );
+ }
+ }, this );
+ },
+
+ __response: function( content ) {
+ if ( content ) {
+ content = this._normalize( content );
+ }
+ this._trigger( "response", null, { content: content } );
+ if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
+ this._suggest( content );
+ this._trigger( "open" );
+ } else {
+ // use ._close() instead of .close() so we don't cancel future searches
+ this._close();
+ }
+ },
+
+ close: function( event ) {
+ this.cancelSearch = true;
+ this._close( event );
+ },
+
+ _close: function( event ) {
+ if ( this.menu.element.is( ":visible" ) ) {
+ this.menu.element.hide();
+ this.menu.blur();
+ this.isNewMenu = true;
+ this._trigger( "close", event );
+ }
+ },
+
+ _change: function( event ) {
+ if ( this.previous !== this._value() ) {
+ this._trigger( "change", event, { item: this.selectedItem } );
+ }
+ },
+
+ _normalize: function( items ) {
+ // assume all items have the right format when the first item is complete
+ if ( items.length && items[0].label && items[0].value ) {
+ return items;
+ }
+ return $.map( items, function( item ) {
+ if ( typeof item === "string" ) {
+ return {
+ label: item,
+ value: item
+ };
+ }
+ return $.extend({
+ label: item.label || item.value,
+ value: item.value || item.label
+ }, item );
+ });
+ },
+
+ _suggest: function( items ) {
+ var ul = this.menu.element.empty();
+ this._renderMenu( ul, items );
+ this.isNewMenu = true;
+ this.menu.refresh();
+
+ // size and position menu
+ ul.show();
+ this._resizeMenu();
+ ul.position( $.extend({
+ of: this.element
+ }, this.options.position ));
+
+ if ( this.options.autoFocus ) {
+ this.menu.next();
+ }
+ },
+
+ _resizeMenu: function() {
+ var ul = this.menu.element;
+ ul.outerWidth( Math.max(
+ // Firefox wraps long text (possibly a rounding bug)
+ // so we add 1px to avoid the wrapping (#7513)
+ ul.width( "" ).outerWidth() + 1,
+ this.element.outerWidth()
+ ) );
+ },
+
+ _renderMenu: function( ul, items ) {
+ var that = this;
+ $.each( items, function( index, item ) {
+ that._renderItemData( ul, item );
+ });
+ },
+
+ _renderItemData: function( ul, item ) {
+ return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
+ },
+
+ _renderItem: function( ul, item ) {
+ return $( "<li>" )
+ .append( $( "<a>" ).text( item.label ) )
+ .appendTo( ul );
+ },
+
+ _move: function( direction, event ) {
+ if ( !this.menu.element.is( ":visible" ) ) {
+ this.search( null, event );
+ return;
+ }
+ if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
+ this.menu.isLastItem() && /^next/.test( direction ) ) {
+ this._value( this.term );
+ this.menu.blur();
+ return;
+ }
+ this.menu[ direction ]( event );
+ },
+
+ widget: function() {
+ return this.menu.element;
+ },
+
+ _value: function() {
+ return this.valueMethod.apply( this.element, arguments );
+ },
+
+ _keyEvent: function( keyEvent, event ) {
+ if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
+ this._move( keyEvent, event );
+
+ // prevents moving cursor to beginning/end of the text field in some browsers
+ event.preventDefault();
+ }
+ }
+});
+
+$.extend( $.ui.autocomplete, {
+ escapeRegex: function( value ) {
+ return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
+ },
+ filter: function(array, term) {
+ var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
+ return $.grep( array, function(value) {
+ return matcher.test( value.label || value.value || value );
+ });
+ }
+});
+
+
+// live region extension, adding a `messages` option
+// NOTE: This is an experimental API. We are still investigating
+// a full solution for string manipulation and internationalization.
+$.widget( "ui.autocomplete", $.ui.autocomplete, {
+ options: {
+ messages: {
+ noResults: "No search results.",
+ results: function( amount ) {
+ return amount + ( amount > 1 ? " results are" : " result is" ) +
+ " available, use up and down arrow keys to navigate.";
+ }
+ }
+ },
+
+ __response: function( content ) {
+ var message;
+ this._superApply( arguments );
+ if ( this.options.disabled || this.cancelSearch ) {
+ return;
+ }
+ if ( content && content.length ) {
+ message = this.options.messages.results( content.length );
+ } else {
+ message = this.options.messages.noResults;
+ }
+ this.liveRegion.text( message );
+ }
+});
+
+}( jQuery ));
+
+(function( $, undefined ) {
+
+var lastActive,
+ baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
+ typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
+ formResetHandler = function() {
+ var form = $( this );
+ setTimeout(function() {
+ form.find( ":ui-button" ).button( "refresh" );
+ }, 1 );
+ },
+ radioGroup = function( radio ) {
+ var name = radio.name,
+ form = radio.form,
+ radios = $( [] );
+ if ( name ) {
+ name = name.replace( /'/g, "\\'" );
+ if ( form ) {
+ radios = $( form ).find( "[name='" + name + "']" );
+ } else {
+ radios = $( "[name='" + name + "']", radio.ownerDocument )
+ .filter(function() {
+ return !this.form;
+ });
+ }
+ }
+ return radios;
+ };
+
+$.widget( "ui.button", {
+ version: "1.10.4",
+ defaultElement: "<button>",
+ options: {
+ disabled: null,
+ text: true,
+ label: null,
+ icons: {
+ primary: null,
+ secondary: null
+ }
+ },
+ _create: function() {
+ this.element.closest( "form" )
+ .unbind( "reset" + this.eventNamespace )
+ .bind( "reset" + this.eventNamespace, formResetHandler );
+
+ if ( typeof this.options.disabled !== "boolean" ) {
+ this.options.disabled = !!this.element.prop( "disabled" );
+ } else {
+ this.element.prop( "disabled", this.options.disabled );
+ }
+
+ this._determineButtonType();
+ this.hasTitle = !!this.buttonElement.attr( "title" );
+
+ var that = this,
+ options = this.options,
+ toggleButton = this.type === "checkbox" || this.type === "radio",
+ activeClass = !toggleButton ? "ui-state-active" : "";
+
+ if ( options.label === null ) {
+ options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
+ }
+
+ this._hoverable( this.buttonElement );
+
+ this.buttonElement
+ .addClass( baseClasses )
+ .attr( "role", "button" )
+ .bind( "mouseenter" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return;
+ }
+ if ( this === lastActive ) {
+ $( this ).addClass( "ui-state-active" );
+ }
+ })
+ .bind( "mouseleave" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return;
+ }
+ $( this ).removeClass( activeClass );
+ })
+ .bind( "click" + this.eventNamespace, function( event ) {
+ if ( options.disabled ) {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ }
+ });
+
+ // Can't use _focusable() because the element that receives focus
+ // and the element that gets the ui-state-focus class are different
+ this._on({
+ focus: function() {
+ this.buttonElement.addClass( "ui-state-focus" );
+ },
+ blur: function() {
+ this.buttonElement.removeClass( "ui-state-focus" );
+ }
+ });
+
+ if ( toggleButton ) {
+ this.element.bind( "change" + this.eventNamespace, function() {
+ that.refresh();
+ });
+ }
+
+ if ( this.type === "checkbox" ) {
+ this.buttonElement.bind( "click" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return false;
+ }
+ });
+ } else if ( this.type === "radio" ) {
+ this.buttonElement.bind( "click" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return false;
+ }
+ $( this ).addClass( "ui-state-active" );
+ that.buttonElement.attr( "aria-pressed", "true" );
+
+ var radio = that.element[ 0 ];
+ radioGroup( radio )
+ .not( radio )
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ });
+ } else {
+ this.buttonElement
+ .bind( "mousedown" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return false;
+ }
+ $( this ).addClass( "ui-state-active" );
+ lastActive = this;
+ that.document.one( "mouseup", function() {
+ lastActive = null;
+ });
+ })
+ .bind( "mouseup" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return false;
+ }
+ $( this ).removeClass( "ui-state-active" );
+ })
+ .bind( "keydown" + this.eventNamespace, function(event) {
+ if ( options.disabled ) {
+ return false;
+ }
+ if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
+ $( this ).addClass( "ui-state-active" );
+ }
+ })
+ // see #8559, we bind to blur here in case the button element loses
+ // focus between keydown and keyup, it would be left in an "active" state
+ .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
+ $( this ).removeClass( "ui-state-active" );
+ });
+
+ if ( this.buttonElement.is("a") ) {
+ this.buttonElement.keyup(function(event) {
+ if ( event.keyCode === $.ui.keyCode.SPACE ) {
+ // TODO pass through original event correctly (just as 2nd argument doesn't work)
+ $( this ).click();
+ }
+ });
+ }
+ }
+
+ // TODO: pull out $.Widget's handling for the disabled option into
+ // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
+ // be overridden by individual plugins
+ this._setOption( "disabled", options.disabled );
+ this._resetButton();
+ },
+
+ _determineButtonType: function() {
+ var ancestor, labelSelector, checked;
+
+ if ( this.element.is("[type=checkbox]") ) {
+ this.type = "checkbox";
+ } else if ( this.element.is("[type=radio]") ) {
+ this.type = "radio";
+ } else if ( this.element.is("input") ) {
+ this.type = "input";
+ } else {
+ this.type = "button";
+ }
+
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ // we don't search against the document in case the element
+ // is disconnected from the DOM
+ ancestor = this.element.parents().last();
+ labelSelector = "label[for='" + this.element.attr("id") + "']";
+ this.buttonElement = ancestor.find( labelSelector );
+ if ( !this.buttonElement.length ) {
+ ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
+ this.buttonElement = ancestor.filter( labelSelector );
+ if ( !this.buttonElement.length ) {
+ this.buttonElement = ancestor.find( labelSelector );
+ }
+ }
+ this.element.addClass( "ui-helper-hidden-accessible" );
+
+ checked = this.element.is( ":checked" );
+ if ( checked ) {
+ this.buttonElement.addClass( "ui-state-active" );
+ }
+ this.buttonElement.prop( "aria-pressed", checked );
+ } else {
+ this.buttonElement = this.element;
+ }
+ },
+
+ widget: function() {
+ return this.buttonElement;
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass( "ui-helper-hidden-accessible" );
+ this.buttonElement
+ .removeClass( baseClasses + " ui-state-active " + typeClasses )
+ .removeAttr( "role" )
+ .removeAttr( "aria-pressed" )
+ .html( this.buttonElement.find(".ui-button-text").html() );
+
+ if ( !this.hasTitle ) {
+ this.buttonElement.removeAttr( "title" );
+ }
+ },
+
+ _setOption: function( key, value ) {
+ this._super( key, value );
+ if ( key === "disabled" ) {
+ this.element.prop( "disabled", !!value );
+ if ( value ) {
+ this.buttonElement.removeClass( "ui-state-focus" );
+ }
+ return;
+ }
+ this._resetButton();
+ },
+
+ refresh: function() {
+ //See #8237 & #8828
+ var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
+
+ if ( isDisabled !== this.options.disabled ) {
+ this._setOption( "disabled", isDisabled );
+ }
+ if ( this.type === "radio" ) {
+ radioGroup( this.element[0] ).each(function() {
+ if ( $( this ).is( ":checked" ) ) {
+ $( this ).button( "widget" )
+ .addClass( "ui-state-active" )
+ .attr( "aria-pressed", "true" );
+ } else {
+ $( this ).button( "widget" )
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ }
+ });
+ } else if ( this.type === "checkbox" ) {
+ if ( this.element.is( ":checked" ) ) {
+ this.buttonElement
+ .addClass( "ui-state-active" )
+ .attr( "aria-pressed", "true" );
+ } else {
+ this.buttonElement
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ }
+ }
+ },
+
+ _resetButton: function() {
+ if ( this.type === "input" ) {
+ if ( this.options.label ) {
+ this.element.val( this.options.label );
+ }
+ return;
+ }
+ var buttonElement = this.buttonElement.removeClass( typeClasses ),
+ buttonText = $( "<span></span>", this.document[0] )
+ .addClass( "ui-button-text" )
+ .html( this.options.label )
+ .appendTo( buttonElement.empty() )
+ .text(),
+ icons = this.options.icons,
+ multipleIcons = icons.primary && icons.secondary,
+ buttonClasses = [];
+
+ if ( icons.primary || icons.secondary ) {
+ if ( this.options.text ) {
+ buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
+ }
+
+ if ( icons.primary ) {
+ buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
+ }
+
+ if ( icons.secondary ) {
+ buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
+ }
+
+ if ( !this.options.text ) {
+ buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
+
+ if ( !this.hasTitle ) {
+ buttonElement.attr( "title", $.trim( buttonText ) );
+ }
+ }
+ } else {
+ buttonClasses.push( "ui-button-text-only" );
+ }
+ buttonElement.addClass( buttonClasses.join( " " ) );
+ }
+});
+
+$.widget( "ui.buttonset", {
+ version: "1.10.4",
+ options: {
+ items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
+ },
+
+ _create: function() {
+ this.element.addClass( "ui-buttonset" );
+ },
+
+ _init: function() {
+ this.refresh();
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "disabled" ) {
+ this.buttons.button( "option", key, value );
+ }
+
+ this._super( key, value );
+ },
+
+ refresh: function() {
+ var rtl = this.element.css( "direction" ) === "rtl";
+
+ this.buttons = this.element.find( this.options.items )
+ .filter( ":ui-button" )
+ .button( "refresh" )
+ .end()
+ .not( ":ui-button" )
+ .button()
+ .end()
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
+ .filter( ":first" )
+ .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
+ .end()
+ .filter( ":last" )
+ .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
+ .end()
+ .end();
+ },
+
+ _destroy: function() {
+ this.element.removeClass( "ui-buttonset" );
+ this.buttons
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-corner-left ui-corner-right" )
+ .end()
+ .button( "destroy" );
+ }
+});
+
+}( jQuery ) );
+
+(function( $, undefined ) {
+
+$.extend($.ui, { datepicker: { version: "1.10.4" } });
+
+var PROP_NAME = "datepicker",
+ instActive;
+
+/* Date picker manager.
+ Use the singleton instance of this class, $.datepicker, to interact with the date picker.
+ Settings for (groups of) date pickers are maintained in an instance object,
+ allowing multiple different settings on the same page. */
+
+function Datepicker() {
+ this._curInst = null; // The current instance in use
+ this._keyEvent = false; // If the last event was a key event
+ this._disabledInputs = []; // List of date picker inputs that have been disabled
+ this._datepickerShowing = false; // True if the popup picker is showing , false if not
+ this._inDialog = false; // True if showing within a "dialog", false if not
+ this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
+ this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
+ this._appendClass = "ui-datepicker-append"; // The name of the append marker class
+ this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
+ this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
+ this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
+ this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
+ this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
+ this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
+ this.regional = []; // Available regional settings, indexed by language code
+ this.regional[""] = { // Default regional settings
+ closeText: "Done", // Display text for close link
+ prevText: "Prev", // Display text for previous month link
+ nextText: "Next", // Display text for next month link
+ currentText: "Today", // Display text for current month link
+ monthNames: ["January","February","March","April","May","June",
+ "July","August","September","October","November","December"], // Names of months for drop-down and formatting
+ monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
+ dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
+ dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
+ weekHeader: "Wk", // Column header for week of the year
+ dateFormat: "mm/dd/yy", // See format options on parseDate
+ firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
+ isRTL: false, // True if right-to-left language, false if left-to-right
+ showMonthAfterYear: false, // True if the year select precedes month, false for month then year
+ yearSuffix: "" // Additional text to append to the year in the month headers
+ };
+ this._defaults = { // Global defaults for all the date picker instances
+ showOn: "focus", // "focus" for popup on focus,
+ // "button" for trigger button, or "both" for either
+ showAnim: "fadeIn", // Name of jQuery animation for popup
+ showOptions: {}, // Options for enhanced animations
+ defaultDate: null, // Used when field is blank: actual date,
+ // +/-number for offset from today, null for today
+ appendText: "", // Display text following the input box, e.g. showing the format
+ buttonText: "...", // Text for trigger button
+ buttonImage: "", // URL for trigger button image
+ buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
+ hideIfNoPrevNext: false, // True to hide next/previous month links
+ // if not applicable, false to just disable them
+ navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
+ gotoCurrent: false, // True if today link goes back to current selection instead
+ changeMonth: false, // True if month can be selected directly, false if only prev/next
+ changeYear: false, // True if year can be selected directly, false if only prev/next
+ yearRange: "c-10:c+10", // Range of years to display in drop-down,
+ // either relative to today's year (-nn:+nn), relative to currently displayed year
+ // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
+ showOtherMonths: false, // True to show dates in other months, false to leave blank
+ selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
+ showWeek: false, // True to show week of the year, false to not show it
+ calculateWeek: this.iso8601Week, // How to calculate the week of the year,
+ // takes a Date and returns the number of the week for it
+ shortYearCutoff: "+10", // Short year values < this are in the current century,
+ // > this are in the previous century,
+ // string value starting with "+" for current year + value
+ minDate: null, // The earliest selectable date, or null for no limit
+ maxDate: null, // The latest selectable date, or null for no limit
+ duration: "fast", // Duration of display/closure
+ beforeShowDay: null, // Function that takes a date and returns an array with
+ // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
+ // [2] = cell title (optional), e.g. $.datepicker.noWeekends
+ beforeShow: null, // Function that takes an input field and
+ // returns a set of custom settings for the date picker
+ onSelect: null, // Define a callback function when a date is selected
+ onChangeMonthYear: null, // Define a callback function when the month or year is changed
+ onClose: null, // Define a callback function when the datepicker is closed
+ numberOfMonths: 1, // Number of months to show at a time
+ showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
+ stepMonths: 1, // Number of months to step back/forward
+ stepBigMonths: 12, // Number of months to step back/forward for the big links
+ altField: "", // Selector for an alternate field to store selected dates into
+ altFormat: "", // The date format to use for the alternate field
+ constrainInput: true, // The input is constrained by the current date format
+ showButtonPanel: false, // True to show button panel, false to not show it
+ autoSize: false, // True to size the input for the date format, false to leave as is
+ disabled: false // The initial disabled state
+ };
+ $.extend(this._defaults, this.regional[""]);
+ this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
+}
+
+$.extend(Datepicker.prototype, {
+ /* Class name added to elements to indicate already configured with a date picker. */
+ markerClassName: "hasDatepicker",
+
+ //Keep track of the maximum number of rows displayed (see #7043)
+ maxRows: 4,
+
+ // TODO rename to "widget" when switching to widget factory
+ _widgetDatepicker: function() {
+ return this.dpDiv;
+ },
+
+ /* Override the default settings for all instances of the date picker.
+ * @param settings object - the new settings to use as defaults (anonymous object)
+ * @return the manager object
+ */
+ setDefaults: function(settings) {
+ extendRemove(this._defaults, settings || {});
+ return this;
+ },
+
+ /* Attach the date picker to a jQuery selection.
+ * @param target element - the target input field or division or span
+ * @param settings object - the new settings to use for this date picker instance (anonymous)
+ */
+ _attachDatepicker: function(target, settings) {
+ var nodeName, inline, inst;
+ nodeName = target.nodeName.toLowerCase();
+ inline = (nodeName === "div" || nodeName === "span");
+ if (!target.id) {
+ this.uuid += 1;
+ target.id = "dp" + this.uuid;
+ }
+ inst = this._newInst($(target), inline);
+ inst.settings = $.extend({}, settings || {});
+ if (nodeName === "input") {
+ this._connectDatepicker(target, inst);
+ } else if (inline) {
+ this._inlineDatepicker(target, inst);
+ }
+ },
+
+ /* Create a new instance object. */
+ _newInst: function(target, inline) {
+ var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
+ return {id: id, input: target, // associated target
+ selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
+ drawMonth: 0, drawYear: 0, // month being drawn
+ inline: inline, // is datepicker inline or not
+ dpDiv: (!inline ? this.dpDiv : // presentation div
+ bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
+ },
+
+ /* Attach the date picker to an input field. */
+ _connectDatepicker: function(target, inst) {
+ var input = $(target);
+ inst.append = $([]);
+ inst.trigger = $([]);
+ if (input.hasClass(this.markerClassName)) {
+ return;
+ }
+ this._attachments(input, inst);
+ input.addClass(this.markerClassName).keydown(this._doKeyDown).
+ keypress(this._doKeyPress).keyup(this._doKeyUp);
+ this._autoSize(inst);
+ $.data(target, PROP_NAME, inst);
+ //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
+ if( inst.settings.disabled ) {
+ this._disableDatepicker( target );
+ }
+ },
+
+ /* Make attachments based on settings. */
+ _attachments: function(input, inst) {
+ var showOn, buttonText, buttonImage,
+ appendText = this._get(inst, "appendText"),
+ isRTL = this._get(inst, "isRTL");
+
+ if (inst.append) {
+ inst.append.remove();
+ }
+ if (appendText) {
+ inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
+ input[isRTL ? "before" : "after"](inst.append);
+ }
+
+ input.unbind("focus", this._showDatepicker);
+
+ if (inst.trigger) {
+ inst.trigger.remove();
+ }
+
+ showOn = this._get(inst, "showOn");
+ if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
+ input.focus(this._showDatepicker);
+ }
+ if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
+ buttonText = this._get(inst, "buttonText");
+ buttonImage = this._get(inst, "buttonImage");
+ inst.trigger = $(this._get(inst, "buttonImageOnly") ?
+ $("<img/>").addClass(this._triggerClass).
+ attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
+ $("<button type='button'></button>").addClass(this._triggerClass).
+ html(!buttonImage ? buttonText : $("<img/>").attr(
+ { src:buttonImage, alt:buttonText, title:buttonText })));
+ input[isRTL ? "before" : "after"](inst.trigger);
+ inst.trigger.click(function() {
+ if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
+ $.datepicker._hideDatepicker();
+ } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
+ $.datepicker._hideDatepicker();
+ $.datepicker._showDatepicker(input[0]);
+ } else {
+ $.datepicker._showDatepicker(input[0]);
+ }
+ return false;
+ });
+ }
+ },
+
+ /* Apply the maximum length for the date format. */
+ _autoSize: function(inst) {
+ if (this._get(inst, "autoSize") && !inst.inline) {
+ var findMax, max, maxI, i,
+ date = new Date(2009, 12 - 1, 20), // Ensure double digits
+ dateFormat = this._get(inst, "dateFormat");
+
+ if (dateFormat.match(/[DM]/)) {
+ findMax = function(names) {
+ max = 0;
+ maxI = 0;
+ for (i = 0; i < names.length; i++) {
+ if (names[i].length > max) {
+ max = names[i].length;
+ maxI = i;
+ }
+ }
+ return maxI;
+ };
+ date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
+ "monthNames" : "monthNamesShort"))));
+ date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
+ "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
+ }
+ inst.input.attr("size", this._formatDate(inst, date).length);
+ }
+ },
+
+ /* Attach an inline date picker to a div. */
+ _inlineDatepicker: function(target, inst) {
+ var divSpan = $(target);
+ if (divSpan.hasClass(this.markerClassName)) {
+ return;
+ }
+ divSpan.addClass(this.markerClassName).append(inst.dpDiv);
+ $.data(target, PROP_NAME, inst);
+ this._setDate(inst, this._getDefaultDate(inst), true);
+ this._updateDatepicker(inst);
+ this._updateAlternate(inst);
+ //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
+ if( inst.settings.disabled ) {
+ this._disableDatepicker( target );
+ }
+ // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
+ // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
+ inst.dpDiv.css( "display", "block" );
+ },
+
+ /* Pop-up the date picker in a "dialog" box.
+ * @param input element - ignored
+ * @param date string or Date - the initial date to display
+ * @param onSelect function - the function to call when a date is selected
+ * @param settings object - update the dialog date picker instance's settings (anonymous object)
+ * @param pos int[2] - coordinates for the dialog's position within the screen or
+ * event - with x/y coordinates or
+ * leave empty for default (screen centre)
+ * @return the manager object
+ */
+ _dialogDatepicker: function(input, date, onSelect, settings, pos) {
+ var id, browserWidth, browserHeight, scrollX, scrollY,
+ inst = this._dialogInst; // internal instance
+
+ if (!inst) {
+ this.uuid += 1;
+ id = "dp" + this.uuid;
+ this._dialogInput = $("<input type='text' id='" + id +
+ "' style='position: absolute; top: -100px; width: 0px;'/>");
+ this._dialogInput.keydown(this._doKeyDown);
+ $("body").append(this._dialogInput);
+ inst = this._dialogInst = this._newInst(this._dialogInput, false);
+ inst.settings = {};
+ $.data(this._dialogInput[0], PROP_NAME, inst);
+ }
+ extendRemove(inst.settings, settings || {});
+ date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
+ this._dialogInput.val(date);
+
+ this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
+ if (!this._pos) {
+ browserWidth = document.documentElement.clientWidth;
+ browserHeight = document.documentElement.clientHeight;
+ scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
+ scrollY = document.documentElement.scrollTop || document.body.scrollTop;
+ this._pos = // should use actual width/height below
+ [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
+ }
+
+ // move input on screen for focus, but hidden behind dialog
+ this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
+ inst.settings.onSelect = onSelect;
+ this._inDialog = true;
+ this.dpDiv.addClass(this._dialogClass);
+ this._showDatepicker(this._dialogInput[0]);
+ if ($.blockUI) {
+ $.blockUI(this.dpDiv);
+ }
+ $.data(this._dialogInput[0], PROP_NAME, inst);
+ return this;
+ },
+
+ /* Detach a datepicker from its control.
+ * @param target element - the target input field or division or span
+ */
+ _destroyDatepicker: function(target) {
+ var nodeName,
+ $target = $(target),
+ inst = $.data(target, PROP_NAME);
+
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+
+ nodeName = target.nodeName.toLowerCase();
+ $.removeData(target, PROP_NAME);
+ if (nodeName === "input") {
+ inst.append.remove();
+ inst.trigger.remove();
+ $target.removeClass(this.markerClassName).
+ unbind("focus", this._showDatepicker).
+ unbind("keydown", this._doKeyDown).
+ unbind("keypress", this._doKeyPress).
+ unbind("keyup", this._doKeyUp);
+ } else if (nodeName === "div" || nodeName === "span") {
+ $target.removeClass(this.markerClassName).empty();
+ }
+ },
+
+ /* Enable the date picker to a jQuery selection.
+ * @param target element - the target input field or division or span
+ */
+ _enableDatepicker: function(target) {
+ var nodeName, inline,
+ $target = $(target),
+ inst = $.data(target, PROP_NAME);
+
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+
+ nodeName = target.nodeName.toLowerCase();
+ if (nodeName === "input") {
+ target.disabled = false;
+ inst.trigger.filter("button").
+ each(function() { this.disabled = false; }).end().
+ filter("img").css({opacity: "1.0", cursor: ""});
+ } else if (nodeName === "div" || nodeName === "span") {
+ inline = $target.children("." + this._inlineClass);
+ inline.children().removeClass("ui-state-disabled");
+ inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
+ prop("disabled", false);
+ }
+ this._disabledInputs = $.map(this._disabledInputs,
+ function(value) { return (value === target ? null : value); }); // delete entry
+ },
+
+ /* Disable the date picker to a jQuery selection.
+ * @param target element - the target input field or division or span
+ */
+ _disableDatepicker: function(target) {
+ var nodeName, inline,
+ $target = $(target),
+ inst = $.data(target, PROP_NAME);
+
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+
+ nodeName = target.nodeName.toLowerCase();
+ if (nodeName === "input") {
+ target.disabled = true;
+ inst.trigger.filter("button").
+ each(function() { this.disabled = true; }).end().
+ filter("img").css({opacity: "0.5", cursor: "default"});
+ } else if (nodeName === "div" || nodeName === "span") {
+ inline = $target.children("." + this._inlineClass);
+ inline.children().addClass("ui-state-disabled");
+ inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
+ prop("disabled", true);
+ }
+ this._disabledInputs = $.map(this._disabledInputs,
+ function(value) { return (value === target ? null : value); }); // delete entry
+ this._disabledInputs[this._disabledInputs.length] = target;
+ },
+
+ /* Is the first field in a jQuery collection disabled as a datepicker?
+ * @param target element - the target input field or division or span
+ * @return boolean - true if disabled, false if enabled
+ */
+ _isDisabledDatepicker: function(target) {
+ if (!target) {
+ return false;
+ }
+ for (var i = 0; i < this._disabledInputs.length; i++) {
+ if (this._disabledInputs[i] === target) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /* Retrieve the instance data for the target control.
+ * @param target element - the target input field or division or span
+ * @return object - the associated instance data
+ * @throws error if a jQuery problem getting data
+ */
+ _getInst: function(target) {
+ try {
+ return $.data(target, PROP_NAME);
+ }
+ catch (err) {
+ throw "Missing instance data for this datepicker";
+ }
+ },
+
+ /* Update or retrieve the settings for a date picker attached to an input field or division.
+ * @param target element - the target input field or division or span
+ * @param name object - the new settings to update or
+ * string - the name of the setting to change or retrieve,
+ * when retrieving also "all" for all instance settings or
+ * "defaults" for all global defaults
+ * @param value any - the new value for the setting
+ * (omit if above is an object or to retrieve a value)
+ */
+ _optionDatepicker: function(target, name, value) {
+ var settings, date, minDate, maxDate,
+ inst = this._getInst(target);
+
+ if (arguments.length === 2 && typeof name === "string") {
+ return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
+ (inst ? (name === "all" ? $.extend({}, inst.settings) :
+ this._get(inst, name)) : null));
+ }
+
+ settings = name || {};
+ if (typeof name === "string") {
+ settings = {};
+ settings[name] = value;
+ }
+
+ if (inst) {
+ if (this._curInst === inst) {
+ this._hideDatepicker();
+ }
+
+ date = this._getDateDatepicker(target, true);
+ minDate = this._getMinMaxDate(inst, "min");
+ maxDate = this._getMinMaxDate(inst, "max");
+ extendRemove(inst.settings, settings);
+ // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
+ if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
+ inst.settings.minDate = this._formatDate(inst, minDate);
+ }
+ if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
+ inst.settings.maxDate = this._formatDate(inst, maxDate);
+ }
+ if ( "disabled" in settings ) {
+ if ( settings.disabled ) {
+ this._disableDatepicker(target);
+ } else {
+ this._enableDatepicker(target);
+ }
+ }
+ this._attachments($(target), inst);
+ this._autoSize(inst);
+ this._setDate(inst, date);
+ this._updateAlternate(inst);
+ this._updateDatepicker(inst);
+ }
+ },
+
+ // change method deprecated
+ _changeDatepicker: function(target, name, value) {
+ this._optionDatepicker(target, name, value);
+ },
+
+ /* Redraw the date picker attached to an input field or division.
+ * @param target element - the target input field or division or span
+ */
+ _refreshDatepicker: function(target) {
+ var inst = this._getInst(target);
+ if (inst) {
+ this._updateDatepicker(inst);
+ }
+ },
+
+ /* Set the dates for a jQuery selection.
+ * @param target element - the target input field or division or span
+ * @param date Date - the new date
+ */
+ _setDateDatepicker: function(target, date) {
+ var inst = this._getInst(target);
+ if (inst) {
+ this._setDate(inst, date);
+ this._updateDatepicker(inst);
+ this._updateAlternate(inst);
+ }
+ },
+
+ /* Get the date(s) for the first entry in a jQuery selection.
+ * @param target element - the target input field or division or span
+ * @param noDefault boolean - true if no default date is to be used
+ * @return Date - the current date
+ */
+ _getDateDatepicker: function(target, noDefault) {
+ var inst = this._getInst(target);
+ if (inst && !inst.inline) {
+ this._setDateFromField(inst, noDefault);
+ }
+ return (inst ? this._getDate(inst) : null);
+ },
+
+ /* Handle keystrokes. */
+ _doKeyDown: function(event) {
+ var onSelect, dateStr, sel,
+ inst = $.datepicker._getInst(event.target),
+ handled = true,
+ isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
+
+ inst._keyEvent = true;
+ if ($.datepicker._datepickerShowing) {
+ switch (event.keyCode) {
+ case 9: $.datepicker._hideDatepicker();
+ handled = false;
+ break; // hide on tab out
+ case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
+ $.datepicker._currentClass + ")", inst.dpDiv);
+ if (sel[0]) {
+ $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
+ }
+
+ onSelect = $.datepicker._get(inst, "onSelect");
+ if (onSelect) {
+ dateStr = $.datepicker._formatDate(inst);
+
+ // trigger custom callback
+ onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
+ } else {
+ $.datepicker._hideDatepicker();
+ }
+
+ return false; // don't submit the form
+ case 27: $.datepicker._hideDatepicker();
+ break; // hide on escape
+ case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ -$.datepicker._get(inst, "stepBigMonths") :
+ -$.datepicker._get(inst, "stepMonths")), "M");
+ break; // previous month/year on page up/+ ctrl
+ case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ +$.datepicker._get(inst, "stepBigMonths") :
+ +$.datepicker._get(inst, "stepMonths")), "M");
+ break; // next month/year on page down/+ ctrl
+ case 35: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._clearDate(event.target);
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // clear on ctrl or command +end
+ case 36: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._gotoToday(event.target);
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // current on ctrl or command +home
+ case 37: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ // -1 day on ctrl or command +left
+ if (event.originalEvent.altKey) {
+ $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ -$.datepicker._get(inst, "stepBigMonths") :
+ -$.datepicker._get(inst, "stepMonths")), "M");
+ }
+ // next month/year on alt +left on Mac
+ break;
+ case 38: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, -7, "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // -1 week on ctrl or command +up
+ case 39: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ // +1 day on ctrl or command +right
+ if (event.originalEvent.altKey) {
+ $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ +$.datepicker._get(inst, "stepBigMonths") :
+ +$.datepicker._get(inst, "stepMonths")), "M");
+ }
+ // next month/year on alt +right
+ break;
+ case 40: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, +7, "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // +1 week on ctrl or command +down
+ default: handled = false;
+ }
+ } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
+ $.datepicker._showDatepicker(this);
+ } else {
+ handled = false;
+ }
+
+ if (handled) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ },
+
+ /* Filter entered characters - based on date format. */
+ _doKeyPress: function(event) {
+ var chars, chr,
+ inst = $.datepicker._getInst(event.target);
+
+ if ($.datepicker._get(inst, "constrainInput")) {
+ chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
+ chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
+ return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
+ }
+ },
+
+ /* Synchronise manual entry and field/alternate field. */
+ _doKeyUp: function(event) {
+ var date,
+ inst = $.datepicker._getInst(event.target);
+
+ if (inst.input.val() !== inst.lastVal) {
+ try {
+ date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
+ (inst.input ? inst.input.val() : null),
+ $.datepicker._getFormatConfig(inst));
+
+ if (date) { // only if valid
+ $.datepicker._setDateFromField(inst);
+ $.datepicker._updateAlternate(inst);
+ $.datepicker._updateDatepicker(inst);
+ }
+ }
+ catch (err) {
+ }
+ }
+ return true;
+ },
+
+ /* Pop-up the date picker for a given input field.
+ * If false returned from beforeShow event handler do not show.
+ * @param input element - the input field attached to the date picker or
+ * event - if triggered by focus
+ */
+ _showDatepicker: function(input) {
+ input = input.target || input;
+ if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
+ input = $("input", input.parentNode)[0];
+ }
+
+ if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
+ return;
+ }
+
+ var inst, beforeShow, beforeShowSettings, isFixed,
+ offset, showAnim, duration;
+
+ inst = $.datepicker._getInst(input);
+ if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
+ $.datepicker._curInst.dpDiv.stop(true, true);
+ if ( inst && $.datepicker._datepickerShowing ) {
+ $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
+ }
+ }
+
+ beforeShow = $.datepicker._get(inst, "beforeShow");
+ beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
+ if(beforeShowSettings === false){
+ return;
+ }
+ extendRemove(inst.settings, beforeShowSettings);
+
+ inst.lastVal = null;
+ $.datepicker._lastInput = input;
+ $.datepicker._setDateFromField(inst);
+
+ if ($.datepicker._inDialog) { // hide cursor
+ input.value = "";
+ }
+ if (!$.datepicker._pos) { // position below input
+ $.datepicker._pos = $.datepicker._findPos(input);
+ $.datepicker._pos[1] += input.offsetHeight; // add the height
+ }
+
+ isFixed = false;
+ $(input).parents().each(function() {
+ isFixed |= $(this).css("position") === "fixed";
+ return !isFixed;
+ });
+
+ offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
+ $.datepicker._pos = null;
+ //to avoid flashes on Firefox
+ inst.dpDiv.empty();
+ // determine sizing offscreen
+ inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
+ $.datepicker._updateDatepicker(inst);
+ // fix width for dynamic number of date pickers
+ // and adjust position before showing
+ offset = $.datepicker._checkOffset(inst, offset, isFixed);
+ inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
+ "static" : (isFixed ? "fixed" : "absolute")), display: "none",
+ left: offset.left + "px", top: offset.top + "px"});
+
+ if (!inst.inline) {
+ showAnim = $.datepicker._get(inst, "showAnim");
+ duration = $.datepicker._get(inst, "duration");
+ inst.dpDiv.zIndex($(input).zIndex()+1);
+ $.datepicker._datepickerShowing = true;
+
+ if ( $.effects && $.effects.effect[ showAnim ] ) {
+ inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
+ } else {
+ inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
+ }
+
+ if ( $.datepicker._shouldFocusInput( inst ) ) {
+ inst.input.focus();
+ }
+
+ $.datepicker._curInst = inst;
+ }
+ },
+
+ /* Generate the date picker content. */
+ _updateDatepicker: function(inst) {
+ this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
+ instActive = inst; // for delegate hover events
+ inst.dpDiv.empty().append(this._generateHTML(inst));
+ this._attachHandlers(inst);
+ inst.dpDiv.find("." + this._dayOverClass + " a").mouseover();
+
+ var origyearshtml,
+ numMonths = this._getNumberOfMonths(inst),
+ cols = numMonths[1],
+ width = 17;
+
+ inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
+ if (cols > 1) {
+ inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
+ }
+ inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
+ "Class"]("ui-datepicker-multi");
+ inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
+ "Class"]("ui-datepicker-rtl");
+
+ if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
+ inst.input.focus();
+ }
+
+ // deffered render of the years select (to avoid flashes on Firefox)
+ if( inst.yearshtml ){
+ origyearshtml = inst.yearshtml;
+ setTimeout(function(){
+ //assure that inst.yearshtml didn't change.
+ if( origyearshtml === inst.yearshtml && inst.yearshtml ){
+ inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
+ }
+ origyearshtml = inst.yearshtml = null;
+ }, 0);
+ }
+ },
+
+ // #6694 - don't focus the input if it's already focused
+ // this breaks the change event in IE
+ // Support: IE and jQuery <1.9
+ _shouldFocusInput: function( inst ) {
+ return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
+ },
+
+ /* Check positioning to remain on screen. */
+ _checkOffset: function(inst, offset, isFixed) {
+ var dpWidth = inst.dpDiv.outerWidth(),
+ dpHeight = inst.dpDiv.outerHeight(),
+ inputWidth = inst.input ? inst.input.outerWidth() : 0,
+ inputHeight = inst.input ? inst.input.outerHeight() : 0,
+ viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
+ viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
+
+ offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
+ offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
+ offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
+
+ // now check if datepicker is showing outside window viewport - move to a better place if so.
+ offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
+ Math.abs(offset.left + dpWidth - viewWidth) : 0);
+ offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
+ Math.abs(dpHeight + inputHeight) : 0);
+
+ return offset;
+ },
+
+ /* Find an object's position on the screen. */
+ _findPos: function(obj) {
+ var position,
+ inst = this._getInst(obj),
+ isRTL = this._get(inst, "isRTL");
+
+ while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
+ obj = obj[isRTL ? "previousSibling" : "nextSibling"];
+ }
+
+ position = $(obj).offset();
+ return [position.left, position.top];
+ },
+
+ /* Hide the date picker from view.
+ * @param input element - the input field attached to the date picker
+ */
+ _hideDatepicker: function(input) {
+ var showAnim, duration, postProcess, onClose,
+ inst = this._curInst;
+
+ if (!inst || (input && inst !== $.data(input, PROP_NAME))) {
+ return;
+ }
+
+ if (this._datepickerShowing) {
+ showAnim = this._get(inst, "showAnim");
+ duration = this._get(inst, "duration");
+ postProcess = function() {
+ $.datepicker._tidyDialog(inst);
+ };
+
+ // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
+ if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
+ inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
+ } else {
+ inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
+ (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
+ }
+
+ if (!showAnim) {
+ postProcess();
+ }
+ this._datepickerShowing = false;
+
+ onClose = this._get(inst, "onClose");
+ if (onClose) {
+ onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
+ }
+
+ this._lastInput = null;
+ if (this._inDialog) {
+ this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
+ if ($.blockUI) {
+ $.unblockUI();
+ $("body").append(this.dpDiv);
+ }
+ }
+ this._inDialog = false;
+ }
+ },
+
+ /* Tidy up after a dialog display. */
+ _tidyDialog: function(inst) {
+ inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
+ },
+
+ /* Close date picker if clicked elsewhere. */
+ _checkExternalClick: function(event) {
+ if (!$.datepicker._curInst) {
+ return;
+ }
+
+ var $target = $(event.target),
+ inst = $.datepicker._getInst($target[0]);
+
+ if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
+ $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
+ !$target.hasClass($.datepicker.markerClassName) &&
+ !$target.closest("." + $.datepicker._triggerClass).length &&
+ $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
+ ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
+ $.datepicker._hideDatepicker();
+ }
+ },
+
+ /* Adjust one of the date sub-fields. */
+ _adjustDate: function(id, offset, period) {
+ var target = $(id),
+ inst = this._getInst(target[0]);
+
+ if (this._isDisabledDatepicker(target[0])) {
+ return;
+ }
+ this._adjustInstDate(inst, offset +
+ (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
+ period);
+ this._updateDatepicker(inst);
+ },
+
+ /* Action for current link. */
+ _gotoToday: function(id) {
+ var date,
+ target = $(id),
+ inst = this._getInst(target[0]);
+
+ if (this._get(inst, "gotoCurrent") && inst.currentDay) {
+ inst.selectedDay = inst.currentDay;
+ inst.drawMonth = inst.selectedMonth = inst.currentMonth;
+ inst.drawYear = inst.selectedYear = inst.currentYear;
+ } else {
+ date = new Date();
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ }
+ this._notifyChange(inst);
+ this._adjustDate(target);
+ },
+
+ /* Action for selecting a new month/year. */
+ _selectMonthYear: function(id, select, period) {
+ var target = $(id),
+ inst = this._getInst(target[0]);
+
+ inst["selected" + (period === "M" ? "Month" : "Year")] =
+ inst["draw" + (period === "M" ? "Month" : "Year")] =
+ parseInt(select.options[select.selectedIndex].value,10);
+
+ this._notifyChange(inst);
+ this._adjustDate(target);
+ },
+
+ /* Action for selecting a day. */
+ _selectDay: function(id, month, year, td) {
+ var inst,
+ target = $(id);
+
+ if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
+ return;
+ }
+
+ inst = this._getInst(target[0]);
+ inst.selectedDay = inst.currentDay = $("a", td).html();
+ inst.selectedMonth = inst.currentMonth = month;
+ inst.selectedYear = inst.currentYear = year;
+ this._selectDate(id, this._formatDate(inst,
+ inst.currentDay, inst.currentMonth, inst.currentYear));
+ },
+
+ /* Erase the input field and hide the date picker. */
+ _clearDate: function(id) {
+ var target = $(id);
+ this._selectDate(target, "");
+ },
+
+ /* Update the input field with the selected date. */
+ _selectDate: function(id, dateStr) {
+ var onSelect,
+ target = $(id),
+ inst = this._getInst(target[0]);
+
+ dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
+ if (inst.input) {
+ inst.input.val(dateStr);
+ }
+ this._updateAlternate(inst);
+
+ onSelect = this._get(inst, "onSelect");
+ if (onSelect) {
+ onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
+ } else if (inst.input) {
+ inst.input.trigger("change"); // fire the change event
+ }
+
+ if (inst.inline){
+ this._updateDatepicker(inst);
+ } else {
+ this._hideDatepicker();
+ this._lastInput = inst.input[0];
+ if (typeof(inst.input[0]) !== "object") {
+ inst.input.focus(); // restore focus
+ }
+ this._lastInput = null;
+ }
+ },
+
+ /* Update any alternate field to synchronise with the main field. */
+ _updateAlternate: function(inst) {
+ var altFormat, date, dateStr,
+ altField = this._get(inst, "altField");
+
+ if (altField) { // update alternate field too
+ altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
+ date = this._getDate(inst);
+ dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
+ $(altField).each(function() { $(this).val(dateStr); });
+ }
+ },
+
+ /* Set as beforeShowDay function to prevent selection of weekends.
+ * @param date Date - the date to customise
+ * @return [boolean, string] - is this date selectable?, what is its CSS class?
+ */
+ noWeekends: function(date) {
+ var day = date.getDay();
+ return [(day > 0 && day < 6), ""];
+ },
+
+ /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
+ * @param date Date - the date to get the week for
+ * @return number - the number of the week within the year that contains this date
+ */
+ iso8601Week: function(date) {
+ var time,
+ checkDate = new Date(date.getTime());
+
+ // Find Thursday of this week starting on Monday
+ checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
+
+ time = checkDate.getTime();
+ checkDate.setMonth(0); // Compare with Jan 1
+ checkDate.setDate(1);
+ return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
+ },
+
+ /* Parse a string value into a date object.
+ * See formatDate below for the possible formats.
+ *
+ * @param format string - the expected format of the date
+ * @param value string - the date in the above format
+ * @param settings Object - attributes include:
+ * shortYearCutoff number - the cutoff year for determining the century (optional)
+ * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
+ * dayNames string[7] - names of the days from Sunday (optional)
+ * monthNamesShort string[12] - abbreviated names of the months (optional)
+ * monthNames string[12] - names of the months (optional)
+ * @return Date - the extracted date value or null if value is blank
+ */
+ parseDate: function (format, value, settings) {
+ if (format == null || value == null) {
+ throw "Invalid arguments";
+ }
+
+ value = (typeof value === "object" ? value.toString() : value + "");
+ if (value === "") {
+ return null;
+ }
+
+ var iFormat, dim, extra,
+ iValue = 0,
+ shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
+ shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
+ new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
+ dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
+ dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
+ monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
+ monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
+ year = -1,
+ month = -1,
+ day = -1,
+ doy = -1,
+ literal = false,
+ date,
+ // Check whether a format character is doubled
+ lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+ if (matches) {
+ iFormat++;
+ }
+ return matches;
+ },
+ // Extract a number from the string value
+ getNumber = function(match) {
+ var isDoubled = lookAhead(match),
+ size = (match === "@" ? 14 : (match === "!" ? 20 :
+ (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
+ digits = new RegExp("^\\d{1," + size + "}"),
+ num = value.substring(iValue).match(digits);
+ if (!num) {
+ throw "Missing number at position " + iValue;
+ }
+ iValue += num[0].length;
+ return parseInt(num[0], 10);
+ },
+ // Extract a name from the string value and convert to an index
+ getName = function(match, shortNames, longNames) {
+ var index = -1,
+ names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
+ return [ [k, v] ];
+ }).sort(function (a, b) {
+ return -(a[1].length - b[1].length);
+ });
+
+ $.each(names, function (i, pair) {
+ var name = pair[1];
+ if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
+ index = pair[0];
+ iValue += name.length;
+ return false;
+ }
+ });
+ if (index !== -1) {
+ return index + 1;
+ } else {
+ throw "Unknown name at position " + iValue;
+ }
+ },
+ // Confirm that a literal character matches the string value
+ checkLiteral = function() {
+ if (value.charAt(iValue) !== format.charAt(iFormat)) {
+ throw "Unexpected literal at position " + iValue;
+ }
+ iValue++;
+ };
+
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
+ if (literal) {
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+ literal = false;
+ } else {
+ checkLiteral();
+ }
+ } else {
+ switch (format.charAt(iFormat)) {
+ case "d":
+ day = getNumber("d");
+ break;
+ case "D":
+ getName("D", dayNamesShort, dayNames);
+ break;
+ case "o":
+ doy = getNumber("o");
+ break;
+ case "m":
+ month = getNumber("m");
+ break;
+ case "M":
+ month = getName("M", monthNamesShort, monthNames);
+ break;
+ case "y":
+ year = getNumber("y");
+ break;
+ case "@":
+ date = new Date(getNumber("@"));
+ year = date.getFullYear();
+ month = date.getMonth() + 1;
+ day = date.getDate();
+ break;
+ case "!":
+ date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
+ year = date.getFullYear();
+ month = date.getMonth() + 1;
+ day = date.getDate();
+ break;
+ case "'":
+ if (lookAhead("'")){
+ checkLiteral();
+ } else {
+ literal = true;
+ }
+ break;
+ default:
+ checkLiteral();
+ }
+ }
+ }
+
+ if (iValue < value.length){
+ extra = value.substr(iValue);
+ if (!/^\s+/.test(extra)) {
+ throw "Extra/unparsed characters found in date: " + extra;
+ }
+ }
+
+ if (year === -1) {
+ year = new Date().getFullYear();
+ } else if (year < 100) {
+ year += new Date().getFullYear() - new Date().getFullYear() % 100 +
+ (year <= shortYearCutoff ? 0 : -100);
+ }
+
+ if (doy > -1) {
+ month = 1;
+ day = doy;
+ do {
+ dim = this._getDaysInMonth(year, month - 1);
+ if (day <= dim) {
+ break;
+ }
+ month++;
+ day -= dim;
+ } while (true);
+ }
+
+ date = this._daylightSavingAdjust(new Date(year, month - 1, day));
+ if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
+ throw "Invalid date"; // E.g. 31/02/00
+ }
+ return date;
+ },
+
+ /* Standard date formats. */
+ ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
+ COOKIE: "D, dd M yy",
+ ISO_8601: "yy-mm-dd",
+ RFC_822: "D, d M y",
+ RFC_850: "DD, dd-M-y",
+ RFC_1036: "D, d M y",
+ RFC_1123: "D, d M yy",
+ RFC_2822: "D, d M yy",
+ RSS: "D, d M y", // RFC 822
+ TICKS: "!",
+ TIMESTAMP: "@",
+ W3C: "yy-mm-dd", // ISO 8601
+
+ _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
+ Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
+
+ /* Format a date object into a string value.
+ * The format can be combinations of the following:
+ * d - day of month (no leading zero)
+ * dd - day of month (two digit)
+ * o - day of year (no leading zeros)
+ * oo - day of year (three digit)
+ * D - day name short
+ * DD - day name long
+ * m - month of year (no leading zero)
+ * mm - month of year (two digit)
+ * M - month name short
+ * MM - month name long
+ * y - year (two digit)
+ * yy - year (four digit)
+ * @ - Unix timestamp (ms since 01/01/1970)
+ * ! - Windows ticks (100ns since 01/01/0001)
+ * "..." - literal text
+ * '' - single quote
+ *
+ * @param format string - the desired format of the date
+ * @param date Date - the date value to format
+ * @param settings Object - attributes include:
+ * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
+ * dayNames string[7] - names of the days from Sunday (optional)
+ * monthNamesShort string[12] - abbreviated names of the months (optional)
+ * monthNames string[12] - names of the months (optional)
+ * @return string - the date in the above format
+ */
+ formatDate: function (format, date, settings) {
+ if (!date) {
+ return "";
+ }
+
+ var iFormat,
+ dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
+ dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
+ monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
+ monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
+ // Check whether a format character is doubled
+ lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+ if (matches) {
+ iFormat++;
+ }
+ return matches;
+ },
+ // Format a number, with leading zero if necessary
+ formatNumber = function(match, value, len) {
+ var num = "" + value;
+ if (lookAhead(match)) {
+ while (num.length < len) {
+ num = "0" + num;
+ }
+ }
+ return num;
+ },
+ // Format a name, short or long as requested
+ formatName = function(match, value, shortNames, longNames) {
+ return (lookAhead(match) ? longNames[value] : shortNames[value]);
+ },
+ output = "",
+ literal = false;
+
+ if (date) {
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
+ if (literal) {
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+ literal = false;
+ } else {
+ output += format.charAt(iFormat);
+ }
+ } else {
+ switch (format.charAt(iFormat)) {
+ case "d":
+ output += formatNumber("d", date.getDate(), 2);
+ break;
+ case "D":
+ output += formatName("D", date.getDay(), dayNamesShort, dayNames);
+ break;
+ case "o":
+ output += formatNumber("o",
+ Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
+ break;
+ case "m":
+ output += formatNumber("m", date.getMonth() + 1, 2);
+ break;
+ case "M":
+ output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
+ break;
+ case "y":
+ output += (lookAhead("y") ? date.getFullYear() :
+ (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
+ break;
+ case "@":
+ output += date.getTime();
+ break;
+ case "!":
+ output += date.getTime() * 10000 + this._ticksTo1970;
+ break;
+ case "'":
+ if (lookAhead("'")) {
+ output += "'";
+ } else {
+ literal = true;
+ }
+ break;
+ default:
+ output += format.charAt(iFormat);
+ }
+ }
+ }
+ }
+ return output;
+ },
+
+ /* Extract all possible characters from the date format. */
+ _possibleChars: function (format) {
+ var iFormat,
+ chars = "",
+ literal = false,
+ // Check whether a format character is doubled
+ lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+ if (matches) {
+ iFormat++;
+ }
+ return matches;
+ };
+
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
+ if (literal) {
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+ literal = false;
+ } else {
+ chars += format.charAt(iFormat);
+ }
+ } else {
+ switch (format.charAt(iFormat)) {
+ case "d": case "m": case "y": case "@":
+ chars += "0123456789";
+ break;
+ case "D": case "M":
+ return null; // Accept anything
+ case "'":
+ if (lookAhead("'")) {
+ chars += "'";
+ } else {
+ literal = true;
+ }
+ break;
+ default:
+ chars += format.charAt(iFormat);
+ }
+ }
+ }
+ return chars;
+ },
+
+ /* Get a setting value, defaulting if necessary. */
+ _get: function(inst, name) {
+ return inst.settings[name] !== undefined ?
+ inst.settings[name] : this._defaults[name];
+ },
+
+ /* Parse existing date and initialise date picker. */
+ _setDateFromField: function(inst, noDefault) {
+ if (inst.input.val() === inst.lastVal) {
+ return;
+ }
+
+ var dateFormat = this._get(inst, "dateFormat"),
+ dates = inst.lastVal = inst.input ? inst.input.val() : null,
+ defaultDate = this._getDefaultDate(inst),
+ date = defaultDate,
+ settings = this._getFormatConfig(inst);
+
+ try {
+ date = this.parseDate(dateFormat, dates, settings) || defaultDate;
+ } catch (event) {
+ dates = (noDefault ? "" : dates);
+ }
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ inst.currentDay = (dates ? date.getDate() : 0);
+ inst.currentMonth = (dates ? date.getMonth() : 0);
+ inst.currentYear = (dates ? date.getFullYear() : 0);
+ this._adjustInstDate(inst);
+ },
+
+ /* Retrieve the default date shown on opening. */
+ _getDefaultDate: function(inst) {
+ return this._restrictMinMax(inst,
+ this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
+ },
+
+ /* A date may be specified as an exact value or a relative one. */
+ _determineDate: function(inst, date, defaultDate) {
+ var offsetNumeric = function(offset) {
+ var date = new Date();
+ date.setDate(date.getDate() + offset);
+ return date;
+ },
+ offsetString = function(offset) {
+ try {
+ return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
+ offset, $.datepicker._getFormatConfig(inst));
+ }
+ catch (e) {
+ // Ignore
+ }
+
+ var date = (offset.toLowerCase().match(/^c/) ?
+ $.datepicker._getDate(inst) : null) || new Date(),
+ year = date.getFullYear(),
+ month = date.getMonth(),
+ day = date.getDate(),
+ pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
+ matches = pattern.exec(offset);
+
+ while (matches) {
+ switch (matches[2] || "d") {
+ case "d" : case "D" :
+ day += parseInt(matches[1],10); break;
+ case "w" : case "W" :
+ day += parseInt(matches[1],10) * 7; break;
+ case "m" : case "M" :
+ month += parseInt(matches[1],10);
+ day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
+ break;
+ case "y": case "Y" :
+ year += parseInt(matches[1],10);
+ day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
+ break;
+ }
+ matches = pattern.exec(offset);
+ }
+ return new Date(year, month, day);
+ },
+ newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
+ (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
+
+ newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
+ if (newDate) {
+ newDate.setHours(0);
+ newDate.setMinutes(0);
+ newDate.setSeconds(0);
+ newDate.setMilliseconds(0);
+ }
+ return this._daylightSavingAdjust(newDate);
+ },
+
+ /* Handle switch to/from daylight saving.
+ * Hours may be non-zero on daylight saving cut-over:
+ * > 12 when midnight changeover, but then cannot generate
+ * midnight datetime, so jump to 1AM, otherwise reset.
+ * @param date (Date) the date to check
+ * @return (Date) the corrected date
+ */
+ _daylightSavingAdjust: function(date) {
+ if (!date) {
+ return null;
+ }
+ date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
+ return date;
+ },
+
+ /* Set the date(s) directly. */
+ _setDate: function(inst, date, noChange) {
+ var clear = !date,
+ origMonth = inst.selectedMonth,
+ origYear = inst.selectedYear,
+ newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
+
+ inst.selectedDay = inst.currentDay = newDate.getDate();
+ inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
+ inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
+ if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
+ this._notifyChange(inst);
+ }
+ this._adjustInstDate(inst);
+ if (inst.input) {
+ inst.input.val(clear ? "" : this._formatDate(inst));
+ }
+ },
+
+ /* Retrieve the date(s) directly. */
+ _getDate: function(inst) {
+ var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
+ this._daylightSavingAdjust(new Date(
+ inst.currentYear, inst.currentMonth, inst.currentDay)));
+ return startDate;
+ },
+
+ /* Attach the onxxx handlers. These are declared statically so
+ * they work with static code transformers like Caja.
+ */
+ _attachHandlers: function(inst) {
+ var stepMonths = this._get(inst, "stepMonths"),
+ id = "#" + inst.id.replace( /\\\\/g, "\\" );
+ inst.dpDiv.find("[data-handler]").map(function () {
+ var handler = {
+ prev: function () {
+ $.datepicker._adjustDate(id, -stepMonths, "M");
+ },
+ next: function () {
+ $.datepicker._adjustDate(id, +stepMonths, "M");
+ },
+ hide: function () {
+ $.datepicker._hideDatepicker();
+ },
+ today: function () {
+ $.datepicker._gotoToday(id);
+ },
+ selectDay: function () {
+ $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
+ return false;
+ },
+ selectMonth: function () {
+ $.datepicker._selectMonthYear(id, this, "M");
+ return false;
+ },
+ selectYear: function () {
+ $.datepicker._selectMonthYear(id, this, "Y");
+ return false;
+ }
+ };
+ $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
+ });
+ },
+
+ /* Generate the HTML for the current state of the date picker. */
+ _generateHTML: function(inst) {
+ var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
+ controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
+ monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
+ selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
+ cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
+ printDate, dRow, tbody, daySettings, otherMonth, unselectable,
+ tempDate = new Date(),
+ today = this._daylightSavingAdjust(
+ new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
+ isRTL = this._get(inst, "isRTL"),
+ showButtonPanel = this._get(inst, "showButtonPanel"),
+ hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
+ navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
+ numMonths = this._getNumberOfMonths(inst),
+ showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
+ stepMonths = this._get(inst, "stepMonths"),
+ isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
+ currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
+ new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
+ minDate = this._getMinMaxDate(inst, "min"),
+ maxDate = this._getMinMaxDate(inst, "max"),
+ drawMonth = inst.drawMonth - showCurrentAtPos,
+ drawYear = inst.drawYear;
+
+ if (drawMonth < 0) {
+ drawMonth += 12;
+ drawYear--;
+ }
+ if (maxDate) {
+ maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
+ maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
+ maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
+ while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
+ drawMonth--;
+ if (drawMonth < 0) {
+ drawMonth = 11;
+ drawYear--;
+ }
+ }
+ }
+ inst.drawMonth = drawMonth;
+ inst.drawYear = drawYear;
+
+ prevText = this._get(inst, "prevText");
+ prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
+ this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
+ this._getFormatConfig(inst)));
+
+ prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
+ "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
+ " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
+ (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>"));
+
+ nextText = this._get(inst, "nextText");
+ nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
+ this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
+ this._getFormatConfig(inst)));
+
+ next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
+ "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
+ " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
+ (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>"));
+
+ currentText = this._get(inst, "currentText");
+ gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
+ currentText = (!navigationAsDateFormat ? currentText :
+ this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
+
+ controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
+ this._get(inst, "closeText") + "</button>" : "");
+
+ buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
+ (this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
+ ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
+
+ firstDay = parseInt(this._get(inst, "firstDay"),10);
+ firstDay = (isNaN(firstDay) ? 0 : firstDay);
+
+ showWeek = this._get(inst, "showWeek");
+ dayNames = this._get(inst, "dayNames");
+ dayNamesMin = this._get(inst, "dayNamesMin");
+ monthNames = this._get(inst, "monthNames");
+ monthNamesShort = this._get(inst, "monthNamesShort");
+ beforeShowDay = this._get(inst, "beforeShowDay");
+ showOtherMonths = this._get(inst, "showOtherMonths");
+ selectOtherMonths = this._get(inst, "selectOtherMonths");
+ defaultDate = this._getDefaultDate(inst);
+ html = "";
+ dow;
+ for (row = 0; row < numMonths[0]; row++) {
+ group = "";
+ this.maxRows = 4;
+ for (col = 0; col < numMonths[1]; col++) {
+ selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
+ cornerClass = " ui-corner-all";
+ calender = "";
+ if (isMultiMonth) {
+ calender += "<div class='ui-datepicker-group";
+ if (numMonths[1] > 1) {
+ switch (col) {
+ case 0: calender += " ui-datepicker-group-first";
+ cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
+ case numMonths[1]-1: calender += " ui-datepicker-group-last";
+ cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
+ default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
+ }
+ }
+ calender += "'>";
+ }
+ calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
+ (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
+ (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
+ this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
+ row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
+ "</div><table class='ui-datepicker-calendar'><thead>" +
+ "<tr>";
+ thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
+ for (dow = 0; dow < 7; dow++) { // days of the week
+ day = (dow + firstDay) % 7;
+ thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
+ "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
+ }
+ calender += thead + "</tr></thead><tbody>";
+ daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
+ if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
+ inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
+ }
+ leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
+ curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
+ numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
+ this.maxRows = numRows;
+ printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
+ for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
+ calender += "<tr>";
+ tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
+ this._get(inst, "calculateWeek")(printDate) + "</td>");
+ for (dow = 0; dow < 7; dow++) { // create date picker days
+ daySettings = (beforeShowDay ?
+ beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
+ otherMonth = (printDate.getMonth() !== drawMonth);
+ unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
+ (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
+ tbody += "<td class='" +
+ ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
+ (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
+ ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
+ (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
+ // or defaultDate is current printedDate and defaultDate is selectedDate
+ " " + this._dayOverClass : "") + // highlight selected day
+ (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
+ (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
+ (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
+ (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
+ ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
+ (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
+ (otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
+ (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
+ (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
+ (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
+ (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
+ "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
+ printDate.setDate(printDate.getDate() + 1);
+ printDate = this._daylightSavingAdjust(printDate);
+ }
+ calender += tbody + "</tr>";
+ }
+ drawMonth++;
+ if (drawMonth > 11) {
+ drawMonth = 0;
+ drawYear++;
+ }
+ calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
+ ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
+ group += calender;
+ }
+ html += group;
+ }
+ html += buttonPanel;
+ inst._keyEvent = false;
+ return html;
+ },
+
+ /* Generate the month and year header. */
+ _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
+ secondary, monthNames, monthNamesShort) {
+
+ var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
+ changeMonth = this._get(inst, "changeMonth"),
+ changeYear = this._get(inst, "changeYear"),
+ showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
+ html = "<div class='ui-datepicker-title'>",
+ monthHtml = "";
+
+ // month selection
+ if (secondary || !changeMonth) {
+ monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
+ } else {
+ inMinYear = (minDate && minDate.getFullYear() === drawYear);
+ inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
+ monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
+ for ( month = 0; month < 12; month++) {
+ if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
+ monthHtml += "<option value='" + month + "'" +
+ (month === drawMonth ? " selected='selected'" : "") +
+ ">" + monthNamesShort[month] + "</option>";
+ }
+ }
+ monthHtml += "</select>";
+ }
+
+ if (!showMonthAfterYear) {
+ html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
+ }
+
+ // year selection
+ if ( !inst.yearshtml ) {
+ inst.yearshtml = "";
+ if (secondary || !changeYear) {
+ html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
+ } else {
+ // determine range of years to display
+ years = this._get(inst, "yearRange").split(":");
+ thisYear = new Date().getFullYear();
+ determineYear = function(value) {
+ var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
+ (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
+ parseInt(value, 10)));
+ return (isNaN(year) ? thisYear : year);
+ };
+ year = determineYear(years[0]);
+ endYear = Math.max(year, determineYear(years[1] || ""));
+ year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
+ endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
+ inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
+ for (; year <= endYear; year++) {
+ inst.yearshtml += "<option value='" + year + "'" +
+ (year === drawYear ? " selected='selected'" : "") +
+ ">" + year + "</option>";
+ }
+ inst.yearshtml += "</select>";
+
+ html += inst.yearshtml;
+ inst.yearshtml = null;
+ }
+ }
+
+ html += this._get(inst, "yearSuffix");
+ if (showMonthAfterYear) {
+ html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
+ }
+ html += "</div>"; // Close datepicker_header
+ return html;
+ },
+
+ /* Adjust one of the date sub-fields. */
+ _adjustInstDate: function(inst, offset, period) {
+ var year = inst.drawYear + (period === "Y" ? offset : 0),
+ month = inst.drawMonth + (period === "M" ? offset : 0),
+ day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
+ date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
+
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ if (period === "M" || period === "Y") {
+ this._notifyChange(inst);
+ }
+ },
+
+ /* Ensure a date is within any min/max bounds. */
+ _restrictMinMax: function(inst, date) {
+ var minDate = this._getMinMaxDate(inst, "min"),
+ maxDate = this._getMinMaxDate(inst, "max"),
+ newDate = (minDate && date < minDate ? minDate : date);
+ return (maxDate && newDate > maxDate ? maxDate : newDate);
+ },
+
+ /* Notify change of month/year. */
+ _notifyChange: function(inst) {
+ var onChange = this._get(inst, "onChangeMonthYear");
+ if (onChange) {
+ onChange.apply((inst.input ? inst.input[0] : null),
+ [inst.selectedYear, inst.selectedMonth + 1, inst]);
+ }
+ },
+
+ /* Determine the number of months to show. */
+ _getNumberOfMonths: function(inst) {
+ var numMonths = this._get(inst, "numberOfMonths");
+ return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
+ },
+
+ /* Determine the current maximum date - ensure no time components are set. */
+ _getMinMaxDate: function(inst, minMax) {
+ return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
+ },
+
+ /* Find the number of days in a given month. */
+ _getDaysInMonth: function(year, month) {
+ return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
+ },
+
+ /* Find the day of the week of the first of a month. */
+ _getFirstDayOfMonth: function(year, month) {
+ return new Date(year, month, 1).getDay();
+ },
+
+ /* Determines if we should allow a "next/prev" month display change. */
+ _canAdjustMonth: function(inst, offset, curYear, curMonth) {
+ var numMonths = this._getNumberOfMonths(inst),
+ date = this._daylightSavingAdjust(new Date(curYear,
+ curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
+
+ if (offset < 0) {
+ date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
+ }
+ return this._isInRange(inst, date);
+ },
+
+ /* Is the given date in the accepted range? */
+ _isInRange: function(inst, date) {
+ var yearSplit, currentYear,
+ minDate = this._getMinMaxDate(inst, "min"),
+ maxDate = this._getMinMaxDate(inst, "max"),
+ minYear = null,
+ maxYear = null,
+ years = this._get(inst, "yearRange");
+ if (years){
+ yearSplit = years.split(":");
+ currentYear = new Date().getFullYear();
+ minYear = parseInt(yearSplit[0], 10);
+ maxYear = parseInt(yearSplit[1], 10);
+ if ( yearSplit[0].match(/[+\-].*/) ) {
+ minYear += currentYear;
+ }
+ if ( yearSplit[1].match(/[+\-].*/) ) {
+ maxYear += currentYear;
+ }
+ }
+
+ return ((!minDate || date.getTime() >= minDate.getTime()) &&
+ (!maxDate || date.getTime() <= maxDate.getTime()) &&
+ (!minYear || date.getFullYear() >= minYear) &&
+ (!maxYear || date.getFullYear() <= maxYear));
+ },
+
+ /* Provide the configuration settings for formatting/parsing. */
+ _getFormatConfig: function(inst) {
+ var shortYearCutoff = this._get(inst, "shortYearCutoff");
+ shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
+ new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
+ return {shortYearCutoff: shortYearCutoff,
+ dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
+ monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
+ },
+
+ /* Format the given date for display. */
+ _formatDate: function(inst, day, month, year) {
+ if (!day) {
+ inst.currentDay = inst.selectedDay;
+ inst.currentMonth = inst.selectedMonth;
+ inst.currentYear = inst.selectedYear;
+ }
+ var date = (day ? (typeof day === "object" ? day :
+ this._daylightSavingAdjust(new Date(year, month, day))) :
+ this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
+ return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
+ }
+});
+
+/*
+ * Bind hover events for datepicker elements.
+ * Done via delegate so the binding only occurs once in the lifetime of the parent div.
+ * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
+ */
+function bindHover(dpDiv) {
+ var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
+ return dpDiv.delegate(selector, "mouseout", function() {
+ $(this).removeClass("ui-state-hover");
+ if (this.className.indexOf("ui-datepicker-prev") !== -1) {
+ $(this).removeClass("ui-datepicker-prev-hover");
+ }
+ if (this.className.indexOf("ui-datepicker-next") !== -1) {
+ $(this).removeClass("ui-datepicker-next-hover");
+ }
+ })
+ .delegate(selector, "mouseover", function(){
+ if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
+ $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
+ $(this).addClass("ui-state-hover");
+ if (this.className.indexOf("ui-datepicker-prev") !== -1) {
+ $(this).addClass("ui-datepicker-prev-hover");
+ }
+ if (this.className.indexOf("ui-datepicker-next") !== -1) {
+ $(this).addClass("ui-datepicker-next-hover");
+ }
+ }
+ });
+}
+
+/* jQuery extend now ignores nulls! */
+function extendRemove(target, props) {
+ $.extend(target, props);
+ for (var name in props) {
+ if (props[name] == null) {
+ target[name] = props[name];
+ }
+ }
+ return target;
+}
+
+/* Invoke the datepicker functionality.
+ @param options string - a command, optionally followed by additional parameters or
+ Object - settings for attaching new datepicker functionality
+ @return jQuery object */
+$.fn.datepicker = function(options){
+
+ /* Verify an empty collection wasn't passed - Fixes #6976 */
+ if ( !this.length ) {
+ return this;
+ }
+
+ /* Initialise the date picker. */
+ if (!$.datepicker.initialized) {
+ $(document).mousedown($.datepicker._checkExternalClick);
+ $.datepicker.initialized = true;
+ }
+
+ /* Append datepicker main container to body if not exist. */
+ if ($("#"+$.datepicker._mainDivId).length === 0) {
+ $("body").append($.datepicker.dpDiv);
+ }
+
+ var otherArgs = Array.prototype.slice.call(arguments, 1);
+ if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
+ return $.datepicker["_" + options + "Datepicker"].
+ apply($.datepicker, [this[0]].concat(otherArgs));
+ }
+ if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
+ return $.datepicker["_" + options + "Datepicker"].
+ apply($.datepicker, [this[0]].concat(otherArgs));
+ }
+ return this.each(function() {
+ typeof options === "string" ?
+ $.datepicker["_" + options + "Datepicker"].
+ apply($.datepicker, [this].concat(otherArgs)) :
+ $.datepicker._attachDatepicker(this, options);
+ });
+};
+
+$.datepicker = new Datepicker(); // singleton instance
+$.datepicker.initialized = false;
+$.datepicker.uuid = new Date().getTime();
+$.datepicker.version = "1.10.4";
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+var sizeRelatedOptions = {
+ buttons: true,
+ height: true,
+ maxHeight: true,
+ maxWidth: true,
+ minHeight: true,
+ minWidth: true,
+ width: true
+ },
+ resizableRelatedOptions = {
+ maxHeight: true,
+ maxWidth: true,
+ minHeight: true,
+ minWidth: true
+ };
+
+$.widget( "ui.dialog", {
+ version: "1.10.4",
+ options: {
+ appendTo: "body",
+ autoOpen: true,
+ buttons: [],
+ closeOnEscape: true,
+ closeText: "close",
+ dialogClass: "",
+ draggable: true,
+ hide: null,
+ height: "auto",
+ maxHeight: null,
+ maxWidth: null,
+ minHeight: 150,
+ minWidth: 150,
+ modal: false,
+ position: {
+ my: "center",
+ at: "center",
+ of: window,
+ collision: "fit",
+ // Ensure the titlebar is always visible
+ using: function( pos ) {
+ var topOffset = $( this ).css( pos ).offset().top;
+ if ( topOffset < 0 ) {
+ $( this ).css( "top", pos.top - topOffset );
+ }
+ }
+ },
+ resizable: true,
+ show: null,
+ title: null,
+ width: 300,
+
+ // callbacks
+ beforeClose: null,
+ close: null,
+ drag: null,
+ dragStart: null,
+ dragStop: null,
+ focus: null,
+ open: null,
+ resize: null,
+ resizeStart: null,
+ resizeStop: null
+ },
+
+ _create: function() {
+ this.originalCss = {
+ display: this.element[0].style.display,
+ width: this.element[0].style.width,
+ minHeight: this.element[0].style.minHeight,
+ maxHeight: this.element[0].style.maxHeight,
+ height: this.element[0].style.height
+ };
+ this.originalPosition = {
+ parent: this.element.parent(),
+ index: this.element.parent().children().index( this.element )
+ };
+ this.originalTitle = this.element.attr("title");
+ this.options.title = this.options.title || this.originalTitle;
+
+ this._createWrapper();
+
+ this.element
+ .show()
+ .removeAttr("title")
+ .addClass("ui-dialog-content ui-widget-content")
+ .appendTo( this.uiDialog );
+
+ this._createTitlebar();
+ this._createButtonPane();
+
+ if ( this.options.draggable && $.fn.draggable ) {
+ this._makeDraggable();
+ }
+ if ( this.options.resizable && $.fn.resizable ) {
+ this._makeResizable();
+ }
+
+ this._isOpen = false;
+ },
+
+ _init: function() {
+ if ( this.options.autoOpen ) {
+ this.open();
+ }
+ },
+
+ _appendTo: function() {
+ var element = this.options.appendTo;
+ if ( element && (element.jquery || element.nodeType) ) {
+ return $( element );
+ }
+ return this.document.find( element || "body" ).eq( 0 );
+ },
+
+ _destroy: function() {
+ var next,
+ originalPosition = this.originalPosition;
+
+ this._destroyOverlay();
+
+ this.element
+ .removeUniqueId()
+ .removeClass("ui-dialog-content ui-widget-content")
+ .css( this.originalCss )
+ // Without detaching first, the following becomes really slow
+ .detach();
+
+ this.uiDialog.stop( true, true ).remove();
+
+ if ( this.originalTitle ) {
+ this.element.attr( "title", this.originalTitle );
+ }
+
+ next = originalPosition.parent.children().eq( originalPosition.index );
+ // Don't try to place the dialog next to itself (#8613)
+ if ( next.length && next[0] !== this.element[0] ) {
+ next.before( this.element );
+ } else {
+ originalPosition.parent.append( this.element );
+ }
+ },
+
+ widget: function() {
+ return this.uiDialog;
+ },
+
+ disable: $.noop,
+ enable: $.noop,
+
+ close: function( event ) {
+ var activeElement,
+ that = this;
+
+ if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
+ return;
+ }
+
+ this._isOpen = false;
+ this._destroyOverlay();
+
+ if ( !this.opener.filter(":focusable").focus().length ) {
+
+ // support: IE9
+ // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
+ try {
+ activeElement = this.document[ 0 ].activeElement;
+
+ // Support: IE9, IE10
+ // If the <body> is blurred, IE will switch windows, see #4520
+ if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) {
+
+ // Hiding a focused element doesn't trigger blur in WebKit
+ // so in case we have nothing to focus on, explicitly blur the active element
+ // https://bugs.webkit.org/show_bug.cgi?id=47182
+ $( activeElement ).blur();
+ }
+ } catch ( error ) {}
+ }
+
+ this._hide( this.uiDialog, this.options.hide, function() {
+ that._trigger( "close", event );
+ });
+ },
+
+ isOpen: function() {
+ return this._isOpen;
+ },
+
+ moveToTop: function() {
+ this._moveToTop();
+ },
+
+ _moveToTop: function( event, silent ) {
+ var moved = !!this.uiDialog.nextAll(":visible").insertBefore( this.uiDialog ).length;
+ if ( moved && !silent ) {
+ this._trigger( "focus", event );
+ }
+ return moved;
+ },
+
+ open: function() {
+ var that = this;
+ if ( this._isOpen ) {
+ if ( this._moveToTop() ) {
+ this._focusTabbable();
+ }
+ return;
+ }
+
+ this._isOpen = true;
+ this.opener = $( this.document[0].activeElement );
+
+ this._size();
+ this._position();
+ this._createOverlay();
+ this._moveToTop( null, true );
+ this._show( this.uiDialog, this.options.show, function() {
+ that._focusTabbable();
+ that._trigger("focus");
+ });
+
+ this._trigger("open");
+ },
+
+ _focusTabbable: function() {
+ // Set focus to the first match:
+ // 1. First element inside the dialog matching [autofocus]
+ // 2. Tabbable element inside the content element
+ // 3. Tabbable element inside the buttonpane
+ // 4. The close button
+ // 5. The dialog itself
+ var hasFocus = this.element.find("[autofocus]");
+ if ( !hasFocus.length ) {
+ hasFocus = this.element.find(":tabbable");
+ }
+ if ( !hasFocus.length ) {
+ hasFocus = this.uiDialogButtonPane.find(":tabbable");
+ }
+ if ( !hasFocus.length ) {
+ hasFocus = this.uiDialogTitlebarClose.filter(":tabbable");
+ }
+ if ( !hasFocus.length ) {
+ hasFocus = this.uiDialog;
+ }
+ hasFocus.eq( 0 ).focus();
+ },
+
+ _keepFocus: function( event ) {
+ function checkFocus() {
+ var activeElement = this.document[0].activeElement,
+ isActive = this.uiDialog[0] === activeElement ||
+ $.contains( this.uiDialog[0], activeElement );
+ if ( !isActive ) {
+ this._focusTabbable();
+ }
+ }
+ event.preventDefault();
+ checkFocus.call( this );
+ // support: IE
+ // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
+ // so we check again later
+ this._delay( checkFocus );
+ },
+
+ _createWrapper: function() {
+ this.uiDialog = $("<div>")
+ .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
+ this.options.dialogClass )
+ .hide()
+ .attr({
+ // Setting tabIndex makes the div focusable
+ tabIndex: -1,
+ role: "dialog"
+ })
+ .appendTo( this._appendTo() );
+
+ this._on( this.uiDialog, {
+ keydown: function( event ) {
+ if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
+ event.keyCode === $.ui.keyCode.ESCAPE ) {
+ event.preventDefault();
+ this.close( event );
+ return;
+ }
+
+ // prevent tabbing out of dialogs
+ if ( event.keyCode !== $.ui.keyCode.TAB ) {
+ return;
+ }
+ var tabbables = this.uiDialog.find(":tabbable"),
+ first = tabbables.filter(":first"),
+ last = tabbables.filter(":last");
+
+ if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
+ first.focus( 1 );
+ event.preventDefault();
+ } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
+ last.focus( 1 );
+ event.preventDefault();
+ }
+ },
+ mousedown: function( event ) {
+ if ( this._moveToTop( event ) ) {
+ this._focusTabbable();
+ }
+ }
+ });
+
+ // We assume that any existing aria-describedby attribute means
+ // that the dialog content is marked up properly
+ // otherwise we brute force the content as the description
+ if ( !this.element.find("[aria-describedby]").length ) {
+ this.uiDialog.attr({
+ "aria-describedby": this.element.uniqueId().attr("id")
+ });
+ }
+ },
+
+ _createTitlebar: function() {
+ var uiDialogTitle;
+
+ this.uiDialogTitlebar = $("<div>")
+ .addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix")
+ .prependTo( this.uiDialog );
+ this._on( this.uiDialogTitlebar, {
+ mousedown: function( event ) {
+ // Don't prevent click on close button (#8838)
+ // Focusing a dialog that is partially scrolled out of view
+ // causes the browser to scroll it into view, preventing the click event
+ if ( !$( event.target ).closest(".ui-dialog-titlebar-close") ) {
+ // Dialog isn't getting focus when dragging (#8063)
+ this.uiDialog.focus();
+ }
+ }
+ });
+
+ // support: IE
+ // Use type="button" to prevent enter keypresses in textboxes from closing the
+ // dialog in IE (#9312)
+ this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
+ .button({
+ label: this.options.closeText,
+ icons: {
+ primary: "ui-icon-closethick"
+ },
+ text: false
+ })
+ .addClass("ui-dialog-titlebar-close")
+ .appendTo( this.uiDialogTitlebar );
+ this._on( this.uiDialogTitlebarClose, {
+ click: function( event ) {
+ event.preventDefault();
+ this.close( event );
+ }
+ });
+
+ uiDialogTitle = $("<span>")
+ .uniqueId()
+ .addClass("ui-dialog-title")
+ .prependTo( this.uiDialogTitlebar );
+ this._title( uiDialogTitle );
+
+ this.uiDialog.attr({
+ "aria-labelledby": uiDialogTitle.attr("id")
+ });
+ },
+
+ _title: function( title ) {
+ if ( !this.options.title ) {
+ title.html("&#160;");
+ }
+ title.text( this.options.title );
+ },
+
+ _createButtonPane: function() {
+ this.uiDialogButtonPane = $("<div>")
+ .addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");
+
+ this.uiButtonSet = $("<div>")
+ .addClass("ui-dialog-buttonset")
+ .appendTo( this.uiDialogButtonPane );
+
+ this._createButtons();
+ },
+
+ _createButtons: function() {
+ var that = this,
+ buttons = this.options.buttons;
+
+ // if we already have a button pane, remove it
+ this.uiDialogButtonPane.remove();
+ this.uiButtonSet.empty();
+
+ if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
+ this.uiDialog.removeClass("ui-dialog-buttons");
+ return;
+ }
+
+ $.each( buttons, function( name, props ) {
+ var click, buttonOptions;
+ props = $.isFunction( props ) ?
+ { click: props, text: name } :
+ props;
+ // Default to a non-submitting button
+ props = $.extend( { type: "button" }, props );
+ // Change the context for the click callback to be the main element
+ click = props.click;
+ props.click = function() {
+ click.apply( that.element[0], arguments );
+ };
+ buttonOptions = {
+ icons: props.icons,
+ text: props.showText
+ };
+ delete props.icons;
+ delete props.showText;
+ $( "<button></button>", props )
+ .button( buttonOptions )
+ .appendTo( that.uiButtonSet );
+ });
+ this.uiDialog.addClass("ui-dialog-buttons");
+ this.uiDialogButtonPane.appendTo( this.uiDialog );
+ },
+
+ _makeDraggable: function() {
+ var that = this,
+ options = this.options;
+
+ function filteredUi( ui ) {
+ return {
+ position: ui.position,
+ offset: ui.offset
+ };
+ }
+
+ this.uiDialog.draggable({
+ cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
+ handle: ".ui-dialog-titlebar",
+ containment: "document",
+ start: function( event, ui ) {
+ $( this ).addClass("ui-dialog-dragging");
+ that._blockFrames();
+ that._trigger( "dragStart", event, filteredUi( ui ) );
+ },
+ drag: function( event, ui ) {
+ that._trigger( "drag", event, filteredUi( ui ) );
+ },
+ stop: function( event, ui ) {
+ options.position = [
+ ui.position.left - that.document.scrollLeft(),
+ ui.position.top - that.document.scrollTop()
+ ];
+ $( this ).removeClass("ui-dialog-dragging");
+ that._unblockFrames();
+ that._trigger( "dragStop", event, filteredUi( ui ) );
+ }
+ });
+ },
+
+ _makeResizable: function() {
+ var that = this,
+ options = this.options,
+ handles = options.resizable,
+ // .ui-resizable has position: relative defined in the stylesheet
+ // but dialogs have to use absolute or fixed positioning
+ position = this.uiDialog.css("position"),
+ resizeHandles = typeof handles === "string" ?
+ handles :
+ "n,e,s,w,se,sw,ne,nw";
+
+ function filteredUi( ui ) {
+ return {
+ originalPosition: ui.originalPosition,
+ originalSize: ui.originalSize,
+ position: ui.position,
+ size: ui.size
+ };
+ }
+
+ this.uiDialog.resizable({
+ cancel: ".ui-dialog-content",
+ containment: "document",
+ alsoResize: this.element,
+ maxWidth: options.maxWidth,
+ maxHeight: options.maxHeight,
+ minWidth: options.minWidth,
+ minHeight: this._minHeight(),
+ handles: resizeHandles,
+ start: function( event, ui ) {
+ $( this ).addClass("ui-dialog-resizing");
+ that._blockFrames();
+ that._trigger( "resizeStart", event, filteredUi( ui ) );
+ },
+ resize: function( event, ui ) {
+ that._trigger( "resize", event, filteredUi( ui ) );
+ },
+ stop: function( event, ui ) {
+ options.height = $( this ).height();
+ options.width = $( this ).width();
+ $( this ).removeClass("ui-dialog-resizing");
+ that._unblockFrames();
+ that._trigger( "resizeStop", event, filteredUi( ui ) );
+ }
+ })
+ .css( "position", position );
+ },
+
+ _minHeight: function() {
+ var options = this.options;
+
+ return options.height === "auto" ?
+ options.minHeight :
+ Math.min( options.minHeight, options.height );
+ },
+
+ _position: function() {
+ // Need to show the dialog to get the actual offset in the position plugin
+ var isVisible = this.uiDialog.is(":visible");
+ if ( !isVisible ) {
+ this.uiDialog.show();
+ }
+ this.uiDialog.position( this.options.position );
+ if ( !isVisible ) {
+ this.uiDialog.hide();
+ }
+ },
+
+ _setOptions: function( options ) {
+ var that = this,
+ resize = false,
+ resizableOptions = {};
+
+ $.each( options, function( key, value ) {
+ that._setOption( key, value );
+
+ if ( key in sizeRelatedOptions ) {
+ resize = true;
+ }
+ if ( key in resizableRelatedOptions ) {
+ resizableOptions[ key ] = value;
+ }
+ });
+
+ if ( resize ) {
+ this._size();
+ this._position();
+ }
+ if ( this.uiDialog.is(":data(ui-resizable)") ) {
+ this.uiDialog.resizable( "option", resizableOptions );
+ }
+ },
+
+ _setOption: function( key, value ) {
+ var isDraggable, isResizable,
+ uiDialog = this.uiDialog;
+
+ if ( key === "dialogClass" ) {
+ uiDialog
+ .removeClass( this.options.dialogClass )
+ .addClass( value );
+ }
+
+ if ( key === "disabled" ) {
+ return;
+ }
+
+ this._super( key, value );
+
+ if ( key === "appendTo" ) {
+ this.uiDialog.appendTo( this._appendTo() );
+ }
+
+ if ( key === "buttons" ) {
+ this._createButtons();
+ }
+
+ if ( key === "closeText" ) {
+ this.uiDialogTitlebarClose.button({
+ // Ensure that we always pass a string
+ label: "" + value
+ });
+ }
+
+ if ( key === "draggable" ) {
+ isDraggable = uiDialog.is(":data(ui-draggable)");
+ if ( isDraggable && !value ) {
+ uiDialog.draggable("destroy");
+ }
+
+ if ( !isDraggable && value ) {
+ this._makeDraggable();
+ }
+ }
+
+ if ( key === "position" ) {
+ this._position();
+ }
+
+ if ( key === "resizable" ) {
+ // currently resizable, becoming non-resizable
+ isResizable = uiDialog.is(":data(ui-resizable)");
+ if ( isResizable && !value ) {
+ uiDialog.resizable("destroy");
+ }
+
+ // currently resizable, changing handles
+ if ( isResizable && typeof value === "string" ) {
+ uiDialog.resizable( "option", "handles", value );
+ }
+
+ // currently non-resizable, becoming resizable
+ if ( !isResizable && value !== false ) {
+ this._makeResizable();
+ }
+ }
+
+ if ( key === "title" ) {
+ this._title( this.uiDialogTitlebar.find(".ui-dialog-title") );
+ }
+ },
+
+ _size: function() {
+ // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
+ // divs will both have width and height set, so we need to reset them
+ var nonContentHeight, minContentHeight, maxContentHeight,
+ options = this.options;
+
+ // Reset content sizing
+ this.element.show().css({
+ width: "auto",
+ minHeight: 0,
+ maxHeight: "none",
+ height: 0
+ });
+
+ if ( options.minWidth > options.width ) {
+ options.width = options.minWidth;
+ }
+
+ // reset wrapper sizing
+ // determine the height of all the non-content elements
+ nonContentHeight = this.uiDialog.css({
+ height: "auto",
+ width: options.width
+ })
+ .outerHeight();
+ minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
+ maxContentHeight = typeof options.maxHeight === "number" ?
+ Math.max( 0, options.maxHeight - nonContentHeight ) :
+ "none";
+
+ if ( options.height === "auto" ) {
+ this.element.css({
+ minHeight: minContentHeight,
+ maxHeight: maxContentHeight,
+ height: "auto"
+ });
+ } else {
+ this.element.height( Math.max( 0, options.height - nonContentHeight ) );
+ }
+
+ if (this.uiDialog.is(":data(ui-resizable)") ) {
+ this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
+ }
+ },
+
+ _blockFrames: function() {
+ this.iframeBlocks = this.document.find( "iframe" ).map(function() {
+ var iframe = $( this );
+
+ return $( "<div>" )
+ .css({
+ position: "absolute",
+ width: iframe.outerWidth(),
+ height: iframe.outerHeight()
+ })
+ .appendTo( iframe.parent() )
+ .offset( iframe.offset() )[0];
+ });
+ },
+
+ _unblockFrames: function() {
+ if ( this.iframeBlocks ) {
+ this.iframeBlocks.remove();
+ delete this.iframeBlocks;
+ }
+ },
+
+ _allowInteraction: function( event ) {
+ if ( $( event.target ).closest(".ui-dialog").length ) {
+ return true;
+ }
+
+ // TODO: Remove hack when datepicker implements
+ // the .ui-front logic (#8989)
+ return !!$( event.target ).closest(".ui-datepicker").length;
+ },
+
+ _createOverlay: function() {
+ if ( !this.options.modal ) {
+ return;
+ }
+
+ var that = this,
+ widgetFullName = this.widgetFullName;
+ if ( !$.ui.dialog.overlayInstances ) {
+ // Prevent use of anchors and inputs.
+ // We use a delay in case the overlay is created from an
+ // event that we're going to be cancelling. (#2804)
+ this._delay(function() {
+ // Handle .dialog().dialog("close") (#4065)
+ if ( $.ui.dialog.overlayInstances ) {
+ this.document.bind( "focusin.dialog", function( event ) {
+ if ( !that._allowInteraction( event ) ) {
+ event.preventDefault();
+ $(".ui-dialog:visible:last .ui-dialog-content")
+ .data( widgetFullName )._focusTabbable();
+ }
+ });
+ }
+ });
+ }
+
+ this.overlay = $("<div>")
+ .addClass("ui-widget-overlay ui-front")
+ .appendTo( this._appendTo() );
+ this._on( this.overlay, {
+ mousedown: "_keepFocus"
+ });
+ $.ui.dialog.overlayInstances++;
+ },
+
+ _destroyOverlay: function() {
+ if ( !this.options.modal ) {
+ return;
+ }
+
+ if ( this.overlay ) {
+ $.ui.dialog.overlayInstances--;
+
+ if ( !$.ui.dialog.overlayInstances ) {
+ this.document.unbind( "focusin.dialog" );
+ }
+ this.overlay.remove();
+ this.overlay = null;
+ }
+ }
+});
+
+$.ui.dialog.overlayInstances = 0;
+
+// DEPRECATED
+if ( $.uiBackCompat !== false ) {
+ // position option with array notation
+ // just override with old implementation
+ $.widget( "ui.dialog", $.ui.dialog, {
+ _position: function() {
+ var position = this.options.position,
+ myAt = [],
+ offset = [ 0, 0 ],
+ isVisible;
+
+ if ( position ) {
+ if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) {
+ myAt = position.split ? position.split(" ") : [ position[0], position[1] ];
+ if ( myAt.length === 1 ) {
+ myAt[1] = myAt[0];
+ }
+
+ $.each( [ "left", "top" ], function( i, offsetPosition ) {
+ if ( +myAt[ i ] === myAt[ i ] ) {
+ offset[ i ] = myAt[ i ];
+ myAt[ i ] = offsetPosition;
+ }
+ });
+
+ position = {
+ my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " +
+ myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]),
+ at: myAt.join(" ")
+ };
+ }
+
+ position = $.extend( {}, $.ui.dialog.prototype.options.position, position );
+ } else {
+ position = $.ui.dialog.prototype.options.position;
+ }
+
+ // need to show the dialog to get the actual offset in the position plugin
+ isVisible = this.uiDialog.is(":visible");
+ if ( !isVisible ) {
+ this.uiDialog.show();
+ }
+ this.uiDialog.position( position );
+ if ( !isVisible ) {
+ this.uiDialog.hide();
+ }
+ }
+ });
+}
+
+}( jQuery ) );
+
+(function( $, undefined ) {
+
+var rvertical = /up|down|vertical/,
+ rpositivemotion = /up|left|vertical|horizontal/;
+
+$.effects.effect.blind = function( o, done ) {
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ direction = o.direction || "up",
+ vertical = rvertical.test( direction ),
+ ref = vertical ? "height" : "width",
+ ref2 = vertical ? "top" : "left",
+ motion = rpositivemotion.test( direction ),
+ animation = {},
+ show = mode === "show",
+ wrapper, distance, margin;
+
+ // if already wrapped, the wrapper's properties are my property. #6245
+ if ( el.parent().is( ".ui-effects-wrapper" ) ) {
+ $.effects.save( el.parent(), props );
+ } else {
+ $.effects.save( el, props );
+ }
+ el.show();
+ wrapper = $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+
+ distance = wrapper[ ref ]();
+ margin = parseFloat( wrapper.css( ref2 ) ) || 0;
+
+ animation[ ref ] = show ? distance : 0;
+ if ( !motion ) {
+ el
+ .css( vertical ? "bottom" : "right", 0 )
+ .css( vertical ? "top" : "left", "auto" )
+ .css({ position: "absolute" });
+
+ animation[ ref2 ] = show ? margin : distance + margin;
+ }
+
+ // start at 0 if we are showing
+ if ( show ) {
+ wrapper.css( ref, 0 );
+ if ( ! motion ) {
+ wrapper.css( ref2, margin + distance );
+ }
+ }
+
+ // Animate
+ wrapper.animate( animation, {
+ duration: o.duration,
+ easing: o.easing,
+ queue: false,
+ complete: function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.bounce = function( o, done ) {
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+
+ // defaults:
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ hide = mode === "hide",
+ show = mode === "show",
+ direction = o.direction || "up",
+ distance = o.distance,
+ times = o.times || 5,
+
+ // number of internal animations
+ anims = times * 2 + ( show || hide ? 1 : 0 ),
+ speed = o.duration / anims,
+ easing = o.easing,
+
+ // utility:
+ ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
+ motion = ( direction === "up" || direction === "left" ),
+ i,
+ upAnim,
+ downAnim,
+
+ // we will need to re-assemble the queue to stack our animations in place
+ queue = el.queue(),
+ queuelen = queue.length;
+
+ // Avoid touching opacity to prevent clearType and PNG issues in IE
+ if ( show || hide ) {
+ props.push( "opacity" );
+ }
+
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el ); // Create Wrapper
+
+ // default distance for the BIGGEST bounce is the outer Distance / 3
+ if ( !distance ) {
+ distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
+ }
+
+ if ( show ) {
+ downAnim = { opacity: 1 };
+ downAnim[ ref ] = 0;
+
+ // if we are showing, force opacity 0 and set the initial position
+ // then do the "first" animation
+ el.css( "opacity", 0 )
+ .css( ref, motion ? -distance * 2 : distance * 2 )
+ .animate( downAnim, speed, easing );
+ }
+
+ // start at the smallest distance if we are hiding
+ if ( hide ) {
+ distance = distance / Math.pow( 2, times - 1 );
+ }
+
+ downAnim = {};
+ downAnim[ ref ] = 0;
+ // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
+ for ( i = 0; i < times; i++ ) {
+ upAnim = {};
+ upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
+
+ el.animate( upAnim, speed, easing )
+ .animate( downAnim, speed, easing );
+
+ distance = hide ? distance * 2 : distance / 2;
+ }
+
+ // Last Bounce when Hiding
+ if ( hide ) {
+ upAnim = { opacity: 0 };
+ upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
+
+ el.animate( upAnim, speed, easing );
+ }
+
+ el.queue(function() {
+ if ( hide ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ });
+
+ // inject all the animations we just queued to be first in line (after "inprogress")
+ if ( queuelen > 1) {
+ queue.splice.apply( queue,
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+ }
+ el.dequeue();
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.clip = function( o, done ) {
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+ direction = o.direction || "vertical",
+ vert = direction === "vertical",
+ size = vert ? "height" : "width",
+ position = vert ? "top" : "left",
+ animation = {},
+ wrapper, animate, distance;
+
+ // Save & Show
+ $.effects.save( el, props );
+ el.show();
+
+ // Create Wrapper
+ wrapper = $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+ animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
+ distance = animate[ size ]();
+
+ // Shift
+ if ( show ) {
+ animate.css( size, 0 );
+ animate.css( position, distance / 2 );
+ }
+
+ // Create Animation Object:
+ animation[ size ] = show ? distance : 0;
+ animation[ position ] = show ? 0 : distance / 2;
+
+ // Animate
+ animate.animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( !show ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.drop = function( o, done ) {
+
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+ direction = o.direction || "left",
+ ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
+ motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
+ animation = {
+ opacity: show ? 1 : 0
+ },
+ distance;
+
+ // Adjust
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el );
+
+ distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2;
+
+ if ( show ) {
+ el
+ .css( "opacity", 0 )
+ .css( ref, motion === "pos" ? -distance : distance );
+ }
+
+ // Animation
+ animation[ ref ] = ( show ?
+ ( motion === "pos" ? "+=" : "-=" ) :
+ ( motion === "pos" ? "-=" : "+=" ) ) +
+ distance;
+
+ // Animate
+ el.animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.explode = function( o, done ) {
+
+ var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
+ cells = rows,
+ el = $( this ),
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+
+ // show and then visibility:hidden the element before calculating offset
+ offset = el.show().css( "visibility", "hidden" ).offset(),
+
+ // width and height of a piece
+ width = Math.ceil( el.outerWidth() / cells ),
+ height = Math.ceil( el.outerHeight() / rows ),
+ pieces = [],
+
+ // loop
+ i, j, left, top, mx, my;
+
+ // children animate complete:
+ function childComplete() {
+ pieces.push( this );
+ if ( pieces.length === rows * cells ) {
+ animComplete();
+ }
+ }
+
+ // clone the element for each row and cell.
+ for( i = 0; i < rows ; i++ ) { // ===>
+ top = offset.top + i * height;
+ my = i - ( rows - 1 ) / 2 ;
+
+ for( j = 0; j < cells ; j++ ) { // |||
+ left = offset.left + j * width;
+ mx = j - ( cells - 1 ) / 2 ;
+
+ // Create a clone of the now hidden main element that will be absolute positioned
+ // within a wrapper div off the -left and -top equal to size of our pieces
+ el
+ .clone()
+ .appendTo( "body" )
+ .wrap( "<div></div>" )
+ .css({
+ position: "absolute",
+ visibility: "visible",
+ left: -j * width,
+ top: -i * height
+ })
+
+ // select the wrapper - make it overflow: hidden and absolute positioned based on
+ // where the original was located +left and +top equal to the size of pieces
+ .parent()
+ .addClass( "ui-effects-explode" )
+ .css({
+ position: "absolute",
+ overflow: "hidden",
+ width: width,
+ height: height,
+ left: left + ( show ? mx * width : 0 ),
+ top: top + ( show ? my * height : 0 ),
+ opacity: show ? 0 : 1
+ }).animate({
+ left: left + ( show ? 0 : mx * width ),
+ top: top + ( show ? 0 : my * height ),
+ opacity: show ? 1 : 0
+ }, o.duration || 500, o.easing, childComplete );
+ }
+ }
+
+ function animComplete() {
+ el.css({
+ visibility: "visible"
+ });
+ $( pieces ).remove();
+ if ( !show ) {
+ el.hide();
+ }
+ done();
+ }
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.fade = function( o, done ) {
+ var el = $( this ),
+ mode = $.effects.setMode( el, o.mode || "toggle" );
+
+ el.animate({
+ opacity: mode
+ }, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: done
+ });
+};
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.effects.effect.fold = function( o, done ) {
+
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+ hide = mode === "hide",
+ size = o.size || 15,
+ percent = /([0-9]+)%/.exec( size ),
+ horizFirst = !!o.horizFirst,
+ widthFirst = show !== horizFirst,
+ ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
+ duration = o.duration / 2,
+ wrapper, distance,
+ animation1 = {},
+ animation2 = {};
+
+ $.effects.save( el, props );
+ el.show();
+
+ // Create Wrapper
+ wrapper = $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+ distance = widthFirst ?
+ [ wrapper.width(), wrapper.height() ] :
+ [ wrapper.height(), wrapper.width() ];
+
+ if ( percent ) {
+ size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
+ }
+ if ( show ) {
+ wrapper.css( horizFirst ? {
+ height: 0,
+ width: size
+ } : {
+ height: size,
+ width: 0
+ });
+ }
+
+ // Animation
+ animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
+ animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
+
+ // Animate
+ wrapper
+ .animate( animation1, duration, o.easing )
+ .animate( animation2, duration, o.easing, function() {
+ if ( hide ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ });
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.highlight = function( o, done ) {
+ var elem = $( this ),
+ props = [ "backgroundImage", "backgroundColor", "opacity" ],
+ mode = $.effects.setMode( elem, o.mode || "show" ),
+ animation = {
+ backgroundColor: elem.css( "backgroundColor" )
+ };
+
+ if (mode === "hide") {
+ animation.opacity = 0;
+ }
+
+ $.effects.save( elem, props );
+
+ elem
+ .show()
+ .css({
+ backgroundImage: "none",
+ backgroundColor: o.color || "#ffff99"
+ })
+ .animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( mode === "hide" ) {
+ elem.hide();
+ }
+ $.effects.restore( elem, props );
+ done();
+ }
+ });
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.pulsate = function( o, done ) {
+ var elem = $( this ),
+ mode = $.effects.setMode( elem, o.mode || "show" ),
+ show = mode === "show",
+ hide = mode === "hide",
+ showhide = ( show || mode === "hide" ),
+
+ // showing or hiding leaves of the "last" animation
+ anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
+ duration = o.duration / anims,
+ animateTo = 0,
+ queue = elem.queue(),
+ queuelen = queue.length,
+ i;
+
+ if ( show || !elem.is(":visible")) {
+ elem.css( "opacity", 0 ).show();
+ animateTo = 1;
+ }
+
+ // anims - 1 opacity "toggles"
+ for ( i = 1; i < anims; i++ ) {
+ elem.animate({
+ opacity: animateTo
+ }, duration, o.easing );
+ animateTo = 1 - animateTo;
+ }
+
+ elem.animate({
+ opacity: animateTo
+ }, duration, o.easing);
+
+ elem.queue(function() {
+ if ( hide ) {
+ elem.hide();
+ }
+ done();
+ });
+
+ // We just queued up "anims" animations, we need to put them next in the queue
+ if ( queuelen > 1 ) {
+ queue.splice.apply( queue,
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+ }
+ elem.dequeue();
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.puff = function( o, done ) {
+ var elem = $( this ),
+ mode = $.effects.setMode( elem, o.mode || "hide" ),
+ hide = mode === "hide",
+ percent = parseInt( o.percent, 10 ) || 150,
+ factor = percent / 100,
+ original = {
+ height: elem.height(),
+ width: elem.width(),
+ outerHeight: elem.outerHeight(),
+ outerWidth: elem.outerWidth()
+ };
+
+ $.extend( o, {
+ effect: "scale",
+ queue: false,
+ fade: true,
+ mode: mode,
+ complete: done,
+ percent: hide ? percent : 100,
+ from: hide ?
+ original :
+ {
+ height: original.height * factor,
+ width: original.width * factor,
+ outerHeight: original.outerHeight * factor,
+ outerWidth: original.outerWidth * factor
+ }
+ });
+
+ elem.effect( o );
+};
+
+$.effects.effect.scale = function( o, done ) {
+
+ // Create element
+ var el = $( this ),
+ options = $.extend( true, {}, o ),
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ percent = parseInt( o.percent, 10 ) ||
+ ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
+ direction = o.direction || "both",
+ origin = o.origin,
+ original = {
+ height: el.height(),
+ width: el.width(),
+ outerHeight: el.outerHeight(),
+ outerWidth: el.outerWidth()
+ },
+ factor = {
+ y: direction !== "horizontal" ? (percent / 100) : 1,
+ x: direction !== "vertical" ? (percent / 100) : 1
+ };
+
+ // We are going to pass this effect to the size effect:
+ options.effect = "size";
+ options.queue = false;
+ options.complete = done;
+
+ // Set default origin and restore for show/hide
+ if ( mode !== "effect" ) {
+ options.origin = origin || ["middle","center"];
+ options.restore = true;
+ }
+
+ options.from = o.from || ( mode === "show" ? {
+ height: 0,
+ width: 0,
+ outerHeight: 0,
+ outerWidth: 0
+ } : original );
+ options.to = {
+ height: original.height * factor.y,
+ width: original.width * factor.x,
+ outerHeight: original.outerHeight * factor.y,
+ outerWidth: original.outerWidth * factor.x
+ };
+
+ // Fade option to support puff
+ if ( options.fade ) {
+ if ( mode === "show" ) {
+ options.from.opacity = 0;
+ options.to.opacity = 1;
+ }
+ if ( mode === "hide" ) {
+ options.from.opacity = 1;
+ options.to.opacity = 0;
+ }
+ }
+
+ // Animate
+ el.effect( options );
+
+};
+
+$.effects.effect.size = function( o, done ) {
+
+ // Create element
+ var original, baseline, factor,
+ el = $( this ),
+ props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
+
+ // Always restore
+ props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
+
+ // Copy for children
+ props2 = [ "width", "height", "overflow" ],
+ cProps = [ "fontSize" ],
+ vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
+ hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
+
+ // Set options
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ restore = o.restore || mode !== "effect",
+ scale = o.scale || "both",
+ origin = o.origin || [ "middle", "center" ],
+ position = el.css( "position" ),
+ props = restore ? props0 : props1,
+ zero = {
+ height: 0,
+ width: 0,
+ outerHeight: 0,
+ outerWidth: 0
+ };
+
+ if ( mode === "show" ) {
+ el.show();
+ }
+ original = {
+ height: el.height(),
+ width: el.width(),
+ outerHeight: el.outerHeight(),
+ outerWidth: el.outerWidth()
+ };
+
+ if ( o.mode === "toggle" && mode === "show" ) {
+ el.from = o.to || zero;
+ el.to = o.from || original;
+ } else {
+ el.from = o.from || ( mode === "show" ? zero : original );
+ el.to = o.to || ( mode === "hide" ? zero : original );
+ }
+
+ // Set scaling factor
+ factor = {
+ from: {
+ y: el.from.height / original.height,
+ x: el.from.width / original.width
+ },
+ to: {
+ y: el.to.height / original.height,
+ x: el.to.width / original.width
+ }
+ };
+
+ // Scale the css box
+ if ( scale === "box" || scale === "both" ) {
+
+ // Vertical props scaling
+ if ( factor.from.y !== factor.to.y ) {
+ props = props.concat( vProps );
+ el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
+ el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
+ }
+
+ // Horizontal props scaling
+ if ( factor.from.x !== factor.to.x ) {
+ props = props.concat( hProps );
+ el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
+ el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
+ }
+ }
+
+ // Scale the content
+ if ( scale === "content" || scale === "both" ) {
+
+ // Vertical props scaling
+ if ( factor.from.y !== factor.to.y ) {
+ props = props.concat( cProps ).concat( props2 );
+ el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
+ el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
+ }
+ }
+
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el );
+ el.css( "overflow", "hidden" ).css( el.from );
+
+ // Adjust
+ if (origin) { // Calculate baseline shifts
+ baseline = $.effects.getBaseline( origin, original );
+ el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
+ el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
+ el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
+ el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
+ }
+ el.css( el.from ); // set top & left
+
+ // Animate
+ if ( scale === "content" || scale === "both" ) { // Scale the children
+
+ // Add margins/font-size
+ vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
+ hProps = hProps.concat([ "marginLeft", "marginRight" ]);
+ props2 = props0.concat(vProps).concat(hProps);
+
+ el.find( "*[width]" ).each( function(){
+ var child = $( this ),
+ c_original = {
+ height: child.height(),
+ width: child.width(),
+ outerHeight: child.outerHeight(),
+ outerWidth: child.outerWidth()
+ };
+ if (restore) {
+ $.effects.save(child, props2);
+ }
+
+ child.from = {
+ height: c_original.height * factor.from.y,
+ width: c_original.width * factor.from.x,
+ outerHeight: c_original.outerHeight * factor.from.y,
+ outerWidth: c_original.outerWidth * factor.from.x
+ };
+ child.to = {
+ height: c_original.height * factor.to.y,
+ width: c_original.width * factor.to.x,
+ outerHeight: c_original.height * factor.to.y,
+ outerWidth: c_original.width * factor.to.x
+ };
+
+ // Vertical props scaling
+ if ( factor.from.y !== factor.to.y ) {
+ child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
+ child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
+ }
+
+ // Horizontal props scaling
+ if ( factor.from.x !== factor.to.x ) {
+ child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
+ child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
+ }
+
+ // Animate children
+ child.css( child.from );
+ child.animate( child.to, o.duration, o.easing, function() {
+
+ // Restore children
+ if ( restore ) {
+ $.effects.restore( child, props2 );
+ }
+ });
+ });
+ }
+
+ // Animate
+ el.animate( el.to, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( el.to.opacity === 0 ) {
+ el.css( "opacity", el.from.opacity );
+ }
+ if( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ if ( !restore ) {
+
+ // we need to calculate our new positioning based on the scaling
+ if ( position === "static" ) {
+ el.css({
+ position: "relative",
+ top: el.to.top,
+ left: el.to.left
+ });
+ } else {
+ $.each([ "top", "left" ], function( idx, pos ) {
+ el.css( pos, function( _, str ) {
+ var val = parseInt( str, 10 ),
+ toRef = idx ? el.to.left : el.to.top;
+
+ // if original was "auto", recalculate the new value from wrapper
+ if ( str === "auto" ) {
+ return toRef + "px";
+ }
+
+ return val + toRef + "px";
+ });
+ });
+ }
+ }
+
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.shake = function( o, done ) {
+
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ direction = o.direction || "left",
+ distance = o.distance || 20,
+ times = o.times || 3,
+ anims = times * 2 + 1,
+ speed = Math.round(o.duration/anims),
+ ref = (direction === "up" || direction === "down") ? "top" : "left",
+ positiveMotion = (direction === "up" || direction === "left"),
+ animation = {},
+ animation1 = {},
+ animation2 = {},
+ i,
+
+ // we will need to re-assemble the queue to stack our animations in place
+ queue = el.queue(),
+ queuelen = queue.length;
+
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el );
+
+ // Animation
+ animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
+ animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
+ animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
+
+ // Animate
+ el.animate( animation, speed, o.easing );
+
+ // Shakes
+ for ( i = 1; i < times; i++ ) {
+ el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
+ }
+ el
+ .animate( animation1, speed, o.easing )
+ .animate( animation, speed / 2, o.easing )
+ .queue(function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ });
+
+ // inject all the animations we just queued to be first in line (after "inprogress")
+ if ( queuelen > 1) {
+ queue.splice.apply( queue,
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+ }
+ el.dequeue();
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.slide = function( o, done ) {
+
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
+ mode = $.effects.setMode( el, o.mode || "show" ),
+ show = mode === "show",
+ direction = o.direction || "left",
+ ref = (direction === "up" || direction === "down") ? "top" : "left",
+ positiveMotion = (direction === "up" || direction === "left"),
+ distance,
+ animation = {};
+
+ // Adjust
+ $.effects.save( el, props );
+ el.show();
+ distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
+
+ $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+
+ if ( show ) {
+ el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
+ }
+
+ // Animation
+ animation[ ref ] = ( show ?
+ ( positiveMotion ? "+=" : "-=") :
+ ( positiveMotion ? "-=" : "+=")) +
+ distance;
+
+ // Animate
+ el.animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.transfer = function( o, done ) {
+ var elem = $( this ),
+ target = $( o.to ),
+ targetFixed = target.css( "position" ) === "fixed",
+ body = $("body"),
+ fixTop = targetFixed ? body.scrollTop() : 0,
+ fixLeft = targetFixed ? body.scrollLeft() : 0,
+ endPosition = target.offset(),
+ animation = {
+ top: endPosition.top - fixTop ,
+ left: endPosition.left - fixLeft ,
+ height: target.innerHeight(),
+ width: target.innerWidth()
+ },
+ startPosition = elem.offset(),
+ transfer = $( "<div class='ui-effects-transfer'></div>" )
+ .appendTo( document.body )
+ .addClass( o.className )
+ .css({
+ top: startPosition.top - fixTop ,
+ left: startPosition.left - fixLeft ,
+ height: elem.innerHeight(),
+ width: elem.innerWidth(),
+ position: targetFixed ? "fixed" : "absolute"
+ })
+ .animate( animation, o.duration, o.easing, function() {
+ transfer.remove();
+ done();
+ });
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.widget( "ui.menu", {
+ version: "1.10.4",
+ defaultElement: "<ul>",
+ delay: 300,
+ options: {
+ icons: {
+ submenu: "ui-icon-carat-1-e"
+ },
+ menus: "ul",
+ position: {
+ my: "left top",
+ at: "right top"
+ },
+ role: "menu",
+
+ // callbacks
+ blur: null,
+ focus: null,
+ select: null
+ },
+
+ _create: function() {
+ this.activeMenu = this.element;
+ // flag used to prevent firing of the click handler
+ // as the event bubbles up through nested menus
+ this.mouseHandled = false;
+ this.element
+ .uniqueId()
+ .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
+ .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
+ .attr({
+ role: this.options.role,
+ tabIndex: 0
+ })
+ // need to catch all clicks on disabled menu
+ // not possible through _on
+ .bind( "click" + this.eventNamespace, $.proxy(function( event ) {
+ if ( this.options.disabled ) {
+ event.preventDefault();
+ }
+ }, this ));
+
+ if ( this.options.disabled ) {
+ this.element
+ .addClass( "ui-state-disabled" )
+ .attr( "aria-disabled", "true" );
+ }
+
+ this._on({
+ // Prevent focus from sticking to links inside menu after clicking
+ // them (focus should always stay on UL during navigation).
+ "mousedown .ui-menu-item > a": function( event ) {
+ event.preventDefault();
+ },
+ "click .ui-state-disabled > a": function( event ) {
+ event.preventDefault();
+ },
+ "click .ui-menu-item:has(a)": function( event ) {
+ var target = $( event.target ).closest( ".ui-menu-item" );
+ if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
+ this.select( event );
+
+ // Only set the mouseHandled flag if the event will bubble, see #9469.
+ if ( !event.isPropagationStopped() ) {
+ this.mouseHandled = true;
+ }
+
+ // Open submenu on click
+ if ( target.has( ".ui-menu" ).length ) {
+ this.expand( event );
+ } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {
+
+ // Redirect focus to the menu
+ this.element.trigger( "focus", [ true ] );
+
+ // If the active item is on the top level, let it stay active.
+ // Otherwise, blur the active item since it is no longer visible.
+ if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
+ clearTimeout( this.timer );
+ }
+ }
+ }
+ },
+ "mouseenter .ui-menu-item": function( event ) {
+ var target = $( event.currentTarget );
+ // Remove ui-state-active class from siblings of the newly focused menu item
+ // to avoid a jump caused by adjacent elements both having a class with a border
+ target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
+ this.focus( event, target );
+ },
+ mouseleave: "collapseAll",
+ "mouseleave .ui-menu": "collapseAll",
+ focus: function( event, keepActiveItem ) {
+ // If there's already an active item, keep it active
+ // If not, activate the first item
+ var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
+
+ if ( !keepActiveItem ) {
+ this.focus( event, item );
+ }
+ },
+ blur: function( event ) {
+ this._delay(function() {
+ if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
+ this.collapseAll( event );
+ }
+ });
+ },
+ keydown: "_keydown"
+ });
+
+ this.refresh();
+
+ // Clicks outside of a menu collapse any open menus
+ this._on( this.document, {
+ click: function( event ) {
+ if ( !$( event.target ).closest( ".ui-menu" ).length ) {
+ this.collapseAll( event );
+ }
+
+ // Reset the mouseHandled flag
+ this.mouseHandled = false;
+ }
+ });
+ },
+
+ _destroy: function() {
+ // Destroy (sub)menus
+ this.element
+ .removeAttr( "aria-activedescendant" )
+ .find( ".ui-menu" ).addBack()
+ .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
+ .removeAttr( "role" )
+ .removeAttr( "tabIndex" )
+ .removeAttr( "aria-labelledby" )
+ .removeAttr( "aria-expanded" )
+ .removeAttr( "aria-hidden" )
+ .removeAttr( "aria-disabled" )
+ .removeUniqueId()
+ .show();
+
+ // Destroy menu items
+ this.element.find( ".ui-menu-item" )
+ .removeClass( "ui-menu-item" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-disabled" )
+ .children( "a" )
+ .removeUniqueId()
+ .removeClass( "ui-corner-all ui-state-hover" )
+ .removeAttr( "tabIndex" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-haspopup" )
+ .children().each( function() {
+ var elem = $( this );
+ if ( elem.data( "ui-menu-submenu-carat" ) ) {
+ elem.remove();
+ }
+ });
+
+ // Destroy menu dividers
+ this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
+ },
+
+ _keydown: function( event ) {
+ var match, prev, character, skip, regex,
+ preventDefault = true;
+
+ function escape( value ) {
+ return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.PAGE_UP:
+ this.previousPage( event );
+ break;
+ case $.ui.keyCode.PAGE_DOWN:
+ this.nextPage( event );
+ break;
+ case $.ui.keyCode.HOME:
+ this._move( "first", "first", event );
+ break;
+ case $.ui.keyCode.END:
+ this._move( "last", "last", event );
+ break;
+ case $.ui.keyCode.UP:
+ this.previous( event );
+ break;
+ case $.ui.keyCode.DOWN:
+ this.next( event );
+ break;
+ case $.ui.keyCode.LEFT:
+ this.collapse( event );
+ break;
+ case $.ui.keyCode.RIGHT:
+ if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
+ this.expand( event );
+ }
+ break;
+ case $.ui.keyCode.ENTER:
+ case $.ui.keyCode.SPACE:
+ this._activate( event );
+ break;
+ case $.ui.keyCode.ESCAPE:
+ this.collapse( event );
+ break;
+ default:
+ preventDefault = false;
+ prev = this.previousFilter || "";
+ character = String.fromCharCode( event.keyCode );
+ skip = false;
+
+ clearTimeout( this.filterTimer );
+
+ if ( character === prev ) {
+ skip = true;
+ } else {
+ character = prev + character;
+ }
+
+ regex = new RegExp( "^" + escape( character ), "i" );
+ match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
+ return regex.test( $( this ).children( "a" ).text() );
+ });
+ match = skip && match.index( this.active.next() ) !== -1 ?
+ this.active.nextAll( ".ui-menu-item" ) :
+ match;
+
+ // If no matches on the current filter, reset to the last character pressed
+ // to move down the menu to the first item that starts with that character
+ if ( !match.length ) {
+ character = String.fromCharCode( event.keyCode );
+ regex = new RegExp( "^" + escape( character ), "i" );
+ match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
+ return regex.test( $( this ).children( "a" ).text() );
+ });
+ }
+
+ if ( match.length ) {
+ this.focus( event, match );
+ if ( match.length > 1 ) {
+ this.previousFilter = character;
+ this.filterTimer = this._delay(function() {
+ delete this.previousFilter;
+ }, 1000 );
+ } else {
+ delete this.previousFilter;
+ }
+ } else {
+ delete this.previousFilter;
+ }
+ }
+
+ if ( preventDefault ) {
+ event.preventDefault();
+ }
+ },
+
+ _activate: function( event ) {
+ if ( !this.active.is( ".ui-state-disabled" ) ) {
+ if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
+ this.expand( event );
+ } else {
+ this.select( event );
+ }
+ }
+ },
+
+ refresh: function() {
+ var menus,
+ icon = this.options.icons.submenu,
+ submenus = this.element.find( this.options.menus );
+
+ this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
+
+ // Initialize nested menus
+ submenus.filter( ":not(.ui-menu)" )
+ .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
+ .hide()
+ .attr({
+ role: this.options.role,
+ "aria-hidden": "true",
+ "aria-expanded": "false"
+ })
+ .each(function() {
+ var menu = $( this ),
+ item = menu.prev( "a" ),
+ submenuCarat = $( "<span>" )
+ .addClass( "ui-menu-icon ui-icon " + icon )
+ .data( "ui-menu-submenu-carat", true );
+
+ item
+ .attr( "aria-haspopup", "true" )
+ .prepend( submenuCarat );
+ menu.attr( "aria-labelledby", item.attr( "id" ) );
+ });
+
+ menus = submenus.add( this.element );
+
+ // Don't refresh list items that are already adapted
+ menus.children( ":not(.ui-menu-item):has(a)" )
+ .addClass( "ui-menu-item" )
+ .attr( "role", "presentation" )
+ .children( "a" )
+ .uniqueId()
+ .addClass( "ui-corner-all" )
+ .attr({
+ tabIndex: -1,
+ role: this._itemRole()
+ });
+
+ // Initialize unlinked menu-items containing spaces and/or dashes only as dividers
+ menus.children( ":not(.ui-menu-item)" ).each(function() {
+ var item = $( this );
+ // hyphen, em dash, en dash
+ if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) {
+ item.addClass( "ui-widget-content ui-menu-divider" );
+ }
+ });
+
+ // Add aria-disabled attribute to any disabled menu item
+ menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
+
+ // If the active item has been removed, blur the menu
+ if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
+ this.blur();
+ }
+ },
+
+ _itemRole: function() {
+ return {
+ menu: "menuitem",
+ listbox: "option"
+ }[ this.options.role ];
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "icons" ) {
+ this.element.find( ".ui-menu-icon" )
+ .removeClass( this.options.icons.submenu )
+ .addClass( value.submenu );
+ }
+ this._super( key, value );
+ },
+
+ focus: function( event, item ) {
+ var nested, focused;
+ this.blur( event, event && event.type === "focus" );
+
+ this._scrollIntoView( item );
+
+ this.active = item.first();
+ focused = this.active.children( "a" ).addClass( "ui-state-focus" );
+ // Only update aria-activedescendant if there's a role
+ // otherwise we assume focus is managed elsewhere
+ if ( this.options.role ) {
+ this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
+ }
+
+ // Highlight active parent menu item, if any
+ this.active
+ .parent()
+ .closest( ".ui-menu-item" )
+ .children( "a:first" )
+ .addClass( "ui-state-active" );
+
+ if ( event && event.type === "keydown" ) {
+ this._close();
+ } else {
+ this.timer = this._delay(function() {
+ this._close();
+ }, this.delay );
+ }
+
+ nested = item.children( ".ui-menu" );
+ if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
+ this._startOpening(nested);
+ }
+ this.activeMenu = item.parent();
+
+ this._trigger( "focus", event, { item: item } );
+ },
+
+ _scrollIntoView: function( item ) {
+ var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
+ if ( this._hasScroll() ) {
+ borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
+ paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
+ offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
+ scroll = this.activeMenu.scrollTop();
+ elementHeight = this.activeMenu.height();
+ itemHeight = item.height();
+
+ if ( offset < 0 ) {
+ this.activeMenu.scrollTop( scroll + offset );
+ } else if ( offset + itemHeight > elementHeight ) {
+ this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
+ }
+ }
+ },
+
+ blur: function( event, fromFocus ) {
+ if ( !fromFocus ) {
+ clearTimeout( this.timer );
+ }
+
+ if ( !this.active ) {
+ return;
+ }
+
+ this.active.children( "a" ).removeClass( "ui-state-focus" );
+ this.active = null;
+
+ this._trigger( "blur", event, { item: this.active } );
+ },
+
+ _startOpening: function( submenu ) {
+ clearTimeout( this.timer );
+
+ // Don't open if already open fixes a Firefox bug that caused a .5 pixel
+ // shift in the submenu position when mousing over the carat icon
+ if ( submenu.attr( "aria-hidden" ) !== "true" ) {
+ return;
+ }
+
+ this.timer = this._delay(function() {
+ this._close();
+ this._open( submenu );
+ }, this.delay );
+ },
+
+ _open: function( submenu ) {
+ var position = $.extend({
+ of: this.active
+ }, this.options.position );
+
+ clearTimeout( this.timer );
+ this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
+ .hide()
+ .attr( "aria-hidden", "true" );
+
+ submenu
+ .show()
+ .removeAttr( "aria-hidden" )
+ .attr( "aria-expanded", "true" )
+ .position( position );
+ },
+
+ collapseAll: function( event, all ) {
+ clearTimeout( this.timer );
+ this.timer = this._delay(function() {
+ // If we were passed an event, look for the submenu that contains the event
+ var currentMenu = all ? this.element :
+ $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
+
+ // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
+ if ( !currentMenu.length ) {
+ currentMenu = this.element;
+ }
+
+ this._close( currentMenu );
+
+ this.blur( event );
+ this.activeMenu = currentMenu;
+ }, this.delay );
+ },
+
+ // With no arguments, closes the currently active menu - if nothing is active
+ // it closes all menus. If passed an argument, it will search for menus BELOW
+ _close: function( startMenu ) {
+ if ( !startMenu ) {
+ startMenu = this.active ? this.active.parent() : this.element;
+ }
+
+ startMenu
+ .find( ".ui-menu" )
+ .hide()
+ .attr( "aria-hidden", "true" )
+ .attr( "aria-expanded", "false" )
+ .end()
+ .find( "a.ui-state-active" )
+ .removeClass( "ui-state-active" );
+ },
+
+ collapse: function( event ) {
+ var newItem = this.active &&
+ this.active.parent().closest( ".ui-menu-item", this.element );
+ if ( newItem && newItem.length ) {
+ this._close();
+ this.focus( event, newItem );
+ }
+ },
+
+ expand: function( event ) {
+ var newItem = this.active &&
+ this.active
+ .children( ".ui-menu " )
+ .children( ".ui-menu-item" )
+ .first();
+
+ if ( newItem && newItem.length ) {
+ this._open( newItem.parent() );
+
+ // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
+ this._delay(function() {
+ this.focus( event, newItem );
+ });
+ }
+ },
+
+ next: function( event ) {
+ this._move( "next", "first", event );
+ },
+
+ previous: function( event ) {
+ this._move( "prev", "last", event );
+ },
+
+ isFirstItem: function() {
+ return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
+ },
+
+ isLastItem: function() {
+ return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
+ },
+
+ _move: function( direction, filter, event ) {
+ var next;
+ if ( this.active ) {
+ if ( direction === "first" || direction === "last" ) {
+ next = this.active
+ [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
+ .eq( -1 );
+ } else {
+ next = this.active
+ [ direction + "All" ]( ".ui-menu-item" )
+ .eq( 0 );
+ }
+ }
+ if ( !next || !next.length || !this.active ) {
+ next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
+ }
+
+ this.focus( event, next );
+ },
+
+ nextPage: function( event ) {
+ var item, base, height;
+
+ if ( !this.active ) {
+ this.next( event );
+ return;
+ }
+ if ( this.isLastItem() ) {
+ return;
+ }
+ if ( this._hasScroll() ) {
+ base = this.active.offset().top;
+ height = this.element.height();
+ this.active.nextAll( ".ui-menu-item" ).each(function() {
+ item = $( this );
+ return item.offset().top - base - height < 0;
+ });
+
+ this.focus( event, item );
+ } else {
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" )
+ [ !this.active ? "first" : "last" ]() );
+ }
+ },
+
+ previousPage: function( event ) {
+ var item, base, height;
+ if ( !this.active ) {
+ this.next( event );
+ return;
+ }
+ if ( this.isFirstItem() ) {
+ return;
+ }
+ if ( this._hasScroll() ) {
+ base = this.active.offset().top;
+ height = this.element.height();
+ this.active.prevAll( ".ui-menu-item" ).each(function() {
+ item = $( this );
+ return item.offset().top - base + height > 0;
+ });
+
+ this.focus( event, item );
+ } else {
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
+ }
+ },
+
+ _hasScroll: function() {
+ return this.element.outerHeight() < this.element.prop( "scrollHeight" );
+ },
+
+ select: function( event ) {
+ // TODO: It should never be possible to not have an active item at this
+ // point, but the tests don't trigger mouseenter before click.
+ this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
+ var ui = { item: this.active };
+ if ( !this.active.has( ".ui-menu" ).length ) {
+ this.collapseAll( event, true );
+ }
+ this._trigger( "select", event, ui );
+ }
+});
+
+}( jQuery ));
+
+(function( $, undefined ) {
+
+$.ui = $.ui || {};
+
+var cachedScrollbarWidth,
+ max = Math.max,
+ abs = Math.abs,
+ round = Math.round,
+ rhorizontal = /left|center|right/,
+ rvertical = /top|center|bottom/,
+ roffset = /[\+\-]\d+(\.[\d]+)?%?/,
+ rposition = /^\w+/,
+ rpercent = /%$/,
+ _position = $.fn.position;
+
+function getOffsets( offsets, width, height ) {
+ return [
+ parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
+ parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
+ ];
+}
+
+function parseCss( element, property ) {
+ return parseInt( $.css( element, property ), 10 ) || 0;
+}
+
+function getDimensions( elem ) {
+ var raw = elem[0];
+ if ( raw.nodeType === 9 ) {
+ return {
+ width: elem.width(),
+ height: elem.height(),
+ offset: { top: 0, left: 0 }
+ };
+ }
+ if ( $.isWindow( raw ) ) {
+ return {
+ width: elem.width(),
+ height: elem.height(),
+ offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
+ };
+ }
+ if ( raw.preventDefault ) {
+ return {
+ width: 0,
+ height: 0,
+ offset: { top: raw.pageY, left: raw.pageX }
+ };
+ }
+ return {
+ width: elem.outerWidth(),
+ height: elem.outerHeight(),
+ offset: elem.offset()
+ };
+}
+
+$.position = {
+ scrollbarWidth: function() {
+ if ( cachedScrollbarWidth !== undefined ) {
+ return cachedScrollbarWidth;
+ }
+ var w1, w2,
+ div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
+ innerDiv = div.children()[0];
+
+ $( "body" ).append( div );
+ w1 = innerDiv.offsetWidth;
+ div.css( "overflow", "scroll" );
+
+ w2 = innerDiv.offsetWidth;
+
+ if ( w1 === w2 ) {
+ w2 = div[0].clientWidth;
+ }
+
+ div.remove();
+
+ return (cachedScrollbarWidth = w1 - w2);
+ },
+ getScrollInfo: function( within ) {
+ var overflowX = within.isWindow || within.isDocument ? "" :
+ within.element.css( "overflow-x" ),
+ overflowY = within.isWindow || within.isDocument ? "" :
+ within.element.css( "overflow-y" ),
+ hasOverflowX = overflowX === "scroll" ||
+ ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
+ hasOverflowY = overflowY === "scroll" ||
+ ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
+ return {
+ width: hasOverflowY ? $.position.scrollbarWidth() : 0,
+ height: hasOverflowX ? $.position.scrollbarWidth() : 0
+ };
+ },
+ getWithinInfo: function( element ) {
+ var withinElement = $( element || window ),
+ isWindow = $.isWindow( withinElement[0] ),
+ isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;
+ return {
+ element: withinElement,
+ isWindow: isWindow,
+ isDocument: isDocument,
+ offset: withinElement.offset() || { left: 0, top: 0 },
+ scrollLeft: withinElement.scrollLeft(),
+ scrollTop: withinElement.scrollTop(),
+ width: isWindow ? withinElement.width() : withinElement.outerWidth(),
+ height: isWindow ? withinElement.height() : withinElement.outerHeight()
+ };
+ }
+};
+
+$.fn.position = function( options ) {
+ if ( !options || !options.of ) {
+ return _position.apply( this, arguments );
+ }
+
+ // make a copy, we don't want to modify arguments
+ options = $.extend( {}, options );
+
+ var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
+ target = $( options.of ),
+ within = $.position.getWithinInfo( options.within ),
+ scrollInfo = $.position.getScrollInfo( within ),
+ collision = ( options.collision || "flip" ).split( " " ),
+ offsets = {};
+
+ dimensions = getDimensions( target );
+ if ( target[0].preventDefault ) {
+ // force left top to allow flipping
+ options.at = "left top";
+ }
+ targetWidth = dimensions.width;
+ targetHeight = dimensions.height;
+ targetOffset = dimensions.offset;
+ // clone to reuse original targetOffset later
+ basePosition = $.extend( {}, targetOffset );
+
+ // force my and at to have valid horizontal and vertical positions
+ // if a value is missing or invalid, it will be converted to center
+ $.each( [ "my", "at" ], function() {
+ var pos = ( options[ this ] || "" ).split( " " ),
+ horizontalOffset,
+ verticalOffset;
+
+ if ( pos.length === 1) {
+ pos = rhorizontal.test( pos[ 0 ] ) ?
+ pos.concat( [ "center" ] ) :
+ rvertical.test( pos[ 0 ] ) ?
+ [ "center" ].concat( pos ) :
+ [ "center", "center" ];
+ }
+ pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
+ pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
+
+ // calculate offsets
+ horizontalOffset = roffset.exec( pos[ 0 ] );
+ verticalOffset = roffset.exec( pos[ 1 ] );
+ offsets[ this ] = [
+ horizontalOffset ? horizontalOffset[ 0 ] : 0,
+ verticalOffset ? verticalOffset[ 0 ] : 0
+ ];
+
+ // reduce to just the positions without the offsets
+ options[ this ] = [
+ rposition.exec( pos[ 0 ] )[ 0 ],
+ rposition.exec( pos[ 1 ] )[ 0 ]
+ ];
+ });
+
+ // normalize collision option
+ if ( collision.length === 1 ) {
+ collision[ 1 ] = collision[ 0 ];
+ }
+
+ if ( options.at[ 0 ] === "right" ) {
+ basePosition.left += targetWidth;
+ } else if ( options.at[ 0 ] === "center" ) {
+ basePosition.left += targetWidth / 2;
+ }
+
+ if ( options.at[ 1 ] === "bottom" ) {
+ basePosition.top += targetHeight;
+ } else if ( options.at[ 1 ] === "center" ) {
+ basePosition.top += targetHeight / 2;
+ }
+
+ atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
+ basePosition.left += atOffset[ 0 ];
+ basePosition.top += atOffset[ 1 ];
+
+ return this.each(function() {
+ var collisionPosition, using,
+ elem = $( this ),
+ elemWidth = elem.outerWidth(),
+ elemHeight = elem.outerHeight(),
+ marginLeft = parseCss( this, "marginLeft" ),
+ marginTop = parseCss( this, "marginTop" ),
+ collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
+ collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
+ position = $.extend( {}, basePosition ),
+ myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
+
+ if ( options.my[ 0 ] === "right" ) {
+ position.left -= elemWidth;
+ } else if ( options.my[ 0 ] === "center" ) {
+ position.left -= elemWidth / 2;
+ }
+
+ if ( options.my[ 1 ] === "bottom" ) {
+ position.top -= elemHeight;
+ } else if ( options.my[ 1 ] === "center" ) {
+ position.top -= elemHeight / 2;
+ }
+
+ position.left += myOffset[ 0 ];
+ position.top += myOffset[ 1 ];
+
+ // if the browser doesn't support fractions, then round for consistent results
+ if ( !$.support.offsetFractions ) {
+ position.left = round( position.left );
+ position.top = round( position.top );
+ }
+
+ collisionPosition = {
+ marginLeft: marginLeft,
+ marginTop: marginTop
+ };
+
+ $.each( [ "left", "top" ], function( i, dir ) {
+ if ( $.ui.position[ collision[ i ] ] ) {
+ $.ui.position[ collision[ i ] ][ dir ]( position, {
+ targetWidth: targetWidth,
+ targetHeight: targetHeight,
+ elemWidth: elemWidth,
+ elemHeight: elemHeight,
+ collisionPosition: collisionPosition,
+ collisionWidth: collisionWidth,
+ collisionHeight: collisionHeight,
+ offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
+ my: options.my,
+ at: options.at,
+ within: within,
+ elem : elem
+ });
+ }
+ });
+
+ if ( options.using ) {
+ // adds feedback as second argument to using callback, if present
+ using = function( props ) {
+ var left = targetOffset.left - position.left,
+ right = left + targetWidth - elemWidth,
+ top = targetOffset.top - position.top,
+ bottom = top + targetHeight - elemHeight,
+ feedback = {
+ target: {
+ element: target,
+ left: targetOffset.left,
+ top: targetOffset.top,
+ width: targetWidth,
+ height: targetHeight
+ },
+ element: {
+ element: elem,
+ left: position.left,
+ top: position.top,
+ width: elemWidth,
+ height: elemHeight
+ },
+ horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
+ vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
+ };
+ if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
+ feedback.horizontal = "center";
+ }
+ if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
+ feedback.vertical = "middle";
+ }
+ if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
+ feedback.important = "horizontal";
+ } else {
+ feedback.important = "vertical";
+ }
+ options.using.call( this, props, feedback );
+ };
+ }
+
+ elem.offset( $.extend( position, { using: using } ) );
+ });
+};
+
+$.ui.position = {
+ fit: {
+ left: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
+ outerWidth = within.width,
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+ overLeft = withinOffset - collisionPosLeft,
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
+ newOverRight;
+
+ // element is wider than within
+ if ( data.collisionWidth > outerWidth ) {
+ // element is initially over the left side of within
+ if ( overLeft > 0 && overRight <= 0 ) {
+ newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
+ position.left += overLeft - newOverRight;
+ // element is initially over right side of within
+ } else if ( overRight > 0 && overLeft <= 0 ) {
+ position.left = withinOffset;
+ // element is initially over both left and right sides of within
+ } else {
+ if ( overLeft > overRight ) {
+ position.left = withinOffset + outerWidth - data.collisionWidth;
+ } else {
+ position.left = withinOffset;
+ }
+ }
+ // too far left -> align with left edge
+ } else if ( overLeft > 0 ) {
+ position.left += overLeft;
+ // too far right -> align with right edge
+ } else if ( overRight > 0 ) {
+ position.left -= overRight;
+ // adjust based on position and margin
+ } else {
+ position.left = max( position.left - collisionPosLeft, position.left );
+ }
+ },
+ top: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
+ outerHeight = data.within.height,
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
+ overTop = withinOffset - collisionPosTop,
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
+ newOverBottom;
+
+ // element is taller than within
+ if ( data.collisionHeight > outerHeight ) {
+ // element is initially over the top of within
+ if ( overTop > 0 && overBottom <= 0 ) {
+ newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
+ position.top += overTop - newOverBottom;
+ // element is initially over bottom of within
+ } else if ( overBottom > 0 && overTop <= 0 ) {
+ position.top = withinOffset;
+ // element is initially over both top and bottom of within
+ } else {
+ if ( overTop > overBottom ) {
+ position.top = withinOffset + outerHeight - data.collisionHeight;
+ } else {
+ position.top = withinOffset;
+ }
+ }
+ // too far up -> align with top
+ } else if ( overTop > 0 ) {
+ position.top += overTop;
+ // too far down -> align with bottom edge
+ } else if ( overBottom > 0 ) {
+ position.top -= overBottom;
+ // adjust based on position and margin
+ } else {
+ position.top = max( position.top - collisionPosTop, position.top );
+ }
+ }
+ },
+ flip: {
+ left: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.offset.left + within.scrollLeft,
+ outerWidth = within.width,
+ offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+ overLeft = collisionPosLeft - offsetLeft,
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
+ myOffset = data.my[ 0 ] === "left" ?
+ -data.elemWidth :
+ data.my[ 0 ] === "right" ?
+ data.elemWidth :
+ 0,
+ atOffset = data.at[ 0 ] === "left" ?
+ data.targetWidth :
+ data.at[ 0 ] === "right" ?
+ -data.targetWidth :
+ 0,
+ offset = -2 * data.offset[ 0 ],
+ newOverRight,
+ newOverLeft;
+
+ if ( overLeft < 0 ) {
+ newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
+ if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
+ position.left += myOffset + atOffset + offset;
+ }
+ }
+ else if ( overRight > 0 ) {
+ newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
+ if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
+ position.left += myOffset + atOffset + offset;
+ }
+ }
+ },
+ top: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.offset.top + within.scrollTop,
+ outerHeight = within.height,
+ offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
+ overTop = collisionPosTop - offsetTop,
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
+ top = data.my[ 1 ] === "top",
+ myOffset = top ?
+ -data.elemHeight :
+ data.my[ 1 ] === "bottom" ?
+ data.elemHeight :
+ 0,
+ atOffset = data.at[ 1 ] === "top" ?
+ data.targetHeight :
+ data.at[ 1 ] === "bottom" ?
+ -data.targetHeight :
+ 0,
+ offset = -2 * data.offset[ 1 ],
+ newOverTop,
+ newOverBottom;
+ if ( overTop < 0 ) {
+ newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
+ if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
+ position.top += myOffset + atOffset + offset;
+ }
+ }
+ else if ( overBottom > 0 ) {
+ newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
+ if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
+ position.top += myOffset + atOffset + offset;
+ }
+ }
+ }
+ },
+ flipfit: {
+ left: function() {
+ $.ui.position.flip.left.apply( this, arguments );
+ $.ui.position.fit.left.apply( this, arguments );
+ },
+ top: function() {
+ $.ui.position.flip.top.apply( this, arguments );
+ $.ui.position.fit.top.apply( this, arguments );
+ }
+ }
+};
+
+// fraction support test
+(function () {
+ var testElement, testElementParent, testElementStyle, offsetLeft, i,
+ body = document.getElementsByTagName( "body" )[ 0 ],
+ div = document.createElement( "div" );
+
+ //Create a "fake body" for testing based on method used in jQuery.support
+ testElement = document.createElement( body ? "div" : "body" );
+ testElementStyle = {
+ visibility: "hidden",
+ width: 0,
+ height: 0,
+ border: 0,
+ margin: 0,
+ background: "none"
+ };
+ if ( body ) {
+ $.extend( testElementStyle, {
+ position: "absolute",
+ left: "-1000px",
+ top: "-1000px"
+ });
+ }
+ for ( i in testElementStyle ) {
+ testElement.style[ i ] = testElementStyle[ i ];
+ }
+ testElement.appendChild( div );
+ testElementParent = body || document.documentElement;
+ testElementParent.insertBefore( testElement, testElementParent.firstChild );
+
+ div.style.cssText = "position: absolute; left: 10.7432222px;";
+
+ offsetLeft = $( div ).offset().left;
+ $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
+
+ testElement.innerHTML = "";
+ testElementParent.removeChild( testElement );
+})();
+
+}( jQuery ) );
+
+(function( $, undefined ) {
+
+$.widget( "ui.progressbar", {
+ version: "1.10.4",
+ options: {
+ max: 100,
+ value: 0,
+
+ change: null,
+ complete: null
+ },
+
+ min: 0,
+
+ _create: function() {
+ // Constrain initial value
+ this.oldValue = this.options.value = this._constrainedValue();
+
+ this.element
+ .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+ .attr({
+ // Only set static values, aria-valuenow and aria-valuemax are
+ // set inside _refreshValue()
+ role: "progressbar",
+ "aria-valuemin": this.min
+ });
+
+ this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
+ .appendTo( this.element );
+
+ this._refreshValue();
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-valuemin" )
+ .removeAttr( "aria-valuemax" )
+ .removeAttr( "aria-valuenow" );
+
+ this.valueDiv.remove();
+ },
+
+ value: function( newValue ) {
+ if ( newValue === undefined ) {
+ return this.options.value;
+ }
+
+ this.options.value = this._constrainedValue( newValue );
+ this._refreshValue();
+ },
+
+ _constrainedValue: function( newValue ) {
+ if ( newValue === undefined ) {
+ newValue = this.options.value;
+ }
+
+ this.indeterminate = newValue === false;
+
+ // sanitize value
+ if ( typeof newValue !== "number" ) {
+ newValue = 0;
+ }
+
+ return this.indeterminate ? false :
+ Math.min( this.options.max, Math.max( this.min, newValue ) );
+ },
+
+ _setOptions: function( options ) {
+ // Ensure "value" option is set after other values (like max)
+ var value = options.value;
+ delete options.value;
+
+ this._super( options );
+
+ this.options.value = this._constrainedValue( value );
+ this._refreshValue();
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "max" ) {
+ // Don't allow a max less than min
+ value = Math.max( this.min, value );
+ }
+
+ this._super( key, value );
+ },
+
+ _percentage: function() {
+ return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
+ },
+
+ _refreshValue: function() {
+ var value = this.options.value,
+ percentage = this._percentage();
+
+ this.valueDiv
+ .toggle( this.indeterminate || value > this.min )
+ .toggleClass( "ui-corner-right", value === this.options.max )
+ .width( percentage.toFixed(0) + "%" );
+
+ this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
+
+ if ( this.indeterminate ) {
+ this.element.removeAttr( "aria-valuenow" );
+ if ( !this.overlayDiv ) {
+ this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
+ }
+ } else {
+ this.element.attr({
+ "aria-valuemax": this.options.max,
+ "aria-valuenow": value
+ });
+ if ( this.overlayDiv ) {
+ this.overlayDiv.remove();
+ this.overlayDiv = null;
+ }
+ }
+
+ if ( this.oldValue !== value ) {
+ this.oldValue = value;
+ this._trigger( "change" );
+ }
+ if ( value === this.options.max ) {
+ this._trigger( "complete" );
+ }
+ }
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+// number of pages in a slider
+// (how many times can you page up/down to go through the whole range)
+var numPages = 5;
+
+$.widget( "ui.slider", $.ui.mouse, {
+ version: "1.10.4",
+ widgetEventPrefix: "slide",
+
+ options: {
+ animate: false,
+ distance: 0,
+ max: 100,
+ min: 0,
+ orientation: "horizontal",
+ range: false,
+ step: 1,
+ value: 0,
+ values: null,
+
+ // callbacks
+ change: null,
+ slide: null,
+ start: null,
+ stop: null
+ },
+
+ _create: function() {
+ this._keySliding = false;
+ this._mouseSliding = false;
+ this._animateOff = true;
+ this._handleIndex = null;
+ this._detectOrientation();
+ this._mouseInit();
+
+ this.element
+ .addClass( "ui-slider" +
+ " ui-slider-" + this.orientation +
+ " ui-widget" +
+ " ui-widget-content" +
+ " ui-corner-all");
+
+ this._refresh();
+ this._setOption( "disabled", this.options.disabled );
+
+ this._animateOff = false;
+ },
+
+ _refresh: function() {
+ this._createRange();
+ this._createHandles();
+ this._setupEvents();
+ this._refreshValue();
+ },
+
+ _createHandles: function() {
+ var i, handleCount,
+ options = this.options,
+ existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
+ handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
+ handles = [];
+
+ handleCount = ( options.values && options.values.length ) || 1;
+
+ if ( existingHandles.length > handleCount ) {
+ existingHandles.slice( handleCount ).remove();
+ existingHandles = existingHandles.slice( 0, handleCount );
+ }
+
+ for ( i = existingHandles.length; i < handleCount; i++ ) {
+ handles.push( handle );
+ }
+
+ this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
+
+ this.handle = this.handles.eq( 0 );
+
+ this.handles.each(function( i ) {
+ $( this ).data( "ui-slider-handle-index", i );
+ });
+ },
+
+ _createRange: function() {
+ var options = this.options,
+ classes = "";
+
+ if ( options.range ) {
+ if ( options.range === true ) {
+ if ( !options.values ) {
+ options.values = [ this._valueMin(), this._valueMin() ];
+ } else if ( options.values.length && options.values.length !== 2 ) {
+ options.values = [ options.values[0], options.values[0] ];
+ } else if ( $.isArray( options.values ) ) {
+ options.values = options.values.slice(0);
+ }
+ }
+
+ if ( !this.range || !this.range.length ) {
+ this.range = $( "<div></div>" )
+ .appendTo( this.element );
+
+ classes = "ui-slider-range" +
+ // note: this isn't the most fittingly semantic framework class for this element,
+ // but worked best visually with a variety of themes
+ " ui-widget-header ui-corner-all";
+ } else {
+ this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
+ // Handle range switching from true to min/max
+ .css({
+ "left": "",
+ "bottom": ""
+ });
+ }
+
+ this.range.addClass( classes +
+ ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
+ } else {
+ if ( this.range ) {
+ this.range.remove();
+ }
+ this.range = null;
+ }
+ },
+
+ _setupEvents: function() {
+ var elements = this.handles.add( this.range ).filter( "a" );
+ this._off( elements );
+ this._on( elements, this._handleEvents );
+ this._hoverable( elements );
+ this._focusable( elements );
+ },
+
+ _destroy: function() {
+ this.handles.remove();
+ if ( this.range ) {
+ this.range.remove();
+ }
+
+ this.element
+ .removeClass( "ui-slider" +
+ " ui-slider-horizontal" +
+ " ui-slider-vertical" +
+ " ui-widget" +
+ " ui-widget-content" +
+ " ui-corner-all" );
+
+ this._mouseDestroy();
+ },
+
+ _mouseCapture: function( event ) {
+ var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
+ that = this,
+ o = this.options;
+
+ if ( o.disabled ) {
+ return false;
+ }
+
+ this.elementSize = {
+ width: this.element.outerWidth(),
+ height: this.element.outerHeight()
+ };
+ this.elementOffset = this.element.offset();
+
+ position = { x: event.pageX, y: event.pageY };
+ normValue = this._normValueFromMouse( position );
+ distance = this._valueMax() - this._valueMin() + 1;
+ this.handles.each(function( i ) {
+ var thisDistance = Math.abs( normValue - that.values(i) );
+ if (( distance > thisDistance ) ||
+ ( distance === thisDistance &&
+ (i === that._lastChangedValue || that.values(i) === o.min ))) {
+ distance = thisDistance;
+ closestHandle = $( this );
+ index = i;
+ }
+ });
+
+ allowed = this._start( event, index );
+ if ( allowed === false ) {
+ return false;
+ }
+ this._mouseSliding = true;
+
+ this._handleIndex = index;
+
+ closestHandle
+ .addClass( "ui-state-active" )
+ .focus();
+
+ offset = closestHandle.offset();
+ mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
+ this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
+ left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
+ top: event.pageY - offset.top -
+ ( closestHandle.height() / 2 ) -
+ ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
+ ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
+ ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
+ };
+
+ if ( !this.handles.hasClass( "ui-state-hover" ) ) {
+ this._slide( event, index, normValue );
+ }
+ this._animateOff = true;
+ return true;
+ },
+
+ _mouseStart: function() {
+ return true;
+ },
+
+ _mouseDrag: function( event ) {
+ var position = { x: event.pageX, y: event.pageY },
+ normValue = this._normValueFromMouse( position );
+
+ this._slide( event, this._handleIndex, normValue );
+
+ return false;
+ },
+
+ _mouseStop: function( event ) {
+ this.handles.removeClass( "ui-state-active" );
+ this._mouseSliding = false;
+
+ this._stop( event, this._handleIndex );
+ this._change( event, this._handleIndex );
+
+ this._handleIndex = null;
+ this._clickOffset = null;
+ this._animateOff = false;
+
+ return false;
+ },
+
+ _detectOrientation: function() {
+ this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
+ },
+
+ _normValueFromMouse: function( position ) {
+ var pixelTotal,
+ pixelMouse,
+ percentMouse,
+ valueTotal,
+ valueMouse;
+
+ if ( this.orientation === "horizontal" ) {
+ pixelTotal = this.elementSize.width;
+ pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
+ } else {
+ pixelTotal = this.elementSize.height;
+ pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
+ }
+
+ percentMouse = ( pixelMouse / pixelTotal );
+ if ( percentMouse > 1 ) {
+ percentMouse = 1;
+ }
+ if ( percentMouse < 0 ) {
+ percentMouse = 0;
+ }
+ if ( this.orientation === "vertical" ) {
+ percentMouse = 1 - percentMouse;
+ }
+
+ valueTotal = this._valueMax() - this._valueMin();
+ valueMouse = this._valueMin() + percentMouse * valueTotal;
+
+ return this._trimAlignValue( valueMouse );
+ },
+
+ _start: function( event, index ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+ return this._trigger( "start", event, uiHash );
+ },
+
+ _slide: function( event, index, newVal ) {
+ var otherVal,
+ newValues,
+ allowed;
+
+ if ( this.options.values && this.options.values.length ) {
+ otherVal = this.values( index ? 0 : 1 );
+
+ if ( ( this.options.values.length === 2 && this.options.range === true ) &&
+ ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
+ ) {
+ newVal = otherVal;
+ }
+
+ if ( newVal !== this.values( index ) ) {
+ newValues = this.values();
+ newValues[ index ] = newVal;
+ // A slide can be canceled by returning false from the slide callback
+ allowed = this._trigger( "slide", event, {
+ handle: this.handles[ index ],
+ value: newVal,
+ values: newValues
+ } );
+ otherVal = this.values( index ? 0 : 1 );
+ if ( allowed !== false ) {
+ this.values( index, newVal );
+ }
+ }
+ } else {
+ if ( newVal !== this.value() ) {
+ // A slide can be canceled by returning false from the slide callback
+ allowed = this._trigger( "slide", event, {
+ handle: this.handles[ index ],
+ value: newVal
+ } );
+ if ( allowed !== false ) {
+ this.value( newVal );
+ }
+ }
+ }
+ },
+
+ _stop: function( event, index ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+
+ this._trigger( "stop", event, uiHash );
+ },
+
+ _change: function( event, index ) {
+ if ( !this._keySliding && !this._mouseSliding ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+
+ //store the last changed value index for reference when handles overlap
+ this._lastChangedValue = index;
+
+ this._trigger( "change", event, uiHash );
+ }
+ },
+
+ value: function( newValue ) {
+ if ( arguments.length ) {
+ this.options.value = this._trimAlignValue( newValue );
+ this._refreshValue();
+ this._change( null, 0 );
+ return;
+ }
+
+ return this._value();
+ },
+
+ values: function( index, newValue ) {
+ var vals,
+ newValues,
+ i;
+
+ if ( arguments.length > 1 ) {
+ this.options.values[ index ] = this._trimAlignValue( newValue );
+ this._refreshValue();
+ this._change( null, index );
+ return;
+ }
+
+ if ( arguments.length ) {
+ if ( $.isArray( arguments[ 0 ] ) ) {
+ vals = this.options.values;
+ newValues = arguments[ 0 ];
+ for ( i = 0; i < vals.length; i += 1 ) {
+ vals[ i ] = this._trimAlignValue( newValues[ i ] );
+ this._change( null, i );
+ }
+ this._refreshValue();
+ } else {
+ if ( this.options.values && this.options.values.length ) {
+ return this._values( index );
+ } else {
+ return this.value();
+ }
+ }
+ } else {
+ return this._values();
+ }
+ },
+
+ _setOption: function( key, value ) {
+ var i,
+ valsLength = 0;
+
+ if ( key === "range" && this.options.range === true ) {
+ if ( value === "min" ) {
+ this.options.value = this._values( 0 );
+ this.options.values = null;
+ } else if ( value === "max" ) {
+ this.options.value = this._values( this.options.values.length-1 );
+ this.options.values = null;
+ }
+ }
+
+ if ( $.isArray( this.options.values ) ) {
+ valsLength = this.options.values.length;
+ }
+
+ $.Widget.prototype._setOption.apply( this, arguments );
+
+ switch ( key ) {
+ case "orientation":
+ this._detectOrientation();
+ this.element
+ .removeClass( "ui-slider-horizontal ui-slider-vertical" )
+ .addClass( "ui-slider-" + this.orientation );
+ this._refreshValue();
+ break;
+ case "value":
+ this._animateOff = true;
+ this._refreshValue();
+ this._change( null, 0 );
+ this._animateOff = false;
+ break;
+ case "values":
+ this._animateOff = true;
+ this._refreshValue();
+ for ( i = 0; i < valsLength; i += 1 ) {
+ this._change( null, i );
+ }
+ this._animateOff = false;
+ break;
+ case "min":
+ case "max":
+ this._animateOff = true;
+ this._refreshValue();
+ this._animateOff = false;
+ break;
+ case "range":
+ this._animateOff = true;
+ this._refresh();
+ this._animateOff = false;
+ break;
+ }
+ },
+
+ //internal value getter
+ // _value() returns value trimmed by min and max, aligned by step
+ _value: function() {
+ var val = this.options.value;
+ val = this._trimAlignValue( val );
+
+ return val;
+ },
+
+ //internal values getter
+ // _values() returns array of values trimmed by min and max, aligned by step
+ // _values( index ) returns single value trimmed by min and max, aligned by step
+ _values: function( index ) {
+ var val,
+ vals,
+ i;
+
+ if ( arguments.length ) {
+ val = this.options.values[ index ];
+ val = this._trimAlignValue( val );
+
+ return val;
+ } else if ( this.options.values && this.options.values.length ) {
+ // .slice() creates a copy of the array
+ // this copy gets trimmed by min and max and then returned
+ vals = this.options.values.slice();
+ for ( i = 0; i < vals.length; i+= 1) {
+ vals[ i ] = this._trimAlignValue( vals[ i ] );
+ }
+
+ return vals;
+ } else {
+ return [];
+ }
+ },
+
+ // returns the step-aligned value that val is closest to, between (inclusive) min and max
+ _trimAlignValue: function( val ) {
+ if ( val <= this._valueMin() ) {
+ return this._valueMin();
+ }
+ if ( val >= this._valueMax() ) {
+ return this._valueMax();
+ }
+ var step = ( this.options.step > 0 ) ? this.options.step : 1,
+ valModStep = (val - this._valueMin()) % step,
+ alignValue = val - valModStep;
+
+ if ( Math.abs(valModStep) * 2 >= step ) {
+ alignValue += ( valModStep > 0 ) ? step : ( -step );
+ }
+
+ // Since JavaScript has problems with large floats, round
+ // the final value to 5 digits after the decimal point (see #4124)
+ return parseFloat( alignValue.toFixed(5) );
+ },
+
+ _valueMin: function() {
+ return this.options.min;
+ },
+
+ _valueMax: function() {
+ return this.options.max;
+ },
+
+ _refreshValue: function() {
+ var lastValPercent, valPercent, value, valueMin, valueMax,
+ oRange = this.options.range,
+ o = this.options,
+ that = this,
+ animate = ( !this._animateOff ) ? o.animate : false,
+ _set = {};
+
+ if ( this.options.values && this.options.values.length ) {
+ this.handles.each(function( i ) {
+ valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
+ _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+ $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+ if ( that.options.range === true ) {
+ if ( that.orientation === "horizontal" ) {
+ if ( i === 0 ) {
+ that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
+ }
+ if ( i === 1 ) {
+ that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ } else {
+ if ( i === 0 ) {
+ that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
+ }
+ if ( i === 1 ) {
+ that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ }
+ }
+ lastValPercent = valPercent;
+ });
+ } else {
+ value = this.value();
+ valueMin = this._valueMin();
+ valueMax = this._valueMax();
+ valPercent = ( valueMax !== valueMin ) ?
+ ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
+ 0;
+ _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+ this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+
+ if ( oRange === "min" && this.orientation === "horizontal" ) {
+ this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
+ }
+ if ( oRange === "max" && this.orientation === "horizontal" ) {
+ this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ if ( oRange === "min" && this.orientation === "vertical" ) {
+ this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
+ }
+ if ( oRange === "max" && this.orientation === "vertical" ) {
+ this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ }
+ },
+
+ _handleEvents: {
+ keydown: function( event ) {
+ var allowed, curVal, newVal, step,
+ index = $( event.target ).data( "ui-slider-handle-index" );
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.HOME:
+ case $.ui.keyCode.END:
+ case $.ui.keyCode.PAGE_UP:
+ case $.ui.keyCode.PAGE_DOWN:
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.RIGHT:
+ case $.ui.keyCode.DOWN:
+ case $.ui.keyCode.LEFT:
+ event.preventDefault();
+ if ( !this._keySliding ) {
+ this._keySliding = true;
+ $( event.target ).addClass( "ui-state-active" );
+ allowed = this._start( event, index );
+ if ( allowed === false ) {
+ return;
+ }
+ }
+ break;
+ }
+
+ step = this.options.step;
+ if ( this.options.values && this.options.values.length ) {
+ curVal = newVal = this.values( index );
+ } else {
+ curVal = newVal = this.value();
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.HOME:
+ newVal = this._valueMin();
+ break;
+ case $.ui.keyCode.END:
+ newVal = this._valueMax();
+ break;
+ case $.ui.keyCode.PAGE_UP:
+ newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
+ break;
+ case $.ui.keyCode.PAGE_DOWN:
+ newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
+ break;
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.RIGHT:
+ if ( curVal === this._valueMax() ) {
+ return;
+ }
+ newVal = this._trimAlignValue( curVal + step );
+ break;
+ case $.ui.keyCode.DOWN:
+ case $.ui.keyCode.LEFT:
+ if ( curVal === this._valueMin() ) {
+ return;
+ }
+ newVal = this._trimAlignValue( curVal - step );
+ break;
+ }
+
+ this._slide( event, index, newVal );
+ },
+ click: function( event ) {
+ event.preventDefault();
+ },
+ keyup: function( event ) {
+ var index = $( event.target ).data( "ui-slider-handle-index" );
+
+ if ( this._keySliding ) {
+ this._keySliding = false;
+ this._stop( event, index );
+ this._change( event, index );
+ $( event.target ).removeClass( "ui-state-active" );
+ }
+ }
+ }
+
+});
+
+}(jQuery));
+
+(function( $ ) {
+
+function modifier( fn ) {
+ return function() {
+ var previous = this.element.val();
+ fn.apply( this, arguments );
+ this._refresh();
+ if ( previous !== this.element.val() ) {
+ this._trigger( "change" );
+ }
+ };
+}
+
+$.widget( "ui.spinner", {
+ version: "1.10.4",
+ defaultElement: "<input>",
+ widgetEventPrefix: "spin",
+ options: {
+ culture: null,
+ icons: {
+ down: "ui-icon-triangle-1-s",
+ up: "ui-icon-triangle-1-n"
+ },
+ incremental: true,
+ max: null,
+ min: null,
+ numberFormat: null,
+ page: 10,
+ step: 1,
+
+ change: null,
+ spin: null,
+ start: null,
+ stop: null
+ },
+
+ _create: function() {
+ // handle string values that need to be parsed
+ this._setOption( "max", this.options.max );
+ this._setOption( "min", this.options.min );
+ this._setOption( "step", this.options.step );
+
+ // Only format if there is a value, prevents the field from being marked
+ // as invalid in Firefox, see #9573.
+ if ( this.value() !== "" ) {
+ // Format the value, but don't constrain.
+ this._value( this.element.val(), true );
+ }
+
+ this._draw();
+ this._on( this._events );
+ this._refresh();
+
+ // turning off autocomplete prevents the browser from remembering the
+ // value when navigating through history, so we re-enable autocomplete
+ // if the page is unloaded before the widget is destroyed. #7790
+ this._on( this.window, {
+ beforeunload: function() {
+ this.element.removeAttr( "autocomplete" );
+ }
+ });
+ },
+
+ _getCreateOptions: function() {
+ var options = {},
+ element = this.element;
+
+ $.each( [ "min", "max", "step" ], function( i, option ) {
+ var value = element.attr( option );
+ if ( value !== undefined && value.length ) {
+ options[ option ] = value;
+ }
+ });
+
+ return options;
+ },
+
+ _events: {
+ keydown: function( event ) {
+ if ( this._start( event ) && this._keydown( event ) ) {
+ event.preventDefault();
+ }
+ },
+ keyup: "_stop",
+ focus: function() {
+ this.previous = this.element.val();
+ },
+ blur: function( event ) {
+ if ( this.cancelBlur ) {
+ delete this.cancelBlur;
+ return;
+ }
+
+ this._stop();
+ this._refresh();
+ if ( this.previous !== this.element.val() ) {
+ this._trigger( "change", event );
+ }
+ },
+ mousewheel: function( event, delta ) {
+ if ( !delta ) {
+ return;
+ }
+ if ( !this.spinning && !this._start( event ) ) {
+ return false;
+ }
+
+ this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
+ clearTimeout( this.mousewheelTimer );
+ this.mousewheelTimer = this._delay(function() {
+ if ( this.spinning ) {
+ this._stop( event );
+ }
+ }, 100 );
+ event.preventDefault();
+ },
+ "mousedown .ui-spinner-button": function( event ) {
+ var previous;
+
+ // We never want the buttons to have focus; whenever the user is
+ // interacting with the spinner, the focus should be on the input.
+ // If the input is focused then this.previous is properly set from
+ // when the input first received focus. If the input is not focused
+ // then we need to set this.previous based on the value before spinning.
+ previous = this.element[0] === this.document[0].activeElement ?
+ this.previous : this.element.val();
+ function checkFocus() {
+ var isActive = this.element[0] === this.document[0].activeElement;
+ if ( !isActive ) {
+ this.element.focus();
+ this.previous = previous;
+ // support: IE
+ // IE sets focus asynchronously, so we need to check if focus
+ // moved off of the input because the user clicked on the button.
+ this._delay(function() {
+ this.previous = previous;
+ });
+ }
+ }
+
+ // ensure focus is on (or stays on) the text field
+ event.preventDefault();
+ checkFocus.call( this );
+
+ // support: IE
+ // IE doesn't prevent moving focus even with event.preventDefault()
+ // so we set a flag to know when we should ignore the blur event
+ // and check (again) if focus moved off of the input.
+ this.cancelBlur = true;
+ this._delay(function() {
+ delete this.cancelBlur;
+ checkFocus.call( this );
+ });
+
+ if ( this._start( event ) === false ) {
+ return;
+ }
+
+ this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
+ },
+ "mouseup .ui-spinner-button": "_stop",
+ "mouseenter .ui-spinner-button": function( event ) {
+ // button will add ui-state-active if mouse was down while mouseleave and kept down
+ if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
+ return;
+ }
+
+ if ( this._start( event ) === false ) {
+ return false;
+ }
+ this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
+ },
+ // TODO: do we really want to consider this a stop?
+ // shouldn't we just stop the repeater and wait until mouseup before
+ // we trigger the stop event?
+ "mouseleave .ui-spinner-button": "_stop"
+ },
+
+ _draw: function() {
+ var uiSpinner = this.uiSpinner = this.element
+ .addClass( "ui-spinner-input" )
+ .attr( "autocomplete", "off" )
+ .wrap( this._uiSpinnerHtml() )
+ .parent()
+ // add buttons
+ .append( this._buttonHtml() );
+
+ this.element.attr( "role", "spinbutton" );
+
+ // button bindings
+ this.buttons = uiSpinner.find( ".ui-spinner-button" )
+ .attr( "tabIndex", -1 )
+ .button()
+ .removeClass( "ui-corner-all" );
+
+ // IE 6 doesn't understand height: 50% for the buttons
+ // unless the wrapper has an explicit height
+ if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
+ uiSpinner.height() > 0 ) {
+ uiSpinner.height( uiSpinner.height() );
+ }
+
+ // disable spinner if element was already disabled
+ if ( this.options.disabled ) {
+ this.disable();
+ }
+ },
+
+ _keydown: function( event ) {
+ var options = this.options,
+ keyCode = $.ui.keyCode;
+
+ switch ( event.keyCode ) {
+ case keyCode.UP:
+ this._repeat( null, 1, event );
+ return true;
+ case keyCode.DOWN:
+ this._repeat( null, -1, event );
+ return true;
+ case keyCode.PAGE_UP:
+ this._repeat( null, options.page, event );
+ return true;
+ case keyCode.PAGE_DOWN:
+ this._repeat( null, -options.page, event );
+ return true;
+ }
+
+ return false;
+ },
+
+ _uiSpinnerHtml: function() {
+ return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
+ },
+
+ _buttonHtml: function() {
+ return "" +
+ "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
+ "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
+ "</a>" +
+ "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
+ "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
+ "</a>";
+ },
+
+ _start: function( event ) {
+ if ( !this.spinning && this._trigger( "start", event ) === false ) {
+ return false;
+ }
+
+ if ( !this.counter ) {
+ this.counter = 1;
+ }
+ this.spinning = true;
+ return true;
+ },
+
+ _repeat: function( i, steps, event ) {
+ i = i || 500;
+
+ clearTimeout( this.timer );
+ this.timer = this._delay(function() {
+ this._repeat( 40, steps, event );
+ }, i );
+
+ this._spin( steps * this.options.step, event );
+ },
+
+ _spin: function( step, event ) {
+ var value = this.value() || 0;
+
+ if ( !this.counter ) {
+ this.counter = 1;
+ }
+
+ value = this._adjustValue( value + step * this._increment( this.counter ) );
+
+ if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
+ this._value( value );
+ this.counter++;
+ }
+ },
+
+ _increment: function( i ) {
+ var incremental = this.options.incremental;
+
+ if ( incremental ) {
+ return $.isFunction( incremental ) ?
+ incremental( i ) :
+ Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
+ }
+
+ return 1;
+ },
+
+ _precision: function() {
+ var precision = this._precisionOf( this.options.step );
+ if ( this.options.min !== null ) {
+ precision = Math.max( precision, this._precisionOf( this.options.min ) );
+ }
+ return precision;
+ },
+
+ _precisionOf: function( num ) {
+ var str = num.toString(),
+ decimal = str.indexOf( "." );
+ return decimal === -1 ? 0 : str.length - decimal - 1;
+ },
+
+ _adjustValue: function( value ) {
+ var base, aboveMin,
+ options = this.options;
+
+ // make sure we're at a valid step
+ // - find out where we are relative to the base (min or 0)
+ base = options.min !== null ? options.min : 0;
+ aboveMin = value - base;
+ // - round to the nearest step
+ aboveMin = Math.round(aboveMin / options.step) * options.step;
+ // - rounding is based on 0, so adjust back to our base
+ value = base + aboveMin;
+
+ // fix precision from bad JS floating point math
+ value = parseFloat( value.toFixed( this._precision() ) );
+
+ // clamp the value
+ if ( options.max !== null && value > options.max) {
+ return options.max;
+ }
+ if ( options.min !== null && value < options.min ) {
+ return options.min;
+ }
+
+ return value;
+ },
+
+ _stop: function( event ) {
+ if ( !this.spinning ) {
+ return;
+ }
+
+ clearTimeout( this.timer );
+ clearTimeout( this.mousewheelTimer );
+ this.counter = 0;
+ this.spinning = false;
+ this._trigger( "stop", event );
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "culture" || key === "numberFormat" ) {
+ var prevValue = this._parse( this.element.val() );
+ this.options[ key ] = value;
+ this.element.val( this._format( prevValue ) );
+ return;
+ }
+
+ if ( key === "max" || key === "min" || key === "step" ) {
+ if ( typeof value === "string" ) {
+ value = this._parse( value );
+ }
+ }
+ if ( key === "icons" ) {
+ this.buttons.first().find( ".ui-icon" )
+ .removeClass( this.options.icons.up )
+ .addClass( value.up );
+ this.buttons.last().find( ".ui-icon" )
+ .removeClass( this.options.icons.down )
+ .addClass( value.down );
+ }
+
+ this._super( key, value );
+
+ if ( key === "disabled" ) {
+ if ( value ) {
+ this.element.prop( "disabled", true );
+ this.buttons.button( "disable" );
+ } else {
+ this.element.prop( "disabled", false );
+ this.buttons.button( "enable" );
+ }
+ }
+ },
+
+ _setOptions: modifier(function( options ) {
+ this._super( options );
+ this._value( this.element.val() );
+ }),
+
+ _parse: function( val ) {
+ if ( typeof val === "string" && val !== "" ) {
+ val = window.Globalize && this.options.numberFormat ?
+ Globalize.parseFloat( val, 10, this.options.culture ) : +val;
+ }
+ return val === "" || isNaN( val ) ? null : val;
+ },
+
+ _format: function( value ) {
+ if ( value === "" ) {
+ return "";
+ }
+ return window.Globalize && this.options.numberFormat ?
+ Globalize.format( value, this.options.numberFormat, this.options.culture ) :
+ value;
+ },
+
+ _refresh: function() {
+ this.element.attr({
+ "aria-valuemin": this.options.min,
+ "aria-valuemax": this.options.max,
+ // TODO: what should we do with values that can't be parsed?
+ "aria-valuenow": this._parse( this.element.val() )
+ });
+ },
+
+ // update the value without triggering change
+ _value: function( value, allowAny ) {
+ var parsed;
+ if ( value !== "" ) {
+ parsed = this._parse( value );
+ if ( parsed !== null ) {
+ if ( !allowAny ) {
+ parsed = this._adjustValue( parsed );
+ }
+ value = this._format( parsed );
+ }
+ }
+ this.element.val( value );
+ this._refresh();
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass( "ui-spinner-input" )
+ .prop( "disabled", false )
+ .removeAttr( "autocomplete" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-valuemin" )
+ .removeAttr( "aria-valuemax" )
+ .removeAttr( "aria-valuenow" );
+ this.uiSpinner.replaceWith( this.element );
+ },
+
+ stepUp: modifier(function( steps ) {
+ this._stepUp( steps );
+ }),
+ _stepUp: function( steps ) {
+ if ( this._start() ) {
+ this._spin( (steps || 1) * this.options.step );
+ this._stop();
+ }
+ },
+
+ stepDown: modifier(function( steps ) {
+ this._stepDown( steps );
+ }),
+ _stepDown: function( steps ) {
+ if ( this._start() ) {
+ this._spin( (steps || 1) * -this.options.step );
+ this._stop();
+ }
+ },
+
+ pageUp: modifier(function( pages ) {
+ this._stepUp( (pages || 1) * this.options.page );
+ }),
+
+ pageDown: modifier(function( pages ) {
+ this._stepDown( (pages || 1) * this.options.page );
+ }),
+
+ value: function( newVal ) {
+ if ( !arguments.length ) {
+ return this._parse( this.element.val() );
+ }
+ modifier( this._value ).call( this, newVal );
+ },
+
+ widget: function() {
+ return this.uiSpinner;
+ }
+});
+
+}( jQuery ) );
+
+(function( $, undefined ) {
+
+var tabId = 0,
+ rhash = /#.*$/;
+
+function getNextTabId() {
+ return ++tabId;
+}
+
+function isLocal( anchor ) {
+ // support: IE7
+ // IE7 doesn't normalize the href property when set via script (#9317)
+ anchor = anchor.cloneNode( false );
+
+ return anchor.hash.length > 1 &&
+ decodeURIComponent( anchor.href.replace( rhash, "" ) ) ===
+ decodeURIComponent( location.href.replace( rhash, "" ) );
+}
+
+$.widget( "ui.tabs", {
+ version: "1.10.4",
+ delay: 300,
+ options: {
+ active: null,
+ collapsible: false,
+ event: "click",
+ heightStyle: "content",
+ hide: null,
+ show: null,
+
+ // callbacks
+ activate: null,
+ beforeActivate: null,
+ beforeLoad: null,
+ load: null
+ },
+
+ _create: function() {
+ var that = this,
+ options = this.options;
+
+ this.running = false;
+
+ this.element
+ .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
+ .toggleClass( "ui-tabs-collapsible", options.collapsible )
+ // Prevent users from focusing disabled tabs via click
+ .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
+ if ( $( this ).is( ".ui-state-disabled" ) ) {
+ event.preventDefault();
+ }
+ })
+ // support: IE <9
+ // Preventing the default action in mousedown doesn't prevent IE
+ // from focusing the element, so if the anchor gets focused, blur.
+ // We don't have to worry about focusing the previously focused
+ // element since clicking on a non-focusable element should focus
+ // the body anyway.
+ .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
+ if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
+ this.blur();
+ }
+ });
+
+ this._processTabs();
+ options.active = this._initialActive();
+
+ // Take disabling tabs via class attribute from HTML
+ // into account and update option properly.
+ if ( $.isArray( options.disabled ) ) {
+ options.disabled = $.unique( options.disabled.concat(
+ $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
+ return that.tabs.index( li );
+ })
+ ) ).sort();
+ }
+
+ // check for length avoids error when initializing empty list
+ if ( this.options.active !== false && this.anchors.length ) {
+ this.active = this._findActive( options.active );
+ } else {
+ this.active = $();
+ }
+
+ this._refresh();
+
+ if ( this.active.length ) {
+ this.load( options.active );
+ }
+ },
+
+ _initialActive: function() {
+ var active = this.options.active,
+ collapsible = this.options.collapsible,
+ locationHash = location.hash.substring( 1 );
+
+ if ( active === null ) {
+ // check the fragment identifier in the URL
+ if ( locationHash ) {
+ this.tabs.each(function( i, tab ) {
+ if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
+ active = i;
+ return false;
+ }
+ });
+ }
+
+ // check for a tab marked active via a class
+ if ( active === null ) {
+ active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
+ }
+
+ // no active tab, set to false
+ if ( active === null || active === -1 ) {
+ active = this.tabs.length ? 0 : false;
+ }
+ }
+
+ // handle numbers: negative, out of range
+ if ( active !== false ) {
+ active = this.tabs.index( this.tabs.eq( active ) );
+ if ( active === -1 ) {
+ active = collapsible ? false : 0;
+ }
+ }
+
+ // don't allow collapsible: false and active: false
+ if ( !collapsible && active === false && this.anchors.length ) {
+ active = 0;
+ }
+
+ return active;
+ },
+
+ _getCreateEventData: function() {
+ return {
+ tab: this.active,
+ panel: !this.active.length ? $() : this._getPanelForTab( this.active )
+ };
+ },
+
+ _tabKeydown: function( event ) {
+ var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
+ selectedIndex = this.tabs.index( focusedTab ),
+ goingForward = true;
+
+ if ( this._handlePageNav( event ) ) {
+ return;
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.RIGHT:
+ case $.ui.keyCode.DOWN:
+ selectedIndex++;
+ break;
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.LEFT:
+ goingForward = false;
+ selectedIndex--;
+ break;
+ case $.ui.keyCode.END:
+ selectedIndex = this.anchors.length - 1;
+ break;
+ case $.ui.keyCode.HOME:
+ selectedIndex = 0;
+ break;
+ case $.ui.keyCode.SPACE:
+ // Activate only, no collapsing
+ event.preventDefault();
+ clearTimeout( this.activating );
+ this._activate( selectedIndex );
+ return;
+ case $.ui.keyCode.ENTER:
+ // Toggle (cancel delayed activation, allow collapsing)
+ event.preventDefault();
+ clearTimeout( this.activating );
+ // Determine if we should collapse or activate
+ this._activate( selectedIndex === this.options.active ? false : selectedIndex );
+ return;
+ default:
+ return;
+ }
+
+ // Focus the appropriate tab, based on which key was pressed
+ event.preventDefault();
+ clearTimeout( this.activating );
+ selectedIndex = this._focusNextTab( selectedIndex, goingForward );
+
+ // Navigating with control key will prevent automatic activation
+ if ( !event.ctrlKey ) {
+ // Update aria-selected immediately so that AT think the tab is already selected.
+ // Otherwise AT may confuse the user by stating that they need to activate the tab,
+ // but the tab will already be activated by the time the announcement finishes.
+ focusedTab.attr( "aria-selected", "false" );
+ this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
+
+ this.activating = this._delay(function() {
+ this.option( "active", selectedIndex );
+ }, this.delay );
+ }
+ },
+
+ _panelKeydown: function( event ) {
+ if ( this._handlePageNav( event ) ) {
+ return;
+ }
+
+ // Ctrl+up moves focus to the current tab
+ if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
+ event.preventDefault();
+ this.active.focus();
+ }
+ },
+
+ // Alt+page up/down moves focus to the previous/next tab (and activates)
+ _handlePageNav: function( event ) {
+ if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
+ this._activate( this._focusNextTab( this.options.active - 1, false ) );
+ return true;
+ }
+ if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
+ this._activate( this._focusNextTab( this.options.active + 1, true ) );
+ return true;
+ }
+ },
+
+ _findNextTab: function( index, goingForward ) {
+ var lastTabIndex = this.tabs.length - 1;
+
+ function constrain() {
+ if ( index > lastTabIndex ) {
+ index = 0;
+ }
+ if ( index < 0 ) {
+ index = lastTabIndex;
+ }
+ return index;
+ }
+
+ while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
+ index = goingForward ? index + 1 : index - 1;
+ }
+
+ return index;
+ },
+
+ _focusNextTab: function( index, goingForward ) {
+ index = this._findNextTab( index, goingForward );
+ this.tabs.eq( index ).focus();
+ return index;
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "active" ) {
+ // _activate() will handle invalid values and update this.options
+ this._activate( value );
+ return;
+ }
+
+ if ( key === "disabled" ) {
+ // don't use the widget factory's disabled handling
+ this._setupDisabled( value );
+ return;
+ }
+
+ this._super( key, value);
+
+ if ( key === "collapsible" ) {
+ this.element.toggleClass( "ui-tabs-collapsible", value );
+ // Setting collapsible: false while collapsed; open first panel
+ if ( !value && this.options.active === false ) {
+ this._activate( 0 );
+ }
+ }
+
+ if ( key === "event" ) {
+ this._setupEvents( value );
+ }
+
+ if ( key === "heightStyle" ) {
+ this._setupHeightStyle( value );
+ }
+ },
+
+ _tabId: function( tab ) {
+ return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId();
+ },
+
+ _sanitizeSelector: function( hash ) {
+ return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
+ },
+
+ refresh: function() {
+ var options = this.options,
+ lis = this.tablist.children( ":has(a[href])" );
+
+ // get disabled tabs from class attribute from HTML
+ // this will get converted to a boolean if needed in _refresh()
+ options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
+ return lis.index( tab );
+ });
+
+ this._processTabs();
+
+ // was collapsed or no tabs
+ if ( options.active === false || !this.anchors.length ) {
+ options.active = false;
+ this.active = $();
+ // was active, but active tab is gone
+ } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
+ // all remaining tabs are disabled
+ if ( this.tabs.length === options.disabled.length ) {
+ options.active = false;
+ this.active = $();
+ // activate previous tab
+ } else {
+ this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
+ }
+ // was active, active tab still exists
+ } else {
+ // make sure active index is correct
+ options.active = this.tabs.index( this.active );
+ }
+
+ this._refresh();
+ },
+
+ _refresh: function() {
+ this._setupDisabled( this.options.disabled );
+ this._setupEvents( this.options.event );
+ this._setupHeightStyle( this.options.heightStyle );
+
+ this.tabs.not( this.active ).attr({
+ "aria-selected": "false",
+ tabIndex: -1
+ });
+ this.panels.not( this._getPanelForTab( this.active ) )
+ .hide()
+ .attr({
+ "aria-expanded": "false",
+ "aria-hidden": "true"
+ });
+
+ // Make sure one tab is in the tab order
+ if ( !this.active.length ) {
+ this.tabs.eq( 0 ).attr( "tabIndex", 0 );
+ } else {
+ this.active
+ .addClass( "ui-tabs-active ui-state-active" )
+ .attr({
+ "aria-selected": "true",
+ tabIndex: 0
+ });
+ this._getPanelForTab( this.active )
+ .show()
+ .attr({
+ "aria-expanded": "true",
+ "aria-hidden": "false"
+ });
+ }
+ },
+
+ _processTabs: function() {
+ var that = this;
+
+ this.tablist = this._getList()
+ .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
+ .attr( "role", "tablist" );
+
+ this.tabs = this.tablist.find( "> li:has(a[href])" )
+ .addClass( "ui-state-default ui-corner-top" )
+ .attr({
+ role: "tab",
+ tabIndex: -1
+ });
+
+ this.anchors = this.tabs.map(function() {
+ return $( "a", this )[ 0 ];
+ })
+ .addClass( "ui-tabs-anchor" )
+ .attr({
+ role: "presentation",
+ tabIndex: -1
+ });
+
+ this.panels = $();
+
+ this.anchors.each(function( i, anchor ) {
+ var selector, panel, panelId,
+ anchorId = $( anchor ).uniqueId().attr( "id" ),
+ tab = $( anchor ).closest( "li" ),
+ originalAriaControls = tab.attr( "aria-controls" );
+
+ // inline tab
+ if ( isLocal( anchor ) ) {
+ selector = anchor.hash;
+ panel = that.element.find( that._sanitizeSelector( selector ) );
+ // remote tab
+ } else {
+ panelId = that._tabId( tab );
+ selector = "#" + panelId;
+ panel = that.element.find( selector );
+ if ( !panel.length ) {
+ panel = that._createPanel( panelId );
+ panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
+ }
+ panel.attr( "aria-live", "polite" );
+ }
+
+ if ( panel.length) {
+ that.panels = that.panels.add( panel );
+ }
+ if ( originalAriaControls ) {
+ tab.data( "ui-tabs-aria-controls", originalAriaControls );
+ }
+ tab.attr({
+ "aria-controls": selector.substring( 1 ),
+ "aria-labelledby": anchorId
+ });
+ panel.attr( "aria-labelledby", anchorId );
+ });
+
+ this.panels
+ .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
+ .attr( "role", "tabpanel" );
+ },
+
+ // allow overriding how to find the list for rare usage scenarios (#7715)
+ _getList: function() {
+ return this.tablist || this.element.find( "ol,ul" ).eq( 0 );
+ },
+
+ _createPanel: function( id ) {
+ return $( "<div>" )
+ .attr( "id", id )
+ .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
+ .data( "ui-tabs-destroy", true );
+ },
+
+ _setupDisabled: function( disabled ) {
+ if ( $.isArray( disabled ) ) {
+ if ( !disabled.length ) {
+ disabled = false;
+ } else if ( disabled.length === this.anchors.length ) {
+ disabled = true;
+ }
+ }
+
+ // disable tabs
+ for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
+ if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
+ $( li )
+ .addClass( "ui-state-disabled" )
+ .attr( "aria-disabled", "true" );
+ } else {
+ $( li )
+ .removeClass( "ui-state-disabled" )
+ .removeAttr( "aria-disabled" );
+ }
+ }
+
+ this.options.disabled = disabled;
+ },
+
+ _setupEvents: function( event ) {
+ var events = {
+ click: function( event ) {
+ event.preventDefault();
+ }
+ };
+ if ( event ) {
+ $.each( event.split(" "), function( index, eventName ) {
+ events[ eventName ] = "_eventHandler";
+ });
+ }
+
+ this._off( this.anchors.add( this.tabs ).add( this.panels ) );
+ this._on( this.anchors, events );
+ this._on( this.tabs, { keydown: "_tabKeydown" } );
+ this._on( this.panels, { keydown: "_panelKeydown" } );
+
+ this._focusable( this.tabs );
+ this._hoverable( this.tabs );
+ },
+
+ _setupHeightStyle: function( heightStyle ) {
+ var maxHeight,
+ parent = this.element.parent();
+
+ if ( heightStyle === "fill" ) {
+ maxHeight = parent.height();
+ maxHeight -= this.element.outerHeight() - this.element.height();
+
+ this.element.siblings( ":visible" ).each(function() {
+ var elem = $( this ),
+ position = elem.css( "position" );
+
+ if ( position === "absolute" || position === "fixed" ) {
+ return;
+ }
+ maxHeight -= elem.outerHeight( true );
+ });
+
+ this.element.children().not( this.panels ).each(function() {
+ maxHeight -= $( this ).outerHeight( true );
+ });
+
+ this.panels.each(function() {
+ $( this ).height( Math.max( 0, maxHeight -
+ $( this ).innerHeight() + $( this ).height() ) );
+ })
+ .css( "overflow", "auto" );
+ } else if ( heightStyle === "auto" ) {
+ maxHeight = 0;
+ this.panels.each(function() {
+ maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
+ }).height( maxHeight );
+ }
+ },
+
+ _eventHandler: function( event ) {
+ var options = this.options,
+ active = this.active,
+ anchor = $( event.currentTarget ),
+ tab = anchor.closest( "li" ),
+ clickedIsActive = tab[ 0 ] === active[ 0 ],
+ collapsing = clickedIsActive && options.collapsible,
+ toShow = collapsing ? $() : this._getPanelForTab( tab ),
+ toHide = !active.length ? $() : this._getPanelForTab( active ),
+ eventData = {
+ oldTab: active,
+ oldPanel: toHide,
+ newTab: collapsing ? $() : tab,
+ newPanel: toShow
+ };
+
+ event.preventDefault();
+
+ if ( tab.hasClass( "ui-state-disabled" ) ||
+ // tab is already loading
+ tab.hasClass( "ui-tabs-loading" ) ||
+ // can't switch durning an animation
+ this.running ||
+ // click on active header, but not collapsible
+ ( clickedIsActive && !options.collapsible ) ||
+ // allow canceling activation
+ ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
+ return;
+ }
+
+ options.active = collapsing ? false : this.tabs.index( tab );
+
+ this.active = clickedIsActive ? $() : tab;
+ if ( this.xhr ) {
+ this.xhr.abort();
+ }
+
+ if ( !toHide.length && !toShow.length ) {
+ $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
+ }
+
+ if ( toShow.length ) {
+ this.load( this.tabs.index( tab ), event );
+ }
+ this._toggle( event, eventData );
+ },
+
+ // handles show/hide for selecting tabs
+ _toggle: function( event, eventData ) {
+ var that = this,
+ toShow = eventData.newPanel,
+ toHide = eventData.oldPanel;
+
+ this.running = true;
+
+ function complete() {
+ that.running = false;
+ that._trigger( "activate", event, eventData );
+ }
+
+ function show() {
+ eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
+
+ if ( toShow.length && that.options.show ) {
+ that._show( toShow, that.options.show, complete );
+ } else {
+ toShow.show();
+ complete();
+ }
+ }
+
+ // start out by hiding, then showing, then completing
+ if ( toHide.length && this.options.hide ) {
+ this._hide( toHide, this.options.hide, function() {
+ eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
+ show();
+ });
+ } else {
+ eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
+ toHide.hide();
+ show();
+ }
+
+ toHide.attr({
+ "aria-expanded": "false",
+ "aria-hidden": "true"
+ });
+ eventData.oldTab.attr( "aria-selected", "false" );
+ // If we're switching tabs, remove the old tab from the tab order.
+ // If we're opening from collapsed state, remove the previous tab from the tab order.
+ // If we're collapsing, then keep the collapsing tab in the tab order.
+ if ( toShow.length && toHide.length ) {
+ eventData.oldTab.attr( "tabIndex", -1 );
+ } else if ( toShow.length ) {
+ this.tabs.filter(function() {
+ return $( this ).attr( "tabIndex" ) === 0;
+ })
+ .attr( "tabIndex", -1 );
+ }
+
+ toShow.attr({
+ "aria-expanded": "true",
+ "aria-hidden": "false"
+ });
+ eventData.newTab.attr({
+ "aria-selected": "true",
+ tabIndex: 0
+ });
+ },
+
+ _activate: function( index ) {
+ var anchor,
+ active = this._findActive( index );
+
+ // trying to activate the already active panel
+ if ( active[ 0 ] === this.active[ 0 ] ) {
+ return;
+ }
+
+ // trying to collapse, simulate a click on the current active header
+ if ( !active.length ) {
+ active = this.active;
+ }
+
+ anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
+ this._eventHandler({
+ target: anchor,
+ currentTarget: anchor,
+ preventDefault: $.noop
+ });
+ },
+
+ _findActive: function( index ) {
+ return index === false ? $() : this.tabs.eq( index );
+ },
+
+ _getIndex: function( index ) {
+ // meta-function to give users option to provide a href string instead of a numerical index.
+ if ( typeof index === "string" ) {
+ index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
+ }
+
+ return index;
+ },
+
+ _destroy: function() {
+ if ( this.xhr ) {
+ this.xhr.abort();
+ }
+
+ this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
+
+ this.tablist
+ .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
+ .removeAttr( "role" );
+
+ this.anchors
+ .removeClass( "ui-tabs-anchor" )
+ .removeAttr( "role" )
+ .removeAttr( "tabIndex" )
+ .removeUniqueId();
+
+ this.tabs.add( this.panels ).each(function() {
+ if ( $.data( this, "ui-tabs-destroy" ) ) {
+ $( this ).remove();
+ } else {
+ $( this )
+ .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
+ "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
+ .removeAttr( "tabIndex" )
+ .removeAttr( "aria-live" )
+ .removeAttr( "aria-busy" )
+ .removeAttr( "aria-selected" )
+ .removeAttr( "aria-labelledby" )
+ .removeAttr( "aria-hidden" )
+ .removeAttr( "aria-expanded" )
+ .removeAttr( "role" );
+ }
+ });
+
+ this.tabs.each(function() {
+ var li = $( this ),
+ prev = li.data( "ui-tabs-aria-controls" );
+ if ( prev ) {
+ li
+ .attr( "aria-controls", prev )
+ .removeData( "ui-tabs-aria-controls" );
+ } else {
+ li.removeAttr( "aria-controls" );
+ }
+ });
+
+ this.panels.show();
+
+ if ( this.options.heightStyle !== "content" ) {
+ this.panels.css( "height", "" );
+ }
+ },
+
+ enable: function( index ) {
+ var disabled = this.options.disabled;
+ if ( disabled === false ) {
+ return;
+ }
+
+ if ( index === undefined ) {
+ disabled = false;
+ } else {
+ index = this._getIndex( index );
+ if ( $.isArray( disabled ) ) {
+ disabled = $.map( disabled, function( num ) {
+ return num !== index ? num : null;
+ });
+ } else {
+ disabled = $.map( this.tabs, function( li, num ) {
+ return num !== index ? num : null;
+ });
+ }
+ }
+ this._setupDisabled( disabled );
+ },
+
+ disable: function( index ) {
+ var disabled = this.options.disabled;
+ if ( disabled === true ) {
+ return;
+ }
+
+ if ( index === undefined ) {
+ disabled = true;
+ } else {
+ index = this._getIndex( index );
+ if ( $.inArray( index, disabled ) !== -1 ) {
+ return;
+ }
+ if ( $.isArray( disabled ) ) {
+ disabled = $.merge( [ index ], disabled ).sort();
+ } else {
+ disabled = [ index ];
+ }
+ }
+ this._setupDisabled( disabled );
+ },
+
+ load: function( index, event ) {
+ index = this._getIndex( index );
+ var that = this,
+ tab = this.tabs.eq( index ),
+ anchor = tab.find( ".ui-tabs-anchor" ),
+ panel = this._getPanelForTab( tab ),
+ eventData = {
+ tab: tab,
+ panel: panel
+ };
+
+ // not remote
+ if ( isLocal( anchor[ 0 ] ) ) {
+ return;
+ }
+
+ this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
+
+ // support: jQuery <1.8
+ // jQuery <1.8 returns false if the request is canceled in beforeSend,
+ // but as of 1.8, $.ajax() always returns a jqXHR object.
+ if ( this.xhr && this.xhr.statusText !== "canceled" ) {
+ tab.addClass( "ui-tabs-loading" );
+ panel.attr( "aria-busy", "true" );
+
+ this.xhr
+ .success(function( response ) {
+ // support: jQuery <1.8
+ // http://bugs.jquery.com/ticket/11778
+ setTimeout(function() {
+ panel.html( response );
+ that._trigger( "load", event, eventData );
+ }, 1 );
+ })
+ .complete(function( jqXHR, status ) {
+ // support: jQuery <1.8
+ // http://bugs.jquery.com/ticket/11778
+ setTimeout(function() {
+ if ( status === "abort" ) {
+ that.panels.stop( false, true );
+ }
+
+ tab.removeClass( "ui-tabs-loading" );
+ panel.removeAttr( "aria-busy" );
+
+ if ( jqXHR === that.xhr ) {
+ delete that.xhr;
+ }
+ }, 1 );
+ });
+ }
+ },
+
+ _ajaxSettings: function( anchor, event, eventData ) {
+ var that = this;
+ return {
+ url: anchor.attr( "href" ),
+ beforeSend: function( jqXHR, settings ) {
+ return that._trigger( "beforeLoad", event,
+ $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );
+ }
+ };
+ },
+
+ _getPanelForTab: function( tab ) {
+ var id = $( tab ).attr( "aria-controls" );
+ return this.element.find( this._sanitizeSelector( "#" + id ) );
+ }
+});
+
+})( jQuery );
+
+(function( $ ) {
+
+var increments = 0;
+
+function addDescribedBy( elem, id ) {
+ var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
+ describedby.push( id );
+ elem
+ .data( "ui-tooltip-id", id )
+ .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
+}
+
+function removeDescribedBy( elem ) {
+ var id = elem.data( "ui-tooltip-id" ),
+ describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
+ index = $.inArray( id, describedby );
+ if ( index !== -1 ) {
+ describedby.splice( index, 1 );
+ }
+
+ elem.removeData( "ui-tooltip-id" );
+ describedby = $.trim( describedby.join( " " ) );
+ if ( describedby ) {
+ elem.attr( "aria-describedby", describedby );
+ } else {
+ elem.removeAttr( "aria-describedby" );
+ }
+}
+
+$.widget( "ui.tooltip", {
+ version: "1.10.4",
+ options: {
+ content: function() {
+ // support: IE<9, Opera in jQuery <1.7
+ // .text() can't accept undefined, so coerce to a string
+ var title = $( this ).attr( "title" ) || "";
+ // Escape title, since we're going from an attribute to raw HTML
+ return $( "<a>" ).text( title ).html();
+ },
+ hide: true,
+ // Disabled elements have inconsistent behavior across browsers (#8661)
+ items: "[title]:not([disabled])",
+ position: {
+ my: "left top+15",
+ at: "left bottom",
+ collision: "flipfit flip"
+ },
+ show: true,
+ tooltipClass: null,
+ track: false,
+
+ // callbacks
+ close: null,
+ open: null
+ },
+
+ _create: function() {
+ this._on({
+ mouseover: "open",
+ focusin: "open"
+ });
+
+ // IDs of generated tooltips, needed for destroy
+ this.tooltips = {};
+ // IDs of parent tooltips where we removed the title attribute
+ this.parents = {};
+
+ if ( this.options.disabled ) {
+ this._disable();
+ }
+ },
+
+ _setOption: function( key, value ) {
+ var that = this;
+
+ if ( key === "disabled" ) {
+ this[ value ? "_disable" : "_enable" ]();
+ this.options[ key ] = value;
+ // disable element style changes
+ return;
+ }
+
+ this._super( key, value );
+
+ if ( key === "content" ) {
+ $.each( this.tooltips, function( id, element ) {
+ that._updateContent( element );
+ });
+ }
+ },
+
+ _disable: function() {
+ var that = this;
+
+ // close open tooltips
+ $.each( this.tooltips, function( id, element ) {
+ var event = $.Event( "blur" );
+ event.target = event.currentTarget = element[0];
+ that.close( event, true );
+ });
+
+ // remove title attributes to prevent native tooltips
+ this.element.find( this.options.items ).addBack().each(function() {
+ var element = $( this );
+ if ( element.is( "[title]" ) ) {
+ element
+ .data( "ui-tooltip-title", element.attr( "title" ) )
+ .attr( "title", "" );
+ }
+ });
+ },
+
+ _enable: function() {
+ // restore title attributes
+ this.element.find( this.options.items ).addBack().each(function() {
+ var element = $( this );
+ if ( element.data( "ui-tooltip-title" ) ) {
+ element.attr( "title", element.data( "ui-tooltip-title" ) );
+ }
+ });
+ },
+
+ open: function( event ) {
+ var that = this,
+ target = $( event ? event.target : this.element )
+ // we need closest here due to mouseover bubbling,
+ // but always pointing at the same event target
+ .closest( this.options.items );
+
+ // No element to show a tooltip for or the tooltip is already open
+ if ( !target.length || target.data( "ui-tooltip-id" ) ) {
+ return;
+ }
+
+ if ( target.attr( "title" ) ) {
+ target.data( "ui-tooltip-title", target.attr( "title" ) );
+ }
+
+ target.data( "ui-tooltip-open", true );
+
+ // kill parent tooltips, custom or native, for hover
+ if ( event && event.type === "mouseover" ) {
+ target.parents().each(function() {
+ var parent = $( this ),
+ blurEvent;
+ if ( parent.data( "ui-tooltip-open" ) ) {
+ blurEvent = $.Event( "blur" );
+ blurEvent.target = blurEvent.currentTarget = this;
+ that.close( blurEvent, true );
+ }
+ if ( parent.attr( "title" ) ) {
+ parent.uniqueId();
+ that.parents[ this.id ] = {
+ element: this,
+ title: parent.attr( "title" )
+ };
+ parent.attr( "title", "" );
+ }
+ });
+ }
+
+ this._updateContent( target, event );
+ },
+
+ _updateContent: function( target, event ) {
+ var content,
+ contentOption = this.options.content,
+ that = this,
+ eventType = event ? event.type : null;
+
+ if ( typeof contentOption === "string" ) {
+ return this._open( event, target, contentOption );
+ }
+
+ content = contentOption.call( target[0], function( response ) {
+ // ignore async response if tooltip was closed already
+ if ( !target.data( "ui-tooltip-open" ) ) {
+ return;
+ }
+ // IE may instantly serve a cached response for ajax requests
+ // delay this call to _open so the other call to _open runs first
+ that._delay(function() {
+ // jQuery creates a special event for focusin when it doesn't
+ // exist natively. To improve performance, the native event
+ // object is reused and the type is changed. Therefore, we can't
+ // rely on the type being correct after the event finished
+ // bubbling, so we set it back to the previous value. (#8740)
+ if ( event ) {
+ event.type = eventType;
+ }
+ this._open( event, target, response );
+ });
+ });
+ if ( content ) {
+ this._open( event, target, content );
+ }
+ },
+
+ _open: function( event, target, content ) {
+ var tooltip, events, delayedShow,
+ positionOption = $.extend( {}, this.options.position );
+
+ if ( !content ) {
+ return;
+ }
+
+ // Content can be updated multiple times. If the tooltip already
+ // exists, then just update the content and bail.
+ tooltip = this._find( target );
+ if ( tooltip.length ) {
+ tooltip.find( ".ui-tooltip-content" ).html( content );
+ return;
+ }
+
+ // if we have a title, clear it to prevent the native tooltip
+ // we have to check first to avoid defining a title if none exists
+ // (we don't want to cause an element to start matching [title])
+ //
+ // We use removeAttr only for key events, to allow IE to export the correct
+ // accessible attributes. For mouse events, set to empty string to avoid
+ // native tooltip showing up (happens only when removing inside mouseover).
+ if ( target.is( "[title]" ) ) {
+ if ( event && event.type === "mouseover" ) {
+ target.attr( "title", "" );
+ } else {
+ target.removeAttr( "title" );
+ }
+ }
+
+ tooltip = this._tooltip( target );
+ addDescribedBy( target, tooltip.attr( "id" ) );
+ tooltip.find( ".ui-tooltip-content" ).html( content );
+
+ function position( event ) {
+ positionOption.of = event;
+ if ( tooltip.is( ":hidden" ) ) {
+ return;
+ }
+ tooltip.position( positionOption );
+ }
+ if ( this.options.track && event && /^mouse/.test( event.type ) ) {
+ this._on( this.document, {
+ mousemove: position
+ });
+ // trigger once to override element-relative positioning
+ position( event );
+ } else {
+ tooltip.position( $.extend({
+ of: target
+ }, this.options.position ) );
+ }
+
+ tooltip.hide();
+
+ this._show( tooltip, this.options.show );
+ // Handle tracking tooltips that are shown with a delay (#8644). As soon
+ // as the tooltip is visible, position the tooltip using the most recent
+ // event.
+ if ( this.options.show && this.options.show.delay ) {
+ delayedShow = this.delayedShow = setInterval(function() {
+ if ( tooltip.is( ":visible" ) ) {
+ position( positionOption.of );
+ clearInterval( delayedShow );
+ }
+ }, $.fx.interval );
+ }
+
+ this._trigger( "open", event, { tooltip: tooltip } );
+
+ events = {
+ keyup: function( event ) {
+ if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
+ var fakeEvent = $.Event(event);
+ fakeEvent.currentTarget = target[0];
+ this.close( fakeEvent, true );
+ }
+ },
+ remove: function() {
+ this._removeTooltip( tooltip );
+ }
+ };
+ if ( !event || event.type === "mouseover" ) {
+ events.mouseleave = "close";
+ }
+ if ( !event || event.type === "focusin" ) {
+ events.focusout = "close";
+ }
+ this._on( true, target, events );
+ },
+
+ close: function( event ) {
+ var that = this,
+ target = $( event ? event.currentTarget : this.element ),
+ tooltip = this._find( target );
+
+ // disabling closes the tooltip, so we need to track when we're closing
+ // to avoid an infinite loop in case the tooltip becomes disabled on close
+ if ( this.closing ) {
+ return;
+ }
+
+ // Clear the interval for delayed tracking tooltips
+ clearInterval( this.delayedShow );
+
+ // only set title if we had one before (see comment in _open())
+ if ( target.data( "ui-tooltip-title" ) ) {
+ target.attr( "title", target.data( "ui-tooltip-title" ) );
+ }
+
+ removeDescribedBy( target );
+
+ tooltip.stop( true );
+ this._hide( tooltip, this.options.hide, function() {
+ that._removeTooltip( $( this ) );
+ });
+
+ target.removeData( "ui-tooltip-open" );
+ this._off( target, "mouseleave focusout keyup" );
+ // Remove 'remove' binding only on delegated targets
+ if ( target[0] !== this.element[0] ) {
+ this._off( target, "remove" );
+ }
+ this._off( this.document, "mousemove" );
+
+ if ( event && event.type === "mouseleave" ) {
+ $.each( this.parents, function( id, parent ) {
+ $( parent.element ).attr( "title", parent.title );
+ delete that.parents[ id ];
+ });
+ }
+
+ this.closing = true;
+ this._trigger( "close", event, { tooltip: tooltip } );
+ this.closing = false;
+ },
+
+ _tooltip: function( element ) {
+ var id = "ui-tooltip-" + increments++,
+ tooltip = $( "<div>" )
+ .attr({
+ id: id,
+ role: "tooltip"
+ })
+ .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
+ ( this.options.tooltipClass || "" ) );
+ $( "<div>" )
+ .addClass( "ui-tooltip-content" )
+ .appendTo( tooltip );
+ tooltip.appendTo( this.document[0].body );
+ this.tooltips[ id ] = element;
+ return tooltip;
+ },
+
+ _find: function( target ) {
+ var id = target.data( "ui-tooltip-id" );
+ return id ? $( "#" + id ) : $();
+ },
+
+ _removeTooltip: function( tooltip ) {
+ tooltip.remove();
+ delete this.tooltips[ tooltip.attr( "id" ) ];
+ },
+
+ _destroy: function() {
+ var that = this;
+
+ // close open tooltips
+ $.each( this.tooltips, function( id, element ) {
+ // Delegate to close method to handle common cleanup
+ var event = $.Event( "blur" );
+ event.target = event.currentTarget = element[0];
+ that.close( event, true );
+
+ // Remove immediately; destroying an open tooltip doesn't use the
+ // hide animation
+ $( "#" + id ).remove();
+
+ // Restore the title
+ if ( element.data( "ui-tooltip-title" ) ) {
+ element.attr( "title", element.data( "ui-tooltip-title" ) );
+ element.removeData( "ui-tooltip-title" );
+ }
+ });
+ }
+});
+
+}( jQuery ) );
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/jquery-ui.min.js b/lib/prado/framework/Web/Javascripts/source/jquery/jquery-ui.min.js
new file mode 100644
index 0000000..6afd615
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/jquery-ui.min.js
@@ -0,0 +1,12 @@
+/*! jQuery UI - v1.10.4 - 2014-01-17
+* http://jqueryui.com
+* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+(function(t,e){function i(e,i){var n,o,a,r=e.nodeName.toLowerCase();return"area"===r?(n=e.parentNode,o=n.name,e.href&&o&&"map"===n.nodeName.toLowerCase()?(a=t("img[usemap=#"+o+"]")[0],!!a&&s(a)):!1):(/input|select|textarea|button|object/.test(r)?!e.disabled:"a"===r?e.href||i:i)&&s(e)}function s(e){return t.expr.filters.visible(e)&&!t(e).parents().addBack().filter(function(){return"hidden"===t.css(this,"visibility")}).length}var n=0,o=/^ui-id-\d+$/;t.ui=t.ui||{},t.extend(t.ui,{version:"1.10.4",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),t.fn.extend({focus:function(e){return function(i,s){return"number"==typeof i?this.each(function(){var e=this;setTimeout(function(){t(e).focus(),s&&s.call(e)},i)}):e.apply(this,arguments)}}(t.fn.focus),scrollParent:function(){var e;return e=t.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(t.css(this,"position"))&&/(auto|scroll)/.test(t.css(this,"overflow")+t.css(this,"overflow-y")+t.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(t.css(this,"overflow")+t.css(this,"overflow-y")+t.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!e.length?t(document):e},zIndex:function(i){if(i!==e)return this.css("zIndex",i);if(this.length)for(var s,n,o=t(this[0]);o.length&&o[0]!==document;){if(s=o.css("position"),("absolute"===s||"relative"===s||"fixed"===s)&&(n=parseInt(o.css("zIndex"),10),!isNaN(n)&&0!==n))return n;o=o.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++n)})},removeUniqueId:function(){return this.each(function(){o.test(this.id)&&t(this).removeAttr("id")})}}),t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])},focusable:function(e){return i(e,!isNaN(t.attr(e,"tabindex")))},tabbable:function(e){var s=t.attr(e,"tabindex"),n=isNaN(s);return(n||s>=0)&&i(e,!n)}}),t("<a>").outerWidth(1).jquery||t.each(["Width","Height"],function(i,s){function n(e,i,s,n){return t.each(o,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),n&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var o="Width"===s?["Left","Right"]:["Top","Bottom"],a=s.toLowerCase(),r={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+s]=function(i){return i===e?r["inner"+s].call(this):this.each(function(){t(this).css(a,n(this,i)+"px")})},t.fn["outer"+s]=function(e,i){return"number"!=typeof e?r["outer"+s].call(this,e):this.each(function(){t(this).css(a,n(this,e,!0,i)+"px")})}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(t.fn.removeData=function(e){return function(i){return arguments.length?e.call(this,t.camelCase(i)):e.call(this)}}(t.fn.removeData)),t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),t.support.selectstart="onselectstart"in document.createElement("div"),t.fn.extend({disableSelection:function(){return this.bind((t.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(t){t.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),t.extend(t.ui,{plugin:{add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i){var s,n=t.plugins[e];if(n&&t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType)for(s=0;n.length>s;s++)t.options[n[s][0]]&&n[s][1].apply(t.element,i)}},hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)}})})(jQuery),function(t,e){var i=0,s=Array.prototype.slice,n=t.cleanData;t.cleanData=function(e){for(var i,s=0;null!=(i=e[s]);s++)try{t(i).triggerHandler("remove")}catch(o){}n(e)},t.widget=function(i,s,n){var o,a,r,h,l={},c=i.split(".")[0];i=i.split(".")[1],o=c+"-"+i,n||(n=s,s=t.Widget),t.expr[":"][o.toLowerCase()]=function(e){return!!t.data(e,o)},t[c]=t[c]||{},a=t[c][i],r=t[c][i]=function(t,i){return this._createWidget?(arguments.length&&this._createWidget(t,i),e):new r(t,i)},t.extend(r,a,{version:n.version,_proto:t.extend({},n),_childConstructors:[]}),h=new s,h.options=t.widget.extend({},h.options),t.each(n,function(i,n){return t.isFunction(n)?(l[i]=function(){var t=function(){return s.prototype[i].apply(this,arguments)},e=function(t){return s.prototype[i].apply(this,t)};return function(){var i,s=this._super,o=this._superApply;return this._super=t,this._superApply=e,i=n.apply(this,arguments),this._super=s,this._superApply=o,i}}(),e):(l[i]=n,e)}),r.prototype=t.widget.extend(h,{widgetEventPrefix:a?h.widgetEventPrefix||i:i},l,{constructor:r,namespace:c,widgetName:i,widgetFullName:o}),a?(t.each(a._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,r,i._proto)}),delete a._childConstructors):s._childConstructors.push(r),t.widget.bridge(i,r)},t.widget.extend=function(i){for(var n,o,a=s.call(arguments,1),r=0,h=a.length;h>r;r++)for(n in a[r])o=a[r][n],a[r].hasOwnProperty(n)&&o!==e&&(i[n]=t.isPlainObject(o)?t.isPlainObject(i[n])?t.widget.extend({},i[n],o):t.widget.extend({},o):o);return i},t.widget.bridge=function(i,n){var o=n.prototype.widgetFullName||i;t.fn[i]=function(a){var r="string"==typeof a,h=s.call(arguments,1),l=this;return a=!r&&h.length?t.widget.extend.apply(null,[a].concat(h)):a,r?this.each(function(){var s,n=t.data(this,o);return n?t.isFunction(n[a])&&"_"!==a.charAt(0)?(s=n[a].apply(n,h),s!==n&&s!==e?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):e):t.error("no such method '"+a+"' for "+i+" widget instance"):t.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+a+"'")}):this.each(function(){var e=t.data(this,o);e?e.option(a||{})._init():t.data(this,o,new n(a,this))}),l}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(e,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this.bindings=t(),this.hoverable=t(),this.focusable=t(),s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:t.noop,_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(t.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:t.noop,widget:function(){return this.element},option:function(i,s){var n,o,a,r=i;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof i)if(r={},n=i.split("."),i=n.shift(),n.length){for(o=r[i]=t.widget.extend({},this.options[i]),a=0;n.length-1>a;a++)o[n[a]]=o[n[a]]||{},o=o[n[a]];if(i=n.pop(),1===arguments.length)return o[i]===e?null:o[i];o[i]=s}else{if(1===arguments.length)return this.options[i]===e?null:this.options[i];r[i]=s}return this._setOptions(r),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return this.options[t]=e,"disabled"===t&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!e).attr("aria-disabled",e),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,n){var o,a=this;"boolean"!=typeof i&&(n=s,s=i,i=!1),n?(s=o=t(s),this.bindings=this.bindings.add(s)):(n=s,s=this.element,o=this.widget()),t.each(n,function(n,r){function h(){return i||a.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof r?a[r]:r).apply(a,arguments):e}"string"!=typeof r&&(h.guid=r.guid=r.guid||h.guid||t.guid++);var l=n.match(/^(\w+)\s*(.*)$/),c=l[1]+a.eventNamespace,u=l[2];u?o.delegate(u,c,h):s.bind(c,h)})},_off:function(t,e){e=(e||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.unbind(e).undelegate(e)},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){t(e.currentTarget).addClass("ui-state-hover")},mouseleave:function(e){t(e.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){t(e.currentTarget).addClass("ui-state-focus")},focusout:function(e){t(e.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}})}(jQuery),function(t){var e=!1;t(document).mouseup(function(){e=!1}),t.widget("ui.mouse",{version:"1.10.4",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.bind("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).bind("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):undefined}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&t(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(i){if(!e){this._mouseStarted&&this._mouseUp(i),this._mouseDownEvent=i;var s=this,n=1===i.which,o="string"==typeof this.options.cancel&&i.target.nodeName?t(i.target).closest(this.options.cancel).length:!1;return n&&!o&&this._mouseCapture(i)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){s.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(i)&&this._mouseDelayMet(i)&&(this._mouseStarted=this._mouseStart(i)!==!1,!this._mouseStarted)?(i.preventDefault(),!0):(!0===t.data(i.target,this.widgetName+".preventClickEvent")&&t.removeData(i.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return s._mouseMove(t)},this._mouseUpDelegate=function(t){return s._mouseUp(t)},t(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),i.preventDefault(),e=!0,!0)):!0}},_mouseMove:function(e){return t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button?this._mouseUp(e):this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){return t(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),!1},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})}(jQuery),function(t){t.widget("ui.draggable",t.ui.mouse,{version:"1.10.4",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"!==this.options.helper||/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy()},_mouseCapture:function(e){var i=this.options;return this.helper||i.disabled||t(e.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(e),this.handle?(t(i.iframeFix===!0?"iframe":i.iframeFix).each(function(){t("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>").css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(t(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(e){var i=this.options;return this.helper=this._createHelper(e),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),t.ui.ddmanager&&(t.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offsetParent=this.helper.offsetParent(),this.offsetParentCssPosition=this.offsetParent.css("position"),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},this.offset.scroll=!1,t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",e)===!1?(this._clear(),!1):(this._cacheHelperProportions(),t.ui.ddmanager&&!i.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this._mouseDrag(e,!0),t.ui.ddmanager&&t.ui.ddmanager.dragStart(this,e),!0)},_mouseDrag:function(e,i){if("fixed"===this.offsetParentCssPosition&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",e,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),!1},_mouseStop:function(e){var i=this,s=!1;return t.ui.ddmanager&&!this.options.dropBehaviour&&(s=t.ui.ddmanager.drop(this,e)),this.dropped&&(s=this.dropped,this.dropped=!1),"original"!==this.options.helper||t.contains(this.element[0].ownerDocument,this.element[0])?("invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||t.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?t(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",e)!==!1&&i._clear()}):this._trigger("stop",e)!==!1&&this._clear(),!1):!1},_mouseUp:function(e){return t("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),t.ui.ddmanager&&t.ui.ddmanager.dragStop(this,e),t.ui.mouse.prototype._mouseUp.call(this,e)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(e){return this.options.handle?!!t(e.target).closest(this.element.find(this.options.handle)).length:!0},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return s.parents("body").length||s.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s[0]===this.element[0]||/(fixed|absolute)/.test(s.css("position"))||s.css("position","absolute"),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.element.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;return n.containment?"window"===n.containment?(this.containment=[t(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,t(window).scrollLeft()+t(window).width()-this.helperProportions.width-this.margins.left,t(window).scrollTop()+(t(window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],undefined):"document"===n.containment?(this.containment=[0,0,t(document).width()-this.helperProportions.width-this.margins.left,(t(document).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],undefined):n.containment.constructor===Array?(this.containment=n.containment,undefined):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=t(n.containment),s=i[0],s&&(e="hidden"!==i.css("overflow"),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(e?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=i),undefined):(this.containment=null,undefined)},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent;return this.offset.scroll||(this.offset.scroll={top:n.scrollTop(),left:n.scrollLeft()}),{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():this.offset.scroll.top)*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():this.offset.scroll.left)*s}},_generatePosition:function(e){var i,s,n,o,a=this.options,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=e.pageX,l=e.pageY;return this.offset.scroll||(this.offset.scroll={top:r.scrollTop(),left:r.scrollLeft()}),this.originalPosition&&(this.containment&&(this.relative_container?(s=this.relative_container.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,e.pageX-this.offset.click.left<i[0]&&(h=i[0]+this.offset.click.left),e.pageY-this.offset.click.top<i[1]&&(l=i[1]+this.offset.click.top),e.pageX-this.offset.click.left>i[2]&&(h=i[2]+this.offset.click.left),e.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),a.grid&&(n=a.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/a.grid[1])*a.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-a.grid[1]:n+a.grid[1]:n,o=a.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/a.grid[0])*a.grid[0]:this.originalPageX,h=i?o-this.offset.click.left>=i[0]||o-this.offset.click.left>i[2]?o:o-this.offset.click.left>=i[0]?o-a.grid[0]:o+a.grid[0]:o)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():this.offset.scroll.left)}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(e,i,s){return s=s||this._uiHash(),t.ui.plugin.call(this,e,[i,s]),"drag"===e&&(this.positionAbs=this._convertPositionTo("absolute")),t.Widget.prototype._trigger.call(this,e,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),t.ui.plugin.add("draggable","connectToSortable",{start:function(e,i){var s=t(this).data("ui-draggable"),n=s.options,o=t.extend({},i,{item:s.element});s.sortables=[],t(n.connectToSortable).each(function(){var i=t.data(this,"ui-sortable");i&&!i.options.disabled&&(s.sortables.push({instance:i,shouldRevert:i.options.revert}),i.refreshPositions(),i._trigger("activate",e,o))})},stop:function(e,i){var s=t(this).data("ui-draggable"),n=t.extend({},i,{item:s.element});t.each(s.sortables,function(){this.instance.isOver?(this.instance.isOver=0,s.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=this.shouldRevert),this.instance._mouseStop(e),this.instance.options.helper=this.instance.options._helper,"original"===s.options.helper&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",e,n))})},drag:function(e,i){var s=t(this).data("ui-draggable"),n=this;t.each(s.sortables,function(){var o=!1,a=this;this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this.instance._intersectsWith(this.instance.containerCache)&&(o=!0,t.each(s.sortables,function(){return this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this!==a&&this.instance._intersectsWith(this.instance.containerCache)&&t.contains(a.instance.element[0],this.instance.element[0])&&(o=!1),o})),o?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=t(n).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return i.helper[0]},e.target=this.instance.currentItem[0],this.instance._mouseCapture(e,!0),this.instance._mouseStart(e,!0,!0),this.instance.offset.click.top=s.offset.click.top,this.instance.offset.click.left=s.offset.click.left,this.instance.offset.parent.left-=s.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=s.offset.parent.top-this.instance.offset.parent.top,s._trigger("toSortable",e),s.dropped=this.instance.element,s.currentItem=s.element,this.instance.fromOutside=s),this.instance.currentItem&&this.instance._mouseDrag(e)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",e,this.instance._uiHash(this.instance)),this.instance._mouseStop(e,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),s._trigger("fromSortable",e),s.dropped=!1)})}}),t.ui.plugin.add("draggable","cursor",{start:function(){var e=t("body"),i=t(this).data("ui-draggable").options;e.css("cursor")&&(i._cursor=e.css("cursor")),e.css("cursor",i.cursor)},stop:function(){var e=t(this).data("ui-draggable").options;e._cursor&&t("body").css("cursor",e._cursor)}}),t.ui.plugin.add("draggable","opacity",{start:function(e,i){var s=t(i.helper),n=t(this).data("ui-draggable").options;s.css("opacity")&&(n._opacity=s.css("opacity")),s.css("opacity",n.opacity)},stop:function(e,i){var s=t(this).data("ui-draggable").options;s._opacity&&t(i.helper).css("opacity",s._opacity)}}),t.ui.plugin.add("draggable","scroll",{start:function(){var e=t(this).data("ui-draggable");e.scrollParent[0]!==document&&"HTML"!==e.scrollParent[0].tagName&&(e.overflowOffset=e.scrollParent.offset())},drag:function(e){var i=t(this).data("ui-draggable"),s=i.options,n=!1;i.scrollParent[0]!==document&&"HTML"!==i.scrollParent[0].tagName?(s.axis&&"x"===s.axis||(i.overflowOffset.top+i.scrollParent[0].offsetHeight-e.pageY<s.scrollSensitivity?i.scrollParent[0].scrollTop=n=i.scrollParent[0].scrollTop+s.scrollSpeed:e.pageY-i.overflowOffset.top<s.scrollSensitivity&&(i.scrollParent[0].scrollTop=n=i.scrollParent[0].scrollTop-s.scrollSpeed)),s.axis&&"y"===s.axis||(i.overflowOffset.left+i.scrollParent[0].offsetWidth-e.pageX<s.scrollSensitivity?i.scrollParent[0].scrollLeft=n=i.scrollParent[0].scrollLeft+s.scrollSpeed:e.pageX-i.overflowOffset.left<s.scrollSensitivity&&(i.scrollParent[0].scrollLeft=n=i.scrollParent[0].scrollLeft-s.scrollSpeed))):(s.axis&&"x"===s.axis||(e.pageY-t(document).scrollTop()<s.scrollSensitivity?n=t(document).scrollTop(t(document).scrollTop()-s.scrollSpeed):t(window).height()-(e.pageY-t(document).scrollTop())<s.scrollSensitivity&&(n=t(document).scrollTop(t(document).scrollTop()+s.scrollSpeed))),s.axis&&"y"===s.axis||(e.pageX-t(document).scrollLeft()<s.scrollSensitivity?n=t(document).scrollLeft(t(document).scrollLeft()-s.scrollSpeed):t(window).width()-(e.pageX-t(document).scrollLeft())<s.scrollSensitivity&&(n=t(document).scrollLeft(t(document).scrollLeft()+s.scrollSpeed)))),n!==!1&&t.ui.ddmanager&&!s.dropBehaviour&&t.ui.ddmanager.prepareOffsets(i,e)}}),t.ui.plugin.add("draggable","snap",{start:function(){var e=t(this).data("ui-draggable"),i=e.options;e.snapElements=[],t(i.snap.constructor!==String?i.snap.items||":data(ui-draggable)":i.snap).each(function(){var i=t(this),s=i.offset();this!==e.element[0]&&e.snapElements.push({item:this,width:i.outerWidth(),height:i.outerHeight(),top:s.top,left:s.left})})},drag:function(e,i){var s,n,o,a,r,h,l,c,u,d,p=t(this).data("ui-draggable"),f=p.options,g=f.snapTolerance,m=i.offset.left,v=m+p.helperProportions.width,_=i.offset.top,b=_+p.helperProportions.height;for(u=p.snapElements.length-1;u>=0;u--)r=p.snapElements[u].left,h=r+p.snapElements[u].width,l=p.snapElements[u].top,c=l+p.snapElements[u].height,r-g>v||m>h+g||l-g>b||_>c+g||!t.contains(p.snapElements[u].item.ownerDocument,p.snapElements[u].item)?(p.snapElements[u].snapping&&p.options.snap.release&&p.options.snap.release.call(p.element,e,t.extend(p._uiHash(),{snapItem:p.snapElements[u].item})),p.snapElements[u].snapping=!1):("inner"!==f.snapMode&&(s=g>=Math.abs(l-b),n=g>=Math.abs(c-_),o=g>=Math.abs(r-v),a=g>=Math.abs(h-m),s&&(i.position.top=p._convertPositionTo("relative",{top:l-p.helperProportions.height,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:c,left:0}).top-p.margins.top),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r-p.helperProportions.width}).left-p.margins.left),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h}).left-p.margins.left)),d=s||n||o||a,"outer"!==f.snapMode&&(s=g>=Math.abs(l-_),n=g>=Math.abs(c-b),o=g>=Math.abs(r-m),a=g>=Math.abs(h-v),s&&(i.position.top=p._convertPositionTo("relative",{top:l,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:c-p.helperProportions.height,left:0}).top-p.margins.top),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r}).left-p.margins.left),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h-p.helperProportions.width}).left-p.margins.left)),!p.snapElements[u].snapping&&(s||n||o||a||d)&&p.options.snap.snap&&p.options.snap.snap.call(p.element,e,t.extend(p._uiHash(),{snapItem:p.snapElements[u].item})),p.snapElements[u].snapping=s||n||o||a||d)}}),t.ui.plugin.add("draggable","stack",{start:function(){var e,i=this.data("ui-draggable").options,s=t.makeArray(t(i.stack)).sort(function(e,i){return(parseInt(t(e).css("zIndex"),10)||0)-(parseInt(t(i).css("zIndex"),10)||0)});s.length&&(e=parseInt(t(s[0]).css("zIndex"),10)||0,t(s).each(function(i){t(this).css("zIndex",e+i)}),this.css("zIndex",e+s.length))}}),t.ui.plugin.add("draggable","zIndex",{start:function(e,i){var s=t(i.helper),n=t(this).data("ui-draggable").options;s.css("zIndex")&&(n._zIndex=s.css("zIndex")),s.css("zIndex",n.zIndex)},stop:function(e,i){var s=t(this).data("ui-draggable").options;s._zIndex&&t(i.helper).css("zIndex",s._zIndex)}})}(jQuery),function(t){function e(t,e,i){return t>e&&e+i>t}t.widget("ui.droppable",{version:"1.10.4",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var e,i=this.options,s=i.accept;
+this.isover=!1,this.isout=!0,this.accept=t.isFunction(s)?s:function(t){return t.is(s)},this.proportions=function(){return arguments.length?(e=arguments[0],undefined):e?e:e={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},t.ui.ddmanager.droppables[i.scope]=t.ui.ddmanager.droppables[i.scope]||[],t.ui.ddmanager.droppables[i.scope].push(this),i.addClasses&&this.element.addClass("ui-droppable")},_destroy:function(){for(var e=0,i=t.ui.ddmanager.droppables[this.options.scope];i.length>e;e++)i[e]===this&&i.splice(e,1);this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(e,i){"accept"===e&&(this.accept=t.isFunction(i)?i:function(t){return t.is(i)}),t.Widget.prototype._setOption.apply(this,arguments)},_activate:function(e){var i=t.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",e,this.ui(i))},_deactivate:function(e){var i=t.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",e,this.ui(i))},_over:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",e,this.ui(i)))},_out:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",e,this.ui(i)))},_drop:function(e,i){var s=i||t.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var e=t.data(this,"ui-droppable");return e.options.greedy&&!e.options.disabled&&e.options.scope===s.options.scope&&e.accept.call(e.element[0],s.currentItem||s.element)&&t.ui.intersect(s,t.extend(e,{offset:e.element.offset()}),e.options.tolerance)?(n=!0,!1):undefined}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",e,this.ui(s)),this.element):!1):!1},ui:function(t){return{draggable:t.currentItem||t.element,helper:t.helper,position:t.position,offset:t.positionAbs}}}),t.ui.intersect=function(t,i,s){if(!i.offset)return!1;var n,o,a=(t.positionAbs||t.position.absolute).left,r=(t.positionAbs||t.position.absolute).top,h=a+t.helperProportions.width,l=r+t.helperProportions.height,c=i.offset.left,u=i.offset.top,d=c+i.proportions().width,p=u+i.proportions().height;switch(s){case"fit":return a>=c&&d>=h&&r>=u&&p>=l;case"intersect":return a+t.helperProportions.width/2>c&&d>h-t.helperProportions.width/2&&r+t.helperProportions.height/2>u&&p>l-t.helperProportions.height/2;case"pointer":return n=(t.positionAbs||t.position.absolute).left+(t.clickOffset||t.offset.click).left,o=(t.positionAbs||t.position.absolute).top+(t.clickOffset||t.offset.click).top,e(o,u,i.proportions().height)&&e(n,c,i.proportions().width);case"touch":return(r>=u&&p>=r||l>=u&&p>=l||u>r&&l>p)&&(a>=c&&d>=a||h>=c&&d>=h||c>a&&h>d);default:return!1}},t.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,i){var s,n,o=t.ui.ddmanager.droppables[e.options.scope]||[],a=i?i.type:null,r=(e.currentItem||e.element).find(":data(ui-droppable)").addBack();t:for(s=0;o.length>s;s++)if(!(o[s].options.disabled||e&&!o[s].accept.call(o[s].element[0],e.currentItem||e.element))){for(n=0;r.length>n;n++)if(r[n]===o[s].element[0]){o[s].proportions().height=0;continue t}o[s].visible="none"!==o[s].element.css("display"),o[s].visible&&("mousedown"===a&&o[s]._activate.call(o[s],i),o[s].offset=o[s].element.offset(),o[s].proportions({width:o[s].element[0].offsetWidth,height:o[s].element[0].offsetHeight}))}},drop:function(e,i){var s=!1;return t.each((t.ui.ddmanager.droppables[e.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&t.ui.intersect(e,this,this.options.tolerance)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],e.currentItem||e.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(e,i){e.element.parentsUntil("body").bind("scroll.droppable",function(){e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)})},drag:function(e,i){e.options.refreshPositions&&t.ui.ddmanager.prepareOffsets(e,i),t.each(t.ui.ddmanager.droppables[e.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,o,a=t.ui.intersect(e,this,this.options.tolerance),r=!a&&this.isover?"isout":a&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,o=this.element.parents(":data(ui-droppable)").filter(function(){return t.data(this,"ui-droppable").options.scope===n}),o.length&&(s=t.data(o[0],"ui-droppable"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(e,i){e.element.parentsUntil("body").unbind("scroll.droppable"),e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)}}}(jQuery),function(t){function e(t){return parseInt(t,10)||0}function i(t){return!isNaN(parseInt(t,10))}t.widget("ui.resizable",t.ui.mouse,{version:"1.10.4",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_create:function(){var e,i,s,n,o,a=this,r=this.options;if(this.element.addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(t("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.data("ui-resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),e=this.handles.split(","),this.handles={},i=0;e.length>i;i++)s=t.trim(e[i]),o="ui-resizable-"+s,n=t("<div class='ui-resizable-handle "+o+"'></div>"),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String&&(this.handles[i]=t(this.handles[i],this.element).show()),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),t(this.handles[i]).length},this._renderAxis(this.element),this._handles=t(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){a.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),a.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),t(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(t(this).removeClass("ui-resizable-autohide"),a._handles.show())}).mouseleave(function(){r.disabled||a.resizing||(t(this).addClass("ui-resizable-autohide"),a._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(i){var s,n,o,a=this.options,r=this.element.position(),h=this.element;return this.resizing=!0,/absolute/.test(h.css("position"))?h.css({position:"absolute",top:h.css("top"),left:h.css("left")}):h.is(".ui-draggable")&&h.css({position:"absolute",top:r.top,left:r.left}),this._renderProxy(),s=e(this.helper.css("left")),n=e(this.helper.css("top")),a.containment&&(s+=t(a.containment).scrollLeft()||0,n+=t(a.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:s,top:n},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:h.width(),height:h.height()},this.originalSize=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalPosition={left:s,top:n},this.sizeDiff={width:h.outerWidth()-h.width(),height:h.outerHeight()-h.height()},this.originalMousePosition={left:i.pageX,top:i.pageY},this.aspectRatio="number"==typeof a.aspectRatio?a.aspectRatio:this.originalSize.width/this.originalSize.height||1,o=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===o?this.axis+"-resize":o),h.addClass("ui-resizable-resizing"),this._propagate("start",i),!0},_mouseDrag:function(e){var i,s=this.helper,n={},o=this.originalMousePosition,a=this.axis,r=this.position.top,h=this.position.left,l=this.size.width,c=this.size.height,u=e.pageX-o.left||0,d=e.pageY-o.top||0,p=this._change[a];return p?(i=p.apply(this,[e,u,d]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),this.position.top!==r&&(n.top=this.position.top+"px"),this.position.left!==h&&(n.left=this.position.left+"px"),this.size.width!==l&&(n.width=this.size.width+"px"),this.size.height!==c&&(n.height=this.size.height+"px"),s.css(n),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(n)||this._trigger("resize",e,this.ui()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&t.ui.hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null,h=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(t){var e,s,n,o,a,r=this.options;a={minWidth:i(r.minWidth)?r.minWidth:0,maxWidth:i(r.maxWidth)?r.maxWidth:1/0,minHeight:i(r.minHeight)?r.minHeight:0,maxHeight:i(r.maxHeight)?r.maxHeight:1/0},(this._aspectRatio||t)&&(e=a.minHeight*this.aspectRatio,n=a.minWidth/this.aspectRatio,s=a.maxHeight*this.aspectRatio,o=a.maxWidth/this.aspectRatio,e>a.minWidth&&(a.minWidth=e),n>a.minHeight&&(a.minHeight=n),a.maxWidth>s&&(a.maxWidth=s),a.maxHeight>o&&(a.maxHeight=o)),this._vBoundaries=a},_updateCache:function(t){this.offset=this.helper.offset(),i(t.left)&&(this.position.left=t.left),i(t.top)&&(this.position.top=t.top),i(t.height)&&(this.size.height=t.height),i(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,s=this.size,n=this.axis;return i(t.height)?t.width=t.height*this.aspectRatio:i(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===n&&(t.left=e.left+(s.width-t.width),t.top=null),"nw"===n&&(t.top=e.top+(s.height-t.height),t.left=e.left+(s.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,s=this.axis,n=i(t.width)&&e.maxWidth&&e.maxWidth<t.width,o=i(t.height)&&e.maxHeight&&e.maxHeight<t.height,a=i(t.width)&&e.minWidth&&e.minWidth>t.width,r=i(t.height)&&e.minHeight&&e.minHeight>t.height,h=this.originalPosition.left+this.originalSize.width,l=this.position.top+this.size.height,c=/sw|nw|w/.test(s),u=/nw|ne|n/.test(s);return a&&(t.width=e.minWidth),r&&(t.height=e.minHeight),n&&(t.width=e.maxWidth),o&&(t.height=e.maxHeight),a&&c&&(t.left=h-e.minWidth),n&&c&&(t.left=h-e.maxWidth),r&&u&&(t.top=l-e.minHeight),o&&u&&(t.top=l-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_proportionallyResize:function(){if(this._proportionallyResizeElements.length){var t,e,i,s,n,o=this.helper||this.element;for(t=0;this._proportionallyResizeElements.length>t;t++){if(n=this._proportionallyResizeElements[t],!this.borderDif)for(this.borderDif=[],i=[n.css("borderTopWidth"),n.css("borderRightWidth"),n.css("borderBottomWidth"),n.css("borderLeftWidth")],s=[n.css("paddingTop"),n.css("paddingRight"),n.css("paddingBottom"),n.css("paddingLeft")],e=0;i.length>e;e++)this.borderDif[e]=(parseInt(i[e],10)||0)+(parseInt(s[e],10)||0);n.css({height:o.height()-this.borderDif[0]-this.borderDif[2]||0,width:o.width()-this.borderDif[1]-this.borderDif[3]||0})}}},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("<div style='overflow:hidden;'></div>"),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).data("ui-resizable"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&t.ui.hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,c=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var i,s,n,o,a,r,h,l=t(this).data("ui-resizable"),c=l.options,u=l.element,d=c.containment,p=d instanceof t?d.get(0):/parent/.test(d)?u.parent().get(0):d;p&&(l.containerElement=t(p),/document/.test(d)||d===document?(l.containerOffset={left:0,top:0},l.containerPosition={left:0,top:0},l.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(i=t(p),s=[],t(["Top","Right","Left","Bottom"]).each(function(t,n){s[t]=e(i.css("padding"+n))}),l.containerOffset=i.offset(),l.containerPosition=i.position(),l.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},n=l.containerOffset,o=l.containerSize.height,a=l.containerSize.width,r=t.ui.hasScroll(p,"left")?p.scrollWidth:a,h=t.ui.hasScroll(p)?p.scrollHeight:o,l.parentData={element:p,left:n.left,top:n.top,width:r,height:h}))},resize:function(e){var i,s,n,o,a=t(this).data("ui-resizable"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio),a.position.top=a._helper?h.top:0),a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top,i=Math.abs((a._helper?a.offset.left-u.left:a.offset.left-u.left)+a.sizeDiff.width),s=Math.abs((a._helper?a.offset.top-u.top:a.offset.top-h.top)+a.sizeDiff.height),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o&&(i-=Math.abs(a.parentData.left)),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio))},stop:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).data("ui-resizable"),i=e.options,s=function(e){t(e).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseInt(e.width(),10),height:parseInt(e.height(),10),left:parseInt(e.css("left"),10),top:parseInt(e.css("top"),10)})})};"object"!=typeof i.alsoResize||i.alsoResize.parentNode?s(i.alsoResize):i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):t.each(i.alsoResize,function(t){s(t)})},resize:function(e,i){var s=t(this).data("ui-resizable"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0},h=function(e,s){t(e).each(function(){var e=t(this),n=t(this).data("ui-resizable-alsoresize"),o={},a=s&&s.length?s:e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(a,function(t,e){var i=(n[e]||0)+(r[e]||0);i&&i>=0&&(o[e]=i||null)}),e.css(o)})};"object"!=typeof n.alsoResize||n.alsoResize.nodeType?h(n.alsoResize):t.each(n.alsoResize,function(t,e){h(t,e)})},stop:function(){t(this).removeData("resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).data("ui-resizable");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).data("ui-resizable");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.size,n=e.originalSize,o=e.originalPosition,a=e.axis,r="number"==typeof i.grid?[i.grid,i.grid]:i.grid,h=r[0]||1,l=r[1]||1,c=Math.round((s.width-n.width)/h)*h,u=Math.round((s.height-n.height)/l)*l,d=n.width+c,p=n.height+u,f=i.maxWidth&&d>i.maxWidth,g=i.maxHeight&&p>i.maxHeight,m=i.minWidth&&i.minWidth>d,v=i.minHeight&&i.minHeight>p;i.grid=r,m&&(d+=h),v&&(p+=l),f&&(d-=h),g&&(p-=l),/^(se|s|e)$/.test(a)?(e.size.width=d,e.size.height=p):/^(ne)$/.test(a)?(e.size.width=d,e.size.height=p,e.position.top=o.top-u):/^(sw)$/.test(a)?(e.size.width=d,e.size.height=p,e.position.left=o.left-c):(p-l>0?(e.size.height=p,e.position.top=o.top-u):(e.size.height=l,e.position.top=o.top+n.height-l),d-h>0?(e.size.width=d,e.position.left=o.left-c):(e.size.width=h,e.position.left=o.left+n.width-h))}})}(jQuery),function(t){t.widget("ui.selectable",t.ui.mouse,{version:"1.10.4",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var e,i=this;this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){e=t(i.options.filter,i.element[0]),e.addClass("ui-selectee"),e.each(function(){var e=t(this),i=e.offset();t.data(this,"selectable-item",{element:this,$element:e,left:i.left,top:i.top,right:i.left+e.outerWidth(),bottom:i.top+e.outerHeight(),startselected:!1,selected:e.hasClass("ui-selected"),selecting:e.hasClass("ui-selecting"),unselecting:e.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=e.addClass("ui-selectee"),this._mouseInit(),this.helper=t("<div class='ui-selectable-helper'></div>")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(e){var i=this,s=this.options;this.opos=[e.pageX,e.pageY],this.options.disabled||(this.selectees=t(s.filter,this.element[0]),this._trigger("start",e),t(s.appendTo).append(this.helper),this.helper.css({left:e.pageX,top:e.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=t.data(this,"selectable-item");s.startselected=!0,e.metaKey||e.ctrlKey||(s.$element.removeClass("ui-selected"),s.selected=!1,s.$element.addClass("ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",e,{unselecting:s.element}))}),t(e.target).parents().addBack().each(function(){var s,n=t.data(this,"selectable-item");return n?(s=!e.metaKey&&!e.ctrlKey||!n.$element.hasClass("ui-selected"),n.$element.removeClass(s?"ui-unselecting":"ui-selected").addClass(s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",e,{selecting:n.element}):i._trigger("unselecting",e,{unselecting:n.element}),!1):undefined}))},_mouseDrag:function(e){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,o=this.opos[0],a=this.opos[1],r=e.pageX,h=e.pageY;return o>r&&(i=r,r=o,o=i),a>h&&(i=h,h=a,a=i),this.helper.css({left:o,top:a,width:r-o,height:h-a}),this.selectees.each(function(){var i=t.data(this,"selectable-item"),l=!1;i&&i.element!==s.element[0]&&("touch"===n.tolerance?l=!(i.left>r||o>i.right||i.top>h||a>i.bottom):"fit"===n.tolerance&&(l=i.left>o&&r>i.right&&i.top>a&&h>i.bottom),l?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,s._trigger("selecting",e,{selecting:i.element}))):(i.selecting&&((e.metaKey||e.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",e,{unselecting:i.element}))),i.selected&&(e.metaKey||e.ctrlKey||i.startselected||(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",e,{unselecting:i.element})))))}),!1}},_mouseStop:function(e){var i=this;return this.dragged=!1,t(".ui-unselecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");s.$element.removeClass("ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",e,{unselected:s.element})}),t(".ui-selecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");s.$element.removeClass("ui-selecting").addClass("ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",e,{selected:s.element})}),this._trigger("stop",e),this.helper.remove(),!1}})}(jQuery),function(t){function e(t,e,i){return t>e&&e+i>t}function i(t){return/left|right/.test(t.css("float"))||/inline|table-cell/.test(t.css("display"))}t.widget("ui.sortable",t.ui.mouse,{version:"1.10.4",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_create:function(){var t=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===t.axis||i(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var t=this.items.length-1;t>=0;t--)this.items[t].item.removeData(this.widgetName+"-item");return this},_setOption:function(e,i){"disabled"===e?(this.options[e]=i,this.widget().toggleClass("ui-sortable-disabled",!!i)):t.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(e,i){var s=null,n=!1,o=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(e),t(e.target).parents().each(function(){return t.data(this,o.widgetName+"-item")===o?(s=t(this),!1):undefined}),t.data(e.target,o.widgetName+"-item")===o&&(s=t(e.target)),s?!this.options.handle||i||(t(this.options.handle,s).find("*").addBack().each(function(){this===e.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(e,i,s){var n,o,a=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(e),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,a.cursorAt&&this._adjustOffsetFromHelper(a.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),a.containment&&this._setContainment(),a.cursor&&"auto"!==a.cursor&&(o=this.document.find("body"),this.storedCursor=o.css("cursor"),o.css("cursor",a.cursor),this.storedStylesheet=t("<style>*{ cursor: "+a.cursor+" !important; }</style>").appendTo(o)),a.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",a.opacity)),a.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",a.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,o,a=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY<a.scrollSensitivity?this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop+a.scrollSpeed:e.pageY-this.overflowOffset.top<a.scrollSensitivity&&(this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop-a.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-e.pageX<a.scrollSensitivity?this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft+a.scrollSpeed:e.pageX-this.overflowOffset.left<a.scrollSensitivity&&(this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft-a.scrollSpeed)):(e.pageY-t(document).scrollTop()<a.scrollSensitivity?r=t(document).scrollTop(t(document).scrollTop()-a.scrollSpeed):t(window).height()-(e.pageY-t(document).scrollTop())<a.scrollSensitivity&&(r=t(document).scrollTop(t(document).scrollTop()+a.scrollSpeed)),e.pageX-t(document).scrollLeft()<a.scrollSensitivity?r=t(document).scrollLeft(t(document).scrollLeft()-a.scrollSpeed):t(window).width()-(e.pageX-t(document).scrollLeft())<a.scrollSensitivity&&(r=t(document).scrollLeft(t(document).scrollLeft()+a.scrollSpeed))),r!==!1&&t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e)),this.positionAbs=this._convertPositionTo("absolute"),this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),i=this.items.length-1;i>=0;i--)if(s=this.items[i],n=s.item[0],o=this._intersectsWithPointer(s),o&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===o?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===o?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;
+this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),o=this.options.axis,a={};o&&"x"!==o||(a.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),o&&"y"!==o||(a.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(a,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,o=t.left,a=o+t.width,r=t.top,h=r+t.height,l=this.offset.click.top,c=this.offset.click.left,u="x"===this.options.axis||s+l>r&&h>s+l,d="y"===this.options.axis||e+c>o&&a>e+c,p=u&&d;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?p:e+this.helperProportions.width/2>o&&a>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var i="x"===this.options.axis||e(this.positionAbs.top+this.offset.click.top,t.top,t.height),s="y"===this.options.axis||e(this.positionAbs.left+this.offset.click.left,t.left,t.width),n=i&&s,o=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return n?this.floating?a&&"right"===a||"down"===o?2:1:o&&("down"===o?2:1):!1},_intersectsWithSides:function(t){var i=e(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),s=e(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),n=this._getDragVerticalDirection(),o=this._getDragHorizontalDirection();return this.floating&&o?"right"===o&&s||"left"===o&&!s:n&&("down"===n&&i||"up"===n&&!i)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){function i(){r.push(this)}var s,n,o,a,r=[],h=[],l=this._connectWith();if(l&&e)for(s=l.length-1;s>=0;s--)for(o=t(l[s]),n=o.length-1;n>=0;n--)a=t.data(o[n],this.widgetFullName),a&&a!==this&&!a.options.disabled&&h.push([t.isFunction(a.options.items)?a.options.items.call(a.element):t(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a]);for(h.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=h.length-1;s>=0;s--)h[s][0].each(i);return t(r)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,o,a,r,h,l,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&(u.push([t.isFunction(o.options.items)?o.options.items.call(o.element[0],e,{item:this.currentItem}):t(o.options.items,o.element),o]),this.containers.push(o));for(i=u.length-1;i>=0;i--)for(a=u[i][1],r=u[i][0],s=0,l=r.length;l>s;s++)h=t(r[s]),h.data(this.widgetName+"-item",a),c.push({item:h,instance:a,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,o;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),o=n.offset(),s.left=o.left,s.top=o.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)o=this.containers[i].element.offset(),this.containers[i].containerCache.left=o.left,this.containers[i].containerCache.top=o.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t("<"+s+">",e.document[0]).addClass(i||e.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===s?e.currentItem.children().each(function(){t("<td>&#160;</td>",e.document[0]).attr("colspan",t(this).attr("colspan")||1).appendTo(n)}):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_contactContainers:function(s){var n,o,a,r,h,l,c,u,d,p,f=null,g=null;for(n=this.containers.length-1;n>=0;n--)if(!t.contains(this.currentItem[0],this.containers[n].element[0]))if(this._intersectsWith(this.containers[n].containerCache)){if(f&&t.contains(this.containers[n].element[0],f.element[0]))continue;f=this.containers[n],g=n}else this.containers[n].containerCache.over&&(this.containers[n]._trigger("out",s,this._uiHash(this)),this.containers[n].containerCache.over=0);if(f)if(1===this.containers.length)this.containers[g].containerCache.over||(this.containers[g]._trigger("over",s,this._uiHash(this)),this.containers[g].containerCache.over=1);else{for(a=1e4,r=null,p=f.floating||i(this.currentItem),h=p?"left":"top",l=p?"width":"height",c=this.positionAbs[h]+this.offset.click[h],o=this.items.length-1;o>=0;o--)t.contains(this.containers[g].element[0],this.items[o].item[0])&&this.items[o].item[0]!==this.currentItem[0]&&(!p||e(this.positionAbs.top+this.offset.click.top,this.items[o].top,this.items[o].height))&&(u=this.items[o].item.offset()[h],d=!1,Math.abs(u-c)>Math.abs(u+this.items[o][l]-c)&&(d=!0,u+=this.items[o][l]),a>Math.abs(u-c)&&(a=Math.abs(u-c),r=this.items[o],this.direction=d?"up":"down"));if(!r&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[g])return;r?this._rearrange(s,r,null,!0):this._rearrange(s,null,this.containers[g].element,!0),this._trigger("change",s,this._uiHash()),this.containers[g]._trigger("change",s,this._uiHash(this)),this.currentContainer=this.containers[g],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[g]._trigger("over",s,this._uiHash(this)),this.containers[g].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,t("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,(t("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n=this.options,o=e.pageX,a=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.left<this.containment[0]&&(o=this.containment[0]+this.offset.click.left),e.pageY-this.offset.click.top<this.containment[1]&&(a=this.containment[1]+this.offset.click.top),e.pageX-this.offset.click.left>this.containment[2]&&(o=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(a=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((a-this.originalPageY)/n.grid[1])*n.grid[1],a=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((o-this.originalPageX)/n.grid[0])*n.grid[0],o=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:a-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:o-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){function i(t,e,i){return function(s){i._trigger(t,s,e._uiHash(e))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&n.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||n.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(n.push(function(t){this._trigger("remove",t,this._uiHash())}),n.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)e||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,this.cancelHelperRemoval){if(!e){for(this._trigger("beforeStop",t,this._uiHash()),s=0;n.length>s;s++)n[s].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!1}if(e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null,!e){for(s=0;n.length>s;s++)n[s].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}})}(jQuery),function(t,e){var i="ui-effects-";t.effects={effect:{}},function(t,e){function i(t,e,i){var s=u[e.type]||{};return null==t?i||!e.def?null:e.def:(t=s.floor?~~t:parseFloat(t),isNaN(t)?e.def:s.mod?(t+s.mod)%s.mod:0>t?0:t>s.max?s.max:t)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(t,o){var a,r=o.re.exec(i),h=r&&o.parse(r),l=o.space||"rgba";return h?(a=s[l](h),s[c[l].cache]=a[c[l].cache],n=s._rgba=a._rgba,!1):e}),n.length?("0,0,0,0"===n.join()&&t.extend(n,o.transparent),s):o[i]}function n(t,e,i){return i=(i+1)%1,1>6*i?t+6*(e-t)*i:1>2*i?e:2>3*i?t+6*(e-t)*(2/3-i):t}var o,a="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[t[1],t[2],t[3],t[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[2.55*t[1],2.55*t[2],2.55*t[3],t[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(t){return[t[1],t[2]/100,t[3]/100,t[4]]}}],l=t.Color=function(e,i,s,n){return new t.Color.fn.parse(e,i,s,n)},c={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},u={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},d=l.support={},p=t("<p>")[0],f=t.each;p.style.cssText="background-color:rgba(1,1,1,.5)",d.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(c,function(t,e){e.cache="_"+t,e.props.alpha={idx:3,type:"percent",def:1}}),l.fn=t.extend(l.prototype,{parse:function(n,a,r,h){if(n===e)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=t(n).css(a),a=e);var u=this,d=t.type(n),p=this._rgba=[];return a!==e&&(n=[n,a,r,h],d="array"),"string"===d?this.parse(s(n)||o._default):"array"===d?(f(c.rgba.props,function(t,e){p[e.idx]=i(n[e.idx],e)}),this):"object"===d?(n instanceof l?f(c,function(t,e){n[e.cache]&&(u[e.cache]=n[e.cache].slice())}):f(c,function(e,s){var o=s.cache;f(s.props,function(t,e){if(!u[o]&&s.to){if("alpha"===t||null==n[t])return;u[o]=s.to(u._rgba)}u[o][e.idx]=i(n[t],e,!0)}),u[o]&&0>t.inArray(null,u[o].slice(0,3))&&(u[o][3]=1,s.from&&(u._rgba=s.from(u[o])))}),this):e},is:function(t){var i=l(t),s=!0,n=this;return f(c,function(t,o){var a,r=i[o.cache];return r&&(a=n[o.cache]||o.to&&o.to(n._rgba)||[],f(o.props,function(t,i){return null!=r[i.idx]?s=r[i.idx]===a[i.idx]:e})),s}),s},_space:function(){var t=[],e=this;return f(c,function(i,s){e[s.cache]&&t.push(i)}),t.pop()},transition:function(t,e){var s=l(t),n=s._space(),o=c[n],a=0===this.alpha()?l("transparent"):this,r=a[o.cache]||o.to(a._rgba),h=r.slice();return s=s[o.cache],f(o.props,function(t,n){var o=n.idx,a=r[o],l=s[o],c=u[n.type]||{};null!==l&&(null===a?h[o]=l:(c.mod&&(l-a>c.mod/2?a+=c.mod:a-l>c.mod/2&&(a-=c.mod)),h[o]=i((l-a)*e+a,n)))}),this[n](h)},blend:function(e){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(e)._rgba;return l(t.map(i,function(t,e){return(1-s)*n[e]+s*t}))},toRgbaString:function(){var e="rgba(",i=t.map(this._rgba,function(t,e){return null==t?e>2?1:0:t});return 1===i[3]&&(i.pop(),e="rgb("),e+i.join()+")"},toHslaString:function(){var e="hsla(",i=t.map(this.hsla(),function(t,e){return null==t&&(t=e>2?1:0),e&&3>e&&(t=Math.round(100*t)+"%"),t});return 1===i[3]&&(i.pop(),e="hsl("),e+i.join()+")"},toHexString:function(e){var i=this._rgba.slice(),s=i.pop();return e&&i.push(~~(255*s)),"#"+t.map(i,function(t){return t=(t||0).toString(16),1===t.length?"0"+t:t}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,c.hsla.to=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e,i,s=t[0]/255,n=t[1]/255,o=t[2]/255,a=t[3],r=Math.max(s,n,o),h=Math.min(s,n,o),l=r-h,c=r+h,u=.5*c;return e=h===r?0:s===r?60*(n-o)/l+360:n===r?60*(o-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=u?l/c:l/(2-c),[Math.round(e)%360,i,u,null==a?1:a]},c.hsla.from=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e=t[0]/360,i=t[1],s=t[2],o=t[3],a=.5>=s?s*(1+i):s+i-s*i,r=2*s-a;return[Math.round(255*n(r,a,e+1/3)),Math.round(255*n(r,a,e)),Math.round(255*n(r,a,e-1/3)),o]},f(c,function(s,n){var o=n.props,a=n.cache,h=n.to,c=n.from;l.fn[s]=function(s){if(h&&!this[a]&&(this[a]=h(this._rgba)),s===e)return this[a].slice();var n,r=t.type(s),u="array"===r||"object"===r?s:arguments,d=this[a].slice();return f(o,function(t,e){var s=u["object"===r?t:e.idx];null==s&&(s=d[e.idx]),d[e.idx]=i(s,e)}),c?(n=l(c(d)),n[a]=d,n):l(d)},f(o,function(e,i){l.fn[e]||(l.fn[e]=function(n){var o,a=t.type(n),h="alpha"===e?this._hsla?"hsla":"rgba":s,l=this[h](),c=l[i.idx];return"undefined"===a?c:("function"===a&&(n=n.call(this,c),a=t.type(n)),null==n&&i.empty?this:("string"===a&&(o=r.exec(n),o&&(n=c+parseFloat(o[2])*("+"===o[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(e){var i=e.split(" ");f(i,function(e,i){t.cssHooks[i]={set:function(e,n){var o,a,r="";if("transparent"!==n&&("string"!==t.type(n)||(o=s(n)))){if(n=l(o||n),!d.rgba&&1!==n._rgba[3]){for(a="backgroundColor"===i?e.parentNode:e;(""===r||"transparent"===r)&&a&&a.style;)try{r=t.css(a,"backgroundColor"),a=a.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{e.style[i]=n}catch(h){}}},t.fx.step[i]=function(e){e.colorInit||(e.start=l(e.elem,i),e.end=l(e.end),e.colorInit=!0),t.cssHooks[i].set(e.elem,e.start.transition(e.end,e.pos))}})},l.hook(a),t.cssHooks.borderColor={expand:function(t){var e={};return f(["Top","Right","Bottom","Left"],function(i,s){e["border"+s+"Color"]=t}),e}},o=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(jQuery),function(){function i(e){var i,s,n=e.ownerDocument.defaultView?e.ownerDocument.defaultView.getComputedStyle(e,null):e.currentStyle,o={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(o[t.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(o[i]=n[i]);return o}function s(e,i){var s,n,a={};for(s in i)n=i[s],e[s]!==n&&(o[s]||(t.fx.step[s]||!isNaN(parseFloat(n)))&&(a[s]=n));return a}var n=["add","remove","toggle"],o={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};t.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(e,i){t.fx.step[i]=function(t){("none"!==t.end&&!t.setAttr||1===t.pos&&!t.setAttr)&&(jQuery.style(t.elem,i,t.end),t.setAttr=!0)}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.effects.animateClass=function(e,o,a,r){var h=t.speed(o,a,r);return this.queue(function(){var o,a=t(this),r=a.attr("class")||"",l=h.children?a.find("*").addBack():a;l=l.map(function(){var e=t(this);return{el:e,start:i(this)}}),o=function(){t.each(n,function(t,i){e[i]&&a[i+"Class"](e[i])})},o(),l=l.map(function(){return this.end=i(this.el[0]),this.diff=s(this.start,this.end),this}),a.attr("class",r),l=l.map(function(){var e=this,i=t.Deferred(),s=t.extend({},h,{queue:!1,complete:function(){i.resolve(e)}});return this.el.animate(this.diff,s),i.promise()}),t.when.apply(t,l.get()).done(function(){o(),t.each(arguments,function(){var e=this.el;t.each(this.diff,function(t){e.css(t,"")})}),h.complete.call(a[0])})})},t.fn.extend({addClass:function(e){return function(i,s,n,o){return s?t.effects.animateClass.call(this,{add:i},s,n,o):e.apply(this,arguments)}}(t.fn.addClass),removeClass:function(e){return function(i,s,n,o){return arguments.length>1?t.effects.animateClass.call(this,{remove:i},s,n,o):e.apply(this,arguments)}}(t.fn.removeClass),toggleClass:function(i){return function(s,n,o,a,r){return"boolean"==typeof n||n===e?o?t.effects.animateClass.call(this,n?{add:s}:{remove:s},o,a,r):i.apply(this,arguments):t.effects.animateClass.call(this,{toggle:s},n,o,a)}}(t.fn.toggleClass),switchClass:function(e,i,s,n,o){return t.effects.animateClass.call(this,{add:i,remove:e},s,n,o)}})}(),function(){function s(e,i,s,n){return t.isPlainObject(e)&&(i=e,e=e.effect),e={effect:e},null==i&&(i={}),t.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||t.fx.speeds[i])&&(n=s,s=i,i={}),t.isFunction(s)&&(n=s,s=null),i&&t.extend(e,i),s=s||i.duration,e.duration=t.fx.off?0:"number"==typeof s?s:s in t.fx.speeds?t.fx.speeds[s]:t.fx.speeds._default,e.complete=n||i.complete,e}function n(e){return!e||"number"==typeof e||t.fx.speeds[e]?!0:"string"!=typeof e||t.effects.effect[e]?t.isFunction(e)?!0:"object"!=typeof e||e.effect?!1:!0:!0}t.extend(t.effects,{version:"1.10.4",save:function(t,e){for(var s=0;e.length>s;s++)null!==e[s]&&t.data(i+e[s],t[0].style[e[s]])},restore:function(t,s){var n,o;for(o=0;s.length>o;o++)null!==s[o]&&(n=t.data(i+s[o]),n===e&&(n=""),t.css(s[o],n))},setMode:function(t,e){return"toggle"===e&&(e=t.is(":hidden")?"show":"hide"),e},getBaseline:function(t,e){var i,s;switch(t[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=t[0]/e.height}switch(t[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=t[1]/e.width}return{x:s,y:i}},createWrapper:function(e){if(e.parent().is(".ui-effects-wrapper"))return e.parent();var i={width:e.outerWidth(!0),height:e.outerHeight(!0),"float":e.css("float")},s=t("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:e.width(),height:e.height()},o=document.activeElement;try{o.id}catch(a){o=document.body}return e.wrap(s),(e[0]===o||t.contains(e[0],o))&&t(o).focus(),s=e.parent(),"static"===e.css("position")?(s.css({position:"relative"}),e.css({position:"relative"})):(t.extend(i,{position:e.css("position"),zIndex:e.css("z-index")}),t.each(["top","left","bottom","right"],function(t,s){i[s]=e.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),e.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),e.css(n),s.css(i).show()},removeWrapper:function(e){var i=document.activeElement;return e.parent().is(".ui-effects-wrapper")&&(e.parent().replaceWith(e),(e[0]===i||t.contains(e[0],i))&&t(i).focus()),e},setTransition:function(e,i,s,n){return n=n||{},t.each(i,function(t,i){var o=e.cssUnit(i);o[0]>0&&(n[i]=o[0]*s+o[1])}),n}}),t.fn.extend({effect:function(){function e(e){function s(){t.isFunction(o)&&o.call(n[0]),t.isFunction(e)&&e()}var n=t(this),o=i.complete,r=i.mode;(n.is(":hidden")?"hide"===r:"show"===r)?(n[r](),s()):a.call(n[0],i,s)}var i=s.apply(this,arguments),n=i.mode,o=i.queue,a=t.effects.effect[i.effect];return t.fx.off||!a?n?this[n](i.duration,i.complete):this.each(function(){i.complete&&i.complete.call(this)}):o===!1?this.each(e):this.queue(o||"fx",e)},show:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="show",this.effect.call(this,i)}}(t.fn.show),hide:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="hide",this.effect.call(this,i)}}(t.fn.hide),toggle:function(t){return function(e){if(n(e)||"boolean"==typeof e)return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="toggle",this.effect.call(this,i)}}(t.fn.toggle),cssUnit:function(e){var i=this.css(e),s=[];return t.each(["em","px","%","pt"],function(t,e){i.indexOf(e)>0&&(s=[parseFloat(i),e])}),s}})}(),function(){var e={};t.each(["Quad","Cubic","Quart","Quint","Expo"],function(t,i){e[i]=function(e){return Math.pow(e,t+2)}}),t.extend(e,{Sine:function(t){return 1-Math.cos(t*Math.PI/2)},Circ:function(t){return 1-Math.sqrt(1-t*t)},Elastic:function(t){return 0===t||1===t?t:-Math.pow(2,8*(t-1))*Math.sin((80*(t-1)-7.5)*Math.PI/15)},Back:function(t){return t*t*(3*t-2)},Bounce:function(t){for(var e,i=4;((e=Math.pow(2,--i))-1)/11>t;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*e-2)/22-t,2)}}),t.each(e,function(e,i){t.easing["easeIn"+e]=i,t.easing["easeOut"+e]=function(t){return 1-i(1-t)},t.easing["easeInOut"+e]=function(t){return.5>t?i(2*t)/2:1-i(-2*t+2)/2}})}()}(jQuery),function(t){var e=0,i={},s={};i.height=i.paddingTop=i.paddingBottom=i.borderTopWidth=i.borderBottomWidth="hide",s.height=s.paddingTop=s.paddingBottom=s.borderTopWidth=s.borderBottomWidth="show",t.widget("ui.accordion",{version:"1.10.4",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var e=this.options;this.prevShow=this.prevHide=t(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),e.collapsible||e.active!==!1&&null!=e.active||(e.active=0),this._processPanels(),0>e.active&&(e.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():t(),content:this.active.length?this.active.next():t()}},_createIcons:function(){var e=this.options.icons;e&&(t("<span>").addClass("ui-accordion-header-icon ui-icon "+e.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(e.header).addClass(e.activeHeader),this.headers.addClass("ui-accordion-icons"))
+},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var t;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this._destroyIcons(),t=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),"content"!==this.options.heightStyle&&t.css("height","")},_setOption:function(t,e){return"active"===t?(this._activate(e),undefined):("event"===t&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(e)),this._super(t,e),"collapsible"!==t||e||this.options.active!==!1||this._activate(0),"icons"===t&&(this._destroyIcons(),e&&this._createIcons()),"disabled"===t&&this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!e),undefined)},_keydown:function(e){if(!e.altKey&&!e.ctrlKey){var i=t.ui.keyCode,s=this.headers.length,n=this.headers.index(e.target),o=!1;switch(e.keyCode){case i.RIGHT:case i.DOWN:o=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:o=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(e);break;case i.HOME:o=this.headers[0];break;case i.END:o=this.headers[s-1]}o&&(t(e.target).attr("tabIndex",-1),t(o).attr("tabIndex",0),o.focus(),e.preventDefault())}},_panelKeyDown:function(e){e.keyCode===t.ui.keyCode.UP&&e.ctrlKey&&t(e.currentTarget).prev().focus()},refresh:function(){var e=this.options;this._processPanels(),e.active===!1&&e.collapsible===!0||!this.headers.length?(e.active=!1,this.active=t()):e.active===!1?this._activate(0):this.active.length&&!t.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(e.active=!1,this.active=t()):this._activate(Math.max(0,e.active-1)):e.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"),this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide()},_refresh:function(){var i,s=this.options,n=s.heightStyle,o=this.element.parent(),a=this.accordionId="ui-accordion-"+(this.element.attr("id")||++e);this.active=this._findActive(s.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(e){var i=t(this),s=i.attr("id"),n=i.next(),o=n.attr("id");s||(s=a+"-header-"+e,i.attr("id",s)),o||(o=a+"-panel-"+e,n.attr("id",o)),i.attr("aria-controls",o),n.attr("aria-labelledby",s)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(s.event),"fill"===n?(i=o.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.headers.each(function(){i-=t(this).outerHeight(!0)}),this.headers.next().each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===n&&(i=0,this.headers.next().each(function(){i=Math.max(i,t(this).css("height","").height())}).height(i))},_activate:function(e){var i=this._findActive(e)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return"number"==typeof e?this.headers.eq(e):t()},_setupEvents:function(e){var i={keydown:"_keydown"};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n[0]===s[0],a=o&&i.collapsible,r=a?t():n.next(),h=s.next(),l={oldHeader:s,oldPanel:h,newHeader:a?t():n,newPanel:r};e.preventDefault(),o&&!i.collapsible||this._trigger("beforeActivate",e,l)===!1||(i.active=a?!1:this.headers.index(n),this.active=o?t():n,this._toggle(l),s.removeClass("ui-accordion-header-active ui-state-active"),i.icons&&s.children(".ui-accordion-header-icon").removeClass(i.icons.activeHeader).addClass(i.icons.header),o||(n.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),i.icons&&n.children(".ui-accordion-header-icon").removeClass(i.icons.header).addClass(i.icons.activeHeader),n.next().addClass("ui-accordion-content-active")))},_toggle:function(e){var i=e.newPanel,s=this.prevShow.length?this.prevShow:e.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,e):(s.hide(),i.show(),this._toggleComplete(e)),s.attr({"aria-hidden":"true"}),s.prev().attr("aria-selected","false"),i.length&&s.length?s.prev().attr({tabIndex:-1,"aria-expanded":"false"}):i.length&&this.headers.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),i.attr("aria-hidden","false").prev().attr({"aria-selected":"true",tabIndex:0,"aria-expanded":"true"})},_animate:function(t,e,n){var o,a,r,h=this,l=0,c=t.length&&(!e.length||t.index()<e.index()),u=this.options.animate||{},d=c&&u.down||u,p=function(){h._toggleComplete(n)};return"number"==typeof d&&(r=d),"string"==typeof d&&(a=d),a=a||d.easing||u.easing,r=r||d.duration||u.duration,e.length?t.length?(o=t.show().outerHeight(),e.animate(i,{duration:r,easing:a,step:function(t,e){e.now=Math.round(t)}}),t.hide().animate(s,{duration:r,easing:a,complete:p,step:function(t,i){i.now=Math.round(t),"height"!==i.prop?l+=i.now:"content"!==h.options.heightStyle&&(i.now=Math.round(o-e.outerHeight()-l),l=0)}}),undefined):e.animate(i,r,a,p):t.animate(s,r,a,p)},_toggleComplete:function(t){var e=t.oldPanel;e.removeClass("ui-accordion-content-active").prev().removeClass("ui-corner-top").addClass("ui-corner-all"),e.length&&(e.parent()[0].className=e.parent()[0].className),this._trigger("activate",null,t)}})}(jQuery),function(t){t.widget("ui.autocomplete",{version:"1.10.4",defaultElement:"<input>",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var e,i,s,n=this.element[0].nodeName.toLowerCase(),o="textarea"===n,a="input"===n;this.isMultiLine=o?!0:a?!1:this.element.prop("isContentEditable"),this.valueMethod=this.element[o||a?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return e=!0,s=!0,i=!0,undefined;e=!1,s=!1,i=!1;var o=t.ui.keyCode;switch(n.keyCode){case o.PAGE_UP:e=!0,this._move("previousPage",n);break;case o.PAGE_DOWN:e=!0,this._move("nextPage",n);break;case o.UP:e=!0,this._keyEvent("previous",n);break;case o.DOWN:e=!0,this._keyEvent("next",n);break;case o.ENTER:case o.NUMPAD_ENTER:this.menu.active&&(e=!0,n.preventDefault(),this.menu.select(n));break;case o.TAB:this.menu.active&&this.menu.select(n);break;case o.ESCAPE:this.menu.element.is(":visible")&&(this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(e)return e=!1,(!this.isMultiLine||this.menu.element.is(":visible"))&&s.preventDefault(),undefined;if(!i){var n=t.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(t){return s?(s=!1,t.preventDefault(),undefined):(this._searchTimeout(t),undefined)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,undefined):(clearTimeout(this.searching),this.close(t),this._change(t),undefined)}}),this._initSource(),this.menu=t("<ul>").addClass("ui-autocomplete ui-front").appendTo(this._appendTo()).menu({role:null}).hide().data("ui-menu"),this._on(this.menu.element,{mousedown:function(e){e.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur});var i=this.menu.element[0];t(e.target).closest(".ui-menu-item").length||this._delay(function(){var e=this;this.document.one("mousedown",function(s){s.target===e.element[0]||s.target===i||t.contains(i,s.target)||e.close()})})},menufocus:function(e,i){if(this.isNewMenu&&(this.isNewMenu=!1,e.originalEvent&&/^mouse/.test(e.originalEvent.type)))return this.menu.blur(),this.document.one("mousemove",function(){t(e.target).trigger(e.originalEvent)}),undefined;var s=i.item.data("ui-autocomplete-item");!1!==this._trigger("focus",e,{item:s})?e.originalEvent&&/^key/.test(e.originalEvent.type)&&this._value(s.value):this.liveRegion.text(s.value)},menuselect:function(t,e){var i=e.item.data("ui-autocomplete-item"),s=this.previous;this.element[0]!==this.document[0].activeElement&&(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s,this.selectedItem=i})),!1!==this._trigger("select",t,{item:i})&&this._value(i.value),this.term=this._value(),this.close(t),this.selectedItem=i}}),this.liveRegion=t("<span>",{role:"status","aria-live":"polite"}).addClass("ui-helper-hidden-accessible").insertBefore(this.element),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(t,e){this._super(t,e),"source"===t&&this._initSource(),"appendTo"===t&&this.menu.element.appendTo(this._appendTo()),"disabled"===t&&e&&this.xhr&&this.xhr.abort()},_appendTo:function(){var e=this.options.appendTo;return e&&(e=e.jquery||e.nodeType?t(e):this.document.find(e).eq(0)),e||(e=this.element.closest(".ui-front")),e.length||(e=this.document[0].body),e},_initSource:function(){var e,i,s=this;t.isArray(this.options.source)?(e=this.options.source,this.source=function(i,s){s(t.ui.autocomplete.filter(e,i.term))}):"string"==typeof this.options.source?(i=this.options.source,this.source=function(e,n){s.xhr&&s.xhr.abort(),s.xhr=t.ajax({url:i,data:e,dataType:"json",success:function(t){n(t)},error:function(){n([])}})}):this.source=this.options.source},_searchTimeout:function(t){clearTimeout(this.searching),this.searching=this._delay(function(){this.term!==this._value()&&(this.selectedItem=null,this.search(null,t))},this.options.delay)},search:function(t,e){return t=null!=t?t:this._value(),this.term=this._value(),t.length<this.options.minLength?this.close(e):this._trigger("search",e)!==!1?this._search(t):undefined},_search:function(t){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.cancelSearch=!1,this.source({term:t},this._response())},_response:function(){var e=++this.requestIndex;return t.proxy(function(t){e===this.requestIndex&&this.__response(t),this.pending--,this.pending||this.element.removeClass("ui-autocomplete-loading")},this)},__response:function(t){t&&(t=this._normalize(t)),this._trigger("response",null,{content:t}),!this.options.disabled&&t&&t.length&&!this.cancelSearch?(this._suggest(t),this._trigger("open")):this._close()},close:function(t){this.cancelSearch=!0,this._close(t)},_close:function(t){this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.blur(),this.isNewMenu=!0,this._trigger("close",t))},_change:function(t){this.previous!==this._value()&&this._trigger("change",t,{item:this.selectedItem})},_normalize:function(e){return e.length&&e[0].label&&e[0].value?e:t.map(e,function(e){return"string"==typeof e?{label:e,value:e}:t.extend({label:e.label||e.value,value:e.value||e.label},e)})},_suggest:function(e){var i=this.menu.element.empty();this._renderMenu(i,e),this.isNewMenu=!0,this.menu.refresh(),i.show(),this._resizeMenu(),i.position(t.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next()},_resizeMenu:function(){var t=this.menu.element;t.outerWidth(Math.max(t.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(e,i){var s=this;t.each(i,function(t,i){s._renderItemData(e,i)})},_renderItemData:function(t,e){return this._renderItem(t,e).data("ui-autocomplete-item",e)},_renderItem:function(e,i){return t("<li>").append(t("<a>").text(i.label)).appendTo(e)},_move:function(t,e){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(t)||this.menu.isLastItem()&&/^next/.test(t)?(this._value(this.term),this.menu.blur(),undefined):(this.menu[t](e),undefined):(this.search(null,e),undefined)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(t,e){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(t,e),e.preventDefault())}}),t.extend(t.ui.autocomplete,{escapeRegex:function(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(e,i){var s=RegExp(t.ui.autocomplete.escapeRegex(i),"i");return t.grep(e,function(t){return s.test(t.label||t.value||t)})}}),t.widget("ui.autocomplete",t.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(t){return t+(t>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(t){var e;this._superApply(arguments),this.options.disabled||this.cancelSearch||(e=t&&t.length?this.options.messages.results(t.length):this.options.messages.noResults,this.liveRegion.text(e))}})}(jQuery),function(t){var e,i="ui-button ui-widget ui-state-default ui-corner-all",s="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",n=function(){var e=t(this);setTimeout(function(){e.find(":ui-button").button("refresh")},1)},o=function(e){var i=e.name,s=e.form,n=t([]);return i&&(i=i.replace(/'/g,"\\'"),n=s?t(s).find("[name='"+i+"']"):t("[name='"+i+"']",e.ownerDocument).filter(function(){return!this.form})),n};t.widget("ui.button",{version:"1.10.4",defaultElement:"<button>",options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset"+this.eventNamespace).bind("reset"+this.eventNamespace,n),"boolean"!=typeof this.options.disabled?this.options.disabled=!!this.element.prop("disabled"):this.element.prop("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var s=this,a=this.options,r="checkbox"===this.type||"radio"===this.type,h=r?"":"ui-state-active";null===a.label&&(a.label="input"===this.type?this.buttonElement.val():this.buttonElement.html()),this._hoverable(this.buttonElement),this.buttonElement.addClass(i).attr("role","button").bind("mouseenter"+this.eventNamespace,function(){a.disabled||this===e&&t(this).addClass("ui-state-active")}).bind("mouseleave"+this.eventNamespace,function(){a.disabled||t(this).removeClass(h)}).bind("click"+this.eventNamespace,function(t){a.disabled&&(t.preventDefault(),t.stopImmediatePropagation())}),this._on({focus:function(){this.buttonElement.addClass("ui-state-focus")},blur:function(){this.buttonElement.removeClass("ui-state-focus")}}),r&&this.element.bind("change"+this.eventNamespace,function(){s.refresh()}),"checkbox"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){return a.disabled?!1:undefined}):"radio"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){if(a.disabled)return!1;t(this).addClass("ui-state-active"),s.buttonElement.attr("aria-pressed","true");var e=s.element[0];o(e).not(e).map(function(){return t(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown"+this.eventNamespace,function(){return a.disabled?!1:(t(this).addClass("ui-state-active"),e=this,s.document.one("mouseup",function(){e=null}),undefined)}).bind("mouseup"+this.eventNamespace,function(){return a.disabled?!1:(t(this).removeClass("ui-state-active"),undefined)}).bind("keydown"+this.eventNamespace,function(e){return a.disabled?!1:((e.keyCode===t.ui.keyCode.SPACE||e.keyCode===t.ui.keyCode.ENTER)&&t(this).addClass("ui-state-active"),undefined)}).bind("keyup"+this.eventNamespace+" blur"+this.eventNamespace,function(){t(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(e){e.keyCode===t.ui.keyCode.SPACE&&t(this).click()})),this._setOption("disabled",a.disabled),this._resetButton()},_determineButtonType:function(){var t,e,i;this.type=this.element.is("[type=checkbox]")?"checkbox":this.element.is("[type=radio]")?"radio":this.element.is("input")?"input":"button","checkbox"===this.type||"radio"===this.type?(t=this.element.parents().last(),e="label[for='"+this.element.attr("id")+"']",this.buttonElement=t.find(e),this.buttonElement.length||(t=t.length?t.siblings():this.element.siblings(),this.buttonElement=t.filter(e),this.buttonElement.length||(this.buttonElement=t.find(e))),this.element.addClass("ui-helper-hidden-accessible"),i=this.element.is(":checked"),i&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.prop("aria-pressed",i)):this.buttonElement=this.element},widget:function(){return this.buttonElement},_destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(i+" ui-state-active "+s).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title")},_setOption:function(t,e){return this._super(t,e),"disabled"===t?(this.element.prop("disabled",!!e),e&&this.buttonElement.removeClass("ui-state-focus"),undefined):(this._resetButton(),undefined)},refresh:function(){var e=this.element.is("input, button")?this.element.is(":disabled"):this.element.hasClass("ui-button-disabled");e!==this.options.disabled&&this._setOption("disabled",e),"radio"===this.type?o(this.element[0]).each(function(){t(this).is(":checked")?t(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):t(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):"checkbox"===this.type&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if("input"===this.type)return this.options.label&&this.element.val(this.options.label),undefined;var e=this.buttonElement.removeClass(s),i=t("<span></span>",this.document[0]).addClass("ui-button-text").html(this.options.label).appendTo(e.empty()).text(),n=this.options.icons,o=n.primary&&n.secondary,a=[];n.primary||n.secondary?(this.options.text&&a.push("ui-button-text-icon"+(o?"s":n.primary?"-primary":"-secondary")),n.primary&&e.prepend("<span class='ui-button-icon-primary ui-icon "+n.primary+"'></span>"),n.secondary&&e.append("<span class='ui-button-icon-secondary ui-icon "+n.secondary+"'></span>"),this.options.text||(a.push(o?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||e.attr("title",t.trim(i)))):a.push("ui-button-text-only"),e.addClass(a.join(" "))}}),t.widget("ui.buttonset",{version:"1.10.4",options:{items:"button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(t,e){"disabled"===t&&this.buttons.button("option",t,e),this._super(t,e)},refresh:function(){var e="rtl"===this.element.css("direction");this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return t(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(e?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(e?"ui-corner-left":"ui-corner-right").end().end()},_destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return t(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy")}})}(jQuery),function(t,e){function i(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},t.extend(this._defaults,this.regional[""]),this.dpDiv=s(t("<div id='"+this._mainDivId+"' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"))}function s(e){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return e.delegate(i,"mouseout",function(){t(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).removeClass("ui-datepicker-next-hover")}).delegate(i,"mouseover",function(){t.datepicker._isDisabledDatepicker(o.inline?e.parent()[0]:o.input[0])||(t(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),t(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).addClass("ui-datepicker-next-hover"))})}function n(e,i){t.extend(e,i);for(var s in i)null==i[s]&&(e[s]=i[s]);return e}t.extend(t.ui,{datepicker:{version:"1.10.4"}});var o,a="datepicker";t.extend(i.prototype,{markerClassName:"hasDatepicker",maxRows:4,_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(t){return n(this._defaults,t||{}),this},_attachDatepicker:function(e,i){var s,n,o;s=e.nodeName.toLowerCase(),n="div"===s||"span"===s,e.id||(this.uuid+=1,e.id="dp"+this.uuid),o=this._newInst(t(e),n),o.settings=t.extend({},i||{}),"input"===s?this._connectDatepicker(e,o):n&&this._inlineDatepicker(e,o)},_newInst:function(e,i){var n=e[0].id.replace(/([^A-Za-z0-9_\-])/g,"\\\\$1");return{id:n,input:e,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:i,dpDiv:i?s(t("<div class='"+this._inlineClass+" ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")):this.dpDiv}},_connectDatepicker:function(e,i){var s=t(e);i.append=t([]),i.trigger=t([]),s.hasClass(this.markerClassName)||(this._attachments(s,i),s.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp),this._autoSize(i),t.data(e,a,i),i.settings.disabled&&this._disableDatepicker(e))},_attachments:function(e,i){var s,n,o,a=this._get(i,"appendText"),r=this._get(i,"isRTL");i.append&&i.append.remove(),a&&(i.append=t("<span class='"+this._appendClass+"'>"+a+"</span>"),e[r?"before":"after"](i.append)),e.unbind("focus",this._showDatepicker),i.trigger&&i.trigger.remove(),s=this._get(i,"showOn"),("focus"===s||"both"===s)&&e.focus(this._showDatepicker),("button"===s||"both"===s)&&(n=this._get(i,"buttonText"),o=this._get(i,"buttonImage"),i.trigger=t(this._get(i,"buttonImageOnly")?t("<img/>").addClass(this._triggerClass).attr({src:o,alt:n,title:n}):t("<button type='button'></button>").addClass(this._triggerClass).html(o?t("<img/>").attr({src:o,alt:n,title:n}):n)),e[r?"before":"after"](i.trigger),i.trigger.click(function(){return t.datepicker._datepickerShowing&&t.datepicker._lastInput===e[0]?t.datepicker._hideDatepicker():t.datepicker._datepickerShowing&&t.datepicker._lastInput!==e[0]?(t.datepicker._hideDatepicker(),t.datepicker._showDatepicker(e[0])):t.datepicker._showDatepicker(e[0]),!1}))},_autoSize:function(t){if(this._get(t,"autoSize")&&!t.inline){var e,i,s,n,o=new Date(2009,11,20),a=this._get(t,"dateFormat");a.match(/[DM]/)&&(e=function(t){for(i=0,s=0,n=0;t.length>n;n++)t[n].length>i&&(i=t[n].length,s=n);return s},o.setMonth(e(this._get(t,a.match(/MM/)?"monthNames":"monthNamesShort"))),o.setDate(e(this._get(t,a.match(/DD/)?"dayNames":"dayNamesShort"))+20-o.getDay())),t.input.attr("size",this._formatDate(t,o).length)}},_inlineDatepicker:function(e,i){var s=t(e);s.hasClass(this.markerClassName)||(s.addClass(this.markerClassName).append(i.dpDiv),t.data(e,a,i),this._setDate(i,this._getDefaultDate(i),!0),this._updateDatepicker(i),this._updateAlternate(i),i.settings.disabled&&this._disableDatepicker(e),i.dpDiv.css("display","block"))},_dialogDatepicker:function(e,i,s,o,r){var h,l,c,u,d,p=this._dialogInst;return p||(this.uuid+=1,h="dp"+this.uuid,this._dialogInput=t("<input type='text' id='"+h+"' style='position: absolute; top: -100px; width: 0px;'/>"),this._dialogInput.keydown(this._doKeyDown),t("body").append(this._dialogInput),p=this._dialogInst=this._newInst(this._dialogInput,!1),p.settings={},t.data(this._dialogInput[0],a,p)),n(p.settings,o||{}),i=i&&i.constructor===Date?this._formatDate(p,i):i,this._dialogInput.val(i),this._pos=r?r.length?r:[r.pageX,r.pageY]:null,this._pos||(l=document.documentElement.clientWidth,c=document.documentElement.clientHeight,u=document.documentElement.scrollLeft||document.body.scrollLeft,d=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[l/2-100+u,c/2-150+d]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),p.settings.onSelect=s,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),t.blockUI&&t.blockUI(this.dpDiv),t.data(this._dialogInput[0],a,p),this},_destroyDatepicker:function(e){var i,s=t(e),n=t.data(e,a);s.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),t.removeData(e,a),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty())},_enableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,a);n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!1,o.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().removeClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}))},_disableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,a);n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!0,o.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().addClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}),this._disabledInputs[this._disabledInputs.length]=e)},_isDisabledDatepicker:function(t){if(!t)return!1;for(var e=0;this._disabledInputs.length>e;e++)if(this._disabledInputs[e]===t)return!0;return!1},_getInst:function(e){try{return t.data(e,a)}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(i,s,o){var a,r,h,l,c=this._getInst(i);return 2===arguments.length&&"string"==typeof s?"defaults"===s?t.extend({},t.datepicker._defaults):c?"all"===s?t.extend({},c.settings):this._get(c,s):null:(a=s||{},"string"==typeof s&&(a={},a[s]=o),c&&(this._curInst===c&&this._hideDatepicker(),r=this._getDateDatepicker(i,!0),h=this._getMinMaxDate(c,"min"),l=this._getMinMaxDate(c,"max"),n(c.settings,a),null!==h&&a.dateFormat!==e&&a.minDate===e&&(c.settings.minDate=this._formatDate(c,h)),null!==l&&a.dateFormat!==e&&a.maxDate===e&&(c.settings.maxDate=this._formatDate(c,l)),"disabled"in a&&(a.disabled?this._disableDatepicker(i):this._enableDatepicker(i)),this._attachments(t(i),c),this._autoSize(c),this._setDate(c,r),this._updateAlternate(c),this._updateDatepicker(c)),e)},_changeDatepicker:function(t,e,i){this._optionDatepicker(t,e,i)},_refreshDatepicker:function(t){var e=this._getInst(t);e&&this._updateDatepicker(e)},_setDateDatepicker:function(t,e){var i=this._getInst(t);i&&(this._setDate(i,e),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(t,e){var i=this._getInst(t);return i&&!i.inline&&this._setDateFromField(i,e),i?this._getDate(i):null},_doKeyDown:function(e){var i,s,n,o=t.datepicker._getInst(e.target),a=!0,r=o.dpDiv.is(".ui-datepicker-rtl");if(o._keyEvent=!0,t.datepicker._datepickerShowing)switch(e.keyCode){case 9:t.datepicker._hideDatepicker(),a=!1;break;case 13:return n=t("td."+t.datepicker._dayOverClass+":not(."+t.datepicker._currentClass+")",o.dpDiv),n[0]&&t.datepicker._selectDay(e.target,o.selectedMonth,o.selectedYear,n[0]),i=t.datepicker._get(o,"onSelect"),i?(s=t.datepicker._formatDate(o),i.apply(o.input?o.input[0]:null,[s,o])):t.datepicker._hideDatepicker(),!1;case 27:t.datepicker._hideDatepicker();break;case 33:t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M");break;case 34:t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");
+break;case 35:(e.ctrlKey||e.metaKey)&&t.datepicker._clearDate(e.target),a=e.ctrlKey||e.metaKey;break;case 36:(e.ctrlKey||e.metaKey)&&t.datepicker._gotoToday(e.target),a=e.ctrlKey||e.metaKey;break;case 37:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?1:-1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M");break;case 38:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,-7,"D"),a=e.ctrlKey||e.metaKey;break;case 39:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?-1:1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 40:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,7,"D"),a=e.ctrlKey||e.metaKey;break;default:a=!1}else 36===e.keyCode&&e.ctrlKey?t.datepicker._showDatepicker(this):a=!1;a&&(e.preventDefault(),e.stopPropagation())},_doKeyPress:function(i){var s,n,o=t.datepicker._getInst(i.target);return t.datepicker._get(o,"constrainInput")?(s=t.datepicker._possibleChars(t.datepicker._get(o,"dateFormat")),n=String.fromCharCode(null==i.charCode?i.keyCode:i.charCode),i.ctrlKey||i.metaKey||" ">n||!s||s.indexOf(n)>-1):e},_doKeyUp:function(e){var i,s=t.datepicker._getInst(e.target);if(s.input.val()!==s.lastVal)try{i=t.datepicker.parseDate(t.datepicker._get(s,"dateFormat"),s.input?s.input.val():null,t.datepicker._getFormatConfig(s)),i&&(t.datepicker._setDateFromField(s),t.datepicker._updateAlternate(s),t.datepicker._updateDatepicker(s))}catch(n){}return!0},_showDatepicker:function(e){if(e=e.target||e,"input"!==e.nodeName.toLowerCase()&&(e=t("input",e.parentNode)[0]),!t.datepicker._isDisabledDatepicker(e)&&t.datepicker._lastInput!==e){var i,s,o,a,r,h,l;i=t.datepicker._getInst(e),t.datepicker._curInst&&t.datepicker._curInst!==i&&(t.datepicker._curInst.dpDiv.stop(!0,!0),i&&t.datepicker._datepickerShowing&&t.datepicker._hideDatepicker(t.datepicker._curInst.input[0])),s=t.datepicker._get(i,"beforeShow"),o=s?s.apply(e,[e,i]):{},o!==!1&&(n(i.settings,o),i.lastVal=null,t.datepicker._lastInput=e,t.datepicker._setDateFromField(i),t.datepicker._inDialog&&(e.value=""),t.datepicker._pos||(t.datepicker._pos=t.datepicker._findPos(e),t.datepicker._pos[1]+=e.offsetHeight),a=!1,t(e).parents().each(function(){return a|="fixed"===t(this).css("position"),!a}),r={left:t.datepicker._pos[0],top:t.datepicker._pos[1]},t.datepicker._pos=null,i.dpDiv.empty(),i.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),t.datepicker._updateDatepicker(i),r=t.datepicker._checkOffset(i,r,a),i.dpDiv.css({position:t.datepicker._inDialog&&t.blockUI?"static":a?"fixed":"absolute",display:"none",left:r.left+"px",top:r.top+"px"}),i.inline||(h=t.datepicker._get(i,"showAnim"),l=t.datepicker._get(i,"duration"),i.dpDiv.zIndex(t(e).zIndex()+1),t.datepicker._datepickerShowing=!0,t.effects&&t.effects.effect[h]?i.dpDiv.show(h,t.datepicker._get(i,"showOptions"),l):i.dpDiv[h||"show"](h?l:null),t.datepicker._shouldFocusInput(i)&&i.input.focus(),t.datepicker._curInst=i))}},_updateDatepicker:function(e){this.maxRows=4,o=e,e.dpDiv.empty().append(this._generateHTML(e)),this._attachHandlers(e),e.dpDiv.find("."+this._dayOverClass+" a").mouseover();var i,s=this._getNumberOfMonths(e),n=s[1],a=17;e.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),n>1&&e.dpDiv.addClass("ui-datepicker-multi-"+n).css("width",a*n+"em"),e.dpDiv[(1!==s[0]||1!==s[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),e.dpDiv[(this._get(e,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),e===t.datepicker._curInst&&t.datepicker._datepickerShowing&&t.datepicker._shouldFocusInput(e)&&e.input.focus(),e.yearshtml&&(i=e.yearshtml,setTimeout(function(){i===e.yearshtml&&e.yearshtml&&e.dpDiv.find("select.ui-datepicker-year:first").replaceWith(e.yearshtml),i=e.yearshtml=null},0))},_shouldFocusInput:function(t){return t.input&&t.input.is(":visible")&&!t.input.is(":disabled")&&!t.input.is(":focus")},_checkOffset:function(e,i,s){var n=e.dpDiv.outerWidth(),o=e.dpDiv.outerHeight(),a=e.input?e.input.outerWidth():0,r=e.input?e.input.outerHeight():0,h=document.documentElement.clientWidth+(s?0:t(document).scrollLeft()),l=document.documentElement.clientHeight+(s?0:t(document).scrollTop());return i.left-=this._get(e,"isRTL")?n-a:0,i.left-=s&&i.left===e.input.offset().left?t(document).scrollLeft():0,i.top-=s&&i.top===e.input.offset().top+r?t(document).scrollTop():0,i.left-=Math.min(i.left,i.left+n>h&&h>n?Math.abs(i.left+n-h):0),i.top-=Math.min(i.top,i.top+o>l&&l>o?Math.abs(o+r):0),i},_findPos:function(e){for(var i,s=this._getInst(e),n=this._get(s,"isRTL");e&&("hidden"===e.type||1!==e.nodeType||t.expr.filters.hidden(e));)e=e[n?"previousSibling":"nextSibling"];return i=t(e).offset(),[i.left,i.top]},_hideDatepicker:function(e){var i,s,n,o,r=this._curInst;!r||e&&r!==t.data(e,a)||this._datepickerShowing&&(i=this._get(r,"showAnim"),s=this._get(r,"duration"),n=function(){t.datepicker._tidyDialog(r)},t.effects&&(t.effects.effect[i]||t.effects[i])?r.dpDiv.hide(i,t.datepicker._get(r,"showOptions"),s,n):r.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?s:null,n),i||n(),this._datepickerShowing=!1,o=this._get(r,"onClose"),o&&o.apply(r.input?r.input[0]:null,[r.input?r.input.val():"",r]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),t.blockUI&&(t.unblockUI(),t("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(t){t.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(e){if(t.datepicker._curInst){var i=t(e.target),s=t.datepicker._getInst(i[0]);(i[0].id!==t.datepicker._mainDivId&&0===i.parents("#"+t.datepicker._mainDivId).length&&!i.hasClass(t.datepicker.markerClassName)&&!i.closest("."+t.datepicker._triggerClass).length&&t.datepicker._datepickerShowing&&(!t.datepicker._inDialog||!t.blockUI)||i.hasClass(t.datepicker.markerClassName)&&t.datepicker._curInst!==s)&&t.datepicker._hideDatepicker()}},_adjustDate:function(e,i,s){var n=t(e),o=this._getInst(n[0]);this._isDisabledDatepicker(n[0])||(this._adjustInstDate(o,i+("M"===s?this._get(o,"showCurrentAtPos"):0),s),this._updateDatepicker(o))},_gotoToday:function(e){var i,s=t(e),n=this._getInst(s[0]);this._get(n,"gotoCurrent")&&n.currentDay?(n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear):(i=new Date,n.selectedDay=i.getDate(),n.drawMonth=n.selectedMonth=i.getMonth(),n.drawYear=n.selectedYear=i.getFullYear()),this._notifyChange(n),this._adjustDate(s)},_selectMonthYear:function(e,i,s){var n=t(e),o=this._getInst(n[0]);o["selected"+("M"===s?"Month":"Year")]=o["draw"+("M"===s?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(o),this._adjustDate(n)},_selectDay:function(e,i,s,n){var o,a=t(e);t(n).hasClass(this._unselectableClass)||this._isDisabledDatepicker(a[0])||(o=this._getInst(a[0]),o.selectedDay=o.currentDay=t("a",n).html(),o.selectedMonth=o.currentMonth=i,o.selectedYear=o.currentYear=s,this._selectDate(e,this._formatDate(o,o.currentDay,o.currentMonth,o.currentYear)))},_clearDate:function(e){var i=t(e);this._selectDate(i,"")},_selectDate:function(e,i){var s,n=t(e),o=this._getInst(n[0]);i=null!=i?i:this._formatDate(o),o.input&&o.input.val(i),this._updateAlternate(o),s=this._get(o,"onSelect"),s?s.apply(o.input?o.input[0]:null,[i,o]):o.input&&o.input.trigger("change"),o.inline?this._updateDatepicker(o):(this._hideDatepicker(),this._lastInput=o.input[0],"object"!=typeof o.input[0]&&o.input.focus(),this._lastInput=null)},_updateAlternate:function(e){var i,s,n,o=this._get(e,"altField");o&&(i=this._get(e,"altFormat")||this._get(e,"dateFormat"),s=this._getDate(e),n=this.formatDate(i,s,this._getFormatConfig(e)),t(o).each(function(){t(this).val(n)}))},noWeekends:function(t){var e=t.getDay();return[e>0&&6>e,""]},iso8601Week:function(t){var e,i=new Date(t.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),e=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((e-i)/864e5)/7)+1},parseDate:function(i,s,n){if(null==i||null==s)throw"Invalid arguments";if(s="object"==typeof s?""+s:s+"",""===s)return null;var o,a,r,h,l=0,c=(n?n.shortYearCutoff:null)||this._defaults.shortYearCutoff,u="string"!=typeof c?c:(new Date).getFullYear()%100+parseInt(c,10),d=(n?n.dayNamesShort:null)||this._defaults.dayNamesShort,p=(n?n.dayNames:null)||this._defaults.dayNames,f=(n?n.monthNamesShort:null)||this._defaults.monthNamesShort,g=(n?n.monthNames:null)||this._defaults.monthNames,m=-1,v=-1,_=-1,b=-1,y=!1,w=function(t){var e=i.length>o+1&&i.charAt(o+1)===t;return e&&o++,e},x=function(t){var e=w(t),i="@"===t?14:"!"===t?20:"y"===t&&e?4:"o"===t?3:2,n=RegExp("^\\d{1,"+i+"}"),o=s.substring(l).match(n);if(!o)throw"Missing number at position "+l;return l+=o[0].length,parseInt(o[0],10)},k=function(i,n,o){var a=-1,r=t.map(w(i)?o:n,function(t,e){return[[e,t]]}).sort(function(t,e){return-(t[1].length-e[1].length)});if(t.each(r,function(t,i){var n=i[1];return s.substr(l,n.length).toLowerCase()===n.toLowerCase()?(a=i[0],l+=n.length,!1):e}),-1!==a)return a+1;throw"Unknown name at position "+l},D=function(){if(s.charAt(l)!==i.charAt(o))throw"Unexpected literal at position "+l;l++};for(o=0;i.length>o;o++)if(y)"'"!==i.charAt(o)||w("'")?D():y=!1;else switch(i.charAt(o)){case"d":_=x("d");break;case"D":k("D",d,p);break;case"o":b=x("o");break;case"m":v=x("m");break;case"M":v=k("M",f,g);break;case"y":m=x("y");break;case"@":h=new Date(x("@")),m=h.getFullYear(),v=h.getMonth()+1,_=h.getDate();break;case"!":h=new Date((x("!")-this._ticksTo1970)/1e4),m=h.getFullYear(),v=h.getMonth()+1,_=h.getDate();break;case"'":w("'")?D():y=!0;break;default:D()}if(s.length>l&&(r=s.substr(l),!/^\s+/.test(r)))throw"Extra/unparsed characters found in date: "+r;if(-1===m?m=(new Date).getFullYear():100>m&&(m+=(new Date).getFullYear()-(new Date).getFullYear()%100+(u>=m?0:-100)),b>-1)for(v=1,_=b;;){if(a=this._getDaysInMonth(m,v-1),a>=_)break;v++,_-=a}if(h=this._daylightSavingAdjust(new Date(m,v-1,_)),h.getFullYear()!==m||h.getMonth()+1!==v||h.getDate()!==_)throw"Invalid date";return h},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(t,e,i){if(!e)return"";var s,n=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,o=(i?i.dayNames:null)||this._defaults.dayNames,a=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,r=(i?i.monthNames:null)||this._defaults.monthNames,h=function(e){var i=t.length>s+1&&t.charAt(s+1)===e;return i&&s++,i},l=function(t,e,i){var s=""+e;if(h(t))for(;i>s.length;)s="0"+s;return s},c=function(t,e,i,s){return h(t)?s[e]:i[e]},u="",d=!1;if(e)for(s=0;t.length>s;s++)if(d)"'"!==t.charAt(s)||h("'")?u+=t.charAt(s):d=!1;else switch(t.charAt(s)){case"d":u+=l("d",e.getDate(),2);break;case"D":u+=c("D",e.getDay(),n,o);break;case"o":u+=l("o",Math.round((new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime()-new Date(e.getFullYear(),0,0).getTime())/864e5),3);break;case"m":u+=l("m",e.getMonth()+1,2);break;case"M":u+=c("M",e.getMonth(),a,r);break;case"y":u+=h("y")?e.getFullYear():(10>e.getYear()%100?"0":"")+e.getYear()%100;break;case"@":u+=e.getTime();break;case"!":u+=1e4*e.getTime()+this._ticksTo1970;break;case"'":h("'")?u+="'":d=!0;break;default:u+=t.charAt(s)}return u},_possibleChars:function(t){var e,i="",s=!1,n=function(i){var s=t.length>e+1&&t.charAt(e+1)===i;return s&&e++,s};for(e=0;t.length>e;e++)if(s)"'"!==t.charAt(e)||n("'")?i+=t.charAt(e):s=!1;else switch(t.charAt(e)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":n("'")?i+="'":s=!0;break;default:i+=t.charAt(e)}return i},_get:function(t,i){return t.settings[i]!==e?t.settings[i]:this._defaults[i]},_setDateFromField:function(t,e){if(t.input.val()!==t.lastVal){var i=this._get(t,"dateFormat"),s=t.lastVal=t.input?t.input.val():null,n=this._getDefaultDate(t),o=n,a=this._getFormatConfig(t);try{o=this.parseDate(i,s,a)||n}catch(r){s=e?"":s}t.selectedDay=o.getDate(),t.drawMonth=t.selectedMonth=o.getMonth(),t.drawYear=t.selectedYear=o.getFullYear(),t.currentDay=s?o.getDate():0,t.currentMonth=s?o.getMonth():0,t.currentYear=s?o.getFullYear():0,this._adjustInstDate(t)}},_getDefaultDate:function(t){return this._restrictMinMax(t,this._determineDate(t,this._get(t,"defaultDate"),new Date))},_determineDate:function(e,i,s){var n=function(t){var e=new Date;return e.setDate(e.getDate()+t),e},o=function(i){try{return t.datepicker.parseDate(t.datepicker._get(e,"dateFormat"),i,t.datepicker._getFormatConfig(e))}catch(s){}for(var n=(i.toLowerCase().match(/^c/)?t.datepicker._getDate(e):null)||new Date,o=n.getFullYear(),a=n.getMonth(),r=n.getDate(),h=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,l=h.exec(i);l;){switch(l[2]||"d"){case"d":case"D":r+=parseInt(l[1],10);break;case"w":case"W":r+=7*parseInt(l[1],10);break;case"m":case"M":a+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a));break;case"y":case"Y":o+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a))}l=h.exec(i)}return new Date(o,a,r)},a=null==i||""===i?s:"string"==typeof i?o(i):"number"==typeof i?isNaN(i)?s:n(i):new Date(i.getTime());return a=a&&"Invalid Date"==""+a?s:a,a&&(a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0)),this._daylightSavingAdjust(a)},_daylightSavingAdjust:function(t){return t?(t.setHours(t.getHours()>12?t.getHours()+2:0),t):null},_setDate:function(t,e,i){var s=!e,n=t.selectedMonth,o=t.selectedYear,a=this._restrictMinMax(t,this._determineDate(t,e,new Date));t.selectedDay=t.currentDay=a.getDate(),t.drawMonth=t.selectedMonth=t.currentMonth=a.getMonth(),t.drawYear=t.selectedYear=t.currentYear=a.getFullYear(),n===t.selectedMonth&&o===t.selectedYear||i||this._notifyChange(t),this._adjustInstDate(t),t.input&&t.input.val(s?"":this._formatDate(t))},_getDate:function(t){var e=!t.currentYear||t.input&&""===t.input.val()?null:this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return e},_attachHandlers:function(e){var i=this._get(e,"stepMonths"),s="#"+e.id.replace(/\\\\/g,"\\");e.dpDiv.find("[data-handler]").map(function(){var e={prev:function(){t.datepicker._adjustDate(s,-i,"M")},next:function(){t.datepicker._adjustDate(s,+i,"M")},hide:function(){t.datepicker._hideDatepicker()},today:function(){t.datepicker._gotoToday(s)},selectDay:function(){return t.datepicker._selectDay(s,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return t.datepicker._selectMonthYear(s,this,"M"),!1},selectYear:function(){return t.datepicker._selectMonthYear(s,this,"Y"),!1}};t(this).bind(this.getAttribute("data-event"),e[this.getAttribute("data-handler")])})},_generateHTML:function(t){var e,i,s,n,o,a,r,h,l,c,u,d,p,f,g,m,v,_,b,y,w,x,k,D,C,I,P,T,M,S,z,A,E,H,N,W,O,F,R,L=new Date,j=this._daylightSavingAdjust(new Date(L.getFullYear(),L.getMonth(),L.getDate())),Y=this._get(t,"isRTL"),B=this._get(t,"showButtonPanel"),V=this._get(t,"hideIfNoPrevNext"),K=this._get(t,"navigationAsDateFormat"),q=this._getNumberOfMonths(t),U=this._get(t,"showCurrentAtPos"),Q=this._get(t,"stepMonths"),X=1!==q[0]||1!==q[1],$=this._daylightSavingAdjust(t.currentDay?new Date(t.currentYear,t.currentMonth,t.currentDay):new Date(9999,9,9)),G=this._getMinMaxDate(t,"min"),J=this._getMinMaxDate(t,"max"),Z=t.drawMonth-U,te=t.drawYear;if(0>Z&&(Z+=12,te--),J)for(e=this._daylightSavingAdjust(new Date(J.getFullYear(),J.getMonth()-q[0]*q[1]+1,J.getDate())),e=G&&G>e?G:e;this._daylightSavingAdjust(new Date(te,Z,1))>e;)Z--,0>Z&&(Z=11,te--);for(t.drawMonth=Z,t.drawYear=te,i=this._get(t,"prevText"),i=K?this.formatDate(i,this._daylightSavingAdjust(new Date(te,Z-Q,1)),this._getFormatConfig(t)):i,s=this._canAdjustMonth(t,-1,te,Z)?"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>":V?"":"<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>",n=this._get(t,"nextText"),n=K?this.formatDate(n,this._daylightSavingAdjust(new Date(te,Z+Q,1)),this._getFormatConfig(t)):n,o=this._canAdjustMonth(t,1,te,Z)?"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>":V?"":"<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>",a=this._get(t,"currentText"),r=this._get(t,"gotoCurrent")&&t.currentDay?$:j,a=K?this.formatDate(a,r,this._getFormatConfig(t)):a,h=t.inline?"":"<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>"+this._get(t,"closeText")+"</button>",l=B?"<div class='ui-datepicker-buttonpane ui-widget-content'>"+(Y?h:"")+(this._isInRange(t,r)?"<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'>"+a+"</button>":"")+(Y?"":h)+"</div>":"",c=parseInt(this._get(t,"firstDay"),10),c=isNaN(c)?0:c,u=this._get(t,"showWeek"),d=this._get(t,"dayNames"),p=this._get(t,"dayNamesMin"),f=this._get(t,"monthNames"),g=this._get(t,"monthNamesShort"),m=this._get(t,"beforeShowDay"),v=this._get(t,"showOtherMonths"),_=this._get(t,"selectOtherMonths"),b=this._getDefaultDate(t),y="",x=0;q[0]>x;x++){for(k="",this.maxRows=4,D=0;q[1]>D;D++){if(C=this._daylightSavingAdjust(new Date(te,Z,t.selectedDay)),I=" ui-corner-all",P="",X){if(P+="<div class='ui-datepicker-group",q[1]>1)switch(D){case 0:P+=" ui-datepicker-group-first",I=" ui-corner-"+(Y?"right":"left");break;case q[1]-1:P+=" ui-datepicker-group-last",I=" ui-corner-"+(Y?"left":"right");break;default:P+=" ui-datepicker-group-middle",I=""}P+="'>"}for(P+="<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix"+I+"'>"+(/all|left/.test(I)&&0===x?Y?o:s:"")+(/all|right/.test(I)&&0===x?Y?s:o:"")+this._generateMonthYearHeader(t,Z,te,G,J,x>0||D>0,f,g)+"</div><table class='ui-datepicker-calendar'><thead>"+"<tr>",T=u?"<th class='ui-datepicker-week-col'>"+this._get(t,"weekHeader")+"</th>":"",w=0;7>w;w++)M=(w+c)%7,T+="<th"+((w+c+6)%7>=5?" class='ui-datepicker-week-end'":"")+">"+"<span title='"+d[M]+"'>"+p[M]+"</span></th>";for(P+=T+"</tr></thead><tbody>",S=this._getDaysInMonth(te,Z),te===t.selectedYear&&Z===t.selectedMonth&&(t.selectedDay=Math.min(t.selectedDay,S)),z=(this._getFirstDayOfMonth(te,Z)-c+7)%7,A=Math.ceil((z+S)/7),E=X?this.maxRows>A?this.maxRows:A:A,this.maxRows=E,H=this._daylightSavingAdjust(new Date(te,Z,1-z)),N=0;E>N;N++){for(P+="<tr>",W=u?"<td class='ui-datepicker-week-col'>"+this._get(t,"calculateWeek")(H)+"</td>":"",w=0;7>w;w++)O=m?m.apply(t.input?t.input[0]:null,[H]):[!0,""],F=H.getMonth()!==Z,R=F&&!_||!O[0]||G&&G>H||J&&H>J,W+="<td class='"+((w+c+6)%7>=5?" ui-datepicker-week-end":"")+(F?" ui-datepicker-other-month":"")+(H.getTime()===C.getTime()&&Z===t.selectedMonth&&t._keyEvent||b.getTime()===H.getTime()&&b.getTime()===C.getTime()?" "+this._dayOverClass:"")+(R?" "+this._unselectableClass+" ui-state-disabled":"")+(F&&!v?"":" "+O[1]+(H.getTime()===$.getTime()?" "+this._currentClass:"")+(H.getTime()===j.getTime()?" ui-datepicker-today":""))+"'"+(F&&!v||!O[2]?"":" title='"+O[2].replace(/'/g,"&#39;")+"'")+(R?"":" data-handler='selectDay' data-event='click' data-month='"+H.getMonth()+"' data-year='"+H.getFullYear()+"'")+">"+(F&&!v?"&#xa0;":R?"<span class='ui-state-default'>"+H.getDate()+"</span>":"<a class='ui-state-default"+(H.getTime()===j.getTime()?" ui-state-highlight":"")+(H.getTime()===$.getTime()?" ui-state-active":"")+(F?" ui-priority-secondary":"")+"' href='#'>"+H.getDate()+"</a>")+"</td>",H.setDate(H.getDate()+1),H=this._daylightSavingAdjust(H);P+=W+"</tr>"}Z++,Z>11&&(Z=0,te++),P+="</tbody></table>"+(X?"</div>"+(q[0]>0&&D===q[1]-1?"<div class='ui-datepicker-row-break'></div>":""):""),k+=P}y+=k}return y+=l,t._keyEvent=!1,y},_generateMonthYearHeader:function(t,e,i,s,n,o,a,r){var h,l,c,u,d,p,f,g,m=this._get(t,"changeMonth"),v=this._get(t,"changeYear"),_=this._get(t,"showMonthAfterYear"),b="<div class='ui-datepicker-title'>",y="";if(o||!m)y+="<span class='ui-datepicker-month'>"+a[e]+"</span>";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,y+="<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>",c=0;12>c;c++)(!h||c>=s.getMonth())&&(!l||n.getMonth()>=c)&&(y+="<option value='"+c+"'"+(c===e?" selected='selected'":"")+">"+r[c]+"</option>");y+="</select>"}if(_||(b+=y+(!o&&m&&v?"":"&#xa0;")),!t.yearshtml)if(t.yearshtml="",o||!v)b+="<span class='ui-datepicker-year'>"+i+"</span>";else{for(u=this._get(t,"yearRange").split(":"),d=(new Date).getFullYear(),p=function(t){var e=t.match(/c[+\-].*/)?i+parseInt(t.substring(1),10):t.match(/[+\-].*/)?d+parseInt(t,10):parseInt(t,10);return isNaN(e)?d:e},f=p(u[0]),g=Math.max(f,p(u[1]||"")),f=s?Math.max(f,s.getFullYear()):f,g=n?Math.min(g,n.getFullYear()):g,t.yearshtml+="<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";g>=f;f++)t.yearshtml+="<option value='"+f+"'"+(f===i?" selected='selected'":"")+">"+f+"</option>";t.yearshtml+="</select>",b+=t.yearshtml,t.yearshtml=null}return b+=this._get(t,"yearSuffix"),_&&(b+=(!o&&m&&v?"":"&#xa0;")+y),b+="</div>"},_adjustInstDate:function(t,e,i){var s=t.drawYear+("Y"===i?e:0),n=t.drawMonth+("M"===i?e:0),o=Math.min(t.selectedDay,this._getDaysInMonth(s,n))+("D"===i?e:0),a=this._restrictMinMax(t,this._daylightSavingAdjust(new Date(s,n,o)));t.selectedDay=a.getDate(),t.drawMonth=t.selectedMonth=a.getMonth(),t.drawYear=t.selectedYear=a.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(t)},_restrictMinMax:function(t,e){var i=this._getMinMaxDate(t,"min"),s=this._getMinMaxDate(t,"max"),n=i&&i>e?i:e;return s&&n>s?s:n},_notifyChange:function(t){var e=this._get(t,"onChangeMonthYear");e&&e.apply(t.input?t.input[0]:null,[t.selectedYear,t.selectedMonth+1,t])},_getNumberOfMonths:function(t){var e=this._get(t,"numberOfMonths");return null==e?[1,1]:"number"==typeof e?[1,e]:e},_getMinMaxDate:function(t,e){return this._determineDate(t,this._get(t,e+"Date"),null)},_getDaysInMonth:function(t,e){return 32-this._daylightSavingAdjust(new Date(t,e,32)).getDate()},_getFirstDayOfMonth:function(t,e){return new Date(t,e,1).getDay()},_canAdjustMonth:function(t,e,i,s){var n=this._getNumberOfMonths(t),o=this._daylightSavingAdjust(new Date(i,s+(0>e?e:n[0]*n[1]),1));return 0>e&&o.setDate(this._getDaysInMonth(o.getFullYear(),o.getMonth())),this._isInRange(t,o)},_isInRange:function(t,e){var i,s,n=this._getMinMaxDate(t,"min"),o=this._getMinMaxDate(t,"max"),a=null,r=null,h=this._get(t,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),a=parseInt(i[0],10),r=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(a+=s),i[1].match(/[+\-].*/)&&(r+=s)),(!n||e.getTime()>=n.getTime())&&(!o||e.getTime()<=o.getTime())&&(!a||e.getFullYear()>=a)&&(!r||r>=e.getFullYear())},_getFormatConfig:function(t){var e=this._get(t,"shortYearCutoff");return e="string"!=typeof e?e:(new Date).getFullYear()%100+parseInt(e,10),{shortYearCutoff:e,dayNamesShort:this._get(t,"dayNamesShort"),dayNames:this._get(t,"dayNames"),monthNamesShort:this._get(t,"monthNamesShort"),monthNames:this._get(t,"monthNames")}},_formatDate:function(t,e,i,s){e||(t.currentDay=t.selectedDay,t.currentMonth=t.selectedMonth,t.currentYear=t.selectedYear);var n=e?"object"==typeof e?e:this._daylightSavingAdjust(new Date(s,i,e)):this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return this.formatDate(this._get(t,"dateFormat"),n,this._getFormatConfig(t))}}),t.fn.datepicker=function(e){if(!this.length)return this;t.datepicker.initialized||(t(document).mousedown(t.datepicker._checkExternalClick),t.datepicker.initialized=!0),0===t("#"+t.datepicker._mainDivId).length&&t("body").append(t.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof e||"isDisabled"!==e&&"getDate"!==e&&"widget"!==e?"option"===e&&2===arguments.length&&"string"==typeof arguments[1]?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof e?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this].concat(i)):t.datepicker._attachDatepicker(this,e)}):t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i))},t.datepicker=new i,t.datepicker.initialized=!1,t.datepicker.uuid=(new Date).getTime(),t.datepicker.version="1.10.4"}(jQuery),function(t){var e={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},i={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};t.widget("ui.dialog",{version:"1.10.4",options:{appendTo:"body",autoOpen:!0,buttons:[],closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(e){var i=t(this).css(e).offset().top;0>i&&t(this).css("top",e.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),this.options.title=this.options.title||this.originalTitle,this._createWrapper(),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(this.uiDialog),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&t.fn.draggable&&this._makeDraggable(),this.options.resizable&&t.fn.resizable&&this._makeResizable(),this._isOpen=!1},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var e=this.options.appendTo;return e&&(e.jquery||e.nodeType)?t(e):this.document.find(e||"body").eq(0)},_destroy:function(){var t,e=this.originalPosition;this._destroyOverlay(),this.element.removeUniqueId().removeClass("ui-dialog-content ui-widget-content").css(this.originalCss).detach(),this.uiDialog.stop(!0,!0).remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),t=e.parent.children().eq(e.index),t.length&&t[0]!==this.element[0]?t.before(this.element):e.parent.append(this.element)},widget:function(){return this.uiDialog},disable:t.noop,enable:t.noop,close:function(e){var i,s=this;if(this._isOpen&&this._trigger("beforeClose",e)!==!1){if(this._isOpen=!1,this._destroyOverlay(),!this.opener.filter(":focusable").focus().length)try{i=this.document[0].activeElement,i&&"body"!==i.nodeName.toLowerCase()&&t(i).blur()}catch(n){}this._hide(this.uiDialog,this.options.hide,function(){s._trigger("close",e)})}},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(t,e){var i=!!this.uiDialog.nextAll(":visible").insertBefore(this.uiDialog).length;return i&&!e&&this._trigger("focus",t),i},open:function(){var e=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),undefined):(this._isOpen=!0,this.opener=t(this.document[0].activeElement),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this._show(this.uiDialog,this.options.show,function(){e._focusTabbable(),e._trigger("focus")}),this._trigger("open"),undefined)},_focusTabbable:function(){var t=this.element.find("[autofocus]");t.length||(t=this.element.find(":tabbable")),t.length||(t=this.uiDialogButtonPane.find(":tabbable")),t.length||(t=this.uiDialogTitlebarClose.filter(":tabbable")),t.length||(t=this.uiDialog),t.eq(0).focus()},_keepFocus:function(e){function i(){var e=this.document[0].activeElement,i=this.uiDialog[0]===e||t.contains(this.uiDialog[0],e);i||this._focusTabbable()}e.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=t("<div>").addClass("ui-dialog ui-widget ui-widget-content ui-corner-all ui-front "+this.options.dialogClass).hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._on(this.uiDialog,{keydown:function(e){if(this.options.closeOnEscape&&!e.isDefaultPrevented()&&e.keyCode&&e.keyCode===t.ui.keyCode.ESCAPE)return e.preventDefault(),this.close(e),undefined;if(e.keyCode===t.ui.keyCode.TAB){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");e.target!==n[0]&&e.target!==this.uiDialog[0]||e.shiftKey?e.target!==s[0]&&e.target!==this.uiDialog[0]||!e.shiftKey||(n.focus(1),e.preventDefault()):(s.focus(1),e.preventDefault())}},mousedown:function(t){this._moveToTop(t)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var e;this.uiDialogTitlebar=t("<div>").addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(this.uiDialog),this._on(this.uiDialogTitlebar,{mousedown:function(e){t(e.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.focus()}}),this.uiDialogTitlebarClose=t("<button type='button'></button>").button({label:this.options.closeText,icons:{primary:"ui-icon-closethick"},text:!1}).addClass("ui-dialog-titlebar-close").appendTo(this.uiDialogTitlebar),this._on(this.uiDialogTitlebarClose,{click:function(t){t.preventDefault(),this.close(t)}}),e=t("<span>").uniqueId().addClass("ui-dialog-title").prependTo(this.uiDialogTitlebar),this._title(e),this.uiDialog.attr({"aria-labelledby":e.attr("id")})},_title:function(t){this.options.title||t.html("&#160;"),t.text(this.options.title)},_createButtonPane:function(){this.uiDialogButtonPane=t("<div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),this.uiButtonSet=t("<div>").addClass("ui-dialog-buttonset").appendTo(this.uiDialogButtonPane),this._createButtons()},_createButtons:function(){var e=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),t.isEmptyObject(i)||t.isArray(i)&&!i.length?(this.uiDialog.removeClass("ui-dialog-buttons"),undefined):(t.each(i,function(i,s){var n,o;s=t.isFunction(s)?{click:s,text:i}:s,s=t.extend({type:"button"},s),n=s.click,s.click=function(){n.apply(e.element[0],arguments)},o={icons:s.icons,text:s.showText},delete s.icons,delete s.showText,t("<button></button>",s).button(o).appendTo(e.uiButtonSet)}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),undefined)},_makeDraggable:function(){function e(t){return{position:t.position,offset:t.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){t(this).addClass("ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,e(n))},drag:function(t,s){i._trigger("drag",t,e(s))},stop:function(n,o){s.position=[o.position.left-i.document.scrollLeft(),o.position.top-i.document.scrollTop()],t(this).removeClass("ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,e(o))}})},_makeResizable:function(){function e(t){return{originalPosition:t.originalPosition,originalSize:t.originalSize,position:t.position,size:t.size}}var i=this,s=this.options,n=s.resizable,o=this.uiDialog.css("position"),a="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";
+this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:a,start:function(s,n){t(this).addClass("ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,e(n))},resize:function(t,s){i._trigger("resize",t,e(s))},stop:function(n,o){s.height=t(this).height(),s.width=t(this).width(),t(this).removeClass("ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,e(o))}}).css("position",o)},_minHeight:function(){var t=this.options;return"auto"===t.height?t.minHeight:Math.min(t.minHeight,t.height)},_position:function(){var t=this.uiDialog.is(":visible");t||this.uiDialog.show(),this.uiDialog.position(this.options.position),t||this.uiDialog.hide()},_setOptions:function(s){var n=this,o=!1,a={};t.each(s,function(t,s){n._setOption(t,s),t in e&&(o=!0),t in i&&(a[t]=s)}),o&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",a)},_setOption:function(t,e){var i,s,n=this.uiDialog;"dialogClass"===t&&n.removeClass(this.options.dialogClass).addClass(e),"disabled"!==t&&(this._super(t,e),"appendTo"===t&&this.uiDialog.appendTo(this._appendTo()),"buttons"===t&&this._createButtons(),"closeText"===t&&this.uiDialogTitlebarClose.button({label:""+e}),"draggable"===t&&(i=n.is(":data(ui-draggable)"),i&&!e&&n.draggable("destroy"),!i&&e&&this._makeDraggable()),"position"===t&&this._position(),"resizable"===t&&(s=n.is(":data(ui-resizable)"),s&&!e&&n.resizable("destroy"),s&&"string"==typeof e&&n.resizable("option","handles",e),s||e===!1||this._makeResizable()),"title"===t&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var t,e,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),t=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),e=Math.max(0,s.minHeight-t),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-t):"none","auto"===s.height?this.element.css({minHeight:e,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-t)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var e=t(this);return t("<div>").css({position:"absolute",width:e.outerWidth(),height:e.outerHeight()}).appendTo(e.parent()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(e){return t(e.target).closest(".ui-dialog").length?!0:!!t(e.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var e=this,i=this.widgetFullName;t.ui.dialog.overlayInstances||this._delay(function(){t.ui.dialog.overlayInstances&&this.document.bind("focusin.dialog",function(s){e._allowInteraction(s)||(s.preventDefault(),t(".ui-dialog:visible:last .ui-dialog-content").data(i)._focusTabbable())})}),this.overlay=t("<div>").addClass("ui-widget-overlay ui-front").appendTo(this._appendTo()),this._on(this.overlay,{mousedown:"_keepFocus"}),t.ui.dialog.overlayInstances++}},_destroyOverlay:function(){this.options.modal&&this.overlay&&(t.ui.dialog.overlayInstances--,t.ui.dialog.overlayInstances||this.document.unbind("focusin.dialog"),this.overlay.remove(),this.overlay=null)}}),t.ui.dialog.overlayInstances=0,t.uiBackCompat!==!1&&t.widget("ui.dialog",t.ui.dialog,{_position:function(){var e,i=this.options.position,s=[],n=[0,0];i?(("string"==typeof i||"object"==typeof i&&"0"in i)&&(s=i.split?i.split(" "):[i[0],i[1]],1===s.length&&(s[1]=s[0]),t.each(["left","top"],function(t,e){+s[t]===s[t]&&(n[t]=s[t],s[t]=e)}),i={my:s[0]+(0>n[0]?n[0]:"+"+n[0])+" "+s[1]+(0>n[1]?n[1]:"+"+n[1]),at:s.join(" ")}),i=t.extend({},t.ui.dialog.prototype.options.position,i)):i=t.ui.dialog.prototype.options.position,e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.position(i),e||this.uiDialog.hide()}})}(jQuery),function(t){var e=/up|down|vertical/,i=/up|left|vertical|horizontal/;t.effects.effect.blind=function(s,n){var o,a,r,h=t(this),l=["position","top","bottom","left","right","height","width"],c=t.effects.setMode(h,s.mode||"hide"),u=s.direction||"up",d=e.test(u),p=d?"height":"width",f=d?"top":"left",g=i.test(u),m={},v="show"===c;h.parent().is(".ui-effects-wrapper")?t.effects.save(h.parent(),l):t.effects.save(h,l),h.show(),o=t.effects.createWrapper(h).css({overflow:"hidden"}),a=o[p](),r=parseFloat(o.css(f))||0,m[p]=v?a:0,g||(h.css(d?"bottom":"right",0).css(d?"top":"left","auto").css({position:"absolute"}),m[f]=v?r:a+r),v&&(o.css(p,0),g||o.css(f,r+a)),o.animate(m,{duration:s.duration,easing:s.easing,queue:!1,complete:function(){"hide"===c&&h.hide(),t.effects.restore(h,l),t.effects.removeWrapper(h),n()}})}}(jQuery),function(t){t.effects.effect.bounce=function(e,i){var s,n,o,a=t(this),r=["position","top","bottom","left","right","height","width"],h=t.effects.setMode(a,e.mode||"effect"),l="hide"===h,c="show"===h,u=e.direction||"up",d=e.distance,p=e.times||5,f=2*p+(c||l?1:0),g=e.duration/f,m=e.easing,v="up"===u||"down"===u?"top":"left",_="up"===u||"left"===u,b=a.queue(),y=b.length;for((c||l)&&r.push("opacity"),t.effects.save(a,r),a.show(),t.effects.createWrapper(a),d||(d=a["top"===v?"outerHeight":"outerWidth"]()/3),c&&(o={opacity:1},o[v]=0,a.css("opacity",0).css(v,_?2*-d:2*d).animate(o,g,m)),l&&(d/=Math.pow(2,p-1)),o={},o[v]=0,s=0;p>s;s++)n={},n[v]=(_?"-=":"+=")+d,a.animate(n,g,m).animate(o,g,m),d=l?2*d:d/2;l&&(n={opacity:0},n[v]=(_?"-=":"+=")+d,a.animate(n,g,m)),a.queue(function(){l&&a.hide(),t.effects.restore(a,r),t.effects.removeWrapper(a),i()}),y>1&&b.splice.apply(b,[1,0].concat(b.splice(y,f+1))),a.dequeue()}}(jQuery),function(t){t.effects.effect.clip=function(e,i){var s,n,o,a=t(this),r=["position","top","bottom","left","right","height","width"],h=t.effects.setMode(a,e.mode||"hide"),l="show"===h,c=e.direction||"vertical",u="vertical"===c,d=u?"height":"width",p=u?"top":"left",f={};t.effects.save(a,r),a.show(),s=t.effects.createWrapper(a).css({overflow:"hidden"}),n="IMG"===a[0].tagName?s:a,o=n[d](),l&&(n.css(d,0),n.css(p,o/2)),f[d]=l?o:0,f[p]=l?0:o/2,n.animate(f,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){l||a.hide(),t.effects.restore(a,r),t.effects.removeWrapper(a),i()}})}}(jQuery),function(t){t.effects.effect.drop=function(e,i){var s,n=t(this),o=["position","top","bottom","left","right","opacity","height","width"],a=t.effects.setMode(n,e.mode||"hide"),r="show"===a,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h?"pos":"neg",u={opacity:r?1:0};t.effects.save(n,o),n.show(),t.effects.createWrapper(n),s=e.distance||n["top"===l?"outerHeight":"outerWidth"](!0)/2,r&&n.css("opacity",0).css(l,"pos"===c?-s:s),u[l]=(r?"pos"===c?"+=":"-=":"pos"===c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===a&&n.hide(),t.effects.restore(n,o),t.effects.removeWrapper(n),i()}})}}(jQuery),function(t){t.effects.effect.explode=function(e,i){function s(){b.push(this),b.length===u*d&&n()}function n(){p.css({visibility:"visible"}),t(b).remove(),g||p.hide(),i()}var o,a,r,h,l,c,u=e.pieces?Math.round(Math.sqrt(e.pieces)):3,d=u,p=t(this),f=t.effects.setMode(p,e.mode||"hide"),g="show"===f,m=p.show().css("visibility","hidden").offset(),v=Math.ceil(p.outerWidth()/d),_=Math.ceil(p.outerHeight()/u),b=[];for(o=0;u>o;o++)for(h=m.top+o*_,c=o-(u-1)/2,a=0;d>a;a++)r=m.left+a*v,l=a-(d-1)/2,p.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-a*v,top:-o*_}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:v,height:_,left:r+(g?l*v:0),top:h+(g?c*_:0),opacity:g?0:1}).animate({left:r+(g?0:l*v),top:h+(g?0:c*_),opacity:g?1:0},e.duration||500,e.easing,s)}}(jQuery),function(t){t.effects.effect.fade=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"toggle");s.animate({opacity:n},{queue:!1,duration:e.duration,easing:e.easing,complete:i})}}(jQuery),function(t){t.effects.effect.fold=function(e,i){var s,n,o=t(this),a=["position","top","bottom","left","right","height","width"],r=t.effects.setMode(o,e.mode||"hide"),h="show"===r,l="hide"===r,c=e.size||15,u=/([0-9]+)%/.exec(c),d=!!e.horizFirst,p=h!==d,f=p?["width","height"]:["height","width"],g=e.duration/2,m={},v={};t.effects.save(o,a),o.show(),s=t.effects.createWrapper(o).css({overflow:"hidden"}),n=p?[s.width(),s.height()]:[s.height(),s.width()],u&&(c=parseInt(u[1],10)/100*n[l?0:1]),h&&s.css(d?{height:0,width:c}:{height:c,width:0}),m[f[0]]=h?n[0]:c,v[f[1]]=h?n[1]:0,s.animate(m,g,e.easing).animate(v,g,e.easing,function(){l&&o.hide(),t.effects.restore(o,a),t.effects.removeWrapper(o),i()})}}(jQuery),function(t){t.effects.effect.highlight=function(e,i){var s=t(this),n=["backgroundImage","backgroundColor","opacity"],o=t.effects.setMode(s,e.mode||"show"),a={backgroundColor:s.css("backgroundColor")};"hide"===o&&(a.opacity=0),t.effects.save(s,n),s.show().css({backgroundImage:"none",backgroundColor:e.color||"#ffff99"}).animate(a,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===o&&s.hide(),t.effects.restore(s,n),i()}})}}(jQuery),function(t){t.effects.effect.pulsate=function(e,i){var s,n=t(this),o=t.effects.setMode(n,e.mode||"show"),a="show"===o,r="hide"===o,h=a||"hide"===o,l=2*(e.times||5)+(h?1:0),c=e.duration/l,u=0,d=n.queue(),p=d.length;for((a||!n.is(":visible"))&&(n.css("opacity",0).show(),u=1),s=1;l>s;s++)n.animate({opacity:u},c,e.easing),u=1-u;n.animate({opacity:u},c,e.easing),n.queue(function(){r&&n.hide(),i()}),p>1&&d.splice.apply(d,[1,0].concat(d.splice(p,l+1))),n.dequeue()}}(jQuery),function(t){t.effects.effect.puff=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"hide"),o="hide"===n,a=parseInt(e.percent,10)||150,r=a/100,h={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()};t.extend(e,{effect:"scale",queue:!1,fade:!0,mode:n,complete:i,percent:o?a:100,from:o?h:{height:h.height*r,width:h.width*r,outerHeight:h.outerHeight*r,outerWidth:h.outerWidth*r}}),s.effect(e)},t.effects.effect.scale=function(e,i){var s=t(this),n=t.extend(!0,{},e),o=t.effects.setMode(s,e.mode||"effect"),a=parseInt(e.percent,10)||(0===parseInt(e.percent,10)?0:"hide"===o?0:100),r=e.direction||"both",h=e.origin,l={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()},c={y:"horizontal"!==r?a/100:1,x:"vertical"!==r?a/100:1};n.effect="size",n.queue=!1,n.complete=i,"effect"!==o&&(n.origin=h||["middle","center"],n.restore=!0),n.from=e.from||("show"===o?{height:0,width:0,outerHeight:0,outerWidth:0}:l),n.to={height:l.height*c.y,width:l.width*c.x,outerHeight:l.outerHeight*c.y,outerWidth:l.outerWidth*c.x},n.fade&&("show"===o&&(n.from.opacity=0,n.to.opacity=1),"hide"===o&&(n.from.opacity=1,n.to.opacity=0)),s.effect(n)},t.effects.effect.size=function(e,i){var s,n,o,a=t(this),r=["position","top","bottom","left","right","width","height","overflow","opacity"],h=["position","top","bottom","left","right","overflow","opacity"],l=["width","height","overflow"],c=["fontSize"],u=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],d=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=t.effects.setMode(a,e.mode||"effect"),f=e.restore||"effect"!==p,g=e.scale||"both",m=e.origin||["middle","center"],v=a.css("position"),_=f?r:h,b={height:0,width:0,outerHeight:0,outerWidth:0};"show"===p&&a.show(),s={height:a.height(),width:a.width(),outerHeight:a.outerHeight(),outerWidth:a.outerWidth()},"toggle"===e.mode&&"show"===p?(a.from=e.to||b,a.to=e.from||s):(a.from=e.from||("show"===p?b:s),a.to=e.to||("hide"===p?b:s)),o={from:{y:a.from.height/s.height,x:a.from.width/s.width},to:{y:a.to.height/s.height,x:a.to.width/s.width}},("box"===g||"both"===g)&&(o.from.y!==o.to.y&&(_=_.concat(u),a.from=t.effects.setTransition(a,u,o.from.y,a.from),a.to=t.effects.setTransition(a,u,o.to.y,a.to)),o.from.x!==o.to.x&&(_=_.concat(d),a.from=t.effects.setTransition(a,d,o.from.x,a.from),a.to=t.effects.setTransition(a,d,o.to.x,a.to))),("content"===g||"both"===g)&&o.from.y!==o.to.y&&(_=_.concat(c).concat(l),a.from=t.effects.setTransition(a,c,o.from.y,a.from),a.to=t.effects.setTransition(a,c,o.to.y,a.to)),t.effects.save(a,_),a.show(),t.effects.createWrapper(a),a.css("overflow","hidden").css(a.from),m&&(n=t.effects.getBaseline(m,s),a.from.top=(s.outerHeight-a.outerHeight())*n.y,a.from.left=(s.outerWidth-a.outerWidth())*n.x,a.to.top=(s.outerHeight-a.to.outerHeight)*n.y,a.to.left=(s.outerWidth-a.to.outerWidth)*n.x),a.css(a.from),("content"===g||"both"===g)&&(u=u.concat(["marginTop","marginBottom"]).concat(c),d=d.concat(["marginLeft","marginRight"]),l=r.concat(u).concat(d),a.find("*[width]").each(function(){var i=t(this),s={height:i.height(),width:i.width(),outerHeight:i.outerHeight(),outerWidth:i.outerWidth()};f&&t.effects.save(i,l),i.from={height:s.height*o.from.y,width:s.width*o.from.x,outerHeight:s.outerHeight*o.from.y,outerWidth:s.outerWidth*o.from.x},i.to={height:s.height*o.to.y,width:s.width*o.to.x,outerHeight:s.height*o.to.y,outerWidth:s.width*o.to.x},o.from.y!==o.to.y&&(i.from=t.effects.setTransition(i,u,o.from.y,i.from),i.to=t.effects.setTransition(i,u,o.to.y,i.to)),o.from.x!==o.to.x&&(i.from=t.effects.setTransition(i,d,o.from.x,i.from),i.to=t.effects.setTransition(i,d,o.to.x,i.to)),i.css(i.from),i.animate(i.to,e.duration,e.easing,function(){f&&t.effects.restore(i,l)})})),a.animate(a.to,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){0===a.to.opacity&&a.css("opacity",a.from.opacity),"hide"===p&&a.hide(),t.effects.restore(a,_),f||("static"===v?a.css({position:"relative",top:a.to.top,left:a.to.left}):t.each(["top","left"],function(t,e){a.css(e,function(e,i){var s=parseInt(i,10),n=t?a.to.left:a.to.top;return"auto"===i?n+"px":s+n+"px"})})),t.effects.removeWrapper(a),i()}})}}(jQuery),function(t){t.effects.effect.shake=function(e,i){var s,n=t(this),o=["position","top","bottom","left","right","height","width"],a=t.effects.setMode(n,e.mode||"effect"),r=e.direction||"left",h=e.distance||20,l=e.times||3,c=2*l+1,u=Math.round(e.duration/c),d="up"===r||"down"===r?"top":"left",p="up"===r||"left"===r,f={},g={},m={},v=n.queue(),_=v.length;for(t.effects.save(n,o),n.show(),t.effects.createWrapper(n),f[d]=(p?"-=":"+=")+h,g[d]=(p?"+=":"-=")+2*h,m[d]=(p?"-=":"+=")+2*h,n.animate(f,u,e.easing),s=1;l>s;s++)n.animate(g,u,e.easing).animate(m,u,e.easing);n.animate(g,u,e.easing).animate(f,u/2,e.easing).queue(function(){"hide"===a&&n.hide(),t.effects.restore(n,o),t.effects.removeWrapper(n),i()}),_>1&&v.splice.apply(v,[1,0].concat(v.splice(_,c+1))),n.dequeue()}}(jQuery),function(t){t.effects.effect.slide=function(e,i){var s,n=t(this),o=["position","top","bottom","left","right","width","height"],a=t.effects.setMode(n,e.mode||"show"),r="show"===a,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h,u={};t.effects.save(n,o),n.show(),s=e.distance||n["top"===l?"outerHeight":"outerWidth"](!0),t.effects.createWrapper(n).css({overflow:"hidden"}),r&&n.css(l,c?isNaN(s)?"-"+s:-s:s),u[l]=(r?c?"+=":"-=":c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===a&&n.hide(),t.effects.restore(n,o),t.effects.removeWrapper(n),i()}})}}(jQuery),function(t){t.effects.effect.transfer=function(e,i){var s=t(this),n=t(e.to),o="fixed"===n.css("position"),a=t("body"),r=o?a.scrollTop():0,h=o?a.scrollLeft():0,l=n.offset(),c={top:l.top-r,left:l.left-h,height:n.innerHeight(),width:n.innerWidth()},u=s.offset(),d=t("<div class='ui-effects-transfer'></div>").appendTo(document.body).addClass(e.className).css({top:u.top-r,left:u.left-h,height:s.innerHeight(),width:s.innerWidth(),position:o?"fixed":"absolute"}).animate(c,e.duration,e.easing,function(){d.remove(),i()})}}(jQuery),function(t){t.widget("ui.menu",{version:"1.10.4",defaultElement:"<ul>",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content ui-corner-all").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}).bind("click"+this.eventNamespace,t.proxy(function(t){this.options.disabled&&t.preventDefault()},this)),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item > a":function(t){t.preventDefault()},"click .ui-state-disabled > a":function(t){t.preventDefault()},"click .ui-menu-item:has(a)":function(e){var i=t(e.target).closest(".ui-menu-item");!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.select(e),e.isPropagationStopped()||(this.mouseHandled=!0),i.has(".ui-menu").length?this.expand(e):!this.element.is(":focus")&&t(this.document[0].activeElement).closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(e){var i=t(e.currentTarget);i.siblings().children(".ui-state-active").removeClass("ui-state-active"),this.focus(e,i)},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this.element.children(".ui-menu-item").eq(0);e||this.focus(t,i)},blur:function(e){this._delay(function(){t.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(e)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(e){t(e.target).closest(".ui-menu").length||this.collapseAll(e),this.mouseHandled=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").children("a").removeUniqueId().removeClass("ui-corner-all ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var e=t(this);e.data("ui-menu-submenu-carat")&&e.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(e){function i(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}var s,n,o,a,r,h=!0;switch(e.keyCode){case t.ui.keyCode.PAGE_UP:this.previousPage(e);break;case t.ui.keyCode.PAGE_DOWN:this.nextPage(e);break;case t.ui.keyCode.HOME:this._move("first","first",e);break;case t.ui.keyCode.END:this._move("last","last",e);break;case t.ui.keyCode.UP:this.previous(e);break;case t.ui.keyCode.DOWN:this.next(e);break;case t.ui.keyCode.LEFT:this.collapse(e);break;case t.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(e);break;case t.ui.keyCode.ENTER:case t.ui.keyCode.SPACE:this._activate(e);break;case t.ui.keyCode.ESCAPE:this.collapse(e);break;default:h=!1,n=this.previousFilter||"",o=String.fromCharCode(e.keyCode),a=!1,clearTimeout(this.filterTimer),o===n?a=!0:o=n+o,r=RegExp("^"+i(o),"i"),s=this.activeMenu.children(".ui-menu-item").filter(function(){return r.test(t(this).children("a").text())}),s=a&&-1!==s.index(this.active.next())?this.active.nextAll(".ui-menu-item"):s,s.length||(o=String.fromCharCode(e.keyCode),r=RegExp("^"+i(o),"i"),s=this.activeMenu.children(".ui-menu-item").filter(function(){return r.test(t(this).children("a").text())})),s.length?(this.focus(e,s),s.length>1?(this.previousFilter=o,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter):delete this.previousFilter}h&&e.preventDefault()},_activate:function(t){this.active.is(".ui-state-disabled")||(this.active.children("a[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var e,i=this.options.icons.submenu,s=this.element.find(this.options.menus);this.element.toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length),s.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-corner-all").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var e=t(this),s=e.prev("a"),n=t("<span>").addClass("ui-menu-icon ui-icon "+i).data("ui-menu-submenu-carat",!0);s.attr("aria-haspopup","true").prepend(n),e.attr("aria-labelledby",s.attr("id"))}),e=s.add(this.element),e.children(":not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","presentation").children("a").uniqueId().addClass("ui-corner-all").attr({tabIndex:-1,role:this._itemRole()}),e.children(":not(.ui-menu-item)").each(function(){var e=t(this);/[^\-\u2014\u2013\s]/.test(e.text())||e.addClass("ui-widget-content ui-menu-divider")}),e.children(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!t.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){"icons"===t&&this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(e.submenu),this._super(t,e)},focus:function(t,e){var i,s;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),s=this.active.children("a").addClass("ui-state-focus"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=e.children(".ui-menu"),i.length&&t&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(e){var i,s,n,o,a,r;this._hasScroll()&&(i=parseFloat(t.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(t.css(this.activeMenu[0],"paddingTop"))||0,n=e.offset().top-this.activeMenu.offset().top-i-s,o=this.activeMenu.scrollTop(),a=this.activeMenu.height(),r=e.height(),0>n?this.activeMenu.scrollTop(o+n):n+r>a&&this.activeMenu.scrollTop(o+n-a+r))},blur:function(t,e){e||clearTimeout(this.timer),this.active&&(this.active.children("a").removeClass("ui-state-focus"),this.active=null,this._trigger("blur",t,{item:this.active}))},_startOpening:function(t){clearTimeout(this.timer),"true"===t.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(t)},this.delay))},_open:function(e){var i=t.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(e.parents(".ui-menu")).hide().attr("aria-hidden","true"),e.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(e,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:t(e&&e.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(e),this.activeMenu=s},this.delay)},_close:function(t){t||(t=this.active?this.active.parent():this.element),t.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find("a.ui-state-active").removeClass("ui-state-active")},collapse:function(t){var e=this.active&&this.active.parent().closest(".ui-menu-item",this.element);e&&e.length&&(this._close(),this.focus(t,e))},expand:function(t){var e=this.active&&this.active.children(".ui-menu ").children(".ui-menu-item").first();e&&e.length&&(this._open(e.parent()),this._delay(function(){this.focus(t,e)}))},next:function(t){this._move("next","first",t)},previous:function(t){this._move("prev","last",t)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(t,e,i){var s;this.active&&(s="first"===t||"last"===t?this.active["first"===t?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[t+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.children(".ui-menu-item")[e]()),this.focus(i,s)},nextPage:function(e){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=t(this),0>i.offset().top-s-n}),this.focus(e,i)):this.focus(e,this.activeMenu.children(".ui-menu-item")[this.active?"last":"first"]())),undefined):(this.next(e),undefined)},previousPage:function(e){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=t(this),i.offset().top-s+n>0}),this.focus(e,i)):this.focus(e,this.activeMenu.children(".ui-menu-item").first())),undefined):(this.next(e),undefined)},_hasScroll:function(){return this.element.outerHeight()<this.element.prop("scrollHeight")},select:function(e){this.active=this.active||t(e.target).closest(".ui-menu-item");var i={item:this.active};this.active.has(".ui-menu").length||this.collapseAll(e,!0),this._trigger("select",e,i)}})}(jQuery),function(t,e){function i(t,e,i){return[parseFloat(t[0])*(p.test(t[0])?e/100:1),parseFloat(t[1])*(p.test(t[1])?i/100:1)]}function s(e,i){return parseInt(t.css(e,i),10)||0}function n(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}t.ui=t.ui||{};var o,a=Math.max,r=Math.abs,h=Math.round,l=/left|center|right/,c=/top|center|bottom/,u=/[\+\-]\d+(\.[\d]+)?%?/,d=/^\w+/,p=/%$/,f=t.fn.position;t.position={scrollbarWidth:function(){if(o!==e)return o;var i,s,n=t("<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>"),a=n.children()[0];return t("body").append(n),i=a.offsetWidth,n.css("overflow","scroll"),s=a.offsetWidth,i===s&&(s=n[0].clientWidth),n.remove(),o=i-s},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.width<e.element[0].scrollWidth,o="scroll"===s||"auto"===s&&e.height<e.element[0].scrollHeight;return{width:o?t.position.scrollbarWidth():0,height:n?t.position.scrollbarWidth():0}},getWithinInfo:function(e){var i=t(e||window),s=t.isWindow(i[0]),n=!!i[0]&&9===i[0].nodeType;return{element:i,isWindow:s,isDocument:n,offset:i.offset()||{left:0,top:0},scrollLeft:i.scrollLeft(),scrollTop:i.scrollTop(),width:s?i.width():i.outerWidth(),height:s?i.height():i.outerHeight()}}},t.fn.position=function(e){if(!e||!e.of)return f.apply(this,arguments);e=t.extend({},e);var o,p,g,m,v,_,b=t(e.of),y=t.position.getWithinInfo(e.within),w=t.position.getScrollInfo(y),x=(e.collision||"flip").split(" "),k={};return _=n(b),b[0].preventDefault&&(e.at="left top"),p=_.width,g=_.height,m=_.offset,v=t.extend({},m),t.each(["my","at"],function(){var t,i,s=(e[this]||"").split(" ");1===s.length&&(s=l.test(s[0])?s.concat(["center"]):c.test(s[0])?["center"].concat(s):["center","center"]),s[0]=l.test(s[0])?s[0]:"center",s[1]=c.test(s[1])?s[1]:"center",t=u.exec(s[0]),i=u.exec(s[1]),k[this]=[t?t[0]:0,i?i[0]:0],e[this]=[d.exec(s[0])[0],d.exec(s[1])[0]]}),1===x.length&&(x[1]=x[0]),"right"===e.at[0]?v.left+=p:"center"===e.at[0]&&(v.left+=p/2),"bottom"===e.at[1]?v.top+=g:"center"===e.at[1]&&(v.top+=g/2),o=i(k.at,p,g),v.left+=o[0],v.top+=o[1],this.each(function(){var n,l,c=t(this),u=c.outerWidth(),d=c.outerHeight(),f=s(this,"marginLeft"),_=s(this,"marginTop"),D=u+f+s(this,"marginRight")+w.width,C=d+_+s(this,"marginBottom")+w.height,I=t.extend({},v),P=i(k.my,c.outerWidth(),c.outerHeight());"right"===e.my[0]?I.left-=u:"center"===e.my[0]&&(I.left-=u/2),"bottom"===e.my[1]?I.top-=d:"center"===e.my[1]&&(I.top-=d/2),I.left+=P[0],I.top+=P[1],t.support.offsetFractions||(I.left=h(I.left),I.top=h(I.top)),n={marginLeft:f,marginTop:_},t.each(["left","top"],function(i,s){t.ui.position[x[i]]&&t.ui.position[x[i]][s](I,{targetWidth:p,targetHeight:g,elemWidth:u,elemHeight:d,collisionPosition:n,collisionWidth:D,collisionHeight:C,offset:[o[0]+P[0],o[1]+P[1]],my:e.my,at:e.at,within:y,elem:c})}),e.using&&(l=function(t){var i=m.left-I.left,s=i+p-u,n=m.top-I.top,o=n+g-d,h={target:{element:b,left:m.left,top:m.top,width:p,height:g},element:{element:c,left:I.left,top:I.top,width:u,height:d},horizontal:0>s?"left":i>0?"right":"center",vertical:0>o?"top":n>0?"bottom":"middle"};u>p&&p>r(i+s)&&(h.horizontal="center"),d>g&&g>r(n+o)&&(h.vertical="middle"),h.important=a(r(i),r(s))>a(r(n),r(o))?"horizontal":"vertical",e.using.call(this,t,h)}),c.offset(t.extend(I,{using:l}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,o=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-o-n;e.collisionWidth>o?h>0&&0>=l?(i=t.left+h+e.collisionWidth-o-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+o-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=a(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,o=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-o-n;e.collisionHeight>o?h>0&&0>=l?(i=t.top+h+e.collisionHeight-o-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+o-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=a(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,a=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-a-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-a-o,(0>i||r(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>r(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,a=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-a-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,g=-2*e.offset[1];0>c?(s=t.top+p+f+g+e.collisionHeight-a-o,t.top+p+f+g>c&&(0>s||r(c)>s)&&(t.top+=p+f+g)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+g-h,t.top+p+f+g>u&&(i>0||u>r(i))&&(t.top+=p+f+g))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}},function(){var e,i,s,n,o,a=document.getElementsByTagName("body")[0],r=document.createElement("div");e=document.createElement(a?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},a&&t.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(o in s)e.style[o]=s[o];e.appendChild(r),i=a||document.documentElement,i.insertBefore(e,i.firstChild),r.style.cssText="position: absolute; left: 10.7432222px;",n=t(r).offset().left,t.support.offsetFractions=n>10&&11>n,e.innerHTML="",i.removeChild(e)}()}(jQuery),function(t,e){t.widget("ui.progressbar",{version:"1.10.4",options:{max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min}),this.valueDiv=t("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this._refreshValue()
+},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(t){return t===e?this.options.value:(this.options.value=this._constrainedValue(t),this._refreshValue(),e)},_constrainedValue:function(t){return t===e&&(t=this.options.value),this.indeterminate=t===!1,"number"!=typeof t&&(t=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,t))},_setOptions:function(t){var e=t.value;delete t.value,this._super(t),this.options.value=this._constrainedValue(e),this._refreshValue()},_setOption:function(t,e){"max"===t&&(e=Math.max(this.min,e)),this._super(t,e)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var e=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||e>this.min).toggleClass("ui-corner-right",e===this.options.max).width(i.toFixed(0)+"%"),this.element.toggleClass("ui-progressbar-indeterminate",this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=t("<div class='ui-progressbar-overlay'></div>").appendTo(this.valueDiv))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":e}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),e===this.options.max&&this._trigger("complete")}})}(jQuery),function(t){var e=5;t.widget("ui.slider",t.ui.mouse,{version:"1.10.4",widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},_create:function(){this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"),this._refresh(),this._setOption("disabled",this.options.disabled),this._animateOff=!1},_refresh:function(){this._createRange(),this._createHandles(),this._setupEvents(),this._refreshValue()},_createHandles:function(){var e,i,s=this.options,n=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),o="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",a=[];for(i=s.values&&s.values.length||1,n.length>i&&(n.slice(i).remove(),n=n.slice(0,i)),e=n.length;i>e;e++)a.push(o);this.handles=n.add(t(a.join("")).appendTo(this.element)),this.handle=this.handles.eq(0),this.handles.each(function(e){t(this).data("ui-slider-handle-index",e)})},_createRange:function(){var e=this.options,i="";e.range?(e.range===!0&&(e.values?e.values.length&&2!==e.values.length?e.values=[e.values[0],e.values[0]]:t.isArray(e.values)&&(e.values=e.values.slice(0)):e.values=[this._valueMin(),this._valueMin()]),this.range&&this.range.length?this.range.removeClass("ui-slider-range-min ui-slider-range-max").css({left:"",bottom:""}):(this.range=t("<div></div>").appendTo(this.element),i="ui-slider-range ui-widget-header ui-corner-all"),this.range.addClass(i+("min"===e.range||"max"===e.range?" ui-slider-range-"+e.range:""))):(this.range&&this.range.remove(),this.range=null)},_setupEvents:function(){var t=this.handles.add(this.range).filter("a");this._off(t),this._on(t,this._handleEvents),this._hoverable(t),this._focusable(t)},_destroy:function(){this.handles.remove(),this.range&&this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-widget ui-widget-content ui-corner-all"),this._mouseDestroy()},_mouseCapture:function(e){var i,s,n,o,a,r,h,l,c=this,u=this.options;return u.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),i={x:e.pageX,y:e.pageY},s=this._normValueFromMouse(i),n=this._valueMax()-this._valueMin()+1,this.handles.each(function(e){var i=Math.abs(s-c.values(e));(n>i||n===i&&(e===c._lastChangedValue||c.values(e)===u.min))&&(n=i,o=t(this),a=e)}),r=this._start(e,a),r===!1?!1:(this._mouseSliding=!0,this._handleIndex=a,o.addClass("ui-state-active").focus(),h=o.offset(),l=!t(e.target).parents().addBack().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:e.pageX-h.left-o.width()/2,top:e.pageY-h.top-o.height()/2-(parseInt(o.css("borderTopWidth"),10)||0)-(parseInt(o.css("borderBottomWidth"),10)||0)+(parseInt(o.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(e,a,s),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(t){var e={x:t.pageX,y:t.pageY},i=this._normValueFromMouse(e);return this._slide(t,this._handleIndex,i),!1},_mouseStop:function(t){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(t,this._handleIndex),this._change(t,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation="vertical"===this.options.orientation?"vertical":"horizontal"},_normValueFromMouse:function(t){var e,i,s,n,o;return"horizontal"===this.orientation?(e=this.elementSize.width,i=t.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(e=this.elementSize.height,i=t.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),s=i/e,s>1&&(s=1),0>s&&(s=0),"vertical"===this.orientation&&(s=1-s),n=this._valueMax()-this._valueMin(),o=this._valueMin()+s*n,this._trimAlignValue(o)},_start:function(t,e){var i={handle:this.handles[e],value:this.value()};return this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._trigger("start",t,i)},_slide:function(t,e,i){var s,n,o;this.options.values&&this.options.values.length?(s=this.values(e?0:1),2===this.options.values.length&&this.options.range===!0&&(0===e&&i>s||1===e&&s>i)&&(i=s),i!==this.values(e)&&(n=this.values(),n[e]=i,o=this._trigger("slide",t,{handle:this.handles[e],value:i,values:n}),s=this.values(e?0:1),o!==!1&&this.values(e,i))):i!==this.value()&&(o=this._trigger("slide",t,{handle:this.handles[e],value:i}),o!==!1&&this.value(i))},_stop:function(t,e){var i={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._trigger("stop",t,i)},_change:function(t,e){if(!this._keySliding&&!this._mouseSliding){var i={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._lastChangedValue=e,this._trigger("change",t,i)}},value:function(t){return arguments.length?(this.options.value=this._trimAlignValue(t),this._refreshValue(),this._change(null,0),undefined):this._value()},values:function(e,i){var s,n,o;if(arguments.length>1)return this.options.values[e]=this._trimAlignValue(i),this._refreshValue(),this._change(null,e),undefined;if(!arguments.length)return this._values();if(!t.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(e):this.value();for(s=this.options.values,n=arguments[0],o=0;s.length>o;o+=1)s[o]=this._trimAlignValue(n[o]),this._change(null,o);this._refreshValue()},_setOption:function(e,i){var s,n=0;switch("range"===e&&this.options.range===!0&&("min"===i?(this.options.value=this._values(0),this.options.values=null):"max"===i&&(this.options.value=this._values(this.options.values.length-1),this.options.values=null)),t.isArray(this.options.values)&&(n=this.options.values.length),t.Widget.prototype._setOption.apply(this,arguments),e){case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":for(this._animateOff=!0,this._refreshValue(),s=0;n>s;s+=1)this._change(null,s);this._animateOff=!1;break;case"min":case"max":this._animateOff=!0,this._refreshValue(),this._animateOff=!1;break;case"range":this._animateOff=!0,this._refresh(),this._animateOff=!1}},_value:function(){var t=this.options.value;return t=this._trimAlignValue(t)},_values:function(t){var e,i,s;if(arguments.length)return e=this.options.values[t],e=this._trimAlignValue(e);if(this.options.values&&this.options.values.length){for(i=this.options.values.slice(),s=0;i.length>s;s+=1)i[s]=this._trimAlignValue(i[s]);return i}return[]},_trimAlignValue:function(t){if(this._valueMin()>=t)return this._valueMin();if(t>=this._valueMax())return this._valueMax();var e=this.options.step>0?this.options.step:1,i=(t-this._valueMin())%e,s=t-i;return 2*Math.abs(i)>=e&&(s+=i>0?e:-e),parseFloat(s.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var e,i,s,n,o,a=this.options.range,r=this.options,h=this,l=this._animateOff?!1:r.animate,c={};this.options.values&&this.options.values.length?this.handles.each(function(s){i=100*((h.values(s)-h._valueMin())/(h._valueMax()-h._valueMin())),c["horizontal"===h.orientation?"left":"bottom"]=i+"%",t(this).stop(1,1)[l?"animate":"css"](c,r.animate),h.options.range===!0&&("horizontal"===h.orientation?(0===s&&h.range.stop(1,1)[l?"animate":"css"]({left:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({width:i-e+"%"},{queue:!1,duration:r.animate})):(0===s&&h.range.stop(1,1)[l?"animate":"css"]({bottom:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({height:i-e+"%"},{queue:!1,duration:r.animate}))),e=i}):(s=this.value(),n=this._valueMin(),o=this._valueMax(),i=o!==n?100*((s-n)/(o-n)):0,c["horizontal"===this.orientation?"left":"bottom"]=i+"%",this.handle.stop(1,1)[l?"animate":"css"](c,r.animate),"min"===a&&"horizontal"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({width:i+"%"},r.animate),"max"===a&&"horizontal"===this.orientation&&this.range[l?"animate":"css"]({width:100-i+"%"},{queue:!1,duration:r.animate}),"min"===a&&"vertical"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({height:i+"%"},r.animate),"max"===a&&"vertical"===this.orientation&&this.range[l?"animate":"css"]({height:100-i+"%"},{queue:!1,duration:r.animate}))},_handleEvents:{keydown:function(i){var s,n,o,a,r=t(i.target).data("ui-slider-handle-index");switch(i.keyCode){case t.ui.keyCode.HOME:case t.ui.keyCode.END:case t.ui.keyCode.PAGE_UP:case t.ui.keyCode.PAGE_DOWN:case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(i.preventDefault(),!this._keySliding&&(this._keySliding=!0,t(i.target).addClass("ui-state-active"),s=this._start(i,r),s===!1))return}switch(a=this.options.step,n=o=this.options.values&&this.options.values.length?this.values(r):this.value(),i.keyCode){case t.ui.keyCode.HOME:o=this._valueMin();break;case t.ui.keyCode.END:o=this._valueMax();break;case t.ui.keyCode.PAGE_UP:o=this._trimAlignValue(n+(this._valueMax()-this._valueMin())/e);break;case t.ui.keyCode.PAGE_DOWN:o=this._trimAlignValue(n-(this._valueMax()-this._valueMin())/e);break;case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:if(n===this._valueMax())return;o=this._trimAlignValue(n+a);break;case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(n===this._valueMin())return;o=this._trimAlignValue(n-a)}this._slide(i,r,o)},click:function(t){t.preventDefault()},keyup:function(e){var i=t(e.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(e,i),this._change(e,i),t(e.target).removeClass("ui-state-active"))}}})}(jQuery),function(t){function e(t){return function(){var e=this.element.val();t.apply(this,arguments),this._refresh(),e!==this.element.val()&&this._trigger("change")}}t.widget("ui.spinner",{version:"1.10.4",defaultElement:"<input>",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var e={},i=this.element;return t.each(["min","max","step"],function(t,s){var n=i.attr(s);void 0!==n&&n.length&&(e[s]=n)}),e},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t),void 0)},mousewheel:function(t,e){if(e){if(!this.spinning&&!this._start(t))return!1;this._spin((e>0?1:-1)*this.options.step,t),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(t)},100),t.preventDefault()}},"mousedown .ui-spinner-button":function(e){function i(){var t=this.element[0]===this.document[0].activeElement;t||(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),e.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(e)!==!1&&this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(e){return t(e.currentTarget).hasClass("ui-state-active")?this._start(e)===!1?!1:(this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var t=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=t.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(.5*t.height())&&t.height()>0&&t.height(t.height()),this.options.disabled&&this.disable()},_keydown:function(e){var i=this.options,s=t.ui.keyCode;switch(e.keyCode){case s.UP:return this._repeat(null,1,e),!0;case s.DOWN:return this._repeat(null,-1,e),!0;case s.PAGE_UP:return this._repeat(null,i.page,e),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,e),!0}return!1},_uiSpinnerHtml:function(){return"<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"},_buttonHtml:function(){return"<a class='ui-spinner-button ui-spinner-up ui-corner-tr'><span class='ui-icon "+this.options.icons.up+"'>&#9650;</span>"+"</a>"+"<a class='ui-spinner-button ui-spinner-down ui-corner-br'>"+"<span class='ui-icon "+this.options.icons.down+"'>&#9660;</span>"+"</a>"},_start:function(t){return this.spinning||this._trigger("start",t)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(t,e,i){t=t||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,e,i)},t),this._spin(e*this.options.step,i)},_spin:function(t,e){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+t*this._increment(this.counter)),this.spinning&&this._trigger("spin",e,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(e){var i=this.options.incremental;return i?t.isFunction(i)?i(e):Math.floor(e*e*e/5e4-e*e/500+17*e/200+1):1},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_adjustValue:function(t){var e,i,s=this.options;return e=null!==s.min?s.min:0,i=t-e,i=Math.round(i/s.step)*s.step,t=e+i,t=parseFloat(t.toFixed(this._precision())),null!==s.max&&t>s.max?s.max:null!==s.min&&s.min>t?s.min:t},_stop:function(t){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",t))},_setOption:function(t,e){if("culture"===t||"numberFormat"===t){var i=this._parse(this.element.val());return this.options[t]=e,this.element.val(this._format(i)),void 0}("max"===t||"min"===t||"step"===t)&&"string"==typeof e&&(e=this._parse(e)),"icons"===t&&(this.buttons.first().find(".ui-icon").removeClass(this.options.icons.up).addClass(e.up),this.buttons.last().find(".ui-icon").removeClass(this.options.icons.down).addClass(e.down)),this._super(t,e),"disabled"===t&&(e?(this.element.prop("disabled",!0),this.buttons.button("disable")):(this.element.prop("disabled",!1),this.buttons.button("enable")))},_setOptions:e(function(t){this._super(t),this._value(this.element.val())}),_parse:function(t){return"string"==typeof t&&""!==t&&(t=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(t,10,this.options.culture):+t),""===t||isNaN(t)?null:t},_format:function(t){return""===t?"":window.Globalize&&this.options.numberFormat?Globalize.format(t,this.options.numberFormat,this.options.culture):t},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},_value:function(t,e){var i;""!==t&&(i=this._parse(t),null!==i&&(e||(i=this._adjustValue(i)),t=this._format(i))),this.element.val(t),this._refresh()},_destroy:function(){this.element.removeClass("ui-spinner-input").prop("disabled",!1).removeAttr("autocomplete").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:e(function(t){this._stepUp(t)}),_stepUp:function(t){this._start()&&(this._spin((t||1)*this.options.step),this._stop())},stepDown:e(function(t){this._stepDown(t)}),_stepDown:function(t){this._start()&&(this._spin((t||1)*-this.options.step),this._stop())},pageUp:e(function(t){this._stepUp((t||1)*this.options.page)}),pageDown:e(function(t){this._stepDown((t||1)*this.options.page)}),value:function(t){return arguments.length?(e(this._value).call(this,t),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}})}(jQuery),function(t,e){function i(){return++n}function s(t){return t=t.cloneNode(!1),t.hash.length>1&&decodeURIComponent(t.href.replace(o,""))===decodeURIComponent(location.href.replace(o,""))}var n=0,o=/#.*$/;t.widget("ui.tabs",{version:"1.10.4",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var e=this,i=this.options;this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",i.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(e){t(this).is(".ui-state-disabled")&&e.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){t(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this._processTabs(),i.active=this._initialActive(),t.isArray(i.disabled)&&(i.disabled=t.unique(i.disabled.concat(t.map(this.tabs.filter(".ui-state-disabled"),function(t){return e.tabs.index(t)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):t(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var i=this.options.active,s=this.options.collapsible,n=location.hash.substring(1);return null===i&&(n&&this.tabs.each(function(s,o){return t(o).attr("aria-controls")===n?(i=s,!1):e}),null===i&&(i=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===i||-1===i)&&(i=this.tabs.length?0:!1)),i!==!1&&(i=this.tabs.index(this.tabs.eq(i)),-1===i&&(i=s?!1:0)),!s&&i===!1&&this.anchors.length&&(i=0),i},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):t()}},_tabKeydown:function(i){var s=t(this.document[0].activeElement).closest("li"),n=this.tabs.index(s),o=!0;if(!this._handlePageNav(i)){switch(i.keyCode){case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:n++;break;case t.ui.keyCode.UP:case t.ui.keyCode.LEFT:o=!1,n--;break;case t.ui.keyCode.END:n=this.anchors.length-1;break;case t.ui.keyCode.HOME:n=0;break;case t.ui.keyCode.SPACE:return i.preventDefault(),clearTimeout(this.activating),this._activate(n),e;case t.ui.keyCode.ENTER:return i.preventDefault(),clearTimeout(this.activating),this._activate(n===this.options.active?!1:n),e;default:return}i.preventDefault(),clearTimeout(this.activating),n=this._focusNextTab(n,o),i.ctrlKey||(s.attr("aria-selected","false"),this.tabs.eq(n).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",n)},this.delay))}},_panelKeydown:function(e){this._handlePageNav(e)||e.ctrlKey&&e.keyCode===t.ui.keyCode.UP&&(e.preventDefault(),this.active.focus())},_handlePageNav:function(i){return i.altKey&&i.keyCode===t.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):i.altKey&&i.keyCode===t.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):e},_findNextTab:function(e,i){function s(){return e>n&&(e=0),0>e&&(e=n),e}for(var n=this.tabs.length-1;-1!==t.inArray(s(),this.options.disabled);)e=i?e+1:e-1;return e},_focusNextTab:function(t,e){return t=this._findNextTab(t,e),this.tabs.eq(t).focus(),t},_setOption:function(t,i){return"active"===t?(this._activate(i),e):"disabled"===t?(this._setupDisabled(i),e):(this._super(t,i),"collapsible"===t&&(this.element.toggleClass("ui-tabs-collapsible",i),i||this.options.active!==!1||this._activate(0)),"event"===t&&this._setupEvents(i),"heightStyle"===t&&this._setupHeightStyle(i),e)},_tabId:function(t){return t.attr("aria-controls")||"ui-tabs-"+i()},_sanitizeSelector:function(t){return t?t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var e=this.options,i=this.tablist.children(":has(a[href])");e.disabled=t.map(i.filter(".ui-state-disabled"),function(t){return i.index(t)}),this._processTabs(),e.active!==!1&&this.anchors.length?this.active.length&&!t.contains(this.tablist[0],this.active[0])?this.tabs.length===e.disabled.length?(e.active=!1,this.active=t()):this._activate(this._findNextTab(Math.max(0,e.active-1),!1)):e.active=this.tabs.index(this.active):(e.active=!1,this.active=t()),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var e=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist"),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return t("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=t(),this.anchors.each(function(i,n){var o,a,r,h=t(n).uniqueId().attr("id"),l=t(n).closest("li"),c=l.attr("aria-controls");s(n)?(o=n.hash,a=e.element.find(e._sanitizeSelector(o))):(r=e._tabId(l),o="#"+r,a=e.element.find(o),a.length||(a=e._createPanel(r),a.insertAfter(e.panels[i-1]||e.tablist)),a.attr("aria-live","polite")),a.length&&(e.panels=e.panels.add(a)),c&&l.data("ui-tabs-aria-controls",c),l.attr({"aria-controls":o.substring(1),"aria-labelledby":h}),a.attr("aria-labelledby",h)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel")},_getList:function(){return this.tablist||this.element.find("ol,ul").eq(0)},_createPanel:function(e){return t("<div>").attr("id",e).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(e){t.isArray(e)&&(e.length?e.length===this.anchors.length&&(e=!0):e=!1);for(var i,s=0;i=this.tabs[s];s++)e===!0||-1!==t.inArray(s,e)?t(i).addClass("ui-state-disabled").attr("aria-disabled","true"):t(i).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=e},_setupEvents:function(e){var i={click:function(t){t.preventDefault()}};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(e){var i,s=this.element.parent();"fill"===e?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=t(this).outerHeight(!0)}),this.panels.each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.panels.each(function(){i=Math.max(i,t(this).height("").height())}).height(i))},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n.closest("li"),a=o[0]===s[0],r=a&&i.collapsible,h=r?t():this._getPanelForTab(o),l=s.length?this._getPanelForTab(s):t(),c={oldTab:s,oldPanel:l,newTab:r?t():o,newPanel:h};e.preventDefault(),o.hasClass("ui-state-disabled")||o.hasClass("ui-tabs-loading")||this.running||a&&!i.collapsible||this._trigger("beforeActivate",e,c)===!1||(i.active=r?!1:this.tabs.index(o),this.active=a?t():o,this.xhr&&this.xhr.abort(),l.length||h.length||t.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(o),e),this._toggle(e,c))},_toggle:function(e,i){function s(){o.running=!1,o._trigger("activate",e,i)}function n(){i.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),a.length&&o.options.show?o._show(a,o.options.show,s):(a.show(),s())}var o=this,a=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),n()}):(i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),r.hide(),n()),r.attr({"aria-expanded":"false","aria-hidden":"true"}),i.oldTab.attr("aria-selected","false"),a.length&&r.length?i.oldTab.attr("tabIndex",-1):a.length&&this.tabs.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),a.attr({"aria-expanded":"true","aria-hidden":"false"}),i.newTab.attr({"aria-selected":"true",tabIndex:0})},_activate:function(e){var i,s=this._findActive(e);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return e===!1?t():this.tabs.eq(e)},_getIndex:function(t){return"string"==typeof t&&(t=this.anchors.index(this.anchors.filter("[href$='"+t+"']"))),t},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){t.data(this,"ui-tabs-destroy")?t(this).remove():t(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var e=t(this),i=e.data("ui-tabs-aria-controls");i?e.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):e.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(i){var s=this.options.disabled;s!==!1&&(i===e?s=!1:(i=this._getIndex(i),s=t.isArray(s)?t.map(s,function(t){return t!==i?t:null}):t.map(this.tabs,function(t,e){return e!==i?e:null})),this._setupDisabled(s))},disable:function(i){var s=this.options.disabled;if(s!==!0){if(i===e)s=!0;else{if(i=this._getIndex(i),-1!==t.inArray(i,s))return;s=t.isArray(s)?t.merge([i],s).sort():[i]}this._setupDisabled(s)}},load:function(e,i){e=this._getIndex(e);var n=this,o=this.tabs.eq(e),a=o.find(".ui-tabs-anchor"),r=this._getPanelForTab(o),h={tab:o,panel:r};s(a[0])||(this.xhr=t.ajax(this._ajaxSettings(a,i,h)),this.xhr&&"canceled"!==this.xhr.statusText&&(o.addClass("ui-tabs-loading"),r.attr("aria-busy","true"),this.xhr.success(function(t){setTimeout(function(){r.html(t),n._trigger("load",i,h)},1)}).complete(function(t,e){setTimeout(function(){"abort"===e&&n.panels.stop(!1,!0),o.removeClass("ui-tabs-loading"),r.removeAttr("aria-busy"),t===n.xhr&&delete n.xhr},1)})))},_ajaxSettings:function(e,i,s){var n=this;return{url:e.attr("href"),beforeSend:function(e,o){return n._trigger("beforeLoad",i,t.extend({jqXHR:e,ajaxSettings:o},s))}}},_getPanelForTab:function(e){var i=t(e).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}})}(jQuery),function(t){function e(e,i){var s=(e.attr("aria-describedby")||"").split(/\s+/);s.push(i),e.data("ui-tooltip-id",i).attr("aria-describedby",t.trim(s.join(" ")))}function i(e){var i=e.data("ui-tooltip-id"),s=(e.attr("aria-describedby")||"").split(/\s+/),n=t.inArray(i,s);-1!==n&&s.splice(n,1),e.removeData("ui-tooltip-id"),s=t.trim(s.join(" ")),s?e.attr("aria-describedby",s):e.removeAttr("aria-describedby")}var s=0;t.widget("ui.tooltip",{version:"1.10.4",options:{content:function(){var e=t(this).attr("title")||"";return t("<a>").text(e).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable()},_setOption:function(e,i){var s=this;return"disabled"===e?(this[i?"_disable":"_enable"](),this.options[e]=i,void 0):(this._super(e,i),"content"===e&&t.each(this.tooltips,function(t,e){s._updateContent(e)}),void 0)},_disable:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0)}),this.element.find(this.options.items).addBack().each(function(){var e=t(this);e.is("[title]")&&e.data("ui-tooltip-title",e.attr("title")).attr("title","")})},_enable:function(){this.element.find(this.options.items).addBack().each(function(){var e=t(this);e.data("ui-tooltip-title")&&e.attr("title",e.data("ui-tooltip-title"))})},open:function(e){var i=this,s=t(e?e.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),e&&"mouseover"===e.type&&s.parents().each(function(){var e,s=t(this);s.data("ui-tooltip-open")&&(e=t.Event("blur"),e.target=e.currentTarget=this,i.close(e,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._updateContent(s,e))},_updateContent:function(t,e){var i,s=this.options.content,n=this,o=e?e.type:null;
+return"string"==typeof s?this._open(e,t,s):(i=s.call(t[0],function(i){t.data("ui-tooltip-open")&&n._delay(function(){e&&(e.type=o),this._open(e,t,i)})}),i&&this._open(e,t,i),void 0)},_open:function(i,s,n){function o(t){l.of=t,a.is(":hidden")||a.position(l)}var a,r,h,l=t.extend({},this.options.position);if(n){if(a=this._find(s),a.length)return a.find(".ui-tooltip-content").html(n),void 0;s.is("[title]")&&(i&&"mouseover"===i.type?s.attr("title",""):s.removeAttr("title")),a=this._tooltip(s),e(s,a.attr("id")),a.find(".ui-tooltip-content").html(n),this.options.track&&i&&/^mouse/.test(i.type)?(this._on(this.document,{mousemove:o}),o(i)):a.position(t.extend({of:s},this.options.position)),a.hide(),this._show(a,this.options.show),this.options.show&&this.options.show.delay&&(h=this.delayedShow=setInterval(function(){a.is(":visible")&&(o(l.of),clearInterval(h))},t.fx.interval)),this._trigger("open",i,{tooltip:a}),r={keyup:function(e){if(e.keyCode===t.ui.keyCode.ESCAPE){var i=t.Event(e);i.currentTarget=s[0],this.close(i,!0)}},remove:function(){this._removeTooltip(a)}},i&&"mouseover"!==i.type||(r.mouseleave="close"),i&&"focusin"!==i.type||(r.focusout="close"),this._on(!0,s,r)}},close:function(e){var s=this,n=t(e?e.currentTarget:this.element),o=this._find(n);this.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&n.attr("title",n.data("ui-tooltip-title")),i(n),o.stop(!0),this._hide(o,this.options.hide,function(){s._removeTooltip(t(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),e&&"mouseleave"===e.type&&t.each(this.parents,function(e,i){t(i.element).attr("title",i.title),delete s.parents[e]}),this.closing=!0,this._trigger("close",e,{tooltip:o}),this.closing=!1)},_tooltip:function(e){var i="ui-tooltip-"+s++,n=t("<div>").attr({id:i,role:"tooltip"}).addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||""));return t("<div>").addClass("ui-tooltip-content").appendTo(n),n.appendTo(this.document[0].body),this.tooltips[i]=e,n},_find:function(e){var i=e.data("ui-tooltip-id");return i?t("#"+i):t()},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0),t("#"+i).remove(),s.data("ui-tooltip-title")&&(s.attr("title",s.data("ui-tooltip-title")),s.removeData("ui-tooltip-title"))})}})}(jQuery); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/jquery.js b/lib/prado/framework/Web/Javascripts/source/jquery/jquery.js
new file mode 100644
index 0000000..3c88fa8
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/jquery.js
@@ -0,0 +1,10337 @@
+/*!
+ * jQuery JavaScript Library v1.11.0
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2014-01-23T21:02Z
+ */
+
+(function( global, factory ) {
+
+ if ( typeof module === "object" && typeof module.exports === "object" ) {
+ // For CommonJS and CommonJS-like environments where a proper window is present,
+ // execute the factory and get jQuery
+ // For environments that do not inherently posses a window with a document
+ // (such as Node.js), expose a jQuery-making factory as module.exports
+ // This accentuates the need for the creation of a real window
+ // e.g. var jQuery = require("jquery")(window);
+ // See ticket #14549 for more info
+ module.exports = global.document ?
+ factory( global, true ) :
+ function( w ) {
+ if ( !w.document ) {
+ throw new Error( "jQuery requires a window with a document" );
+ }
+ return factory( w );
+ };
+ } else {
+ factory( global );
+ }
+
+// Pass this if window is not defined yet
+}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Can't do this because several apps including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+// Support: Firefox 18+
+//
+
+var deletedIds = [];
+
+var slice = deletedIds.slice;
+
+var concat = deletedIds.concat;
+
+var push = deletedIds.push;
+
+var indexOf = deletedIds.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var trim = "".trim;
+
+var support = {};
+
+
+
+var
+ version = "1.11.0",
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ // Need init if jQuery is called (just allow error to be thrown if not included)
+ return new jQuery.fn.init( selector, context );
+ },
+
+ // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+ // Matches dashed string for camelizing
+ rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([\da-z])/gi,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return letter.toUpperCase();
+ };
+
+jQuery.fn = jQuery.prototype = {
+ // The current version of jQuery being used
+ jquery: version,
+
+ constructor: jQuery,
+
+ // Start with an empty selector
+ selector: "",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ toArray: function() {
+ return slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num != null ?
+
+ // Return a 'clean' array
+ ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
+
+ // Return just the object
+ slice.call( this );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+ ret.context = this.context;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ slice: function() {
+ return this.pushStack( slice.apply( this, arguments ) );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ eq: function( i ) {
+ var len = this.length,
+ j = +i + ( i < 0 ? len : 0 );
+ return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: deletedIds.sort,
+ splice: deletedIds.splice
+};
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var src, copyIsArray, copy, name, options, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+
+ // skip the boolean and the target
+ target = arguments[ i ] || {};
+ i++;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( i === length ) {
+ target = this;
+ i--;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ // Unique for each copy of jQuery on the page
+ expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+ // Assume jQuery is ready without the ready module
+ isReady: true,
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ noop: function() {},
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ isWindow: function( obj ) {
+ /* jshint eqeqeq: false */
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ // parseFloat NaNs numeric-cast false positives (null|true|false|"")
+ // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+ // subtraction forces infinities to NaN
+ return obj - parseFloat( obj ) >= 0;
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ isPlainObject: function( obj ) {
+ var key;
+
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ try {
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !hasOwn.call(obj, "constructor") &&
+ !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+ } catch ( e ) {
+ // IE8,9 Will throw exceptions on certain host objects #9897
+ return false;
+ }
+
+ // Support: IE<9
+ // Handle iteration over inherited properties before own properties.
+ if ( support.ownLast ) {
+ for ( key in obj ) {
+ return hasOwn.call( obj, key );
+ }
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+ for ( key in obj ) {}
+
+ return key === undefined || hasOwn.call( obj, key );
+ },
+
+ type: function( obj ) {
+ if ( obj == null ) {
+ return obj + "";
+ }
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ toString.call(obj) ] || "object" :
+ typeof obj;
+ },
+
+ // Evaluates a script in a global context
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+ globalEval: function( data ) {
+ if ( data && jQuery.trim( data ) ) {
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data );
+ } )( data );
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+ },
+
+ // args is for internal usage only
+ each: function( obj, callback, args ) {
+ var value,
+ i = 0,
+ length = obj.length,
+ isArray = isArraylike( obj );
+
+ if ( args ) {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // Use native String.trim function wherever possible
+ trim: trim && !trim.call("\uFEFF\xA0") ?
+ function( text ) {
+ return text == null ?
+ "" :
+ trim.call( text );
+ } :
+
+ // Otherwise use our own trimming functionality
+ function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var ret = results || [];
+
+ if ( arr != null ) {
+ if ( isArraylike( Object(arr) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
+ } else {
+ push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ var len;
+
+ if ( arr ) {
+ if ( indexOf ) {
+ return indexOf.call( arr, elem, i );
+ }
+
+ len = arr.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in arr && arr[ i ] === elem ) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var len = +second.length,
+ j = 0,
+ i = first.length;
+
+ while ( j < len ) {
+ first[ i++ ] = second[ j++ ];
+ }
+
+ // Support: IE<9
+ // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
+ if ( len !== len ) {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, invert ) {
+ var callbackInverse,
+ matches = [],
+ i = 0,
+ length = elems.length,
+ callbackExpect = !invert;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ callbackInverse = !callback( elems[ i ], i );
+ if ( callbackInverse !== callbackExpect ) {
+ matches.push( elems[ i ] );
+ }
+ }
+
+ return matches;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value,
+ i = 0,
+ length = elems.length,
+ isArray = isArraylike( elems ),
+ ret = [];
+
+ // Go through the array, translating each of the items to their new values
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ var args, proxy, tmp;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ now: function() {
+ return +( new Date() );
+ },
+
+ // jQuery.support is not used in Core but other projects attach their
+ // properties to it so it needs to exist.
+ support: support
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+ var length = obj.length,
+ type = jQuery.type( obj );
+
+ if ( type === "function" || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ if ( obj.nodeType === 1 && length ) {
+ return true;
+ }
+
+ return type === "array" || length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+}
+var Sizzle =
+/*!
+ * Sizzle CSS Selector Engine v1.10.16
+ * http://sizzlejs.com/
+ *
+ * Copyright 2013 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2014-01-13
+ */
+(function( window ) {
+
+var i,
+ support,
+ Expr,
+ getText,
+ isXML,
+ compile,
+ outermostContext,
+ sortInput,
+ hasDuplicate,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsHTML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+
+ // Instance-specific data
+ expando = "sizzle" + -(new Date()),
+ preferredDoc = window.document,
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ },
+
+ // General-purpose constants
+ strundefined = typeof undefined,
+ MAX_NEGATIVE = 1 << 31,
+
+ // Instance methods
+ hasOwn = ({}).hasOwnProperty,
+ arr = [],
+ pop = arr.pop,
+ push_native = arr.push,
+ push = arr.push,
+ slice = arr.slice,
+ // Use a stripped-down indexOf if we can't use a native one
+ indexOf = arr.indexOf || function( elem ) {
+ var i = 0,
+ len = this.length;
+ for ( ; i < len; i++ ) {
+ if ( this[i] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+ // Regular expressions
+
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+ // http://www.w3.org/TR/css3-syntax/#characters
+ characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+ // Loosely modeled on CSS identifier characters
+ // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = characterEncoding.replace( "w", "w#" ),
+
+ // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
+ "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
+
+ // Prefer arguments quoted,
+ // then not containing pseudos/brackets,
+ // then attribute selectors/non-parenthetical expressions,
+ // then anything else
+ // These preferences are here to reduce the number of selectors
+ // needing tokenize in the PSEUDO preFilter
+ pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+
+ rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
+
+ rpseudo = new RegExp( pseudos ),
+ ridentifier = new RegExp( "^" + identifier + "$" ),
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+ // For use in libraries implementing .is()
+ // We use this for POS matching in `select`
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+ whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+ },
+
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rnative = /^[^{]+\{\s*\[native \w/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rsibling = /[+~]/,
+ rescape = /'|\\/g,
+
+ // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
+ funescape = function( _, escaped, escapedWhitespace ) {
+ var high = "0x" + escaped - 0x10000;
+ // NaN means non-codepoint
+ // Support: Firefox
+ // Workaround erroneous numeric interpretation of +"0x"
+ return high !== high || escapedWhitespace ?
+ escaped :
+ high < 0 ?
+ // BMP codepoint
+ String.fromCharCode( high + 0x10000 ) :
+ // Supplemental Plane codepoint (surrogate pair)
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+ };
+
+// Optimize for push.apply( _, NodeList )
+try {
+ push.apply(
+ (arr = slice.call( preferredDoc.childNodes )),
+ preferredDoc.childNodes
+ );
+ // Support: Android<4.0
+ // Detect silently failing push.apply
+ arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+ push = { apply: arr.length ?
+
+ // Leverage slice if possible
+ function( target, els ) {
+ push_native.apply( target, slice.call(els) );
+ } :
+
+ // Support: IE<9
+ // Otherwise append directly
+ function( target, els ) {
+ var j = target.length,
+ i = 0;
+ // Can't trust NodeList.length
+ while ( (target[j++] = els[i++]) ) {}
+ target.length = j - 1;
+ }
+ };
+}
+
+function Sizzle( selector, context, results, seed ) {
+ var match, elem, m, nodeType,
+ // QSA vars
+ i, groups, old, nid, newContext, newSelector;
+
+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+ setDocument( context );
+ }
+
+ context = context || document;
+ results = results || [];
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( documentIsHTML && !seed ) {
+
+ // Shortcuts
+ if ( (match = rquickExpr.exec( selector )) ) {
+ // Speed-up: Sizzle("#ID")
+ if ( (m = match[1]) ) {
+ if ( nodeType === 9 ) {
+ elem = context.getElementById( m );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document (jQuery #6963)
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE, Opera, and Webkit return items
+ // by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+ } else {
+ // Context is not a document
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+ contains( context, elem ) && elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Speed-up: Sizzle("TAG")
+ } else if ( match[2] ) {
+ push.apply( results, context.getElementsByTagName( selector ) );
+ return results;
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
+ push.apply( results, context.getElementsByClassName( m ) );
+ return results;
+ }
+ }
+
+ // QSA path
+ if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
+ nid = old = expando;
+ newContext = context;
+ newSelector = nodeType === 9 && selector;
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ groups = tokenize( selector );
+
+ if ( (old = context.getAttribute("id")) ) {
+ nid = old.replace( rescape, "\\$&" );
+ } else {
+ context.setAttribute( "id", nid );
+ }
+ nid = "[id='" + nid + "'] ";
+
+ i = groups.length;
+ while ( i-- ) {
+ groups[i] = nid + toSelector( groups[i] );
+ }
+ newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
+ newSelector = groups.join(",");
+ }
+
+ if ( newSelector ) {
+ try {
+ push.apply( results,
+ newContext.querySelectorAll( newSelector )
+ );
+ return results;
+ } catch(qsaError) {
+ } finally {
+ if ( !old ) {
+ context.removeAttribute("id");
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ * deleting the oldest entry
+ */
+function createCache() {
+ var keys = [];
+
+ function cache( key, value ) {
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ if ( keys.push( key + " " ) > Expr.cacheLength ) {
+ // Only keep the most recent entries
+ delete cache[ keys.shift() ];
+ }
+ return (cache[ key + " " ] = value);
+ }
+ return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+ fn[ expando ] = true;
+ return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+ var div = document.createElement("div");
+
+ try {
+ return !!fn( div );
+ } catch (e) {
+ return false;
+ } finally {
+ // Remove from its parent by default
+ if ( div.parentNode ) {
+ div.parentNode.removeChild( div );
+ }
+ // release memory in IE
+ div = null;
+ }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+ var arr = attrs.split("|"),
+ i = attrs.length;
+
+ while ( i-- ) {
+ Expr.attrHandle[ arr[i] ] = handler;
+ }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+ var cur = b && a,
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+ ( ~b.sourceIndex || MAX_NEGATIVE ) -
+ ( ~a.sourceIndex || MAX_NEGATIVE );
+
+ // Use IE sourceIndex if available on both nodes
+ if ( diff ) {
+ return diff;
+ }
+
+ // Check if b follows a
+ if ( cur ) {
+ while ( (cur = cur.nextSibling) ) {
+ if ( cur === b ) {
+ return -1;
+ }
+ }
+ }
+
+ return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+ return markFunction(function( argument ) {
+ argument = +argument;
+ return markFunction(function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ (j = matchIndexes[i]) ] ) {
+ seed[j] = !(matches[j] = seed[j]);
+ }
+ }
+ });
+ });
+}
+
+/**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+function testContext( context ) {
+ return context && typeof context.getElementsByTagName !== strundefined && context;
+}
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+isXML = Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+ var hasCompare,
+ doc = node ? node.ownerDocument || node : preferredDoc,
+ parent = doc.defaultView;
+
+ // If no document and documentElement is available, return
+ if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+ return document;
+ }
+
+ // Set our document
+ document = doc;
+ docElem = doc.documentElement;
+
+ // Support tests
+ documentIsHTML = !isXML( doc );
+
+ // Support: IE>8
+ // If iframe document is assigned to "document" variable and if iframe has been reloaded,
+ // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
+ // IE6-8 do not support the defaultView property so parent will be undefined
+ if ( parent && parent !== parent.top ) {
+ // IE11 does not have attachEvent, so all must suffer
+ if ( parent.addEventListener ) {
+ parent.addEventListener( "unload", function() {
+ setDocument();
+ }, false );
+ } else if ( parent.attachEvent ) {
+ parent.attachEvent( "onunload", function() {
+ setDocument();
+ });
+ }
+ }
+
+ /* Attributes
+ ---------------------------------------------------------------------- */
+
+ // Support: IE<8
+ // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
+ support.attributes = assert(function( div ) {
+ div.className = "i";
+ return !div.getAttribute("className");
+ });
+
+ /* getElement(s)By*
+ ---------------------------------------------------------------------- */
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.getElementsByTagName = assert(function( div ) {
+ div.appendChild( doc.createComment("") );
+ return !div.getElementsByTagName("*").length;
+ });
+
+ // Check if getElementsByClassName can be trusted
+ support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
+ div.innerHTML = "<div class='a'></div><div class='a i'></div>";
+
+ // Support: Safari<4
+ // Catch class over-caching
+ div.firstChild.className = "i";
+ // Support: Opera<10
+ // Catch gEBCN failure to find non-leading classes
+ return div.getElementsByClassName("i").length === 2;
+ });
+
+ // Support: IE<10
+ // Check if getElementById returns elements by name
+ // The broken getElementById methods don't pick up programatically-set names,
+ // so use a roundabout getElementsByName test
+ support.getById = assert(function( div ) {
+ docElem.appendChild( div ).id = expando;
+ return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
+ });
+
+ // ID find and filter
+ if ( support.getById ) {
+ Expr.find["ID"] = function( id, context ) {
+ if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
+ var m = context.getElementById( id );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ }
+ };
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ return elem.getAttribute("id") === attrId;
+ };
+ };
+ } else {
+ // Support: IE6/7
+ // getElementById is not reliable as a find shortcut
+ delete Expr.find["ID"];
+
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+ return node && node.value === attrId;
+ };
+ };
+ }
+
+ // Tag
+ Expr.find["TAG"] = support.getElementsByTagName ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== strundefined ) {
+ return context.getElementsByTagName( tag );
+ }
+ } :
+ function( tag, context ) {
+ var elem,
+ tmp = [],
+ i = 0,
+ results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ };
+
+ // Class
+ Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+ if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
+ return context.getElementsByClassName( className );
+ }
+ };
+
+ /* QSA/matchesSelector
+ ---------------------------------------------------------------------- */
+
+ // QSA and matchesSelector support
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ rbuggyMatches = [];
+
+ // qSa(:focus) reports false when true (Chrome 21)
+ // We allow this because of a bug in IE8/9 that throws an error
+ // whenever `document.activeElement` is accessed on an iframe
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
+ // See http://bugs.jquery.com/ticket/13378
+ rbuggyQSA = [];
+
+ if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function( div ) {
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explicitly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ div.innerHTML = "<select t=''><option selected=''></option></select>";
+
+ // Support: IE8, Opera 10-12
+ // Nothing should be selected when empty strings follow ^= or $= or *=
+ if ( div.querySelectorAll("[t^='']").length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+ }
+
+ // Support: IE8
+ // Boolean attributes and "value" are not treated correctly
+ if ( !div.querySelectorAll("[selected]").length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":checked").length ) {
+ rbuggyQSA.push(":checked");
+ }
+ });
+
+ assert(function( div ) {
+ // Support: Windows 8 Native Apps
+ // The type and name attributes are restricted during .innerHTML assignment
+ var input = doc.createElement("input");
+ input.setAttribute( "type", "hidden" );
+ div.appendChild( input ).setAttribute( "name", "D" );
+
+ // Support: IE8
+ // Enforce case-sensitivity of name attribute
+ if ( div.querySelectorAll("[name=d]").length ) {
+ rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":enabled").length ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Opera 10-11 does not throw on post-comma invalid pseudos
+ div.querySelectorAll("*,:x");
+ rbuggyQSA.push(",.*:");
+ });
+ }
+
+ if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector) )) ) {
+
+ assert(function( div ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ support.disconnectedMatch = matches.call( div, "div" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( div, "[s!='']:x" );
+ rbuggyMatches.push( "!=", pseudos );
+ });
+ }
+
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+
+ /* Contains
+ ---------------------------------------------------------------------- */
+ hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+ // Element contains another
+ // Purposefully does not implement inclusive descendent
+ // As in, an element does not contain itself
+ contains = hasCompare || rnative.test( docElem.contains ) ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && (
+ adown.contains ?
+ adown.contains( bup ) :
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+ ));
+ } :
+ function( a, b ) {
+ if ( b ) {
+ while ( (b = b.parentNode) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ /* Sorting
+ ---------------------------------------------------------------------- */
+
+ // Document order sorting
+ sortOrder = hasCompare ?
+ function( a, b ) {
+
+ // Flag for duplicate removal
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ // Sort on method existence if only one input has compareDocumentPosition
+ var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+ if ( compare ) {
+ return compare;
+ }
+
+ // Calculate position if both inputs belong to the same document
+ compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
+ a.compareDocumentPosition( b ) :
+
+ // Otherwise we know they are disconnected
+ 1;
+
+ // Disconnected nodes
+ if ( compare & 1 ||
+ (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+ // Choose the first element that is related to our preferred document
+ if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
+ return -1;
+ }
+ if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
+ return 1;
+ }
+
+ // Maintain original order
+ return sortInput ?
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ 0;
+ }
+
+ return compare & 4 ? -1 : 1;
+ } :
+ function( a, b ) {
+ // Exit early if the nodes are identical
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [ a ],
+ bp = [ b ];
+
+ // Parentless nodes are either documents or disconnected
+ if ( !aup || !bup ) {
+ return a === doc ? -1 :
+ b === doc ? 1 :
+ aup ? -1 :
+ bup ? 1 :
+ sortInput ?
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ 0;
+
+ // If the nodes are siblings, we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+ }
+
+ // Otherwise we need full lists of their ancestors for comparison
+ cur = a;
+ while ( (cur = cur.parentNode) ) {
+ ap.unshift( cur );
+ }
+ cur = b;
+ while ( (cur = cur.parentNode) ) {
+ bp.unshift( cur );
+ }
+
+ // Walk down the tree looking for a discrepancy
+ while ( ap[i] === bp[i] ) {
+ i++;
+ }
+
+ return i ?
+ // Do a sibling check if the nodes have a common ancestor
+ siblingCheck( ap[i], bp[i] ) :
+
+ // Otherwise nodes in our document sort first
+ ap[i] === preferredDoc ? -1 :
+ bp[i] === preferredDoc ? 1 :
+ 0;
+ };
+
+ return doc;
+};
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace( rattributeQuotes, "='$1']" );
+
+ if ( support.matchesSelector && documentIsHTML &&
+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
+
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || support.disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle( expr, document, null, [elem] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+ // Set document vars if needed
+ if ( ( context.ownerDocument || context ) !== document ) {
+ setDocument( context );
+ }
+ return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ var fn = Expr.attrHandle[ name.toLowerCase() ],
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+ fn( elem, name, !documentIsHTML ) :
+ undefined;
+
+ return val !== undefined ?
+ val :
+ support.attributes || !documentIsHTML ?
+ elem.getAttribute( name ) :
+ (val = elem.getAttributeNode(name)) && val.specified ?
+ val.value :
+ null;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ j = 0,
+ i = 0;
+
+ // Unless we *know* we can detect duplicates, assume their presence
+ hasDuplicate = !support.detectDuplicates;
+ sortInput = !support.sortStable && results.slice( 0 );
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem === results[ i ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ // Clear input after sorting to release objects
+ // See https://github.com/jquery/sizzle/pull/225
+ sortInput = null;
+
+ return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( !nodeType ) {
+ // If no nodeType, this is expected to be an array
+ while ( (node = elem[i++]) ) {
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (jQuery #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ attrHandle: {},
+
+ find: {},
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[1] = match[1].replace( runescape, funescape );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
+
+ if ( match[2] === "~=" ) {
+ match[3] = " " + match[3] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 what (child|of-type)
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
+ 5 sign of xn-component
+ 6 x of xn-component
+ 7 sign of y-component
+ 8 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+
+ if ( match[1].slice( 0, 3 ) === "nth" ) {
+ // nth-* requires argument
+ if ( !match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+ match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var excess,
+ unquoted = !match[5] && match[2];
+
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if ( match[3] && match[4] !== undefined ) {
+ match[2] = match[4];
+
+ // Strip excess characters from unquoted arguments
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
+ // Get excess from tokenize (recursively)
+ (excess = tokenize( unquoted, true )) &&
+ // advance to the next closing parenthesis
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+ // excess is a negative index
+ match[0] = match[0].slice( 0, excess );
+ match[2] = unquoted.slice( 0, excess );
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+
+ "TAG": function( nodeNameSelector ) {
+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+ return nodeNameSelector === "*" ?
+ function() { return true; } :
+ function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ className + " " ];
+
+ return pattern ||
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+ classCache( className, function( elem ) {
+ return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
+ });
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.slice( -check.length ) === check :
+ operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+ false;
+ };
+ },
+
+ "CHILD": function( type, what, argument, first, last ) {
+ var simple = type.slice( 0, 3 ) !== "nth",
+ forward = type.slice( -4 ) !== "last",
+ ofType = what === "of-type";
+
+ return first === 1 && last === 0 ?
+
+ // Shortcut for :nth-*(n)
+ function( elem ) {
+ return !!elem.parentNode;
+ } :
+
+ function( elem, context, xml ) {
+ var cache, outerCache, node, diff, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType;
+
+ if ( parent ) {
+
+ // :(first|last|only)-(child|of-type)
+ if ( simple ) {
+ while ( dir ) {
+ node = elem;
+ while ( (node = node[ dir ]) ) {
+ if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+ return false;
+ }
+ }
+ // Reverse direction for :only-* (if we haven't yet done so)
+ start = dir = type === "only" && !start && "nextSibling";
+ }
+ return true;
+ }
+
+ start = [ forward ? parent.firstChild : parent.lastChild ];
+
+ // non-xml :nth-child(...) stores cache data on `parent`
+ if ( forward && useCache ) {
+ // Seek `elem` from a previously-cached index
+ outerCache = parent[ expando ] || (parent[ expando ] = {});
+ cache = outerCache[ type ] || [];
+ nodeIndex = cache[0] === dirruns && cache[1];
+ diff = cache[0] === dirruns && cache[2];
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+ // Fallback to seeking `elem` from the start
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ // When found, cache indexes on `parent` and break
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
+ outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+ break;
+ }
+ }
+
+ // Use previously-cached element index if available
+ } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
+ diff = cache[1];
+
+ // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ } else {
+ // Use the same loop as above to seek `elem` from the start
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+ // Cache the index of each encountered element
+ if ( useCache ) {
+ (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+ }
+
+ if ( node === elem ) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset, then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction(function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf.call( seed, matched[i] );
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
+ }
+ }) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+ // Potentially complex pseudos
+ "not": markFunction(function( selector ) {
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction(function( seed, matches, context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( (elem = unmatched[i]) ) {
+ seed[i] = !(matches[i] = elem);
+ }
+ }
+ }) :
+ function( elem, context, xml ) {
+ input[0] = elem;
+ matcher( input, null, xml, results );
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function( text ) {
+ return function( elem ) {
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+ };
+ }),
+
+ // "Whether an element is represented by a :lang() selector
+ // is based solely on the element's language value
+ // being equal to the identifier C,
+ // or beginning with the identifier C immediately followed by "-".
+ // The matching of C against the element's language value is performed case-insensitively.
+ // The identifier C does not have to be a valid language name."
+ // http://www.w3.org/TR/selectors/#lang-pseudo
+ "lang": markFunction( function( lang ) {
+ // lang value must be a valid identifier
+ if ( !ridentifier.test(lang || "") ) {
+ Sizzle.error( "unsupported lang: " + lang );
+ }
+ lang = lang.replace( runescape, funescape ).toLowerCase();
+ return function( elem ) {
+ var elemLang;
+ do {
+ if ( (elemLang = documentIsHTML ?
+ elem.lang :
+ elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
+
+ elemLang = elemLang.toLowerCase();
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+ }
+ } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+ return false;
+ };
+ }),
+
+ // Miscellaneous
+ "target": function( elem ) {
+ var hash = window.location && window.location.hash;
+ return hash && hash.slice( 1 ) === elem.id;
+ },
+
+ "root": function( elem ) {
+ return elem === docElem;
+ },
+
+ "focus": function( elem ) {
+ return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+ },
+
+ // Boolean properties
+ "enabled": function( elem ) {
+ return elem.disabled === false;
+ },
+
+ "disabled": function( elem ) {
+ return elem.disabled === true;
+ },
+
+ "checked": function( elem ) {
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+
+ "selected": function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ // Contents
+ "empty": function( elem ) {
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+ // but not by others (comment: 8; processing instruction: 7; etc.)
+ // nodeType < 6 works because attributes (2) do not appear as children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ if ( elem.nodeType < 6 ) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos["empty"]( elem );
+ },
+
+ // Element/input types
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "text": function( elem ) {
+ var attr;
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+
+ // Support: IE<8
+ // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
+ },
+
+ // Position-in-collection
+ "first": createPositionalPseudo(function() {
+ return [ 0 ];
+ }),
+
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
+ return [ length - 1 ];
+ }),
+
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ }),
+
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 0;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 1;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ })
+ }
+};
+
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+ Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+ Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+function tokenize( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
+ if ( match ) {
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[0].length ) || soFar;
+ }
+ groups.push( (tokens = []) );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( (match = rcombinators.exec( soFar )) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ // Cast descendant combinators to space
+ type: match[0].replace( rtrim, " " )
+ });
+ soFar = soFar.slice( matched.length );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+ (match = preFilters[ type ]( match ))) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ type: type,
+ matches: match
+ });
+ soFar = soFar.slice( matched.length );
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+}
+
+function toSelector( tokens ) {
+ var i = 0,
+ len = tokens.length,
+ selector = "";
+ for ( ; i < len; i++ ) {
+ selector += tokens[i].value;
+ }
+ return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ checkNonElements = base && dir === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ var oldCache, outerCache,
+ newCache = [ dirruns, doneName ];
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ if ( xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ if ( matcher( elem, context, xml ) ) {
+ return true;
+ }
+ }
+ }
+ } else {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ outerCache = elem[ expando ] || (elem[ expando ] = {});
+ if ( (oldCache = outerCache[ dir ]) &&
+ oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
+
+ // Assign to newCache so results back-propagate to previous elements
+ return (newCache[ 2 ] = oldCache[ 2 ]);
+ } else {
+ // Reuse newcache so results back-propagate to previous elements
+ outerCache[ dir ] = newCache;
+
+ // A match means we're done; a fail means we have to keep checking
+ if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[i]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[0];
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( (elem = unmatched[i]) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction(function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( (elem = temp[i]) ) {
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) ) {
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( (matcherIn[i] = elem) );
+ }
+ }
+ postFinder( null, (matcherOut = []), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) &&
+ (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+ seed[temp] = !(results[temp] = elem);
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ });
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[0].type ],
+ implicitRelative = leadingRelative || Expr.relative[" "],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf.call( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ (checkContext = context).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+ matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+ } else {
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[j].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && toSelector(
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+ tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+ ).replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+ j < len && toSelector( tokens )
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ var bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, outermost ) {
+ var elem, j, matcher,
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ setMatched = [],
+ contextBackup = outermostContext,
+ // We must always have either seed elements or outermost context
+ elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
+ len = elems.length;
+
+ if ( outermost ) {
+ outermostContext = context !== document && context;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
+ // Support: IE<9, Safari
+ // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
+ for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
+ if ( byElement && elem ) {
+ j = 0;
+ while ( (matcher = elementMatchers[j++]) ) {
+ if ( matcher( elem, context, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+ // They will have gone through all possible matchers
+ if ( (elem = !matcher && elem) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // Apply set filters to unmatched elements
+ matchedCount += i;
+ if ( bySet && i !== matchedCount ) {
+ j = 0;
+ while ( (matcher = setMatchers[j++]) ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !(unmatched[i] || setMatched[i]) ) {
+ setMatched[i] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ selector + " " ];
+
+ if ( !cached ) {
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !group ) {
+ group = tokenize( selector );
+ }
+ i = group.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( group[i] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+ }
+ return cached;
+};
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[i], results );
+ }
+ return results;
+}
+
+function select( selector, context, results, seed ) {
+ var i, tokens, token, type, find,
+ match = tokenize( selector );
+
+ if ( !seed ) {
+ // Try to minimize operations if there is only one group
+ if ( match.length === 1 ) {
+
+ // Take a shortcut and set the context if the root selector is an ID
+ tokens = match[0] = match[0].slice( 0 );
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+ support.getById && context.nodeType === 9 && documentIsHTML &&
+ Expr.relative[ tokens[1].type ] ) {
+
+ context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+ if ( !context ) {
+ return results;
+ }
+ selector = selector.slice( tokens.shift().value.length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+ while ( i-- ) {
+ token = tokens[i];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ (type = token.type) ] ) {
+ break;
+ }
+ if ( (find = Expr.find[ type ]) ) {
+ // Search, expanding context for leading sibling combinators
+ if ( (seed = find(
+ token.matches[0].replace( runescape, funescape ),
+ rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
+ )) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && toSelector( tokens );
+ if ( !selector ) {
+ push.apply( results, seed );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function
+ // Provide `match` to avoid retokenization if we modified the selector above
+ compile( selector, match )(
+ seed,
+ context,
+ !documentIsHTML,
+ results,
+ rsibling.test( selector ) && testContext( context.parentNode ) || context
+ );
+ return results;
+}
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+// Support: Chrome<14
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = !!hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert(function( div1 ) {
+ // Should return 1, but returns 4 (following)
+ return div1.compareDocumentPosition( document.createElement("div") ) & 1;
+});
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert(function( div ) {
+ div.innerHTML = "<a href='#'></a>";
+ return div.firstChild.getAttribute("href") === "#" ;
+}) ) {
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+ }
+ });
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert(function( div ) {
+ div.innerHTML = "<input/>";
+ div.firstChild.setAttribute( "value", "" );
+ return div.firstChild.getAttribute( "value" ) === "";
+}) ) {
+ addHandle( "value", function( elem, name, isXML ) {
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+ return elem.defaultValue;
+ }
+ });
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert(function( div ) {
+ return div.getAttribute("disabled") == null;
+}) ) {
+ addHandle( booleans, function( elem, name, isXML ) {
+ var val;
+ if ( !isXML ) {
+ return elem[ name ] === true ? name.toLowerCase() :
+ (val = elem.getAttributeNode( name )) && val.specified ?
+ val.value :
+ null;
+ }
+ });
+}
+
+return Sizzle;
+
+})( window );
+
+
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+
+var rneedsContext = jQuery.expr.match.needsContext;
+
+var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
+
+
+
+var risSimple = /^.[^:#\[\.,]*$/;
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep( elements, function( elem, i ) {
+ /* jshint -W018 */
+ return !!qualifier.call( elem, i, elem ) !== not;
+ });
+
+ }
+
+ if ( qualifier.nodeType ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( elem === qualifier ) !== not;
+ });
+
+ }
+
+ if ( typeof qualifier === "string" ) {
+ if ( risSimple.test( qualifier ) ) {
+ return jQuery.filter( qualifier, elements, not );
+ }
+
+ qualifier = jQuery.filter( qualifier, elements );
+ }
+
+ return jQuery.grep( elements, function( elem ) {
+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
+ });
+}
+
+jQuery.filter = function( expr, elems, not ) {
+ var elem = elems[ 0 ];
+
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 && elem.nodeType === 1 ?
+ jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+ jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+ return elem.nodeType === 1;
+ }));
+};
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var i,
+ ret = [],
+ self = this,
+ len = self.length;
+
+ if ( typeof selector !== "string" ) {
+ return this.pushStack( jQuery( selector ).filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ }) );
+ }
+
+ for ( i = 0; i < len; i++ ) {
+ jQuery.find( selector, self[ i ], ret );
+ }
+
+ // Needed because $( selector, context ) becomes $( context ).find( selector )
+ ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+ ret.selector = this.selector ? this.selector + " " + selector : selector;
+ return ret;
+ },
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector || [], false) );
+ },
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector || [], true) );
+ },
+ is: function( selector ) {
+ return !!winnow(
+ this,
+
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ typeof selector === "string" && rneedsContext.test( selector ) ?
+ jQuery( selector ) :
+ selector || [],
+ false
+ ).length;
+ }
+});
+
+
+// Initialize a jQuery object
+
+
+// A central reference to the root jQuery(document)
+var rootjQuery,
+
+ // Use the correct document accordingly with window argument (sandbox)
+ document = window.document,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+ // Strict HTML recognition (#11290: must start with <)
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+ init = jQuery.fn.init = function( selector, context ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+
+ // scripts is true for back-compat
+ // Intentionally let the error be thrown if parseHTML is not present
+ jQuery.merge( this, jQuery.parseHTML(
+ match[1],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+ // Properties of context are called as methods if possible
+ if ( jQuery.isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
+ }
+ }
+
+ return this;
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || rootjQuery ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return typeof rootjQuery.ready !== "undefined" ?
+ rootjQuery.ready( selector ) :
+ // Execute immediately if ready is not present
+ selector( jQuery );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ };
+
+// Give the init function the jQuery prototype for later instantiation
+init.prototype = jQuery.fn;
+
+// Initialize central reference
+rootjQuery = jQuery( document );
+
+
+var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.extend({
+ dir: function( elem, dir, until ) {
+ var matched = [],
+ cur = elem[ dir ];
+
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+ if ( cur.nodeType === 1 ) {
+ matched.push( cur );
+ }
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ r.push( n );
+ }
+ }
+
+ return r;
+ }
+});
+
+jQuery.fn.extend({
+ has: function( target ) {
+ var i,
+ targets = jQuery( target, this ),
+ len = targets.length;
+
+ return this.filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ closest: function( selectors, context ) {
+ var cur,
+ i = 0,
+ l = this.length,
+ matched = [],
+ pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+ jQuery( selectors, context || this.context ) :
+ 0;
+
+ for ( ; i < l; i++ ) {
+ for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
+ // Always skip document fragments
+ if ( cur.nodeType < 11 && (pos ?
+ pos.index(cur) > -1 :
+
+ // Don't pass non-elements to Sizzle
+ cur.nodeType === 1 &&
+ jQuery.find.matchesSelector(cur, selectors)) ) {
+
+ matched.push( cur );
+ break;
+ }
+ }
+ }
+
+ return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
+ }
+
+ // index in selector
+ if ( typeof elem === "string" ) {
+ return jQuery.inArray( this[0], jQuery( elem ) );
+ }
+
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[0] : elem, this );
+ },
+
+ add: function( selector, context ) {
+ return this.pushStack(
+ jQuery.unique(
+ jQuery.merge( this.get(), jQuery( selector, context ) )
+ )
+ );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter(selector)
+ );
+ }
+});
+
+function sibling( cur, dir ) {
+ do {
+ cur = cur[ dir ];
+ } while ( cur && cur.nodeType !== 1 );
+
+ return cur;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return jQuery.nodeName( elem, "iframe" ) ?
+ elem.contentDocument || elem.contentWindow.document :
+ jQuery.merge( [], elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var ret = jQuery.map( this, fn, until );
+
+ if ( name.slice( -5 ) !== "Until" ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ ret = jQuery.filter( selector, ret );
+ }
+
+ if ( this.length > 1 ) {
+ // Remove duplicates
+ if ( !guaranteedUnique[ name ] ) {
+ ret = jQuery.unique( ret );
+ }
+
+ // Reverse order for parents* and prev-derivatives
+ if ( rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+ }
+
+ return this.pushStack( ret );
+ };
+});
+var rnotwhite = (/\S+/g);
+
+
+
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+ var object = optionsCache[ options ] = {};
+ jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ });
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ ( optionsCache[ options ] || createOptions( options ) ) :
+ jQuery.extend( {}, options );
+
+ var // Flag to know if list is currently firing
+ firing,
+ // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = !options.once && [],
+ // Fire callbacks
+ fire = function( data ) {
+ memory = options.memory && data;
+ fired = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ firing = true;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+ memory = false; // To prevent further calls using add
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( stack ) {
+ if ( stack.length ) {
+ fire( stack.shift() );
+ }
+ } else if ( memory ) {
+ list = [];
+ } else {
+ self.disable();
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ // First, we save the current length
+ var start = list.length;
+ (function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ var type = jQuery.type( arg );
+ if ( type === "function" ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && type !== "string" ) {
+ // Inspect recursively
+ add( arg );
+ }
+ });
+ })( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away
+ } else if ( memory ) {
+ firingStart = start;
+ fire( memory );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+ // Handle firing indexes
+ if ( firing ) {
+ if ( index <= firingLength ) {
+ firingLength--;
+ }
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ });
+ }
+ return this;
+ },
+ // Check if a given callback is in the list.
+ // If no argument is given, return whether or not list has callbacks attached.
+ has: function( fn ) {
+ return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ firingLength = 0;
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( list && ( !fired || stack ) ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ if ( firing ) {
+ stack.push( args );
+ } else {
+ fire( args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+
+
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var tuples = [
+ // action, add listener, listener list, final state
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
+ deferred[ tuple[1] ](function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise()
+ .done( newDefer.resolve )
+ .fail( newDefer.reject )
+ .progress( newDefer.notify );
+ } else {
+ newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+ }
+ });
+ });
+ fns = null;
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Keep pipe for back-compat
+ promise.pipe = promise.then;
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 3 ];
+
+ // promise[ done | fail | progress ] = list.add
+ promise[ tuple[1] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(function() {
+ // state = [ resolved | rejected ]
+ state = stateString;
+
+ // [ reject_list | resolve_list ].disable; progress_list.lock
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ }
+
+ // deferred[ resolve | reject | notify ]
+ deferred[ tuple[0] ] = function() {
+ deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+ return this;
+ };
+ deferred[ tuple[0] + "With" ] = list.fireWith;
+ });
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( subordinate /* , ..., subordinateN */ ) {
+ var i = 0,
+ resolveValues = slice.call( arguments ),
+ length = resolveValues.length,
+
+ // the count of uncompleted subordinates
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+ // Update function for both resolve and progress values
+ updateFunc = function( i, contexts, values ) {
+ return function( value ) {
+ contexts[ i ] = this;
+ values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
+ if ( values === progressValues ) {
+ deferred.notifyWith( contexts, values );
+
+ } else if ( !(--remaining) ) {
+ deferred.resolveWith( contexts, values );
+ }
+ };
+ },
+
+ progressValues, progressContexts, resolveContexts;
+
+ // add listeners to Deferred subordinates; treat others as resolved
+ if ( length > 1 ) {
+ progressValues = new Array( length );
+ progressContexts = new Array( length );
+ resolveContexts = new Array( length );
+ for ( ; i < length; i++ ) {
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+ resolveValues[ i ].promise()
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject )
+ .progress( updateFunc( i, progressContexts, progressValues ) );
+ } else {
+ --remaining;
+ }
+ }
+ }
+
+ // if we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
+ return deferred.promise();
+ }
+});
+
+
+// The deferred used on DOM ready
+var readyList;
+
+jQuery.fn.ready = function( fn ) {
+ // Add the callback
+ jQuery.ready.promise().done( fn );
+
+ return this;
+};
+
+jQuery.extend({
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.trigger ) {
+ jQuery( document ).trigger("ready").off("ready");
+ }
+ }
+});
+
+/**
+ * Clean-up method for dom ready events
+ */
+function detach() {
+ if ( document.addEventListener ) {
+ document.removeEventListener( "DOMContentLoaded", completed, false );
+ window.removeEventListener( "load", completed, false );
+
+ } else {
+ document.detachEvent( "onreadystatechange", completed );
+ window.detachEvent( "onload", completed );
+ }
+}
+
+/**
+ * The ready event handler and self cleanup method
+ */
+function completed() {
+ // readyState === "complete" is good enough for us to call the dom ready in oldIE
+ if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
+ detach();
+ jQuery.ready();
+ }
+}
+
+jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ setTimeout( jQuery.ready );
+
+ // Standards-based browsers support DOMContentLoaded
+ } else if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed, false );
+
+ // If IE event model is used
+ } else {
+ // Ensure firing before onload, maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", completed );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", completed );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var top = false;
+
+ try {
+ top = window.frameElement == null && document.documentElement;
+ } catch(e) {}
+
+ if ( top && top.doScroll ) {
+ (function doScrollCheck() {
+ if ( !jQuery.isReady ) {
+
+ try {
+ // Use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ top.doScroll("left");
+ } catch(e) {
+ return setTimeout( doScrollCheck, 50 );
+ }
+
+ // detach all dom ready events
+ detach();
+
+ // and execute any waiting functions
+ jQuery.ready();
+ }
+ })();
+ }
+ }
+ }
+ return readyList.promise( obj );
+};
+
+
+var strundefined = typeof undefined;
+
+
+
+// Support: IE<9
+// Iteration over object's inherited properties before its own
+var i;
+for ( i in jQuery( support ) ) {
+ break;
+}
+support.ownLast = i !== "0";
+
+// Note: most support tests are defined in their respective modules.
+// false until the test is run
+support.inlineBlockNeedsLayout = false;
+
+jQuery(function() {
+ // We need to execute this one support test ASAP because we need to know
+ // if body.style.zoom needs to be set.
+
+ var container, div,
+ body = document.getElementsByTagName("body")[0];
+
+ if ( !body ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ // Setup
+ container = document.createElement( "div" );
+ container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
+
+ div = document.createElement( "div" );
+ body.appendChild( container ).appendChild( div );
+
+ if ( typeof div.style.zoom !== strundefined ) {
+ // Support: IE<8
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ div.style.cssText = "border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1";
+
+ if ( (support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 )) ) {
+ // Prevent IE 6 from affecting layout for positioned elements #11048
+ // Prevent IE from shrinking the body in IE 7 mode #12869
+ // Support: IE<8
+ body.style.zoom = 1;
+ }
+ }
+
+ body.removeChild( container );
+
+ // Null elements to avoid leaks in IE
+ container = div = null;
+});
+
+
+
+
+(function() {
+ var div = document.createElement( "div" );
+
+ // Execute the test only if not already executed in another module.
+ if (support.deleteExpando == null) {
+ // Support: IE<9
+ support.deleteExpando = true;
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+ }
+
+ // Null elements to avoid leaks in IE.
+ div = null;
+})();
+
+
+/**
+ * Determines whether an object can have data
+ */
+jQuery.acceptData = function( elem ) {
+ var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ],
+ nodeType = +elem.nodeType || 1;
+
+ // Do not set data on non-element DOM nodes because it will not be cleared (#8335).
+ return nodeType !== 1 && nodeType !== 9 ?
+ false :
+
+ // Nodes accept data unless otherwise specified; rejection can be conditional
+ !noData || noData !== true && elem.getAttribute("classid") === noData;
+};
+
+
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+function dataAttr( elem, key, data ) {
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+ var name;
+ for ( name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var ret, thisCache,
+ internalKey = jQuery.expando,
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ // Avoid exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
+ cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ thisCache = cache[ id ];
+
+ // jQuery data() is stored in a separate object inside the object's internal data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
+ }
+
+ thisCache = thisCache.data;
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( typeof name === "string" ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
+}
+
+function internalRemoveData( elem, name, pvt ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, i,
+ isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+ if ( thisCache ) {
+
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split(" ");
+ }
+ }
+ } else {
+ // If "name" is an array of keys...
+ // When data is initially created, via ("key", "val") signature,
+ // keys will be converted to camelCase.
+ // Since there is no way to tell _how_ a key was added, remove
+ // both plain key and camelCase key. #12786
+ // This will only penalize the array argument path.
+ name = name.concat( jQuery.map( name, jQuery.camelCase ) );
+ }
+
+ i = name.length;
+ while ( i-- ) {
+ delete thisCache[ name[i] ];
+ }
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( !pvt ) {
+ delete cache[ id ].data;
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject( cache[ id ] ) ) {
+ return;
+ }
+ }
+
+ // Destroy the cache
+ if ( isNode ) {
+ jQuery.cleanData( [ elem ], true );
+
+ // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+ /* jshint eqeqeq: false */
+ } else if ( support.deleteExpando || cache != cache.window ) {
+ /* jshint eqeqeq: true */
+ delete cache[ id ];
+
+ // When all else fails, null
+ } else {
+ cache[ id ] = null;
+ }
+}
+
+jQuery.extend({
+ cache: {},
+
+ // The following elements (space-suffixed to avoid Object.prototype collisions)
+ // throw uncatchable exceptions if you attempt to set expando properties
+ noData: {
+ "applet ": true,
+ "embed ": true,
+ // ...but Flash objects (which have this classid) *can* handle expandos
+ "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return internalData( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ return internalRemoveData( elem, name );
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return internalData( elem, name, data, true );
+ },
+
+ _removeData: function( elem, name ) {
+ return internalRemoveData( elem, name, true );
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var i, name, data,
+ elem = this[0],
+ attrs = elem && elem.attributes;
+
+ // Special expections of .data basically thwart jQuery.access,
+ // so implement the relevant behavior ourselves
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ i = attrs.length;
+ while ( i-- ) {
+ name = attrs[i].name;
+
+ if ( name.indexOf("data-") === 0 ) {
+ name = jQuery.camelCase( name.slice(5) );
+
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ jQuery._data( elem, "parsedAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ return arguments.length > 1 ?
+
+ // Sets one value
+ this.each(function() {
+ jQuery.data( this, key, value );
+ }) :
+
+ // Gets one value
+ // Try to fetch any internally stored data first
+ elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+
+
+jQuery.extend({
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = jQuery._data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || jQuery.isArray(data) ) {
+ queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // not intended for public consumption - generates a queueHooks object, or returns the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+ empty: jQuery.Callbacks("once memory").add(function() {
+ jQuery._removeData( elem, type + "queue" );
+ jQuery._removeData( elem, key );
+ })
+ });
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[0], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while ( i-- ) {
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+});
+var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
+
+var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
+
+var isHidden = function( elem, el ) {
+ // isHidden might be called from jQuery#filter function;
+ // in that case, element will be second argument
+ elem = el || elem;
+ return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+ };
+
+
+
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ length = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( jQuery.type( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !jQuery.isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < length; i++ ) {
+ fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+ }
+ }
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
+};
+var rcheckableType = (/^(?:checkbox|radio)$/i);
+
+
+
+(function() {
+ var fragment = document.createDocumentFragment(),
+ div = document.createElement("div"),
+ input = document.createElement("input");
+
+ // Setup
+ div.setAttribute( "className", "t" );
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a>";
+
+ // IE strips leading whitespace when .innerHTML is used
+ support.leadingWhitespace = div.firstChild.nodeType === 3;
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ support.tbody = !div.getElementsByTagName( "tbody" ).length;
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ support.htmlSerialize = !!div.getElementsByTagName( "link" ).length;
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ support.html5Clone =
+ document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav></:nav>";
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ input.type = "checkbox";
+ input.checked = true;
+ fragment.appendChild( input );
+ support.appendChecked = input.checked;
+
+ // Make sure textarea (and checkbox) defaultValue is properly cloned
+ // Support: IE6-IE11+
+ div.innerHTML = "<textarea>x</textarea>";
+ support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ fragment.appendChild( div );
+ div.innerHTML = "<input type='radio' checked='checked' name='t'/>";
+
+ // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
+ // old WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE<9
+ // Opera does not clone events (and typeof div.attachEvent === undefined).
+ // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
+ support.noCloneEvent = true;
+ if ( div.attachEvent ) {
+ div.attachEvent( "onclick", function() {
+ support.noCloneEvent = false;
+ });
+
+ div.cloneNode( true ).click();
+ }
+
+ // Execute the test only if not already executed in another module.
+ if (support.deleteExpando == null) {
+ // Support: IE<9
+ support.deleteExpando = true;
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+ }
+
+ // Null elements to avoid leaks in IE.
+ fragment = div = input = null;
+})();
+
+
+(function() {
+ var i, eventName,
+ div = document.createElement( "div" );
+
+ // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event)
+ for ( i in { submit: true, change: true, focusin: true }) {
+ eventName = "on" + i;
+
+ if ( !(support[ i + "Bubbles" ] = eventName in window) ) {
+ // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
+ div.setAttribute( eventName, "t" );
+ support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false;
+ }
+ }
+
+ // Null elements to avoid leaks in IE.
+ div = null;
+})();
+
+
+var rformElems = /^(?:input|select|textarea)$/i,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+function safeActiveElement() {
+ try {
+ return document.activeElement;
+ } catch ( err ) { }
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+ var tmp, events, t, handleObjIn,
+ special, eventHandle, handleObj,
+ handlers, type, namespaces, origType,
+ elemData = jQuery._data( elem );
+
+ // Don't attach events to noData or text/comment nodes (but allow plain objects)
+ if ( !elemData ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ if ( !(events = elemData.events) ) {
+ events = elemData.events = {};
+ }
+ if ( !(eventHandle = elemData.handle) ) {
+ eventHandle = elemData.handle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
+ }
+
+ // Handle multiple events separated by a space
+ types = ( types || "" ).match( rnotwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // There *must* be a type, no attaching namespace-only handlers
+ if ( !type ) {
+ continue;
+ }
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !(handlers = events[ type ]) ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener/attachEvent if the special events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+ var j, handleObj, tmp,
+ origCount, t, events,
+ special, handlers, type,
+ namespaces, origType,
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( rnotwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ delete elemData.handle;
+
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery._removeData( elem, "events" );
+ }
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+ var handle, ontype, cur,
+ bubbleType, special, tmp, i,
+ eventPath = [ elem || document ],
+ type = hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
+
+ cur = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf(".") >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf(":") < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+ event.isTrigger = onlyHandlers ? 2 : 3;
+ event.namespace = namespaces.join(".");
+ event.namespace_re = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === (elem.ownerDocument || document) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
+ event.result = handle.apply( cur, data );
+ if ( event.result === false ) {
+ event.preventDefault();
+ }
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
+ jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ try {
+ elem[ type ]();
+ } catch ( e ) {
+ // IE<9 dies on focus/blur to hidden element (#1486,#12518)
+ // only reproducible on winXP IE8 native, not IE9 in IE8 mode
+ }
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event );
+
+ var i, ret, handleObj, matched, j,
+ handlerQueue = [],
+ args = slice.call( arguments ),
+ handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[0] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+ // Triggered event must either 1) have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( (event.result = ret) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ handlers: function( event, handlers ) {
+ var sel, handleObj, matches, i,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Find delegate handlers
+ // Black-hole SVG <use> instance trees (#13180)
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+ /* jshint eqeqeq: false */
+ for ( ; cur != this; cur = cur.parentNode || this ) {
+ /* jshint eqeqeq: true */
+
+ // Don't check non-elements (#13208)
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
+ matches = [];
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+
+ // Don't conflict with Object.prototype properties (#13203)
+ sel = handleObj.selector + " ";
+
+ if ( matches[ sel ] === undefined ) {
+ matches[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) >= 0 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
+ }
+ if ( matches[ sel ] ) {
+ matches.push( handleObj );
+ }
+ }
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, handlers: matches });
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ if ( delegateCount < handlers.length ) {
+ handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+ }
+
+ return handlerQueue;
+ },
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop, copy,
+ type = event.type,
+ originalEvent = event,
+ fixHook = this.fixHooks[ type ];
+
+ if ( !fixHook ) {
+ this.fixHooks[ type ] = fixHook =
+ rmouseEvent.test( type ) ? this.mouseHooks :
+ rkeyEvent.test( type ) ? this.keyHooks :
+ {};
+ }
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+ event = new jQuery.Event( originalEvent );
+
+ i = copy.length;
+ while ( i-- ) {
+ prop = copy[ i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Support: IE<9
+ // Fix target property (#1925)
+ if ( !event.target ) {
+ event.target = originalEvent.srcElement || document;
+ }
+
+ // Support: Chrome 23+, Safari?
+ // Target should not be a text node (#504, #13143)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ // Support: IE<9
+ // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
+ event.metaKey = !!event.metaKey;
+
+ return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
+ },
+
+ // Includes some event props shared by KeyEvent and MouseEvent
+ props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+ fixHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+ filter: function( event, original ) {
+ var body, eventDoc, doc,
+ button = original.button,
+ fromElement = original.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && fromElement ) {
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event;
+ }
+ },
+
+ special: {
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+ focus: {
+ // Fire native event if possible so blur/focus sequence is correct
+ trigger: function() {
+ if ( this !== safeActiveElement() && this.focus ) {
+ try {
+ this.focus();
+ return false;
+ } catch ( e ) {
+ // Support: IE<9
+ // If we error on focus to hidden element (#1486, #12518),
+ // let .trigger() run the handlers
+ }
+ }
+ },
+ delegateType: "focusin"
+ },
+ blur: {
+ trigger: function() {
+ if ( this === safeActiveElement() && this.blur ) {
+ this.blur();
+ return false;
+ }
+ },
+ delegateType: "focusout"
+ },
+ click: {
+ // For checkbox, fire native event so checked state will be right
+ trigger: function() {
+ if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
+ this.click();
+ return false;
+ }
+ },
+
+ // For cross-browser consistency, don't fire native .click() on links
+ _default: function( event ) {
+ return jQuery.nodeName( event.target, "a" );
+ }
+ },
+
+ beforeunload: {
+ postDispatch: function( event ) {
+
+ // Even when returnValue equals to undefined Firefox will still show alert
+ if ( event.result !== undefined ) {
+ event.originalEvent.returnValue = event.result;
+ }
+ }
+ }
+ },
+
+ simulate: function( type, elem, event, bubble ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ {
+ type: type,
+ isSimulated: true,
+ originalEvent: {}
+ }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.dispatch.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
+ }
+};
+
+jQuery.removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+ } :
+ function( elem, type, handle ) {
+ var name = "on" + type;
+
+ if ( elem.detachEvent ) {
+
+ // #8545, #7054, preventing memory leaks for custom events in IE6-8
+ // detachEvent needed property on element, by name of that event, to properly expose it to GC
+ if ( typeof elem[ name ] === strundefined ) {
+ elem[ name ] = null;
+ }
+
+ elem.detachEvent( name, handle );
+ }
+ };
+
+jQuery.Event = function( src, props ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !(this instanceof jQuery.Event) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = src.defaultPrevented ||
+ src.defaultPrevented === undefined && (
+ // Support: IE < 9
+ src.returnValue === false ||
+ // Support: Android < 4.0
+ src.getPreventDefault && src.getPreventDefault() ) ?
+ returnTrue :
+ returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse,
+
+ preventDefault: function() {
+ var e = this.originalEvent;
+
+ this.isDefaultPrevented = returnTrue;
+ if ( !e ) {
+ return;
+ }
+
+ // If preventDefault exists, run it on the original event
+ if ( e.preventDefault ) {
+ e.preventDefault();
+
+ // Support: IE
+ // Otherwise set the returnValue property of the original event to false
+ } else {
+ e.returnValue = false;
+ }
+ },
+ stopPropagation: function() {
+ var e = this.originalEvent;
+
+ this.isPropagationStopped = returnTrue;
+ if ( !e ) {
+ return;
+ }
+ // If stopPropagation exists, run it on the original event
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+
+ // Support: IE
+ // Set the cancelBubble property of the original event to true
+ e.cancelBubble = true;
+ },
+ stopImmediatePropagation: function() {
+ this.isImmediatePropagationStopped = returnTrue;
+ this.stopPropagation();
+ }
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var ret,
+ target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj;
+
+ // For mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+});
+
+// IE submit delegation
+if ( !support.submitBubbles ) {
+
+ jQuery.event.special.submit = {
+ setup: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+ // Node name check avoids a VML-related crash in IE (#9807)
+ var elem = e.target,
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+ if ( form && !jQuery._data( form, "submitBubbles" ) ) {
+ jQuery.event.add( form, "submit._submit", function( event ) {
+ event._submit_bubble = true;
+ });
+ jQuery._data( form, "submitBubbles", true );
+ }
+ });
+ // return undefined since we don't need an event listener
+ },
+
+ postDispatch: function( event ) {
+ // If form was submitted by the user, bubble the event up the tree
+ if ( event._submit_bubble ) {
+ delete event._submit_bubble;
+ if ( this.parentNode && !event.isTrigger ) {
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
+ }
+ }
+ },
+
+ teardown: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+ jQuery.event.remove( this, "._submit" );
+ }
+ };
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !support.changeBubbles ) {
+
+ jQuery.event.special.change = {
+
+ setup: function() {
+
+ if ( rformElems.test( this.nodeName ) ) {
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
+ // after a propertychange. Eat the blur-change in special.change.handle.
+ // This still fires onchange a second time for check/radio after blur.
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ jQuery.event.add( this, "propertychange._change", function( event ) {
+ if ( event.originalEvent.propertyName === "checked" ) {
+ this._just_changed = true;
+ }
+ });
+ jQuery.event.add( this, "click._change", function( event ) {
+ if ( this._just_changed && !event.isTrigger ) {
+ this._just_changed = false;
+ }
+ // Allow triggered, simulated change events (#11500)
+ jQuery.event.simulate( "change", this, event, true );
+ });
+ }
+ return false;
+ }
+ // Delegated event; lazy-add a change handler on descendant inputs
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
+ var elem = e.target;
+
+ if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
+ jQuery.event.add( elem, "change._change", function( event ) {
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+ jQuery.event.simulate( "change", this.parentNode, event, true );
+ }
+ });
+ jQuery._data( elem, "changeBubbles", true );
+ }
+ });
+ },
+
+ handle: function( event ) {
+ var elem = event.target;
+
+ // Swallow native change events from checkbox/radio, we already triggered them above
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+ return event.handleObj.handler.apply( this, arguments );
+ }
+ },
+
+ teardown: function() {
+ jQuery.event.remove( this, "._change" );
+
+ return !rformElems.test( this.nodeName );
+ }
+ };
+}
+
+// Create "bubbling" focus and blur events
+if ( !support.focusinBubbles ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler on the document while someone wants focusin/focusout
+ var handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ var doc = this.ownerDocument || this,
+ attaches = jQuery._data( doc, fix );
+
+ if ( !attaches ) {
+ doc.addEventListener( orig, handler, true );
+ }
+ jQuery._data( doc, fix, ( attaches || 0 ) + 1 );
+ },
+ teardown: function() {
+ var doc = this.ownerDocument || this,
+ attaches = jQuery._data( doc, fix ) - 1;
+
+ if ( !attaches ) {
+ doc.removeEventListener( orig, handler, true );
+ jQuery._removeData( doc, fix );
+ } else {
+ jQuery._data( doc, fix, attaches );
+ }
+ }
+ };
+ });
+}
+
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var type, origFn;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
+ }
+ return this;
+ }
+
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on( types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ var handleObj, type;
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+ triggerHandler: function( type, data ) {
+ var elem = this[0];
+ if ( elem ) {
+ return jQuery.event.trigger( type, data, elem, true );
+ }
+ }
+});
+
+
+function createSafeFragment( document ) {
+ var list = nodeNames.split( "|" ),
+ safeFrag = document.createDocumentFragment();
+
+ if ( safeFrag.createElement ) {
+ while ( list.length ) {
+ safeFrag.createElement(
+ list.pop()
+ );
+ }
+ }
+ return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+ rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
+ rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
+ rleadingWhitespace = /^\s+/,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+ rtagName = /<([\w:]+)/,
+ rtbody = /<tbody/i,
+ rhtml = /<|&#?\w+;/,
+ rnoInnerhtml = /<(?:script|style|link)/i,
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rscriptType = /^$|\/(?:java|ecma)script/i,
+ rscriptTypeMasked = /^true\/(.*)/,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
+
+ // We have to close these tags to support XHTML (#13200)
+ wrapMap = {
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
+ legend: [ 1, "<fieldset>", "</fieldset>" ],
+ area: [ 1, "<map>", "</map>" ],
+ param: [ 1, "<object>", "</object>" ],
+ thead: [ 1, "<table>", "</table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+ // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
+ // unless wrapped in a div with non-breaking characters in front of it.
+ _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ]
+ },
+ safeFragment = createSafeFragment( document ),
+ fragmentDiv = safeFragment.appendChild( document.createElement("div") );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+function getAll( context, tag ) {
+ var elems, elem,
+ i = 0,
+ found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) :
+ typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) :
+ undefined;
+
+ if ( !found ) {
+ for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
+ if ( !tag || jQuery.nodeName( elem, tag ) ) {
+ found.push( elem );
+ } else {
+ jQuery.merge( found, getAll( elem, tag ) );
+ }
+ }
+ }
+
+ return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+ jQuery.merge( [ context ], found ) :
+ found;
+}
+
+// Used in buildFragment, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+ if ( rcheckableType.test( elem.type ) ) {
+ elem.defaultChecked = elem.checked;
+ }
+}
+
+// Support: IE<8
+// Manipulating tables requires a tbody
+function manipulationTarget( elem, content ) {
+ return jQuery.nodeName( elem, "table" ) &&
+ jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
+
+ elem.getElementsByTagName("tbody")[0] ||
+ elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
+ elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+ elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type;
+ return elem;
+}
+function restoreScript( elem ) {
+ var match = rscriptTypeMasked.exec( elem.type );
+ if ( match ) {
+ elem.type = match[1];
+ } else {
+ elem.removeAttribute("type");
+ }
+ return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+ var elem,
+ i = 0;
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
+ }
+}
+
+function cloneCopyEvent( src, dest ) {
+
+ if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+ return;
+ }
+
+ var type, i, l,
+ oldData = jQuery._data( src ),
+ curData = jQuery._data( dest, oldData ),
+ events = oldData.events;
+
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+
+ // make the cloned public data object a copy from the original
+ if ( curData.data ) {
+ curData.data = jQuery.extend( {}, curData.data );
+ }
+}
+
+function fixCloneNodeIssues( src, dest ) {
+ var nodeName, e, data;
+
+ // We do not need to do anything for non-Elements
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ nodeName = dest.nodeName.toLowerCase();
+
+ // IE6-8 copies events bound via attachEvent when using cloneNode.
+ if ( !support.noCloneEvent && dest[ jQuery.expando ] ) {
+ data = jQuery._data( dest );
+
+ for ( e in data.events ) {
+ jQuery.removeEvent( dest, e, data.handle );
+ }
+
+ // Event data gets referenced instead of copied if the expando gets copied too
+ dest.removeAttribute( jQuery.expando );
+ }
+
+ // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
+ if ( nodeName === "script" && dest.text !== src.text ) {
+ disableScript( dest ).text = src.text;
+ restoreScript( dest );
+
+ // IE6-10 improperly clones children of object elements using classid.
+ // IE10 throws NoModificationAllowedError if parent is null, #12132.
+ } else if ( nodeName === "object" ) {
+ if ( dest.parentNode ) {
+ dest.outerHTML = src.outerHTML;
+ }
+
+ // This path appears unavoidable for IE9. When cloning an object
+ // element in IE9, the outerHTML strategy above is not sufficient.
+ // If the src has innerHTML and the destination does not,
+ // copy the src.innerHTML into the dest.innerHTML. #10324
+ if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
+ dest.innerHTML = src.innerHTML;
+ }
+
+ } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+ // IE6-8 fails to persist the checked state of a cloned checkbox
+ // or radio button. Worse, IE6-7 fail to give the cloned element
+ // a checked appearance if the defaultChecked value isn't also set
+
+ dest.defaultChecked = dest.checked = src.checked;
+
+ // IE6-7 get confused and end up setting the value of a cloned
+ // checkbox/radio button to an empty string instead of "on"
+ if ( dest.value !== src.value ) {
+ dest.value = src.value;
+ }
+
+ // IE6-8 fails to return the selected option to the default selected
+ // state when cloning options
+ } else if ( nodeName === "option" ) {
+ dest.defaultSelected = dest.selected = src.defaultSelected;
+
+ // IE6-8 fails to set the defaultValue to the correct value when
+ // cloning other types of input fields
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+ }
+}
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var destElements, node, clone, i, srcElements,
+ inPage = jQuery.contains( elem.ownerDocument, elem );
+
+ if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
+ clone = elem.cloneNode( true );
+
+ // IE<=8 does not properly clone detached, unknown element nodes
+ } else {
+ fragmentDiv.innerHTML = elem.outerHTML;
+ fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
+ }
+
+ if ( (!support.noCloneEvent || !support.noCloneChecked) &&
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+
+ // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+ destElements = getAll( clone );
+ srcElements = getAll( elem );
+
+ // Fix all IE cloning issues
+ for ( i = 0; (node = srcElements[i]) != null; ++i ) {
+ // Ensure that the destination node is not null; Fixes #9587
+ if ( destElements[i] ) {
+ fixCloneNodeIssues( node, destElements[i] );
+ }
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ if ( deepDataAndEvents ) {
+ srcElements = srcElements || getAll( elem );
+ destElements = destElements || getAll( clone );
+
+ for ( i = 0; (node = srcElements[i]) != null; i++ ) {
+ cloneCopyEvent( node, destElements[i] );
+ }
+ } else {
+ cloneCopyEvent( elem, clone );
+ }
+ }
+
+ // Preserve script evaluation history
+ destElements = getAll( clone, "script" );
+ if ( destElements.length > 0 ) {
+ setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+ }
+
+ destElements = srcElements = node = null;
+
+ // Return the cloned set
+ return clone;
+ },
+
+ buildFragment: function( elems, context, scripts, selection ) {
+ var j, elem, contains,
+ tmp, tag, tbody, wrap,
+ l = elems.length,
+
+ // Ensure a safe fragment
+ safe = createSafeFragment( context ),
+
+ nodes = [],
+ i = 0;
+
+ for ( ; i < l; i++ ) {
+ elem = elems[ i ];
+
+ if ( elem || elem === 0 ) {
+
+ // Add nodes directly
+ if ( jQuery.type( elem ) === "object" ) {
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+ // Convert non-html into a text node
+ } else if ( !rhtml.test( elem ) ) {
+ nodes.push( context.createTextNode( elem ) );
+
+ // Convert html into DOM nodes
+ } else {
+ tmp = tmp || safe.appendChild( context.createElement("div") );
+
+ // Deserialize a standard representation
+ tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+
+ tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
+
+ // Descend through wrappers to the right content
+ j = wrap[0];
+ while ( j-- ) {
+ tmp = tmp.lastChild;
+ }
+
+ // Manually add leading whitespace removed by IE
+ if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+ nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
+ }
+
+ // Remove IE's autoinserted <tbody> from table fragments
+ if ( !support.tbody ) {
+
+ // String was a <table>, *may* have spurious <tbody>
+ elem = tag === "table" && !rtbody.test( elem ) ?
+ tmp.firstChild :
+
+ // String was a bare <thead> or <tfoot>
+ wrap[1] === "<table>" && !rtbody.test( elem ) ?
+ tmp :
+ 0;
+
+ j = elem && elem.childNodes.length;
+ while ( j-- ) {
+ if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
+ elem.removeChild( tbody );
+ }
+ }
+ }
+
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Fix #12392 for WebKit and IE > 9
+ tmp.textContent = "";
+
+ // Fix #12392 for oldIE
+ while ( tmp.firstChild ) {
+ tmp.removeChild( tmp.firstChild );
+ }
+
+ // Remember the top-level container for proper cleanup
+ tmp = safe.lastChild;
+ }
+ }
+ }
+
+ // Fix #11356: Clear elements from fragment
+ if ( tmp ) {
+ safe.removeChild( tmp );
+ }
+
+ // Reset defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ if ( !support.appendChecked ) {
+ jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
+ }
+
+ i = 0;
+ while ( (elem = nodes[ i++ ]) ) {
+
+ // #4087 - If origin and destination elements are the same, and this is
+ // that element, do not do anything
+ if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+ continue;
+ }
+
+ contains = jQuery.contains( elem.ownerDocument, elem );
+
+ // Append to fragment
+ tmp = getAll( safe.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( contains ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( (elem = tmp[ j++ ]) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
+ }
+ }
+
+ tmp = null;
+
+ return safe;
+ },
+
+ cleanData: function( elems, /* internal */ acceptData ) {
+ var elem, type, id, data,
+ i = 0,
+ internalKey = jQuery.expando,
+ cache = jQuery.cache,
+ deleteExpando = support.deleteExpando,
+ special = jQuery.event.special;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ if ( acceptData || jQuery.acceptData( elem ) ) {
+
+ id = elem[ internalKey ];
+ data = id && cache[ id ];
+
+ if ( data ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ // Remove cache only if it was not already removed by jQuery.event.remove
+ if ( cache[ id ] ) {
+
+ delete cache[ id ];
+
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( deleteExpando ) {
+ delete elem[ internalKey ];
+
+ } else if ( typeof elem.removeAttribute !== strundefined ) {
+ elem.removeAttribute( internalKey );
+
+ } else {
+ elem[ internalKey ] = null;
+ }
+
+ deletedIds.push( id );
+ }
+ }
+ }
+ }
+ }
+});
+
+jQuery.fn.extend({
+ text: function( value ) {
+ return access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+ }, null, value, arguments.length );
+ },
+
+ append: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.insertBefore( elem, target.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this );
+ }
+ });
+ },
+
+ after: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ }
+ });
+ },
+
+ remove: function( selector, keepData /* Internal Use Only */ ) {
+ var elem,
+ elems = selector ? jQuery.filter( selector, this ) : this,
+ i = 0;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem ) );
+ }
+
+ if ( elem.parentNode ) {
+ if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
+ setGlobalEval( getAll( elem, "script" ) );
+ }
+ elem.parentNode.removeChild( elem );
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ var elem,
+ i = 0;
+
+ for ( ; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+
+ // If this is a select, ensure that it displays empty (#12336)
+ // Support: IE<9
+ if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
+ elem.options.length = 0;
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map(function() {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ });
+ },
+
+ html: function( value ) {
+ return access( this, function( value ) {
+ var elem = this[ 0 ] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined ) {
+ return elem.nodeType === 1 ?
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
+ undefined;
+ }
+
+ // See if we can take a shortcut and just use innerHTML
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ ( support.htmlSerialize || !rnoshimcache.test( value ) ) &&
+ ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+ !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) {
+
+ value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+ try {
+ for (; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ elem = this[i] || {};
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch(e) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function() {
+ var arg = arguments[ 0 ];
+
+ // Make the changes, replacing each context element with the new content
+ this.domManip( arguments, function( elem ) {
+ arg = this.parentNode;
+
+ jQuery.cleanData( getAll( this ) );
+
+ if ( arg ) {
+ arg.replaceChild( elem, this );
+ }
+ });
+
+ // Force removal if there was no new content (e.g., from empty arguments)
+ return arg && (arg.length || arg.nodeType) ? this : this.remove();
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, callback ) {
+
+ // Flatten any nested arrays
+ args = concat.apply( [], args );
+
+ var first, node, hasScripts,
+ scripts, doc, fragment,
+ i = 0,
+ l = this.length,
+ set = this,
+ iNoClone = l - 1,
+ value = args[0],
+ isFunction = jQuery.isFunction( value );
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( isFunction ||
+ ( l > 1 && typeof value === "string" &&
+ !support.checkClone && rchecked.test( value ) ) ) {
+ return this.each(function( index ) {
+ var self = set.eq( index );
+ if ( isFunction ) {
+ args[0] = value.call( this, index, self.html() );
+ }
+ self.domManip( args, callback );
+ });
+ }
+
+ if ( l ) {
+ fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ if ( first ) {
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+ hasScripts = scripts.length;
+
+ // Use the original fragment for the last item instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ for ( ; i < l; i++ ) {
+ node = fragment;
+
+ if ( i !== iNoClone ) {
+ node = jQuery.clone( node, true, true );
+
+ // Keep references to cloned scripts for later restoration
+ if ( hasScripts ) {
+ jQuery.merge( scripts, getAll( node, "script" ) );
+ }
+ }
+
+ callback.call( this[i], node, i );
+ }
+
+ if ( hasScripts ) {
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+ // Reenable scripts
+ jQuery.map( scripts, restoreScript );
+
+ // Evaluate executable scripts on first document insertion
+ for ( i = 0; i < hasScripts; i++ ) {
+ node = scripts[ i ];
+ if ( rscriptType.test( node.type || "" ) &&
+ !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+ if ( node.src ) {
+ // Optional AJAX dependency, but won't run scripts if not present
+ if ( jQuery._evalUrl ) {
+ jQuery._evalUrl( node.src );
+ }
+ } else {
+ jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
+ }
+ }
+ }
+ }
+
+ // Fix #11809: Avoid leaking memory
+ fragment = first = null;
+ }
+ }
+
+ return this;
+ }
+});
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var elems,
+ i = 0,
+ ret = [],
+ insert = jQuery( selector ),
+ last = insert.length - 1;
+
+ for ( ; i <= last; i++ ) {
+ elems = i === last ? this : this.clone(true);
+ jQuery( insert[i] )[ original ]( elems );
+
+ // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
+ push.apply( ret, elems.get() );
+ }
+
+ return this.pushStack( ret );
+ };
+});
+
+
+var iframe,
+ elemdisplay = {};
+
+/**
+ * Retrieve the actual display of a element
+ * @param {String} name nodeName of the element
+ * @param {Object} doc Document object
+ */
+// Called only from within defaultDisplay
+function actualDisplay( name, doc ) {
+ var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+
+ // getDefaultComputedStyle might be reliably used only on attached element
+ display = window.getDefaultComputedStyle ?
+
+ // Use of this method is a temporary fix (more like optmization) until something better comes along,
+ // since it was removed from specification and supported only in FF
+ window.getDefaultComputedStyle( elem[ 0 ] ).display : jQuery.css( elem[ 0 ], "display" );
+
+ // We don't have any data stored on the element,
+ // so use "detach" method as fast way to get rid of the element
+ elem.detach();
+
+ return display;
+}
+
+/**
+ * Try to determine the default display value of an element
+ * @param {String} nodeName
+ */
+function defaultDisplay( nodeName ) {
+ var doc = document,
+ display = elemdisplay[ nodeName ];
+
+ if ( !display ) {
+ display = actualDisplay( nodeName, doc );
+
+ // If the simple way fails, read from inside an iframe
+ if ( display === "none" || !display ) {
+
+ // Use the already-created iframe if possible
+ iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
+
+ // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+ doc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document;
+
+ // Support: IE
+ doc.write();
+ doc.close();
+
+ display = actualDisplay( nodeName, doc );
+ iframe.detach();
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return display;
+}
+
+
+(function() {
+ var a, shrinkWrapBlocksVal,
+ div = document.createElement( "div" ),
+ divReset =
+ "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;" +
+ "display:block;padding:0;margin:0;border:0";
+
+ // Setup
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+ a = div.getElementsByTagName( "a" )[ 0 ];
+
+ a.style.cssText = "float:left;opacity:.5";
+
+ // Make sure that element opacity exists
+ // (IE uses filter instead)
+ // Use a regex to work around a WebKit issue. See #5145
+ support.opacity = /^0.5/.test( a.style.opacity );
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ support.cssFloat = !!a.style.cssFloat;
+
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ // Null elements to avoid leaks in IE.
+ a = div = null;
+
+ support.shrinkWrapBlocks = function() {
+ var body, container, div, containerStyles;
+
+ if ( shrinkWrapBlocksVal == null ) {
+ body = document.getElementsByTagName( "body" )[ 0 ];
+ if ( !body ) {
+ // Test fired too early or in an unsupported environment, exit.
+ return;
+ }
+
+ containerStyles = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px";
+ container = document.createElement( "div" );
+ div = document.createElement( "div" );
+
+ body.appendChild( container ).appendChild( div );
+
+ // Will be changed later if needed.
+ shrinkWrapBlocksVal = false;
+
+ if ( typeof div.style.zoom !== strundefined ) {
+ // Support: IE6
+ // Check if elements with layout shrink-wrap their children
+ div.style.cssText = divReset + ";width:1px;padding:1px;zoom:1";
+ div.innerHTML = "<div></div>";
+ div.firstChild.style.width = "5px";
+ shrinkWrapBlocksVal = div.offsetWidth !== 3;
+ }
+
+ body.removeChild( container );
+
+ // Null elements to avoid leaks in IE.
+ body = container = div = null;
+ }
+
+ return shrinkWrapBlocksVal;
+ };
+
+})();
+var rmargin = (/^margin/);
+
+var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
+
+
+
+var getStyles, curCSS,
+ rposition = /^(top|right|bottom|left)$/;
+
+if ( window.getComputedStyle ) {
+ getStyles = function( elem ) {
+ return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
+ };
+
+ curCSS = function( elem, name, computed ) {
+ var width, minWidth, maxWidth, ret,
+ style = elem.style;
+
+ computed = computed || getStyles( elem );
+
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+ ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;
+
+ if ( computed ) {
+
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
+ // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+ // Remember the original values
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ // Put in the new values to get a computed value out
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ // Revert the changed values
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ // Support: IE
+ // IE returns zIndex value as an integer.
+ return ret === undefined ?
+ ret :
+ ret + "";
+ };
+} else if ( document.documentElement.currentStyle ) {
+ getStyles = function( elem ) {
+ return elem.currentStyle;
+ };
+
+ curCSS = function( elem, name, computed ) {
+ var left, rs, rsLeft, ret,
+ style = elem.style;
+
+ computed = computed || getStyles( elem );
+ ret = computed ? computed[ name ] : undefined;
+
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret == null && style && style[ name ] ) {
+ ret = style[ name ];
+ }
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ // but not position css attributes, as those are proportional to the parent element instead
+ // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
+ if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+
+ // Remember the original values
+ left = style.left;
+ rs = elem.runtimeStyle;
+ rsLeft = rs && rs.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ rs.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : ret;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ rs.left = rsLeft;
+ }
+ }
+
+ // Support: IE
+ // IE returns zIndex value as an integer.
+ return ret === undefined ?
+ ret :
+ ret + "" || "auto";
+ };
+}
+
+
+
+
+function addGetHookIf( conditionFn, hookFn ) {
+ // Define the hook, we'll check on the first run if it's really needed.
+ return {
+ get: function() {
+ var condition = conditionFn();
+
+ if ( condition == null ) {
+ // The test was not ready at this point; screw the hook this time
+ // but check again when needed next time.
+ return;
+ }
+
+ if ( condition ) {
+ // Hook not needed (or it's not possible to use it due to missing dependency),
+ // remove it.
+ // Since there are no other hooks for marginRight, remove the whole object.
+ delete this.get;
+ return;
+ }
+
+ // Hook needed; redefine it so that the support test is not executed again.
+
+ return (this.get = hookFn).apply( this, arguments );
+ }
+ };
+}
+
+
+(function() {
+ var a, reliableHiddenOffsetsVal, boxSizingVal, boxSizingReliableVal,
+ pixelPositionVal, reliableMarginRightVal,
+ div = document.createElement( "div" ),
+ containerStyles = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px",
+ divReset =
+ "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;" +
+ "display:block;padding:0;margin:0;border:0";
+
+ // Setup
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+ a = div.getElementsByTagName( "a" )[ 0 ];
+
+ a.style.cssText = "float:left;opacity:.5";
+
+ // Make sure that element opacity exists
+ // (IE uses filter instead)
+ // Use a regex to work around a WebKit issue. See #5145
+ support.opacity = /^0.5/.test( a.style.opacity );
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ support.cssFloat = !!a.style.cssFloat;
+
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ // Null elements to avoid leaks in IE.
+ a = div = null;
+
+ jQuery.extend(support, {
+ reliableHiddenOffsets: function() {
+ if ( reliableHiddenOffsetsVal != null ) {
+ return reliableHiddenOffsetsVal;
+ }
+
+ var container, tds, isSupported,
+ div = document.createElement( "div" ),
+ body = document.getElementsByTagName( "body" )[ 0 ];
+
+ if ( !body ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ // Setup
+ div.setAttribute( "className", "t" );
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+
+ container = document.createElement( "div" );
+ container.style.cssText = containerStyles;
+
+ body.appendChild( container ).appendChild( div );
+
+ // Support: IE8
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
+ tds = div.getElementsByTagName( "td" );
+ tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+ tds[ 0 ].style.display = "";
+ tds[ 1 ].style.display = "none";
+
+ // Support: IE8
+ // Check if empty table cells still have offsetWidth/Height
+ reliableHiddenOffsetsVal = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+
+ body.removeChild( container );
+
+ // Null elements to avoid leaks in IE.
+ div = body = null;
+
+ return reliableHiddenOffsetsVal;
+ },
+
+ boxSizing: function() {
+ if ( boxSizingVal == null ) {
+ computeStyleTests();
+ }
+ return boxSizingVal;
+ },
+
+ boxSizingReliable: function() {
+ if ( boxSizingReliableVal == null ) {
+ computeStyleTests();
+ }
+ return boxSizingReliableVal;
+ },
+
+ pixelPosition: function() {
+ if ( pixelPositionVal == null ) {
+ computeStyleTests();
+ }
+ return pixelPositionVal;
+ },
+
+ reliableMarginRight: function() {
+ var body, container, div, marginDiv;
+
+ // Use window.getComputedStyle because jsdom on node.js will break without it.
+ if ( reliableMarginRightVal == null && window.getComputedStyle ) {
+ body = document.getElementsByTagName( "body" )[ 0 ];
+ if ( !body ) {
+ // Test fired too early or in an unsupported environment, exit.
+ return;
+ }
+
+ container = document.createElement( "div" );
+ div = document.createElement( "div" );
+ container.style.cssText = containerStyles;
+
+ body.appendChild( container ).appendChild( div );
+
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. (#3333)
+ // Fails in WebKit before Feb 2011 nightlies
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ marginDiv = div.appendChild( document.createElement( "div" ) );
+ marginDiv.style.cssText = div.style.cssText = divReset;
+ marginDiv.style.marginRight = marginDiv.style.width = "0";
+ div.style.width = "1px";
+
+ reliableMarginRightVal =
+ !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
+
+ body.removeChild( container );
+ }
+
+ return reliableMarginRightVal;
+ }
+ });
+
+ function computeStyleTests() {
+ var container, div,
+ body = document.getElementsByTagName( "body" )[ 0 ];
+
+ if ( !body ) {
+ // Test fired too early or in an unsupported environment, exit.
+ return;
+ }
+
+ container = document.createElement( "div" );
+ div = document.createElement( "div" );
+ container.style.cssText = containerStyles;
+
+ body.appendChild( container ).appendChild( div );
+
+ div.style.cssText =
+ "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;" +
+ "position:absolute;display:block;padding:1px;border:1px;width:4px;" +
+ "margin-top:1%;top:1%";
+
+ // Workaround failing boxSizing test due to offsetWidth returning wrong value
+ // with some non-1 values of body zoom, ticket #13543
+ jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() {
+ boxSizingVal = div.offsetWidth === 4;
+ });
+
+ // Will be changed later if needed.
+ boxSizingReliableVal = true;
+ pixelPositionVal = false;
+ reliableMarginRightVal = true;
+
+ // Use window.getComputedStyle because jsdom on node.js will break without it.
+ if ( window.getComputedStyle ) {
+ pixelPositionVal = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+ boxSizingReliableVal =
+ ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+ }
+
+ body.removeChild( container );
+
+ // Null elements to avoid leaks in IE.
+ div = body = null;
+ }
+
+})();
+
+
+// A method for quickly swapping in/out CSS properties to get correct calculations.
+jQuery.swap = function( elem, options, callback, args ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.apply( elem, args || [] );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+};
+
+
+var
+ ralpha = /alpha\([^)]*\)/i,
+ ropacity = /opacity\s*=\s*([^)]*)/,
+
+ // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+ // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
+ rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: 0,
+ fontWeight: 400
+ },
+
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+ // shortcut for names that are not vendor prefixed
+ if ( name in style ) {
+ return name;
+ }
+
+ // check for vendor prefixed names
+ var capName = name.charAt(0).toUpperCase() + name.slice(1),
+ origName = name,
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in style ) {
+ return name;
+ }
+ }
+
+ return origName;
+}
+
+function showHide( elements, show ) {
+ var display, elem, hidden,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+
+ values[ index ] = jQuery._data( elem, "olddisplay" );
+ display = elem.style.display;
+ if ( show ) {
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !values[ index ] && display === "none" ) {
+ elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( elem.style.display === "" && isHidden( elem ) ) {
+ values[ index ] = jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
+ }
+ } else {
+
+ if ( !values[ index ] ) {
+ hidden = isHidden( elem );
+
+ if ( display && display !== "none" || !hidden ) {
+ jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
+ }
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( index = 0; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+ elem.style.display = show ? values[ index ] || "" : "none";
+ }
+ }
+
+ return elements;
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+ var matches = rnumsplit.exec( value );
+ return matches ?
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
+ Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+ value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+ var i = extra === ( isBorderBox ? "border" : "content" ) ?
+ // If we already have the right measurement, avoid augmentation
+ 4 :
+ // Otherwise initialize for horizontal or vertical properties
+ name === "width" ? 1 : 0,
+
+ val = 0;
+
+ for ( ; i < 4; i += 2 ) {
+ // both box models exclude margin, so add it if we want it
+ if ( extra === "margin" ) {
+ val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+ }
+
+ if ( isBorderBox ) {
+ // border-box includes padding, so remove it if we want content
+ if ( extra === "content" ) {
+ val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ }
+
+ // at this point, extra isn't border nor margin, so remove border
+ if ( extra !== "margin" ) {
+ val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ } else {
+ // at this point, extra isn't content, so add padding
+ val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+ // at this point, extra isn't content nor padding, so add border
+ if ( extra !== "padding" ) {
+ val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ }
+ }
+
+ return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property, which is equivalent to the border-box value
+ var valueIsBorderBox = true,
+ val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ styles = getStyles( elem ),
+ isBorderBox = support.boxSizing() && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+ // some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+ if ( val <= 0 || val == null ) {
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name, styles );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // we need the check for style in case a browser which returns unreliable values
+ // for getComputedStyle silently falls back to the reliable elem.style
+ valueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] );
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+ }
+
+ // use the active box-sizing model to add/subtract irrelevant styles
+ return ( val +
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox,
+ styles
+ )
+ ) + "px";
+}
+
+jQuery.extend({
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+ }
+ }
+ }
+ },
+
+ // Don't automatically add "px" to these possibly-unitless properties
+ cssNumber: {
+ "columnCount": true,
+ "fillOpacity": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "order": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": support.cssFloat ? "cssFloat" : "styleFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, hooks,
+ origName = jQuery.camelCase( name ),
+ style = elem.style;
+
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // convert relative number strings (+= or -=) to relative numbers. #7345
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that null and NaN values aren't set. See: #7116
+ if ( value == null || value !== value ) {
+ return;
+ }
+
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
+ // but it would mean to define eight (for every problematic property) identical functions
+ if ( !support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
+ style[ name ] = "inherit";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+
+ // Support: IE
+ // Swallow errors from 'invalid' CSS values (#5509)
+ try {
+ // Support: Chrome, Safari
+ // Setting style to blank string required to delete "style: x !important;"
+ style[ name ] = "";
+ style[ name ] = value;
+ } catch(e) {}
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra, styles ) {
+ var num, val, hooks,
+ origName = jQuery.camelCase( name );
+
+ // Make sure that we're working with the right name
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
+
+ // Otherwise, if a way to get the computed value exists, use that
+ if ( val === undefined ) {
+ val = curCSS( elem, name, styles );
+ }
+
+ //convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Return, converting to number if forced or a qualifier was provided and val looks numeric
+ if ( extra === "" || extra ) {
+ num = parseFloat( val );
+ return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+ }
+ return val;
+ }
+});
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+ // certain elements can have dimension info if we invisibly show them
+ // however, it must have a current display style that would benefit from this
+ return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
+ jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ }) :
+ getWidthOrHeight( elem, name, extra );
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ var styles = extra && getStyles( elem );
+ return setPositiveNumber( elem, value, extra ?
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra,
+ support.boxSizing() && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ styles
+ ) : 0
+ );
+ }
+ };
+});
+
+if ( !support.opacity ) {
+ jQuery.cssHooks.opacity = {
+ get: function( elem, computed ) {
+ // IE uses filters for opacity
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+ ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
+ computed ? "1" : "";
+ },
+
+ set: function( elem, value ) {
+ var style = elem.style,
+ currentStyle = elem.currentStyle,
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+ filter = currentStyle && currentStyle.filter || style.filter || "";
+
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
+
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+ // if value === "", then remove inline opacity #12685
+ if ( ( value >= 1 || value === "" ) &&
+ jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
+ style.removeAttribute ) {
+
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
+ // style.removeAttribute is IE Only, but so apparently is this code path...
+ style.removeAttribute( "filter" );
+
+ // if there is no filter style applied in a css rule or unset inline opacity, we are done
+ if ( value === "" || currentStyle && !currentStyle.filter ) {
+ return;
+ }
+ }
+
+ // otherwise, set new filter values
+ style.filter = ralpha.test( filter ) ?
+ filter.replace( ralpha, opacity ) :
+ filter + " " + opacity;
+ }
+ };
+}
+
+jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
+ function( elem, computed ) {
+ if ( computed ) {
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ return jQuery.swap( elem, { "display": "inline-block" },
+ curCSS, [ elem, "marginRight" ] );
+ }
+ }
+);
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i = 0,
+ expanded = {},
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+ for ( ; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( !rmargin.test( prefix ) ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+});
+
+jQuery.fn.extend({
+ css: function( name, value ) {
+ return access( this, function( elem, name, value ) {
+ var styles, len,
+ map = {},
+ i = 0;
+
+ if ( jQuery.isArray( name ) ) {
+ styles = getStyles( elem );
+ len = name.length;
+
+ for ( ; i < len; i++ ) {
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+ }
+
+ return map;
+ }
+
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ },
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state ) {
+ if ( typeof state === "boolean" ) {
+ return state ? this.show() : this.hide();
+ }
+
+ return this.each(function() {
+ if ( isHidden( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ });
+ }
+});
+
+
+function Tween( elem, options, prop, end, easing ) {
+ return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+ constructor: Tween,
+ init: function( elem, options, prop, end, easing, unit ) {
+ this.elem = elem;
+ this.prop = prop;
+ this.easing = easing || "swing";
+ this.options = options;
+ this.start = this.now = this.cur();
+ this.end = end;
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+ },
+ cur: function() {
+ var hooks = Tween.propHooks[ this.prop ];
+
+ return hooks && hooks.get ?
+ hooks.get( this ) :
+ Tween.propHooks._default.get( this );
+ },
+ run: function( percent ) {
+ var eased,
+ hooks = Tween.propHooks[ this.prop ];
+
+ if ( this.options.duration ) {
+ this.pos = eased = jQuery.easing[ this.easing ](
+ percent, this.options.duration * percent, 0, 1, this.options.duration
+ );
+ } else {
+ this.pos = eased = percent;
+ }
+ this.now = ( this.end - this.start ) * eased + this.start;
+
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ if ( hooks && hooks.set ) {
+ hooks.set( this );
+ } else {
+ Tween.propHooks._default.set( this );
+ }
+ return this;
+ }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+ _default: {
+ get: function( tween ) {
+ var result;
+
+ if ( tween.elem[ tween.prop ] != null &&
+ (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+ return tween.elem[ tween.prop ];
+ }
+
+ // passing an empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails
+ // so, simple values such as "10px" are parsed to Float.
+ // complex values such as "rotate(1rad)" are returned as is.
+ result = jQuery.css( tween.elem, tween.prop, "" );
+ // Empty strings, null, undefined and "auto" are converted to 0.
+ return !result || result === "auto" ? 0 : result;
+ },
+ set: function( tween ) {
+ // use step hook for back compat - use cssHook if its there - use .style if its
+ // available and use plain properties where available
+ if ( jQuery.fx.step[ tween.prop ] ) {
+ jQuery.fx.step[ tween.prop ]( tween );
+ } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+ } else {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+ }
+};
+
+// Support: IE <=9
+// Panic based approach to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+ set: function( tween ) {
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+};
+
+jQuery.easing = {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return 0.5 - Math.cos( p * Math.PI ) / 2;
+ }
+};
+
+jQuery.fx = Tween.prototype.init;
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+
+
+
+var
+ fxNow, timerId,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
+ rrun = /queueHooks$/,
+ animationPrefilters = [ defaultPrefilter ],
+ tweeners = {
+ "*": [ function( prop, value ) {
+ var tween = this.createTween( prop, value ),
+ target = tween.cur(),
+ parts = rfxnum.exec( value ),
+ unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
+ rfxnum.exec( jQuery.css( tween.elem, prop ) ),
+ scale = 1,
+ maxIterations = 20;
+
+ if ( start && start[ 3 ] !== unit ) {
+ // Trust units reported by jQuery.css
+ unit = unit || start[ 3 ];
+
+ // Make sure we update the tween properties later on
+ parts = parts || [];
+
+ // Iteratively approximate from a nonzero starting point
+ start = +target || 1;
+
+ do {
+ // If previous iteration zeroed out, double until we get *something*
+ // Use a string for doubling factor so we don't accidentally see scale as unchanged below
+ scale = scale || ".5";
+
+ // Adjust and apply
+ start = start / scale;
+ jQuery.style( tween.elem, prop, start + unit );
+
+ // Update scale, tolerating zero or NaN from tween.cur()
+ // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+ } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+ }
+
+ // Update tween properties
+ if ( parts ) {
+ start = tween.start = +start || +target || 0;
+ tween.unit = unit;
+ // If a +=/-= token was provided, we're doing a relative animation
+ tween.end = parts[ 1 ] ?
+ start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
+ +parts[ 2 ];
+ }
+
+ return tween;
+ } ]
+ };
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ setTimeout(function() {
+ fxNow = undefined;
+ });
+ return ( fxNow = jQuery.now() );
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+ var which,
+ attrs = { height: type },
+ i = 0;
+
+ // if we include width, step value is 1 to do all cssExpand values,
+ // if we don't include width, step value is 2 to skip over Left and Right
+ includeWidth = includeWidth ? 1 : 0;
+ for ( ; i < 4 ; i += 2 - includeWidth ) {
+ which = cssExpand[ i ];
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+ }
+
+ if ( includeWidth ) {
+ attrs.opacity = attrs.width = type;
+ }
+
+ return attrs;
+}
+
+function createTween( value, prop, animation ) {
+ var tween,
+ collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+ index = 0,
+ length = collection.length;
+ for ( ; index < length; index++ ) {
+ if ( (tween = collection[ index ].call( animation, prop, value )) ) {
+
+ // we're done with this property
+ return tween;
+ }
+ }
+}
+
+function defaultPrefilter( elem, props, opts ) {
+ /* jshint validthis: true */
+ var prop, value, toggle, tween, hooks, oldfire, display, dDisplay,
+ anim = this,
+ orig = {},
+ style = elem.style,
+ hidden = elem.nodeType && isHidden( elem ),
+ dataShow = jQuery._data( elem, "fxshow" );
+
+ // handle queue: false promises
+ if ( !opts.queue ) {
+ hooks = jQuery._queueHooks( elem, "fx" );
+ if ( hooks.unqueued == null ) {
+ hooks.unqueued = 0;
+ oldfire = hooks.empty.fire;
+ hooks.empty.fire = function() {
+ if ( !hooks.unqueued ) {
+ oldfire();
+ }
+ };
+ }
+ hooks.unqueued++;
+
+ anim.always(function() {
+ // doing this makes sure that the complete handler will be called
+ // before this completes
+ anim.always(function() {
+ hooks.unqueued--;
+ if ( !jQuery.queue( elem, "fx" ).length ) {
+ hooks.empty.fire();
+ }
+ });
+ });
+ }
+
+ // height/width overflow pass
+ if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+ // Make sure that nothing sneaks out
+ // Record all 3 overflow attributes because IE does not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height animated
+ display = jQuery.css( elem, "display" );
+ dDisplay = defaultDisplay( elem.nodeName );
+ if ( display === "none" ) {
+ display = dDisplay;
+ }
+ if ( display === "inline" &&
+ jQuery.css( elem, "float" ) === "none" ) {
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( !support.inlineBlockNeedsLayout || dDisplay === "inline" ) {
+ style.display = "inline-block";
+ } else {
+ style.zoom = 1;
+ }
+ }
+ }
+
+ if ( opts.overflow ) {
+ style.overflow = "hidden";
+ if ( !support.shrinkWrapBlocks() ) {
+ anim.always(function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ });
+ }
+ }
+
+ // show/hide pass
+ for ( prop in props ) {
+ value = props[ prop ];
+ if ( rfxtypes.exec( value ) ) {
+ delete props[ prop ];
+ toggle = toggle || value === "toggle";
+ if ( value === ( hidden ? "hide" : "show" ) ) {
+
+ // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
+ if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+ hidden = true;
+ } else {
+ continue;
+ }
+ }
+ orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+ }
+ }
+
+ if ( !jQuery.isEmptyObject( orig ) ) {
+ if ( dataShow ) {
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+ } else {
+ dataShow = jQuery._data( elem, "fxshow", {} );
+ }
+
+ // store state if its toggle - enables .stop().toggle() to "reverse"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
+ if ( hidden ) {
+ jQuery( elem ).show();
+ } else {
+ anim.done(function() {
+ jQuery( elem ).hide();
+ });
+ }
+ anim.done(function() {
+ var prop;
+ jQuery._removeData( elem, "fxshow" );
+ for ( prop in orig ) {
+ jQuery.style( elem, prop, orig[ prop ] );
+ }
+ });
+ for ( prop in orig ) {
+ tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+
+ if ( !( prop in dataShow ) ) {
+ dataShow[ prop ] = tween.start;
+ if ( hidden ) {
+ tween.end = tween.start;
+ tween.start = prop === "width" || prop === "height" ? 1 : 0;
+ }
+ }
+ }
+ }
+}
+
+function propFilter( props, specialEasing ) {
+ var index, name, easing, value, hooks;
+
+ // camelCase, specialEasing and expand cssHook pass
+ for ( index in props ) {
+ name = jQuery.camelCase( index );
+ easing = specialEasing[ name ];
+ value = props[ index ];
+ if ( jQuery.isArray( value ) ) {
+ easing = value[ 1 ];
+ value = props[ index ] = value[ 0 ];
+ }
+
+ if ( index !== name ) {
+ props[ name ] = value;
+ delete props[ index ];
+ }
+
+ hooks = jQuery.cssHooks[ name ];
+ if ( hooks && "expand" in hooks ) {
+ value = hooks.expand( value );
+ delete props[ name ];
+
+ // not quite $.extend, this wont overwrite keys already present.
+ // also - reusing 'index' from above because we have the correct "name"
+ for ( index in value ) {
+ if ( !( index in props ) ) {
+ props[ index ] = value[ index ];
+ specialEasing[ index ] = easing;
+ }
+ }
+ } else {
+ specialEasing[ name ] = easing;
+ }
+ }
+}
+
+function Animation( elem, properties, options ) {
+ var result,
+ stopped,
+ index = 0,
+ length = animationPrefilters.length,
+ deferred = jQuery.Deferred().always( function() {
+ // don't match elem in the :animated selector
+ delete tick.elem;
+ }),
+ tick = function() {
+ if ( stopped ) {
+ return false;
+ }
+ var currentTime = fxNow || createFxNow(),
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+ // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+ temp = remaining / animation.duration || 0,
+ percent = 1 - temp,
+ index = 0,
+ length = animation.tweens.length;
+
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( percent );
+ }
+
+ deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+ if ( percent < 1 && length ) {
+ return remaining;
+ } else {
+ deferred.resolveWith( elem, [ animation ] );
+ return false;
+ }
+ },
+ animation = deferred.promise({
+ elem: elem,
+ props: jQuery.extend( {}, properties ),
+ opts: jQuery.extend( true, { specialEasing: {} }, options ),
+ originalProperties: properties,
+ originalOptions: options,
+ startTime: fxNow || createFxNow(),
+ duration: options.duration,
+ tweens: [],
+ createTween: function( prop, end ) {
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
+ animation.tweens.push( tween );
+ return tween;
+ },
+ stop: function( gotoEnd ) {
+ var index = 0,
+ // if we are going to the end, we want to run all the tweens
+ // otherwise we skip this part
+ length = gotoEnd ? animation.tweens.length : 0;
+ if ( stopped ) {
+ return this;
+ }
+ stopped = true;
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( 1 );
+ }
+
+ // resolve when we played the last frame
+ // otherwise, reject
+ if ( gotoEnd ) {
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
+ } else {
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
+ }
+ return this;
+ }
+ }),
+ props = animation.props;
+
+ propFilter( props, animation.opts.specialEasing );
+
+ for ( ; index < length ; index++ ) {
+ result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+ if ( result ) {
+ return result;
+ }
+ }
+
+ jQuery.map( props, createTween, animation );
+
+ if ( jQuery.isFunction( animation.opts.start ) ) {
+ animation.opts.start.call( elem, animation );
+ }
+
+ jQuery.fx.timer(
+ jQuery.extend( tick, {
+ elem: elem,
+ anim: animation,
+ queue: animation.opts.queue
+ })
+ );
+
+ // attach callbacks from options
+ return animation.progress( animation.opts.progress )
+ .done( animation.opts.done, animation.opts.complete )
+ .fail( animation.opts.fail )
+ .always( animation.opts.always );
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+ tweener: function( props, callback ) {
+ if ( jQuery.isFunction( props ) ) {
+ callback = props;
+ props = [ "*" ];
+ } else {
+ props = props.split(" ");
+ }
+
+ var prop,
+ index = 0,
+ length = props.length;
+
+ for ( ; index < length ; index++ ) {
+ prop = props[ index ];
+ tweeners[ prop ] = tweeners[ prop ] || [];
+ tweeners[ prop ].unshift( callback );
+ }
+ },
+
+ prefilter: function( callback, prepend ) {
+ if ( prepend ) {
+ animationPrefilters.unshift( callback );
+ } else {
+ animationPrefilters.push( callback );
+ }
+ }
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+ // normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function() {
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ }
+ };
+
+ return opt;
+};
+
+jQuery.fn.extend({
+ fadeTo: function( speed, to, easing, callback ) {
+
+ // show any hidden elements after setting opacity to 0
+ return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+ // animate to the value specified
+ .end().animate({ opacity: to }, speed, easing, callback );
+ },
+ animate: function( prop, speed, easing, callback ) {
+ var empty = jQuery.isEmptyObject( prop ),
+ optall = jQuery.speed( speed, easing, callback ),
+ doAnimation = function() {
+ // Operate on a copy of prop so per-property easing won't be lost
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+ // Empty animations, or finishing resolves immediately
+ if ( empty || jQuery._data( this, "finish" ) ) {
+ anim.stop( true );
+ }
+ };
+ doAnimation.finish = doAnimation;
+
+ return empty || optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+ stop: function( type, clearQueue, gotoEnd ) {
+ var stopQueue = function( hooks ) {
+ var stop = hooks.stop;
+ delete hooks.stop;
+ stop( gotoEnd );
+ };
+
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each(function() {
+ var dequeue = true,
+ index = type != null && type + "queueHooks",
+ timers = jQuery.timers,
+ data = jQuery._data( this );
+
+ if ( index ) {
+ if ( data[ index ] && data[ index ].stop ) {
+ stopQueue( data[ index ] );
+ }
+ } else {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+ stopQueue( data[ index ] );
+ }
+ }
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ timers[ index ].anim.stop( gotoEnd );
+ dequeue = false;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // start the next in the queue if the last step wasn't forced
+ // timers currently will call their complete callbacks, which will dequeue
+ // but only if they were gotoEnd
+ if ( dequeue || !gotoEnd ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ finish: function( type ) {
+ if ( type !== false ) {
+ type = type || "fx";
+ }
+ return this.each(function() {
+ var index,
+ data = jQuery._data( this ),
+ queue = data[ type + "queue" ],
+ hooks = data[ type + "queueHooks" ],
+ timers = jQuery.timers,
+ length = queue ? queue.length : 0;
+
+ // enable finishing flag on private data
+ data.finish = true;
+
+ // empty the queue first
+ jQuery.queue( this, type, [] );
+
+ if ( hooks && hooks.stop ) {
+ hooks.stop.call( this, true );
+ }
+
+ // look for any active animations, and finish them
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+ timers[ index ].anim.stop( true );
+ timers.splice( index, 1 );
+ }
+ }
+
+ // look for any animations in the old queue and finish them
+ for ( index = 0; index < length; index++ ) {
+ if ( queue[ index ] && queue[ index ].finish ) {
+ queue[ index ].finish.call( this );
+ }
+ }
+
+ // turn off finishing flag
+ delete data.finish;
+ });
+ }
+});
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+ var cssFn = jQuery.fn[ name ];
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return speed == null || typeof speed === "boolean" ?
+ cssFn.apply( this, arguments ) :
+ this.animate( genFx( name, true ), speed, easing, callback );
+ };
+});
+
+// Generate shortcuts for custom animations
+jQuery.each({
+ slideDown: genFx("show"),
+ slideUp: genFx("hide"),
+ slideToggle: genFx("toggle"),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+});
+
+jQuery.timers = [];
+jQuery.fx.tick = function() {
+ var timer,
+ timers = jQuery.timers,
+ i = 0;
+
+ fxNow = jQuery.now();
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+ jQuery.timers.push( timer );
+ if ( timer() ) {
+ jQuery.fx.start();
+ } else {
+ jQuery.timers.pop();
+ }
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+ if ( !timerId ) {
+ timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+ }
+};
+
+jQuery.fx.stop = function() {
+ clearInterval( timerId );
+ timerId = null;
+};
+
+jQuery.fx.speeds = {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+};
+
+
+// Based off of the plugin by Clint Helfers, with permission.
+// http://blindsignals.com/index.php/2009/07/jquery-delay/
+jQuery.fn.delay = function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+};
+
+
+(function() {
+ var a, input, select, opt,
+ div = document.createElement("div" );
+
+ // Setup
+ div.setAttribute( "className", "t" );
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+ a = div.getElementsByTagName("a")[ 0 ];
+
+ // First batch of tests.
+ select = document.createElement("select");
+ opt = select.appendChild( document.createElement("option") );
+ input = div.getElementsByTagName("input")[ 0 ];
+
+ a.style.cssText = "top:1px";
+
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+ support.getSetAttribute = div.className !== "t";
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText instead)
+ support.style = /top/.test( a.getAttribute("style") );
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ support.hrefNormalized = a.getAttribute("href") === "/a";
+
+ // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
+ support.checkOn = !!input.value;
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ support.optSelected = opt.selected;
+
+ // Tests for enctype support on a form (#6743)
+ support.enctype = !!document.createElement("form").enctype;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as disabled)
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Support: IE8 only
+ // Check if we can trust getAttribute("value")
+ input = document.createElement( "input" );
+ input.setAttribute( "value", "" );
+ support.input = input.getAttribute( "value" ) === "";
+
+ // Check if an input maintains its value after becoming a radio
+ input.value = "t";
+ input.setAttribute( "type", "radio" );
+ support.radioValue = input.value === "t";
+
+ // Null elements to avoid leaks in IE.
+ a = input = select = opt = div = null;
+})();
+
+
+var rreturn = /\r/g;
+
+jQuery.fn.extend({
+ val: function( value ) {
+ var hooks, ret, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // handle most common string cases
+ ret.replace(rreturn, "") :
+ // handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var val;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, jQuery( this ).val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map( val, function( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ var val = jQuery.find.attr( elem, "value" );
+ return val != null ?
+ val :
+ jQuery.text( elem );
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one" || index < 0,
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // oldIE doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+ // Don't return options that are disabled or in a disabled optgroup
+ ( support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var optionSet, option,
+ options = elem.options,
+ values = jQuery.makeArray( value ),
+ i = options.length;
+
+ while ( i-- ) {
+ option = options[ i ];
+
+ if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) >= 0 ) {
+
+ // Support: IE6
+ // When new option element is added to select box we need to
+ // force reflow of newly added node in order to workaround delay
+ // of initialization properties
+ try {
+ option.selected = optionSet = true;
+
+ } catch ( _ ) {
+
+ // Will be executed only in IE6
+ option.scrollHeight;
+ }
+
+ } else {
+ option.selected = false;
+ }
+ }
+
+ // Force browsers to behave consistently when non-matching value is set
+ if ( !optionSet ) {
+ elem.selectedIndex = -1;
+ }
+
+ return options;
+ }
+ }
+ }
+});
+
+// Radios and checkboxes getter/setter
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ };
+ if ( !support.checkOn ) {
+ jQuery.valHooks[ this ].get = function( elem ) {
+ // Support: Webkit
+ // "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ };
+ }
+});
+
+
+
+
+var nodeHook, boolHook,
+ attrHandle = jQuery.expr.attrHandle,
+ ruseDefault = /^(?:checked|selected)$/i,
+ getSetAttribute = support.getSetAttribute,
+ getSetInput = support.input;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ }
+});
+
+jQuery.extend({
+ attr: function( elem, name, value ) {
+ var hooks, ret,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === strundefined ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] ||
+ ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+
+ } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+ ret = jQuery.find.attr( elem, name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var name, propName,
+ i = 0,
+ attrNames = value && value.match( rnotwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( (name = attrNames[i++]) ) {
+ propName = jQuery.propFix[ name ] || name;
+
+ // Boolean attributes get special treatment (#10870)
+ if ( jQuery.expr.match.bool.test( name ) ) {
+ // Set corresponding property to false
+ if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ elem[ propName ] = false;
+ // Support: IE<9
+ // Also clear defaultChecked/defaultSelected (if appropriate)
+ } else {
+ elem[ jQuery.camelCase( "default-" + name ) ] =
+ elem[ propName ] = false;
+ }
+
+ // See #9699 for explanation of this approach (setting first, then removal)
+ } else {
+ jQuery.attr( elem, name, "" );
+ }
+
+ elem.removeAttribute( getSetAttribute ? name : propName );
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ if ( !support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ // Setting the type on a radio button after the value resets the value in IE6-9
+ // Reset value to default in case type is set after value during creation
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ }
+ }
+});
+
+// Hook for boolean attributes
+boolHook = {
+ set: function( elem, value, name ) {
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ // IE<8 needs the *property* name
+ elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
+
+ // Use defaultChecked and defaultSelected for oldIE
+ } else {
+ elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
+ }
+
+ return name;
+ }
+};
+
+// Retrieve booleans specially
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
+
+ var getter = attrHandle[ name ] || jQuery.find.attr;
+
+ attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
+ function( elem, name, isXML ) {
+ var ret, handle;
+ if ( !isXML ) {
+ // Avoid an infinite loop by temporarily removing this function from the getter
+ handle = attrHandle[ name ];
+ attrHandle[ name ] = ret;
+ ret = getter( elem, name, isXML ) != null ?
+ name.toLowerCase() :
+ null;
+ attrHandle[ name ] = handle;
+ }
+ return ret;
+ } :
+ function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem[ jQuery.camelCase( "default-" + name ) ] ?
+ name.toLowerCase() :
+ null;
+ }
+ };
+});
+
+// fix oldIE attroperties
+if ( !getSetInput || !getSetAttribute ) {
+ jQuery.attrHooks.value = {
+ set: function( elem, value, name ) {
+ if ( jQuery.nodeName( elem, "input" ) ) {
+ // Does not return so that setAttribute is also used
+ elem.defaultValue = value;
+ } else {
+ // Use nodeHook if defined (#1954); otherwise setAttribute is fine
+ return nodeHook && nodeHook.set( elem, value, name );
+ }
+ }
+ };
+}
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+ // Use this for any attribute in IE6/7
+ // This fixes almost every IE6/7 issue
+ nodeHook = {
+ set: function( elem, value, name ) {
+ // Set the existing or create a new attribute node
+ var ret = elem.getAttributeNode( name );
+ if ( !ret ) {
+ elem.setAttributeNode(
+ (ret = elem.ownerDocument.createAttribute( name ))
+ );
+ }
+
+ ret.value = value += "";
+
+ // Break association with cloned elements by also using setAttribute (#9646)
+ if ( name === "value" || value === elem.getAttribute( name ) ) {
+ return value;
+ }
+ }
+ };
+
+ // Some attributes are constructed with empty-string values when not defined
+ attrHandle.id = attrHandle.name = attrHandle.coords =
+ function( elem, name, isXML ) {
+ var ret;
+ if ( !isXML ) {
+ return (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
+ ret.value :
+ null;
+ }
+ };
+
+ // Fixing value retrieval on a button requires this module
+ jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret = elem.getAttributeNode( name );
+ if ( ret && ret.specified ) {
+ return ret.value;
+ }
+ },
+ set: nodeHook.set
+ };
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ set: function( elem, value, name ) {
+ nodeHook.set( elem, value === "" ? false : value, name );
+ }
+ };
+
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+ // This is for removals
+ jQuery.each([ "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = {
+ set: function( elem, value ) {
+ if ( value === "" ) {
+ elem.setAttribute( name, "auto" );
+ return value;
+ }
+ }
+ };
+ });
+}
+
+if ( !support.style ) {
+ jQuery.attrHooks.style = {
+ get: function( elem ) {
+ // Return undefined in the case of empty string
+ // Note: IE uppercases css property names, but if we were to .toLowerCase()
+ // .cssText, that would destroy case senstitivity in URL's, like in "background"
+ return elem.style.cssText || undefined;
+ },
+ set: function( elem, value ) {
+ return ( elem.style.cssText = value + "" );
+ }
+ };
+}
+
+
+
+
+var rfocusable = /^(?:input|select|textarea|button|object)$/i,
+ rclickable = /^(?:a|area)$/i;
+
+jQuery.fn.extend({
+ prop: function( name, value ) {
+ return access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ name = jQuery.propFix[ name ] || name;
+ return this.each(function() {
+ // try/catch handles cases where IE balks (such as removing a property on window)
+ try {
+ this[ name ] = undefined;
+ delete this[ name ];
+ } catch( e ) {}
+ });
+ }
+});
+
+jQuery.extend({
+ propFix: {
+ "for": "htmlFor",
+ "class": "className"
+ },
+
+ prop: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
+ ret :
+ ( elem[ name ] = value );
+
+ } else {
+ return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
+ ret :
+ elem[ name ];
+ }
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ // Use proper attribute retrieval(#12072)
+ var tabindex = jQuery.find.attr( elem, "tabindex" );
+
+ return tabindex ?
+ parseInt( tabindex, 10 ) :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ -1;
+ }
+ }
+ }
+});
+
+// Some attributes require a special call on IE
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !support.hrefNormalized ) {
+ // href/src property should get the full normalized URL (#10299/#12915)
+ jQuery.each([ "href", "src" ], function( i, name ) {
+ jQuery.propHooks[ name ] = {
+ get: function( elem ) {
+ return elem.getAttribute( name, 4 );
+ }
+ };
+ });
+}
+
+// Support: Safari, IE9+
+// mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !support.optSelected ) {
+ jQuery.propHooks.selected = {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ return null;
+ }
+ };
+}
+
+jQuery.each([
+ "tabIndex",
+ "readOnly",
+ "maxLength",
+ "cellSpacing",
+ "cellPadding",
+ "rowSpan",
+ "colSpan",
+ "useMap",
+ "frameBorder",
+ "contentEditable"
+], function() {
+ jQuery.propFix[ this.toLowerCase() ] = this;
+});
+
+// IE6/7 call enctype encoding
+if ( !support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
+}
+
+
+
+
+var rclass = /[\t\r\n\f]/g;
+
+jQuery.fn.extend({
+ addClass: function( value ) {
+ var classes, elem, cur, clazz, j, finalValue,
+ i = 0,
+ len = this.length,
+ proceed = typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call( this, j, this.className ) );
+ });
+ }
+
+ if ( proceed ) {
+ // The disjunction here is for better compressibility (see removeClass)
+ classes = ( value || "" ).match( rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ " "
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
+ }
+ }
+
+ // only assign if different to avoid unneeded rendering.
+ finalValue = jQuery.trim( cur );
+ if ( elem.className !== finalValue ) {
+ elem.className = finalValue;
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classes, elem, cur, clazz, j, finalValue,
+ i = 0,
+ len = this.length,
+ proceed = arguments.length === 0 || typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, this.className ) );
+ });
+ }
+ if ( proceed ) {
+ classes = ( value || "" ).match( rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ ""
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
+ }
+ }
+
+ // only assign if different to avoid unneeded rendering.
+ finalValue = value ? jQuery.trim( cur ) : "";
+ if ( elem.className !== finalValue ) {
+ elem.className = finalValue;
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value;
+
+ if ( typeof stateVal === "boolean" && type === "string" ) {
+ return stateVal ? this.addClass( value ) : this.removeClass( value );
+ }
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ classNames = value.match( rnotwhite ) || [];
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space separated list
+ if ( self.hasClass( className ) ) {
+ self.removeClass( className );
+ } else {
+ self.addClass( className );
+ }
+ }
+
+ // Toggle whole class name
+ } else if ( type === strundefined || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery._data( this, "__className__", this.className );
+ }
+
+ // If the element has a class name or if we're passed "false",
+ // then remove the whole classname (if there was one, the above saved it).
+ // Otherwise bring back whatever was previously saved (if anything),
+ // falling back to the empty string if nothing was stored.
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+});
+
+
+
+
+// Return jQuery for attributes-only inclusion
+
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+});
+
+jQuery.fn.extend({
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+ }
+});
+
+
+var nonce = jQuery.now();
+
+var rquery = (/\?/);
+
+
+
+var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;
+
+jQuery.parseJSON = function( data ) {
+ // Attempt to parse using the native JSON parser first
+ if ( window.JSON && window.JSON.parse ) {
+ // Support: Android 2.3
+ // Workaround failure to string-cast null input
+ return window.JSON.parse( data + "" );
+ }
+
+ var requireNonComma,
+ depth = null,
+ str = jQuery.trim( data + "" );
+
+ // Guard against invalid (and possibly dangerous) input by ensuring that nothing remains
+ // after removing valid tokens
+ return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) {
+
+ // Force termination if we see a misplaced comma
+ if ( requireNonComma && comma ) {
+ depth = 0;
+ }
+
+ // Perform no more replacements after returning to outermost depth
+ if ( depth === 0 ) {
+ return token;
+ }
+
+ // Commas must not follow "[", "{", or ","
+ requireNonComma = open || comma;
+
+ // Determine new depth
+ // array/object open ("[" or "{"): depth += true - false (increment)
+ // array/object close ("]" or "}"): depth += false - true (decrement)
+ // other cases ("," or primitive): depth += true - true (numeric cast)
+ depth += !close - !open;
+
+ // Remove this token
+ return "";
+ }) ) ?
+ ( Function( "return " + str ) )() :
+ jQuery.error( "Invalid JSON: " + data );
+};
+
+
+// Cross-browser xml parsing
+jQuery.parseXML = function( data ) {
+ var xml, tmp;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ try {
+ if ( window.DOMParser ) { // Standard
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data, "text/xml" );
+ } else { // IE
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
+ xml.async = "false";
+ xml.loadXML( data );
+ }
+ } catch( e ) {
+ xml = undefined;
+ }
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+};
+
+
+var
+ // Document location
+ ajaxLocParts,
+ ajaxLocation,
+
+ rhash = /#.*$/,
+ rts = /([?&])_=[^&]*/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = "*/".concat("*");
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+ ajaxLocation = location.href;
+} catch( e ) {
+ // Use the href attribute of an A element
+ // since IE will modify it given document.location
+ ajaxLocation = document.createElement( "a" );
+ ajaxLocation.href = "";
+ ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ var dataType,
+ i = 0,
+ dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
+
+ if ( jQuery.isFunction( func ) ) {
+ // For each dataType in the dataTypeExpression
+ while ( (dataType = dataTypes[i++]) ) {
+ // Prepend if requested
+ if ( dataType.charAt( 0 ) === "+" ) {
+ dataType = dataType.slice( 1 ) || "*";
+ (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+ // Otherwise append
+ } else {
+ (structure[ dataType ] = structure[ dataType ] || []).push( func );
+ }
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+ var inspected = {},
+ seekingTransport = ( structure === transports );
+
+ function inspect( dataType ) {
+ var selected;
+ inspected[ dataType ] = true;
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+ if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+ options.dataTypes.unshift( dataTypeOrTransport );
+ inspect( dataTypeOrTransport );
+ return false;
+ } else if ( seekingTransport ) {
+ return !( selected = dataTypeOrTransport );
+ }
+ });
+ return selected;
+ }
+
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var deep, key,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+
+ return target;
+}
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+ var firstDataType, ct, finalDataType, type,
+ contents = s.contents,
+ dataTypes = s.dataTypes;
+
+ // Remove auto dataType and get content-type in the process
+ while ( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+ var conv2, current, conv, tmp, prev,
+ converters = {},
+ // Work with a copy of dataTypes in case we need to modify it for conversion
+ dataTypes = s.dataTypes.slice();
+
+ // Create converters map with lowercased keys
+ if ( dataTypes[ 1 ] ) {
+ for ( conv in s.converters ) {
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
+ }
+ }
+
+ current = dataTypes.shift();
+
+ // Convert to each sequential dataType
+ while ( current ) {
+
+ if ( s.responseFields[ current ] ) {
+ jqXHR[ s.responseFields[ current ] ] = response;
+ }
+
+ // Apply the dataFilter if provided
+ if ( !prev && isSuccess && s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ prev = current;
+ current = dataTypes.shift();
+
+ if ( current ) {
+
+ // There's only work to do if current dataType is non-auto
+ if ( current === "*" ) {
+
+ current = prev;
+
+ // Convert response if prev dataType is non-auto and differs from current
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Seek a direct converter
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+ // If none found, seek a pair
+ if ( !conv ) {
+ for ( conv2 in converters ) {
+
+ // If conv2 outputs current
+ tmp = conv2.split( " " );
+ if ( tmp[ 1 ] === current ) {
+
+ // If prev can be converted to accepted input
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
+ converters[ "* " + tmp[ 0 ] ];
+ if ( conv ) {
+ // Condense equivalence converters
+ if ( conv === true ) {
+ conv = converters[ conv2 ];
+
+ // Otherwise, insert the intermediate dataType
+ } else if ( converters[ conv2 ] !== true ) {
+ current = tmp[ 0 ];
+ dataTypes.unshift( tmp[ 1 ] );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Apply converter (if not an equivalence)
+ if ( conv !== true ) {
+
+ // Unless errors are allowed to bubble, catch and return them
+ if ( conv && s[ "throws" ] ) {
+ response = conv( response );
+ } else {
+ try {
+ response = conv( response );
+ } catch ( e ) {
+ return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return { state: "success", data: response };
+}
+
+jQuery.extend({
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
+
+ ajaxSettings: {
+ url: ajaxLocation,
+ type: "GET",
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+ global: true,
+ processData: true,
+ async: true,
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ throws: false,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ "*": allTypes,
+ text: "text/plain",
+ html: "text/html",
+ xml: "application/xml, text/xml",
+ json: "application/json, text/javascript"
+ },
+
+ contents: {
+ xml: /xml/,
+ html: /html/,
+ json: /json/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText",
+ json: "responseJSON"
+ },
+
+ // Data converters
+ // Keys separate source (or catchall "*") and destination types with a single space
+ converters: {
+
+ // Convert anything to text
+ "* text": String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": jQuery.parseJSON,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ url: true,
+ context: true
+ }
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ return settings ?
+
+ // Building a settings object
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+ // Extending ajaxSettings
+ ajaxExtend( jQuery.ajaxSettings, target );
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var // Cross-domain detection vars
+ parts,
+ // Loop variable
+ i,
+ // URL without anti-cache param
+ cacheURL,
+ // Response headers as string
+ responseHeadersString,
+ // timeout handle
+ timeoutTimer,
+
+ // To know if global events are to be dispatched
+ fireGlobals,
+
+ transport,
+ // Response headers
+ responseHeaders,
+ // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+ // Callbacks context
+ callbackContext = s.context || s,
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
+ globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+ jQuery( callbackContext ) :
+ jQuery.event,
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks("once memory"),
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+ // The jqXHR state
+ state = 0,
+ // Default abort message
+ strAbort = "canceled",
+ // Fake xhr
+ jqXHR = {
+ readyState: 0,
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( state === 2 ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while ( (match = rheaders.exec( responseHeadersString )) ) {
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() ];
+ }
+ return match == null ? null : match;
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return state === 2 ? responseHeadersString : null;
+ },
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ var lname = name.toLowerCase();
+ if ( !state ) {
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( !state ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Status-dependent callbacks
+ statusCode: function( map ) {
+ var code;
+ if ( map ) {
+ if ( state < 2 ) {
+ for ( code in map ) {
+ // Lazy-add the new callback in a way that preserves old ones
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+ }
+ } else {
+ // Execute the appropriate callbacks
+ jqXHR.always( map[ jqXHR.status ] );
+ }
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ var finalText = statusText || strAbort;
+ if ( transport ) {
+ transport.abort( finalText );
+ }
+ done( 0, finalText );
+ return this;
+ }
+ };
+
+ // Attach deferreds
+ deferred.promise( jqXHR ).complete = completeDeferred.add;
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+
+ // Remove hash character (#7531: and string promotion)
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+ // Alias method option to type as per ticket #12004
+ s.type = options.method || options.type || s.method || s.type;
+
+ // Extract dataTypes list
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
+
+ // A cross-domain request is in order when we have a protocol:host:port mismatch
+ if ( s.crossDomain == null ) {
+ parts = rurl.exec( s.url.toLowerCase() );
+ s.crossDomain = !!( parts &&
+ ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
+ );
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( state === 2 ) {
+ return jqXHR;
+ }
+
+ // We can fire global events as of now if asked to
+ fireGlobals = s.global;
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger("ajaxStart");
+ }
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Save the URL in case we're toying with the If-Modified-Since
+ // and/or If-None-Match header later on
+ cacheURL = s.url;
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // If data is available, append data to url
+ if ( s.data ) {
+ cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
+ s.url = rts.test( cacheURL ) ?
+
+ // If there is already a '_' parameter, set its value
+ cacheURL.replace( rts, "$1_=" + nonce++ ) :
+
+ // Otherwise add one to the end
+ cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
+ }
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery.lastModified[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+ }
+ if ( jQuery.etag[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ // Abort if not done already and return
+ return jqXHR.abort();
+ }
+
+ // aborting is no longer a cancellation
+ strAbort = "abort";
+
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout(function() {
+ jqXHR.abort("timeout");
+ }, s.timeout );
+ }
+
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch ( e ) {
+ // Propagate exception as error if not done
+ if ( state < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ // Callback for when everything is done
+ function done( status, nativeStatusText, responses, headers ) {
+ var isSuccess, success, error, response, modified,
+ statusText = nativeStatusText;
+
+ // Called once
+ if ( state === 2 ) {
+ return;
+ }
+
+ // State is "done" now
+ state = 2;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ // Determine if successful
+ isSuccess = status >= 200 && status < 300 || status === 304;
+
+ // Get response data
+ if ( responses ) {
+ response = ajaxHandleResponses( s, jqXHR, responses );
+ }
+
+ // Convert no matter what (that way responseXXX fields are always set)
+ response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+ // If successful, handle type chaining
+ if ( isSuccess ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ modified = jqXHR.getResponseHeader("Last-Modified");
+ if ( modified ) {
+ jQuery.lastModified[ cacheURL ] = modified;
+ }
+ modified = jqXHR.getResponseHeader("etag");
+ if ( modified ) {
+ jQuery.etag[ cacheURL ] = modified;
+ }
+ }
+
+ // if no content
+ if ( status === 204 || s.type === "HEAD" ) {
+ statusText = "nocontent";
+
+ // if not modified
+ } else if ( status === 304 ) {
+ statusText = "notmodified";
+
+ // If we have data, let's convert it
+ } else {
+ statusText = response.state;
+ success = response.data;
+ error = response.error;
+ isSuccess = !error;
+ }
+ } else {
+ // We extract error from statusText
+ // then normalize statusText and status for non-aborts
+ error = statusText;
+ if ( status || !statusText ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger("ajaxStop");
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ }
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+ // shift arguments if data argument was omitted
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ return jQuery.ajax({
+ url: url,
+ type: method,
+ dataType: type,
+ data: data,
+ success: callback
+ });
+ };
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
+ jQuery.fn[ type ] = function( fn ) {
+ return this.on( type, fn );
+ };
+});
+
+
+jQuery._evalUrl = function( url ) {
+ return jQuery.ajax({
+ url: url,
+ type: "GET",
+ dataType: "script",
+ async: false,
+ global: false,
+ "throws": true
+ });
+};
+
+
+jQuery.fn.extend({
+ wrapAll: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[0] ) {
+ // The elements to wrap the target around
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+ if ( this[0].parentNode ) {
+ wrap.insertBefore( this[0] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+ elem = elem.firstChild;
+ }
+
+ return elem;
+ }).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function(i) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ }
+});
+
+
+jQuery.expr.filters.hidden = function( elem ) {
+ // Support: Opera <= 12.12
+ // Opera reports offsetWidths and offsetHeights less than zero on some elements
+ return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
+ (!support.reliableHiddenOffsets() &&
+ ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+};
+
+jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+};
+
+
+
+
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // Item is non-scalar (array or object), encode its numeric index.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+
+// Serialize an array of form elements or a set of
+// key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+};
+
+jQuery.fn.extend({
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map(function() {
+ // Can add propHook for "elements" to filter or add form elements
+ var elements = jQuery.prop( this, "elements" );
+ return elements ? jQuery.makeArray( elements ) : this;
+ })
+ .filter(function() {
+ var type = this.type;
+ // Use .is(":disabled") so that fieldset[disabled] works
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+ ( this.checked || !rcheckableType.test( type ) );
+ })
+ .map(function( i, elem ) {
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val ) {
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ?
+ // Support: IE6+
+ function() {
+
+ // XHR cannot access local files, always use ActiveX for that case
+ return !this.isLocal &&
+
+ // Support: IE7-8
+ // oldIE XHR does not support non-RFC2616 methods (#13240)
+ // See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx
+ // and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
+ // Although this check for six methods instead of eight
+ // since IE also does not support "trace" and "connect"
+ /^(get|post|head|put|delete|options)$/i.test( this.type ) &&
+
+ createStandardXHR() || createActiveXHR();
+ } :
+ // For all other browsers, use the standard XMLHttpRequest object
+ createStandardXHR;
+
+var xhrId = 0,
+ xhrCallbacks = {},
+ xhrSupported = jQuery.ajaxSettings.xhr();
+
+// Support: IE<10
+// Open requests must be manually aborted on unload (#5280)
+if ( window.ActiveXObject ) {
+ jQuery( window ).on( "unload", function() {
+ for ( var key in xhrCallbacks ) {
+ xhrCallbacks[ key ]( undefined, true );
+ }
+ });
+}
+
+// Determine support properties
+support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+xhrSupported = support.ajax = !!xhrSupported;
+
+// Create transport if the browser can provide an xhr
+if ( xhrSupported ) {
+
+ jQuery.ajaxTransport(function( options ) {
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( !options.crossDomain || support.cors ) {
+
+ var callback;
+
+ return {
+ send: function( headers, complete ) {
+ var i,
+ xhr = options.xhr(),
+ id = ++xhrId;
+
+ // Open the socket
+ xhr.open( options.type, options.url, options.async, options.username, options.password );
+
+ // Apply custom fields if provided
+ if ( options.xhrFields ) {
+ for ( i in options.xhrFields ) {
+ xhr[ i ] = options.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( options.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( options.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !options.crossDomain && !headers["X-Requested-With"] ) {
+ headers["X-Requested-With"] = "XMLHttpRequest";
+ }
+
+ // Set headers
+ for ( i in headers ) {
+ // Support: IE<9
+ // IE's ActiveXObject throws a 'Type Mismatch' exception when setting
+ // request header to a null-value.
+ //
+ // To keep consistent with other XHR implementations, cast the value
+ // to string and ignore `undefined`.
+ if ( headers[ i ] !== undefined ) {
+ xhr.setRequestHeader( i, headers[ i ] + "" );
+ }
+ }
+
+ // Do send the request
+ // This may raise an exception which is actually
+ // handled in jQuery.ajax (so no try/catch here)
+ xhr.send( ( options.hasContent && options.data ) || null );
+
+ // Listener
+ callback = function( _, isAbort ) {
+ var status, statusText, responses;
+
+ // Was never called and is aborted or complete
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+ // Clean up
+ delete xhrCallbacks[ id ];
+ callback = undefined;
+ xhr.onreadystatechange = jQuery.noop;
+
+ // Abort manually if needed
+ if ( isAbort ) {
+ if ( xhr.readyState !== 4 ) {
+ xhr.abort();
+ }
+ } else {
+ responses = {};
+ status = xhr.status;
+
+ // Support: IE<10
+ // Accessing binary-data responseText throws an exception
+ // (#11426)
+ if ( typeof xhr.responseText === "string" ) {
+ responses.text = xhr.responseText;
+ }
+
+ // Firefox throws an exception when accessing
+ // statusText for faulty cross-domain requests
+ try {
+ statusText = xhr.statusText;
+ } catch( e ) {
+ // We normalize with Webkit giving an empty statusText
+ statusText = "";
+ }
+
+ // Filter status for non standard behaviors
+
+ // If the request is local and we have data: assume a success
+ // (success with no data won't get notified, that's the best we
+ // can do given current implementations)
+ if ( !status && options.isLocal && !options.crossDomain ) {
+ status = responses.text ? 200 : 404;
+ // IE - #1450: sometimes returns 1223 when it should be 204
+ } else if ( status === 1223 ) {
+ status = 204;
+ }
+ }
+ }
+
+ // Call complete if needed
+ if ( responses ) {
+ complete( status, statusText, responses, xhr.getAllResponseHeaders() );
+ }
+ };
+
+ if ( !options.async ) {
+ // if we're in sync mode we fire the callback
+ callback();
+ } else if ( xhr.readyState === 4 ) {
+ // (IE6 & IE7) if it's in cache and has been
+ // retrieved directly we need to fire the callback
+ setTimeout( callback );
+ } else {
+ // Add to the list of active xhr callbacks
+ xhr.onreadystatechange = xhrCallbacks[ id ] = callback;
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback( undefined, true );
+ }
+ }
+ };
+ }
+ });
+}
+
+// Functions to create xhrs
+function createStandardXHR() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch( e ) {}
+}
+
+function createActiveXHR() {
+ try {
+ return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+ } catch( e ) {}
+}
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+ accepts: {
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /(?:java|ecma)script/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ s.global = false;
+ }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+ // This transport only deals with cross domain requests
+ if ( s.crossDomain ) {
+
+ var script,
+ head = document.head || jQuery("head")[0] || document.documentElement;
+
+ return {
+
+ send: function( _, callback ) {
+
+ script = document.createElement("script");
+
+ script.async = true;
+
+ if ( s.scriptCharset ) {
+ script.charset = s.scriptCharset;
+ }
+
+ script.src = s.url;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+ if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+ // Handle memory leak in IE
+ script.onload = script.onreadystatechange = null;
+
+ // Remove the script
+ if ( script.parentNode ) {
+ script.parentNode.removeChild( script );
+ }
+
+ // Dereference the script
+ script = null;
+
+ // Callback if not abort
+ if ( !isAbort ) {
+ callback( 200, "success" );
+ }
+ }
+ };
+
+ // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
+ // Use native DOM manipulation to avoid our domManip AJAX trickery
+ head.insertBefore( script, head.firstChild );
+ },
+
+ abort: function() {
+ if ( script ) {
+ script.onload( undefined, true );
+ }
+ }
+ };
+ }
+});
+
+
+
+
+var oldCallbacks = [],
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+ jsonp: "callback",
+ jsonpCallback: function() {
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
+ this[ callback ] = true;
+ return callback;
+ }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var callbackName, overwritten, responseContainer,
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+ "url" :
+ typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+ );
+
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+ // Get callback name, remembering preexisting value associated with it
+ callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+ s.jsonpCallback() :
+ s.jsonpCallback;
+
+ // Insert callback into url or form data
+ if ( jsonProp ) {
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+ } else if ( s.jsonp !== false ) {
+ s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+ }
+
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( callbackName + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Install callback
+ overwritten = window[ callbackName ];
+ window[ callbackName ] = function() {
+ responseContainer = arguments;
+ };
+
+ // Clean-up function (fires after converters)
+ jqXHR.always(function() {
+ // Restore preexisting value
+ window[ callbackName ] = overwritten;
+
+ // Save back as free
+ if ( s[ callbackName ] ) {
+ // make sure that re-using the options doesn't screw things around
+ s.jsonpCallback = originalSettings.jsonpCallback;
+
+ // save the callback name for future use
+ oldCallbacks.push( callbackName );
+ }
+
+ // Call if it was a function and we have a response
+ if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+ overwritten( responseContainer[ 0 ] );
+ }
+
+ responseContainer = overwritten = undefined;
+ });
+
+ // Delegate to script
+ return "script";
+ }
+});
+
+
+
+
+// data: string of html
+// context (optional): If specified, the fragment will be created in this context, defaults to document
+// keepScripts (optional): If true, will include scripts passed in the html string
+jQuery.parseHTML = function( data, context, keepScripts ) {
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ if ( typeof context === "boolean" ) {
+ keepScripts = context;
+ context = false;
+ }
+ context = context || document;
+
+ var parsed = rsingleTag.exec( data ),
+ scripts = !keepScripts && [];
+
+ // Single tag
+ if ( parsed ) {
+ return [ context.createElement( parsed[1] ) ];
+ }
+
+ parsed = jQuery.buildFragment( [ data ], context, scripts );
+
+ if ( scripts && scripts.length ) {
+ jQuery( scripts ).remove();
+ }
+
+ return jQuery.merge( [], parsed.childNodes );
+};
+
+
+// Keep a copy of the old load method
+var _load = jQuery.fn.load;
+
+/**
+ * Load a url into a page
+ */
+jQuery.fn.load = function( url, params, callback ) {
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
+ }
+
+ var selector, response, type,
+ self = this,
+ off = url.indexOf(" ");
+
+ if ( off >= 0 ) {
+ selector = url.slice( off, url.length );
+ url = url.slice( 0, off );
+ }
+
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( params && typeof params === "object" ) {
+ type = "POST";
+ }
+
+ // If we have elements to modify, make the request
+ if ( self.length > 0 ) {
+ jQuery.ajax({
+ url: url,
+
+ // if "type" variable is undefined, then "GET" method will be used
+ type: type,
+ dataType: "html",
+ data: params
+ }).done(function( responseText ) {
+
+ // Save response for use in complete callback
+ response = arguments;
+
+ self.html( selector ?
+
+ // If a selector was specified, locate the right elements in a dummy div
+ // Exclude scripts to avoid IE 'Permission Denied' errors
+ jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+ // Otherwise use the full result
+ responseText );
+
+ }).complete( callback && function( jqXHR, status ) {
+ self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+ });
+ }
+
+ return this;
+};
+
+
+
+
+jQuery.expr.filters.animated = function( elem ) {
+ return jQuery.grep(jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ }).length;
+};
+
+
+
+
+
+var docElem = window.document.documentElement;
+
+/**
+ * Gets a window from an element
+ */
+function getWindow( elem ) {
+ return jQuery.isWindow( elem ) ?
+ elem :
+ elem.nodeType === 9 ?
+ elem.defaultView || elem.parentWindow :
+ false;
+}
+
+jQuery.offset = {
+ setOffset: function( elem, options, i ) {
+ var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
+ position = jQuery.css( elem, "position" ),
+ curElem = jQuery( elem ),
+ props = {};
+
+ // set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ curOffset = curElem.offset();
+ curCSSTop = jQuery.css( elem, "top" );
+ curCSSLeft = jQuery.css( elem, "left" );
+ calculatePosition = ( position === "absolute" || position === "fixed" ) &&
+ jQuery.inArray("auto", [ curCSSTop, curCSSLeft ] ) > -1;
+
+ // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( jQuery.isFunction( options ) ) {
+ options = options.call( elem, i, curOffset );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+jQuery.fn.extend({
+ offset: function( options ) {
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ var docElem, win,
+ box = { top: 0, left: 0 },
+ elem = this[ 0 ],
+ doc = elem && elem.ownerDocument;
+
+ if ( !doc ) {
+ return;
+ }
+
+ docElem = doc.documentElement;
+
+ // Make sure it's not a disconnected DOM node
+ if ( !jQuery.contains( docElem, elem ) ) {
+ return box;
+ }
+
+ // If we don't have gBCR, just use 0,0 rather than error
+ // BlackBerry 5, iOS 3 (original iPhone)
+ if ( typeof elem.getBoundingClientRect !== strundefined ) {
+ box = elem.getBoundingClientRect();
+ }
+ win = getWindow( doc );
+ return {
+ top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
+ left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
+ };
+ },
+
+ position: function() {
+ if ( !this[ 0 ] ) {
+ return;
+ }
+
+ var offsetParent, offset,
+ parentOffset = { top: 0, left: 0 },
+ elem = this[ 0 ];
+
+ // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
+ // we assume that getBoundingClientRect is available when computed position is fixed
+ offset = elem.getBoundingClientRect();
+ } else {
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent();
+
+ // Get correct offsets
+ offset = this.offset();
+ if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+ parentOffset = offsetParent.offset();
+ }
+
+ // Add offsetParent borders
+ parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+ parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+ }
+
+ // Subtract parent offsets and element margins
+ // note: when an element has margin: auto the offsetLeft and marginLeft
+ // are the same in Safari causing offset.left to incorrectly be 0
+ return {
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
+ };
+ },
+
+ offsetParent: function() {
+ return this.map(function() {
+ var offsetParent = this.offsetParent || docElem;
+
+ while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+ return offsetParent || docElem;
+ });
+ }
+});
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
+ var top = /Y/.test( prop );
+
+ jQuery.fn[ method ] = function( val ) {
+ return access( this, function( elem, method, val ) {
+ var win = getWindow( elem );
+
+ if ( val === undefined ) {
+ return win ? (prop in win) ? win[ prop ] :
+ win.document.documentElement[ method ] :
+ elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : jQuery( win ).scrollLeft(),
+ top ? val : jQuery( win ).scrollTop()
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length, null );
+ };
+});
+
+// Add the top/left cssHooks using jQuery.fn.position
+// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+// getComputedStyle returns percent when specified for top/left/bottom/right
+// rather than make the css module depend on the offset module, we just check for it here
+jQuery.each( [ "top", "left" ], function( i, prop ) {
+ jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
+ function( elem, computed ) {
+ if ( computed ) {
+ computed = curCSS( elem, prop );
+ // if curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( computed ) ?
+ jQuery( elem ).position()[ prop ] + "px" :
+ computed;
+ }
+ }
+ );
+});
+
+
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+ // margin is only for outerHeight, outerWidth
+ jQuery.fn[ funcName ] = function( margin, value ) {
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+ return access( this, function( elem, type, value ) {
+ var doc;
+
+ if ( jQuery.isWindow( elem ) ) {
+ // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+ // isn't a whole lot we can do. See pull request at this URL for discussion:
+ // https://github.com/jquery/jquery/pull/764
+ return elem.document.documentElement[ "client" + name ];
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ doc = elem.documentElement;
+
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
+ // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
+ return Math.max(
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
+ doc[ "client" + name ]
+ );
+ }
+
+ return value === undefined ?
+ // Get width or height on the element, requesting but not forcing parseFloat
+ jQuery.css( elem, type, extra ) :
+
+ // Set width or height on the element
+ jQuery.style( elem, type, value, extra );
+ }, type, chainable ? margin : undefined, chainable, null );
+ };
+ });
+});
+
+
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+ return this.length;
+};
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+
+
+
+// Register as a named AMD module, since jQuery can be concatenated with other
+// files that may use define, but not via a proper concatenation script that
+// understands anonymous AMD modules. A named AMD is safest and most robust
+// way to register. Lowercase jquery is used because AMD module names are
+// derived from file names, and jQuery is normally delivered in a lowercase
+// file name. Do this after creating the global so that if an AMD module wants
+// to call noConflict to hide this version of jQuery, it will work.
+if ( typeof define === "function" && define.amd ) {
+ define( "jquery", [], function() {
+ return jQuery;
+ });
+}
+
+
+
+
+var
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$;
+
+jQuery.noConflict = function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+};
+
+// Expose jQuery and $ identifiers, even in
+// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// and CommonJS for browser emulators (#13566)
+if ( typeof noGlobal === strundefined ) {
+ window.jQuery = window.$ = jQuery;
+}
+
+
+
+
+return jQuery;
+
+}));
diff --git a/lib/prado/framework/Web/Javascripts/source/jquery/jquery.min.js b/lib/prado/framework/Web/Javascripts/source/jquery/jquery.min.js
new file mode 100644
index 0000000..73f33fb
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/jquery/jquery.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v1.11.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m="1.11.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(l.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:k&&!k.call("\ufeff\xa0")?function(a){return null==a?"":k.call(a)}:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||n.guid++,e):void 0},now:function(){return+new Date},support:l}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="<select t=''><option selected=''></option></select>",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=jb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=kb(b);function nb(){}nb.prototype=d.filters=d.pseudos,d.setFilters=new nb;function ob(a,b){var c,e,f,g,h,i,j,k=x[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=Q.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?db.error(a):x(a,i).slice(0)}function pb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=a.document,A=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,B=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:A.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:z,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=z.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return y.find(a);this.length=1,this[0]=d}return this.context=z,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};B.prototype=n.fn,y=n(z);var C=/^(?:parents|prev(?:Until|All))/,D={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!n(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function E(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return E(a,"nextSibling")},prev:function(a){return E(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(D[a]||(e=n.unique(e)),C.test(a)&&(e=e.reverse())),this.pushStack(e)}});var F=/\S+/g,G={};function H(a){var b=G[a]={};return n.each(a.match(F)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?G[a]||H(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&n.each(arguments,function(a,c){var d;while((d=n.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){if(a===!0?!--n.readyWait:!n.isReady){if(!z.body)return setTimeout(n.ready);n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(z,[n]),n.fn.trigger&&n(z).trigger("ready").off("ready"))}}});function J(){z.addEventListener?(z.removeEventListener("DOMContentLoaded",K,!1),a.removeEventListener("load",K,!1)):(z.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(z.addEventListener||"load"===event.type||"complete"===z.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===z.readyState)setTimeout(n.ready);else if(z.addEventListener)z.addEventListener("DOMContentLoaded",K,!1),a.addEventListener("load",K,!1);else{z.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&z.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!n.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}J(),n.ready()}}()}return I.promise(b)};var L="undefined",M;for(M in n(l))break;l.ownLast="0"!==M,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c=z.getElementsByTagName("body")[0];c&&(a=z.createElement("div"),a.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",b=z.createElement("div"),c.appendChild(a).appendChild(b),typeof b.style.zoom!==L&&(b.style.cssText="border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1",(l.inlineBlockNeedsLayout=3===b.offsetWidth)&&(c.style.zoom=1)),c.removeChild(a),a=b=null)}),function(){var a=z.createElement("div");if(null==l.deleteExpando){l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}}a=null}(),n.acceptData=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(n.acceptData(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f
+}}function S(a,b,c){if(n.acceptData(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d]));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=n._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var T=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,U=["Top","Right","Bottom","Left"],V=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},W=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},X=/^(?:checkbox|radio)$/i;!function(){var a=z.createDocumentFragment(),b=z.createElement("div"),c=z.createElement("input");if(b.setAttribute("className","t"),b.innerHTML=" <link/><table></table><a href='/a'>a</a>",l.leadingWhitespace=3===b.firstChild.nodeType,l.tbody=!b.getElementsByTagName("tbody").length,l.htmlSerialize=!!b.getElementsByTagName("link").length,l.html5Clone="<:nav></:nav>"!==z.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,a.appendChild(c),l.appendChecked=c.checked,b.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,a.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){l.noCloneEvent=!1}),b.cloneNode(!0).click()),null==l.deleteExpando){l.deleteExpando=!0;try{delete b.test}catch(d){l.deleteExpando=!1}}a=b=c=null}(),function(){var b,c,d=z.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),l[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var Y=/^(?:input|select|textarea)$/i,Z=/^key/,$=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,ab=/^([^.]*)(?:\.(.+)|)$/;function bb(){return!0}function cb(){return!1}function db(){try{return z.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof n===L||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(F)||[""],h=b.length;while(h--)f=ab.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(F)||[""],j=b.length;while(j--)if(h=ab.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,m,o=[d||z],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||z,3!==d.nodeType&&8!==d.nodeType&&!_.test(p+n.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[n.expando]?b:new n.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),k=n.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!n.isWindow(d)){for(i=k.delegateType||p,_.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||z)&&o.push(l.defaultView||l.parentWindow||a)}m=0;while((h=o[m++])&&!b.isPropagationStopped())b.type=m>1?i:k.bindType||p,f=(n._data(h,"events")||{})[b.type]&&n._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&n.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&n.acceptData(d)&&g&&d[p]&&!n.isWindow(d)){l=d[g],l&&(d[g]=null),n.event.triggered=p;try{d[p]()}catch(r){}n.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((n.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?n(c,this).index(i)>=0:n.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=$.test(e)?this.mouseHooks:Z.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||z),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||z,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==db()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===db()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return n.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=z.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===L&&(a[d]=null),a.detachEvent(d,c))},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&(a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault())?bb:cb):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:cb,isPropagationStopped:cb,isImmediatePropagationStopped:cb,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=bb,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=bb,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.submitBubbles||(n.event.special.submit={setup:function(){return n.nodeName(this,"form")?!1:void n.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=n.nodeName(b,"input")||n.nodeName(b,"button")?b.form:void 0;c&&!n._data(c,"submitBubbles")&&(n.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),n._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&n.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return n.nodeName(this,"form")?!1:void n.event.remove(this,"._submit")}}),l.changeBubbles||(n.event.special.change={setup:function(){return Y.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(n.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),n.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),n.event.simulate("change",this,a,!0)})),!1):void n.event.add(this,"beforeactivate._change",function(a){var b=a.target;Y.test(b.nodeName)&&!n._data(b,"changeBubbles")&&(n.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||n.event.simulate("change",this.parentNode,a,!0)}),n._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return n.event.remove(this,"._change"),!Y.test(this.nodeName)}}),l.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=n._data(d,b);e||d.addEventListener(a,c,!0),n._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=n._data(d,b)-1;e?n._data(d,b,e):(d.removeEventListener(a,c,!0),n._removeData(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=cb;else if(!d)return this;return 1===e&&(g=d,d=function(a){return n().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=cb),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});function eb(a){var b=fb.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var fb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gb=/ jQuery\d+="(?:null|\d+)"/g,hb=new RegExp("<(?:"+fb+")[\\s/>]","i"),ib=/^\s+/,jb=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,kb=/<([\w:]+)/,lb=/<tbody/i,mb=/<|&#?\w+;/,nb=/<(?:script|style|link)/i,ob=/checked\s*(?:[^=]|=\s*.checked.)/i,pb=/^$|\/(?:java|ecma)script/i,qb=/^true\/(.*)/,rb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,sb={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:l.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},tb=eb(z),ub=tb.appendChild(z.createElement("div"));sb.optgroup=sb.option,sb.tbody=sb.tfoot=sb.colgroup=sb.caption=sb.thead,sb.th=sb.td;function vb(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==L?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==L?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,vb(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function wb(a){X.test(a.type)&&(a.defaultChecked=a.checked)}function xb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function yb(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function zb(a){var b=qb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ab(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}function Bb(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Cb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(yb(b).text=a.text,zb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&X.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}n.extend({clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!hb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ub.innerHTML=a.outerHTML,ub.removeChild(f=ub.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=vb(f),h=vb(a),g=0;null!=(e=h[g]);++g)d[g]&&Cb(e,d[g]);if(b)if(c)for(h=h||vb(a),d=d||vb(f),g=0;null!=(e=h[g]);g++)Bb(e,d[g]);else Bb(a,f);return d=vb(f,"script"),d.length>0&&Ab(d,!i&&vb(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k,m=a.length,o=eb(b),p=[],q=0;m>q;q++)if(f=a[q],f||0===f)if("object"===n.type(f))n.merge(p,f.nodeType?[f]:f);else if(mb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(kb.exec(f)||["",""])[1].toLowerCase(),k=sb[i]||sb._default,h.innerHTML=k[1]+f.replace(jb,"<$1></$2>")+k[2],e=k[0];while(e--)h=h.lastChild;if(!l.leadingWhitespace&&ib.test(f)&&p.push(b.createTextNode(ib.exec(f)[0])),!l.tbody){f="table"!==i||lb.test(f)?"<table>"!==k[1]||lb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)n.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}n.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),l.appendChecked||n.grep(vb(p,"input"),wb),q=0;while(f=p[q++])if((!d||-1===n.inArray(f,d))&&(g=n.contains(f.ownerDocument,f),h=vb(o.appendChild(f),"script"),g&&Ab(h),c)){e=0;while(f=h[e++])pb.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.deleteExpando,m=n.event.special;null!=(d=a[h]);h++)if((b||n.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k?delete d[i]:typeof d.removeAttribute!==L?d.removeAttribute(i):d[i]=null,c.push(f))}}}),n.fn.extend({text:function(a){return W(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||z).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(vb(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&Ab(vb(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(vb(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return W(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(gb,""):void 0;if(!("string"!=typeof a||nb.test(a)||!l.htmlSerialize&&hb.test(a)||!l.leadingWhitespace&&ib.test(a)||sb[(kb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(jb,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(vb(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(vb(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,o=k-1,p=a[0],q=n.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&ob.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(i=n.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=n.map(vb(i,"script"),yb),f=g.length;k>j;j++)d=i,j!==o&&(d=n.clone(d,!0,!0),f&&n.merge(g,vb(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,n.map(g,zb),j=0;f>j;j++)d=g[j],pb.test(d.type||"")&&!n._data(d,"globalEval")&&n.contains(h,d)&&(d.src?n._evalUrl&&n._evalUrl(d.src):n.globalEval((d.text||d.textContent||d.innerHTML||"").replace(rb,"")));i=c=null}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],g=n(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Db,Eb={};function Fb(b,c){var d=n(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:n.css(d[0],"display");return d.detach(),e}function Gb(a){var b=z,c=Eb[a];return c||(c=Fb(a,b),"none"!==c&&c||(Db=(Db||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Db[0].contentWindow||Db[0].contentDocument).document,b.write(),b.close(),c=Fb(a,b),Db.detach()),Eb[a]=c),c}!function(){var a,b,c=z.createElement("div"),d="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;padding:0;margin:0;border:0";c.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=c.getElementsByTagName("a")[0],a.style.cssText="float:left;opacity:.5",l.opacity=/^0.5/.test(a.style.opacity),l.cssFloat=!!a.style.cssFloat,c.style.backgroundClip="content-box",c.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===c.style.backgroundClip,a=c=null,l.shrinkWrapBlocks=function(){var a,c,e,f;if(null==b){if(a=z.getElementsByTagName("body")[0],!a)return;f="border:0;width:0;height:0;position:absolute;top:0;left:-9999px",c=z.createElement("div"),e=z.createElement("div"),a.appendChild(c).appendChild(e),b=!1,typeof e.style.zoom!==L&&(e.style.cssText=d+";width:1px;padding:1px;zoom:1",e.innerHTML="<div></div>",e.firstChild.style.width="5px",b=3!==e.offsetWidth),a.removeChild(c),a=c=e=null}return b}}();var Hb=/^margin/,Ib=new RegExp("^("+T+")(?!px)[a-z%]+$","i"),Jb,Kb,Lb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Jb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Kb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Jb(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),Ib.test(g)&&Hb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):z.documentElement.currentStyle&&(Jb=function(a){return a.currentStyle},Kb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Jb(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Ib.test(g)&&!Lb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Mb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h=z.createElement("div"),i="border:0;width:0;height:0;position:absolute;top:0;left:-9999px",j="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;padding:0;margin:0;border:0";h.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",b=h.getElementsByTagName("a")[0],b.style.cssText="float:left;opacity:.5",l.opacity=/^0.5/.test(b.style.opacity),l.cssFloat=!!b.style.cssFloat,h.style.backgroundClip="content-box",h.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===h.style.backgroundClip,b=h=null,n.extend(l,{reliableHiddenOffsets:function(){if(null!=c)return c;var a,b,d,e=z.createElement("div"),f=z.getElementsByTagName("body")[0];if(f)return e.setAttribute("className","t"),e.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=z.createElement("div"),a.style.cssText=i,f.appendChild(a).appendChild(e),e.innerHTML="<table><tr><td></td><td>t</td></tr></table>",b=e.getElementsByTagName("td"),b[0].style.cssText="padding:0;margin:0;border:0;display:none",d=0===b[0].offsetHeight,b[0].style.display="",b[1].style.display="none",c=d&&0===b[0].offsetHeight,f.removeChild(a),e=f=null,c},boxSizing:function(){return null==d&&k(),d},boxSizingReliable:function(){return null==e&&k(),e},pixelPosition:function(){return null==f&&k(),f},reliableMarginRight:function(){var b,c,d,e;if(null==g&&a.getComputedStyle){if(b=z.getElementsByTagName("body")[0],!b)return;c=z.createElement("div"),d=z.createElement("div"),c.style.cssText=i,b.appendChild(c).appendChild(d),e=d.appendChild(z.createElement("div")),e.style.cssText=d.style.cssText=j,e.style.marginRight=e.style.width="0",d.style.width="1px",g=!parseFloat((a.getComputedStyle(e,null)||{}).marginRight),b.removeChild(c)}return g}});function k(){var b,c,h=z.getElementsByTagName("body")[0];h&&(b=z.createElement("div"),c=z.createElement("div"),b.style.cssText=i,h.appendChild(b).appendChild(c),c.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;display:block;padding:1px;border:1px;width:4px;margin-top:1%;top:1%",n.swap(h,null!=h.style.zoom?{zoom:1}:{},function(){d=4===c.offsetWidth}),e=!0,f=!1,g=!0,a.getComputedStyle&&(f="1%"!==(a.getComputedStyle(c,null)||{}).top,e="4px"===(a.getComputedStyle(c,null)||{width:"4px"}).width),h.removeChild(b),c=h=null)}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Nb=/alpha\([^)]*\)/i,Ob=/opacity\s*=\s*([^)]*)/,Pb=/^(none|table(?!-c[ea]).+)/,Qb=new RegExp("^("+T+")(.*)$","i"),Rb=new RegExp("^([+-])=("+T+")","i"),Sb={position:"absolute",visibility:"hidden",display:"block"},Tb={letterSpacing:0,fontWeight:400},Ub=["Webkit","O","Moz","ms"];function Vb(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Ub.length;while(e--)if(b=Ub[e]+c,b in a)return b;return d}function Wb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=n._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&V(d)&&(f[g]=n._data(d,"olddisplay",Gb(d.nodeName)))):f[g]||(e=V(d),(c&&"none"!==c||!e)&&n._data(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Xb(a,b,c){var d=Qb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Yb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+U[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+U[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+U[f]+"Width",!0,e))):(g+=n.css(a,"padding"+U[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+U[f]+"Width",!0,e)));return g}function Zb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Jb(a),g=l.boxSizing()&&"border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Kb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Ib.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Yb(a,b,c||(g?"border":"content"),d,f)+"px"}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Kb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":l.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;if(b=n.cssProps[h]||(n.cssProps[h]=Vb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Rb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]="",i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Vb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Kb(a,b,d)),"normal"===f&&b in Tb&&(f=Tb[b]),""===c||c?(e=parseFloat(f),c===!0||n.isNumeric(e)?e||0:f):f}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?0===a.offsetWidth&&Pb.test(n.css(a,"display"))?n.swap(a,Sb,function(){return Zb(a,b,d)}):Zb(a,b,d):void 0},set:function(a,c,d){var e=d&&Jb(a);return Xb(a,c,d?Yb(a,b,d,l.boxSizing()&&"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),l.opacity||(n.cssHooks.opacity={get:function(a,b){return Ob.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=n.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===n.trim(f.replace(Nb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Nb.test(f)?f.replace(Nb,e):f+" "+e)}}),n.cssHooks.marginRight=Mb(l.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},Kb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+U[d]+b]=f[d]||f[d-2]||f[0];return e}},Hb.test(a)||(n.cssHooks[a+b].set=Xb)}),n.fn.extend({css:function(a,b){return W(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Jb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)
+},a,b,arguments.length>1)},show:function(){return Wb(this,!0)},hide:function(){return Wb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){V(this)?n(this).show():n(this).hide()})}});function $b(a,b,c,d,e){return new $b.prototype.init(a,b,c,d,e)}n.Tween=$b,$b.prototype={constructor:$b,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=$b.propHooks[this.prop];return a&&a.get?a.get(this):$b.propHooks._default.get(this)},run:function(a){var b,c=$b.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):$b.propHooks._default.set(this),this}},$b.prototype.init.prototype=$b.prototype,$b.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},$b.propHooks.scrollTop=$b.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=$b.prototype.init,n.fx.step={};var _b,ac,bc=/^(?:toggle|show|hide)$/,cc=new RegExp("^(?:([+-])=|)("+T+")([a-z%]*)$","i"),dc=/queueHooks$/,ec=[jc],fc={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=cc.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&cc.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function gc(){return setTimeout(function(){_b=void 0}),_b=n.now()}function hc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=U[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function ic(a,b,c){for(var d,e=(fc[b]||[]).concat(fc["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function jc(a,b,c){var d,e,f,g,h,i,j,k,m=this,o={},p=a.style,q=a.nodeType&&V(a),r=n._data(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,m.always(function(){m.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=n.css(a,"display"),k=Gb(a.nodeName),"none"===j&&(j=k),"inline"===j&&"none"===n.css(a,"float")&&(l.inlineBlockNeedsLayout&&"inline"!==k?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",l.shrinkWrapBlocks()||m.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],bc.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||n.style(a,d)}if(!n.isEmptyObject(o)){r?"hidden"in r&&(q=r.hidden):r=n._data(a,"fxshow",{}),f&&(r.hidden=!q),q?n(a).show():m.done(function(){n(a).hide()}),m.done(function(){var b;n._removeData(a,"fxshow");for(b in o)n.style(a,b,o[b])});for(d in o)g=ic(q?r[d]:0,d,m),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function kc(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function lc(a,b,c){var d,e,f=0,g=ec.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=_b||gc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:_b||gc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(kc(k,j.opts.specialEasing);g>f;f++)if(d=ec[f].call(j,a,k,j.opts))return d;return n.map(k,ic,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(lc,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],fc[c]=fc[c]||[],fc[c].unshift(b)},prefilter:function(a,b){b?ec.unshift(a):ec.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(V).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=lc(this,n.extend({},a),f);(e||n._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=n._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&dc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=n._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(hc(b,!0),a,d,e)}}),n.each({slideDown:hc("show"),slideUp:hc("hide"),slideToggle:hc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=n.timers,c=0;for(_b=n.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||n.fx.stop(),_b=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){ac||(ac=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(ac),ac=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e=z.createElement("div");e.setAttribute("className","t"),e.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=e.getElementsByTagName("a")[0],c=z.createElement("select"),d=c.appendChild(z.createElement("option")),b=e.getElementsByTagName("input")[0],a.style.cssText="top:1px",l.getSetAttribute="t"!==e.className,l.style=/top/.test(a.getAttribute("style")),l.hrefNormalized="/a"===a.getAttribute("href"),l.checkOn=!!b.value,l.optSelected=d.selected,l.enctype=!!z.createElement("form").enctype,c.disabled=!0,l.optDisabled=!d.disabled,b=z.createElement("input"),b.setAttribute("value",""),l.input=""===b.getAttribute("value"),b.value="t",b.setAttribute("type","radio"),l.radioValue="t"===b.value,a=b=c=d=e=null}();var mc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(mc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.text(a)}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(l.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)if(d=e[g],n.inArray(n.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var nc,oc,pc=n.expr.attrHandle,qc=/^(?:checked|selected)$/i,rc=l.getSetAttribute,sc=l.input;n.fn.extend({attr:function(a,b){return W(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===L?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?oc:nc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(F);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)?sc&&rc||!qc.test(c)?a[d]=!1:a[n.camelCase("default-"+c)]=a[d]=!1:n.attr(a,c,""),a.removeAttribute(rc?c:d)},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),oc={set:function(a,b,c){return b===!1?n.removeAttr(a,c):sc&&rc||!qc.test(c)?a.setAttribute(!rc&&n.propFix[c]||c,c):a[n.camelCase("default-"+c)]=a[c]=!0,c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=pc[b]||n.find.attr;pc[b]=sc&&rc||!qc.test(b)?function(a,b,d){var e,f;return d||(f=pc[b],pc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,pc[b]=f),e}:function(a,b,c){return c?void 0:a[n.camelCase("default-"+b)]?b.toLowerCase():null}}),sc&&rc||(n.attrHooks.value={set:function(a,b,c){return n.nodeName(a,"input")?void(a.defaultValue=b):nc&&nc.set(a,b,c)}}),rc||(nc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},pc.id=pc.name=pc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},n.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:nc.set},n.attrHooks.contenteditable={set:function(a,b,c){nc.set(a,""===b?!1:b,c)}},n.each(["width","height"],function(a,b){n.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),l.style||(n.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var tc=/^(?:input|select|textarea|button|object)$/i,uc=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return W(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return a=n.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):tc.test(a.nodeName)||uc.test(a.nodeName)&&a.href?0:-1}}}}),l.hrefNormalized||n.each(["href","src"],function(a,b){n.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this}),l.enctype||(n.propFix.enctype="encoding");var vc=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(F)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(vc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(F)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(vc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(F)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===L||"boolean"===c)&&(this.className&&n._data(this,"__className__",this.className),this.className=this.className||a===!1?"":n._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(vc," ").indexOf(b)>=0)return!0;return!1}}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var wc=n.now(),xc=/\?/,yc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;n.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=n.trim(b+"");return e&&!n.trim(e.replace(yc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():n.error("Invalid JSON: "+b)},n.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||n.error("Invalid XML: "+b),c};var zc,Ac,Bc=/#.*$/,Cc=/([?&])_=[^&]*/,Dc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Ec=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Fc=/^(?:GET|HEAD)$/,Gc=/^\/\//,Hc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Ic={},Jc={},Kc="*/".concat("*");try{Ac=location.href}catch(Lc){Ac=z.createElement("a"),Ac.href="",Ac=Ac.href}zc=Hc.exec(Ac.toLowerCase())||[];function Mc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(F)||[];if(n.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nc(a,b,c,d){var e={},f=a===Jc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Oc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&n.extend(!0,a,c),a}function Pc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Qc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ac,type:"GET",isLocal:Ec.test(zc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Oc(Oc(a,n.ajaxSettings),b):Oc(n.ajaxSettings,a)},ajaxPrefilter:Mc(Ic),ajaxTransport:Mc(Jc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Dc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||Ac)+"").replace(Bc,"").replace(Gc,zc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(F)||[""],null==k.crossDomain&&(c=Hc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===zc[1]&&c[2]===zc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(zc[3]||("http:"===zc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),Nc(Ic,k,b,v),2===t)return v;h=k.global,h&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Fc.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(xc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Cc.test(e)?e.replace(Cc,"$1_="+wc++):e+(xc.test(e)?"&":"?")+"_="+wc++)),k.ifModified&&(n.lastModified[e]&&v.setRequestHeader("If-Modified-Since",n.lastModified[e]),n.etag[e]&&v.setRequestHeader("If-None-Match",n.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Kc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Nc(Jc,k,b,v)){v.readyState=1,h&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Pc(k,v,c)),u=Qc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(n.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){if(n.isFunction(a))return this.each(function(b){n(this).wrapAll(a.call(this,b))});if(this[0]){var b=n(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!l.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||n.css(a,"display"))},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var Rc=/%20/g,Sc=/\[\]$/,Tc=/\r?\n/g,Uc=/^(?:submit|button|image|reset|file)$/i,Vc=/^(?:input|select|textarea|keygen)/i;function Wc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||Sc.test(a)?d(a,e):Wc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Wc(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Wc(c,a[c],b,e);return d.join("&").replace(Rc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&Vc.test(this.nodeName)&&!Uc.test(a)&&(this.checked||!X.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(Tc,"\r\n")}}):{name:b.name,value:c.replace(Tc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&$c()||_c()}:$c;var Xc=0,Yc={},Zc=n.ajaxSettings.xhr();a.ActiveXObject&&n(a).on("unload",function(){for(var a in Yc)Yc[a](void 0,!0)}),l.cors=!!Zc&&"withCredentials"in Zc,Zc=l.ajax=!!Zc,Zc&&n.ajaxTransport(function(a){if(!a.crossDomain||l.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Xc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Yc[g],b=void 0,f.onreadystatechange=n.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Yc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function $c(){try{return new a.XMLHttpRequest}catch(b){}}function _c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=z.head||n("head")[0]||z.documentElement;return{send:function(d,e){b=z.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var ad=[],bd=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=ad.pop()||n.expando+"_"+wc++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(bd.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&bd.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(bd,"$1"+e):b.jsonp!==!1&&(b.url+=(xc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,ad.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||z;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var cd=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&cd)return cd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=a.slice(h,a.length),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&n.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var dd=a.document.documentElement;function ed(a){return n.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&n.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,n.contains(b,e)?(typeof e.getBoundingClientRect!==L&&(d=e.getBoundingClientRect()),c=ed(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===n.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(c=a.offset()),c.top+=n.css(a[0],"borderTopWidth",!0),c.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-n.css(d,"marginTop",!0),left:b.left-c.left-n.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||dd;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||dd})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);n.fn[a]=function(d){return W(this,function(a,d,e){var f=ed(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?n(f).scrollLeft():e,c?e:n(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Mb(l.pixelPosition,function(a,c){return c?(c=Kb(a,b),Ib.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return W(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var fd=a.jQuery,gd=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=gd),b&&a.jQuery===n&&(a.jQuery=fd),n},typeof b===L&&(a.jQuery=a.$=n),n});
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/activecontrols3.js b/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/activecontrols3.js
new file mode 100644
index 0000000..02f33a6
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/activecontrols3.js
@@ -0,0 +1,421 @@
+/**
+ * Generic postback control.
+ */
+Prado.WebUI.CallbackControl = jQuery.klass(Prado.WebUI.PostBackControl,
+{
+ onPostBack : function(options, event)
+ {
+ var request = new Prado.CallbackRequest(options.EventTarget, options);
+ request.dispatch();
+ event.preventDefault();
+ }
+});
+
+/**
+ * TActiveButton control.
+ */
+Prado.WebUI.TActiveButton = jQuery.klass(Prado.WebUI.CallbackControl);
+/**
+ * TActiveLinkButton control.
+ */
+Prado.WebUI.TActiveLinkButton = jQuery.klass(Prado.WebUI.CallbackControl);
+
+Prado.WebUI.TActiveImageButton = jQuery.klass(Prado.WebUI.TImageButton,
+{
+ onPostBack : function(options, event)
+ {
+ this.addXYInput(options, event);
+ var request = new Prado.CallbackRequest(options.EventTarget, options);
+ request.dispatch();
+ event.preventDefault();
+ this.removeXYInput(options, event);
+ }
+});
+/**
+ * Active check box.
+ */
+Prado.WebUI.TActiveCheckBox = jQuery.klass(Prado.WebUI.CallbackControl,
+{
+ onPostBack : function(options, event)
+ {
+ var request = new Prado.CallbackRequest(options.EventTarget, options);
+ if(request.dispatch()==false)
+ event.preventDefault();
+ }
+});
+
+/**
+ * TActiveRadioButton control.
+ */
+Prado.WebUI.TActiveRadioButton = jQuery.klass(Prado.WebUI.TActiveCheckBox);
+
+
+Prado.WebUI.TActiveCheckBoxList = jQuery.klass(Prado.WebUI.Control,
+{
+ onInit : function(options)
+ {
+ for(var i = 0; i<options.ItemCount; i++)
+ {
+ var checkBoxOptions = jQuery.extend({}, options,
+ {
+ ID : options.ID+"_c"+i,
+ EventTarget : options.ListName+"$c"+i
+ });
+ new Prado.WebUI.TActiveCheckBox(checkBoxOptions);
+ }
+ }
+});
+
+Prado.WebUI.TActiveRadioButtonList = Prado.WebUI.TActiveCheckBoxList;
+
+/**
+ * TActiveTextBox control, handles onchange event.
+ */
+Prado.WebUI.TActiveTextBox = jQuery.klass(Prado.WebUI.TTextBox,
+{
+ onInit : function(options)
+ {
+ this.options=options;
+ if(options['TextMode'] != 'MultiLine')
+ this.observe(this.element, "keydown", this.handleReturnKey.bind(this));
+ if(this.options['AutoPostBack']==true)
+ this.observe(this.element, "change", jQuery.proxy(this.doCallback,this,options));
+ },
+
+ doCallback : function(options, event)
+ {
+ var request = new Prado.CallbackRequest(options.EventTarget, options);
+ request.dispatch();
+ event.preventDefault();
+ }
+});
+
+/**
+ * TJuiAutoComplete control.
+ */
+
+Prado.WebUI.TJuiAutoComplete = jQuery.klass(Prado.WebUI.TActiveTextBox,
+{
+ initialize : function(options)
+ {
+ this.options = options;
+ this.observers = new Array();
+ this.hasResults = false;
+ jQuery.extend(this.options, {
+ source: this.getUpdatedChoices.bind(this),
+ select: this.selectEntry.bind(this),
+ focus: function () {
+ return false;
+ },
+ minLength: this.options.minLength,
+ frequency: this.options.frequency
+ });
+ jQuery('#'+options.ID).autocomplete(this.options)
+ .data( "ui-autocomplete")._renderItem = function( ul, item ) {
+ return jQuery( "<li>" )
+ .attr( "data-value", item.value )
+ .append( jQuery( "<a>" ).html( item.label ) )
+ .appendTo( ul );
+ };
+
+ if(options.AutoPostBack)
+ this.onInit(options);
+
+ Prado.Registry[options.ID] = this;
+ },
+
+ doCallback : function(event, options)
+ {
+ if(!this.active)
+ {
+ var request = new Prado.CallbackRequest(this.options.EventTarget, options);
+ request.dispatch();
+ event.stopPropagation();
+ }
+ },
+
+ getUpdatedChoices : function(request, callback)
+ {
+ var lastTerm = this.extractLastTerm(request.term);
+ var params = new Array(lastTerm, "__TJuiAutoComplete_onSuggest__");
+ var options = jQuery.extend(this.options, {
+ 'autocompleteCallback' : callback
+ });
+ Prado.Callback(this.options.EventTarget, params, this.onComplete.bind(this), this.options);
+ },
+
+ extractLastTerm: function(string)
+ {
+ var re = new RegExp("[" + (this.options.Separators || '') + "]");
+ return string.split(re).pop().trim();
+ },
+
+ /**
+ * Overrides parent implements, don't update if no results.
+ */
+ selectEntry: function(event, ui) {
+ var value = event.target.value;
+ var lastTerm = this.extractLastTerm(value);
+
+ // strip (possibly) incomplete last part
+ var previousTerms = value.substr(0, value.length - lastTerm.length);
+ // and append selected value
+ ui.item.value = previousTerms + ui.item.value;
+
+ //ui.item.value = event.target.value;
+ var options = [ui.item.id, "__TJuiAutoComplete_onSuggestionSelected__"];
+ Prado.Callback(this.options.EventTarget, options, null, this.options);
+ },
+
+
+ onComplete : function(request, result)
+ {
+ var that = this;
+ if(that.options.textCssClass===undefined)
+ {
+ jQuery.each(result, function(idx, item) {
+ result[idx]['value']=jQuery.trim(jQuery('<div/>').html(item['label']).text());
+ });
+ } else {
+ jQuery.each(result, function(idx, item) {
+ result[idx]['value']=jQuery.trim(jQuery('<div/>').html(item['label']).find('.'+that.options.textCssClass).text());
+ });
+ }
+
+ request.options.autocompleteCallback(result);
+ }
+});
+
+/**
+ * Time Triggered Callback class.
+ */
+Prado.WebUI.TTimeTriggeredCallback = jQuery.klass(Prado.WebUI.Control,
+{
+ onInit : function(options)
+ {
+ this.options = jQuery.extend({ Interval : 1 }, options || {});
+ Prado.WebUI.TTimeTriggeredCallback.registerTimer(this);
+ },
+
+ startTimer : function()
+ {
+ if(typeof(this.timer) == 'undefined' || this.timer == null)
+ this.timer = this.setInterval(this.onTimerEvent.bind(this),this.options.Interval*1000);
+ },
+
+ stopTimer : function()
+ {
+ if(typeof(this.timer) != 'undefined')
+ {
+ this.clearInterval(this.timer);
+ this.timer = null;
+ }
+ },
+
+ resetTimer : function()
+ {
+ if(typeof(this.timer) != 'undefined')
+ {
+ this.clearInterval(this.timer);
+ this.timer = null;
+ this.timer = this.setInterval(this.onTimerEvent.bind(this),this.options.Interval*1000);
+ }
+ },
+
+ onTimerEvent : function()
+ {
+ var request = new Prado.CallbackRequest(this.options.EventTarget, this.options);
+ request.dispatch();
+ },
+
+ setTimerInterval : function(value)
+ {
+ if (this.options.Interval != value){
+ this.options.Interval = value;
+ this.resetTimer();
+ }
+ },
+
+ onDone: function()
+ {
+ this.stopTimer();
+ }
+});
+
+jQuery.extend(Prado.WebUI.TTimeTriggeredCallback,
+{
+
+ //class methods
+
+ timers : {},
+
+ registerTimer : function(timer)
+ {
+ Prado.WebUI.TTimeTriggeredCallback.timers[timer.options.ID] = timer;
+ },
+
+ start : function(id)
+ {
+ if(Prado.WebUI.TTimeTriggeredCallback.timers[id])
+ Prado.WebUI.TTimeTriggeredCallback.timers[id].startTimer();
+ },
+
+ stop : function(id)
+ {
+ if(Prado.WebUI.TTimeTriggeredCallback.timers[id])
+ Prado.WebUI.TTimeTriggeredCallback.timers[id].stopTimer();
+ },
+
+ setTimerInterval : function (id,value)
+ {
+ if(Prado.WebUI.TTimeTriggeredCallback.timers[id])
+ Prado.WebUI.TTimeTriggeredCallback.timers[id].setTimerInterval(value);
+ }
+});
+
+Prado.WebUI.ActiveListControl = jQuery.klass(Prado.WebUI.Control,
+{
+ onInit : function(options)
+ {
+ if(this.element)
+ {
+ this.options = options;
+ this.observe(this.element, "change", this.doCallback.bind(this));
+ }
+ },
+
+ doCallback : function(event)
+ {
+ var request = new Prado.CallbackRequest(this.options.EventTarget, this.options);
+ request.dispatch();
+ event.preventDefault();
+ }
+});
+
+Prado.WebUI.TActiveDropDownList = jQuery.klass(Prado.WebUI.ActiveListControl);
+Prado.WebUI.TActiveListBox = jQuery.klass(Prado.WebUI.ActiveListControl);
+
+/**
+ * Observe event of a particular control to trigger a callback request.
+ */
+Prado.WebUI.TEventTriggeredCallback = jQuery.klass(Prado.WebUI.Control,
+{
+ onInit : function(options)
+ {
+ this.options = options || {} ;
+ var element = jQuery('#'+options['ControlID']).get(0);
+ if(element)
+ this.observe(element, this.getEventName(element), this.doCallback.bind(this));
+ },
+
+ getEventName : function(element)
+ {
+ var name = this.options.EventName;
+ if(typeof(name) == "undefined" && element.type)
+ {
+ switch (element.type.toLowerCase())
+ {
+ case 'password':
+ case 'text':
+ case 'textarea':
+ case 'select-one':
+ case 'select-multiple':
+ return 'change';
+ }
+ }
+ return typeof(name) == "undefined" || name == "undefined" ? 'click' : name;
+ },
+
+ doCallback : function(event)
+ {
+ var request = new Prado.CallbackRequest(this.options.EventTarget, this.options);
+ request.dispatch();
+ if(this.options.StopEvent == true)
+ event.preventDefault();
+ }
+});
+
+/**
+ * Observe changes to a property of a particular control to trigger a callback.
+ */
+Prado.WebUI.TValueTriggeredCallback = jQuery.klass(Prado.WebUI.Control,
+{
+ count : 1,
+
+ observing : true,
+
+ onInit : function(options)
+ {
+ this.options = options || {} ;
+ this.options.PropertyName = this.options.PropertyName || 'value';
+ var element = jQuery('#'+options['ControlID']).get(0);
+ this.value = element ? element[this.options.PropertyName] : undefined;
+ Prado.WebUI.TValueTriggeredCallback.register(this);
+ this.startObserving();
+ },
+
+ stopObserving : function()
+ {
+ this.clearTimeout(this.timer);
+ this.observing = false;
+ },
+
+ startObserving : function()
+ {
+ this.timer = this.setTimeout(this.checkChanges.bind(this), this.options.Interval*1000);
+ },
+
+ checkChanges : function()
+ {
+ var element = jQuery('#'+this.options.ControlID).get(0);
+ if(element)
+ {
+ var value = element[this.options.PropertyName];
+ if(this.value != value)
+ {
+ this.doCallback(this.value, value);
+ this.value = value;
+ this.count=1;
+ }
+ else
+ this.count = this.count + this.options.Decay;
+ if(this.observing)
+ this.time = this.setTimeout(this.checkChanges.bind(this),
+ parseInt(this.options.Interval*1000*this.count));
+ }
+ },
+
+ doCallback : function(oldValue, newValue)
+ {
+ var request = new Prado.CallbackRequest(this.options.EventTarget, this.options);
+ var param = {'OldValue' : oldValue, 'NewValue' : newValue};
+ request.setCallbackParameter(param);
+ request.dispatch();
+ },
+
+ onDone : function()
+ {
+ if (this.observing)
+ this.stopObserving();
+ }
+});
+
+jQuery.extend(Prado.WebUI.TValueTriggeredCallback,
+{
+ //class methods
+
+ timers : {},
+
+ register : function(timer)
+ {
+ Prado.WebUI.TValueTriggeredCallback.timers[timer.options.ID] = timer;
+ },
+
+ stop : function(id)
+ {
+ Prado.WebUI.TValueTriggeredCallback.timers[id].stopObserving();
+ }
+});
+
+Prado.WebUI.TActiveTableCell = jQuery.klass(Prado.WebUI.CallbackControl);
+Prado.WebUI.TActiveTableRow = jQuery.klass(Prado.WebUI.CallbackControl);
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/activedatepicker.js b/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/activedatepicker.js
new file mode 100755
index 0000000..dd0fc6f
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/activedatepicker.js
@@ -0,0 +1,87 @@
+/**
+ * TActiveDatePicker control
+ */
+Prado.WebUI.TActiveDatePicker = jQuery.klass(Prado.WebUI.TDatePicker,
+{
+ onInit : function(options)
+ {
+ this.options = options || [];
+ this.control = jQuery('#'+options.ID).get(0);
+ this.dateSlot = new Array(42);
+ this.weekSlot = new Array(6);
+ this.minimalDaysInFirstWeek = 4;
+ this.selectedDate = this.newDate();
+ this.positionMode = 'Bottom';
+
+
+ //which element to trigger to show the calendar
+ if(this.options.Trigger)
+ {
+ this.trigger = jQuery('#'+this.options.Trigger).get(0) ;
+ var triggerEvent = this.options.TriggerEvent || "click";
+ }
+ else
+ {
+ this.trigger = this.control;
+ var triggerEvent = this.options.TriggerEvent || "focus";
+ }
+
+ // Popup position
+ if(this.options.PositionMode == 'Top')
+ {
+ this.positionMode = this.options.PositionMode;
+ }
+
+ jQuery.extend(this,options);
+
+ if (this.options.ShowCalendar)
+ this.observe(this.trigger, triggerEvent, jQuery.proxy(this.show,this));
+
+ // Listen to change event
+ if(this.options.InputMode == "TextBox")
+ {
+ this.observe(this.control, "change", jQuery.proxy(this.onDateChanged,this));
+ }
+ else
+ {
+ var day = Prado.WebUI.TDatePicker.getDayListControl(this.control);
+ var month = Prado.WebUI.TDatePicker.getMonthListControl(this.control);
+ var year = Prado.WebUI.TDatePicker.getYearListControl(this.control);
+ if (day) this.observe (day, "change", jQuery.proxy(this.onDateChanged,this));
+ if (month) this.observe (month, "change", jQuery.proxy(this.onDateChanged,this));
+ if (year) this.observe (year, "change", jQuery.proxy(this.onDateChanged,this));
+
+ }
+
+ },
+
+ // Respond to change event on the textbox or dropdown list
+ // This method raises OnDateChanged event on client side if it has been defined,
+ // and raise the callback request
+ onDateChanged : function ()
+ {
+ var date;
+ if (this.options.InputMode == "TextBox")
+ {
+ date=this.control.value;
+ }
+ else
+ {
+ var day = Prado.WebUI.TDatePicker.getDayListControl(this.control);
+ if (day) day=day.selectedIndex+1;
+ var month = Prado.WebUI.TDatePicker.getMonthListControl(this.control);
+ if (month) month=month.selectedIndex;
+ var year = Prado.WebUI.TDatePicker.getYearListControl(this.control);
+ if (year) year=year.value;
+ date=new Date(year, month, day, 0,0,0).SimpleFormat(this.Format, this);
+ }
+ if (typeof(this.options.OnDateChanged) == "function") this.options.OnDateChanged(this, date);
+
+ if(this.options['AutoPostBack']==true)
+ {
+ // Make callback request
+ var request = new Prado.CallbackRequest(this.options.EventTarget,this.options);
+ request.dispatch();
+ }
+ }
+});
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/ajax3.js b/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/ajax3.js
new file mode 100644
index 0000000..e0e67ce
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/ajax3.js
@@ -0,0 +1,996 @@
+Prado.CallbackRequestManager =
+{
+ /**
+ * Callback request target POST field name.
+ */
+ FIELD_CALLBACK_TARGET : 'PRADO_CALLBACK_TARGET',
+ /**
+ * Callback request parameter POST field name.
+ */
+ FIELD_CALLBACK_PARAMETER : 'PRADO_CALLBACK_PARAMETER',
+ /**
+ * Callback request page state field name,
+ */
+ FIELD_CALLBACK_PAGESTATE : 'PRADO_PAGESTATE',
+ /**
+ * Response redirect header name.
+ */
+ REDIRECT_HEADER : 'X-PRADO-REDIRECT',
+ /**
+ * Response data header name.
+ */
+ DATA_HEADER : 'X-PRADO-DATA',
+ /**
+ * Response javascript execution statement header name.
+ */
+ ACTION_HEADER : 'X-PRADO-ACTIONS',
+ /**
+ * Response errors/exceptions header name.
+ */
+ ERROR_HEADER : 'X-PRADO-ERROR',
+ /**
+ * Page state header name.
+ */
+ PAGESTATE_HEADER : 'X-PRADO-PAGESTATE',
+ /**
+ * Script list header name.
+ */
+ SCRIPTLIST_HEADER : 'X-PRADO-SCRIPTLIST',
+ /**
+ * Stylesheet code header name.
+ */
+ STYLESHEET_HEADER : 'X-PRADO-STYLESHEET',
+ /**
+ * Stylesheet list header name.
+ */
+ STYLESHEETLIST_HEADER : 'X-PRADO-STYLESHEETLIST',
+ /**
+ * Hidden field list header name.
+ */
+ HIDDENFIELDLIST_HEADER : 'X-PRADO-HIDDENFIELDLIST',
+ /**
+ * Log debug informations when a callback fails, default true
+ */
+ LOG_ERROR : true,
+ /**
+ * Log debug informations when a callback succedes, default false
+ */
+ LOG_SUCCESS : false,
+
+ /**
+ * Formats the exception message for display in console.
+ */
+ formatException : function(e)
+ {
+ var msg = e.type + " with message \""+e.message+"\"";
+ msg += " in "+e.file+"("+e.line+")\n";
+ msg += "Stack trace:\n";
+ var trace = e.trace;
+ for(var i = 0; i<trace.length; i++)
+ {
+ msg += " #"+i+" "+trace[i].file;
+ msg += "("+trace[i].line+"): ";
+ msg += trace[i]["class"]+"->"+trace[i]["function"]+"()"+"\n";
+ }
+ msg += e.version+" "+e.time+"\n";
+ return msg;
+ },
+
+ /*! jQuery Ajax Queue - v0.1.2pre - 2013-03-19
+ * https://github.com/gnarf37/jquery-ajaxQueue
+ * Copyright (c) 2013 Corey Frang; Licensed MIT
+ * Slightly adapted for use within prado by Fabio Bas <ctrlaltca@gmail.com>
+ */
+
+ // jQuery on an empty object, we are going to use this as our Queue
+ ajaxQueue : jQuery({}),
+
+ ajax : function( ajaxOpts ) {
+ var jqXHR,
+ dfd = jQuery.Deferred(),
+ promise = dfd.promise();
+
+ // run the actual query
+ function doRequest( next ) {
+ jqXHR = jQuery.ajax( ajaxOpts );
+ jqXHR.done( dfd.resolve )
+ .fail( dfd.reject )
+ .then( next, next );
+ }
+
+ // queue our ajax request
+ Prado.CallbackRequestManager.ajaxQueue.queue( doRequest );
+
+ // add the abort method
+ promise.abort = function( statusText ) {
+
+ // proxy abort to the jqXHR if it is active
+ if ( jqXHR ) {
+ return jqXHR.abort( statusText );
+ }
+
+ // if there wasn't already a jqXHR we need to remove from queue
+ var queue = Prado.CallbackRequestManager.ajaxQueue.queue(),
+ index = jQuery.inArray( doRequest, queue );
+
+ if ( index > -1 ) {
+ queue.splice( index, 1 );
+ }
+
+ // and then reject the deferred
+ dfd.rejectWith( ajaxOpts.context || ajaxOpts, [ promise, statusText, "" ] );
+ return promise;
+ };
+
+ return promise;
+ }
+};
+
+Prado.CallbackRequest = jQuery.klass(Prado.PostBack,
+{
+
+ options : {},
+ data : '',
+
+ initialize: function(id, options)
+ {
+ this.options = {
+ RequestTimeOut : 30000, // 30 second timeout.
+ EnablePageStateUpdate : true,
+ CausesValidation : true,
+ ValidationGroup : null,
+ PostInputs : true,
+
+ type: "POST",
+ context: this,
+ success: this.successHandler,
+ error: this.errorHandler,
+ complete: this.completeHandler
+ };
+
+ jQuery.extend(this.options, options || {});
+
+ if(this.options.onUninitialized)
+ this.options.onUninitialized(this,null);
+ },
+
+ /**
+ * Sets the request options
+ * @return {Array} request options.
+ */
+ setOptions: function(options) {
+ jQuery.extend(this.options, options || { });
+ },
+
+ getForm: function()
+ {
+ return jQuery('#'+this.options.ID).parents('form:first').get(0) || jQuery('#PRADO_PAGESTATE').get(0).form;
+ },
+
+ /**
+ * Gets the url from the forms that contains the PRADO_PAGESTATE
+ * @return {String} callback url.
+ */
+ getCallbackUrl : function()
+ {
+ return this.getForm().action;
+ },
+
+ /**
+ * Sets the request parameter
+ * @param {Object} parameter value
+ */
+ setCallbackParameter : function(value)
+ {
+ this.options['CallbackParameter'] = value;
+ },
+
+ /**
+ * @return {Object} request paramater value.
+ */
+ getCallbackParameter : function()
+ {
+ return JSON.stringify(this.options['CallbackParameter']);
+ },
+
+ /**
+ * Sets the callback request timeout.
+ * @param {integer} timeout in milliseconds
+ */
+ setRequestTimeOut : function(timeout)
+ {
+ this.options['RequestTimeOut'] = timeout;
+ },
+
+ /**
+ * @return {integer} request timeout in milliseconds
+ */
+ getRequestTimeOut : function()
+ {
+ return this.options['RequestTimeOut'];
+ },
+
+ /**
+ * Set true to enable validation on callback dispatch.
+ * @param {boolean} true to validate
+ */
+ setCausesValidation : function(validate)
+ {
+ this.options['CausesValidation'] = validate;
+ },
+
+ /**
+ * @return {boolean} validate on request dispatch
+ */
+ getCausesValidation : function()
+ {
+ return this.options['CausesValidation'];
+ },
+
+ /**
+ * Sets the validation group to validate during request dispatch.
+ * @param {string} validation group name
+ */
+ setValidationGroup : function(group)
+ {
+ this.options['ValidationGroup'] = group;
+ },
+
+ /**
+ * @return {string} validation group name.
+ */
+ getValidationGroup : function()
+ {
+ return this.options['ValidationGroup'];
+ },
+
+ dispatch: function()
+ {
+ //trigger tinyMCE to save data.
+ if(typeof tinyMCE != "undefined")
+ tinyMCE.triggerSave();
+
+ if(this.options['CausesValidation'] && typeof(Prado.Validation) != "undefined")
+ {
+ if(!Prado.Validation.validate(this.getForm().id, this.options['ValidationGroup'], this))
+ return false;
+ }
+
+ if(this.options.onPreDispatch)
+ this.options.onPreDispatch(this,null);
+
+ // jQuery don't have all these states.. simulate them to avoid breaking old scripts
+ if (this.options.onLoading)
+ this.options.onLoading(this,null);
+ if (this.options.onLoaded)
+ this.options.onLoaded(this,null);
+ if (this.options.onInteractive)
+ this.options.onInteractive(this,null);
+
+ // go!
+ this.options.data = this.getParameters();
+ this.options.url = this.getCallbackUrl();
+
+ this.request = Prado.CallbackRequestManager.ajax(this.options);
+ },
+
+ abort : function()
+ {
+ if(this.request != "undefined")
+ this.request.abort();
+ },
+
+ /**
+ * Collects the form inputs, encode the parameters, and sets the callback
+ * target id. The resulting string is the request content body.
+ * @return string request body content containing post data.
+ */
+ getParameters : function()
+ {
+ var data = {};
+
+ if(typeof(this.options.CallbackParameter) != "undefined")
+ data[Prado.CallbackRequestManager.FIELD_CALLBACK_PARAMETER] = this.getCallbackParameter();
+ if(this.options.EventTarget)
+ data[Prado.CallbackRequestManager.FIELD_CALLBACK_TARGET] = this.options.EventTarget;
+
+ if(this.options.PostInputs != false)
+ {
+ var form = this.getForm();
+ return jQuery(form).serialize() + '&' + jQuery.param(data);
+ } else {
+ var pagestate = jQuery("#"+Prado.CallbackRequestManager.FIELD_CALLBACK_PAGESTATE);
+ if(pagestate)
+ data[Prado.CallbackRequestManager.FIELD_CALLBACK_PAGESTATE] = pagestate.val();
+ return jQuery.param(data);
+ }
+ },
+
+ /**
+ * Extract content from a text by its boundary id.
+ * Boundaries have this form:
+ * <pre>
+ * &lt;!--123456--&gt;Democontent&lt;!--//123456--&gt;
+ * </pre>
+ * @function {string} ?
+ * @param {string} boundary - Boundary id
+ * @returns Content from given boundaries
+ */
+ extractContent: function (boundary)
+ {
+ var tagStart = '<!--'+boundary+'-->';
+ var tagEnd = '<!--//'+boundary+'-->';
+ var start = this.data.indexOf(tagStart);
+ if(start > -1)
+ {
+ start += tagStart.length;
+ var end = this.data.indexOf(tagEnd,start);
+ if(end > -1)
+ return this.data.substring(start,end);
+ }
+ return null;
+ },
+
+ getLogger: function()
+ {
+ if(typeof Logger != "undefined")
+ return Logger;
+
+ // use the browser console if no Logger is available
+ if(typeof console != "undefined")
+ return console;
+
+ return null;
+ },
+
+ errorHandler: function(request, textStatus, errorThrown)
+ {
+ this.data = request.responseText;
+
+ if(Prado.CallbackRequestManager.LOG_ERROR && (log = this.getLogger()))
+ {
+ log.error("PRADO Ajax callback error:", request.status, "(" + request.statusText + ")");
+ if(request.status==500)
+ {
+ /**
+ * Server returns 500 exception. Just log it.
+ */
+ var errorData = this.extractContent(Prado.CallbackRequestManager.ERROR_HEADER);
+ if (typeof(errorData) == "string" && errorData.length > 0)
+ {
+ errorData = jQuery.parseJSON(errorData);
+ if(typeof(errorData) == "object")
+ log.info(Prado.CallbackRequestManager.formatException(errorData));
+ }
+ }
+ }
+
+ if (this.options.onFailure)
+ this.options.onFailure(this,textStatus);
+ },
+
+ completeHandler: function(request, textStatus)
+ {
+//"success", "notmodified", "error", "timeout", "abort", or "parsererror"
+ if (this.options.onComplete)
+ this.options.onComplete(this,textStatus);
+ },
+
+ /**
+ * Uncaught exceptions during callback response.
+ */
+ exceptionHandler: function(e)
+ {
+ if(Prado.CallbackRequestManager.LOG_ERROR && (log = this.getLogger()))
+ {
+ log.error("Uncaught Callback Client Exception:", e.message);
+ log.info('Stack:', e.stack);
+ } else {
+ debugger;
+ }
+
+ if (this.options.onException)
+ this.options.onException(this,e);
+ },
+
+ /**
+ * Callback OnSuccess event,logs reponse and data to console.
+ */
+ successHandler: function(data, textStatus, request)
+ {
+ this.data = data;
+
+ if(Prado.CallbackRequestManager.LOG_SUCCESS && (log = this.getLogger()))
+ {
+ log.info('HTTP '+request.status+" with response : \n");
+
+ var tagStart = '<!--';
+ var tagEnd = '<!--//';
+ var start = request.responseText.indexOf(tagStart);
+ while(start > -1)
+ {
+ var end = request.responseText.indexOf(tagEnd,start);
+ if(end > -1)
+ log.info(request.responseText.substring(start,end)+'\n');
+ start = request.responseText.indexOf(tagStart,end+6);
+ }
+ }
+
+ if (this.options.onSuccess)
+ {
+ var customData=this.extractContent(Prado.CallbackRequestManager.DATA_HEADER);
+ if (typeof(customData) == "string" && customData.length > 0)
+ customData = jQuery.parseJSON(customData);
+
+ this.options.onSuccess(this,customData);
+ }
+
+ var redirectUrl = this.extractContent(Prado.CallbackRequestManager.REDIRECT_HEADER);
+ if (redirectUrl)
+ document.location.href = redirectUrl;
+
+ try {
+ this.updatePageState(this, data);
+ this.checkHiddenFields(this, data);
+ var obj = this;
+ this.loadAssets(this, data, function()
+ {
+ try {
+ obj.dispatchActions(obj, data);
+ } catch (e) {
+ obj.exceptionHandler(e);
+ }
+ }
+ );
+
+ } catch (e) {
+ this.exceptionHandler(e);
+ }
+ },
+
+ /**
+ * Updates the page state. It will update only if EnablePageStateUpdate and
+ * HasPriority options are both true.
+ */
+ updatePageState : function(request, datain)
+ {
+ var pagestate = jQuery("#"+Prado.CallbackRequestManager.FIELD_CALLBACK_PAGESTATE);
+ var enabled = request.options.EnablePageStateUpdate;
+ var aborted = false; //typeof(self.currentRequest) == 'undefined' || self.currentRequest == null;
+ if(enabled && !aborted && pagestate)
+ {
+ var data = this.extractContent(Prado.CallbackRequestManager.PAGESTATE_HEADER);
+ if(typeof(data) == "string" && data.length > 0)
+ pagestate.val(data);
+ else
+ {
+ if(Prado.CallbackRequestManager.LOG_ERROR && (log = this.getLogger()))
+ log.warn("Missing page state:"+data);
+ //Logger.warn('## bad state: setting current request to null');
+ //self.endCurrentRequest();
+ //self.tryNextRequest();
+ return false;
+ }
+ }
+ //self.endCurrentRequest();
+ //Logger.warn('## state updated: setting current request to null');
+ //self.tryNextRequest();
+ return true;
+ },
+
+ checkHiddenField: function(name, value)
+ {
+ var id = name.replace(':','_');
+ if (!document.getElementById(id))
+ {
+ var field = document.createElement('input');
+ field.setAttribute('type','hidden');
+ field.id = id;
+ field.name = name;
+ field.value = value;
+ document.body.appendChild(field);
+ }
+ },
+
+ checkHiddenFields : function(request, datain)
+ {
+ var data = this.extractContent(Prado.CallbackRequestManager.HIDDENFIELDLIST_HEADER);
+ if (typeof(data) == "string" && data.length > 0)
+ {
+ json = jQuery.parseJSON(data);
+ if(typeof(json) != "object")
+ {
+ if(Prado.CallbackRequestManager.LOG_ERROR && (log = this.getLogger()))
+ log.warn("Invalid hidden field list:"+data);
+ } else {
+ for(var key in json)
+ this.checkHiddenField(key,json[key]);
+ }
+ }
+ },
+
+ /*
+ * Checks which assets are used by the response and ensures they're loaded
+ */
+ loadAssets : function(request, datain, callback)
+ {
+ /*
+
+ ! This is the callback-based loader for stylesheets, which loads them one-by-one, and
+ ! waits for all of them to be loaded before loading scripts and processing the rest of
+ ! the callback.
+ !
+ ! That however is not neccessary, as stylesheets can be loaded asynchronously too.
+ !
+ ! I leave this code here for the case that this turns out to be a compatibility issue
+ ! (for ex. I can imagine some scripts trying to access stylesheet properties and such)
+ ! so if need can be reactivated. If you do so, comment out the async stylesheet loader below!
+
+ var obj = this;
+ this.loadStyleSheets(request,transport, function() {
+ obj.loadScripts(request,transport,callback);
+ });
+
+ */
+
+ this.loadStyleSheetsCode(request,datain);
+
+ this.loadStyleSheetsAsync(request,datain);
+
+ this.loadScripts(request,datain,callback);
+ },
+
+ /*
+ * Checks which scripts are used by the response and ensures they're loaded
+ */
+ loadScripts : function(request, datain, callback)
+ {
+ var data = this.extractContent(Prado.CallbackRequestManager.SCRIPTLIST_HEADER);
+ if (!this.ScriptsToLoad) this.ScriptsToLoad = new Array();
+ this.ScriptLoadFinishedCallback = callback;
+ if (typeof(data) == "string" && data.length > 0)
+ {
+ json = jQuery.parseJSON(data);
+ if(typeof(json) != "object")
+ {
+ if(Prado.CallbackRequestManager.LOG_ERROR && (log = this.getLogger()))
+ log.warn("Invalid script list:"+data);
+ } else {
+ for(var key in json)
+ if (/^\d+$/.test(key))
+ {
+ var url = json[key];
+ if (!Prado.ScriptManager.isAssetLoaded(url))
+ this.ScriptsToLoad.push(url);
+ }
+ }
+ }
+ this.loadNextScript();
+ },
+
+ loadNextScript: function()
+ {
+ var done = (!this.ScriptsToLoad || (this.ScriptsToLoad.length==0));
+ if (!done)
+ {
+ var url = this.ScriptsToLoad.shift(); var obj = this;
+ if (
+ Prado.ScriptManager.ensureAssetIsLoaded(url,
+ function() {
+ obj.loadNextScript();
+ }
+ )
+ )
+ this.loadNextScript();
+ }
+ else
+ {
+ if (this.ScriptLoadFinishedCallback)
+ {
+ var cb = this.ScriptLoadFinishedCallback;
+ this.ScriptLoadFinishedCallback = null;
+ cb();
+ }
+ }
+ },
+
+ loadStyleSheetsCode : function(request, datain)
+ {
+ var data = this.extractContent(Prado.CallbackRequestManager.STYLESHEET_HEADER);
+ if (typeof(data) == "string" && data.length > 0)
+ {
+ json = jQuery.parseJSON(data);
+ if(typeof(json) != "object")
+ {
+ if(Prado.CallbackRequestManager.LOG_ERROR && (log = this.getLogger()))
+ log.warn("Invalid stylesheet list:"+data);
+ } else {
+ for(var key in json)
+ if (/^\d+$/.test(key))
+ Prado.StyleSheetManager.createStyleSheetCode(json[key],null);
+ }
+ }
+ },
+
+ loadStyleSheetsAsync : function(request, datain)
+ {
+ var data = this.extractContent(Prado.CallbackRequestManager.STYLESHEETLIST_HEADER);
+ if (typeof(data) == "string" && data.length > 0)
+ {
+ json = jQuery.parseJSON(data);
+ if(typeof(json) != "object")
+ {
+ if(Prado.CallbackRequestManager.LOG_ERROR && (log = this.getLogger()))
+ log.warn("Invalid stylesheet list:"+data);
+ } else {
+ for(var key in json)
+ if (/^\d+$/.test(key))
+ Prado.StyleSheetManager.ensureAssetIsLoaded(json[key],null);
+ }
+ }
+ },
+
+ loadStyleSheets : function(request, datain, callback)
+ {
+ var data = this.extractContent(Prado.CallbackRequestManager.STYLESHEETLIST_HEADER);
+ if (!this.StyleSheetsToLoad) this.StyleSheetsToLoad = new Array();
+ this.StyleSheetLoadFinishedCallback = callback;
+ if (typeof(data) == "string" && data.length > 0)
+ {
+ json = jQuery.parseJSON(data);
+ if(typeof(json) != "object")
+ {
+ if(Prado.CallbackRequestManager.LOG_ERROR && (log = this.getLogger()))
+ log.warn("Invalid stylesheet list:"+data);
+ } else {
+ for(var key in json)
+ if (/^\d+$/.test(key))
+ {
+ var url = json[key];
+ if (!Prado.StyleSheetManager.isAssetLoaded(url))
+ this.StyleSheetsToLoad.push(url);
+ }
+ }
+ }
+ this.loadNextStyleSheet();
+ },
+
+ loadNextStyleSheet: function()
+ {
+ var done = (!this.StyleSheetsToLoad || (this.StyleSheetsToLoad.length==0));
+ if (!done)
+ {
+ var url = this.StyleSheetsToLoad.shift(); var obj = this;
+ if (
+ Prado.StyleSheetManager.ensureAssetIsLoaded(url,
+ function() {
+ obj.loadNextStyleSheet();
+ }
+ )
+ )
+ this.loadNextStyleSheet();
+ } else {
+ if (this.StyleSheetLoadFinishedCallback)
+ {
+ var cb = this.StyleSheetLoadFinishedCallback;
+ this.StyleSheetLoadFinishedCallback = null;
+ cb();
+ }
+ }
+ },
+
+ /**
+ * Dispatch callback response actions.
+ */
+ dispatchActions : function(request, datain)
+ {
+ var data = this.extractContent(Prado.CallbackRequestManager.ACTION_HEADER);
+ if (typeof(data) == "string" && data.length > 0)
+ {
+ json = jQuery.parseJSON(data);
+ if(typeof(json) != "object")
+ {
+ if(Prado.CallbackRequestManager.LOG_ERROR && (log = this.getLogger()))
+ log.warn("Invalid action:"+data);
+ } else {
+ var that = this;
+ jQuery.each(json, function(idx, item){
+ that.__run(that, item);
+ });
+ }
+ }
+ },
+
+ /**
+ * Prase and evaluate a Callback clien-side action
+ */
+ __run : function(request, command)
+ {
+ for(var method in command)
+ {
+ try {
+ method.toFunction().apply(request,command[method]);
+ } catch(e) {
+ this.exceptionHandler(e);
+ }
+ }
+ }
+});
+
+/**
+ * Create a new callback request using default settings.
+ * @param string callback handler unique ID.
+ * @param mixed parameter to pass to callback handler on the server side.
+ * @param function client side onSuccess event handler.
+ * @param object additional request options.
+ * @return Prado.CallbackRequest request that was created
+ */
+Prado.Callback = function(UniqueID, parameter, onSuccess, options)
+{
+ var callback =
+ {
+ 'EventTarget' : UniqueID || '',
+ 'CallbackParameter' : parameter || '',
+ 'onSuccess' : onSuccess || jQuery.noop()
+ };
+
+ jQuery.extend(callback, options || {});
+
+ var request = new Prado.CallbackRequest(UniqueID, callback);
+ request.dispatch();
+ return request;
+};
+
+/**
+ * Create a new callback request initiated by jQuery-UI elements.
+ * @param event object as sent by jQuery-UI events
+ * @param ui object as sent by jQuery-UI events
+ * @return Prado.CallbackRequest request that was created
+ */
+Prado.JuiCallback = function(UniqueID, eventType, event, ui, target)
+{
+ // Retuns an array of all properties of the object received as parameter and their values.
+ // If a property represent a jQuery element, its id is returnet instead
+ var cleanUi = {};
+ jQuery.each( ui, function( key, value ) {
+ if(value instanceof jQuery)
+ cleanUi[key]=value[0].id;
+ else
+ cleanUi[key]=value;
+ });
+
+ target=jQuery(target);
+ cleanUi['target']= {
+ 'position' : target.position(),
+ 'offset' : target.offset()
+ };
+
+ var callback =
+ {
+ 'EventTarget' : UniqueID,
+ 'CallbackParameter' : {
+ 'event' : eventType,
+ 'ui' : cleanUi
+ }
+ };
+
+ var request = new Prado.CallbackRequest(UniqueID, callback);
+ request.dispatch();
+ return request;
+};
+
+/**
+* Asset manager classes for lazy loading of scripts and stylesheets
+* @author Gabor Berczi (gabor.berczi@devworx.hu)
+*/
+
+if (typeof(Prado.AssetManagerClass)=="undefined") {
+
+ Prado.AssetManagerClass = jQuery.klass();
+ Prado.AssetManagerClass.prototype = {
+
+ initialize: function() {
+ this.loadedAssets = new Array();
+ this.discoverLoadedAssets();
+ },
+
+
+ /**
+ * Detect which assets are already loaded by page markup.
+ * This is done by looking up all <asset> elements and registering the values of their src attributes.
+ */
+ discoverLoadedAssets: function() {
+
+ // wait until document has finished loading to avoid javascript errors
+ if (!document.body) return;
+
+ var assets = this.findAssetUrlsInMarkup();
+ for(var i=0;i<assets.length;i++)
+ this.markAssetAsLoaded(assets[i]);
+ },
+
+ /**
+ * Extend url to a fully qualified url.
+ * @param string url
+ */
+ makeFullUrl: function(url) {
+
+ // this is not intended to be a fully blown url "canonicalizator",
+ // just to handle the most common and basic asset paths used by Prado
+
+ if (!this.baseUri) this.baseUri = window.location;
+
+ if (url.indexOf('://')==-1)
+ {
+ var a = document.createElement('a');
+ a.href = url;
+
+ if (a.href.indexOf('://')!=-1)
+ url = a.href;
+ else
+ {
+ var path = a.pathname;
+ if (path.substr(0,1)!='/') path = '/'+path;
+ url = this.baseUri.protocol+'//'+this.baseUri.host+path;
+ }
+ }
+ return url;
+ },
+
+ isAssetLoaded: function(url) {
+ url = this.makeFullUrl(url);
+ return (jQuery.inArray(url, this.loadedAssets)!=-1);
+ },
+
+ /**
+ * Mark asset as being already loaded
+ * @param string url of the asset
+ */
+ markAssetAsLoaded: function(url) {
+ url = this.makeFullUrl(url);
+ if (jQuery.inArray(url, this.loadedAssets)==-1)
+ this.loadedAssets.push(url);
+ },
+
+ assetReadyStateChanged: function(url, element, callback, finalevent) {
+ if (finalevent || (element.readyState == 'loaded') || (element.readyState == 'complete'))
+ if (!element.assetCallbackFired)
+ {
+ element.assetCallbackFired = true;
+ callback(url,element);
+ }
+ },
+
+ assetLoadFailed: function(url, element, callback) {
+ debugger;
+ element.assetCallbackFired = true;
+ if(Prado.CallbackRequestManager.LOG_ERROR && (log = this.getLogger()))
+ log.error("Failed to load asset: "+url, this);
+ if (!element.assetCallbackFired)
+ callback(url,element,false);
+ },
+
+ /**
+ * Load a new asset dynamically into the page.
+ * Please not thet loading is asynchronous and therefore you can't assume that
+ * the asset is loaded and ready when returning from this function.
+ * @param string url of the asset to load
+ * @param callback will be called when the asset has loaded (or failed to load)
+ */
+ startAssetLoad: function(url, callback) {
+
+ // create new <asset> element in page header
+ var asset = this.createAssetElement(url);
+
+ if (callback)
+ {
+ asset.onreadystatechange = this.assetReadyStateChanged.bind(this, url, asset, callback, false);
+ asset.onload = this.assetReadyStateChanged.bind(this, url, asset, callback, true);
+ asset.onerror = this.assetLoadFailed.bind(this, url, asset, callback);
+ asset.assetCallbackFired = false;
+ }
+
+ var head = document.getElementsByTagName('head')[0];
+ head.appendChild(asset);
+
+ // mark this asset as loaded
+ this.markAssetAsLoaded(url);
+
+ return (callback!=false);
+ },
+
+ /**
+ * Check whether a asset is loaded into the page, and if itsn't, load it now
+ * @param string url of the asset to check/load
+ * @return boolean returns true if asset is already loaded, or false, if loading has just started. callback will be called when loading has finished.
+ */
+ ensureAssetIsLoaded: function(url, callback) {
+ url = this.makeFullUrl(url);
+ if (jQuery.inArray(url, this.loadedAssets)==-1)
+ {
+ this.startAssetLoad(url,callback);
+ return false;
+ }
+ else
+ return true;
+ }
+
+ }
+
+};
+
+Prado.ScriptManagerClass = jQuery.klass(Prado.AssetManagerClass, {
+
+ findAssetUrlsInMarkup: function() {
+ var urls = new Array();
+ var scripts = document.getElementsByTagName('script');
+ for(var i=0;i<scripts.length;i++)
+ {
+ var e = scripts[i]; var src = e.src;
+ if (src!="")
+ urls.push(src);
+ }
+ return urls;
+ },
+
+ createAssetElement: function(url) {
+ var asset = document.createElement('script');
+ asset.type = 'text/javascript';
+ asset.src = url;
+ // asset.async = false; // HTML5 only
+ return asset;
+ }
+
+});
+
+Prado.StyleSheetManagerClass = jQuery.klass(Prado.AssetManagerClass, {
+
+ findAssetUrlsInMarkup: function() {
+ var urls = new Array();
+ var scripts = document.getElementsByTagName('link');
+ for(var i=0;i<scripts.length;i++)
+ {
+ var e = scripts[i]; var href = e.href;
+ if ((e.rel=="stylesheet") && (href.length>0))
+ urls.push(href);
+ }
+ return urls;
+ },
+
+ createAssetElement: function(url) {
+ var asset = document.createElement('link');
+ asset.rel = 'stylesheet';
+ asset.media = 'screen';
+ asset.setAttribute('type', 'text/css');
+ asset.href = url;
+ // asset.async = false; // HTML5 only
+ return asset;
+ },
+
+ createStyleSheetCode: function(code) {
+ var asset = document.createElement('style');
+ asset.setAttribute('type', 'text/css');
+
+ if(asset.styleSheet)
+ asset.styleSheet.cssText = code; // IE7+IE8
+ else {
+ var cssCodeNode = document.createTextNode(code);
+ asset.appendChild(cssCodeNode);
+ }
+
+ var head = document.getElementsByTagName('head')[0];
+ head.appendChild(asset);
+ }
+
+});
+
+if (typeof(Prado.ScriptManager)=="undefined") Prado.ScriptManager = new Prado.ScriptManagerClass();
+if (typeof(Prado.StyleSheetManager)=="undefined") Prado.StyleSheetManager = new Prado.StyleSheetManagerClass();
+
+// make sure we scan for loaded scripts again when the page has been loaded
+var discover = function() {
+ Prado.ScriptManager.discoverLoadedAssets();
+ Prado.StyleSheetManager.discoverLoadedAssets();
+}
+if (window.attachEvent) window.attachEvent('onload', discover);
+else if (window.addEventListener) window.addEventListener('load', discover, false);
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/autocomplete.js b/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/autocomplete.js
new file mode 100644
index 0000000..da5f4b5
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/autocomplete.js
@@ -0,0 +1,83 @@
+jQuery.noConflict();
+
+/**
+ * TAutoComplete control.
+ */
+Prado.WebUI.TAutoComplete = jQuery.klass(Autocompleter.Base, Prado.WebUI.TActiveTextBox.prototype,
+{
+ initialize : function(options)
+ {
+ this.options = options;
+ this.observers = new Array();
+ this.hasResults = false;
+ this.baseInitialize(options.ID, options.ResultPanel, options);
+ Object.extend(this.options,
+ {
+ onSuccess : this.onComplete.bind(this)
+ });
+
+ if(options.AutoPostBack)
+ this.onInit(options);
+
+ Prado.Registry[options.ID] = this;
+ },
+
+ doCallback : function(options, event)
+ {
+ if(!this.active)
+ {
+ var request = new Prado.CallbackRequest(this.options.EventTarget, options);
+ request.dispatch();
+ event.preventDefault();
+ }
+ },
+
+ //Overrides parent implementation, fires onchange event.
+ onClick: function(event)
+ {
+ var element = Event.findElement(event, 'LI');
+ this.index = element.autocompleteIndex;
+ this.selectEntry();
+ this.hide();
+ jQuery(this.element).trigger('change');
+ },
+
+ getUpdatedChoices : function()
+ {
+ var options = new Array(this.getToken(),"__TAutoComplete_onSuggest__");
+ Prado.Callback(this.options.EventTarget, options, null, this.options);
+ },
+
+ /**
+ * Overrides parent implements, don't update if no results.
+ */
+ selectEntry: function()
+ {
+ if(this.hasResults)
+ {
+ this.active = false;
+ this.updateElement(this.getCurrentEntry());
+ var options = [this.index, "__TAutoComplete_onSuggestionSelected__"];
+ Prado.Callback(this.options.EventTarget, options, null, this.options);
+ }
+ },
+
+ onComplete : function(request, boundary)
+ {
+ var result = request.extractContent(boundary);
+ if(typeof(result) == "string")
+ {
+ if(result.length > 0)
+ {
+ this.hasResults = true;
+ this.updateChoices(result);
+ }
+ else
+ {
+ this.active = false;
+ this.hasResults = false;
+ this.hide();
+ }
+ }
+ }
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/dragdrop.js b/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/dragdrop.js
new file mode 100755
index 0000000..9e583c1
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/dragdrop.js
@@ -0,0 +1,63 @@
+jQuery.noConflict();
+
+/**
+ * DropContainer control
+ */
+
+Prado.WebUI.DropContainer = Class.create(Prado.WebUI.CallbackControl,
+{
+ onInit: function(options)
+ {
+ this.options = options;
+ Object.extend (this.options,
+ {
+ onDrop: this.onDrop.bind(this)
+ });
+
+ Droppables.add (options.ID, this.options);
+ },
+
+ onDrop: function(dragElement, dropElement, event)
+ {
+ var elementId=dragElement.id.replace(/clone_/,"");
+ var req = new Prado.CallbackRequest(this.options.EventTarget, this.options);
+ var curleft = curtop = 0;
+ var obj = dropElement;
+ if (obj.offsetParent) {
+ curleft = obj.offsetLeft
+ curtop = obj.offsetTop
+ while (obj = obj.offsetParent) {
+ curleft += obj.offsetLeft
+ curtop += obj.offsetTop
+ }
+ }
+ var scrOfX = 0, scrOfY = 0;
+ if( typeof( window.pageYOffset ) == 'number' ) {
+ //Netscape compliant
+ scrOfY = window.pageYOffset;
+ scrOfX = window.pageXOffset;
+ } else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
+ //DOM compliant
+ scrOfY = document.body.scrollTop;
+ scrOfX = document.body.scrollLeft;
+ } else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
+ //IE6 standards compliant mode
+ scrOfY = document.documentElement.scrollTop;
+ scrOfX = document.documentElement.scrollLeft;
+ }
+ req.setCallbackParameter({
+ DragElementID : elementId,
+ ScreenX : event.screenX,
+ ScreenY : event.screenY,
+ OffsetX : event.offsetX || event.clientX - curleft + scrOfX,
+ OffsetY : event.offsetY || event.clientY - curtop + scrOfY,
+ ClientX : event.clientX,
+ ClientY : event.clientY,
+ AltKey : event.altKey,
+ CtrlKey : event.ctrlKey,
+ ShiftKey : event.shiftKey
+ });
+ req.dispatch();
+
+ }
+});
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/dragdropextra.js b/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/dragdropextra.js
new file mode 100644
index 0000000..1cec6f9
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/dragdropextra.js
@@ -0,0 +1,233 @@
+// DragDropExtra Scriptaculous Enhancement, version 0.5
+// (c) 2007-2008 Christopher Williams, Iterative Designs
+//
+// v0.5 release
+// - Fixed bug where 2nd drag on an element in IE would result in funny placement of the
+// element. [shammond42]
+// v0.4 release
+// - Fixed issue with dragging and dropping in IE7 due to an exception being thrown and not properly reseting in FinishDrag.
+// v0.3 release
+// - Fixed bug found by Phillip Sauerbeck psauerbeck@gmail. Tests added based on Phillip's efforts.
+// v0.2 release
+// - Minor bug fix for the releasing of objects after they have been dropped, prevents memory leak.
+// v0.1 release
+// - initial release for the super ghosting capability
+// - Drags from one scrolling list to the other (overflow:auto)
+// - Retains the original object so that it can remain present despite being dragged
+//
+// dragdropextra.js is freely distributable under the terms of an MIT-style license.
+// For details, see the Iterative Designs web site: http://www.iterativedesigns.com/
+// Parts of this code have been taken from the original dragdrop.js library which is
+// copyrighted by (c) 2005-2007 Thomas Fuchs (http://script.aculo.us,
+// http://mir.aculo.us) and (c) 2005-2007 Sammi Williams
+// (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) and available under
+// a MIT-style license.
+
+Draggable.prototype.startDrag = function(event) {
+ this.dragging = true;
+ if(!this.delta)
+ this.delta = this.currentDelta();
+
+ if(this.options.zindex) {
+ this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
+ this.element.style.zIndex = this.options.zindex;
+ }
+
+ if(this.options.ghosting) {
+ this._clone = this.element.cloneNode(true);
+ this.element._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
+ if (!this.element._originallyAbsolute)
+ Position.absolutize(this.element);
+ this.element.parentNode.insertBefore(this._clone, this.element);
+ }
+
+ if(this.options.superghosting) {
+ Position.prepare();
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ body = document.getElementsByTagName("body")[0];
+ me = this.element;
+ this._clone = me.cloneNode(true);
+ if (Prototype.Browser.IE) {
+ // Clear event handing from the clone
+ // Solves the second drag issue in IE
+ this._clone.clearAttributes();
+ this._clone.mergeAttributes(me.cloneNode(false));
+ }
+ me.parentNode.insertBefore(this._clone, me);
+ me.id = "clone_"+me.id;
+ me.hide();
+
+ Position.absolutize(me);
+ me.parentNode.removeChild(me);
+ body.appendChild(me);
+ //Retain height and width of object only if it has been nulled out. -v0.3 Fix
+ if (me.style.width == "0px" || me.style.height == "0px") {
+ me.style.width=Element.getWidth(this._clone)+"px";
+ me.style.height=Element.getHeight(this._clone)+"px";
+ }
+
+ //overloading in order to reduce repeated code weight.
+ this.originalScrollTop = (Element.getHeight(this._clone)/2);
+
+ this.draw(pointer);
+ me.show();
+ }
+
+ if(this.options.scroll) {
+ if (this.options.scroll == window) {
+ var where = this._getWindowScroll(this.options.scroll);
+ this.originalScrollLeft = where.left;
+ this.originalScrollTop = where.top;
+ } else {
+ this.originalScrollLeft = this.options.scroll.scrollLeft;
+ this.originalScrollTop = this.options.scroll.scrollTop;
+ }
+ }
+
+ Draggables.notify('onStart', this, event);
+
+ if(this.options.starteffect) this.options.starteffect(this.element);
+}
+
+
+
+
+Draggable.prototype.draw = function(point) {
+ var pos = Position.cumulativeOffset(this.element);
+ if(this.options.ghosting) {
+ var r = Position.realOffset(this.element);
+ pos[0] += r[0] - Position.deltaX;
+ pos[1] += r[1] - Position.deltaY;
+ }
+
+ var d = this.currentDelta();
+ pos[0] -= d[0];
+ pos[1] -= d[1];
+
+ if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
+ pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
+ pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
+ }
+
+ var p = [0,1].map(function(i){
+ return (point[i]-pos[i]-this.offset[i])
+ }.bind(this));
+
+ if(this.options.snap) {
+ if(Object.isFunction(this.options.snap)) {
+ p = this.options.snap(p[0],p[1],this);
+ } else {
+ if(Object.isArray(this.options.snap)) {
+ p = p.map( function(v, i) {
+ return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this))
+ } else {
+ p = p.map( function(v) {
+ return (v/this.options.snap).round()*this.options.snap }.bind(this))
+ }
+ }}
+
+ if (this.options.superghosting) {
+ p[1] = point[1] - this.originalScrollTop;
+ }
+
+
+
+ var style = this.element.style;
+ if((!this.options.constraint) || (this.options.constraint=='horizontal'))
+ style.left = p[0] + "px";
+ if((!this.options.constraint) || (this.options.constraint=='vertical'))
+ style.top = p[1] + "px";
+
+ if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
+}
+
+Draggable.prototype.initDrag = function(event) {
+ if(!Object.isUndefined(Draggable._dragging[this.element]) &&
+ Draggable._dragging[this.element]) return;
+ if(Event.isLeftClick(event)) {
+ // abort on form elements, fixes a Firefox issue
+ var src = Event.element(event);
+ if((tag_name = src.tagName.toUpperCase()) && (
+ tag_name=='INPUT' ||
+ tag_name=='SELECT' ||
+ tag_name=='OPTION' ||
+ tag_name=='BUTTON' ||
+ tag_name=='TEXTAREA')) return;
+
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var pos = Position.cumulativeOffset(this.element);
+ this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
+
+ Draggables.activate(this);
+ Event.stop(event);
+ }
+}
+
+Droppables.isAffected = function(point, element, drop) {
+ Position.prepare();
+ positioned_within = Position.withinIncludingScrolloffsets(drop.element, point[0], point[1])
+ return (
+ (drop.element!=element) &&
+ ((!drop._containers) ||
+ this.isContained(element, drop)) &&
+ ((!drop.accept) ||
+ (Element.classNames(element).detect(
+ function(v) { return drop.accept.include(v) } ) )) && positioned_within );
+
+
+}
+
+Draggable.prototype.finishDrag = function(event, success) {
+ this.dragging = false;
+
+ if(this.options.quiet){
+ Position.prepare();
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ Droppables.show(pointer, this.element);
+ }
+
+ if(this.options.ghosting) {
+ if (!this.element._originallyAbsolute)
+ Position.relativize(this.element);
+ delete this.element._originallyAbsolute;
+ Element.remove(this._clone);
+ this._clone = null;
+ }
+
+ var dropped = false;
+ if(success) {
+ dropped = Droppables.fire(event, this.element);
+ if (!dropped) dropped = false;
+ }
+ if(dropped && this.options.onDropped) this.options.onDropped(this.element);
+ Draggables.notify('onEnd', this, event);
+
+ var revert = this.options.revert;
+ if(revert && Object.isFunction(revert)) revert = revert(this.element);
+
+ var d = this.currentDelta();
+ if(revert && this.options.reverteffect) {
+ if (dropped == 0 || revert != 'failure')
+ this.options.reverteffect(this.element,
+ d[1]-this.delta[1], d[0]-this.delta[0]);
+ } else {
+ this.delta = d;
+ }
+
+ if(this.options.zindex)
+ this.element.style.zIndex = this.originalZ;
+
+ if(this.options.endeffect)
+ this.options.endeffect(this.element);
+
+
+ if(this.options.superghosting) {
+ body = document.getElementsByTagName("body")[0];
+ Element.remove(this.element);
+ new Draggable(this._clone, this.options);
+ }
+
+
+ Draggables.deactivate(this);
+ Droppables.reset();
+}
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/inlineeditor.js b/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/inlineeditor.js
new file mode 100644
index 0000000..6686258
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/activecontrols/inlineeditor.js
@@ -0,0 +1,306 @@
+Prado.WebUI.TInPlaceTextBox = jQuery.klass(Prado.WebUI.Control,
+{
+ onInit : function(options)
+ {
+
+ this.isSaving = false;
+ this.isEditing = false;
+ this.editField = null;
+ this.readOnly = options.ReadOnly;
+
+ this.options = jQuery.extend(
+ {
+ LoadTextFromSource : false,
+ TextMode : 'SingleLine'
+
+ }, options || {});
+ this.element = jQuery('#'+this.options.ID).get(0);
+ Prado.WebUI.TInPlaceTextBox.register(this);
+ this.createEditorInput();
+ this.initializeListeners();
+ },
+
+ /**
+ * Initialize the listeners.
+ */
+ initializeListeners : function()
+ {
+ this.onclickListener = this.enterEditMode.bind(this);
+ this.observe(this.element, 'click', this.onclickListener);
+ if (this.options.ExternalControl)
+ this.observe(jQuery('#'+this.options.ExternalControl).get(0), 'click', this.onclickListener);
+ },
+
+ /**
+ * Changes the panel to an editable input.
+ * @param {Event} evt event source
+ */
+ enterEditMode : function(evt)
+ {
+ if (this.isSaving || this.isEditing || this.readOnly) return;
+ this.isEditing = true;
+ this.onEnterEditMode();
+ this.createEditorInput();
+ this.showTextBox();
+ this.editField.disabled = false;
+ if(this.options.LoadTextOnEdit)
+ this.loadExternalText();
+ jQuery(this.editField).focus();
+ if (evt)
+ evt.preventDefault();
+ return false;
+ },
+
+ exitEditMode : function(evt)
+ {
+ this.isEditing = false;
+ this.isSaving = false;
+ this.editField.disabled = false;
+ this.element.innerHTML = this.editField.value;
+ this.showLabel();
+ },
+
+ showTextBox : function()
+ {
+ jQuery(this.element).hide();
+ jQuery(this.editField).show();
+ },
+
+ showLabel : function()
+ {
+ jQuery(this.element).show();
+ jQuery(this.editField).hide();
+ },
+
+ /**
+ * Create the edit input field.
+ */
+ createEditorInput : function()
+ {
+ if(this.editField == null)
+ this.createTextBox();
+
+ this.editField.value = this.getText();
+ },
+
+ loadExternalText : function()
+ {
+ this.editField.disabled = true;
+ this.onLoadingText();
+ var options = new Array('__InlineEditor_loadExternalText__', this.getText());
+ var request = new Prado.CallbackRequest(this.options.EventTarget, this.options);
+ request.setCausesValidation(false);
+ request.setCallbackParameter(options);
+ request.options.onSuccess = this.onloadExternalTextSuccess.bind(this);
+ request.options.onFailure = this.onloadExternalTextFailure.bind(this);
+ request.dispatch();
+ },
+
+ /**
+ * Create a new input textbox or textarea
+ */
+ createTextBox : function()
+ {
+ var cssClass= this.element.className || '';
+ var inputName = this.options.EventTarget;
+
+ if(this.options.TextMode == 'SingleLine')
+ {
+ this.editField = document.createElement("input");
+ if(this.options.MaxLength > 0)
+ this.editField.maxlength = this.options.MaxLength;
+ if(this.options.Columns > 0)
+ this.editField.size = this.options.Columns;
+ }
+ else
+ {
+ this.editField = document.createElement("textarea");
+ if(this.options.Rows > 0)
+ this.editField.rows = this.options.Rows;
+ if(this.options.Columns > 0)
+ this.editField.cols = this.options.Columns;
+ if(this.options.Wrap)
+ this.editField.wrap = 'off';
+ }
+
+ this.editField.className = cssClass;
+ this.editField.name = inputName;
+ this.editField.id = this.options.TextBoxID;
+ this.editField.style.display="none";
+ this.element.parentNode.insertBefore(this.editField, this.element)
+
+ //handle return key within single line textbox
+ if(this.options.TextMode == 'SingleLine')
+ {
+ this.observe(this.editField, "keydown", function(e)
+ {
+ if(e.keyCode == 13) //KEY_RETURN
+ {
+ var target = e.target;
+ if(target)
+ {
+ jQuery(target).trigger("blur");
+ e.preventDefault();
+ }
+ }
+ });
+ }
+
+ this.observe(this.editField, "blur", this.onTextBoxBlur.bind(this));
+ this.observe(this.editField, "keypress", this.onKeyPressed.bind(this));
+ },
+
+ /**
+ * @return {String} panel inner html text.
+ */
+ getText: function()
+ {
+ return this.element.innerHTML;
+ },
+
+ /**
+ * Edit mode entered, calls optional event handlers.
+ */
+ onEnterEditMode : function()
+ {
+ if(typeof(this.options.onEnterEditMode) == "function")
+ this.options.onEnterEditMode(this,null);
+ },
+
+ onTextBoxBlur : function(e)
+ {
+ var text = this.element.innerHTML;
+ if(this.options.AutoPostBack && text != this.editField.value)
+ {
+ if(this.isEditing)
+ this.onTextChanged(text);
+ }
+ else
+ {
+ this.element.innerHTML = this.editField.value;
+ this.isEditing = false;
+ if(this.options.AutoHide)
+ this.showLabel();
+ }
+ },
+
+ onKeyPressed : function(e)
+ {
+ if (e.keyCode == 27) //KEY_ESC
+ {
+ this.editField.value = this.getText();
+ this.isEditing = false;
+ if(this.options.AutoHide)
+ this.showLabel();
+ }
+ else if (e.keyCode == 13 // KEY_RETURN
+ && this.options.TextMode != 'MultiLine')
+ e.preventDefault()
+ },
+
+ /**
+ * When the text input value has changed.
+ * @param {String} original text
+ */
+ onTextChanged : function(text)
+ {
+ var request = new Prado.CallbackRequest(this.options.EventTarget, this.options);
+ request.setCallbackParameter(text);
+ request.options.onSuccess = this.onTextChangedSuccess.bind(this);
+ request.options.onFailure = this.onTextChangedFailure.bind(this);
+ if(request.dispatch())
+ {
+ this.isSaving = true;
+ this.editField.disabled = true;
+ }
+ },
+
+ /**
+ * When loading external text.
+ */
+ onLoadingText : function()
+ {
+ //Logger.info("on loading text");
+ },
+
+ onloadExternalTextSuccess : function(request, parameter)
+ {
+ this.isEditing = true;
+ this.editField.disabled = false;
+ this.editField.value = this.getText();
+ jQuery(this.editField).focus();
+ if(typeof(this.options.onSuccess)=="function")
+ this.options.onSuccess(sender,parameter);
+ },
+
+ onloadExternalTextFailure : function(request, parameter)
+ {
+ this.isSaving = false;
+ this.isEditing = false;
+ this.showLabel();
+ if(typeof(this.options.onFailure)=="function")
+ this.options.onFailure(sender,parameter);
+ },
+
+ /**
+ * Text change successfully.
+ * @param {Object} sender
+ * @param {Object} parameter
+ */
+ onTextChangedSuccess : function(sender, parameter)
+ {
+ this.isSaving = false;
+ this.isEditing = false;
+ if(this.options.AutoHide)
+ this.showLabel();
+ this.element.innerHTML = parameter == null ? this.editField.value : parameter;
+ this.editField.disabled = false;
+ if(typeof(this.options.onSuccess)=="function")
+ this.options.onSuccess(sender,parameter);
+ },
+
+ onTextChangedFailure : function(sender, parameter)
+ {
+ this.editField.disabled = false;
+ this.isSaving = false;
+ this.isEditing = false;
+ if(typeof(this.options.onFailure)=="function")
+ this.options.onFailure(sender,parameter);
+ }
+});
+
+
+jQuery.extend(Prado.WebUI.TInPlaceTextBox,
+{
+ //class methods
+
+ textboxes : {},
+
+ register : function(obj)
+ {
+ Prado.WebUI.TInPlaceTextBox.textboxes[obj.options.TextBoxID] = obj;
+ },
+
+ setDisplayTextBox : function(id,value)
+ {
+ var textbox = Prado.WebUI.TInPlaceTextBox.textboxes[id];
+ if(textbox)
+ {
+ if(value)
+ textbox.enterEditMode(null);
+ else
+ {
+ textbox.exitEditMode(null);
+ }
+ }
+ },
+
+ setReadOnly : function(id, value)
+ {
+ var textbox = Prado.WebUI.TInPlaceTextBox.textboxes[id];
+ if (textbox)
+ {
+ textbox.readOnly=value;
+ }
+ }
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadBlank.html b/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadBlank.html
new file mode 100755
index 0000000..44f50ce
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadBlank.html
@@ -0,0 +1 @@
+<!-- Nothing here to see, move right along. --> \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadComplete.png b/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadComplete.png
new file mode 100755
index 0000000..98badd7
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadComplete.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadError.png b/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadError.png
new file mode 100755
index 0000000..26c529f
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadError.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadIndicator.gif b/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadIndicator.gif
new file mode 100755
index 0000000..085ccae
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/ActiveFileUploadIndicator.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/activefileupload.js b/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/activefileupload.js
new file mode 100755
index 0000000..1599827
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/activefileupload/activefileupload.js
@@ -0,0 +1,104 @@
+Prado.WebUI.TActiveFileUpload = jQuery.klass(Prado.WebUI.Control,
+{
+ onInit : function(options)
+ {
+ this.options = options || {};
+ Prado.WebUI.TActiveFileUpload.register(this);
+
+ this.input = jQuery('#'+options.inputID).get(0);
+ this.flag = jQuery('#'+options.flagID).get(0);
+ this.form = jQuery('#'+options.formID).get(0);
+
+ this.indicator = jQuery('#'+options.indicatorID).get(0);
+ this.complete = jQuery('#'+options.completeID).get(0);
+ this.error = jQuery('#'+options.errorID).get(0);
+
+ // set up events
+ if (options.autoPostBack){
+ this.observe(this.input,"change",this.fileChanged.bind(this));
+ }
+ },
+
+ fileChanged : function(){
+ // show the upload indicator, and hide the complete and error indicators (if they areSn't already).
+ this.flag.value = '1';
+ this.complete.style.display = 'none';
+ this.error.style.display = 'none';
+ this.indicator.style.display = '';
+
+ // set the form to submit in the iframe, submit it, and then reset it.
+ this.oldtargetID = this.form.target;
+ this.oldFormAction = this.form.action;
+ this.oldFormMethod = this.form.method;
+ this.oldFormEnctype = this.form.enctype;
+
+ this.form.action += (this.form.action.indexOf('?')!=-1 ? '&' : '?')+'TActiveFileUpload_InputId='+this.options.inputID+'&TActiveFileUpload_TargetId='+this.options.targetID;
+ this.form.target = this.options.targetID;
+ this.form.method = 'POST';
+ this.form.enctype = 'multipart/form-data';
+ this.form.submit();
+
+ this.form.action = this.oldFormAction;
+ this.form.target = this.oldtargetID;
+ this.form.method = this.oldFormMethod;
+ this.form.enctype = this.oldFormEnctype;
+ },
+
+ finishUpload : function(options){
+
+ if (this.options.targetID == options.targetID)
+ {
+ this.finishoptions = options;
+ var e = this;
+ var callback =
+ {
+ 'CallbackParameter' : options || '',
+ 'onSuccess' : function() { e.finishCallBack(true); },
+ 'onFailure' : function() { e.finishCallBack(false); }
+ };
+
+ jQuery.extend(callback, this.options);
+
+ var request = new Prado.CallbackRequest(this.options.EventTarget, callback);
+ request.dispatch();
+ }
+ else
+ this.finishCallBack(true);
+
+ },
+
+ finishCallBack : function(success){
+ // hide the display indicator.
+ this.flag.value = '';
+ this.indicator.style.display = 'none';
+ // show the complete indicator.
+ if ((this.finishoptions.errorCode == 0) && (success)) {
+ this.complete.style.display = '';
+ this.input.value = '';
+ } else {
+ this.error.style.display = '';
+ }
+ }
+
+});
+
+jQuery.extend(Prado.WebUI.TActiveFileUpload,
+{
+ //class methods
+
+ controls : {},
+
+ register : function(control)
+ {
+ Prado.WebUI.TActiveFileUpload.controls[control.options.ID] = control;
+ },
+
+ onFileUpload : function(options)
+ {
+ Prado.WebUI.TActiveFileUpload.controls[options.clientID].finishUpload(options);
+ },
+
+ fileChanged : function(controlID){
+ Prado.WebUI.TActiveFileUpload.controls[controlID].fileChanged();
+ }
+});
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/background.png b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/background.png
new file mode 100644
index 0000000..91798cf
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/background.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/button.gif b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/button.gif
new file mode 100644
index 0000000..67f1797
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/button.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/colorpicker.js b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/colorpicker.js
new file mode 100644
index 0000000..9915eb8
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/colorpicker.js
@@ -0,0 +1,829 @@
+//-------------------- ricoColor.js
+if(typeof(Rico) == "undefined") Rico = {};
+
+Rico.Color = jQuery.klass();
+
+Rico.Color.prototype = {
+
+ initialize: function(red, green, blue) {
+ this.rgb = { r: red, g : green, b : blue };
+ },
+
+ setRed: function(r) {
+ this.rgb.r = r;
+ },
+
+ setGreen: function(g) {
+ this.rgb.g = g;
+ },
+
+ setBlue: function(b) {
+ this.rgb.b = b;
+ },
+
+ setHue: function(h) {
+
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.h = h;
+
+ // convert back to RGB...
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
+ },
+
+ setSaturation: function(s) {
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.s = s;
+
+ // convert back to RGB and set values...
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
+ },
+
+ setBrightness: function(b) {
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.b = b;
+
+ // convert back to RGB and set values...
+ this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
+ },
+
+ darken: function(percent) {
+ var hsb = this.asHSB();
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
+ },
+
+ brighten: function(percent) {
+ var hsb = this.asHSB();
+ this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
+ },
+
+ blend: function(other) {
+ this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
+ this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
+ this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
+ },
+
+ isBright: function() {
+ var hsb = this.asHSB();
+ return this.asHSB().b > 0.5;
+ },
+
+ isDark: function() {
+ return ! this.isBright();
+ },
+
+ asRGB: function() {
+ return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
+ },
+
+ asHex: function() {
+ return "#" + this.toColorPart(this.rgb.r) + this.toColorPart(this.rgb.g) + this.toColorPart(this.rgb.b);
+ },
+
+ asHSB: function() {
+ return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
+ },
+
+ toString: function() {
+ return this.asHex();
+ },
+
+ toColorPart: function(number) {
+ number = (number > 255 ? 255 : (number < 0 ? 0 : number));
+ var hex = number.toString(16);
+ return hex.length < 2 ? "0" + hex : hex;
+ }
+};
+
+Rico.Color.createFromHex = function(hexCode) {
+
+ if ( hexCode.indexOf('#') == 0 )
+ hexCode = hexCode.substring(1);
+
+ var red = "ff", green = "ff", blue="ff";
+ if(hexCode.length > 4)
+ {
+ red = hexCode.substring(0,2);
+ green = hexCode.substring(2,4);
+ blue = hexCode.substring(4,6);
+ }
+ else if(hexCode.length > 0 & hexCode.length < 4)
+ {
+ var r = hexCode.substring(0,1);
+ var g = hexCode.substring(1,2);
+ var b = hexCode.substring(2);
+ red = r+r;
+ green = g+g;
+ blue = b+b;
+ }
+ return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
+};
+
+/**
+ * Factory method for creating a color from the background of
+ * an HTML element.
+ */
+Rico.Color.createColorFromBackground = function(elem) {
+
+ var actualColor = jQuery(elem).css("background-color");
+ if ( actualColor == "transparent" && elem.parent )
+ return Rico.Color.createColorFromBackground(elem.parent);
+
+ if ( actualColor == null )
+ return new Rico.Color(255,255,255);
+
+ if ( actualColor.indexOf("rgb(") == 0 ) {
+ var colors = actualColor.substring(4, actualColor.length - 1 );
+ var colorArray = colors.split(",");
+ return new Rico.Color( parseInt( colorArray[0] ),
+ parseInt( colorArray[1] ),
+ parseInt( colorArray[2] ) );
+
+ }
+ else if ( actualColor.indexOf("#") == 0 ) {
+ return Rico.Color.createFromHex(actualColor);
+ }
+ else
+ return new Rico.Color(255,255,255);
+};
+
+Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
+
+ var red = 0;
+ var green = 0;
+ var blue = 0;
+
+ if (saturation == 0) {
+ red = parseInt(brightness * 255.0 + 0.5);
+ green = red;
+ blue = red;
+ }
+ else {
+ var h = (hue - Math.floor(hue)) * 6.0;
+ var f = h - Math.floor(h);
+ var p = brightness * (1.0 - saturation);
+ var q = brightness * (1.0 - saturation * f);
+ var t = brightness * (1.0 - (saturation * (1.0 - f)));
+
+ switch (parseInt(h)) {
+ case 0:
+ red = (brightness * 255.0 + 0.5);
+ green = (t * 255.0 + 0.5);
+ blue = (p * 255.0 + 0.5);
+ break;
+ case 1:
+ red = (q * 255.0 + 0.5);
+ green = (brightness * 255.0 + 0.5);
+ blue = (p * 255.0 + 0.5);
+ break;
+ case 2:
+ red = (p * 255.0 + 0.5);
+ green = (brightness * 255.0 + 0.5);
+ blue = (t * 255.0 + 0.5);
+ break;
+ case 3:
+ red = (p * 255.0 + 0.5);
+ green = (q * 255.0 + 0.5);
+ blue = (brightness * 255.0 + 0.5);
+ break;
+ case 4:
+ red = (t * 255.0 + 0.5);
+ green = (p * 255.0 + 0.5);
+ blue = (brightness * 255.0 + 0.5);
+ break;
+ case 5:
+ red = (brightness * 255.0 + 0.5);
+ green = (p * 255.0 + 0.5);
+ blue = (q * 255.0 + 0.5);
+ break;
+ }
+ }
+
+ return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
+};
+
+Rico.Color.RGBtoHSB = function(r, g, b) {
+
+ var hue;
+ var saturation;
+ var brightness;
+
+ var cmax = (r > g) ? r : g;
+ if (b > cmax)
+ cmax = b;
+
+ var cmin = (r < g) ? r : g;
+ if (b < cmin)
+ cmin = b;
+
+ brightness = cmax / 255.0;
+ if (cmax != 0)
+ saturation = (cmax - cmin)/cmax;
+ else
+ saturation = 0;
+
+ if (saturation == 0)
+ hue = 0;
+ else {
+ var redc = (cmax - r)/(cmax - cmin);
+ var greenc = (cmax - g)/(cmax - cmin);
+ var bluec = (cmax - b)/(cmax - cmin);
+
+ if (r == cmax)
+ hue = bluec - greenc;
+ else if (g == cmax)
+ hue = 2.0 + redc - bluec;
+ else
+ hue = 4.0 + greenc - redc;
+
+ hue = hue / 6.0;
+ if (hue < 0)
+ hue = hue + 1.0;
+ }
+
+ return { h : hue, s : saturation, b : brightness };
+};
+
+Prado.WebUI.TColorPicker = jQuery.klass(Prado.WebUI.Control, {
+
+ onInit : function(options)
+ {
+ var basics =
+ {
+ Palette : 'Small',
+ ClassName : 'TColorPicker',
+ Mode : 'Basic',
+ OKButtonText : 'OK',
+ CancelButtonText : 'Cancel',
+ ShowColorPicker : true
+ }
+
+ this.element = null;
+ this.showing = false;
+
+ options = jQuery.extend(basics, options);
+ this.options = options;
+ this.input = jQuery('#'+options['ID']).get(0);
+ this.button = jQuery('#'+options['ID']+'_button').get(0);
+ this._buttonOnClick = jQuery.proxy(this.buttonOnClick, this);
+ if(options['ShowColorPicker'])
+ this.observe(this.button, "click", this._buttonOnClick);
+ this.observe(this.input, "change", jQuery.proxy(this.updatePicker, this));
+
+ Prado.Registry[options.ID] = this;
+ },
+
+ updatePicker : function(e)
+ {
+ var color = Rico.Color.createFromHex(this.input.value);
+ this.button.style.backgroundColor = color.toString();
+ },
+
+ buttonOnClick : function(event)
+ {
+ var mode = this.options['Mode'];
+ if(this.element == null)
+ {
+ var constructor = mode == "Basic" ? "getBasicPickerContainer": "getFullPickerContainer"
+ this.element = this[constructor](this.options['ID'], this.options['Palette'])
+ this.input.parentNode.appendChild(this.element);
+ this.element.style.display = "none";
+
+ if(mode == "Full")
+ this.initializeFullPicker();
+ }
+ this.show(mode);
+ },
+
+ show : function(type)
+ {
+ if(!this.showing)
+ {
+ var pos = jQuery(this.input).position();
+ pos['top'] += this.input.offsetHeight;
+
+ this.element.style.top = (pos['top']-1) + "px";
+ this.element.style.left = pos['left'] + "px";
+ this.element.style.display = "block";
+
+ //observe for clicks on the document body
+ this._documentClickEvent = jQuery.bind(this.hideOnClick, this, type);
+ this._documentKeyDownEvent = jQuery.bind(this.keyPressed, this, type);
+ this.observe(document.body, "click", this._documentClickEvent);
+ this.observe(document,"keydown", this._documentKeyDownEvent);
+ this.showing = true;
+
+ if(type == "Full")
+ {
+ this.observeMouseMovement();
+ var color = Rico.Color.createFromHex(this.input.value);
+ this.inputs.oldColor.style.backgroundColor = color.asHex();
+ this.setColor(color,true);
+ }
+ }
+ },
+
+ hide : function(event)
+ {
+ if(this.showing)
+ {
+ this.element.style.display = "none";
+ this.showing = false;
+ this.stopObserving(document.body, "click", this._documentClickEvent);
+ this.stopObserving(document,"keydown", this._documentKeyDownEvent);
+
+ if(this._observingMouseMove)
+ {
+ this.stopObserving(document.body, "mousemove", this._onMouseMove);
+ this._observingMouseMove = false;
+ }
+ }
+ },
+
+ keyPressed : function(event,type)
+ {
+ // esc
+ if(event.keyCode == 27)
+ this.hide(event,type);
+ },
+
+ hideOnClick : function(ev)
+ {
+ if(!this.showing) return;
+ var el = ev.target;
+ var within = false;
+ do
+ { within = within || String(el.className).indexOf('FullColorPicker') > -1
+ within = within || el == this.button;
+ within = within || el == this.input;
+ if(within) break;
+ el = el.parentNode;
+ }
+ while(el);
+ if(!within) this.hide(ev);
+ },
+
+ getBasicPickerContainer : function(pickerID, palette)
+ {
+ var div;
+ var table;
+ var tbody;
+ var tr;
+ var td;
+
+ // main div
+ div = document.createElement("div");
+ div.className = this.options['ClassName']+" BasicColorPicker";
+ div.id = pickerID+"_picker";
+
+ table = document.createElement("table");
+ table.className = 'basic_colors palette_'+palette;
+ div.appendChild(table);
+
+ tbody = document.createElement("tbody");
+ table.appendChild(tbody);
+
+ var colors = Prado.WebUI.TColorPicker.palettes[palette];
+ var pickerOnClick = this.cellOnClick.bind(this);
+ var obj=this;
+ jQuery.each(colors, function(idx, color)
+ {
+ var row = document.createElement("tr");
+ jQuery.each(color, function(idx, c)
+ {
+ var td = document.createElement("td");
+ var img = document.createElement("img");
+ img.src=Prado.WebUI.TColorPicker.UIImages['button.gif'];
+ img.width=16;
+ img.height=16;
+ img.style.backgroundColor = "#"+c;
+ obj.observe(img,"click", pickerOnClick);
+ obj.observe(img,"mouseover", function(e)
+ {
+ jQuery(e.target).addClass("pickerhover");
+ });
+ obj.observe(img,"mouseout", function(e)
+ {
+ jQuery(e.target).removeClass("pickerhover");
+ });
+ td.appendChild(img);
+ row.appendChild(td);
+ });
+ table.childNodes[0].appendChild(row);
+ });
+ return div;
+ },
+
+ cellOnClick : function(e)
+ {
+ var el = e.target;
+ if(el.tagName.toLowerCase() != "img")
+ return;
+ var color = Rico.Color.createColorFromBackground(el);
+ this.updateColor(color);
+ },
+
+ updateColor : function(color)
+ {
+ this.input.value = color.toString().toUpperCase();
+ this.button.style.backgroundColor = color.toString();
+ if(typeof(this.onChange) == "function")
+ this.onChange(color);
+ if(this.options.OnColorSelected)
+ this.options.OnColorSelected(this,color);
+ },
+
+ getFullPickerContainer : function(pickerID)
+ {
+ //create the buttons
+ var okBtn = document.createElement("input");
+ okBtn.className = 'button';
+ okBtn.type = 'button';
+ okBtn.value = this.options.OKButtonText;
+
+ var cancelBtn = document.createElement("input");
+ cancelBtn.className = 'button';
+ cancelBtn.type = 'button';
+ cancelBtn.value = this.options.CancelButtonText;
+
+ this.buttons =
+ {
+ OK : okBtn,
+ Cancel : cancelBtn
+ };
+
+ //create the 6 inputs
+ var inputs = {};
+ jQuery.each(['H','S','V','R','G','B'], function(idx, type)
+ {
+ inputs[type] = document.createElement("input");
+ inputs[type].type='text';
+ inputs[type].size='3';
+ inputs[type].maxlength='3';
+ });
+
+ //create the HEX input
+ inputs['HEX'] = document.createElement("input");
+ inputs['HEX'].className = 'hex';
+ inputs['HEX'].type='text';
+ inputs['HEX'].size='6';
+ inputs['HEX'].maxlength='6';
+
+ this.inputs = inputs;
+
+ var images = Prado.WebUI.TColorPicker.UIImages;
+
+ this.inputs['currentColor'] = document.createElement("span");
+ this.inputs['currentColor'].className='currentColor';
+ this.inputs['oldColor'] = document.createElement("span");
+ this.inputs['oldColor'].className='oldColor';
+
+ var inputsTable = document.createElement("table");
+ inputsTable.className='inputs';
+
+ var tbody = document.createElement("tbody");
+ inputsTable.appendChild(tbody);
+
+ var tr = document.createElement("tr");
+ tbody.appendChild(tr);
+
+ var td= document.createElement("td");
+ tr.appendChild(td);
+ td.className='currentcolor';
+ td.colSpan=2;
+ td.appendChild(this.inputs['currentColor']);
+ td.appendChild(this.inputs['oldColor']);
+
+ this.internalAddRow(tbody, 'H:', this.inputs['H'], '°');
+ this.internalAddRow(tbody, 'S:', this.inputs['S'], '%');
+ this.internalAddRow(tbody, 'V:', this.inputs['V'], '%');
+ this.internalAddRow(tbody, 'R:', this.inputs['R'], null, 'gap');
+ this.internalAddRow(tbody, 'G:', this.inputs['G']);
+ this.internalAddRow(tbody, 'B:', this.inputs['B']);
+ this.internalAddRow(tbody, '#', this.inputs['HEX'], null, 'gap');
+
+ var UIimages =
+ {
+ selector : document.createElement("span"),
+ background : document.createElement("span"),
+ slider : document.createElement("span"),
+ hue : document.createElement("span")
+ }
+
+ UIimages['selector'].className='selector';
+ UIimages['background'].className='colorpanel';
+ UIimages['slider'].className='slider';
+ UIimages['hue'].className='strip';
+
+ this.inputs = jQuery.extend(this.inputs, UIimages);
+
+ var pickerTable = document.createElement("table");
+ tbody=document.createElement("tbody");
+ pickerTable.appendChild(tbody);
+
+ var tr = document.createElement("tr");
+ tr.className='selection';
+ tbody.appendChild(tr);
+
+ var td= document.createElement("td");
+ tr.appendChild(td);
+ td.className='colors';
+ td.appendChild(UIimages['selector']);
+ td.appendChild(UIimages['background']);
+
+ var td= document.createElement("td");
+ tr.appendChild(td);
+ td.className='hue';
+ td.appendChild(UIimages['slider']);
+ td.appendChild(UIimages['hue']);
+
+ var td= document.createElement("td");
+ tr.appendChild(td);
+ td.className='inputs';
+ td.appendChild(inputsTable);
+
+ var tr = document.createElement("tr");
+ tr.className='options';
+ tbody.appendChild(tr);
+
+ var td= document.createElement("td");
+ tr.appendChild(td);
+ td.colSpan=3;
+ td.appendChild(this.buttons['OK']);
+ td.appendChild(this.buttons['Cancel']);
+
+ var div = document.createElement('div');
+ div.className=this.options['ClassName']+" FullColorPicker";
+ div.id=pickerID+"_picker";
+ div.appendChild(pickerTable);
+ return div;
+ },
+
+ internalAddRow : function(tbody, label1, object2, label2, className)
+ {
+ var tr = document.createElement("tr");
+ tbody.appendChild(tr);
+
+ var td= document.createElement("td");
+ if(className!==undefined && className!==null)
+ td.className=className;
+ tr.appendChild(td);
+ td.appendChild(document.createTextNode(label1));
+
+ var td= document.createElement("td");
+ if(className!==undefined && className!==null)
+ td.className=className;
+ tr.appendChild(td);
+ td.appendChild(object2);
+ if(label2!==undefined && label2!==null)
+ td.appendChild(document.createTextNode(label2));
+ },
+
+ initializeFullPicker : function()
+ {
+ var color = Rico.Color.createFromHex(this.input.value);
+ this.inputs.oldColor.style.backgroundColor = color.asHex();
+ this.setColor(color,true);
+
+ var i = 0;
+ for(var type in this.inputs)
+ {
+ this.observe(this.inputs[type], "change",
+ jQuery.proxy(this.onInputChanged,this,type));
+ i++;
+
+ if(i > 6) break;
+ }
+
+ this.isMouseDownOnColor = false;
+ this.isMouseDownOnHue = false;
+
+ this._onColorMouseDown = this.onColorMouseDown.bind(this);
+ this._onHueMouseDown = this.onHueMouseDown.bind(this);
+ this._onMouseUp = this.onMouseUp.bind(this);
+ this._onMouseMove = this.onMouseMove.bind(this);
+
+ this.observe(this.inputs.background, "mousedown", this._onColorMouseDown);
+ this.observe(this.inputs.selector, "mousedown", this._onColorMouseDown);
+ this.observe(this.inputs.hue, "mousedown", this._onHueMouseDown);
+ this.observe(this.inputs.slider, "mousedown", this._onHueMouseDown);
+
+ this.observe(document.body, "mouseup", this._onMouseUp);
+
+ this.observeMouseMovement();
+
+ this.observe(this.buttons.Cancel, "click", jQuery.proxy(this.hide,this,this.options['Mode']));
+ this.observe(this.buttons.OK, "click", this.onOKClicked.bind(this));
+ },
+
+ observeMouseMovement : function()
+ {
+ if(!this._observingMouseMove)
+ {
+ this.observe(document.body, "mousemove", this._onMouseMove);
+ this._observingMouseMove = true;
+ }
+ },
+
+ onColorMouseDown : function(ev)
+ {
+ this.isMouseDownOnColor = true;
+ this.onMouseMove(ev);
+ ev.stopPropagation();
+ },
+
+ onHueMouseDown : function(ev)
+ {
+ this.isMouseDownOnHue = true;
+ this.onMouseMove(ev);
+ ev.stopPropagation();
+ },
+
+ onMouseUp : function(ev)
+ {
+ this.isMouseDownOnColor = false;
+ this.isMouseDownOnHue = false;
+ ev.stopPropagation();
+ },
+
+ onMouseMove : function(ev)
+ {
+ if(this.isMouseDownOnColor)
+ this.changeSV(ev);
+ if(this.isMouseDownOnHue)
+ this.changeH(ev);
+ ev.stopPropagation();
+ },
+
+ changeSV : function(ev)
+ {
+ var px = ev.pageX;
+ var py = ev.pageY;
+ var pos = jQuery(this.inputs.background).offset();
+
+ var x = this.truncate(px - pos['left'],0,255);
+ var y = this.truncate(py - pos['top'],0,255);
+
+
+ var s = x/255;
+ var b = (255-y)/255;
+
+ var current_s = parseInt(this.inputs.S.value);
+ var current_b = parseInt(this.inputs.V.value);
+
+ if(current_s == parseInt(s*100) && current_b == parseInt(b*100)) return;
+
+ var h = this.truncate(this.inputs.H.value,0,360)/360;
+
+ var color = new Rico.Color();
+ color.rgb = Rico.Color.HSBtoRGB(h,s,b);
+
+
+ this.inputs.selector.style.left = x+"px";
+ this.inputs.selector.style.top = y+"px";
+
+ this.inputs.currentColor.style.backgroundColor = color.asHex();
+
+ return this.setColor(color);
+ },
+
+ changeH : function(ev)
+ {
+ var py = ev.pageY;
+ var pos = jQuery(this.inputs.background).offset();
+ var y = this.truncate(py - pos['top'],0,255);
+
+ var h = (255-y)/255;
+ var current_h = this.truncate(this.inputs.H.value,0,360);
+ current_h = current_h == 0 ? 360 : current_h;
+ if(current_h == parseInt(h*360)) return;
+
+ var s = parseInt(this.inputs.S.value)/100;
+ var b = parseInt(this.inputs.V.value)/100;
+ var color = new Rico.Color();
+ color.rgb = Rico.Color.HSBtoRGB(h,s,b);
+
+ var hue = new Rico.Color(color.rgb.r,color.rgb.g,color.rgb.b);
+ hue.setSaturation(1); hue.setBrightness(1);
+
+ this.inputs.background.style.backgroundColor = hue.asHex();
+ this.inputs.currentColor.style.backgroundColor = color.asHex();
+
+ this.inputs.slider.style.top = this.truncate(y,0,255)+"px";
+ return this.setColor(color);
+
+ },
+
+ onOKClicked : function(ev)
+ {
+ var r = this.truncate(this.inputs.R.value,0,255);///255;
+ var g = this.truncate(this.inputs.G.value,0,255);///255;
+ var b = this.truncate(this.inputs.B.value,0,255);///255;
+ var color = new Rico.Color(r,g,b);
+ this.updateColor(color);
+ this.inputs.oldColor.style.backgroundColor = color.asHex();
+ this.hide(ev);
+ },
+
+ onInputChanged : function(ev, type)
+ {
+ if(this.isMouseDownOnColor || isMouseDownOnHue)
+ return;
+
+
+ switch(type)
+ {
+ case "H": case "S": case "V":
+ var h = this.truncate(this.inputs.H.value,0,360)/360;
+ var s = this.truncate(this.inputs.S.value,0,100)/100;
+ var b = this.truncate(this.inputs.V.value,0,100)/100;
+ var color = new Rico.Color();
+ color.rgb = Rico.Color.HSBtoRGB(h,s,b);
+ return this.setColor(color,true);
+ case "R": case "G": case "B":
+ var r = this.truncate(this.inputs.R.value,0,255);///255;
+ var g = this.truncate(this.inputs.G.value,0,255);///255;
+ var b = this.truncate(this.inputs.B.value,0,255);///255;
+ var color = new Rico.Color(r,g,b);
+ return this.setColor(color,true);
+ case "HEX":
+ var color = Rico.Color.createFromHex(this.inputs.HEX.value);
+ return this.setColor(color,true);
+ }
+ },
+
+ setColor : function(color, update)
+ {
+ var hsb = color.asHSB();
+
+ this.inputs.H.value = parseInt(hsb.h*360);
+ this.inputs.S.value = parseInt(hsb.s*100);
+ this.inputs.V.value = parseInt(hsb.b*100);
+ this.inputs.R.value = color.rgb.r;
+ this.inputs.G.value = color.rgb.g;
+ this.inputs.B.value = color.rgb.b;
+ this.inputs.HEX.value = color.asHex().substring(1).toUpperCase();
+
+ var images = Prado.WebUI.TColorPicker.UIImages;
+
+ if(color.isBright())
+ jQuery(this.inputs.selector).removeClass('target_white');
+ else
+ jQuery(this.inputs.selector).addClass('target_white');
+
+ if(update)
+ this.updateSelectors(color);
+ },
+
+ updateSelectors : function(color)
+ {
+ var hsb = color.asHSB();
+ var pos = [hsb.s*255, hsb.b*255, hsb.h*255];
+
+ this.inputs.selector.style.left = this.truncate(pos[0],0,255)+"px";
+ this.inputs.selector.style.top = this.truncate(255-pos[1],0,255)+"px";
+ this.inputs.slider.style.top = this.truncate(255-pos[2],0,255)+"px";
+
+ var hue = new Rico.Color(color.rgb.r,color.rgb.g,color.rgb.b);
+ hue.setSaturation(1); hue.setBrightness(1);
+ this.inputs.background.style.backgroundColor = hue.asHex();
+ this.inputs.currentColor.style.backgroundColor = color.asHex();
+ },
+
+ truncate : function(value, min, max)
+ {
+ value = parseInt(value);
+ return value < min ? min : value > max ? max : value;
+ }
+});
+
+jQuery.extend(Prado.WebUI.TColorPicker,
+{
+ palettes:
+ {
+ Small : [["fff", "fcc", "fc9", "ff9", "ffc", "9f9", "9ff", "cff", "ccf", "fcf"],
+ ["ccc", "f66", "f96", "ff6", "ff3", "6f9", "3ff", "6ff", "99f", "f9f"],
+ ["c0c0c0", "f00", "f90", "fc6", "ff0", "3f3", "6cc", "3cf", "66c", "c6c"],
+ ["999", "c00", "f60", "fc3", "fc0", "3c0", "0cc", "36f", "63f", "c3c"],
+ ["666", "900", "c60", "c93", "990", "090", "399", "33f", "60c", "939"],
+ ["333", "600", "930", "963", "660", "060", "366", "009", "339", "636"],
+ ["000", "300", "630", "633", "330", "030", "033", "006", "309", "303"]],
+
+ Tiny : [["ffffff"/*white*/, "00ff00"/*lime*/, "008000"/*green*/, "0000ff"/*blue*/],
+ ["c0c0c0"/*silver*/, "ffff00"/*yellow*/, "ff00ff"/*fuchsia*/, "000080"/*navy*/],
+ ["808080"/*gray*/, "ff0000"/*red*/, "800080"/*purple*/, "000000"/*black*/]]
+ },
+
+ UIImages :
+ {
+ 'button.gif' : 'button.gif',
+// 'target_black.gif' : 'target_black.gif',
+// 'target_white.gif' : 'target_white.gif',
+// 'background.png' : 'background.png'
+// 'slider.gif' : 'slider.gif',
+// 'hue.gif' : 'hue.gif'
+ }
+});
+
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/default.css b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/default.css
new file mode 100644
index 0000000..7bbc08d
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/default.css
@@ -0,0 +1,249 @@
+
+/** Colors **/
+
+.TColorPicker_button
+{
+}
+
+.TColorPicker
+{
+ background-color: white;
+ border: 1px solid #919EA9;
+}
+
+.FullColorPicker
+{
+ width: 388px;
+}
+
+.BasicColorPicker .basic_colors td img
+{
+ border: 1px solid #919EA9;
+}
+
+.BasicColorPicker .basic_colors .pickerhover
+{
+ border-color: white;
+}
+
+.FullColorPicker .colors .colorpanel
+{
+ border: 1px solid #919EA9;
+}
+
+.FullColorPicker .hue .strip
+{
+ border: 1px solid #919EA9;
+}
+
+.FullColorPicker .inputs .currentcolor span
+{
+ border: 1px solid #919EA9;
+}
+
+.FullColorPicker .options td
+{
+ border-top: 1px solid #919EA9;
+}
+
+/** UI **/
+.TColorPicker_button img
+{
+ border: 2px ridge ActiveBorder;
+ background-color: #fff;
+ padding: 1px;
+ height: 16px;
+ width: 16px;
+ margin: 1px;
+ margin-bottom: -6px;
+ margin-bottom: expression(-4); /** IE hack **/
+}
+
+.TColorPicker
+{
+ position: absolute;
+}
+
+.BasicColorPicker .palette_Tiny img
+{
+ width: 30px;
+ height: 30px;
+}
+.BasicColorPicker .basic_colors
+{
+ border-collapse: separate;
+ border-spacing: 2px;
+}
+
+.BasicColorPicker .basic_colors td
+{
+ padding: 0;
+ font-size: 0;
+}
+
+.FullColorPicker table
+{
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+.FullColorPicker .colors .colorpanel
+{
+ margin-left: 7px;
+ margin-top: -9px;
+ display: block;
+ width:256px;
+ height:256px;
+ background-image: url(background.png);
+}
+
+* html .FullColorPicker .colors .colorpanel
+{
+ background-image: none;
+ margin-top: -10px;
+}
+
+.FullColorPicker .colors
+{
+ padding-bottom: 10px;
+ padding-top: 17px;
+}
+
+* html .FullColorPicker .colors
+{
+ margin-top: 10px;
+}
+
+.FullColorPicker .colors .selector
+{
+ position: relative;
+ top: 0px;
+ left: 0px;
+ border: 0 none;
+ float: left;
+ margin-left: 2px;
+ margin-top: -12px;
+ display: block;
+ background-image: url(target_black.gif);
+ background-repeat: no-repeat;
+ width: 8px;
+ height:8px;
+ background-position: 50%
+}
+
+* html .FullColorPicker .colors .selector
+{
+ margin-top: -16px;
+}
+
+.FullColorPicker .colors span.target_white
+{
+ background-image: url(target_white.gif);
+}
+
+.FullColorPicker .hue
+{
+ text-align: center;
+ width: 50px;
+}
+
+.FullColorPicker .hue .strip
+{
+ margin-top: -5px;
+ margin-left: 9px;
+ display: block;
+ background-image: url(hue.gif);
+ width:19px;
+ height:256px;
+}
+
+* html .FullColorPicker .hue .strip
+{
+ margin-left: 10px;
+}
+
+.FullColorPicker .slider
+{
+ position: relative;
+ top: 0px;
+ margin-top: -5px;
+ background-image: url(slider.gif);
+ width: 40px;
+ height: 9px;
+ font-size: 0;
+ display: block;
+}
+
+* html .FullColorPicker .slider
+{
+ margin-left: 10px;
+}
+
+.FullColorPicker .inputs
+{
+ font-family: Tahoma;
+ font-size: 10pt;
+}
+
+.FullColorPicker .inputs input
+{
+ width: 30px;
+ text-align: center;
+ height: 16px;
+ margin-right: 2px;
+}
+
+.FullColorPicker .currentcolor
+{
+ text-align: center;
+}
+
+.FullColorPicker .inputs .currentcolor span
+{
+ display: block;
+ width: 60px;
+ height: 30px;
+}
+
+.FullColorPicker .inputs .currentcolor span.currentColor
+{
+ margin: 5px 5px 0 2px;
+ border-bottom: 0 none;
+}
+
+.FullColorPicker .inputs .currentcolor span.oldColor
+{
+ margin: 0px 5px 5px 2px;
+ border-top: 0 none;
+}
+
+.FullColorPicker input.hex
+{
+ width: 50px;
+ margin-right: 5px;
+}
+
+.FullColorPicker input.button
+{
+ width: 90px;
+ margin: 3px;
+ font-size: 10px;
+}
+
+.FullColorPicker .inputs .gap
+{
+ padding-top: 8px;
+}
+
+.FullColorPicker .customs
+{
+ width: 100%;
+ border-collapse: separate;
+}
+
+.FullColorPicker .options td
+{
+ height: 0px;
+ text-align: right;
+ padding: 7px 10px 7px 0px;
+} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/hue.gif b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/hue.gif
new file mode 100644
index 0000000..901e409
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/hue.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/slider.gif b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/slider.gif
new file mode 100644
index 0000000..92f9d74
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/slider.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/spacer.gif b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/spacer.gif
new file mode 100755
index 0000000..fc25609
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/spacer.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/target_black.gif b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/target_black.gif
new file mode 100644
index 0000000..ebb89f5
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/target_black.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/target_white.gif b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/target_white.gif
new file mode 100644
index 0000000..c3527c8
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/colorpicker/target_white.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/controls/accordion.js b/lib/prado/framework/Web/Javascripts/source/prado/controls/accordion.js
new file mode 100644
index 0000000..084aef7
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/controls/accordion.js
@@ -0,0 +1,109 @@
+/* Simple Accordion Script
+ * Requires Prototype and Script.aculo.us Libraries
+ * By: Brian Crescimanno <brian.crescimanno@gmail.com>
+ * http://briancrescimanno.com
+ * Adapted to Prado & minor improvements: Gabor Berczi <gabor.berczi@devworx.hu>
+ * jQuery port by Bas Fabio <ctrlaltca@gmail.com>
+ * This work is licensed under the Creative Commons Attribution-Share Alike 3.0
+ * http://creativecommons.org/licenses/by-sa/3.0/us/
+ */
+
+Prado.WebUI.TAccordion = jQuery.klass(Prado.WebUI.Control,
+{
+ onInit : function(options)
+ {
+ this.accordion = jQuery('#'+options.ID).get(0);
+ this.options = options;
+ this.hiddenField = jQuery('#'+options.ID+'_1').get(0);
+
+ if (this.options.maxHeight)
+ {
+ this.maxHeight = this.options.maxHeight;
+ } else {
+ this.maxHeight = 0;
+ this.checkMaxHeight();
+ }
+
+ this.currentView = null;
+ this.oldView = null;
+
+ var i = 0;
+ for(var view in this.options.Views)
+ {
+ var header = jQuery('#'+view+'_0').get(0);
+ if(header)
+ {
+ this.observe(header, "click", jQuery.proxy(this.elementClicked,this,view));
+ if(this.hiddenField.value == i)
+ {
+ this.currentView = view;
+ if(jQuery('#'+this.currentView).height() != this.maxHeight)
+ jQuery('#'+this.currentView).css({height: this.maxHeight+"px"});
+ }
+ }
+ i++;
+ }
+ },
+
+ checkMaxHeight: function()
+ {
+ for(var viewID in this.options.Views)
+ {
+ var view = jQuery('#'+viewID);
+ if(view.height() > this.maxHeight)
+ this.maxHeight = view.height();
+ }
+ },
+
+ elementClicked : function(viewID, event)
+ {
+ var i = 0;
+ for(var index in this.options.Views)
+ {
+ if (jQuery('#'+index).get(0))
+ {
+ var header = jQuery('#'+index+'_0').get(0);
+ if(index == viewID)
+ {
+ this.oldView = this.currentView;
+ this.currentView = index;
+
+ this.hiddenField.value=i;
+ }
+ }
+ i++;
+ }
+ if(this.oldView != this.currentView)
+ {
+ if(this.options.Duration > 0)
+ {
+ this.animate();
+ } else {
+ jQuery('#'+this.currentView).css({ height: this.maxHeight+"px" });
+ jQuery('#'+this.currentView).show();
+ jQuery('#'+this.oldView).hide();
+
+ jQuery('#'+this.oldView+'_0').removeClass().addClass(this.options.HeaderCssClass);
+ jQuery('#'+this.currentView+'_0').removeClass().addClass(this.options.ActiveHeaderCssClass);
+ }
+ }
+ },
+
+ animate: function() {
+ jQuery('#'+this.oldView+'_0').removeClass().addClass(this.options.HeaderCssClass);
+ jQuery('#'+this.currentView+'_0').removeClass().addClass(this.options.ActiveHeaderCssClass);
+
+ jQuery('#'+this.oldView).animate(
+ {height: 0},
+ this.options.Duration,
+ function() {
+ jQuery(this).hide()
+ }
+ );
+ jQuery('#'+this.currentView).css({height: 0}).show().animate(
+ {height: this.maxHeight+'px'},
+ this.options.Duration
+ );
+ }
+});
+
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/controls/controls.js b/lib/prado/framework/Web/Javascripts/source/prado/controls/controls.js
new file mode 100644
index 0000000..9eff6a1
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/controls/controls.js
@@ -0,0 +1,531 @@
+Prado.WebUI = jQuery.klass();
+
+Prado.WebUI.Control = jQuery.klass({
+
+ initialize : function(options)
+ {
+ this.registered = false;
+ this.ID = options.ID;
+ this.element = jQuery("#" + this.ID).get(0);
+ this.observers = new Array();
+ this.intervals = new Array();
+ var e;
+ if (jQuery.inArray(this.ID, Prado.Registry) == -1)
+ this.register(options);
+ else
+ this.replace(Prado.Registry[this.ID], options);
+
+ if (this === Prado.Registry[this.ID])
+ {
+ this.registered = true;
+ if(this.onInit)
+ this.onInit(options);
+ }
+ },
+
+ /**
+ * Registers the control wrapper in the Prado client side control registry
+ * @param array control wrapper options
+ */
+ register : function(options)
+ {
+ return Prado.Registry[options.ID] = this;
+ },
+
+ /**
+ * De-registers the control wrapper in the Prado client side control registry
+ */
+ deregister : function()
+ {
+ // extra check so we don't ever deregister another wrapper
+ var value = Prado.Registry[this.ID];
+ if (value===this)
+ {
+ delete Prado.Registry[this.ID];
+ return value;
+ }
+ else
+ debugger; // invoke debugger - this should never happen
+ },
+
+ /**
+ * Replaces and control wrapper for an already existing control in the Prado client side control registry
+ * @param object reference to the old wrapper
+ * @param array control wrapper options
+ */
+ replace : function(oldwrapper, options)
+ {
+ // if there's some advanced state management in the wrapper going on, then
+ // this method could be used either to copy the current state of the control
+ // from the old wrapper to this new one (which then could live on, while the old
+ // one could get destroyed), or to copy the new, changed options to the old wrapper,
+ // (which could then left intact to keep working, while this new wrapper could be
+ // disposed of by exiting its initialization without installing any handlers or
+ // leaving any references to it)
+ //
+
+ // for now this method is simply deinitializing and deregistering the old wrapper,
+ // and then registering the new wrapper for the control id
+
+ if (oldwrapper.deinitialize)
+ oldwrapper.deinitialize();
+
+ return this.register(options);
+ },
+
+ /**
+ * Registers an event observer which will be automatically disposed of when the wrapper
+ * is deregistered
+ * @param element DOM element reference or id to attach the event handler to
+ * @param string event name to observe
+ * @param handler event handler function
+ */
+ observe: function(element, eventName, handler, options)
+ {
+ var e = { _element: element, _eventName: eventName, _handler: handler };
+ this.observers.push(e);
+ return jQuery(e._element).bind(e._eventName, options, e._handler);
+ },
+
+ /**
+ * Checks whether an event observer is installed and returns its index
+ * @param element DOM element reference or id the event handler was attached to
+ * @param string event name observed
+ * @param handler event handler function
+ * @result int false if the event handler is not installed, or 1-based index when installed
+ */
+ findObserver: function(element, eventName, handler)
+ {
+ var e = { _element: element, _eventName: eventName, _handler: handler };
+ var idx = -1;
+ for(var i=0;i<this.observers.length;i++)
+ {
+ var o = this.observers[i];
+ if ((o._element===element) && (o._eventName===eventName) && (o._handler===handler))
+ {
+ idx = i;
+ break;
+ }
+ }
+ return idx;
+ },
+
+
+ /**
+ * Degisters an event observer from the list of automatically disposed handlers
+ * @param element DOM element reference or id the event handler was attached to
+ * @param string event name observed
+ * @param handler event handler function
+ */
+ stopObserving: function(element, eventName, handler)
+ {
+ var idx = this.findObserver(element,eventName,handler);
+ if (idx!=-1)
+ this.observers.splice(idx, 1);
+ else
+ debugger; // shouldn't happen
+
+ return jQuery(element).unbind(eventName, handler);
+ },
+
+ /**
+ * Registers a code snippet or function to be executed after a delay, if the
+ * wrapper hasn't been destroyed in the meantime
+ * @param code function or code snippet to execute
+ * @param int number of milliseconds to wait before executing
+ * @return int unique ID that can be used to cancel the scheduled execution
+ */
+ setTimeout: function(func, delay)
+ {
+ if (!jQuery.isFunction(func))
+ {
+ var expr = func;
+ func = function() { return eval(expr); }
+ };
+ var obj = this;
+ return window.setTimeout(function() {
+ if (!obj.isLingering())
+ func();
+ obj = null;
+ },delay);
+ },
+
+ /**
+ * Cancels a previously scheduled code snippet or function
+ * @param int unique ID returned by setTimeout()
+ */
+ clearTimeout: function(timeoutid)
+ {
+ return window.clearTimeout(timeoutid);
+ },
+
+ /**
+ * Registers a code snippet or function to be executed periodically, up until the
+ * wrapper gets destroyed or the schedule cancelled using cancelInterval()
+ * @param code function or code snippet to execute
+ * @param int number of milliseconds to wait before executing
+ * @return int unique ID that can be used to cancel the interval (see clearInterval() method)
+ */
+ setInterval: function(func, delay)
+ {
+ if (!jQuery.isFunction(func)) func = function() { eval(func); };
+ var obj = this;
+ var h = window.setInterval(function() {
+ if (!obj.isLingering())
+ func();
+ },delay);
+ this.intervals.push(h);
+ return h;
+ },
+
+ /**
+ * Deregisters a snipper or function previously registered with setInterval()
+ * @param int unique ID of interval (returned by setInterval() previously)
+ */
+ clearInterval: function(intervalid)
+ {
+ window.clearInterval(intervalid);
+ this.intervals.splice( jQuery.inArray(intervalid, this.intervals), 1 );
+ },
+
+ /**
+ * Tells whether this is a wrapper that has already been deregistered and is lingering
+ * @return bool true if object
+ */
+ isLingering: function()
+ {
+ return !this.registered;
+ },
+
+ /**
+ * Deinitializes the control wrapper by calling the onDone method and the deregistering it
+ * @param array control wrapper options
+ */
+ deinitialize : function()
+ {
+ if (this.registered)
+ {
+ if(this.onDone)
+ this.onDone();
+
+ // automatically stop all intervals
+ while (this.intervals.length>0)
+ window.clearInterval(this.intervals.pop());
+
+ // automatically deregister all installed observers
+ while (this.observers.length>0)
+ {
+ var e = this.observers.pop();
+ jQuery(e._element).unbind(e._eventName, e._handler);
+ }
+ }
+ else
+ debugger; // shouldn't happen
+
+ this.deregister();
+
+ this.registered = false;
+ }
+
+});
+
+Prado.WebUI.PostBackControl = jQuery.klass(Prado.WebUI.Control, {
+
+ onInit : function(options)
+ {
+ this._elementOnClick = null;
+
+ if (!this.element)
+ debugger; // element not found
+ else
+ {
+ //capture the element's onclick function
+ if(typeof(this.element.onclick)=="function")
+ {
+ this._elementOnClick = this.element.onclick.bind(this.element);
+ this.element.onclick = null;
+ }
+ this.observe(this.element, "click", jQuery.proxy(this.elementClicked,this,options));
+ }
+ },
+
+ elementClicked : function(options, event)
+ {
+ var src = event.target;
+ var doPostBack = true;
+ var onclicked = null;
+
+ if(this._elementOnClick)
+ {
+ var onclicked = this._elementOnClick(event);
+ if(typeof(onclicked) == "boolean")
+ doPostBack = onclicked;
+ }
+ if(doPostBack && !jQuery(src).is(':disabled'))
+ this.onPostBack(options,event);
+ if(typeof(onclicked) == "boolean" && !onclicked)
+ {
+ event.stopPropagation();
+ event.preventDefault();
+ return false;
+ }
+ },
+
+ onPostBack : function(options, event)
+ {
+ new Prado.PostBack(options, event);
+ }
+
+});
+
+Prado.WebUI.TButton = jQuery.klass(Prado.WebUI.PostBackControl);
+Prado.WebUI.TLinkButton = jQuery.klass(Prado.WebUI.PostBackControl);
+Prado.WebUI.TCheckBox = jQuery.klass(Prado.WebUI.PostBackControl);
+Prado.WebUI.TBulletedList = jQuery.klass(Prado.WebUI.PostBackControl);
+Prado.WebUI.TImageMap = jQuery.klass(Prado.WebUI.PostBackControl);
+
+/**
+ * TImageButton client-side behaviour. With validation, Firefox needs
+ * to capture the x,y point of the clicked image in hidden form fields.
+ */
+Prado.WebUI.TImageButton = jQuery.klass(Prado.WebUI.PostBackControl,
+{
+ /**
+ * Override parent onPostBack function, tried to add hidden forms
+ * inputs to capture x,y clicked point.
+ */
+ onPostBack : function(options, event)
+ {
+ this.addXYInput(options, event);
+ new Prado.PostBack(options, event);
+ this.removeXYInput(options, event);
+ },
+
+ /**
+ * Add hidden inputs to capture the x,y point clicked on the image.
+ * @param event DOM click event.
+ * @param array image button options.
+ */
+ addXYInput : function(options, event)
+ {
+ var imagePos = jQuery(this.element).offset();
+ var clickedPos = [event.clientX, event.clientY];
+ var x = clickedPos[0]-imagePos['left']+1;
+ var y = clickedPos[1]-imagePos['top']+1;
+ x = x < 0 ? 0 : x;
+ y = y < 0 ? 0 : y;
+ var id = this.element.id;
+ var name = options['EventTarget'];
+ var form = this.element.form;
+
+ var input=null;
+ input = document.createElement("input");
+ input.setAttribute("type", "hidden");
+ input.setAttribute("id", id+"_x");
+ input.setAttribute("name", name+"_x");
+ input.setAttribute("value", x);
+ form.appendChild(input);
+
+ input = document.createElement("input");
+ input.setAttribute("type", "hidden");
+ input.setAttribute("id", id+"_y");
+ input.setAttribute("name", name+"_y");
+ input.setAttribute("value", y);
+ form.appendChild(input);
+ },
+
+ /**
+ * Remove hidden inputs for x,y-click capturing
+ * @param event DOM click event.
+ * @param array image button options.
+ */
+ removeXYInput : function(options, event)
+ {
+ var id = this.element.id;
+ jQuery('#'+id+'_x').remove();
+ jQuery('#'+id+'_y').remove();
+ }
+});
+
+
+/**
+ * Radio button, only initialize if not already checked.
+ */
+Prado.WebUI.TRadioButton = jQuery.klass(Prado.WebUI.PostBackControl,
+{
+ initialize : function($super, options)
+ {
+ this.element = jQuery("#" + options['ID']).get(0);
+ if(this.element)
+ {
+ if(!this.element.checked)
+ $super(options);
+ }
+ }
+});
+
+
+Prado.WebUI.TTextBox = jQuery.klass(Prado.WebUI.PostBackControl,
+{
+ onInit : function(options)
+ {
+ this.options=options;
+ if(this.options['TextMode'] != 'MultiLine')
+ this.observe(this.element, "keydown", this.handleReturnKey.bind(this));
+ if(this.options['AutoPostBack']==true)
+ this.observe(this.element, "change", jQuery.proxy(this.doPostback,this,options));
+ },
+
+ doPostback : function(options, event)
+ {
+ new Prado.PostBack(options, event);
+ },
+
+ handleReturnKey : function(e)
+ {
+ if(e.keyCode == 13) // KEY_RETURN
+ {
+ var target = e.target;
+ if(target)
+ {
+ if(this.options['AutoPostBack']==true)
+ {
+ jQuery(target).trigger( "change" );
+ e.stopPropagation();
+ }
+ else
+ {
+ if(this.options['CausesValidation'] && typeof(Prado.Validation) != "undefined")
+ {
+ if(!Prado.Validation.validate(this.options['FormID'], this.options['ValidationGroup'], jQuery(this.options['ID'])))
+ return e.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+});
+
+Prado.WebUI.TListControl = jQuery.klass(Prado.WebUI.PostBackControl,
+{
+ onInit : function(options)
+ {
+ this.observe(this.element, "change", jQuery.proxy(this.doPostback,this,options));
+ },
+
+ doPostback : function(options, event)
+ {
+ new Prado.PostBack(options, event);
+ }
+});
+
+Prado.WebUI.TListBox = jQuery.klass(Prado.WebUI.TListControl);
+Prado.WebUI.TDropDownList = jQuery.klass(Prado.WebUI.TListControl);
+
+Prado.WebUI.DefaultButton = jQuery.klass(Prado.WebUI.Control,
+{
+ onInit : function(options)
+ {
+ this.options = options;
+ this.observe(jQuery('#'+options['Panel']), "keydown", jQuery.proxy(this.triggerEvent,this));
+ },
+
+ triggerEvent : function(ev)
+ {
+ var enterPressed = ev.keyCode == 13;
+ var isTextArea = ev.target.tagName.toLowerCase() == "textarea";
+ var isHyperLink = ev.target.tagName.toLowerCase() == "a" && ev.target.hasAttribute("href");
+ var isValidButton = ev.target.tagName.toLowerCase() == "input" && ev.target.type.toLowerCase() == "submit";
+
+ if(enterPressed && !isTextArea && !isValidButton && !isHyperLink)
+ {
+ var defaultButton = jQuery('#'+this.options['Target']);
+ if(defaultButton)
+ {
+ this.triggered = true;
+ defaultButton.trigger(this.options['Event']);
+ ev.preventDefault();
+ }
+ }
+ }
+});
+
+Prado.WebUI.TTextHighlighter = jQuery.klass();
+Prado.WebUI.TTextHighlighter.prototype =
+{
+ initialize:function(id)
+ {
+ if(!window.clipboardData) return;
+ var options =
+ {
+ href : 'javascript:;/'+'/copy code to clipboard',
+ onclick : 'Prado.WebUI.TTextHighlighter.copy(this)',
+ onmouseover : 'Prado.WebUI.TTextHighlighter.hover(this)',
+ onmouseout : 'Prado.WebUI.TTextHighlighter.out(this)'
+ }
+ var div = DIV({className:'copycode'}, A(options, 'Copy Code'));
+ document.write(DIV(null,div).innerHTML);
+ }
+};
+
+jQuery.klass(Prado.WebUI.TTextHighlighter,
+{
+ copy : function(obj)
+ {
+ var parent = obj.parentNode.parentNode.parentNode;
+ var text = '';
+ for(var i = 0; i < parent.childNodes.length; i++)
+ {
+ var node = parent.childNodes[i];
+ if(node.innerText)
+ text += node.innerText == 'Copy Code' ? '' : node.innerText;
+ else
+ text += node.nodeValue;
+ }
+ if(text.length > 0)
+ window.clipboardData.setData("Text", text);
+ },
+
+ hover : function(obj)
+ {
+ obj.parentNode.className = "copycode copycode_hover";
+ },
+
+ out : function(obj)
+ {
+ obj.parentNode.className = "copycode";
+ }
+});
+
+
+Prado.WebUI.TCheckBoxList = jQuery.klass(Prado.WebUI.Control,
+{
+ onInit : function(options)
+ {
+ for(var i = 0; i<options.ItemCount; i++)
+ {
+ var checkBoxOptions = jQuery.extend({}, options,
+ {
+ ID : options.ID+"_c"+i,
+ EventTarget : options.ListName+"$c"+i
+ });
+ new Prado.WebUI.TCheckBox(checkBoxOptions);
+ }
+ }
+});
+
+Prado.WebUI.TRadioButtonList = jQuery.klass(Prado.WebUI.Control,
+{
+ onInit : function(options)
+ {
+ for(var i = 0; i<options.ItemCount; i++)
+ {
+ var radioButtonOptions = jQuery.extend({}, options,
+ {
+ ID : options.ID+"_c"+i,
+ EventTarget : options.ListName+"$c"+i
+ });
+ new Prado.WebUI.TRadioButton(radioButtonOptions);
+ }
+ }
+});
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/controls/htmlarea.js b/lib/prado/framework/Web/Javascripts/source/prado/controls/htmlarea.js
new file mode 100644
index 0000000..aa0a5d4
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/controls/htmlarea.js
@@ -0,0 +1,148 @@
+
+/*
+ *
+ * HtmlArea (tinyMCE) wrapper
+ *
+ * @author Gabor Berczi <gabor.berczi@devworx.hu>
+ *
+*/
+
+
+Prado.WebUI.THtmlArea = jQuery.klass(Prado.WebUI.Control,
+{
+ initialize: function($super, options)
+ {
+ options.ID = options.EditorOptions.elements;
+ $super(options);
+ },
+
+ onInit : function(options)
+ {
+ this.options = options;
+
+ this.registerAjaxHook();
+
+ this.registerInstance();
+ },
+
+
+
+ registerInstance: function()
+ {
+ if (typeof tinyMCE_GZ == 'undefined')
+ {
+ if (typeof tinyMCE == 'undefined')
+ {
+ if (typeof Prado.CallbackRequest != 'undefined')
+ if (typeof Prado.CallbackRequest.transport != 'undefined')
+ {
+ // we're in a callback
+ // try it again in some time, as tinyMCE is most likely still loading
+ this.setTimeout(this.registerInstance.bind(this), 50);
+ return;
+ }
+ throw "TinyMCE libraries must be loaded first";
+ }
+ Prado.WebUI.THtmlArea.tinyMCELoadState = 255;
+ this.initInstance();
+ }
+ else
+ if (Prado.WebUI.THtmlArea.tinyMCELoadState==255)
+ this.initInstance();
+ else
+ {
+ Prado.WebUI.THtmlArea.pendingRegistrations.push(this.options.ID);
+ if (Prado.WebUI.THtmlArea.tinyMCELoadState==0)
+ {
+ Prado.WebUI.THtmlArea.tinyMCELoadState = 1;
+ tinyMCE_GZ.init(
+ this.options.CompressionOptions,
+ this.compressedScriptsLoaded.bind(this)
+ );
+ }
+ }
+ },
+
+ compressedScriptsLoaded: function()
+ {
+ Prado.WebUI.THtmlArea.tinyMCELoadState = 255;
+ var wrapper;
+ while(Prado.WebUI.THtmlArea.pendingRegistrations.length>0)
+ if (wrapper = Prado.Registry[Prado.WebUI.THtmlArea.pendingRegistrations.pop()])
+ wrapper.initInstance();
+ },
+
+ initInstance: function()
+ {
+ tinyMCE.init(this.options.EditorOptions);
+ },
+
+ checkInstance: function()
+ {
+ if (!document.getElementById(this.ID))
+ this.deinitialize();
+ },
+
+ removePreviousInstance: function()
+ {
+ for(var i=0;i<tinyMCE.editors.length;i++)
+ if (tinyMCE.editors[i].id==this.ID)
+ {
+ tinyMCE.editors.splice(i,1); // ugly hack, but works
+ this.deRegisterAjaxHook();
+ this.deregister();
+ i--;
+ }
+ },
+
+ registerAjaxHook: function()
+ {
+ jQuery(document).on('ajaxComplete', this.ajaxresponder.bind(this));
+ },
+
+
+ deRegisterAjaxHook: function()
+ {
+ jQuery(document).off('ajaxComplete', this.ajaxresponder.bind(this));
+ },
+
+ ajaxresponder: function(request)
+ {
+ if(request && (request instanceof Prado.CallbackRequest))
+ this.checkInstance();
+ },
+
+ onDone: function()
+ {
+ // check for previous tinyMCE registration, and try to remove it gracefully first
+ var prev = tinyMCE.get(this.ID);
+ if (prev)
+ try
+ {
+ tinyMCE.execCommand('mceFocus', false, this.ID);
+ // when removed, tinyMCE restores its content to the textarea. If the textarea content has been
+ // updated in this same callback, it will be overwritten with the old content. Workaround this.
+ var curtext = jQuery('#'+this.ID).get(0).value;
+ tinyMCE.execCommand('mceRemoveControl', false, this.ID);
+ jQuery('#'+this.ID).get(0).value = curtext;
+ }
+ catch (e)
+ {
+ // suppress error here in case editor can't be properly removed
+ // (happens when <textarea> has been removed from DOM tree without deinitialzing the tinyMCE editor first)
+ }
+
+ // doublecheck editor instance here and remove manually from tinyMCE-registry if neccessary
+ this.removePreviousInstance();
+
+ this.deRegisterAjaxHook();
+ }
+});
+
+jQuery.extend(Prado.WebUI.THtmlArea,
+{
+ pendingRegistrations : [],
+ tinyMCELoadState : 0
+});
+
+
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/controls/htmlarea4.js b/lib/prado/framework/Web/Javascripts/source/prado/controls/htmlarea4.js
new file mode 100644
index 0000000..64a7817
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/controls/htmlarea4.js
@@ -0,0 +1,58 @@
+
+/*
+ *
+ * HtmlArea (tinyMCE 4) wrapper
+ *
+ * @author Gabor Berczi <gabor.berczi@devworx.hu>
+ *
+*/
+
+
+Prado.WebUI.THtmlArea4 = jQuery.klass(Prado.WebUI.Control,
+{
+ initialize: function($super, options)
+ {
+ options.ID = options.EditorOptions.elements;
+ $super(options);
+ },
+
+ onInit : function(options)
+ {
+ this.options = options;
+ tinyMCE.init(this.options.EditorOptions);
+ },
+
+ removePreviousInstance: function()
+ {
+ for(var i=0;i<tinyMCE.editors.length;i++)
+ if (tinyMCE.editors[i].id==this.ID)
+ {
+ tinyMCE.editors.splice(i,1); // ugly hack, but works
+ i--;
+ }
+ },
+
+ onDone: function()
+ {
+ // check for previous tinyMCE registration, and try to remove it gracefully first
+ var prev = tinyMCE.get(this.ID);
+ if (prev)
+ try
+ {
+ tinyMCE.execCommand('mceFocus', false, this.ID);
+ // when removed, tinyMCE restores its content to the textarea. If the textarea content has been
+ // updated in this same callback, it will be overwritten with the old content. Workaround this.
+ // var curtext = jQuery(this.ID).html();
+ tinyMCE.execCommand('mceRemoveControl', false, this.ID);
+ // jQuery(this.ID).html(curtext);
+ }
+ catch (e)
+ {
+ // suppress error here in case editor can't be properly removed
+ // (happens when <textarea> has been removed from DOM tree without deinitialzing the tinyMCE editor first)
+ }
+
+ // doublecheck editor instance here and remove manually from tinyMCE-registry if neccessary
+ this.removePreviousInstance();
+ }
+});
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/controls/keyboard.js b/lib/prado/framework/Web/Javascripts/source/prado/controls/keyboard.js
new file mode 100644
index 0000000..768b8d8
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/controls/keyboard.js
@@ -0,0 +1,161 @@
+Prado.WebUI.TKeyboard = jQuery.klass(Prado.WebUI.Control,
+{
+ onInit : function(options)
+ {
+ this.cssClass = options['CssClass'];
+ this.forControl = document.getElementById(options['ForControl']);
+ this.autoHide = options['AutoHide'];
+
+ this.flagShift = false;
+ this.flagCaps = false;
+ this.flagHover = false;
+ this.flagFocus = false;
+
+ this.keys = new Array
+ (
+ new Array('` ~ D', '1 ! D', '2 @ D', '3 # D', '4 $ D', '5 % D', '6 ^ D', '7 &amp; D', '8 * D', '9 ( D', '0 ) D', '- _ D', '= + D', 'Bksp Bksp Bksp'),
+ new Array('Del Del Del', 'q Q L', 'w W L', 'e E L', 'r R L', 't T L', 'y Y L', 'u U L', 'i I L', 'o O L', 'p P L', '[ { D', '] } D', '\\ | \\'),
+ new Array('Caps Caps Caps', 'a A L', 's S L', 'd D L', 'f F L', 'g G L', 'h H L', 'j J L', 'k K L', 'l L L', '; : D', '\' " D', 'Exit Exit Exit'),
+ new Array('Shift Shift Shift', 'z Z L', 'x X L', 'c C L', 'v V L', 'b B L', 'n N L', 'm M L', ', &lt; D', '. &gt; D', '/ ? D', 'Shift Shift Shift')
+ );
+
+ if (this.isObject(this.forControl))
+ {
+ this.forControl.keyboard = this;
+ this.forControl.onfocus = function() {this.keyboard.show(); };
+ this.forControl.onblur = function() {if (this.keyboard.flagHover == false) this.keyboard.hide();};
+ this.forControl.onkeydown = function(e) {if (!e) e = window.event; var key = (e.keyCode)?e.keyCode:e.which; if(key == 9) this.keyboard.hide();;};
+ this.forControl.onselect = this.saveSelection;
+ this.forControl.onclick = this.saveSelection;
+ this.forControl.onkeyup = this.saveSelection;
+ }
+
+ this.render();
+
+ this.tagKeyboard.onmouseover = function() {this.keyboard.flagHover = true;};
+ this.tagKeyboard.onmouseout = function() {this.keyboard.flagHover = false;};
+
+ if (!this.autoHide) this.show();
+ },
+
+ isObject : function(a)
+ {
+ return (typeof a == 'object' && !!a) || typeof a == 'function';
+ },
+
+ createElement : function(tagName, attributes, parent)
+ {
+ var tagElement = document.createElement(tagName);
+ if (this.isObject(attributes)) for (attribute in attributes) tagElement[attribute] = attributes[attribute];
+ if (this.isObject(parent)) parent.appendChild(tagElement);
+ return tagElement;
+ },
+
+ onmouseover : function()
+ {
+ this.className += ' Hover';
+ },
+
+ onmouseout : function()
+ {
+ this.className = this.className.replace(/( Hover| Active)/ig, '');
+ },
+
+ onmousedown : function()
+ {
+ this.className += ' Active';
+ },
+
+ onmouseup : function()
+ {
+ this.className = this.className.replace(/( Active)/ig, '');
+ this.keyboard.type(this.innerHTML);
+ },
+
+ render : function()
+ {
+ this.tagKeyboard = this.createElement('div', {className: this.cssClass, onselectstart: function() {return false;}}, this.element);
+ this.tagKeyboard.keyboard = this;
+
+ for (var line = 0; line < this.keys.length; line++)
+ {
+ var tagLine = this.createElement('div', {className: 'Line'}, this.tagKeyboard);
+ for (var key = 0; key < this.keys[line].length; key++)
+ {
+ var split = this.keys[line][key].split(' ');
+ var tagKey = this.createElement('div', {className: 'Key ' + split[2]}, tagLine);
+ var tagKey1 = this.createElement('div', {className: 'Key1', innerHTML: split[0], keyboard: this, onmouseover: this.onmouseover, onmouseout: this.onmouseout, onmousedown: this.onmousedown, onmouseup: this.onmouseup}, tagKey);
+ var tagKey2 = this.createElement('div', {className: 'Key2', innerHTML: split[1], keyboard: this, onmouseover: this.onmouseover, onmouseout: this.onmouseout, onmousedown: this.onmousedown, onmouseup: this.onmouseup}, tagKey);
+ }
+ }
+ },
+
+ isShown : function()
+ {
+ return (this.tagKeyboard.style.visibility.toLowerCase() == 'visible');
+ },
+
+ show : function()
+ {
+ if (this.isShown() == false) this.tagKeyboard.style.visibility = 'visible';
+ },
+
+ hide : function()
+ {
+ if (this.isShown() == true && this.autoHide) {this.tagKeyboard.style.visibility = 'hidden'; }
+ },
+
+ type : function(key)
+ {
+ var input = this.forControl;
+ var command = key.toLowerCase();
+
+ if (command == 'exit') {this.hide();}
+ else if (input != 'undefined' && input != null && command == 'bksp') {this.insert(input, 'bksp');}
+ else if (input != 'undefined' && input != null && command == 'del') {this.insert(input, 'del');}
+ else if (command == 'shift') {this.tagKeyboard.className = this.flagShift?'Keyboard Off':'Keyboard Shift';this.flagShift = this.flagShift?false:true;}
+ else if (command == 'caps') {this.tagKeyboard.className = this.caps?'Keyboard Off':'Keyboard Caps';this.caps = this.caps?false:true;}
+ else if (input != 'undefined' && input != null)
+ {
+ if (this.flagShift == true) {this.flagShift = false; this.tagKeyboard.className = 'Keyboard Off';}
+ key = key.replace(/&gt;/, '>'); key = key.replace(/&lt;/, '<'); key = key.replace(/&amp;/, '&');
+ this.insert(input, key);
+ }
+
+ if (command != 'exit') input.focus();
+ },
+
+ saveSelection : function()
+ {
+ if (this.keyboard.forControl.createTextRange)
+ {
+ this.keyboard.selection = document.selection.createRange().duplicate();
+ return;
+ }
+ },
+
+ insert : function(field, value)
+ {
+ if (this.forControl.createTextRange && this.selection)
+ {
+ if (value == 'bksp') {this.selection.moveStart("character", -1); this.selection.text = '';}
+ else if (value == 'del') {this.selection.moveEnd("character", 1); this.selection.text = '';}
+ else {this.selection.text = value;}
+ this.selection.select();
+ }
+ else
+ {
+ var selectStart = this.forControl.selectionStart;
+ var selectEnd = this.forControl.selectionEnd;
+ var start = (this.forControl.value).substring(0, selectStart);
+ var end = (this.forControl.value).substring(selectEnd, this.forControl.textLength);
+
+ if (value == 'bksp') {start = start.substring(0, start.length - 1); selectStart -= 1; value = '';}
+ if (value == 'del') {end = end.substring(1, end.length); value = '';}
+
+ this.forControl.value = start + value + end;
+ this.forControl.selectionStart = selectEnd + value.length;
+ this.forControl.selectionEnd = selectStart + value.length;
+ }
+ }
+});
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/controls/slider.js b/lib/prado/framework/Web/Javascripts/source/prado/controls/slider.js
new file mode 100644
index 0000000..1f1507e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/controls/slider.js
@@ -0,0 +1,235 @@
+/**
+ * TSlider client class.
+ * This clas is mainly based on Scriptaculous Slider control (http://script.aculo.us)
+ */
+
+Prado.WebUI.TSlider = jQuery.klass(Prado.WebUI.PostBackControl,
+{
+ onInit : function (options)
+ {
+ var slider = this;
+ this.options=options || {};
+ this.track = jQuery('#'+options.ID+'_track').get(0);
+ this.handle =jQuery('#'+options.ID+'_handle').get(0);
+ this.progress = jQuery('#'+options.ID+'_progress').get(0);
+ this.axis = this.options.axis || 'horizontal';
+ this.range = this.options.range || [0, 1];
+ this.value = 0;
+ this.maximum = this.options.maximum || this.range[1];
+ this.minimum = this.options.minimum || this.range[0];
+ this.hiddenField=jQuery('#'+this.options.ID+'_1').get(0);
+ this.trackInitialized=false;
+
+ this.initializeTrack();
+
+ this.active = false;
+ this.dragging = false;
+ this.disabled = false;
+
+ if(this.options.disabled) this.setDisabled();
+
+ // Allowed values array
+ this.allowedValues = this.options.values ? this.options.values.sort() : false;
+ if(this.allowedValues) {
+ this.minimum = Math.min.apply( Math, this.allowedValues );
+ this.maximum = Math.max.apply( Math, this.allowedValues );
+ }
+
+ this.eventMouseDown = this.startDrag.bind(this);
+ this.eventMouseUp = this.endDrag.bind(this);
+ this.eventMouseMove = this.update.bind(this);
+
+ // Initialize handle
+ this.setValue(parseFloat(slider.options.sliderValue));
+ this.observe (this.handle, "mousedown", this.eventMouseDown);
+
+ this.observe (this.track, "mousedown", this.eventMouseDown);
+ if (this.progress) this.observe (this.progress, "mousedown", this.eventMouseDown);
+
+ this.observe (document, "mouseup", this.eventMouseUp);
+ this.observe (document, "mousemove", this.eventMouseMove);
+
+ this.initialized=true;
+
+ if(this.options['AutoPostBack']==true)
+ this.observe(this.hiddenField, "change", jQuery.proxy(this.doPostback,this,options));
+ },
+
+ initializeTrack : function()
+ {
+ if(this.trackInitialized || !$(this.track).is(":visible"))
+ return;
+
+ // Will be used to align the handle onto the track, if necessary
+ this.alignX = parseInt(this.options.alignX || - this.track.offsetLeft);
+ this.alignY = parseInt(this.options.alignY || - this.track.offsetTop);
+
+ this.trackLength = this.maximumOffset() - this.minimumOffset();
+ this.handleLength = this.isVertical() ?
+ (this.handle.offsetHeight != 0 ?
+ this.handle.offsetHeight : this.handles.style.height.replace(/px$/,"")) :
+ (this.handle.offsetWidth != 0 ? this.handle.offsetWidth :
+ this.handle.style.width.replace(/px$/,""));
+ this.trackInitialized=true;
+ },
+
+ doPostback : function(options, event)
+ {
+ new Prado.PostBack(options, event);
+ },
+
+ setDisabled: function(){
+ this.disabled = true;
+ },
+ setEnabled: function(){
+ this.disabled = false;
+ },
+ getNearestValue: function(value){
+ if(this.allowedValues){
+ var max = Math.max.apply( Math, this.allowedValues );
+ var min = Math.min.apply( Math, this.allowedValues );
+ if(value >= max) return(max);
+ if(value <= min) return(min);
+
+ var offset = Math.abs(this.allowedValues[0] - value);
+ var newValue = this.allowedValues[0];
+ jQuery.each(this.allowedValues, function(idx, v) {
+ var currentOffset = Math.abs(v - value);
+ if(currentOffset <= offset){
+ newValue = v;
+ offset = currentOffset;
+ }
+ });
+ return newValue;
+ }
+ if(value > this.range[1]) return this.range[1];
+ if(value < this.range[0]) return this.range[0];
+ return value;
+ },
+
+ setValue: function(sliderValue){
+ if(!this.active) {
+ this.updateStyles();
+ }
+ this.value = this.getNearestValue(sliderValue);
+ var pixelValue= this.translateToPx(this.value);
+ this.handle.style[this.isVertical() ? 'top' : 'left'] = pixelValue;
+ if (this.progress)
+ this.progress.style[this.isVertical() ? 'height' : 'width'] = pixelValue;
+
+ //this.drawSpans();
+ if(!this.dragging || !this.event) this.updateFinished();
+ },
+
+ setValueBy: function(delta) {
+ this.setValue(this.value + delta);
+ },
+
+ translateToPx: function(value) {
+ return Math.round(
+ ((this.trackLength-this.handleLength)/(this.range[1]-this.range[0])) * (value - this.range[0])) + "px";
+ },
+
+ translateToValue: function(offset) {
+ return ((offset/(this.trackLength-this.handleLength) * (this.range[1]-this.range[0])) + this.range[0]);
+ },
+
+ minimumOffset: function(){
+ return(this.isVertical() ? this.alignY : this.alignX);
+ },
+
+ maximumOffset: function(){
+ return(this.isVertical() ?
+ (this.track.offsetHeight != 0 ? this.track.offsetHeight :
+ this.track.style.height.replace(/px$/,"")) - this.alignY :
+ (this.track.offsetWidth != 0 ? this.track.offsetWidth :
+ this.track.style.width.replace(/px$/,"")) - this.alignX);
+ },
+
+ isVertical: function(){
+ return (this.axis == 'vertical');
+ },
+
+ updateStyles: function() {
+ if (this.active)
+ jQuery(this.handle).addClass('selected');
+ else
+ jQuery(this.handle).removeClass('selected');
+ },
+
+ startDrag: function(event) {
+ if (event.which === 1) {
+ this.initializeTrack();
+ // left click
+ if(!this.disabled){
+ this.active = true;
+ var handle = event.target;
+ var pointer = [event.pageX, event.pageY];
+ var track = handle;
+ if(track==this.track) {
+ var offsets = jQuery(this.track).offset();
+ this.event = event;
+ this.setValue(this.translateToValue(
+ (this.isVertical() ? pointer[1]-offsets['top'] : pointer[0]-offsets['left'])-(this.handleLength/2)
+ ));
+ var offsets = jQuery(this.handle).offset();
+ this.offsetX = (pointer[0] - offsets['left']);
+ this.offsetY = (pointer[1] - offsets['top']);
+ } else {
+ this.updateStyles();
+ var offsets = jQuery(this.handle).offset();
+ this.offsetX = (pointer[0] - offsets['left']);
+ this.offsetY = (pointer[1] - offsets['top']);
+ }
+ }
+ event.stopPropagation();
+ }
+ },
+
+ update: function(event) {
+ if(this.active) {
+ if(!this.dragging) this.dragging = true;
+ this.draw(event);
+ event.stopPropagation();
+ }
+ },
+
+ draw: function(event) {
+ var pointer = [event.pageX, event.pageY];
+ var offsets = jQuery(this.track).offset();
+ pointer[0] -= this.offsetX + offsets['left'];
+ pointer[1] -= this.offsetY + offsets['top'];
+ this.event = event;
+ this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
+ if(this.initialized && this.options.onSlide)
+ this.options.onSlide(this.value, this);
+ },
+
+ endDrag: function(event) {
+ if(this.active && this.dragging) {
+ this.finishDrag(event, true);
+ event.stopPropagation();
+ }
+ this.active = false;
+ this.dragging = false;
+ },
+
+ finishDrag: function(event, success) {
+ this.active = false;
+ this.dragging = false;
+ this.updateFinished();
+ },
+
+ updateFinished: function() {
+ this.hiddenField.value=this.value;
+ this.updateStyles();
+ if(this.initialized && this.options.onChange)
+ this.options.onChange(this.value, this);
+ this.event = null;
+ if (this.options['AutoPostBack']==true)
+ {
+ jQuery(this.hiddenField).trigger("change");
+ }
+ }
+
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/controls/tabpanel.js b/lib/prado/framework/Web/Javascripts/source/prado/controls/tabpanel.js
new file mode 100644
index 0000000..61a18a2
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/controls/tabpanel.js
@@ -0,0 +1,60 @@
+Prado.WebUI.TTabPanel = jQuery.klass(Prado.WebUI.Control,
+{
+ onInit : function(options)
+ {
+ this.views = options.Views;
+ this.viewsvis = options.ViewsVis;
+ this.hiddenField = jQuery("#"+options.ID+'_1').get(0);
+ this.activeCssClass = options.ActiveCssClass;
+ this.normalCssClass = options.NormalCssClass;
+ var length = options.Views.length;
+ for(var i = 0; i<length; i++)
+ {
+ var item = options.Views[i];
+ var element = jQuery("#"+item+'_0').get(0);
+ if (element && options.ViewsVis[i])
+ {
+ this.observe(element, "click", jQuery.proxy(this.elementClicked,this,item));
+ if (options.AutoSwitch)
+ this.observe(element, "mouseenter", jQuery.proxy(this.elementClicked,this,item));
+ }
+
+ if(element)
+ {
+ var view = jQuery("#"+options.Views[i]).get(0);
+ if (view)
+ if(this.hiddenField.value == i)
+ {
+ jQuery(element).addClass(this.activeCssClass).removeClass(this.normalCssClass);
+ jQuery(view).show();
+ } else {
+ jQuery(element).addClass(this.normalCssClass).removeClass(this.activeCssClass);
+ jQuery(view).hide();
+ }
+ }
+ }
+ },
+
+ elementClicked : function(viewID, event)
+ {
+ var length = this.views.length;
+ for(var i = 0; i<length; i++)
+ {
+ var item = this.views[i];
+ if (jQuery("#"+item))
+ {
+ if(item == viewID)
+ {
+ jQuery("#"+item+'_0').removeClass(this.normalCssClass).addClass(this.activeCssClass);
+ jQuery("#"+item).show();
+ this.hiddenField.value=i;
+ }
+ else
+ {
+ jQuery("#"+item+'_0').removeClass(this.activeCssClass).addClass(this.normalCssClass);
+ jQuery("#"+item).hide();
+ }
+ }
+ }
+ }
+});
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/datepicker/calendar.png b/lib/prado/framework/Web/Javascripts/source/prado/datepicker/calendar.png
new file mode 100644
index 0000000..c245f1b
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/datepicker/calendar.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/datepicker/datepicker.js b/lib/prado/framework/Web/Javascripts/source/prado/datepicker/datepicker.js
new file mode 100644
index 0000000..68b3145
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/datepicker/datepicker.js
@@ -0,0 +1,759 @@
+Prado.WebUI.TDatePicker = jQuery.klass(Prado.WebUI.Control,
+{
+ MonthNames : [ "January", "February", "March", "April",
+ "May", "June", "July", "August",
+ "September", "October", "November", "December"
+ ],
+ AbbreviatedMonthNames : ["Jan", "Feb", "Mar", "Apr", "May",
+ "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ ShortWeekDayNames : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ],
+
+ Format : "yyyy-MM-dd",
+
+ FirstDayOfWeek : 1, // 0 for sunday
+
+ ClassName : "",
+
+ CalendarStyle : "default",
+
+ FromYear : 2005, UpToYear: 2020,
+
+ onInit : function(options)
+ {
+ this.options = options || [];
+ this.control = jQuery('#'+options.ID).get(0);
+ this.dateSlot = new Array(42);
+ this.weekSlot = new Array(6);
+ this.minimalDaysInFirstWeek = 4;
+ this.positionMode = 'Bottom';
+
+ Prado.Registry[options.ID] = this;
+
+ //which element to trigger to show the calendar
+ if(this.options.Trigger)
+ {
+ this.trigger = jQuery('#'+this.options.Trigger).get(0);
+ var triggerEvent = this.options.TriggerEvent || "click";
+ }
+ else
+ {
+ this.trigger = this.control;
+ var triggerEvent = this.options.TriggerEvent || "focus";
+ }
+
+ // Popup position
+ if(this.options.PositionMode == 'Top')
+ {
+ this.positionMode = this.options.PositionMode;
+ }
+
+ jQuery.extend(this,options);
+ // generate default date _after_ extending options
+ this.selectedDate = this.newDate();
+
+ this.observe(this.trigger, triggerEvent, jQuery.proxy(this.show,this));
+
+ // Listen to change event if needed
+ if (typeof(this.options.OnDateChanged) == "function")
+ {
+ if(this.options.InputMode == "TextBox")
+ {
+ this.observe(this.control, "change", jQuery.proxy(this.onDateChanged,this));
+ }
+ else
+ {
+ var day = Prado.WebUI.TDatePicker.getDayListControl(this.control);
+ var month = Prado.WebUI.TDatePicker.getMonthListControl(this.control);
+ var year = Prado.WebUI.TDatePicker.getYearListControl(this.control);
+ this.observe (day, "change", jQuery.proxy(this.onDateChanged,this));
+ this.observe (month, "change", jQuery.proxy(this.onDateChanged,this));
+ this.observe (year, "change", jQuery.proxy(this.onDateChanged,this));
+
+ }
+
+
+ }
+
+ },
+
+ create : function()
+ {
+ if(typeof(this._calDiv) != "undefined")
+ return;
+
+ var div;
+ var table;
+ var tbody;
+ var tr;
+ var td;
+
+ // Create the top-level div element
+ this._calDiv = document.createElement("div");
+ this._calDiv.className = "TDatePicker_"+this.CalendarStyle+" "+this.ClassName;
+ this._calDiv.style.display = "none";
+ this._calDiv.style.position = "absolute"
+
+ // header div
+ div = document.createElement("div");
+ div.className = "calendarHeader";
+ this._calDiv.appendChild(div);
+
+ table = document.createElement("table");
+ table.style.cellSpacing = 0;
+ div.appendChild(table);
+
+ tbody = document.createElement("tbody");
+ table.appendChild(tbody);
+
+ tr = document.createElement("tr");
+ tbody.appendChild(tr);
+
+ // Previous Month Button
+ td = document.createElement("td");
+ var previousMonth = document.createElement("input");
+ previousMonth.className = "prevMonthButton button";
+ previousMonth.type = "button"
+ previousMonth.value = "<<";
+ td.appendChild(previousMonth);
+ tr.appendChild(td);
+
+
+
+ //
+ // Create the month drop down
+ //
+ td = document.createElement("td");
+ tr.appendChild(td);
+ this._monthSelect = document.createElement("select");
+ this._monthSelect.className = "months";
+ for (var i = 0 ; i < this.MonthNames.length ; i++) {
+ var opt = document.createElement("option");
+ opt.innerHTML = this.MonthNames[i];
+ opt.value = i;
+ if (i == this.selectedDate.getMonth()) {
+ opt.selected = true;
+ }
+ this._monthSelect.appendChild(opt);
+ }
+ td.appendChild(this._monthSelect);
+
+
+ //
+ // Create the year drop down
+ //
+ td = document.createElement("td");
+ td.className = "labelContainer";
+ tr.appendChild(td);
+ this._yearSelect = document.createElement("select");
+ for(var i=this.FromYear; i <= this.UpToYear; ++i) {
+ var opt = document.createElement("option");
+ opt.innerHTML = i;
+ opt.value = i;
+ if (i == this.selectedDate.getFullYear()) {
+ opt.selected = false;
+ }
+ this._yearSelect.appendChild(opt);
+ }
+ td.appendChild(this._yearSelect);
+
+
+ td = document.createElement("td");
+ var nextMonth = document.createElement("input");
+ nextMonth.className = "nextMonthButton button";
+ nextMonth.type = "button";
+ nextMonth.value = ">>";
+ td.appendChild(nextMonth);
+ tr.appendChild(td);
+
+ // Calendar body
+ div = document.createElement("div");
+ div.className = "calendarBody";
+ this._calDiv.appendChild(div);
+ var calendarBody = div;
+
+ // Create the inside of calendar body
+
+ var text;
+ table = document.createElement("table");
+ table.align="center";
+ table.className = "grid";
+
+ div.appendChild(table);
+ var thead = document.createElement("thead");
+ table.appendChild(thead);
+ tr = document.createElement("tr");
+ thead.appendChild(tr);
+
+ for(i=0; i < 7; ++i) {
+ td = document.createElement("th");
+ text = document.createTextNode(this.ShortWeekDayNames[(i+this.FirstDayOfWeek)%7]);
+ td.appendChild(text);
+ td.className = "weekDayHead";
+ tr.appendChild(td);
+ }
+
+ // Date grid
+ tbody = document.createElement("tbody");
+ table.appendChild(tbody);
+
+ for(var week=0; week<6; ++week) {
+ tr = document.createElement("tr");
+ tbody.appendChild(tr);
+
+ for(var day=0; day<7; ++day) {
+ td = document.createElement("td");
+ td.className = "calendarDate";
+ text = document.createTextNode(String.fromCharCode(160));
+ td.appendChild(text);
+
+ tr.appendChild(td);
+ var tmp = new Object();
+ tmp.tag = "DATE";
+ tmp.value = -1;
+ tmp.data = text;
+ this.dateSlot[(week*7)+day] = tmp;
+
+ this.observe(td, "mouseover", jQuery.proxy(this.hover,this));
+ this.observe(td, "mouseout", jQuery.proxy(this.hover,this));
+
+ }
+ }
+
+ // Calendar Footer
+ div = document.createElement("div");
+ div.className = "calendarFooter";
+ this._calDiv.appendChild(div);
+
+ var todayButton = document.createElement("input");
+ todayButton.type="button";
+ todayButton.className = "todayButton";
+ var today = this.newDate();
+ var buttonText = today.SimpleFormat(this.Format,this);
+ todayButton.value = buttonText;
+ div.appendChild(todayButton);
+
+ this.control.parentNode.appendChild(this._calDiv);
+
+ this.update();
+ this.updateHeader();
+
+ // hook up events
+ this.observe(previousMonth, "click", jQuery.proxy(this.prevMonth,this));
+ this.observe(nextMonth, "click", jQuery.proxy(this.nextMonth,this));
+ this.observe(todayButton, "click", jQuery.proxy(this.selectToday,this));
+ //Event.observe(clearButton, "click", jQuery.proxy(this.clearSelection,this));
+ this.observe(this._monthSelect, "change", jQuery.proxy(this.monthSelect,this));
+ this.observe(this._yearSelect, "change", jQuery.proxy(this.yearSelect,this));
+
+ // ie, opera
+ this.observe(this._calDiv, "mousewheel", jQuery.proxy(this.mouseWheelChange,this));
+ // ff
+ this.observe(this._calDiv, "DOMMouseScroll", jQuery.proxy(this.mouseWheelChange,this));
+
+ this.observe(calendarBody, "click", jQuery.proxy(this.selectDate,this));
+
+ jQuery(this.control).focus();
+
+ },
+
+ keyPressed : function(ev)
+ {
+ if(!this.showing) return;
+ if (!ev) ev = document.parentWindow.event;
+ var kc = ev.keyCode != null ? ev.keyCode : ev.charCode;
+
+ // return, space, tab
+ if(kc == 13 || kc == 32 || kc == 9)
+ {
+ this.setSelectedDate(this.selectedDate);
+ ev.preventDefault();
+ this.hide();
+ }
+ // esc
+ if(kc == 27)
+ {
+ ev.preventDefault();
+ this.hide();
+ }
+
+ var getDaysPerMonth = function (nMonth, nYear)
+ {
+ nMonth = (nMonth + 12) % 12;
+ var days= [31,28,31,30,31,30,31,31,30,31,30,31];
+ var res = days[nMonth];
+ if (nMonth == 1) //feburary, leap years has 29
+ res += nYear % 4 == 0 && !(nYear % 400 == 0) ? 1 : 0;
+ return res;
+ }
+
+ if(kc < 37 || kc > 40) return true;
+
+ var current = this.selectedDate;
+ var d = current.valueOf();
+ if(kc == 37) // left
+ {
+ if(ev.ctrlKey || ev.shiftKey) // -1 month
+ {
+ current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth() - 1,current.getFullYear())) ); // no need to catch dec -> jan for the year
+ d = current.setMonth( current.getMonth() - 1 );
+ }
+ else
+ d -= 86400000; //-1 day
+ }
+ else if (kc == 39) // right
+ {
+ if(ev.ctrlKey || ev.shiftKey) // +1 month
+ {
+ current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth() + 1,current.getFullYear())) ); // no need to catch dec -> jan for the year
+ d = current.setMonth( current.getMonth() + 1 );
+ }
+ else
+ d += 86400000; //+1 day
+ }
+ else if (kc == 38) // up
+ {
+ if(ev.ctrlKey || ev.shiftKey) //-1 year
+ {
+ current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth(),current.getFullYear() - 1)) ); // no need to catch dec -> jan for the year
+ d = current.setFullYear( current.getFullYear() - 1 );
+ }
+ else
+ d -= 604800000; // -7 days
+ }
+ else if (kc == 40) // down
+ {
+ if(ev.ctrlKey || ev.shiftKey) // +1 year
+ {
+ current.setDate( Math.min(current.getDate(), getDaysPerMonth(current.getMonth(),current.getFullYear() + 1)) ); // no need to catch dec -> jan for the year
+ d = current.setFullYear( current.getFullYear() + 1 );
+ }
+ else
+ d += 7 * 24 * 61 * 60 * 1000; // +7 days
+ }
+ this.setSelectedDate(d);
+ ev.preventDefault();
+ },
+
+ selectDate : function(ev)
+ {
+ var el = ev.target;
+ while (el.nodeType != 1)
+ el = el.parentNode;
+
+ while (el != null && el.tagName && el.tagName.toLowerCase() != "td")
+ el = el.parentNode;
+
+ // if no td found, return
+ if (el == null || el.tagName == null || el.tagName.toLowerCase() != "td")
+ return;
+
+ var d = this.newDate(this.selectedDate);
+ var n = Number(el.firstChild.data);
+ if (isNaN(n) || n <= 0 || n == null)
+ return;
+
+ d.setDate(n);
+ this.setSelectedDate(d);
+ this.hide();
+ },
+
+ selectToday : function()
+ {
+ if(this.selectedDate.toISODate() == this.newDate().toISODate())
+ this.hide();
+
+ this.setSelectedDate(this.newDate());
+ },
+
+ clearSelection : function()
+ {
+ this.setSelectedDate(this.newDate());
+ this.hide();
+ },
+
+ monthSelect : function(ev)
+ {
+ this.setMonth(ev.target.value);
+ },
+
+ yearSelect : function(ev)
+ {
+ this.setYear(ev.target.value);
+ },
+
+ mouseWheelChange : function (event)
+ {
+ var delta = 0;
+ if (!event) event = document.parentWindow.event;
+ if (event.wheelDelta) {
+ delta = event.wheelDelta/120;
+ if (window.opera) delta = -delta;
+ } else if (event.detail) { delta = -event.detail/3; }
+
+ var d = this.newDate(this.selectedDate);
+ var m = d.getMonth() + Math.round(delta);
+ this.setMonth(m,true);
+ return false;
+ },
+
+ // Respond to change event on the textbox or dropdown list
+ // This method raises OnDateChanged event on client side if it has been defined
+ onDateChanged : function ()
+ {
+ if (this.options.OnDateChanged)
+ {
+ var date;
+ if (this.options.InputMode == "TextBox")
+ {
+ date=this.control.value;
+ }
+ else
+ {
+ var day = Prado.WebUI.TDatePicker.getDayListControl(this.control).selectedIndex+1;
+ var month = Prado.WebUI.TDatePicker.getMonthListControl(this.control).selectedIndex;
+ var year = Prado.WebUI.TDatePicker.getYearListControl(this.control).value;
+ date=new Date(year, month, day, 0,0,0).SimpleFormat(this.Format, this);
+ }
+ this.options.OnDateChanged(this, date);
+ }
+ },
+
+ fireChangeEvent: function(element, capped)
+ {
+ if (capped)
+ {
+ var obj = this;
+
+ if (typeof(obj.changeeventtimer)!="undefined")
+ {
+ clearTimeout(obj.changeeventtimer);
+ obj.changeeventtimer = null;
+ }
+ obj.changeeventtimer = setTimeout(
+ function() { obj.changeeventtimer = null; jQuery(element).trigger("change"); },
+ 1500
+ );
+ }
+ else
+ jQuery(element).trigger("change");
+ },
+
+ onChange : function(ref, date, capevents)
+ {
+ if(this.options.InputMode == "TextBox")
+ {
+ this.control.value = this.formatDate();
+ this.fireChangeEvent(this.control, capevents);
+ }
+ else
+ {
+ var day = Prado.WebUI.TDatePicker.getDayListControl(this.control);
+ var month = Prado.WebUI.TDatePicker.getMonthListControl(this.control);
+ var year = Prado.WebUI.TDatePicker.getYearListControl(this.control);
+ var date = this.selectedDate;
+ if(day)
+ {
+ day.selectedIndex = date.getDate()-1;
+ }
+ if(month)
+ {
+ month.selectedIndex = date.getMonth();
+ }
+ if(year)
+ {
+ var years = year.options;
+ var currentYear = date.getFullYear();
+ for(var i = 0; i < years.length; i++)
+ years[i].selected = years[i].value.toInteger() == currentYear;
+ }
+
+ day && this.fireChangeEvent(day, capevents);
+ month && this.fireChangeEvent(month, capevents);
+ year && this.fireChangeEvent(year, capevents);
+ }
+ },
+
+ formatDate : function()
+ {
+ return this.selectedDate ? this.selectedDate.SimpleFormat(this.Format,this) : '';
+ },
+
+ newDate : function(date)
+ {
+ if(!date)
+ date = new Date();
+ if(typeof(date) == "string" || typeof(date) == "number")
+ date = new Date(date);
+ return new Date(Math.min(Math.max(date.getFullYear(),this.FromYear),this.UpToYear), date.getMonth(), date.getDate(), 0,0,0);
+ },
+
+ setSelectedDate : function(date, capevents)
+ {
+ if (date == null)
+ return;
+ var old=this.selectedDate;
+ this.selectedDate = this.newDate(date);
+ var dateChanged=(old - this.selectedDate != 0) || ( this.options.InputMode == "TextBox" && this.control.value != this.formatDate());
+
+ this.updateHeader();
+ this.update();
+ if (dateChanged && typeof(this.onChange) == "function")
+ this.onChange(this, date, capevents);
+ },
+
+ getElement : function()
+ {
+ return this._calDiv;
+ },
+
+ getSelectedDate : function ()
+ {
+ return this.selectedDate == null ? null : this.newDate(this.selectedDate);
+ },
+
+ setYear : function(year)
+ {
+ var d = this.newDate(this.selectedDate);
+ d.setFullYear(year);
+ this.setSelectedDate(d);
+ },
+
+ setMonth : function (month, capevents)
+ {
+ var d = this.newDate(this.selectedDate);
+ d.setDate(Math.min(d.getDate(), this.getDaysPerMonth(month,d.getFullYear())));
+ d.setMonth(month);
+ this.setSelectedDate(d,capevents);
+ },
+
+ nextMonth : function ()
+ {
+ this.setMonth(this.selectedDate.getMonth()+1);
+ },
+
+ prevMonth : function ()
+ {
+ this.setMonth(this.selectedDate.getMonth()-1);
+ },
+
+ getDaysPerMonth : function (month, year)
+ {
+ month = (Number(month)+12) % 12;
+ var days = [31,28,31,30,31,30,31,31,30,31,30,31];
+ var res = days[month];
+ if (month == 1 && ((!(year % 4) && (year % 100)) || !(year % 400))) //feburary, leap years has 29
+ res++;
+ return res;
+ },
+
+ getDatePickerOffsetHeight : function()
+ {
+ if(this.options.InputMode == "TextBox")
+ return this.control.offsetHeight;
+
+ var control = Prado.WebUI.TDatePicker.getDayListControl(this.control);
+ if(control) return control.offsetHeight;
+
+ var control = Prado.WebUI.TDatePicker.getMonthListControl(this.control);
+ if(control) return control.offsetHeight;
+
+ var control = Prado.WebUI.TDatePicker.getYearListControl(this.control);
+ if(control) return control.offsetHeight;
+ return 0;
+ },
+
+ show : function()
+ {
+ this.create();
+
+ if(!this.showing)
+ {
+ var pos = jQuery(this.control).position();
+
+ pos['top'] += this.getDatePickerOffsetHeight();
+ this._calDiv.style.top = (pos['top']-1) + "px";
+ this._calDiv.style.display = "block";
+ this._calDiv.style.left = pos['left'] + "px";
+
+ this.documentClickEvent = jQuery.bind(this.hideOnClick, this);
+ this.documentKeyDownEvent = jQuery.bind(this.keyPressed, this);
+ this.observe(document.body, "click", this.documentClickEvent);
+ var date = this.getDateFromInput();
+ if(date)
+ {
+ this.selectedDate = date;
+ this.setSelectedDate(date);
+ }
+ this.observe(document,"keydown", this.documentKeyDownEvent);
+ this.showing = true;
+
+ if(this.positionMode=='Top')
+ {
+ this._calDiv.style.top = ((pos['top']-1) - this.getDatePickerOffsetHeight() - this._calDiv.offsetHeight) + 'px';
+ }
+ }
+ },
+
+ getDateFromInput : function()
+ {
+ if(this.options.InputMode == "TextBox")
+ return Date.SimpleParse(this.control.value, this.Format);
+ else
+ return Prado.WebUI.TDatePicker.getDropDownDate(this.control);
+ },
+
+ //hide the calendar when clicked outside any calendar
+ hideOnClick : function(ev)
+ {
+ if(!this.showing) return;
+ var el = ev.target;
+ var within = false;
+ do
+ {
+ within = within || (el.className && jQuery(el).hasClass("TDatePicker_"+this.CalendarStyle));
+ within = within || el == this.trigger;
+ within = within || el == this.control;
+ if(within) break;
+ el = el.parentNode;
+ }
+ while(el);
+ if(!within) this.hide();
+ },
+
+
+ hide : function()
+ {
+ if(this.showing)
+ {
+ this._calDiv.style.display = "none";
+ this.showing = false;
+ this.stopObserving(document.body, "click", this.documentClickEvent);
+ this.stopObserving(document,"keydown", this.documentKeyDownEvent);
+ }
+ },
+
+ update : function()
+ {
+ // Calculate the number of days in the month for the selected date
+ var date = this.selectedDate;
+ var today = (this.newDate()).toISODate();
+
+ var selected = date.toISODate();
+ var d1 = new Date(date.getFullYear(), date.getMonth(), 1);
+ var d2 = new Date(date.getFullYear(), date.getMonth()+1, 1);
+ var monthLength = Math.round((d2 - d1) / (24 * 60 * 60 * 1000));
+
+ // Find out the weekDay index for the first of this month
+ var firstIndex = (d1.getDay() - this.FirstDayOfWeek) % 7 ;
+ if (firstIndex < 0)
+ firstIndex += 7;
+
+ var index = 0;
+ while (index < firstIndex) {
+ this.dateSlot[index].value = -1;
+ this.dateSlot[index].data.data = String.fromCharCode(160);
+ this.dateSlot[index].data.parentNode.className = "empty";
+ index++;
+ }
+
+ for (var i = 1; i <= monthLength; i++, index++) {
+ var slot = this.dateSlot[index];
+ var slotNode = slot.data.parentNode;
+ slot.value = i;
+ slot.data.data = i;
+ slotNode.className = "date";
+ //slotNode.style.color = "";
+ if (d1.toISODate() == today) {
+ slotNode.className += " today";
+ }
+ if (d1.toISODate() == selected) {
+ // slotNode.style.color = "blue";
+ slotNode.className += " selected";
+ }
+ d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate()+1);
+ }
+
+ var lastDateIndex = index;
+
+ while(index < 42) {
+ this.dateSlot[index].value = -1;
+ this.dateSlot[index].data.data = String.fromCharCode(160);
+ this.dateSlot[index].data.parentNode.className = "empty";
+ ++index;
+ }
+
+ },
+
+ hover : function(ev)
+ {
+ if(ev.target.tagName)
+ {
+ if(ev.type == "mouseover")
+ jQuery(ev.target).addClass("hover");
+ else
+ jQuery(ev.target).removeClass("hover");
+ }
+ },
+
+ updateHeader : function () {
+
+ var options = this._monthSelect.options;
+ var m = this.selectedDate.getMonth();
+ for(var i=0; i < options.length; ++i) {
+ options[i].selected = false;
+ if (options[i].value == m) {
+ options[i].selected = true;
+ }
+ }
+
+ options = this._yearSelect.options;
+ var year = this.selectedDate.getFullYear();
+ for(var i=0; i < options.length; ++i) {
+ options[i].selected = false;
+ if (options[i].value == year) {
+ options[i].selected = true;
+ }
+ }
+
+ }
+});
+
+jQuery.extend(Prado.WebUI.TDatePicker,
+{
+ /**
+ * @return Date the date from drop down list options.
+ */
+ getDropDownDate : function(control)
+ {
+ var now=new Date();
+ var year=now.getFullYear();
+ var month=now.getMonth();
+ var day=1;
+
+ var month_list = Prado.WebUI.TDatePicker.getMonthListControl(control);
+ var day_list = Prado.WebUI.TDatePicker.getDayListControl(control);
+ var year_list = Prado.WebUI.TDatePicker.getYearListControl(control);
+
+ var day = day_list ? day_list.value : 1;
+ var month = month_list ? month_list.value : now.getMonth();
+ var year = year_list ? year_list.value : now.getFullYear();
+
+ return new Date(year,month,day, 0, 0, 0);
+ },
+
+ getYearListControl : function(control)
+ {
+ return jQuery('#'+control.id+"_year").get(0);
+ },
+
+ getMonthListControl : function(control)
+ {
+ return jQuery('#'+control.id+"_month").get(0);
+ },
+
+ getDayListControl : function(control)
+ {
+ return jQuery('#'+control.id+"_day").get(0);
+ }
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/datepicker/default.css b/lib/prado/framework/Web/Javascripts/source/prado/datepicker/default.css
new file mode 100644
index 0000000..9532dad
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/datepicker/default.css
@@ -0,0 +1,98 @@
+.TDatePicker_default
+{
+ border: 1px solid #919EA9;
+ background-color: White;
+ text-align: center;
+ font-size: 11px;
+ font-family: Tahoma, Arial, Helvetica, sans-serif;
+ cursor: default;
+}
+
+.TDatePickerButton
+{
+ width: 30px;
+}
+
+.TDatePickerImageButton
+{
+ padding: 2px;
+ border: 1px solid #919EA9;
+ vertical-align: top;
+ margin-left: 1px;
+}
+
+
+.TDatePickerImageButton:hover
+{
+ border-color: #ddd;
+}
+
+.TDatePicker_default select
+{
+ font-size: 11px;
+}
+
+.TDatePicker_default input.button
+{
+ font-size: 11px;
+ width: 32px;
+}
+
+.TDatePicker_default .date
+{
+ padding: 4px 0;
+ border: 1px solid white;
+ text-align: center;
+}
+.TDatePicker_default .hover
+{
+ border: 1px solid blue;
+}
+.TDatePicker_default .selected
+{
+ background-color: blue;
+ border: 1px solid blue;
+ color: white;
+}
+.TDatePicker_default .today
+{
+ font-weight: bold;
+}
+
+.TDatePicker_default td.empty
+{
+ border: 1px solid white;
+ cursor: default;
+ height: 22px;
+}
+
+.TDatePicker_default th
+{
+ width: 28px;
+}
+
+.TDatePicker_default .calendarBody
+{
+ text-align: center;
+ width: 210px;
+ margin: 3px 6px;
+}
+
+.TDatePicker_default .grid
+{
+ border-spacing: 0px;
+}
+
+.TDatePicker_default .calendarFooter
+{
+ margin: 2px;
+ border-top: 1px solid #919EA9;
+ padding-top: 2px;
+}
+.TDatePicker_default .todayButton
+{
+ font-size: 11px;
+ margin: 4px;
+ padding-left: 1em;
+ padding-right: 1em;
+} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/datepicker/spacer.gif b/lib/prado/framework/Web/Javascripts/source/prado/datepicker/spacer.gif
new file mode 100755
index 0000000..fc25609
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/datepicker/spacer.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/logger/logger.js b/lib/prado/framework/Web/Javascripts/source/prado/logger/logger.js
new file mode 100644
index 0000000..fde772c
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/logger/logger.js
@@ -0,0 +1,748 @@
+/*
+
+Created By: Corey Johnson
+E-mail: probablyCorey@gmail.com
+
+Requires: Prototype Javascript library (http://prototype.conio.net/)
+
+Use it all you want. Just remember to give me some credit :)
+
+*/
+
+// ------------
+// Custom Event
+// ------------
+
+CustomEvent = jQuery.klass({
+ initialize : function() {
+ this.listeners = []
+ },
+
+ addListener : function(method) {
+ this.listeners.push(method)
+ },
+
+ removeListener : function(method) {
+ var foundIndexes = this._findListenerIndexes(method)
+
+ for(var i = 0; i < foundIndexes.length; i++) {
+ this.listeners.splice(foundIndexes[i], 1)
+ }
+ },
+
+ dispatch : function(handler) {
+ for(var i = 0; i < this.listeners.length; i++) {
+ try {
+ this.listeners[i](handler)
+ }
+ catch (e) {
+ alert("Could not run the listener " + this.listeners[i] + ". " + e)
+ }
+ }
+ },
+
+ // Private Methods
+ // ---------------
+ _findListenerIndexes : function(method) {
+ var indexes = []
+ for(var i = 0; i < this.listeners.length; i++) {
+ if (this.listeners[i] == method) {
+ indexes.push(i)
+ }
+ }
+
+ return indexes
+ }
+});
+
+// ------
+// Cookie
+// ------
+
+var Cookie = {
+ set : function(name, value, expirationInDays, path) {
+ var cookie = escape(name) + "=" + escape(value)
+
+ if (expirationInDays) {
+ var date = new Date()
+ date.setDate(date.getDate() + expirationInDays)
+ cookie += "; expires=" + date.toGMTString()
+ }
+
+ if (path) {
+ cookie += ";path=" + path
+ }
+
+ document.cookie = cookie
+
+ if (value && (expirationInDays == undefined || expirationInDays > 0) && !this.get(name)) {
+ Logger.error("Cookie (" + name + ") was not set correctly... The value was " + value.toString().length + " charachters long (This may be over the cookie limit)");
+ }
+ },
+
+ get : function(name) {
+ var pattern = "(^|;)\\s*" + escape(name) + "=([^;]+)"
+
+ var m = document.cookie.match(pattern)
+ if (m && m[2]) {
+ return unescape(m[2])
+ }
+ else return null
+ },
+
+ getAll : function() {
+ var cookies = document.cookie.split(';')
+ var cookieArray = []
+
+ for (var i = 0; i < cookies.length; i++) {
+ try {
+ var name = unescape(cookies[i].match(/^\s*([^=]+)/m)[1])
+ var value = unescape(cookies[i].match(/=(.*$)/m)[1])
+ }
+ catch (e) {
+ continue
+ }
+
+ cookieArray.push({name : name, value : value})
+
+ if (cookieArray[name] != undefined) {
+ Logger.waring("Trying to retrieve cookie named(" + name + "). There appears to be another property with this name though.");
+ }
+
+ cookieArray[name] = value
+ }
+
+ return cookieArray
+ },
+
+ clear : function(name) {
+ this.set(name, "", -1)
+ },
+
+ clearAll : function() {
+ var cookies = this.getAll()
+
+ for(var i = 0; i < cookies.length; i++) {
+ this.clear(cookies[i].name)
+ }
+
+ }
+};
+
+// ------
+// Logger
+// -----
+
+Logger = {
+ logEntries : [],
+
+ onupdate : new CustomEvent(),
+ onclear : new CustomEvent(),
+
+
+ // Logger output
+ log : function(message, tag) {
+ var logEntry = new LogEntry(message, tag || "info")
+ this.logEntries.push(logEntry)
+ this.onupdate.dispatch(logEntry)
+ },
+
+ info : function(message) {
+ this.log(message, 'info')
+ if(typeof(console) != "undefined")
+ console.info(message);
+ },
+
+ debug : function(message) {
+ this.log(message, 'debug')
+ if(typeof(console) != "undefined")
+ console.debug(message);
+ },
+
+ warn : function(message) {
+ this.log(message, 'warning')
+ if(typeof(console) != "undefined")
+ console.warn(message);
+ },
+
+ error : function(message, error) {
+ this.log(message + ": \n" + error, 'error')
+ if(typeof(console) != "undefined")
+ console.error(message + ": \n" + error);
+
+ },
+
+ clear : function () {
+ this.logEntries = []
+ this.onclear.dispatch()
+ }
+};
+
+LogEntry = jQuery.klass({
+ initialize : function(message, tag) {
+ this.message = message
+ this.tag = tag
+ }
+});
+
+LogConsole = jQuery.klass({
+
+ // Properties
+ // ----------
+ commandHistory : [],
+ commandIndex : 0,
+
+ hidden : true,
+
+ // Methods
+ // -------
+
+ initialize : function(toggleKey) {
+ this.outputCount = 0
+ this.tagPattern = Cookie.get('tagPattern') || ".*"
+
+ // I hate writing javascript in HTML... but what's a better alternative
+ this.logElement = document.createElement('div')
+ document.body.appendChild(this.logElement)
+ jQuery(this.logElement).hide();
+
+ this.logElement.style.position = "absolute"
+ this.logElement.style.left = '0px'
+ this.logElement.style.width = '100%'
+
+ this.logElement.style.textAlign = "left"
+ this.logElement.style.fontFamily = "lucida console"
+ this.logElement.style.fontSize = "100%"
+ this.logElement.style.backgroundColor = 'darkgray'
+ this.logElement.style.opacity = 0.9
+ this.logElement.style.zIndex = 2000
+
+ // Add toolbarElement
+ this.toolbarElement = document.createElement('div')
+ this.logElement.appendChild(this.toolbarElement)
+ this.toolbarElement.style.padding = "0 0 0 2px"
+
+ // Add buttons
+ this.buttonsContainerElement = document.createElement('span')
+ this.toolbarElement.appendChild(this.buttonsContainerElement)
+
+ this.buttonsContainerElement.innerHTML += '<button onclick="logConsole.toggle()" style="float:right;color:black">close</button>'
+ this.buttonsContainerElement.innerHTML += '<button onclick="Logger.clear()" style="float:right;color:black">clear</button>'
+ if(!Prado.Inspector.disabled)
+ this.buttonsContainerElement.innerHTML += '<button onclick="Prado.Inspector.inspect()" style="float:right;color:black; margin-right:15px;">Object Tree</button>'
+
+
+ //Add Tag Filter
+ this.tagFilterContainerElement = document.createElement('span')
+ this.toolbarElement.appendChild(this.tagFilterContainerElement)
+ this.tagFilterContainerElement.style.cssFloat = 'left'
+ this.tagFilterContainerElement.appendChild(document.createTextNode("Log Filter"))
+
+ this.tagFilterElement = document.createElement('input')
+ this.tagFilterContainerElement.appendChild(this.tagFilterElement)
+ this.tagFilterElement.style.width = '200px'
+ this.tagFilterElement.value = this.tagPattern
+ this.tagFilterElement.setAttribute('autocomplete', 'off') // So Firefox doesn't flip out
+
+ jQuery(this.tagFilterElement).on('keyup', this.updateTags.bind(this));
+ jQuery(this.tagFilterElement).on('click', function() {this.tagFilterElement.select()}.bind(this));
+
+ // Add outputElement
+ this.outputElement = document.createElement('div')
+ this.logElement.appendChild(this.outputElement)
+ this.outputElement.style.overflow = "auto"
+ this.outputElement.style.clear = "both"
+ this.outputElement.style.height = "200px"
+ this.outputElement.style.backgroundColor = 'black'
+
+ this.inputContainerElement = document.createElement('div')
+ this.inputContainerElement.style.width = "100%"
+ this.logElement.appendChild(this.inputContainerElement)
+
+ this.inputElement = document.createElement('input')
+ this.inputContainerElement.appendChild(this.inputElement)
+ this.inputElement.style.width = '100%'
+ this.inputElement.style.borderWidth = '0px' // Inputs with 100% width always seem to be too large (I HATE THEM) they only work if the border, margin and padding are 0
+ this.inputElement.style.margin = '0px'
+ this.inputElement.style.padding = '0px'
+ this.inputElement.value = 'Type command here'
+ this.inputElement.setAttribute('autocomplete', 'off') // So Firefox doesn't flip out
+
+ jQuery(this.inputElement).on('keyup', this.handleInput.bind(this));
+ jQuery(this.inputElement).on('click', function() {this.inputElement.select()}.bind(this));
+
+ if(document.all && !window.opera)
+ {
+ window.setInterval(this.repositionWindow.bind(this), 500)
+ }
+ else
+ {
+ this.logElement.style.position="fixed";
+ this.logElement.style.bottom="0px";
+ }
+ var self=this;
+ jQuery(document).on('keydown', function(e)
+ {
+ if((e.altKey==true) && e.keyCode == toggleKey ) //Alt+J | Ctrl+J
+ self.toggle();
+ });
+
+ // Listen to the logger....
+ Logger.onupdate.addListener(this.logUpdate.bind(this))
+ Logger.onclear.addListener(this.clear.bind(this))
+
+ // Preload log element with the log entries that have been entered
+ for (var i = 0; i < Logger.logEntries.length; i++) {
+ this.logUpdate(Logger.logEntries[i])
+ }
+
+ // Feed all errors into the logger (For some unknown reason I can only get this to work
+ // with an inline event declaration)
+ jQuery(window).on('error', function(msg, url, lineNumber) {Logger.error("Error in (" + (url || location) + ") on line "+lineNumber+"", msg)});
+
+ // Allow acess key link
+ var accessElement = document.createElement('span')
+ accessElement.innerHTML = '<button style="position:absolute;top:-100px" onclick="javascript:logConsole.toggle()" accesskey="d"></button>'
+ document.body.appendChild(accessElement)
+
+ if (Cookie.get('ConsoleVisible') == 'true') {
+ this.toggle()
+ }
+ },
+
+ toggle : function() {
+ if (this.logElement.style.display == 'none') {
+ this.show();
+ }
+ else {
+ this.hide();
+ }
+ },
+
+ show : function() {
+ jQuery(this.logElement).show();
+ this.outputElement.scrollTop = this.outputElement.scrollHeight // Scroll to bottom when toggled
+ if(document.all && !window.opera)
+ this.repositionWindow();
+ Cookie.set('ConsoleVisible', 'true')
+ this.inputElement.select();
+ this.hidden = false;
+ },
+
+ hide : function() {
+ this.hidden = true;
+ jQuery(this.logElement).hide();
+ Cookie.set('ConsoleVisible', 'false');
+ },
+
+ output : function(message, style) {
+ // If we are at the bottom of the window, then keep scrolling with the output
+ var shouldScroll = (this.outputElement.scrollTop + (2 * this.outputElement.clientHeight)) >= this.outputElement.scrollHeight
+
+ this.outputCount++
+ style = (style ? style += ';' : '')
+ style += 'padding:1px;margin:0 0 5px 0'
+
+ if (this.outputCount % 2 == 0) style += ";background-color:#101010"
+
+ message = message || "undefined"
+ message = message.toString().replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
+
+ this.outputElement.innerHTML += "<pre style='" + style + "'>" + message + "</pre>"
+
+ if (shouldScroll) {
+ this.outputElement.scrollTop = this.outputElement.scrollHeight
+ }
+ },
+
+ updateTags : function() {
+ var pattern = this.tagFilterElement.value
+
+ if (this.tagPattern == pattern) return
+
+ try {
+ new RegExp(pattern)
+ }
+ catch (e) {
+ return
+ }
+
+ this.tagPattern = pattern
+ Cookie.set('tagPattern', this.tagPattern)
+
+ this.outputElement.innerHTML = ""
+
+ // Go through each log entry again
+ this.outputCount = 0;
+ for (var i = 0; i < Logger.logEntries.length; i++) {
+ this.logUpdate(Logger.logEntries[i])
+ }
+ },
+
+ repositionWindow : function() {
+ var offset = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
+ var pageHeight = self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
+ this.logElement.style.top = (offset + pageHeight - Element.getHeight(this.logElement)) + "px"
+ },
+
+ // Event Handlers
+ // --------------
+
+ logUpdate : function(logEntry) {
+ if (logEntry.tag.search(new RegExp(this.tagPattern, 'igm')) == -1) return
+ var style = ''
+ if (logEntry.tag.search(/error/) != -1) style += 'color:red'
+ else if (logEntry.tag.search(/warning/) != -1) style += 'color:orange'
+ else if (logEntry.tag.search(/debug/) != -1) style += 'color:green'
+ else if (logEntry.tag.search(/info/) != -1) style += 'color:white'
+ else style += 'color:yellow'
+
+ this.output(logEntry.message, style)
+ },
+
+ clear : function(e) {
+ this.outputElement.innerHTML = ""
+ },
+
+ handleInput : function(e) {
+ if (e.keyCode == 13 ) {
+ var command = this.inputElement.value
+
+ switch(command) {
+ case "clear":
+ Logger.clear()
+ break
+
+ default:
+ var consoleOutput = ""
+
+ try {
+ consoleOutput = eval(this.inputElement.value)
+ }
+ catch (e) {
+ Logger.error("Problem parsing input <" + command + ">", e)
+ break
+ }
+
+ Logger.log(consoleOutput)
+ break
+ }
+
+ if (this.inputElement.value != "" && this.inputElement.value != this.commandHistory[0]) {
+ this.commandHistory.unshift(this.inputElement.value)
+ }
+
+ this.commandIndex = 0
+ this.inputElement.value = ""
+ }
+ else if (e.keyCode == 38 && this.commandHistory.length > 0) {
+ this.inputElement.value = this.commandHistory[this.commandIndex]
+
+ if (this.commandIndex < this.commandHistory.length - 1) {
+ this.commandIndex += 1
+ }
+ }
+ else if (e.keyCode == 40 && this.commandHistory.length > 0) {
+ if (this.commandIndex > 0) {
+ this.commandIndex -= 1
+ }
+
+ this.inputElement.value = this.commandHistory[this.commandIndex]
+ }
+ else {
+ this.commandIndex = 0
+ }
+ }
+});
+
+
+// -------------------------
+// Helper Functions And Junk
+// -------------------------
+function inspect(o)
+{
+ var objtype = typeof(o);
+ if (objtype == "undefined") {
+ return "undefined";
+ } else if (objtype == "number" || objtype == "boolean") {
+ return o + "";
+ } else if (o === null) {
+ return "null";
+ }
+
+ try {
+ var ostring = (o + "");
+ } catch (e) {
+ return "[" + typeof(o) + "]";
+ }
+
+ if (typeof(o) == "function")
+ {
+ o = ostring.replace(/^\s+/, "");
+ var idx = o.indexOf("{");
+ if (idx != -1) {
+ o = o.substr(0, idx) + "{...}";
+ }
+ return o;
+ }
+
+ var reprString = function (o)
+ {
+ return ('"' + o.replace(/(["\\])/g, '\\$1') + '"'
+ ).replace(/[\f]/g, "\\f"
+ ).replace(/[\b]/g, "\\b"
+ ).replace(/[\n]/g, "\\n"
+ ).replace(/[\t]/g, "\\t"
+ ).replace(/[\r]/g, "\\r");
+ };
+
+ if (objtype == "string") {
+ return reprString(o);
+ }
+ // recurse
+ var me = arguments.callee;
+ // short-circuit for objects that support "json" serialization
+ // if they return "self" then just pass-through...
+ var newObj;
+ if (typeof(o.__json__) == "function") {
+ newObj = o.__json__();
+ if (o !== newObj) {
+ return me(newObj);
+ }
+ }
+ if (typeof(o.json) == "function") {
+ newObj = o.json();
+ if (o !== newObj) {
+ return me(newObj);
+ }
+ }
+ // array
+ if (objtype != "function" && typeof(o.length) == "number") {
+ var res = [];
+ for (var i = 0; i < o.length; i++) {
+ var val = me(o[i]);
+ if (typeof(val) != "string") {
+ val = "undefined";
+ }
+ res.push(val);
+ }
+ return "[" + res.join(", ") + "]";
+ }
+
+ // generic object code path
+ res = [];
+ for (var k in o) {
+ var useKey;
+ if (typeof(k) == "number") {
+ useKey = '"' + k + '"';
+ } else if (typeof(k) == "string") {
+ useKey = reprString(k);
+ } else {
+ // skip non-string or number keys
+ continue;
+ }
+ val = me(o[k]);
+ if (typeof(val) != "string") {
+ // skip non-serializable values
+ continue;
+ }
+ res.push(useKey + ":" + val);
+ }
+ return "{" + res.join(", ") + "}";
+};
+
+Array.prototype.contains = function(object) {
+ for(var i = 0; i < this.length; i++) {
+ if (object == this[i]) return true
+ }
+
+ return false
+};
+
+// Helper Alias for simple logging
+var puts = function() {return Logger.log(arguments[0], arguments[1])};
+
+/*************************************
+
+ Javascript Object Tree
+ version 1.0
+ last revision:04.11.2004
+ steve@slayeroffice.com
+ http://slayeroffice.com
+
+ (c)2004 S.G. Chipman
+
+ Please notify me of any modifications
+ you make to this code so that I can
+ update the version hosted on slayeroffice.com
+
+
+************************************/
+if(typeof Prado == "undefined")
+ var Prado = {};
+Prado.Inspector =
+{
+ d : document,
+ types : new Array(),
+ objs : new Array(),
+ hidden : new Array(),
+ opera : window.opera,
+ displaying : '',
+ nameList : new Array(),
+
+ format : function(str) {
+ if(typeof(str) != "string") return str;
+ str=str.replace(/</g,"&lt;");
+ str=str.replace(/>/g,"&gt;");
+ return str;
+ },
+
+ parseJS : function(obj) {
+ var name;
+ if(typeof obj == "string") { name = obj; obj = eval(obj); }
+ win= typeof obj == 'undefined' ? window : obj;
+ this.displaying = name ? name : win.toString();
+ for(js in win) {
+ try {
+ if(win[js] && js.toString().indexOf("Inspector")==-1 && (win[js]+"").indexOf("[native code]")==-1) {
+
+ t=typeof(win[js]);
+ if(!this.objs[t.toString()]) {
+ this.types[this.types.length]=t;
+ this.objs[t]={};
+ this.nameList[t] = new Array();
+ }
+ this.nameList[t].push(js);
+ this.objs[t][js] = this.format(win[js]+"");
+ }
+ } catch(err) { }
+ }
+
+ for(i=0;i<this.types.length;i++)
+ this.nameList[this.types[i]].sort();
+ },
+
+ show : function(objID) {
+ this.d.getElementById(objID).style.display=this.hidden[objID]?"none":"block";
+ this.hidden[objID]=this.hidden[objID]?0:1;
+ },
+
+ changeSpan : function(spanID) {
+ if(this.d.getElementById(spanID).innerHTML.indexOf("+")>-1){
+ this.d.getElementById(spanID).innerHTML="[-]";
+ } else {
+ this.d.getElementById(spanID).innerHTML="[+]";
+ }
+ },
+
+ buildInspectionLevel : function()
+ {
+ var display = this.displaying;
+ var list = display.split(".");
+ var links = ["<a href=\"javascript:var_dump()\">[object Window]</a>"];
+ var name = '';
+ if(display.indexOf("[object ") >= 0) return links.join(".");
+ for(var i = 0; i < list.length; i++)
+ {
+ name += (name.length ? "." : "") + list[i];
+ links[i+1] = "<a href=\"javascript:var_dump('"+name+"')\">"+list[i]+"</a>";
+ }
+ return links.join(".");
+ },
+
+ buildTree : function() {
+ mHTML = "<div>Inspecting "+this.buildInspectionLevel()+"</div>";
+ mHTML +="<ul class=\"topLevel\">";
+ this.types.sort();
+ var so_objIndex=0;
+ for(i=0;i<this.types.length;i++)
+ {
+ mHTML+="<li style=\"cursor:pointer;\" onclick=\"Prado.Inspector.show('ul"+i+"');Prado.Inspector.changeSpan('sp" + i + "')\"><span id=\"sp" + i + "\">[+]</span><b>" + this.types[i] + "</b> (" + this.nameList[this.types[i]].length + ")</li><ul style=\"display:none;\" id=\"ul"+i+"\">";
+ this.hidden["ul"+i]=0;
+ for(e=0;e<this.nameList[this.types[i]].length;e++)
+ {
+ var prop = this.nameList[this.types[i]][e];
+ var value = this.objs[this.types[i]][prop]
+ var more = "";
+ if(value.indexOf("[object ") >= 0 && /^[a-zA-Z_]/.test(prop))
+ {
+ if(this.displaying.indexOf("[object ") < 0)
+ more = " <a href=\"javascript:var_dump('"+this.displaying+"."+prop+"')\"><b>more</b></a>";
+ else if(this.displaying.indexOf("[object Window]") >= 0)
+ more = " <a href=\"javascript:var_dump('"+prop+"')\"><b>more</b></a>";
+ }
+ mHTML+="<li style=\"cursor:pointer;\" onclick=\"Prado.Inspector.show('mul" + so_objIndex + "');Prado.Inspector.changeSpan('sk" + so_objIndex + "')\"><span id=\"sk" + so_objIndex + "\">[+]</span>" + prop + "</li><ul id=\"mul" + so_objIndex + "\" style=\"display:none;\"><li style=\"list-style-type:none;\"><pre>" + value + more + "</pre></li></ul>";
+ this.hidden["mul"+so_objIndex]=0;
+ so_objIndex++;
+ }
+ mHTML+="</ul>";
+ }
+ mHTML+="</ul>";
+ this.d.getElementById("so_mContainer").innerHTML =mHTML;
+ },
+
+ handleKeyEvent : function(e) {
+ keyCode=document.all?window.event.keyCode:e.keyCode;
+ if(keyCode==27) {
+ this.cleanUp();
+ }
+ },
+
+ cleanUp : function()
+ {
+ if(this.d.getElementById("so_mContainer"))
+ {
+ this.d.body.removeChild(this.d.getElementById("so_mContainer"));
+ this.d.body.removeChild(this.d.getElementById("so_mStyle"));
+ jQuery(this.d).unbind("keydown", this.dKeyDownEvent);
+ this.types = new Array();
+ this.objs = new Array();
+ this.hidden = new Array();
+ }
+ },
+
+ disabled : document.all && !this.opera,
+
+ inspect : function(obj)
+ {
+ if(this.disabled)return alert("Sorry, this only works in Mozilla and Firefox currently.");
+ this.cleanUp();
+ mObj=this.d.body.appendChild(this.d.createElement("div"));
+ mObj.id="so_mContainer";
+ sObj=this.d.body.appendChild(this.d.createElement("style"));
+ sObj.id="so_mStyle";
+ sObj.type="text/css";
+ sObj.innerHTML = this.style;
+ this.dKeyDownEvent = this.handleKeyEvent.bind(this);
+ jQuery(this.d).on("keydown", this.dKeyDownEvent);
+
+ this.parseJS(obj);
+ this.buildTree();
+
+ cObj=mObj.appendChild(this.d.createElement("div"));
+ cObj.className="credits";
+ cObj.innerHTML = "<b>[esc] to <a href=\"javascript:Prado.Inspector.cleanUp();\">close</a></b><br />Javascript Object Tree V2.0.";
+
+ window.scrollTo(0,0);
+ },
+
+ style : "#so_mContainer { position:absolute; top:5px; left:5px; background-color:#E3EBED; text-align:left; font:9pt verdana; width:85%; border:2px solid #000; padding:5px; z-index:1000; color:#000; } " +
+ "#so_mContainer ul { padding-left:20px; } " +
+ "#so_mContainer ul li { display:block; list-style-type:none; list-style-image:url(); line-height:2em; -moz-border-radius:.75em; font:10px verdana; padding:0; margin:2px; color:#000; } " +
+ "#so_mContainer li:hover { background-color:#E3EBED; } " +
+ "#so_mContainer ul li span { position:relative; width:15px; height:15px; margin-right:4px; } " +
+ "#so_mContainer pre { background-color:#F9FAFB; border:1px solid #638DA1; height:auto; padding:5px; font:9px verdana; color:#000; } " +
+ "#so_mContainer .topLevel { margin:0; padding:0; } " +
+ "#so_mContainer .credits { float:left; width:200px; font:6.5pt verdana; color:#000; padding:2px; margin-left:5px; text-align:left; border-top:1px solid #000; margin-top:15px; width:75%; } " +
+ "#so_mContainer .credits a { font:9px verdana; font-weight:bold; color:#004465; text-decoration:none; background-color:transparent; }"
+};
+
+//similar function to var_dump in PHP, brings up the javascript object tree UI.
+function var_dump(obj)
+{
+ Prado.Inspector.inspect(obj);
+}
+
+//similar function to print_r for PHP
+var print_r = inspect;
+
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/prado.js b/lib/prado/framework/Web/Javascripts/source/prado/prado.js
new file mode 100644
index 0000000..e100dc7
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/prado.js
@@ -0,0 +1,1238 @@
+/*
+ * Polyfill for ECMAScript5's bind() function.
+ * ----------
+ * Adds compatible .bind() function; needed for Internet Explorer < 9
+ * Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
+ */
+
+if (!Function.prototype.bind) {
+ Function.prototype.bind = function (oThis) {
+ if (typeof this !== "function") {
+ // closest thing possible to the ECMAScript 5 internal IsCallable function
+ throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
+ }
+
+ var aArgs = Array.prototype.slice.call(arguments, 1),
+ fToBind = this,
+ fNOP = function () {},
+ fBound = function () {
+ return fToBind.apply(this instanceof fNOP && oThis
+ ? this
+ : oThis,
+ aArgs.concat(Array.prototype.slice.call(arguments)));
+ };
+
+ fNOP.prototype = this.prototype;
+ fBound.prototype = new fNOP();
+
+ return fBound;
+ };
+}
+
+/*
+ * Low Pro JQ
+ * ----------
+ *
+ * Author: Dan Webb (dan@danwebb.net)
+ * GIT: github.com:danwrong/low-pro-for-jquery.git
+ * Download: http://github.com/danwrong/low-pro-for-jquery/tree/master/src/lowpro.jquery.js?raw=true
+ *
+ * A jQuery port of the Low Pro behavior framework that was originally written for Prototype.
+ *
+ * Prado actually uses it as a base to emulate OOP subclassing, inheritance and contructor events.
+ * The "behaviour" and the "Remote" bits are not used and have been commented out.
+ */
+
+(function($) {
+
+ var addMethods = function(source) {
+ var ancestor = this.superclass && this.superclass.prototype;
+ var properties = $.keys(source);
+
+ if (!$.keys({ toString: true }).length) properties.push("toString", "valueOf");
+
+ for (var i = 0, length = properties.length; i < length; i++) {
+ var property = properties[i], value = source[property];
+ if (ancestor && $.isFunction(value) && $.argumentNames(value)[0] == "$super") {
+
+ var method = value, value = $.extend($.wrap((function(m) {
+ return function() { return ancestor[m].apply(this, arguments) };
+ })(property), method), {
+ valueOf: function() { return method },
+ toString: function() { return method.toString() }
+ });
+ }
+ this.prototype[property] = value;
+ }
+
+ return this;
+ };
+
+ $.extend({
+ keys: function(obj) {
+ var keys = [];
+ for (var key in obj) keys.push(key);
+ return keys;
+ },
+
+ argumentNames: function(func) {
+ var names = func.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(/, ?/);
+ return names.length == 1 && !names[0] ? [] : names;
+ },
+
+ bind: function(func, scope) {
+ return function() {
+ return func.apply(scope, $.makeArray(arguments));
+ };
+ },
+
+ wrap: function(func, wrapper) {
+ var __method = func;
+ return function() {
+ return wrapper.apply(this, [$.bind(__method, this)].concat($.makeArray(arguments)));
+ };
+ },
+
+ klass: function() {
+ var parent = null, properties = $.makeArray(arguments);
+ if ($.isFunction(properties[0])) parent = properties.shift();
+
+ var klass = function() {
+ this.initialize.apply(this, arguments);
+ };
+
+ klass.superclass = parent;
+ klass.subclasses = [];
+ klass.addMethods = addMethods;
+
+ if (parent) {
+ var subclass = function() { };
+ subclass.prototype = parent.prototype;
+ klass.prototype = new subclass;
+ parent.subclasses.push(klass);
+ }
+
+ for (var i = 0; i < properties.length; i++)
+ klass.addMethods(properties[i]);
+
+ if (!klass.prototype.initialize)
+ klass.prototype.initialize = function() {};
+
+ klass.prototype.constructor = klass;
+
+ return klass;
+ },
+ delegate: function(rules) {
+ return function(e) {
+ var target = $(e.target), parent = null;
+ for (var selector in rules) {
+ if (target.is(selector) || ((parent = target.parents(selector)) && parent.length > 0)) {
+ return rules[selector].apply(this, [parent || target].concat($.makeArray(arguments)));
+ }
+ parent = null;
+ }
+ };
+ }
+ });
+/*
+ var bindEvents = function(instance) {
+ for (var member in instance) {
+ if (member.match(/^on(.+)/) && typeof instance[member] == 'function') {
+ instance.element.live(RegExp.$1, {'behavior': instance}, instance[member]);
+ }
+ }
+ };
+
+ var behaviorWrapper = function(behavior) {
+ return $.klass(behavior, {
+ initialize: function($super, element, args) {
+ this.element = element;
+ if ($super) $super.apply(this, args);
+ },
+ trigger: function(eventType, extraParameters) {
+ var parameters = [this].concat(extraParameters);
+ this.element.trigger(eventType, parameters);
+ }
+ });
+ };
+
+ var attachBehavior = function(el, behavior, args) {
+ var wrapper = behaviorWrapper(behavior);
+ var instance = new wrapper(el, args);
+
+ bindEvents(instance);
+
+ if (!behavior.instances) behavior.instances = [];
+
+ behavior.instances.push(instance);
+
+ return instance;
+ };
+
+
+ $.fn.extend({
+ attach: function() {
+ var args = $.makeArray(arguments), behavior = args.shift();
+ attachBehavior(this, behavior, args);
+ return this;
+ },
+ delegate: function(type, rules) {
+ return this.bind(type, $.delegate(rules));
+ },
+ attached: function(behavior) {
+ var instances = [];
+
+ if (!behavior.instances) return instances;
+
+ this.each(function(i, element) {
+ $.each(behavior.instances, function(i, instance) {
+ if (instance.element.get(0) == element) instances.push(instance);
+ });
+ });
+
+ return instances;
+ },
+ firstAttached: function(behavior) {
+ return this.attached(behavior)[0];
+ }
+ });
+
+ Remote = $.klass({
+ initialize: function(options) {
+ if (this.element.attr('nodeName') == 'FORM') this.element.attach(Remote.Form, options);
+ else this.element.attach(Remote.Link, options);
+ }
+ });
+
+ Remote.Base = $.klass({
+ initialize : function(options) {
+ this.options = $.extend(true, {}, options || {});
+ },
+ _makeRequest : function(options) {
+ $.ajax(options);
+ return false;
+ }
+ });
+
+ Remote.Link = $.klass(Remote.Base, {
+ onclick: function(e) {
+ var options = $.extend({
+ url: $(this).attr('href'),
+ type: 'GET'
+ }, this.options);
+ return e.data.behavior._makeRequest(e.data.behavior.options);
+ }
+ });
+
+ Remote.Form = $.klass(Remote.Base, {
+ onclick: function(e) {
+ var target = e.target;
+
+ if ($.inArray(target.nodeName.toLowerCase(), ['input', 'button']) >= 0 && target.type.match(/submit|image/))
+ e.data.behavior._submitButton = target;
+ },
+ onsubmit: function(e) {
+ var elm = $(this), data = elm.serializeArray();
+
+ if (e.data.behavior._submitButton) data.push({
+ name: e.data.behavior._submitButton.name,
+ value: e.data.behavior._submitButton.value
+ });
+
+ var options = $.extend({
+ url : elm.attr('action'),
+ type : elm.attr('method') || 'GET',
+ data : data
+ }, e.data.behavior.options);
+
+ e.data.behavior._makeRequest(options);
+
+ return false;
+ }
+ });
+
+ $.ajaxSetup({
+ beforeSend: function(xhr) {
+ if (!this.dataType)
+ xhr.setRequestHeader("Accept", "text/javascript, text/html, application/xml, text/xml, *\/*");
+ }
+ });
+*/
+})(jQuery);
+
+
+/**
+ * Prado base namespace
+ * @namespace Prado
+ */
+var Prado =
+{
+ /**
+ * Version of Prado clientscripts
+ * @var Version
+ */
+ Version: '3.3.0',
+
+ /**
+ * Registry for Prado components
+ * @var Registry
+ */
+ Registry: {}
+};
+
+Prado.RequestManager =
+{
+ FIELD_POSTBACK_TARGET : 'PRADO_POSTBACK_TARGET',
+
+ FIELD_POSTBACK_PARAMETER : 'PRADO_POSTBACK_PARAMETER'
+};
+/**
+ * Performs a PostBack using javascript.
+ * @function Prado.PostBack
+ * @param options - Postback options
+ * @param event - Event that triggered this postback
+ * @... {string} FormID - Form that should be posted back
+ * @... {optional boolean} CausesValidation - Validate before PostBack if true
+ * @... {optional string} ValidationGroup - Group to Validate
+ * @... {optional string} ID - Validation ID
+ * @... {optional string} PostBackUrl - Postback URL
+ * @... {optional boolean} TrackFocus - Keep track of focused element if true
+ * @... {string} EventTarget - Id of element that triggered PostBack
+ * @... {string} EventParameter - EventParameter for PostBack
+ */
+Prado.PostBack = jQuery.klass(
+{
+ options : {},
+
+ initialize: function(options, event)
+ {
+ jQuery.extend(this.options, options || {});
+ this.event = event;
+ this.doPostBack();
+ },
+
+ getForm : function()
+ {
+ return jQuery("#" + this.options['FormID']).get(0);
+ },
+
+ doPostBack : function()
+ {
+ var form = this.getForm();
+ if(this.options['CausesValidation'] && typeof(Prado.Validation) != "undefined")
+ {
+ if(!Prado.Validation.validate(this.options['FormID'], this.options['ValidationGroup'], jQuery("#" + this.options['ID'])))
+ return this.event.preventDefault();
+ }
+
+ if(this.options['PostBackUrl'] && this.options['PostBackUrl'].length > 0)
+ form.action = this.options['PostBackUrl'];
+
+ if(this.options['TrackFocus'])
+ {
+ var lastFocus = jQuery('#PRADO_LASTFOCUS');
+ if(lastFocus)
+ {
+ var active = document.activeElement; //where did this come from
+ if(active)
+ lastFocus.value = active.id;
+ else
+ lastFocus.value = this.options['EventTarget'];
+ }
+ }
+
+ var input=null;
+ if(this.options.EventTarget)
+ {
+ input = document.createElement("input");
+ input.setAttribute("type", "hidden");
+ input.setAttribute("name", Prado.RequestManager.FIELD_POSTBACK_TARGET);
+ input.setAttribute("value", this.options.EventTarget);
+ form.appendChild(input);
+ }
+ if(this.options.EventParameter)
+ {
+ input = document.createElement("input");
+ input.setAttribute("type", "hidden");
+ input.setAttribute("name", Prado.RequestManager.FIELD_POSTBACK_PARAMETER);
+ input.setAttribute("value", this.options.EventParameter);
+ form.appendChild(input);
+ }
+
+ jQuery(form).trigger('submit');
+ }
+});
+
+/**
+ * Prado utilities to manipulate DOM elements.
+ * @object Prado.Element
+ */
+Prado.Element =
+{
+ /**
+ * Executes a jQuery method on a particular element.
+ * @function ?
+ * @param {string} element - Element id
+ * @param {string} method - method name
+ * @param {array} value - method parameters
+ */
+ j: function(element, method, params)
+ {
+ var obj=jQuery("#" + element);
+ obj[method].apply(obj, params);
+ },
+
+ /**
+ * Select options from a selectable element.
+ * @function ?
+ * @param {string} element - Element id
+ * @param {string} method - Name of any {@link Prado.Element.Selection} method
+ * @param {array|boolean|string} value - Values that should be selected
+ * @param {int} total - Number of elements
+ */
+ select : function(element, method, value, total)
+ {
+ var el = jQuery("#" + element).get(0);
+ if(!el) return;
+ var selection = Prado.Element.Selection;
+ if(typeof(selection[method]) == "function")
+ {
+ var control = selection.isSelectable(el) ? [el] : selection.getListElements(element,total);
+ selection[method](control, value);
+ }
+ },
+
+ /**
+ * Sets an attribute of a DOM element.
+ * @function ?
+ * @param {string} element - Element id
+ * @param {string} attribute - Name of attribute
+ * @param {string} value - Value of attribute
+ */
+ setAttribute : function(element, attribute, value)
+ {
+ var el = jQuery("#" + element);
+ if(!el) return;
+ if((attribute == "disabled" || attribute == "multiple" || attribute == "readonly" || attribute == "href") && value==false)
+ el.removeAttr(attribute);
+ else if(attribute.match(/^on/i)) //event methods
+ {
+ try
+ {
+ eval("(func = function(event){"+value+"})");
+ el.get(0)[attribute] = func;
+ }
+ catch(e)
+ {
+ debugger;
+ throw "Error in evaluating '"+value+"' for attribute "+attribute+" for element "+element;
+ }
+ }
+ else
+ el.attr(attribute, value);
+ },
+
+ scrollTo : function(element, options)
+ {
+ var op = {
+ duration : 500,
+ offset : 50
+ };
+ jQuery.extend(op, options || {});
+ jQuery('html, body').animate({
+ scrollTop: jQuery("#"+element).offset().top - op.offset
+ }, op.duration);
+ },
+
+ focus : function(element)
+ {
+ jQuery("#"+element).focus();
+ },
+
+ /**
+ * Sets the options for a select element.
+ * @function ?
+ * @param {string} element - Element id
+ * @param {array[]} options - Array of options, each an array of structure
+ * [ "optionText" , "optionValue" , "optionGroup" ]
+ */
+ setOptions : function(element, options)
+ {
+ var el = jQuery("#" + element).get(0);
+ var previousGroup = null;
+ var optGroup=null;
+ if(el && el.tagName.toLowerCase() == "select")
+ {
+ while(el.childNodes.length > 0)
+ el.removeChild(el.lastChild);
+
+ var optDom = Prado.Element.createOptions(options);
+ for(var i = 0; i < optDom.length; i++)
+ el.appendChild(optDom[i]);
+ }
+ },
+
+ /**
+ * Create opt-group options from an array of options.
+ * @function {array} ?
+ * @param {array[]} options - Array of options, each an array of structure
+ * [ "optionText" , "optionValue" , "optionGroup" ]
+ * @returns Array of option DOM elements
+ */
+ createOptions : function(options)
+ {
+ var previousGroup = null;
+ var optgroup=null;
+ var result = [];
+ for(var i = 0; i<options.length; i++)
+ {
+ var option = options[i];
+ if(option.length > 2)
+ {
+ var group = option[2];
+ if(group!=previousGroup)
+ {
+ if(previousGroup!=null && optgroup!=null)
+ {
+ result.push(optgroup);
+ previousGroup=null;
+ optgroup=null;
+ }
+ optgroup = document.createElement('optgroup');
+ optgroup.label = group;
+ previousGroup = group;
+ }
+ }
+ var opt = document.createElement('option');
+ opt.text = option[0];
+ opt.innerHTML = option[0];
+ opt.value = option[1];
+ if(optgroup!=null)
+ optgroup.appendChild(opt);
+ else
+ result.push(opt);
+ }
+ if(optgroup!=null)
+ result.push(optgroup);
+ return result;
+ },
+
+ /**
+ * Replace a DOM element either with given content or
+ * with content from a CallBack response boundary
+ * using a replacement method.
+ * @function ?
+ * @param {string|element} element - DOM element or element id
+ * @param {optional string} content - New content of element
+ * @param {optional string} boundary - Boundary of new content
+ * @param {optional boolean} self - Whether to replace itself or just the inner content
+ */
+ replace : function(element, content, boundary, self)
+ {
+ if(boundary)
+ {
+ var result = this.extractContent(boundary);
+ if(result != null)
+ content = result;
+ }
+ if(self)
+ jQuery('#'+element).replaceWith(content);
+ else
+ jQuery('#'+element).html(content);
+ },
+
+ /**
+ * Appends a javascript block to the document.
+ * @function ?
+ * @param {string} boundary - Boundary containing the javascript code
+ */
+ appendScriptBlock : function(boundary)
+ {
+ var content = this.extractContent(boundary);
+ if(content == null)
+ return;
+
+ var el = document.createElement("script");
+ el.type = "text/javascript";
+ el.id = 'inline_' + boundary;
+ el.text = content;
+
+ (document.getElementsByTagName('head')[0] || document.documentElement).appendChild(el);
+ el.parentNode.removeChild(el);
+ },
+
+ /**
+ * Evaluate a javascript snippet from a string.
+ * @function ?
+ * @param {string} content - String containing the script
+ * @param {string} boundary - Boundary containing the script
+ */
+ evaluateScript : function(content, boundary)
+ {
+ if(boundary)
+ {
+ var result = this.extractContent(boundary);
+ if(result != null)
+ content = result;
+ }
+
+ try
+ {
+ jQuery.globalEval(content);
+ }
+ catch(e)
+ {
+ if(typeof(Logger) != "undefined")
+ Logger.error('Error during evaluation of script "'+content+'"');
+ else
+ debugger;
+ throw e;
+ }
+ }
+};
+
+/**
+ * Utilities for selections.
+ * @object Prado.Element.Selection
+ */
+Prado.Element.Selection =
+{
+ /**
+ * Check if an DOM element can be selected.
+ * @function {boolean} ?
+ * @param {element} el - DOM elemet
+ * @returns true if element is selectable
+ */
+ isSelectable : function(el)
+ {
+ if(el && el.type)
+ {
+ switch(el.type.toLowerCase())
+ {
+ case 'checkbox':
+ case 'radio':
+ case 'select':
+ case 'select-multiple':
+ case 'select-one':
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /**
+ * Set checked attribute of a checkbox or radiobutton to value.
+ * @function {boolean} ?
+ * @param {element} el - DOM element
+ * @param {boolean} value - New value of checked attribute
+ * @returns New value of checked attribute
+ */
+ inputValue : function(el, value)
+ {
+ switch(el.type.toLowerCase())
+ {
+ case 'checkbox':
+ case 'radio':
+ return el.checked = value;
+ }
+ },
+
+ /**
+ * Set selected attribute for elements options by value.
+ * If value is boolean, all elements options selected attribute will be set
+ * to value. Otherwhise all options that have the given value will be selected.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ * @param {boolean|string} value - Value of options that should be selected or boolean value of selection status
+ */
+ selectValue : function(elements, value)
+ {
+ jQuery.each(elements, function(idx, el)
+ {
+ jQuery.each(el.options, function(idx, option)
+ {
+ if(typeof(value) == "boolean")
+ option.selected = value;
+ else if(option.value == value)
+ option.selected = true;
+ });
+ })
+ },
+
+ /**
+ * Set selected attribute for elements options by array of values.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ * @param {string[]} value - Array of values to select
+ */
+ selectValues : function(elements, values)
+ {
+ var selection = this;
+ jQuery.each(values, function(idx, value)
+ {
+ selection.selectValue(elements,value);
+ })
+ },
+
+ /**
+ * Set selected attribute for elements options by option index.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ * @param {int} index - Index of option to select
+ */
+ selectIndex : function(elements, index)
+ {
+ jQuery.each(elements, function(idx, el)
+ {
+ if(el.type.toLowerCase() == 'select-one')
+ el.selectedIndex = index;
+ else
+ {
+ for(var i = 0; i<el.length; i++)
+ {
+ if(i == index)
+ el.options[i].selected = true;
+ }
+ }
+ })
+ },
+
+ /**
+ * Set selected attribute to true for all elements options.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ */
+ selectAll : function(elements)
+ {
+ jQuery.each(elements, function(idx, el)
+ {
+ if(el.type.toLowerCase() != 'select-one')
+ {
+ jQuery.each(el.options, function(idx, option)
+ {
+ option.selected = true;
+ })
+ }
+ })
+ },
+
+ /**
+ * Toggle the selected attribute for elements options.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ */
+ selectInvert : function(elements)
+ {
+ jQuery.each(elements, function(idx, el)
+ {
+ if(el.type.toLowerCase() != 'select-one')
+ {
+ jQuery.each(el.options, function(idx, option)
+ {
+ option.selected = !option.selected;
+ })
+ }
+ })
+ },
+
+ /**
+ * Set selected attribute for elements options by array of option indices.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ * @param {int[]} indices - Array of option indices to select
+ */
+ selectIndices : function(elements, indices)
+ {
+ var selection = this;
+ jQuery.each(indices, function(idx, index)
+ {
+ selection.selectIndex(elements,index);
+ })
+ },
+
+ /**
+ * Unselect elements.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ */
+ selectClear : function(elements)
+ {
+ jQuery.each(elements, function(idx, el)
+ {
+ el.selectedIndex = -1;
+ })
+ },
+
+ /**
+ * Get list elements of an element.
+ * @function {element[]} ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ * @param {int} total - Number of list elements to return
+ * @returns Array of list DOM elements
+ */
+ getListElements : function(element, total)
+ {
+ var elements = new Array();
+ var el;
+ for(var i = 0; i < total; i++)
+ {
+ el = jQuery("#"+element+"_c"+i).get(0);
+ if(el)
+ elements.push(el);
+ }
+ return elements;
+ },
+
+ /**
+ * Set checked attribute of elements by value.
+ * If value is boolean, checked attribute will be set to value.
+ * Otherwhise all elements that have the given value will be checked.
+ * @function ?
+ * @param {element[]} elements - Array of checkable DOM elements
+ * @param {boolean|String} value - Value that should be checked or boolean value of checked status
+ *
+ */
+ checkValue : function(elements, value)
+ {
+ jQuery.each(elements, function(idx, el)
+ {
+ if(typeof(value) == "boolean")
+ el.checked = value;
+ else if(el.value == value)
+ el.checked = true;
+ });
+ },
+
+ /**
+ * Set checked attribute of elements by array of values.
+ * @function ?
+ * @param {element[]} elements - Array of checkable DOM elements
+ * @param {string[]} values - Values that should be checked
+ *
+ */
+ checkValues : function(elements, values)
+ {
+ var selection = this;
+ jQuery(values).each(function(idx, value)
+ {
+ selection.checkValue(elements, value);
+ })
+ },
+
+ /**
+ * Set checked attribute of elements by list index.
+ * @function ?
+ * @param {element[]} elements - Array of checkable DOM elements
+ * @param {int} index - Index of element to set checked
+ */
+ checkIndex : function(elements, index)
+ {
+ for(var i = 0; i<elements.length; i++)
+ {
+ if(i == index)
+ elements[i].checked = true;
+ }
+ },
+
+ /**
+ * Set checked attribute of elements by array of list indices.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ * @param {int[]} indices - Array of list indices to set checked
+ */
+ checkIndices : function(elements, indices)
+ {
+ var selection = this;
+ jQuery.each(indices, function(idx, index)
+ {
+ selection.checkIndex(elements, index);
+ })
+ },
+
+ /**
+ * Uncheck elements.
+ * @function ?
+ * @param {element[]} elements - Array of checkable DOM elements
+ */
+ checkClear : function(elements)
+ {
+ jQuery.each(elements, function(idx, el)
+ {
+ el.checked = false;
+ });
+ },
+
+ /**
+ * Set checked attribute of all elements to true.
+ * @function ?
+ * @param {element[]} elements - Array of checkable DOM elements
+ */
+ checkAll : function(elements)
+ {
+ jQuery.each(elements, function(idx, el)
+ {
+ el.checked = true;
+ })
+ },
+
+ /**
+ * Toggle the checked attribute of elements.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ */
+ checkInvert : function(elements)
+ {
+ jQuery.each(elements, function(idx, el)
+ {
+ el.checked = !el.checked;
+ })
+ }
+};
+
+jQuery.extend(String.prototype, {
+
+ /**
+ * Add padding to string
+ * @function {string} ?
+ * @param {string} side - "left" to pad the string on the left, "right" to pad right.
+ * @param {int} len - Minimum string length.
+ * @param {string} chr - Character(s) to pad
+ * @returns Padded string
+ */
+ pad : function(side, len, chr) {
+ if (!chr) chr = ' ';
+ var s = this;
+ var left = side.toLowerCase()=='left';
+ while (s.length<len) s = left? chr + s : s + chr;
+ return s;
+ },
+
+ /**
+ * Add left padding to string
+ * @function {string} ?
+ * @param {int} len - Minimum string length.
+ * @param {string} chr - Character(s) to pad
+ * @returns Padded string
+ */
+ padLeft : function(len, chr) {
+ return this.pad('left',len,chr);
+ },
+
+ /**
+ * Add right padding to string
+ * @function {string} ?
+ * @param {int} len - Minimum string length.
+ * @param {string} chr - Character(s) to pad
+ * @returns Padded string
+ */
+ padRight : function(len, chr) {
+ return this.pad('right',len,chr);
+ },
+
+ /**
+ * Add zeros to the right of string
+ * @function {string} ?
+ * @param {int} len - Minimum string length.
+ * @returns Padded string
+ */
+ zerofill : function(len) {
+ return this.padLeft(len,'0');
+ },
+
+ /**
+ * Remove white spaces from both ends of string.
+ * @function {string} ?
+ * @returns Trimmed string
+ */
+ trim : function() {
+ return this.replace(/^\s+|\s+$/g,'');
+ },
+
+ /**
+ * Remove white spaces from the left side of string.
+ * @function {string} ?
+ * @returns Trimmed string
+ */
+ trimLeft : function() {
+ return this.replace(/^\s+/,'');
+ },
+
+ /**
+ * Remove white spaces from the right side of string.
+ * @function {string} ?
+ * @returns Trimmed string
+ */
+ trimRight : function() {
+ return this.replace(/\s+$/,'');
+ },
+
+ /**
+ * Convert period separated function names into a function reference.
+ * <br />Example:
+ * <pre>
+ * "Prado.AJAX.Callback.Action.setValue".toFunction()
+ * </pre>
+ * @function {function} ?
+ * @returns Reference to the corresponding function
+ */
+ toFunction : function()
+ {
+ var commands = this.split(/\./);
+ var command = window;
+ jQuery(commands).each(function(idx, action)
+ {
+ if(command[new String(action)])
+ command=command[new String(action)];
+ });
+ if(typeof(command) == "function")
+ return command;
+ else
+ {
+ if(typeof Logger != "undefined")
+ Logger.error("Missing function", this);
+
+ throw new Error ("Missing function '"+this+"'");
+ }
+ },
+
+ /**
+ * Convert string into integer, returns null if not integer.
+ * @function {int} ?
+ * @returns Integer, null if string does not represent an integer.
+ */
+ toInteger : function()
+ {
+ var exp = /^\s*[-\+]?\d+\s*$/;
+ if (this.match(exp) == null)
+ return null;
+ var num = parseInt(this, 10);
+ return (isNaN(num) ? null : num);
+ },
+
+ /**
+ * Convert string into a double/float value. <b>Internationalization
+ * is not supported</b>
+ * @function {double} ?
+ * @param {string} decimalchar - Decimal character, defaults to "."
+ * @returns Double, null if string does not represent a float value
+ */
+ toDouble : function(decimalchar)
+ {
+ if(this.length <= 0) return null;
+ decimalchar = decimalchar || ".";
+ var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$");
+ var m = this.match(exp);
+
+ if (m == null)
+ return null;
+ m[1] = m[1] || "";
+ m[2] = m[2] || "0";
+ m[4] = m[4] || "0";
+
+ var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4];
+ var num = parseFloat(cleanInput);
+ return (isNaN(num) ? null : num);
+ },
+
+ /**
+ * Convert strings that represent a currency value to float.
+ * E.g. "10,000.50" will become "10000.50". The number
+ * of dicimal digits, grouping and decimal characters can be specified.
+ * <i>The currency input format is <b>very</b> strict, null will be returned if
+ * the pattern does not match</i>.
+ * @function {double} ?
+ * @param {string} groupchar - Grouping character, defaults to ","
+ * @param {int} digits - Number of decimal digits
+ * @param {string} decimalchar - Decimal character, defaults to "."
+ * @returns Double, null if string does not represent a currency value
+ */
+ toCurrency : function(groupchar, digits, decimalchar)
+ {
+ groupchar = groupchar || ",";
+ decimalchar = decimalchar || ".";
+ digits = typeof(digits) == "undefined" ? 2 : digits;
+
+ var exp = new RegExp("^\\s*([-\\+])?(((\\d+)\\" + groupchar + ")*)(\\d+)"
+ + ((digits > 0) ? "(\\" + decimalchar + "(\\d{1," + digits + "}))?" : "")
+ + "\\s*$");
+ var m = this.match(exp);
+ if (m == null)
+ return null;
+ var intermed = m[2] + m[5] ;
+ var cleanInput = m[1] + intermed.replace(
+ new RegExp("(\\" + groupchar + ")", "g"), "")
+ + ((digits > 0) ? "." + m[7] : "");
+ var num = parseFloat(cleanInput);
+ return (isNaN(num) ? null : num);
+ }
+});
+
+jQuery.extend(Date.prototype,
+{
+ /**
+ * SimpleFormat
+ * @function ?
+ * @param {string} format - TODO
+ * @param {string} data - TODO
+ * @returns TODO
+ */
+ SimpleFormat: function(format, data)
+ {
+ data = data || {};
+ var bits = new Array();
+ bits['d'] = this.getDate();
+ bits['dd'] = String(this.getDate()).zerofill(2);
+
+ bits['M'] = this.getMonth()+1;
+ bits['MM'] = String(this.getMonth()+1).zerofill(2);
+ if(data.AbbreviatedMonthNames)
+ bits['MMM'] = data.AbbreviatedMonthNames[this.getMonth()];
+ if(data.MonthNames)
+ bits['MMMM'] = data.MonthNames[this.getMonth()];
+ var yearStr = "" + this.getFullYear();
+ yearStr = (yearStr.length == 2) ? '19' + yearStr: yearStr;
+ bits['yyyy'] = yearStr;
+ bits['yy'] = bits['yyyy'].toString().substr(2,2);
+
+ // do some funky regexs to replace the format string
+ // with the real values
+ var frm = new String(format);
+ for (var sect in bits)
+ {
+ var reg = new RegExp("\\b"+sect+"\\b" ,"g");
+ frm = frm.replace(reg, bits[sect]);
+ }
+ return frm;
+ },
+
+ /**
+ * toISODate
+ * @function {string} ?
+ * @returns TODO
+ */
+ toISODate : function()
+ {
+ var y = this.getFullYear();
+ var m = String(this.getMonth() + 1).zerofill(2);
+ var d = String(this.getDate()).zerofill(2);
+ return String(y) + String(m) + String(d);
+ }
+});
+
+jQuery.extend(Date,
+{
+ /**
+ * SimpleParse
+ * @function ?
+ * @param {string} format - TODO
+ * @param {string} data - TODO
+ * @returns TODO
+ */
+ SimpleParse: function(value, format)
+ {
+ var val=String(value);
+ format=String(format);
+
+ if(val.length <= 0) return null;
+
+ if(format.length <= 0) return new Date(value);
+
+ var isInteger = function (val)
+ {
+ var digits="1234567890";
+ for (var i=0; i < val.length; i++)
+ {
+ if (digits.indexOf(val.charAt(i))==-1) { return false; }
+ }
+ return true;
+ };
+
+ var getInt = function(str,i,minlength,maxlength)
+ {
+ for (var x=maxlength; x>=minlength; x--)
+ {
+ var token=str.substring(i,i+x);
+ if (token.length < minlength) { return null; }
+ if (isInteger(token)) { return token; }
+ }
+ return null;
+ };
+
+ var i_val=0;
+ var i_format=0;
+ var c="";
+ var token="";
+ var token2="";
+ var x,y;
+ var now=new Date();
+ var year=now.getFullYear();
+ var month=now.getMonth()+1;
+ var date=1;
+
+ while (i_format < format.length)
+ {
+ // Get next token from format string
+ c=format.charAt(i_format);
+ token="";
+ while ((format.charAt(i_format)==c) && (i_format < format.length))
+ {
+ token += format.charAt(i_format++);
+ }
+
+ // Extract contents of value based on format token
+ if (token=="yyyy" || token=="yy" || token=="y")
+ {
+ if (token=="yyyy") { x=4;y=4; }
+ if (token=="yy") { x=2;y=2; }
+ if (token=="y") { x=2;y=4; }
+ year=getInt(val,i_val,x,y);
+ if (year==null) { return null; }
+ i_val += year.length;
+ if (year.length==2)
+ {
+ if (year > 70) { year=1900+(year-0); }
+ else { year=2000+(year-0); }
+ }
+ }
+
+ else if (token=="MM"||token=="M")
+ {
+ month=getInt(val,i_val,token.length,2);
+ if(month==null||(month<1)||(month>12)){return null;}
+ i_val+=month.length;
+ }
+ else if (token=="dd"||token=="d")
+ {
+ date=getInt(val,i_val,token.length,2);
+ if(date==null||(date<1)||(date>31)){return null;}
+ i_val+=date.length;
+ }
+ else
+ {
+ if (val.substring(i_val,i_val+token.length)!=token) {return null;}
+ else {i_val+=token.length;}
+ }
+ }
+
+ // If there are any trailing characters left in the value, it doesn't match
+ if (i_val != val.length) { return null; }
+
+ // Is date valid for month?
+ if (month==2)
+ {
+ // Check for leap year
+ if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
+ if (date > 29){ return null; }
+ }
+ else { if (date > 28) { return null; } }
+ }
+
+ if ((month==4)||(month==6)||(month==9)||(month==11))
+ {
+ if (date > 30) { return null; }
+ }
+
+ var newdate=new Date(year,month-1,date, 0, 0, 0);
+ return newdate;
+ }
+});
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks.css b/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks.css
new file mode 100644
index 0000000..2bf2e90
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks.css
@@ -0,0 +1,29 @@
+.TRatingList_blocks
+{
+ border-collapse: collapse;
+}
+.TRatingList_blocks input, .TRatingList_blocks label
+{
+ display: none;
+}
+.TRatingList_blocks td
+{
+ width: 17px;
+ height: 18px;
+ background-image: url(blocks_blank.gif);
+ background-repeat: no-repeat;
+ cursor: pointer;
+}
+.TRatingList_blocks td.rating_selected
+{
+ background-image: url(blocks_selected.gif);
+}
+
+.TRatingList_blocks td.rating_hover
+{
+ background-image: url(blocks_hover.gif);
+}
+.TRatingList_blocks td.rating_half
+{
+ background-image: url(blocks_half.gif);
+}
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks.png b/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks.png
new file mode 100644
index 0000000..16a2b24
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_blank.gif b/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_blank.gif
new file mode 100644
index 0000000..a68d0e9
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_blank.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_half.gif b/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_half.gif
new file mode 100644
index 0000000..4cff014
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_half.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_hover.gif b/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_hover.gif
new file mode 100644
index 0000000..58ad749
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_hover.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_selected.gif b/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_selected.gif
new file mode 100644
index 0000000..f91873e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/ratings/blocks_selected.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/ratings/default.css b/lib/prado/framework/Web/Javascripts/source/prado/ratings/default.css
new file mode 100644
index 0000000..c15a36b
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/ratings/default.css
@@ -0,0 +1,29 @@
+.TRatingList_default
+{
+ border-collapse: collapse;
+}
+.TRatingList_default input, .TRatingList_default label
+{
+ display: none;
+}
+.TRatingList_default td
+{
+ width: 17px;
+ height: 18px;
+ background-image: url(default_blank.gif);
+ background-repeat: no-repeat;
+ cursor: pointer;
+}
+.TRatingList_default td.rating_selected
+{
+ background-image: url(default_selected.gif);
+}
+
+.TRatingList_default td.rating_hover
+{
+ background-image: url(default_hover.gif);
+}
+.TRatingList_default td.rating_half
+{
+ background-image: url(default_half.gif);
+}
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/ratings/default_blank.gif b/lib/prado/framework/Web/Javascripts/source/prado/ratings/default_blank.gif
new file mode 100644
index 0000000..4e6fda3
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/ratings/default_blank.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/ratings/default_half.gif b/lib/prado/framework/Web/Javascripts/source/prado/ratings/default_half.gif
new file mode 100644
index 0000000..7cecf0e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/ratings/default_half.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/ratings/default_hover.gif b/lib/prado/framework/Web/Javascripts/source/prado/ratings/default_hover.gif
new file mode 100644
index 0000000..ad0cd28
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/ratings/default_hover.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/ratings/default_selected.gif b/lib/prado/framework/Web/Javascripts/source/prado/ratings/default_selected.gif
new file mode 100644
index 0000000..a19ab39
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/ratings/default_selected.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/ratings/ratings.js b/lib/prado/framework/Web/Javascripts/source/prado/ratings/ratings.js
new file mode 100644
index 0000000..eb541b9
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/ratings/ratings.js
@@ -0,0 +1,179 @@
+Prado.WebUI.TRatingList = jQuery.klass(Prado.WebUI.Control,
+{
+ selectedIndex : -1,
+ rating: -1,
+ readOnly : false,
+
+ onInit : function(options)
+ {
+ var cap = $('#'+options.CaptionID).get(0);
+ this.options = jQuery.extend(
+ {
+ caption : cap ? cap.innerHTML : ''
+ }, options || {});
+
+ this.radios = [];
+
+ $('#'+options.ID).addClass(options.Style);
+ for(var i = 0; i<options.ItemCount; i++)
+ {
+ var radio = $('#'+options.ID+"_c"+i).get(0);
+ var td = radio.parentNode.parentNode;
+
+ if(radio && td.tagName.toLowerCase()=='td')
+ {
+ this.radios.push(radio);
+ $(td).addClass("rating");
+ }
+ }
+
+ this.selectedIndex = options.SelectedIndex;
+ this.rating = options.Rating;
+ this.readOnly = options.ReadOnly
+ if(options.Rating <= 0 && options.SelectedIndex >= 0)
+ this.rating = options.SelectedIndex+1;
+ this.setReadOnly(this.readOnly);
+ },
+
+ hover : function(index, ev)
+ {
+ if(this.readOnly==true) return;
+
+ for(var i = 0; i<this.radios.length; i++)
+ {
+ var node = this.radios[i].parentNode.parentNode;
+ if(i <= index)
+ $(node).addClass('rating_hover');
+ else
+ $(node).removeClass('rating_hover');
+ $(node).removeClass("rating_selected");
+ $(node).removeClass("rating_half");
+ }
+ this.showCaption(this.getIndexCaption(index));
+ },
+
+ recover : function(index, ev)
+ {
+ if(this.readOnly==true) return;
+ this.showRating(this.rating);
+ this.showCaption(this.options.caption);
+ },
+
+ click : function(index, ev)
+ {
+ if(this.readOnly==true) return;
+ this.selectedIndex = index;
+ this.setRating(index+1);
+
+ if(this.options['AutoPostBack']==true){
+ this.dispatchRequest(ev);
+ }
+ },
+
+ dispatchRequest : function(ev)
+ {
+ var requestOptions =jQuery.extend({}, this.options,
+ {
+ ID : this.options.ID+"_c"+this.selectedIndex,
+ EventTarget : this.options.ListName+"$c"+this.selectedIndex
+ });
+ new Prado.PostBack(requestOptions, ev);
+ },
+
+ setRating : function(value)
+ {
+ this.rating = value;
+ var base = Math.floor(value-1);
+ var remainder = value - base-1;
+ var halfMax = this.options.HalfRating["1"];
+ var index = remainder > halfMax ? base+1 : base;
+ for(var i = 0; i<this.radios.length; i++)
+ this.radios[i].checked = (i == index);
+
+ var caption = this.getIndexCaption(index);
+ this.setCaption(caption);
+ this.showCaption(caption);
+
+ this.showRating(this.rating);
+ },
+
+ showRating: function(value)
+ {
+ var base = Math.floor(value-1);
+ var remainder = value - base-1;
+ var halfMin = this.options.HalfRating["0"];
+ var halfMax = this.options.HalfRating["1"];
+ var index = remainder > halfMax ? base+1 : base;
+ var hasHalf = remainder >= halfMin && remainder <= halfMax;
+ for(var i = 0; i<this.radios.length; i++)
+ {
+ var node = this.radios[i].parentNode.parentNode;
+ if(i <= index)
+ $(node).addClass('rating_selected');
+ else
+ $(node).removeClass('rating_selected');
+
+ if(i==index+1 && hasHalf)
+ $(node).addClass("rating_half");
+ else
+ $(node).removeClass("rating_half");
+ $(node).removeClass("rating_hover");
+ }
+ },
+
+ getIndexCaption : function(index)
+ {
+ return index > -1 ? this.radios[index].value : this.options.caption;
+ },
+
+ showCaption : function(value)
+ {
+ $('#'+this.options.CaptionID).html(value);
+ $('#'+this.options.ID).attr( "title", value);
+ },
+
+ setCaption : function(value)
+ {
+ this.options.caption = value;
+ this.showCaption(value);
+ },
+
+ setReadOnly : function(value)
+ {
+ this.readOnly = value;
+ for(var i = 0; i<this.radios.length; i++)
+ {
+ var node = this.radios[i].parentNode.parentNode;
+ if(value)
+ {
+ $(node).addClass('rating_disabled');
+ $(node).off('mouseover', jQuery.proxy(this.hover, this, i));
+ $(node).off('mouseout', jQuery.proxy(this.recover, this, i));
+ $(node).off('click', jQuery.proxy(this.click, this, i));
+ } else {
+ $(node).removeClass('rating_disabled');
+ $(node).on('mouseover', jQuery.proxy(this.hover, this, i));
+ $(node).on('mouseout', jQuery.proxy(this.recover, this, i));
+ $(node).on('click', jQuery.proxy(this.click, this, i));
+ }
+ }
+
+ this.showRating(this.rating);
+ }
+});
+
+Prado.WebUI.TActiveRatingList = jQuery.klass(Prado.WebUI.TRatingList,
+{
+ dispatchRequest : function(ev)
+ {
+ var requestOptions =jQuery.extend({}, this.options,
+ {
+ ID : this.options.ID+"_c"+this.selectedIndex,
+ EventTarget : this.options.ListName+"$c"+this.selectedIndex
+ });
+ var request = new Prado.CallbackRequest(requestOptions.EventTarget, requestOptions);
+ if(request.dispatch()==false)
+ ev.preventDefault();
+ }
+
+});
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/ratings/stars1.png b/lib/prado/framework/Web/Javascripts/source/prado/ratings/stars1.png
new file mode 100644
index 0000000..e4dd3c2
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/ratings/stars1.png
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/scriptaculous-adapter.js b/lib/prado/framework/Web/Javascripts/source/prado/scriptaculous-adapter.js
new file mode 100644
index 0000000..1b9b290
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/scriptaculous-adapter.js
@@ -0,0 +1,1399 @@
+/**
+ * Utilities and extions to Prototype/Scriptaculous
+ * @file scriptaculous-adapter.js
+ */
+
+/**
+ * Extension to
+ * <a href="http://www.prototypejs.org/api/function" target="_blank">Prototype's Function</a>
+ * @namespace Function
+ */
+/**
+ * Similar to bindAsEventLister, but takes additional arguments.
+ * @function Function.bindEvent
+ */
+Function.prototype.bindEvent = function()
+{
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function(event)
+ {
+ return __method.apply(object, [event || window.event].concat(args));
+ }
+};
+
+/**
+ * Extension to
+ * <a href="http://www.prototypejs.org/api/class" target="_blank">Prototype's Class</a>
+ * @namespace Class
+ */
+
+/**
+ * Creates a new class by copying class definition from
+ * the <tt>base</tt> and optional <tt>definition</tt>.
+ * @function {Class} Class.extend
+ * @param {function} base - Base class to copy from.
+ * @param {optional Array} - Additional definition
+ * @returns Constructor for the extended class
+ */
+Class.extend = function(base, definition)
+{
+ var component = Class.create();
+ Object.extend(component.prototype, base.prototype);
+ if(definition)
+ Object.extend(component.prototype, definition);
+ return component;
+};
+
+/**
+ * Base, version 1.0.2
+ * Copyright 2006, Dean Edwards
+ * License: http://creativecommons.org/licenses/LGPL/2.1/
+ * @class Base
+ */
+var Base = function() {
+ if (arguments.length) {
+ if (this == window) { // cast an object to this class
+ Base.prototype.extend.call(arguments[0], arguments.callee.prototype);
+ } else {
+ this.extend(arguments[0]);
+ }
+ }
+};
+
+Base.version = "1.0.2";
+
+Base.prototype = {
+ extend: function(source, value) {
+ var extend = Base.prototype.extend;
+ if (arguments.length == 2) {
+ var ancestor = this[source];
+ // overriding?
+ if ((ancestor instanceof Function) && (value instanceof Function) &&
+ ancestor.valueOf() != value.valueOf() && /\bbase\b/.test(value)) {
+ var method = value;
+ // var _prototype = this.constructor.prototype;
+ // var fromPrototype = !Base._prototyping && _prototype[source] == ancestor;
+ value = function() {
+ var previous = this.base;
+ // this.base = fromPrototype ? _prototype[source] : ancestor;
+ this.base = ancestor;
+ var returnValue = method.apply(this, arguments);
+ this.base = previous;
+ return returnValue;
+ };
+ // point to the underlying method
+ value.valueOf = function() {
+ return method;
+ };
+ value.toString = function() {
+ return String(method);
+ };
+ }
+ return this[source] = value;
+ } else if (source) {
+ var _prototype = {toSource: null};
+ // do the "toString" and other methods manually
+ var _protected = ["toString", "valueOf"];
+ // if we are prototyping then include the constructor
+ if (Base._prototyping) _protected[2] = "constructor";
+ var name;
+ for (var i = 0; (name = _protected[i]); i++) {
+ if (source[name] != _prototype[name]) {
+ extend.call(this, name, source[name]);
+ }
+ }
+ // copy each of the source object's properties to this object
+ for (var name in source) {
+ if (!_prototype[name]) {
+ extend.call(this, name, source[name]);
+ }
+ }
+ }
+ return this;
+ },
+
+ base: function() {
+ // call this method from any other method to invoke that method's ancestor
+ }
+};
+
+Base.extend = function(_instance, _static) {
+ var extend = Base.prototype.extend;
+ if (!_instance) _instance = {};
+ // build the prototype
+ Base._prototyping = true;
+ var _prototype = new this;
+ extend.call(_prototype, _instance);
+ var constructor = _prototype.constructor;
+ _prototype.constructor = this;
+ delete Base._prototyping;
+ // create the wrapper for the constructor function
+ var klass = function() {
+ if (!Base._prototyping) constructor.apply(this, arguments);
+ this.constructor = klass;
+ };
+ klass.prototype = _prototype;
+ // build the class interface
+ klass.extend = this.extend;
+ klass.implement = this.implement;
+ klass.toString = function() {
+ return String(constructor);
+ };
+ extend.call(klass, _static);
+ // single instance
+ var object = constructor ? klass : _prototype;
+ // class initialisation
+ if (object.init instanceof Function) object.init();
+ return object;
+};
+
+Base.implement = function(_interface) {
+ if (_interface instanceof Function) _interface = _interface.prototype;
+ this.prototype.extend(_interface);
+};
+
+/**
+ * Performs a PostBack using javascript.
+ * @function Prado.PostBack
+ * @param event - Event that triggered this postback
+ * @param options - Postback options
+ * @... {string} FormID - Form that should be posted back
+ * @... {optional boolean} CausesValidation - Validate before PostBack if true
+ * @... {optional string} ValidationGroup - Group to Validate
+ * @... {optional string} ID - Validation ID
+ * @... {optional string} PostBackUrl - Postback URL
+ * @... {optional boolean} TrackFocus - Keep track of focused element if true
+ * @... {string} EventTarget - Id of element that triggered PostBack
+ * @... {string} EventParameter - EventParameter for PostBack
+ */
+Prado.PostBack = function(event,options)
+{
+ var form = $(options['FormID']);
+ var canSubmit = true;
+
+ if(options['CausesValidation'] && typeof(Prado.Validation) != "undefined")
+ {
+ if(!Prado.Validation.validate(options['FormID'], options['ValidationGroup'], $(options['ID'])))
+ return Event.stop(event);
+ }
+
+ if(options['PostBackUrl'] && options['PostBackUrl'].length > 0)
+ form.action = options['PostBackUrl'];
+
+ if(options['TrackFocus'])
+ {
+ var lastFocus = $('PRADO_LASTFOCUS');
+ if(lastFocus)
+ {
+ var active = document.activeElement; //where did this come from
+ if(active)
+ lastFocus.value = active.id;
+ else
+ lastFocus.value = options['EventTarget'];
+ }
+ }
+
+ $('PRADO_POSTBACK_TARGET').value = options['EventTarget'];
+ $('PRADO_POSTBACK_PARAMETER').value = options['EventParameter'];
+ /**
+ * Since google toolbar prevents browser default action,
+ * we will always disable default client-side browser action
+ */
+ /*if(options['StopEvent']) */
+ Event.stop(event);
+ Event.fireEvent(form,"submit");
+
+ $('PRADO_POSTBACK_TARGET').value = '';
+ $('PRADO_POSTBACK_PARAMETER').value = '';
+};
+
+/**
+ * Prado utilities to manipulate DOM elements.
+ * @object Prado.Element
+ */
+Prado.Element =
+{
+ /**
+ * Set the value of a particular element.
+ * @function ?
+ * @param {string} element - Element id
+ * @param {string} value - New element value
+ */
+ setValue : function(element, value)
+ {
+ var el = $(element);
+ if(el && typeof(el.value) != "undefined")
+ el.value = value;
+ },
+
+ /**
+ * Select options from a selectable element.
+ * @function ?
+ * @param {string} element - Element id
+ * @param {string} method - Name of any {@link Prado.Element.Selection} method
+ * @param {array|boolean|string} value - Values that should be selected
+ * @param {int} total - Number of elements
+ */
+ select : function(element, method, value, total)
+ {
+ var el = $(element);
+ if(!el) return;
+ var selection = Prado.Element.Selection;
+ if(typeof(selection[method]) == "function")
+ {
+ var control = selection.isSelectable(el) ? [el] : selection.getListElements(element,total);
+ selection[method](control, value);
+ }
+ },
+
+ /**
+ * Trigger a click event on a DOM element.
+ * @function ?
+ * @param {string} element - Element id
+ */
+ click : function(element)
+ {
+ var el = $(element);
+ if(el)
+ el.click();
+ },
+
+ /**
+ * Check if an DOM element is disabled.
+ * @function {boolean} ?
+ * @param {string} element - Element id
+ * @returns true if element is disabled
+ */
+ isDisabled : function(element)
+ {
+ if(!element.attributes['disabled']) //FF
+ return false;
+ var value = element.attributes['disabled'].nodeValue;
+ if(typeof(value)=="string")
+ return value.toLowerCase() == "disabled";
+ else
+ return value == true;
+ },
+
+ /**
+ * Sets an attribute of a DOM element.
+ * @function ?
+ * @param {string} element - Element id
+ * @param {string} attribute - Name of attribute
+ * @param {string} value - Value of attribute
+ */
+ setAttribute : function(element, attribute, value)
+ {
+ var el = $(element);
+ if(!el) return;
+ if((attribute == "disabled" || attribute == "multiple" || attribute == "readonly" || attribute == "href") && value==false)
+ el.removeAttribute(attribute);
+ else if(attribute.match(/^on/i)) //event methods
+ {
+ try
+ {
+ eval("(func = function(event){"+value+"})");
+ el[attribute] = func;
+ }
+ catch(e)
+ {
+ debugger;
+ throw "Error in evaluating '"+value+"' for attribute "+attribute+" for element "+element.id;
+ }
+ }
+ else
+ el.setAttribute(attribute, value);
+ },
+
+ /**
+ * Sets the options for a select element.
+ * @function ?
+ * @param {string} element - Element id
+ * @param {array[]} options - Array of options, each an array of structure
+ * [ "optionText" , "optionValue" , "optionGroup" ]
+ */
+ setOptions : function(element, options)
+ {
+ var el = $(element);
+ if(!el) return;
+ var previousGroup = null;
+ var optGroup=null;
+ if(el && el.tagName.toLowerCase() == "select")
+ {
+ while(el.childNodes.length > 0)
+ el.removeChild(el.lastChild);
+
+ var optDom = Prado.Element.createOptions(options);
+ for(var i = 0; i < optDom.length; i++)
+ el.appendChild(optDom[i]);
+ }
+ },
+
+ /**
+ * Create opt-group options from an array of options.
+ * @function {array} ?
+ * @param {array[]} options - Array of options, each an array of structure
+ * [ "optionText" , "optionValue" , "optionGroup" ]
+ * @returns Array of option DOM elements
+ */
+ createOptions : function(options)
+ {
+ var previousGroup = null;
+ var optgroup=null;
+ var result = [];
+ for(var i = 0; i<options.length; i++)
+ {
+ var option = options[i];
+ if(option.length > 2)
+ {
+ var group = option[2];
+ if(group!=previousGroup)
+ {
+ if(previousGroup!=null && optgroup!=null)
+ {
+ result.push(optgroup);
+ previousGroup=null;
+ optgroup=null;
+ }
+ optgroup = document.createElement('optgroup');
+ optgroup.label = group;
+ previousGroup = group;
+ }
+ }
+ var opt = document.createElement('option');
+ opt.text = option[0];
+ opt.innerHTML = option[0];
+ opt.value = option[1];
+ if(optgroup!=null)
+ optgroup.appendChild(opt);
+ else
+ result.push(opt);
+ }
+ if(optgroup!=null)
+ result.push(optgroup);
+ return result;
+ },
+
+ /**
+ * Set focus (delayed) on a particular element.
+ * @function ?
+ * @param {string} element - Element id
+ */
+ focus : function(element)
+ {
+ var obj = $(element);
+ if(typeof(obj) != "undefined" && typeof(obj.focus) != "undefined")
+ setTimeout(function(){ obj.focus(); }, 100);
+ return false;
+ },
+
+ /**
+ * Replace a DOM element either with given content or
+ * with content from a CallBack response boundary
+ * using a replacement method.
+ * @function ?
+ * @param {string|element} element - DOM element or element id
+ * @param {string} method - Name of method to use for replacement
+ * @param {optional string} content - New content of element
+ * @param {optional string} boundary - Boundary of new content
+ */
+ replace : function(element, method, content, boundary)
+ {
+ if(boundary)
+ {
+ var result = Prado.Element.extractContent(this.transport.responseText, boundary);
+ if(result != null)
+ content = result;
+ }
+ if(typeof(element) == "string")
+ {
+ if($(element))
+ method.toFunction().apply(this,[element,""+content]);
+ }
+ else
+ {
+ method.toFunction().apply(this,[""+content]);
+ }
+ },
+
+ /**
+ * Appends a javascript block to the document.
+ * @function ?
+ * @param {string} boundary - Boundary containing the javascript code
+ */
+ appendScriptBlock : function(boundary)
+ {
+ var content = Prado.Element.extractContent(this.transport.responseText, boundary);
+ if(content == null)
+ return;
+
+ var el = document.createElement("script");
+ el.type = "text/javascript";
+ el.id = 'inline_' + boundary;
+ el.text = content;
+
+ (document.getElementsByTagName('head')[0] || document.documentElement).appendChild(el);
+ el.parentNode.removeChild(el);
+ },
+
+ /**
+ * Extract content from a text by its boundary id.
+ * Boundaries have this form:
+ * <pre>
+ * &lt;!--123456--&gt;Democontent&lt;!--//123456--&gt;
+ * </pre>
+ * @function {string} ?
+ * @param {string} text - Text that contains boundaries
+ * @param {string} boundary - Boundary id
+ * @returns Content from given boundaries
+ */
+ extractContent : function(text, boundary)
+ {
+ var tagStart = '<!--'+boundary+'-->';
+ var tagEnd = '<!--//'+boundary+'-->';
+ var start = text.indexOf(tagStart);
+ if(start > -1)
+ {
+ start += tagStart.length;
+ var end = text.indexOf(tagEnd,start);
+ if(end > -1)
+ return text.substring(start,end);
+ }
+ return null;
+ /*var f = RegExp('(?:<!--'+boundary+'-->)((?:.|\n|\r)+?)(?:<!--//'+boundary+'-->)',"m");
+ var result = text.match(f);
+ if(result && result.length >= 2)
+ return result[1];
+ else
+ return null;*/
+ },
+
+ /**
+ * Evaluate a javascript snippet from a string.
+ * @function ?
+ * @param {string} content - String containing the script
+ */
+ evaluateScript : function(content)
+ {
+ try
+ {
+ content.evalScripts();
+ }
+ catch(e)
+ {
+ if(typeof(Logger) != "undefined")
+ Logger.error('Error during evaluation of script "'+content+'"');
+ else
+ debugger;
+ throw e;
+ }
+ },
+
+ /**
+ * Set CSS style with Camelized keys.
+ * See <a href="http://www.prototypejs.org/api/element/setstyle" target="_blank">Prototype's
+ * Element.setStyle</a> for details.
+ * @function ?
+ * @param {string|element} element - DOM element or element id
+ * @param {object} styles - Object with style properties/values
+ */
+ setStyle : function (element, styles)
+ {
+ var s = {}
+ // Camelize all styles keys
+ for (var property in styles)
+ {
+ s[property.camelize()]=styles[property].camelize();
+ }
+ Element.setStyle(element, s);
+ }
+};
+
+/**
+ * Utilities for selections.
+ * @object Prado.Element.Selection
+ */
+Prado.Element.Selection =
+{
+ /**
+ * Check if an DOM element can be selected.
+ * @function {boolean} ?
+ * @param {element} el - DOM elemet
+ * @returns true if element is selectable
+ */
+ isSelectable : function(el)
+ {
+ if(el && el.type)
+ {
+ switch(el.type.toLowerCase())
+ {
+ case 'checkbox':
+ case 'radio':
+ case 'select':
+ case 'select-multiple':
+ case 'select-one':
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /**
+ * Set checked attribute of a checkbox or radiobutton to value.
+ * @function {boolean} ?
+ * @param {element} el - DOM element
+ * @param {boolean} value - New value of checked attribute
+ * @returns New value of checked attribute
+ */
+ inputValue : function(el, value)
+ {
+ switch(el.type.toLowerCase())
+ {
+ case 'checkbox':
+ case 'radio':
+ return el.checked = value;
+ }
+ },
+
+ /**
+ * Set selected attribute for elements options by value.
+ * If value is boolean, all elements options selected attribute will be set
+ * to value. Otherwhise all options that have the given value will be selected.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ * @param {boolean|string} value - Value of options that should be selected or boolean value of selection status
+ */
+ selectValue : function(elements, value)
+ {
+ elements.each(function(el)
+ {
+ $A(el.options).each(function(option)
+ {
+ if(typeof(value) == "boolean")
+ option.selected = value;
+ else if(option.value == value)
+ option.selected = true;
+ });
+ })
+ },
+
+ /**
+ * Set selected attribute for elements options by array of values.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ * @param {string[]} value - Array of values to select
+ */
+ selectValues : function(elements, values)
+ {
+ var selection = this;
+ values.each(function(value)
+ {
+ selection.selectValue(elements,value);
+ })
+ },
+
+ /**
+ * Set selected attribute for elements options by option index.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ * @param {int} index - Index of option to select
+ */
+ selectIndex : function(elements, index)
+ {
+ elements.each(function(el)
+ {
+ if(el.type.toLowerCase() == 'select-one')
+ el.selectedIndex = index;
+ else
+ {
+ for(var i = 0; i<el.length; i++)
+ {
+ if(i == index)
+ el.options[i].selected = true;
+ }
+ }
+ })
+ },
+
+ /**
+ * Set selected attribute to true for all elements options.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ */
+ selectAll : function(elements)
+ {
+ elements.each(function(el)
+ {
+ if(el.type.toLowerCase() != 'select-one')
+ {
+ $A(el.options).each(function(option)
+ {
+ option.selected = true;
+ })
+ }
+ })
+ },
+
+ /**
+ * Toggle the selected attribute for elements options.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ */
+ selectInvert : function(elements)
+ {
+ elements.each(function(el)
+ {
+ if(el.type.toLowerCase() != 'select-one')
+ {
+ $A(el.options).each(function(option)
+ {
+ option.selected = !options.selected;
+ })
+ }
+ })
+ },
+
+ /**
+ * Set selected attribute for elements options by array of option indices.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ * @param {int[]} indices - Array of option indices to select
+ */
+ selectIndices : function(elements, indices)
+ {
+ var selection = this;
+ indices.each(function(index)
+ {
+ selection.selectIndex(elements,index);
+ })
+ },
+
+ /**
+ * Unselect elements.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ */
+ selectClear : function(elements)
+ {
+ elements.each(function(el)
+ {
+ el.selectedIndex = -1;
+ })
+ },
+
+ /**
+ * Get list elements of an element.
+ * @function {element[]} ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ * @param {int} total - Number of list elements to return
+ * @returns Array of list DOM elements
+ */
+ getListElements : function(element, total)
+ {
+ var elements = new Array();
+ var el;
+ for(var i = 0; i < total; i++)
+ {
+ el = $(element+"_c"+i);
+ if(el)
+ elements.push(el);
+ }
+ return elements;
+ },
+
+ /**
+ * Set checked attribute of elements by value.
+ * If value is boolean, checked attribute will be set to value.
+ * Otherwhise all elements that have the given value will be checked.
+ * @function ?
+ * @param {element[]} elements - Array of checkable DOM elements
+ * @param {boolean|String} value - Value that should be checked or boolean value of checked status
+ *
+ */
+ checkValue : function(elements, value)
+ {
+ elements.each(function(el)
+ {
+ if(typeof(value) == "boolean")
+ el.checked = value;
+ else if(el.value == value)
+ el.checked = true;
+ });
+ },
+
+ /**
+ * Set checked attribute of elements by array of values.
+ * @function ?
+ * @param {element[]} elements - Array of checkable DOM elements
+ * @param {string[]} values - Values that should be checked
+ *
+ */
+ checkValues : function(elements, values)
+ {
+ var selection = this;
+ values.each(function(value)
+ {
+ selection.checkValue(elements, value);
+ })
+ },
+
+ /**
+ * Set checked attribute of elements by list index.
+ * @function ?
+ * @param {element[]} elements - Array of checkable DOM elements
+ * @param {int} index - Index of element to set checked
+ */
+ checkIndex : function(elements, index)
+ {
+ for(var i = 0; i<elements.length; i++)
+ {
+ if(i == index)
+ elements[i].checked = true;
+ }
+ },
+
+ /**
+ * Set checked attribute of elements by array of list indices.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ * @param {int[]} indices - Array of list indices to set checked
+ */
+ checkIndices : function(elements, indices)
+ {
+ var selection = this;
+ indices.each(function(index)
+ {
+ selection.checkIndex(elements, index);
+ })
+ },
+
+ /**
+ * Uncheck elements.
+ * @function ?
+ * @param {element[]} elements - Array of checkable DOM elements
+ */
+ checkClear : function(elements)
+ {
+ elements.each(function(el)
+ {
+ el.checked = false;
+ });
+ },
+
+ /**
+ * Set checked attribute of all elements to true.
+ * @function ?
+ * @param {element[]} elements - Array of checkable DOM elements
+ */
+ checkAll : function(elements)
+ {
+ elements.each(function(el)
+ {
+ el.checked = true;
+ })
+ },
+
+ /**
+ * Toggle the checked attribute of elements.
+ * @function ?
+ * @param {element[]} elements - Array of selectable DOM elements
+ */
+ checkInvert : function(elements)
+ {
+ elements.each(function(el)
+ {
+ el.checked != el.checked;
+ })
+ }
+};
+
+
+/**
+ * Utilities for insertion.
+ * @object Prado.Element.Insert
+ */
+Prado.Element.Insert =
+{
+ /**
+ * Append content to element
+ * @function ?
+ * @param {element} element - DOM element that content should be appended to
+ * @param {element} content - DOM element to append
+ */
+ append: function(element, content)
+ {
+ $(element).insert(content);
+ },
+
+ /**
+ * Prepend content to element
+ * @function ?
+ * @param {element} element - DOM element that content should be prepended to
+ * @param {element} content - DOM element to prepend
+ */
+ prepend: function(element, content)
+ {
+ $(element).insert({top:content});
+ },
+
+ /**
+ * Insert content after element
+ * @function ?
+ * @param {element} element - DOM element that content should be inserted after
+ * @param {element} content - DOM element to insert
+ */
+ after: function(element, content)
+ {
+ $(element).insert({after:content});
+ },
+
+ /**
+ * Insert content before element
+ * @function ?
+ * @param {element} element - DOM element that content should be inserted before
+ * @param {element} content - DOM element to insert
+ */
+ before: function(element, content)
+ {
+ $(element).insert({before:content});
+ }
+};
+
+
+/**
+ * Extension to
+ * <a href="http://wiki.script.aculo.us/scriptaculous/show/builder" target="_blank">Scriptaculous' Builder</a>
+ * @namespace Builder
+ */
+
+Object.extend(Builder,
+{
+ /**
+ * Export scriptaculous builder utilities as window[functions]
+ * @function ?
+ */
+ exportTags:function()
+ {
+ var tags=["BUTTON","TT","PRE","H1","H2","H3","BR","CANVAS","HR","LABEL","TEXTAREA","FORM","STRONG","SELECT","OPTION","OPTGROUP","LEGEND","FIELDSET","P","UL","OL","LI","TD","TR","THEAD","TBODY","TFOOT","TABLE","TH","INPUT","SPAN","A","DIV","IMG", "CAPTION"];
+ tags.each(function(tag)
+ {
+ window[tag]=function()
+ {
+ var args=$A(arguments);
+ if(args.length==0)
+ return Builder.node(tag,null);
+ if(args.length==1)
+ return Builder.node(tag,args[0]);
+ if(args.length>1)
+ return Builder.node(tag,args.shift(),args);
+
+ };
+ });
+ }
+});
+Builder.exportTags();
+
+/**
+ * Extension to
+ * <a href="http://www.prototypejs.org/api/string" target="_blank">Prototype's String</a>
+ * @namespace String
+ */
+Object.extend(String.prototype, {
+
+ /**
+ * Add padding to string
+ * @function {string} ?
+ * @param {string} side - "left" to pad the string on the left, "right" to pad right.
+ * @param {int} len - Minimum string length.
+ * @param {string} chr - Character(s) to pad
+ * @returns Padded string
+ */
+ pad : function(side, len, chr) {
+ if (!chr) chr = ' ';
+ var s = this;
+ var left = side.toLowerCase()=='left';
+ while (s.length<len) s = left? chr + s : s + chr;
+ return s;
+ },
+
+ /**
+ * Add left padding to string
+ * @function {string} ?
+ * @param {int} len - Minimum string length.
+ * @param {string} chr - Character(s) to pad
+ * @returns Padded string
+ */
+ padLeft : function(len, chr) {
+ return this.pad('left',len,chr);
+ },
+
+ /**
+ * Add right padding to string
+ * @function {string} ?
+ * @param {int} len - Minimum string length.
+ * @param {string} chr - Character(s) to pad
+ * @returns Padded string
+ */
+ padRight : function(len, chr) {
+ return this.pad('right',len,chr);
+ },
+
+ /**
+ * Add zeros to the right of string
+ * @function {string} ?
+ * @param {int} len - Minimum string length.
+ * @returns Padded string
+ */
+ zerofill : function(len) {
+ return this.padLeft(len,'0');
+ },
+
+ /**
+ * Remove white spaces from both ends of string.
+ * @function {string} ?
+ * @returns Trimmed string
+ */
+ trim : function() {
+ return this.replace(/^\s+|\s+$/g,'');
+ },
+
+ /**
+ * Remove white spaces from the left side of string.
+ * @function {string} ?
+ * @returns Trimmed string
+ */
+ trimLeft : function() {
+ return this.replace(/^\s+/,'');
+ },
+
+ /**
+ * Remove white spaces from the right side of string.
+ * @function {string} ?
+ * @returns Trimmed string
+ */
+ trimRight : function() {
+ return this.replace(/\s+$/,'');
+ },
+
+ /**
+ * Convert period separated function names into a function reference.
+ * <br />Example:
+ * <pre>
+ * "Prado.AJAX.Callback.Action.setValue".toFunction()
+ * </pre>
+ * @function {function} ?
+ * @returns Reference to the corresponding function
+ */
+ toFunction : function()
+ {
+ var commands = this.split(/\./);
+ var command = window;
+ commands.each(function(action)
+ {
+ if(command[new String(action)])
+ command=command[new String(action)];
+ });
+ if(typeof(command) == "function")
+ return command;
+ else
+ {
+ if(typeof Logger != "undefined")
+ Logger.error("Missing function", this);
+
+ throw new Error ("Missing function '"+this+"'");
+ }
+ },
+
+ /**
+ * Convert string into integer, returns null if not integer.
+ * @function {int} ?
+ * @returns Integer, null if string does not represent an integer.
+ */
+ toInteger : function()
+ {
+ var exp = /^\s*[-\+]?\d+\s*$/;
+ if (this.match(exp) == null)
+ return null;
+ var num = parseInt(this, 10);
+ return (isNaN(num) ? null : num);
+ },
+
+ /**
+ * Convert string into a double/float value. <b>Internationalization
+ * is not supported</b>
+ * @function {double} ?
+ * @param {string} decimalchar - Decimal character, defaults to "."
+ * @returns Double, null if string does not represent a float value
+ */
+ toDouble : function(decimalchar)
+ {
+ if(this.length <= 0) return null;
+ decimalchar = decimalchar || ".";
+ var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$");
+ var m = this.match(exp);
+
+ if (m == null)
+ return null;
+ m[1] = m[1] || "";
+ m[2] = m[2] || "0";
+ m[4] = m[4] || "0";
+
+ var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4];
+ var num = parseFloat(cleanInput);
+ return (isNaN(num) ? null : num);
+ },
+
+ /**
+ * Convert strings that represent a currency value to float.
+ * E.g. "10,000.50" will become "10000.50". The number
+ * of dicimal digits, grouping and decimal characters can be specified.
+ * <i>The currency input format is <b>very</b> strict, null will be returned if
+ * the pattern does not match</i>.
+ * @function {double} ?
+ * @param {string} groupchar - Grouping character, defaults to ","
+ * @param {int} digits - Number of decimal digits
+ * @param {string} decimalchar - Decimal character, defaults to "."
+ * @returns Double, null if string does not represent a currency value
+ */
+ toCurrency : function(groupchar, digits, decimalchar)
+ {
+ groupchar = groupchar || ",";
+ decimalchar = decimalchar || ".";
+ digits = typeof(digits) == "undefined" ? 2 : digits;
+
+ var exp = new RegExp("^\\s*([-\\+])?(((\\d+)\\" + groupchar + ")*)(\\d+)"
+ + ((digits > 0) ? "(\\" + decimalchar + "(\\d{1," + digits + "}))?" : "")
+ + "\\s*$");
+ var m = this.match(exp);
+ if (m == null)
+ return null;
+ var intermed = m[2] + m[5] ;
+ var cleanInput = m[1] + intermed.replace(
+ new RegExp("(\\" + groupchar + ")", "g"), "")
+ + ((digits > 0) ? "." + m[7] : "");
+ var num = parseFloat(cleanInput);
+ return (isNaN(num) ? null : num);
+ },
+
+ /**
+ * Converts the string to a date by finding values that matches the
+ * date format pattern.
+ * @function {Date} ?
+ * @param {string} format - Date format pattern, e.g. MM-dd-yyyy
+ * @returns Date extracted from the string
+ */
+ toDate : function(format)
+ {
+ return Date.SimpleParse(this, format);
+ }
+});
+
+/**
+ * Extension to
+ * <a href="http://www.prototypejs.org/api/event" target="_blank">Prototype's Event</a>
+ * @namespace Event
+ */
+Object.extend(Event,
+{
+ /**
+ * Register a function to be executed when the page is loaded.
+ * Note that the page is only loaded if all resources (e.g. images)
+ * are loaded.
+ * <br />Example:
+ * <br />Show an alert box with message "Page Loaded!" when the
+ * page finished loading.
+ * <pre>
+ * Event.OnLoad(function(){ alert("Page Loaded!"); });
+ * </pre>
+ * @function ?
+ * @param {function} fn - Function to execute when page is loaded.
+ */
+ OnLoad : function (fn)
+ {
+ // opera onload is in document, not window
+ var w = document.addEventListener &&
+ !window.addEventListener ? document : window;
+ Event.observe(w,'load',fn);
+ },
+
+ /**
+ * Returns the unicode character generated by key.
+ * @param {event} e - Keyboard event
+ * @function {int} ?
+ * @returns Unicode character code generated by the key that was struck.
+ */
+ keyCode : function(e)
+ {
+ return e.keyCode != null ? e.keyCode : e.charCode
+ },
+
+ /**
+ * Checks if an Event is of type HTMLEvent.
+ * @function {boolean} ?
+ * @param {string} type - Event type or event name.
+ * @return true if event is of type HTMLEvent.
+ */
+ isHTMLEvent : function(type)
+ {
+ var events = ['abort', 'blur', 'change', 'error', 'focus',
+ 'load', 'reset', 'resize', 'scroll', 'select',
+ 'submit', 'unload'];
+ return events.include(type);
+ },
+
+ /**
+ * Checks if an Event is a mouse event.
+ * @function {boolean} ?
+ * @param {string} type - Event type or event name
+ * @return true if event is of type MouseEvent.
+ */
+ isMouseEvent : function(type)
+ {
+ var events = ['click', 'mousedown', 'mousemove', 'mouseout',
+ 'mouseover', 'mouseup'];
+ return events.include(type);
+ },
+
+ /**
+ * Dispatch the DOM event of a given <tt>type</tt> on a DOM
+ * <tt>element</tt>. Only HTMLEvent and MouseEvent can be
+ * dispatched, keyboard events or UIEvent can not be dispatch
+ * via javascript consistently.
+ * For the "submit" event the submit() method is called.
+ * @function ?
+ * @param {element|string} element - Element id string or DOM element.
+ * @param {string} type - Event type to dispatch.
+ */
+ fireEvent : function(element,type)
+ {
+ element = $(element);
+ if(type == "submit")
+ return element.submit();
+ if(document.createEvent)
+ {
+ if(Event.isHTMLEvent(type))
+ {
+ var event = document.createEvent('HTMLEvents');
+ event.initEvent(type, true, true);
+ }
+ else if(Event.isMouseEvent(type))
+ {
+ var event = document.createEvent('MouseEvents');
+ if (event.initMouseEvent)
+ {
+ event.initMouseEvent(type,true,true,
+ document.defaultView, 1, 0, 0, 0, 0, false,
+ false, false, false, 0, null);
+ }
+ else
+ {
+ // Safari
+ // TODO we should be initialising other mouse-event related attributes here
+ event.initEvent(type, true, true);
+ }
+ }
+ element.dispatchEvent(event);
+ }
+ else if(document.createEventObject)
+ {
+ var evObj = document.createEventObject();
+ element.fireEvent('on'+type, evObj);
+ }
+ else if(typeof(element['on'+type]) == "function")
+ element['on'+type]();
+ }
+});
+
+
+/**
+ * Extension to
+ * <a href="http://www.prototypejs.org/api/date" target="_blank">Prototype's Date</a>
+ * @namespace Date
+ */
+Object.extend(Date.prototype,
+{
+ /**
+ * SimpleFormat
+ * @function ?
+ * @param {string} format - TODO
+ * @param {string} data - TODO
+ * @returns TODO
+ */
+ SimpleFormat: function(format, data)
+ {
+ data = data || {};
+ var bits = new Array();
+ bits['d'] = this.getDate();
+ bits['dd'] = String(this.getDate()).zerofill(2);
+
+ bits['M'] = this.getMonth()+1;
+ bits['MM'] = String(this.getMonth()+1).zerofill(2);
+ if(data.AbbreviatedMonthNames)
+ bits['MMM'] = data.AbbreviatedMonthNames[this.getMonth()];
+ if(data.MonthNames)
+ bits['MMMM'] = data.MonthNames[this.getMonth()];
+ var yearStr = "" + this.getFullYear();
+ yearStr = (yearStr.length == 2) ? '19' + yearStr: yearStr;
+ bits['yyyy'] = yearStr;
+ bits['yy'] = bits['yyyy'].toString().substr(2,2);
+
+ // do some funky regexs to replace the format string
+ // with the real values
+ var frm = new String(format);
+ for (var sect in bits)
+ {
+ var reg = new RegExp("\\b"+sect+"\\b" ,"g");
+ frm = frm.replace(reg, bits[sect]);
+ }
+ return frm;
+ },
+
+ /**
+ * toISODate
+ * @function {string} ?
+ * @returns TODO
+ */
+ toISODate : function()
+ {
+ var y = this.getFullYear();
+ var m = String(this.getMonth() + 1).zerofill(2);
+ var d = String(this.getDate()).zerofill(2);
+ return String(y) + String(m) + String(d);
+ }
+});
+
+Object.extend(Date,
+{
+ /**
+ * SimpleParse
+ * @function ?
+ * @param {string} format - TODO
+ * @param {string} data - TODO
+ * @returns TODO
+ */
+ SimpleParse: function(value, format)
+ {
+ var val=String(value);
+ format=String(format);
+
+ if(val.length <= 0) return null;
+
+ if(format.length <= 0) return new Date(value);
+
+ var isInteger = function (val)
+ {
+ var digits="1234567890";
+ for (var i=0; i < val.length; i++)
+ {
+ if (digits.indexOf(val.charAt(i))==-1) { return false; }
+ }
+ return true;
+ };
+
+ var getInt = function(str,i,minlength,maxlength)
+ {
+ for (var x=maxlength; x>=minlength; x--)
+ {
+ var token=str.substring(i,i+x);
+ if (token.length < minlength) { return null; }
+ if (isInteger(token)) { return token; }
+ }
+ return null;
+ };
+
+ var i_val=0;
+ var i_format=0;
+ var c="";
+ var token="";
+ var token2="";
+ var x,y;
+ var now=new Date();
+ var year=now.getFullYear();
+ var month=now.getMonth()+1;
+ var date=1;
+
+ while (i_format < format.length)
+ {
+ // Get next token from format string
+ c=format.charAt(i_format);
+ token="";
+ while ((format.charAt(i_format)==c) && (i_format < format.length))
+ {
+ token += format.charAt(i_format++);
+ }
+
+ // Extract contents of value based on format token
+ if (token=="yyyy" || token=="yy" || token=="y")
+ {
+ if (token=="yyyy") { x=4;y=4; }
+ if (token=="yy") { x=2;y=2; }
+ if (token=="y") { x=2;y=4; }
+ year=getInt(val,i_val,x,y);
+ if (year==null) { return null; }
+ i_val += year.length;
+ if (year.length==2)
+ {
+ if (year > 70) { year=1900+(year-0); }
+ else { year=2000+(year-0); }
+ }
+ }
+
+ else if (token=="MM"||token=="M")
+ {
+ month=getInt(val,i_val,token.length,2);
+ if(month==null||(month<1)||(month>12)){return null;}
+ i_val+=month.length;
+ }
+ else if (token=="dd"||token=="d")
+ {
+ date=getInt(val,i_val,token.length,2);
+ if(date==null||(date<1)||(date>31)){return null;}
+ i_val+=date.length;
+ }
+ else
+ {
+ if (val.substring(i_val,i_val+token.length)!=token) {return null;}
+ else {i_val+=token.length;}
+ }
+ }
+
+ // If there are any trailing characters left in the value, it doesn't match
+ if (i_val != val.length) { return null; }
+
+ // Is date valid for month?
+ if (month==2)
+ {
+ // Check for leap year
+ if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
+ if (date > 29){ return null; }
+ }
+ else { if (date > 28) { return null; } }
+ }
+
+ if ((month==4)||(month==6)||(month==9)||(month==11))
+ {
+ if (date > 30) { return null; }
+ }
+
+ var newdate=new Date(year,month-1,date, 0, 0, 0);
+ return newdate;
+ }
+});
+
+/**
+ * Prado utilities for effects.
+ * @object Prado.Effect
+ */
+Prado.Effect =
+{
+ /**
+ * Highlights an element
+ * @function ?
+ * @param {element} element - DOM element to highlight
+ * @param {optional object} options - Highlight options
+ */
+ Highlight : function (element,options)
+ {
+ new Effect.Highlight(element,options);
+ }
+};
diff --git a/lib/prado/framework/Web/Javascripts/source/prado/validator/validation3.js b/lib/prado/framework/Web/Javascripts/source/prado/validator/validation3.js
new file mode 100644
index 0000000..98be95d
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prado/validator/validation3.js
@@ -0,0 +1,1996 @@
+/**
+ * Prado client-side javascript validation fascade.
+ *
+ * <p>There are 4 basic classes: {@link Prado.Validation},
+ * {@link Prado.ValidationManager}, {@link Prado.WebUI.TValidationSummary}
+ * and {@link Prado.WebUI.TBaseValidator},
+ * that interact together to perform validation.
+ * The {@link Prado.Validation} class co-ordinates together the
+ * validation scheme and is responsible for maintaining references
+ * to ValidationManagers.</p>
+ *
+ * <p>The {@link Prado.ValidationManager} class is responsible for
+ * maintaining refereneces
+ * to individual validators, validation summaries and their associated
+ * groupings.</p>
+ *
+ * <p>The {@link Prado.WebUI.TValidationSummary} takes care of displaying
+ * the validator error messages
+ * as html output or an alert output.</p>
+ *
+ * <p>The {@link Prado.WebUI.TBaseValidator} is the base class for all
+ * validators and contains
+ * methods to interact with the actual inputs, data type conversion.</p>
+ *
+ * <p>An instance of {@link Prado.ValidationManager} must be instantiated first for a
+ * particular form before instantiating validators and summaries.</p>
+ *
+ * <p>Usage example: adding a required field to a text box input with
+ * ID "input1" in a form with ID "form1".</p>
+ * <pre>
+ * &lt;script type="text/javascript" src="../prado.js"&gt;&lt;/script&gt;
+ * &lt;script type="text/javascript" src="../validator.js"&gt;&lt;/script&gt;
+ * &lt;form id="form1" action="..."&gt;
+ * &lt;div&gt;
+ * &lt;input type="text" id="input1" /&gt;
+ * &lt;span id="validator1" style="display:none; color:red"&gt;*&lt;/span&gt;
+ * &lt;input type="submit text="submit" /&gt;
+ * &lt;script type="text/javascript"&gt;
+ * new Prado.ValidationManager({FormID : 'form1'});
+ * var options =
+ * {
+ * ID : 'validator1',
+ * FormID : 'form1',
+ * ErrorMessage : '*',
+ * ControlToValidate : 'input1'
+ * }
+ * new Prado.WebUI.TRequiredFieldValidator(options);
+ * new Prado.WebUI.TValidationSummary({ID:'summary1',FormID:'form1'});
+ *
+ * //watch the form onsubmit event, check validators, stop if not valid.
+ * Event.observe("form1", "submit" function(ev)
+ * {
+ * if(Prado.WebUI.Validation.isValid("form1") == false)
+ * Event.stop(ev);
+ * });
+ * &lt;/script&gt;
+ * &lt;/div&gt;
+ * &lt;/form&gt;
+ * </pre>
+ *
+ * @module validation
+ */
+
+Prado.Validation = jQuery.klass();
+
+/**
+ * Global Validation Object.
+ *
+ * <p>To validate the inputs of a particular form, call
+ * <code>{@link Prado.Validation.validate}(formID, groupID)</code>
+ * where <tt>formID</tt> is the HTML form ID, and the optional
+ * <tt>groupID</tt> if present will only validate the validators
+ * in a particular group.</p>
+ * <p>Use <code>{@link Prado.Validation.validateControl}(controlClientID)</code>
+ * to trigger validation for a single control.</p>
+ *
+ * @object {static} Prado.Validation
+ */
+jQuery.extend(Prado.Validation,
+{
+ /**
+ * Hash of registered validation managers
+ * @var managers
+ */
+ managers : {},
+
+ /**
+ * Validate the validators (those that <strong>DO NOT</strong>
+ * belong to a particular group) in the form specified by the
+ * <tt>formID</tt> parameter. If <tt>groupID</tt> is specified
+ * only validators belonging to that group will be validated.
+ * @function {boolean} ?
+ * @param {string} formID - ID of the form to validate
+ * @param {string} groupID - ID of the ValidationGroup to validate.
+ * @param {element} invoker - DOM element that calls for validation
+ * @returns true if validation succeeded
+ */
+ validate : function(formID, groupID, invoker)
+ {
+ formID = formID || this.getForm();
+ if(this.managers[formID])
+ {
+ return this.managers[formID].validate(groupID, invoker);
+ }
+ else
+ {
+ throw new Error("Form '"+formID+"' is not registered with Prado.Validation");
+ }
+ },
+
+ /**
+ * Validate all validators of a specific control.
+ * @function {boolean} ?
+ * @param {string} id - ID of DOM element to validate
+ * @return true if all validators are valid or no validators present, false otherwise.
+ */
+ validateControl : function(id)
+ {
+ var formId=this.getForm();
+
+ if (this.managers[formId])
+ {
+ return this.managers[formId].validateControl(id);
+ } else {
+ throw new Error("A validation manager needs to be created first.");
+ }
+ },
+
+ /**
+ * Return first registered form
+ * @function {string} ?
+ * @returns ID of first form.
+ */
+ getForm : function()
+ {
+ var keys = jQuery.map(this.managers, function(value, key) {
+ return key;
+ });
+ return keys.length>0 ? keys[0] : null;
+ },
+
+ /**
+ * Check if the validators are valid for a particular form (and group).
+ * The validators states will not be changed.
+ * The <tt>validate</tt> function should be called first.
+ * @function {boolean} ?
+ * @param {string} formID - ID of the form to validate
+ * @param {string} groupID - ID of the ValiationGroup to validate.
+ * @return true if form is valid
+ */
+ isValid : function(formID, groupID)
+ {
+ formID = formID || this.getForm();
+ if(this.managers[formID])
+ return this.managers[formID].isValid(groupID);
+ return true;
+ },
+
+ /**
+ * Reset the validators for a given group.
+ * The group is searched in the first registered form.
+ * @function ?
+ * @param {string} groupID - ID of the ValidationGroup to reset.
+ */
+ reset : function(groupID)
+ {
+ var formID = this.getForm();
+ if(this.managers[formID])
+ this.managers[formID].reset(groupID);
+ },
+
+ /**
+ * Add a new validator to a particular form.
+ * @function {ValidationManager} ?
+ * @param {string} formID - ID of the form that the validator belongs to.
+ * @param {TBaseValidator} validator - Validator object
+ * @return ValidationManager for the form
+ */
+ addValidator : function(formID, validator)
+ {
+ if(this.managers[formID])
+ this.managers[formID].addValidator(validator);
+ else
+ throw new Error("A validation manager for form '"+formID+"' needs to be created first.");
+ return this.managers[formID];
+ },
+
+ /**
+ * Add a new validation summary.
+ * @function {ValidationManager} ?
+ * @param {string} formID - ID of the form that the validation summary belongs to.
+ * @param {TValidationSummary} validator - TValidationSummary object
+ * @return ValidationManager for the form
+ */
+ addSummary : function(formID, validator)
+ {
+ if(this.managers[formID])
+ this.managers[formID].addSummary(validator);
+ else
+ throw new Error("A validation manager for form '"+formID+"' needs to be created first.");
+ return this.managers[formID];
+ },
+
+ setErrorMessage : function(validatorID, message)
+ {
+ jQuery.each(Prado.Validation.managers, function(idx, manager)
+ {
+ jQuery.each(manager.validators, function(idx, validator)
+ {
+ if(validator.options.ID == validatorID)
+ {
+ validator.options.ErrorMessage = message;
+ jQuery("#" + validatorID).get(0).innerHTML = message;
+ }
+ });
+ });
+ },
+
+ updateActiveCustomValidator : function(validatorID, isValid)
+ {
+ jQuery.each(Prado.Validation.managers, function(idx, manager)
+ {
+ jQuery.each(manager.validators, function(idx, validator)
+ {
+ if(validator.options.ID == validatorID)
+ {
+ validator.updateIsValid(isValid);
+ }
+ });
+ });
+ }
+});
+
+/**
+ * Manages validators for a particular HTML form.
+ *
+ * <p>The manager contains references to all the validators
+ * summaries, and their groupings for a particular form.
+ * Generally, {@link Prado.Validation} methods should be called rather
+ * than calling directly the ValidationManager.</p>
+ *
+ * @class Prado.ValidationManager
+ */
+Prado.ValidationManager = jQuery.klass();
+Prado.ValidationManager.prototype =
+{
+ /**
+ * Hash of registered validators by control's clientID
+ * @var controls
+ */
+ controls: {},
+
+ /**
+ * Initialize ValidationManager.
+ * @constructor {protected} ?
+ * @param {object} options - Options for initialization
+ * @... {string} FormID - ID of form of this manager
+ */
+ initialize : function(options)
+ {
+ if(!Prado.Validation.managers[options.FormID])
+ {
+ /**
+ * List of validators
+ * @var {TBaseValidator[]} validators
+ */
+ this.validators = [];
+ /**
+ * List of validation summaries
+ * @var {TValidationSummary[]} summaries
+ */
+ this.summaries = [];
+ /**
+ * List of ValidationGroups
+ * @var {string[]} groups
+ */
+ this.groups = [];
+ /**
+ * Options of this ValidationManager
+ * @var {object} options
+ */
+ this.options = {};
+
+ this.options = options;
+
+ Prado.Validation.managers[options.FormID] = this;
+ }
+ else
+ {
+ var manager = Prado.Validation.managers[options.FormID];
+ this.validators = manager.validators;
+ this.summaries = manager.summaries;
+ this.groups = manager.groups;
+ this.options = manager.options;
+ }
+ },
+
+ /**
+ * Reset all validators in the given group.
+ * If group is null, validators without a group are used.
+ * @function ?
+ * @param {string} group - ID of ValidationGroup
+ */
+ reset : function(group)
+ {
+ var vals = this.validatorPartition(group)[0];
+ for(var i = 0; i < vals.length; i++)
+ vals[i].reset();
+
+ this.updateSummary(group, true);
+ },
+
+ /**
+ * Validate the validators managed by this validation manager.
+ * If group is set, only validate validators in that group.
+ * @function {boolean} ?
+ * @param {optional string} group - ID of ValidationGroup
+ * @param {element} source - DOM element that calls for validation
+ * @return true if all validators are valid, false otherwise.
+ */
+ validate : function(group, source)
+ {
+ var partition = this.validatorPartition(group);
+ var valid=true;
+ for(var i = 0; i < partition[0].length; i++)
+ {
+ if(!partition[0][i].validate(source))
+ valid=false;
+ }
+ this.focusOnError(partition[0]);
+ jQuery(partition[1]).hide();
+ this.updateSummary(group, true);
+ return valid;
+ },
+
+ /**
+ * Perform validation for all validators of a single control.
+ * @function {boolean} ?
+ * @param {string} id - ID of DOM element to validate
+ * @return true if all validators are valid or no validators present, false otherwise.
+ */
+ validateControl : function (id)
+ {
+ var valid = true;
+ if(this.controls[id])
+ {
+ jQuery.each(this.controls[id], function (idx, element) {
+ if(!element.validate(null))
+ valid = false;
+ });
+ }
+
+ return valid;
+ },
+
+ /**
+ * Focus on the first validator that is invalid and options.FocusOnError is true.
+ * @function ?
+ * @param {TBaseValidator[]} validators - Array of validator objects
+ */
+ focusOnError : function(validators)
+ {
+ for(var i = 0; i < validators.length; i++)
+ {
+ if(!validators[i].isValid && validators[i].options.FocusOnError)
+ return Prado.Element.focus(validators[i].options.FocusElementID);
+ }
+ },
+
+ /**
+ * Get all validators in a group and all other validators.
+ * Returns an array with two arrays of validators. The first
+ * array contains all validators in the group if group is given,
+ * otherwhise all validators without a group. The second array
+ * contains all other validators.
+ * @function {[ TBaseValidator[] , TBaseValidator[] ]} ?
+ * @param {optional string} group - ID of ValidationGroup
+ * @return Array with two arrays of validators.
+ */
+ validatorPartition : function(group)
+ {
+ return group ? this.validatorsInGroup(group) : this.validatorsWithoutGroup();
+ },
+
+ /**
+ * Get all validators in a group.
+ * Returns an array with two arrays of validators. The first
+ * array contains all validators in the group. The second array
+ * contains all other validators.
+ * @function {[ TBaseValidator[] , TBaseValidator[] ]} ?
+ * @param {optional string} groupID - ID of ValidationGroup
+ * @return Array with two arrays of validators.
+ */
+ validatorsInGroup : function(groupID)
+ {
+ if(jQuery.inArray(groupID, this.groups)!=-1)
+ {
+ var trues = [], falses = [];
+ jQuery.each(this.validators, function(idx, val) {
+ if(val.group == groupID)
+ trues.push(val);
+ else
+ falses.push(val);
+ });
+ return [trues, falses];
+ }
+ else
+ return [[],[]];
+ },
+
+ /**
+ * Get all validators without a group.
+ * Returns an array with two arrays of validators. The first
+ * array contains all validators without a group. The second
+ * array contains all other validators.
+ * @function {[ TBaseValidator[] , TBaseValidator[] ]} ?
+ * @return Array with two arrays of validators: Array[0] has all
+ * validators without a group, Array[1] all other validators.
+ */
+ validatorsWithoutGroup : function()
+ {
+ var trues = [], falses = [];
+ jQuery.each(this.validators, function(idx, val) {
+ if(!val.group)
+ trues.push(val);
+ else
+ falses.push(val);
+ });
+ return [trues, falses];
+ },
+
+ /**
+ * Get the state of validators.
+ * If group is set, only validators in that group are checked.
+ * Otherwhise only validators without a group are checked.
+ * @function {booelan} ?
+ * @param {optional string} group - ID of ValidationGroup
+ * @return true if all validators (in a group, if supplied) are valid.
+ */
+ isValid : function(group)
+ {
+ for(var i = 0; i < this.validatorPartition(group)[0].length; i++)
+ {
+ if(!this.validatorPartition(group)[0][i].isValid)
+ return false;
+ }
+
+ return true;
+ },
+
+ /**
+ * Add a validator to this manager.
+ * @function ?
+ * @param {TBaseValidator} validator - Validator object
+ */
+ addValidator : function(validator)
+ {
+ // Remove previously registered validator with same ID
+ // to prevent stale validators created by AJAX updates
+ this.removeValidator(validator);
+
+ this.validators.push(validator);
+ if(validator.group && jQuery.inArray(validator.group, this.groups)==-1)
+ this.groups.push(validator.group);
+
+ if(typeof this.controls[validator.control.id] === 'undefined')
+ this.controls[validator.control.id] = Array();
+ this.controls[validator.control.id].push(validator);
+ },
+
+ /**
+ * Add a validation summary.
+ * @function ?
+ * @param {TValidationSummary} summary - Validation summary.
+ */
+ addSummary : function(summary)
+ {
+ this.summaries.push(summary);
+ },
+
+ /**
+ * Remove a validator from this manager
+ * @function ?
+ * @param {TBaseValidator} validator - Validator object
+ */
+ removeValidator : function(validator)
+ {
+ // Remove from list of validators
+ this.validators = jQuery.grep(this.validators, function(v)
+ {
+ return (v.options.ID!=validator.options.ID);
+ });
+ // Remove from global list of validators per control
+ if (this.controls[validator.control.id])
+ {
+ this.controls[validator.control.id] = jQuery.grep(this.controls[validator.control.id], function(v)
+ {
+ return (v.options.ID!=validator.options.ID)
+ });
+ // Delete array if empty
+ if(this.controls[validator.control.id].length == 0)
+ delete this.controls[validator.control.id];
+ }
+ },
+
+ /**
+ * Gets validators with errors.
+ * If group is set, only validators in that group are returned.
+ * Otherwhise only validators without a group are returned.
+ * @function {TBaseValidator[]} ?
+ * @param {optional string} group - ID of ValidationGroup
+ * @return array list of validators with error.
+ */
+ getValidatorsWithError : function(group)
+ {
+ return jQuery.grep(this.validatorPartition(group)[0], function(validator)
+ {
+ return !validator.isValid;
+ });
+ },
+
+ /**
+ * Update the summary of a particular group.
+ * If group is set, only the summary for validators in that
+ * group is updated. Otherwhise only the summary for validators
+ * without a group is updated.
+ * @function ?
+ * @param {optional string} group - ID of ValidationGroup
+ * @param {boolean} refresh - Wether the summary should be refreshed
+ */
+ updateSummary : function(group, refresh)
+ {
+ var validators = this.getValidatorsWithError(group);
+ jQuery.each(this.summaries, function(idx, summary)
+ {
+ var inGroup = group && summary.group == group;
+ var noGroup = !group || !summary.group;
+ if(inGroup || noGroup)
+ summary.updateSummary(validators, refresh);
+ else
+ summary.hideSummary(true);
+ });
+ }
+};
+
+/**
+ * TValidationSummary displays a summary of validation errors.
+ *
+ * <p>The summary is displayed inline on a Web page,
+ * in a message box, or both. By default, a validation summary will collect
+ * <tt>ErrorMessage</tt> of all failed validators on the page. If
+ * <tt>ValidationGroup</tt> is not empty, only those validators who belong
+ * to the group will show their error messages in the summary.</p>
+ *
+ * <p>The summary can be displayed as a list, as a bulleted list, or as a single
+ * paragraph based on the <tt>DisplayMode</tt> option.
+ * The messages shown can be prefixed with <tt>HeaderText</tt>.</p>
+ *
+ * <p>The summary can be displayed on the Web page and in a message box by setting
+ * the <tt>ShowSummary</tt> and <tt>ShowMessageBox</tt>
+ * options, respectively.</p>
+ *
+ * @class Prado.WebUI.TValidationSummary
+ */
+Prado.WebUI.TValidationSummary = jQuery.klass();
+Prado.WebUI.TValidationSummary.prototype =
+{
+ /**
+ * Initialize TValidationSummary.
+ * @constructor {protected} ?
+ * @param {object} options - Options for initialization
+ * @... {string} ID - ID of validation summary element
+ * @... {string} FormID - ID of form of this manager
+ * @... {optional string} ValidationGroup - ID of ValidationGroup.
+ * @... {optional boolean} ShowMessageBox - true to show the summary in an alert box.
+ * @... {optional boolean} ShowSummary - true to show the inline summary.
+ * @... {optional string} HeaderText - Summary header text
+ * @... {optional string} DisplayMode - Summary display style, 'BulletList', 'List', 'SingleParagraph'
+ * @... {optional boolean} Refresh - true to update the summary upon validator state change.
+ * @... {optional string} Display - Display mode, 'None', 'Fixed', 'Dynamic'.
+ * @... {optional boolean} ScrollToSummary - true to scroll to the validation summary upon refresh.
+ * @... {optional function} OnHideSummary - Called on hide event.
+ * @... {optional function} OnShowSummary - Called on show event.
+ */
+ initialize : function(options)
+ {
+ /**
+ * Validator options
+ * @var {object} options
+ */
+ this.options = options;
+ /**
+ * ValidationGroup
+ * @var {string} group
+ */
+ this.group = options.ValidationGroup;
+ /**
+ * Summary DOM element
+ * @var {element} messages
+ */
+ this.messages = jQuery("#" + options.ID).get(0);
+ Prado.Registry[options.ID] = this;
+ if(this.messages)
+ {
+ /**
+ * Current visibility state of summary
+ * @var {boolean} visible
+ */
+ this.visible = this.messages.style.visibility != "hidden"
+ this.visible = this.visible && this.messages.style.display != "none";
+ Prado.Validation.addSummary(options.FormID, this);
+ }
+ },
+
+ /**
+ * Update the validation summary.
+ * @function ?
+ * @param {TBaseValidator[]} validators - List of validators that failed validation.
+ * @param {boolean} update - true if visible summary should be updated
+ */
+ updateSummary : function(validators, update)
+ {
+ if(validators.length <= 0)
+ {
+ if(update || this.options.Refresh != false)
+ {
+ return this.hideSummary(validators);
+ }
+ return;
+ }
+
+ var refresh = update || this.visible == false || this.options.Refresh != false;
+ // Also, do not refresh summary if at least 1 validator is waiting for callback response.
+ // This will avoid the flickering of summary if the validator passes its test
+ for(var i = 0; i < validators.length; i++)
+ {
+ if(validators[i].requestDispatched)
+ {
+ refresh=false;
+ break;
+ }
+ }
+
+ if(this.options.ShowSummary != false && refresh)
+ {
+ this.updateHTMLMessages(this.getMessages(validators));
+ this.showSummary(validators);
+ }
+
+ if(this.options.ScrollToSummary != false && refresh)
+ window.scrollTo(this.messages.offsetLeft-20, this.messages.offsetTop-20);
+
+ if(this.options.ShowMessageBox == true && refresh)
+ {
+ this.alertMessages(this.getMessages(validators));
+ this.visible = true;
+ }
+ },
+
+ /**
+ * Display the validator error messages as inline HTML.
+ * @function ?
+ * @param {string[]} messages - Array of error messages.
+ */
+ updateHTMLMessages : function(messages)
+ {
+ while(this.messages.childNodes.length > 0)
+ this.messages.removeChild(this.messages.lastChild);
+ jQuery(this.messages).append(this.formatSummary(messages));
+ },
+
+ /**
+ * Display the validator error messages as an alert box.
+ * @function ?
+ * @param {string[]} messages - Array of error messages.
+ */
+ alertMessages : function(messages)
+ {
+ var text = this.formatMessageBox(messages);
+ setTimeout(function(){ alert(text); },20);
+ },
+
+ /**
+ * Get messages from validators.
+ * @function {string[]} ?
+ * @param {TBaseValidator[]} validators - Array of validators.
+ * @return Array of validator error messages.
+ */
+ getMessages : function(validators)
+ {
+ var messages = [];
+ jQuery.each(validators, function(idx, validator)
+ {
+ var message = validator.getErrorMessage();
+ if(typeof(message) == 'string' && message.length > 0)
+ messages.push(message);
+ })
+ return messages;
+ },
+
+ /**
+ * Hide the validation summary.
+ * @function ?
+ * @param {TBaseValidator[]} validators - Array of validators.
+ */
+ hideSummary : function(validators)
+ { if(typeof(this.options.OnHideSummary) == "function")
+ {
+ this.messages.style.visibility="visible";
+ this.options.OnHideSummary(this,validators)
+ }
+ else
+ {
+ this.messages.style.visibility="hidden";
+ if(this.options.Display == "None" || this.options.Display == "Dynamic")
+ jQuery(this.messages).hide();
+ }
+ this.visible = false;
+ },
+
+ /**
+ * Shows the validation summary.
+ * @function ?
+ * @param {TBaseValidator[]} validators - Array of validators.
+ */
+ showSummary : function(validators)
+ {
+ this.messages.style.visibility="visible";
+ if(typeof(this.options.OnShowSummary) == "function")
+ this.options.OnShowSummary(this,validators);
+ else
+ jQuery(this.messages).show();
+ this.visible = true;
+ },
+
+ /**
+ * Return the format parameters for the summary.
+ * @function {object} ?
+ * @param {string} type - Format type: "List", "SingleParagraph", "HeaderOnly" or "BulletList" (default)
+ * @return Object with format parameters:
+ * @... {string} header - Text for header
+ * @... {string} first - Text to prepend before message list
+ * @... {string} pre - Text to prepend before each message
+ * @... {string} post - Text to append after each message
+ * @... {string} first - Text to append after message list
+ */
+ formats : function(type)
+ {
+ switch(type)
+ {
+ case "SimpleList":
+ return { header : "<br />", first : "", pre : "", post : "<br />", last : ""};
+ case "SingleParagraph":
+ return { header : " ", first : "", pre : "", post : " ", last : "<br />"};
+ case "HeaderOnly":
+ return { header : "", first : "<!--", pre : "", post : "", last : "-->"};
+ case "BulletList":
+ default:
+ return { header : "", first : "<ul>", pre : "<li>", post : "</li>", last : "</ul>"};
+ }
+ },
+
+ /**
+ * Format the message summary.
+ * @function {string} ?
+ * @param {string[]} messages - Array of error messages.
+ * @return Formatted message
+ */
+ formatSummary : function(messages)
+ {
+ var format = this.formats(this.options.DisplayMode);
+ var output = this.options.HeaderText ? this.options.HeaderText + format.header : "";
+ output += format.first;
+ jQuery.each(messages, function(idx, message)
+ {
+ output += message.length > 0 ? format.pre + message + format.post : "";
+ });
+// for(var i = 0; i < messages.length; i++)
+ // output += (messages[i].length>0) ? format.pre + messages[i] + format.post : "";
+ output += format.last;
+ return output;
+ },
+ /**
+ * Format the message alert box.
+ * @function {string} ?
+ * @param {string[]} messages - Array of error messages.
+ * @return Formatted message for alert
+ */
+ formatMessageBox : function(messages)
+ {
+ if(this.options.DisplayMode == 'HeaderOnly' && this.options.HeaderText)
+ return this.options.HeaderText;
+
+ var output = this.options.HeaderText ? this.options.HeaderText + "\n" : "";
+ for(var i = 0; i < messages.length; i++)
+ {
+ switch(this.options.DisplayMode)
+ {
+ case "List":
+ output += messages[i] + "\n";
+ break;
+ case "BulletList":
+ default:
+ output += " - " + messages[i] + "\n";
+ break;
+ case "SingleParagraph":
+ output += messages[i] + " ";
+ break;
+ }
+ }
+ return output;
+ }
+};
+
+/**
+ * TBaseValidator serves as the base class for validator controls.
+ *
+ * <p>Validation is performed when a postback control, such as a TButton,
+ * a TLinkButton or a TTextBox (under AutoPostBack mode) is submitting
+ * the page and its <tt>CausesValidation</tt> option is true.
+ * The input control to be validated is specified by <tt>ControlToValidate</tt>
+ * option.</p>
+ *
+ * @class Prado.WebUI.TBaseValidator
+ */
+Prado.WebUI.TBaseValidator = jQuery.klass(Prado.WebUI.Control,
+{
+ /**
+ * Initialize TBaseValidator.
+ * @constructor {protected} ?
+ * @param {object} options - Options for initialization.
+ * @... {string} ID - ID of validator
+ * @... {string} FormID - ID of form of this manager.
+ * @... {string} ControlToValidate - ID of control to validate.
+ * @... {optional string} InitialValue - Initial value of control to validate.
+ * @... {optional string} ErrorMessage - Validation error message.
+ * @... {optional string} ValidationGroup - ID of ValidationGroup.
+ * @... {optional string} Display - Display mode, 'None', 'Fixed', 'Dynamic'.
+ * @... {optional boolean} ObserveChanges - True to observer changes of ControlToValidate
+ * @... {optional boolean} FocusOnError - True to focus on validation error.
+ * @... {optional string} FocusElementID - ID of element to focus on error.
+ * @... {optional string} ControlCssClass - Css class to use on ControlToValidate on error
+ * @... {optional function} OnValidate - Called immediately after validation.
+ * @... {optional function} OnValidationSuccess - Called after successful validation.
+ * @... {optional function} OnValidationError - Called after validation error.
+ */
+ initialize : function(options)
+ {
+ this.observers = new Array();
+ this.intervals = new Array();
+
+ /* options.OnValidate = options.OnValidate || Prototype.emptyFunction;
+ options.OnSuccess = options.OnSuccess || Prototype.emptyFunction;
+ options.OnError = options.OnError || Prototype.emptyFunction;
+ */
+ /**
+ * Wether the validator is enabled (default true)
+ * @var {boolean} enabled
+ */
+ this.enabled = options.Enabled;
+ /**
+ * Visibility state of validator(default false)
+ * @var {boolean} visible
+ */
+ this.visible = false;
+ /**
+ * State of validation (default true)
+ * @var {boolean} isValid
+ */
+ this.isValid = true;
+ /**
+ * DOM elements that are observed by this validator
+ * @var {private element[]} _isObserving
+ */
+ this._isObserving = {};
+ /**
+ * ValidationGroup
+ * @var {string} group
+ */
+ this.group = null;
+ /**
+ * Wether a request was dispatched (default false)
+ * @var {boolean} requestDispatched
+ */
+ this.requestDispatched = false;
+
+ /**
+ * Validator options
+ * @var {object} options
+ */
+ this.options = options;
+ /**
+ * DOM element of control to validate
+ * @var {element} control
+ */
+ this.control = jQuery("#" + options.ControlToValidate).get(0);
+ /**
+ * DOM element of validator
+ * @var {element} message
+ */
+ this.message = jQuery("#" + options.ID).get(0);
+
+ Prado.Registry[options.ID] = this;
+
+ if (this.onInit) this.onInit();
+
+ if(this.control && this.message)
+ {
+ this.group = options.ValidationGroup;
+
+ /**
+ * ValidationManager of this validator
+ * @var {ValidationManager} manager
+ */
+ this.manager = Prado.Validation.addValidator(options.FormID, this);
+ }
+ },
+
+ /**
+ * Get error message.
+ * @function {string} ?
+ * @return Validation error message.
+ */
+ getErrorMessage : function()
+ {
+ return this.options.ErrorMessage;
+ },
+
+ /**
+ * Update the validator.
+ * Updating the validator control will set the validator
+ * <tt>visible</tt> property to true.
+ * @function ?
+ */
+ updateControl: function()
+ {
+ this.refreshControlAndMessage();
+
+ //if(this.options.FocusOnError && !this.isValid )
+ // Prado.Element.focus(this.options.FocusElementID);
+
+ this.visible = true;
+ },
+
+ /**
+ * Updates span and input CSS class.
+ * @function ?
+ */
+ refreshControlAndMessage : function()
+ {
+ this.visible = true;
+ if(this.message)
+ {
+ if(this.options.Display == "Dynamic")
+ {
+ var msg=this.message;
+ this.isValid ? jQuery(msg).hide() : jQuery(msg).show();
+ }
+ this.message.style.visibility = this.isValid ? "hidden" : "visible";
+ }
+ if(this.control)
+ this.updateControlCssClass(this.control, this.isValid);
+ },
+
+ /**
+ * Update CSS class of control to validate.
+ * Add a css class to the input control if validator is invalid,
+ * removes the css class if valid.
+ * @function ?
+ * @param {element} control - DOM element of control to validate
+ * @param {boolean} valid - Validation state of control
+ */
+ updateControlCssClass : function(control, valid)
+ {
+ var CssClass = this.options.ControlCssClass;
+ if(typeof(CssClass) == "string" && CssClass.length > 0)
+ {
+ if(valid)
+ {
+ if (control.lastValidator == this.options.ID)
+ {
+ control.lastValidator = null;
+ jQuery(control).removeClass(CssClass);
+ }
+ }
+ else
+ {
+ control.lastValidator = this.options.ID;
+ jQuery(control).addClass(CssClass);
+ }
+ }
+ },
+
+ /**
+ * Hide the validator messages and remove any validation changes.
+ * @function ?
+ */
+ hide : function()
+ {
+ this.reset();
+ this.visible = false;
+ },
+
+ /**
+ * Reset validator.
+ * Sets isValid = true and updates the validator display.
+ * @function ?
+ */
+ reset : function()
+ {
+ this.isValid = true;
+ this.updateControl();
+ },
+
+ /**
+ * Perform validation.
+ * Calls evaluateIsValid() function to set the value of isValid property.
+ * Triggers onValidate event and onSuccess or onError event.
+ * @function {boolean} ?
+ * @param {element} invoker - DOM element that triggered validation
+ * @return Valdation state of control.
+ */
+ validate : function(invoker)
+ {
+ //try to find the control.
+ if(!this.control)
+ this.control = jQuery("#" + this.options.ControlToValidate).get(0);
+
+ if(!this.control || this.control.disabled || !jQuery.contains(document, this.control))
+ {
+ this.isValid = true;
+ return this.isValid;
+ }
+
+ if(typeof(this.options.OnValidate) == "function")
+ {
+ if(this.requestDispatched == false)
+ this.options.OnValidate(this, invoker);
+ }
+
+ if(this.enabled && !this.control.getAttribute('disabled'))
+ this.isValid = this.evaluateIsValid();
+ else
+ this.isValid = true;
+
+ this.updateValidationDisplay(invoker);
+ this.observeChanges(this.control);
+
+ return this.isValid;
+ },
+
+ /**
+ * Update validation display.
+ * Updates the validation messages and the control to validate.
+ * @param {element} invoker - DOM element that triggered validation
+ */
+ updateValidationDisplay : function(invoker)
+ {
+ if(this.isValid)
+ {
+ if(typeof(this.options.OnValidationSuccess) == "function")
+ {
+ if(this.requestDispatched == false)
+ {
+ this.refreshControlAndMessage();
+ this.options.OnValidationSuccess(this, invoker);
+ }
+ }
+ else
+ this.updateControl();
+ }
+ else
+ {
+ if(typeof(this.options.OnValidationError) == "function")
+ {
+ if(this.requestDispatched == false)
+ {
+ this.refreshControlAndMessage();
+ this.options.OnValidationError(this, invoker)
+ }
+ }
+ else
+ this.updateControl();
+ }
+ },
+
+ /**
+ * Add control to observe for changes.
+ * Re-validates upon change. If the validator is not visible,
+ * no updates are propagated.
+ * @function ?
+ * @param {element} control - DOM element of control to observe
+ */
+ observeChanges : function(control)
+ {
+ if(!control) return;
+
+ var canObserveChanges = this.options.ObserveChanges != false;
+ var currentlyObserving = this._isObserving[control.id+this.options.ID];
+
+ if(canObserveChanges && !currentlyObserving)
+ {
+ var validator = this;
+
+ this.observe(control, 'change', function()
+ {
+ if(validator.visible)
+ {
+ validator.validate();
+ validator.manager.updateSummary(validator.group);
+ }
+ });
+ this._isObserving[control.id+this.options.ID] = true;
+ }
+ },
+
+ /**
+ * Trim a string.
+ * @function {string} ?
+ * @param {string} value - String that should be trimmed.
+ * @return Trimmed string, empty string if value is not string.
+ */
+ trim : function(value)
+ {
+ return typeof(value) == "string" ? value.trim() : "";
+ },
+
+ /**
+ * Convert the value to a specific data type.
+ * @function {mixed|null} ?
+ * @param {string} dataType - Data type: "Integer", "Double", "Date" or "String"
+ * @param {mixed} value - Value to convert.
+ * @return Converted data value.
+ */
+ convert : function(dataType, value)
+ {
+ if(typeof(value) == "undefined")
+ value = this.getValidationValue();
+ var string = new String(value);
+ switch(dataType)
+ {
+ case "Integer":
+ return string.toInteger();
+ case "Double" :
+ case "Float" :
+ return string.toDouble(this.options.DecimalChar);
+ case "Date":
+ if(typeof(value) != "string")
+ return value;
+ else
+ {
+ var value = Date.SimpleParse(string, this.options.DateFormat);
+ if(value && typeof(value.getTime) == "function")
+ return value.getTime();
+ else
+ return null;
+ }
+ case "String":
+ return string.toString();
+ }
+ return value;
+ },
+
+ /**
+ * Get value that should be validated.
+ * The ControlType property comes from TBaseValidator::getClientControlClass()
+ * Be sure to update the TBaseValidator::$_clientClass if new cases are added.
+ * @function {mixed} ?
+ * @param {optional element} control - Control to get value from (default: this.control)
+ * @return Control value to validate
+ */
+ getRawValidationValue : function(control)
+ {
+ if(!control)
+ control = this.control
+ switch(this.options.ControlType)
+ {
+ case 'TDatePicker':
+ if(control.type == "text")
+ {
+ var value = this.trim(jQuery(control).val());
+
+ if(this.options.DateFormat)
+ {
+ var date = Date.SimpleParse(value, this.options.DateFormat);
+ return date == null ? value : date;
+ }
+ else
+ return value;
+ }
+ else
+ {
+ this.observeDatePickerChanges();
+
+ return Prado.WebUI.TDatePicker.getDropDownDate(control);//.getTime();
+ }
+ case 'THtmlArea':
+ case 'THtmlArea4':
+ if(typeof tinyMCE != "undefined")
+ tinyMCE.triggerSave();
+ return control.value;
+ case 'TRadioButton':
+ case 'TActiveRadioButton':
+ if(this.options.GroupName)
+ return this.getRadioButtonGroupValue();
+ case 'TCheckBox':
+ case 'TActiveCheckBox':
+ return control.checked;
+ default:
+ if(this.isListControlType())
+ return this.getFirstSelectedListValue();
+ else
+ return jQuery(control).val();
+ }
+ },
+
+ /**
+ * Get a trimmed value that should be validated.
+ * The ControlType property comes from TBaseValidator::getClientControlClass()
+ * Be sure to update the TBaseValidator::$_clientClass if new cases are added.
+ * @function {mixed} ?
+ * @param {optional element} control - Control to get value fron (default: this.control)
+ * @return Control value to validate
+ */
+ getValidationValue : function(control)
+ {
+ var value = this.getRawValidationValue(control);
+ if(!control)
+ control = this.control
+ switch(this.options.ControlType)
+ {
+ case 'TDatePicker':
+ return value;
+ case 'THtmlArea':
+ case 'THtmlArea4':
+ return this.trim(value);
+ case 'TRadioButton':
+ case 'TCheckBox':
+ case 'TActiveCheckBox':
+ case 'TActiveRadioButton':
+ return value;
+ default:
+ if(this.isListControlType())
+ return value;
+ else
+ return this.trim(value);
+ }
+ },
+
+ /**
+ * Get value of radio button group
+ * @function {string} ?
+ * @return Value of a radio button group
+ */
+ getRadioButtonGroupValue : function()
+ {
+ var name = this.control.name;
+ var value = "";
+ jQuery.each(document.getElementsByName(name), function(idx, el)
+ {
+ if(el.checked)
+ value = el.value;
+ });
+ return value;
+ },
+
+ /**
+ * Observe changes in the drop down list date picker, IE only.
+ * @function ?
+ */
+ observeDatePickerChanges : function()
+ {
+ var DatePicker = Prado.WebUI.TDatePicker;
+ this.observeChanges(DatePicker.getDayListControl(this.control));
+ this.observeChanges(DatePicker.getMonthListControl(this.control));
+ this.observeChanges(DatePicker.getYearListControl(this.control));
+ },
+
+ /**
+ * Gets number of selections and their values.
+ * @function {object} ?
+ * @param {element[]} elements - Elements to get values from.
+ * @param {string} initialValue - Initial value of element
+ * @return Object:
+ * @... {mixed[]} values - Array of selected values
+ * @... {int} checks - Number of selections
+ */
+ getSelectedValuesAndChecks : function(elements, initialValue)
+ {
+ var checked = 0;
+ var values = [];
+ var isSelected = this.isCheckBoxType(elements[0]) ? 'checked' : 'selected';
+ jQuery.each(elements, function(idx, element)
+ {
+ if(element[isSelected] && element.value != initialValue)
+ {
+ checked++;
+ values.push(element.value);
+ }
+ });
+ return {'checks' : checked, 'values' : values};
+ },
+
+ /**
+ * Get list elements of TCheckBoxList or TListBox.
+ * Gets an array of the list control item input elements, for TCheckBoxList
+ * checkbox input elements are returned, for TListBox HTML option elements
+ * are returned.
+ * @function {element[]} ?
+ * @return Array of list control option DOM elements.
+ */
+ getListElements : function()
+ {
+ switch(this.options.ControlType)
+ {
+ case 'TCheckBoxList': case 'TRadioButtonList':
+ var elements = [];
+ for(var i = 0; i < this.options.TotalItems; i++)
+ {
+ var element = jQuery("#" + this.options.ControlToValidate+"_c"+i).get(0);
+ if(this.isCheckBoxType(element))
+ elements.push(element);
+ }
+ return elements;
+ case 'TListBox':
+ var elements = [];
+ var element = jQuery("#" + this.options.ControlToValidate).get(0);
+ var type;
+ if(element && (type = element.type.toLowerCase()))
+ {
+ if(type == "select-one" || type == "select-multiple")
+ elements = element.options;
+ }
+ return elements;
+ default:
+ return [];
+ }
+ },
+
+ /**
+ * Check if control is of type checkbox or radio.
+ * @function {boolean} ?
+ * @param {element} element - DOM element to check.
+ * @return True if element is of checkbox or radio type.
+ */
+ isCheckBoxType : function(element)
+ {
+ if(element && element.type)
+ {
+ var type = element.type.toLowerCase();
+ return type == "checkbox" || type == "radio";
+ }
+ return false;
+ },
+
+ /**
+ * Check if control to validate is a TListControl type.
+ * @function {boolean} ?
+ * @return True if control to validate is a TListControl type.
+ */
+ isListControlType : function()
+ {
+ var list = ['TCheckBoxList', 'TRadioButtonList', 'TListBox'];
+ return (jQuery.inArray(this.options.ControlType, list)!=-1);
+ },
+
+ /**
+ * Get first selected list value or initial value if none found.
+ * @function {string} ?
+ * @return First selected list value, initial value if none found.
+ */
+ getFirstSelectedListValue : function()
+ {
+ var initial = "";
+ if(typeof(this.options.InitialValue) != "undefined")
+ initial = this.options.InitialValue;
+ var elements = this.getListElements();
+ var selection = this.getSelectedValuesAndChecks(elements, initial);
+ return selection.values.length > 0 ? selection.values[0] : initial;
+ }
+});
+
+
+/**
+ * TRequiredFieldValidator makes the associated input control a required field.
+ *
+ * <p>The input control fails validation if its value does not change from
+ * the <tt>InitialValue</tt> option upon losing focus.</p>
+ *
+ * @class Prado.WebUI.TRequiredFieldValidator
+ * @extends Prado.WebUI.TBaseValidator
+ */
+Prado.WebUI.TRequiredFieldValidator = jQuery.klass(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Evaluate validation state
+ * @function {boolean} ?
+ * @return True if the input value is not empty nor equal to the initial value.
+ */
+ evaluateIsValid : function()
+ {
+ var a = this.getValidationValue();
+ var b = this.trim(this.options.InitialValue);
+ return(a != b);
+ }
+});
+
+
+/**
+ * TCompareValidator compares the value entered by the user into an input
+ * control with the value entered into another input control or a constant value.
+ *
+ * <p>To compare the associated input control with another input control,
+ * set the <tt>ControlToCompare</tt> option to the ID path
+ * of the control to compare with. To compare the associated input control with
+ * a constant value, specify the constant value to compare with by setting the
+ * <tt>ValueToCompare</tt> option.</p>
+ *
+ * <p>The <tt>DataType</tt> property is used to specify the data type
+ * of both comparison values. Both values are automatically converted to this data
+ * type before the comparison operation is performed. The following value types are supported:
+ * - <b>Integer</b> A 32-bit signed integer data type.
+ * - <b>Float</b> A double-precision floating point number data type.
+ * - <b>Date</b> A date data type. The format can be set by the <tt>DateFormat</tt> option.
+ * - <b>String</b> A string data type.</p>
+ *
+ * Use the <tt>Operator</tt> property to specify the type of comparison
+ * to perform. Valid operators include Equal, NotEqual, GreaterThan, GreaterThanEqual,
+ * LessThan and LessThanEqual.
+ *
+ * @class Prado.WebUI.TCompareValidator
+ * @extends Prado.WebUI.TBaseValidator
+ */
+Prado.WebUI.TCompareValidator = jQuery.klass(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Additional constructor options.
+ * @constructor initialize
+ * @param {object} options - Additional constructor options:
+ * @... {string} ControlToCompare - Control with compare value.
+ * @... {string} ValueToCompare - Value to compare.
+ * @... {string} Operator - Type of comparison: "Equal", "NotEqual", "GreaterThan",
+ * "GreaterThanEqual", "LessThan" or "LessThanEqual".
+ * @... {string} Type - Type of values: "Integer", "Float", "Date" or "String".
+ * @... {string} DateFormat - Valid date format.
+ */
+
+ //_observingComparee : false,
+
+ /**
+ * Evaluate validation state
+ * @function {boolean} ?
+ * @return True if comparision condition is met.
+ */
+ evaluateIsValid : function()
+ {
+ var value = this.getValidationValue();
+ if (value.length <= 0)
+ return true;
+
+ var comparee = jQuery("#" + this.options.ControlToCompare).get(0);
+
+ if(comparee)
+ var compareTo = this.getValidationValue(comparee);
+ else
+ var compareTo = this.options.ValueToCompare || "";
+
+ var isValid = this.compare(value, compareTo);
+
+ if(comparee)
+ {
+ this.updateControlCssClass(comparee, isValid);
+ this.observeChanges(comparee);
+ }
+ return isValid;
+ },
+
+ /**
+ * Compare two operands.
+ * The operand values are casted to type defined
+ * by <tt>DataType</tt> option. False is returned if the first
+ * operand converts to null. Returns true if the second operand
+ * converts to null. The comparision is done based on the
+ * <tt>Operator</tt> option.
+ * @function ?
+ * @param {mixed} operand1 - First operand.
+ * @param {mixed} operand2 - Second operand.
+ */
+ compare : function(operand1, operand2)
+ {
+ var op1, op2;
+ if((op1 = this.convert(this.options.DataType, operand1)) == null)
+ return false;
+ if ((op2 = this.convert(this.options.DataType, operand2)) == null)
+ return true;
+ switch (this.options.Operator)
+ {
+ case "NotEqual":
+ return (op1 != op2);
+ case "GreaterThan":
+ return (op1 > op2);
+ case "GreaterThanEqual":
+ return (op1 >= op2);
+ case "LessThan":
+ return (op1 < op2);
+ case "LessThanEqual":
+ return (op1 <= op2);
+ default:
+ return (op1 == op2);
+ }
+ }
+});
+
+/**
+ * TCustomValidator performs user-defined client-side validation on an
+ * input component.
+ *
+ * <p>To create a client-side validation function, add the client-side
+ * validation javascript function to the page template.
+ * The function should have the following signature:</p>
+ *
+ * <pre>
+ * &lt;script type="text/javascript"&gt;
+ * function ValidationFunctionName(sender, parameter)
+ * {
+ * if(parameter == ...)
+ * return true;
+ * else
+ * return false;
+ * }
+ * &lt;/script&gt;
+ * </pre>
+ *
+ * <p>Use the <tt>ClientValidationFunction</tt> option
+ * to specify the name of the client-side validation script function associated
+ * with the TCustomValidator.</p>
+ *
+ * @class Prado.WebUI.TCustomValidator
+ * @extends Prado.WebUI.TBaseValidator
+ */
+Prado.WebUI.TCustomValidator = jQuery.klass(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Additional constructor options.
+ * @constructor initialize
+ * @param {object} options - Additional constructor options:
+ * @... {function} ClientValidationFunction - Custom validation function.
+ */
+
+ /**
+ * Evaluate validation state
+ * Returns true if no valid custom validation function is present.
+ * @function {boolean} ?
+ * @return True if custom validation returned true.
+ */
+ evaluateIsValid : function()
+ {
+ var value = this.getValidationValue();
+ var clientFunction = this.options.ClientValidationFunction;
+ if(typeof(clientFunction) == "string" && clientFunction.length > 0)
+ {
+ var validate = clientFunction.toFunction();
+ return validate(this, value);
+ }
+ return true;
+ }
+});
+
+/**
+ * Uses callback request to perform validation.
+ *
+ * @class Prado.WebUI.TActiveCustomValidator
+ * @extends Prado.WebUI.TBaseValidator
+ */
+Prado.WebUI.TActiveCustomValidator = jQuery.klass(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Override the parent implementation to store the invoker, in order to
+ * re-validate after the callback has returned
+ * Calls evaluateIsValid() function to set the value of isValid property.
+ * Triggers onValidate event and onSuccess or onError event.
+ * @function {boolean} ?
+ * @param {element} invoker - DOM element that triggered validation
+ * @return True if valid.
+ */
+ validate : function(invoker)
+ {
+ this.invoker = invoker;
+
+ //try to find the control.
+ if(!this.control)
+ this.control = jQuery("#" + this.options.ControlToValidate).get(0);
+
+ if(!this.control || this.control.disabled)
+ {
+ this.isValid = true;
+ return this.isValid;
+ }
+
+ if(typeof(this.options.OnValidate) == "function")
+ {
+ if(this.requestDispatched == false)
+ this.options.OnValidate(this, invoker);
+ }
+
+ return this.isValid;
+ },
+
+ /**
+ * Send CallBack to start serverside validation.
+ * @function {boolean} ?
+ * @return True if valid.
+ */
+ evaluateIsValid : function()
+ {
+ return this.isValid;
+ },
+
+ /**
+ * Parse CallBack response data on success.
+ * @function ?
+ * @param {CallbackRequest} request - CallbackRequest.
+ * @param {string} data - Response data.
+ */
+ updateIsValid : function(data)
+ {
+ this.isValid = data;
+ this.requestDispatched = false;
+ if(typeof(this.options.onSuccess) == "function")
+ this.options.onSuccess(null,data);
+ this.updateValidationDisplay();
+ this.manager.updateSummary(this.group);
+ }
+});
+
+/**
+ * TRangeValidator tests whether an input value is within a specified range.
+ *
+ * <p>TRangeValidator uses three key properties to perform its validation.</p>
+ *
+ * <p>The <tt>MinValue</tt> and <tt>MaxValue</tt> options specify the minimum
+ * and maximum values of the valid range.</p>
+ * <p>The <tt>DataType</tt> option is
+ * used to specify the data type of the value and the minimum and maximum range values.
+ * The values are converted to this data type before the validation
+ * operation is performed. The following value types are supported:</p>
+ *
+ * - <b>Integer</b> A 32-bit signed integer data type.<br />
+ * - <b>Float</b> A double-precision floating point number data type.<br />
+ * - <b>Date</b> A date data type. The date format can be specified by<br />
+ * setting <tt>DateFormat</tt> option, which must be recognizable
+ * by <tt>Date.SimpleParse</tt> javascript function.
+ * - <b>String</b> A string data type.
+ *
+ * @class Prado.WebUI.TRangeValidator
+ * @extends Prado.WebUI.TBaseValidator
+ */
+Prado.WebUI.TRangeValidator = jQuery.klass(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Additional constructor options.
+ * @constructor initialize
+ * @param {object} options - Additional constructor options:
+ * @... {string} MinValue - Minimum range value
+ * @... {string} MaxValue - Maximum range value
+ * @... {string} DataType - Value data type: "Integer", "Float", "Date" or "String"
+ * @... {string} DateFormat - Date format for data type Date.
+ */
+
+ /**
+ * Evaluate validation state
+ * @function {boolean} ?
+ * @return True if value is in range or value is empty,
+ * false otherwhise and when type conversion failed.
+ */
+ evaluateIsValid : function()
+ {
+ var value = this.getValidationValue();
+ if(value.length <= 0)
+ return true;
+ if(typeof(this.options.DataType) == "undefined")
+ this.options.DataType = "String";
+
+ if(this.options.DataType != "StringLength")
+ {
+ var min = this.convert(this.options.DataType, this.options.MinValue || null);
+ var max = this.convert(this.options.DataType, this.options.MaxValue || null);
+ value = this.convert(this.options.DataType, value);
+ }
+ else
+ {
+ var min = this.options.MinValue || 0;
+ var max = this.options.MaxValue || Number.POSITIVE_INFINITY;
+ value = value.length;
+ }
+
+ if(value == null)
+ return false;
+
+ var valid = true;
+
+ if(min != null)
+ valid = valid && (this.options.StrictComparison ? value > min : value >= min);
+ if(max != null)
+ valid = valid && (this.options.StrictComparison ? value < max : value <= max);
+ return valid;
+ }
+});
+
+/**
+ * TRegularExpressionValidator validates whether the value of an associated
+ * input component matches the pattern specified by a regular expression.
+ *
+ * @class Prado.WebUI.TRegularExpressionValidator
+ * @extends Prado.WebUI.TBaseValidator
+ */
+Prado.WebUI.TRegularExpressionValidator = jQuery.klass(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Additional constructor option.
+ * @constructor initialize
+ * @param {object} options - Additional constructor option:
+ * @... {string} ValidationExpression - Regular expression to match against.
+ * @... {string} PatternModifiers - Pattern modifiers: combinations of g, i, and m
+ */
+
+ /**
+ * Evaluate validation state
+ * @function {boolean} ?
+ * @return True if value matches regular expression or value is empty.
+ */
+ evaluateIsValid : function()
+ {
+ var value = this.getRawValidationValue();
+ if (value.length <= 0)
+ return true;
+
+ var rx = new RegExp('^'+this.options.ValidationExpression+'$',this.options.PatternModifiers);
+ var matches = rx.exec(value);
+ return (matches != null && value == matches[0]);
+ }
+});
+
+/**
+ * TEmailAddressValidator validates whether the value of an associated
+ * input component is a valid email address.
+ *
+ * @class Prado.WebUI.TEmailAddressValidator
+ * @extends Prado.WebUI.TRegularExpressionValidator
+ */
+Prado.WebUI.TEmailAddressValidator = Prado.WebUI.TRegularExpressionValidator;
+
+
+/**
+ * TListControlValidator checks the number of selection and their values
+ * for a TListControl that allows multiple selections.
+ *
+ * @class Prado.WebUI.TListControlValidator
+ * @extends Prado.WebUI.TBaseValidator
+ */
+Prado.WebUI.TListControlValidator = jQuery.klass(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Evaluate validation state
+ * @function {boolean} ?
+ * @return True if number of selections and/or their values match requirements.
+ */
+ evaluateIsValid : function()
+ {
+ var elements = this.getListElements();
+ if(elements && elements.length <= 0)
+ return true;
+
+ this.observeListElements(elements);
+
+ var selection = this.getSelectedValuesAndChecks(elements);
+ return this.isValidList(selection.checks, selection.values);
+ },
+
+ /**
+ * Observe list elements for of changes (only IE)
+ * @function ?
+ * @param {element[]} elements - Array of DOM elements to observe
+ */
+ observeListElements : function(elements)
+ {
+ if(this.isCheckBoxType(elements[0]))
+ {
+ var validator = this;
+ jQuery.each(elements, function(idx, element)
+ {
+ validator.observeChanges(element);
+ });
+ }
+ },
+
+ /**
+ * Check if list is valid.
+ * Determine if the number of checked values and the checked values
+ * satisfy the required number of checks and/or the checked values
+ * equal to the required values.
+ * @function {boolean} ?
+ * @param {int} checked - Number of required checked values
+ * @param {string[]} values - Array of required checked values
+ * @return True if checked values and number of checks are satisfied.
+ */
+ isValidList : function(checked, values)
+ {
+ var exists = true;
+
+ //check the required values
+ var required = this.getRequiredValues();
+ if(required.length > 0)
+ {
+ if(values.length < required.length)
+ return false;
+ jQuery.each(required, function(idx, requiredValue)
+ {
+ exists = exists && (jQuery.inArray(requiredValue, values)!=-1);
+ });
+ }
+
+ var min = typeof(this.options.Min) == "undefined" ?
+ Number.NEGATIVE_INFINITY : this.options.Min;
+ var max = typeof(this.options.Max) == "undefined" ?
+ Number.POSITIVE_INFINITY : this.options.Max;
+ return exists && checked >= min && checked <= max;
+ },
+
+ /**
+ * Get list of required values.
+ * @function {string[]} ?
+ * @return Array of required values that must be selected.
+ */
+ getRequiredValues : function()
+ {
+ var required = [];
+ if(this.options.Required && this.options.Required.length > 0)
+ required = this.options.Required.split(/,\s*/);
+ return required;
+ }
+});
+
+
+/**
+ * TDataTypeValidator verifies if the input data is of the type specified
+ * by <tt>DataType</tt> option.
+ *
+ * <p>The following data types are supported:</p>
+ *
+ * - <b>Integer</b> A 32-bit signed integer data type.<br />
+ * - <b>Float</b> A double-precision floating point number data type.<br />
+ * - <b>Date</b> A date data type.<br />
+ * - <b>String</b> A string data type.<br />
+ *
+ * <p>For <b>Date</b> type, the option <tt>DateFormat</tt>
+ * will be used to determine how to parse the date string.</p>
+ *
+ * @class Prado.WebUI.TDataTypeValidator
+ * @extends Prado.WebUI.TBaseValidator
+ */
+Prado.WebUI.TDataTypeValidator = jQuery.klass(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Additional constructor option.
+ * @constructor initialize
+ * @param {object} options - Additional constructor option:
+ * @... {string} DataType - Value data type: "Integer", "Float", "Date" or "String"
+ * @... {string} DateFormat - Date format for data type Date.
+ */
+
+ /**
+ * Evaluate validation state
+ * @function {boolean} ?
+ * @return True if value matches required data type.
+ */
+ evaluateIsValid : function()
+ {
+ var value = this.getValidationValue();
+ if(value.length <= 0)
+ return true;
+ return this.convert(this.options.DataType, value) != null;
+ }
+});
+
+/**
+ * TCaptchaValidator verifies if the input data is the same as
+ * the token shown in the associated CAPTCHA control.
+ *
+ * @class Prado.WebUI.TCaptchaValidator
+ * @extends Prado.WebUI.TBaseValidator
+ */
+Prado.WebUI.TCaptchaValidator = jQuery.klass(Prado.WebUI.TBaseValidator,
+{
+ /**
+ * Evaluate validation state
+ * @function {boolean} ?
+ * @return True if value matches captcha text
+ */
+ evaluateIsValid : function()
+ {
+ var a = this.getValidationValue();
+ var h = 0;
+ if (this.options.CaseSensitive==false)
+ a = a.toUpperCase();
+ for(var i = a.length-1; i >= 0; --i)
+ h += a.charCodeAt(i);
+ return h == this.options.TokenHash;
+ },
+
+ crc32 : function(str)
+ {
+ function Utf8Encode(string)
+ {
+ string = string.replace(/\r\n/g,"\n");
+ var utftext = "";
+
+ for (var n = 0; n < string.length; n++)
+ {
+ var c = string.charCodeAt(n);
+
+ if (c < 128) {
+ utftext += String.fromCharCode(c);
+ }
+ else if((c > 127) && (c < 2048)) {
+ utftext += String.fromCharCode((c >> 6) | 192);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+ else {
+ utftext += String.fromCharCode((c >> 12) | 224);
+ utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+ }
+
+ return utftext;
+ };
+
+ str = Utf8Encode(str);
+
+ var table = "00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F 63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC 51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E 7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D 806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA 11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D";
+ var crc = 0;
+ var x = 0;
+ var y = 0;
+
+ crc = crc ^ (-1);
+ for( var i = 0, iTop = str.length; i < iTop; i++ )
+ {
+ y = ( crc ^ str.charCodeAt( i ) ) & 0xFF;
+ x = "0x" + table.substr( y * 9, 8 );
+ crc = ( crc >>> 8 ) ^ x;
+ }
+ return crc ^ (-1);
+ }
+});
+
+
+/**
+ * TReCaptchaValidator client-side control.
+ *
+ * @class Prado.WebUI.TReCaptchaValidator
+ * @extends Prado.WebUI.TBaseValidator
+ */
+Prado.WebUI.TReCaptchaValidator = jQuery.klass(Prado.WebUI.TBaseValidator,
+{
+ onInit : function()
+ {
+ var obj = this;
+ var elements = document.getElementsByName(this.options.ResponseFieldName);
+ if (elements)
+ if (elements.length>=1)
+ {
+ this.observe(elements[0],'change',function() { obj.responseChanged() });
+ this.observe(elements[0],'keydown',function() { obj.responseChanged() });
+ }
+ },
+
+ responseChanged: function()
+ {
+ var field = jQuery("#" + this.options.ID+'_1').get(0);
+ if (field.value=='1') return;
+ field.value = '1';
+ Prado.Validation.validateControl(this.options.ID);
+ },
+
+ /**
+ * Evaluate validation state
+ * @function {boolean} ?
+ * @return True if the captcha has validate, False otherwise.
+ */
+ evaluateIsValid : function()
+ {
+ return (jQuery("#" + this.options.ID+'_1').get(0).value=='1');
+ }
+});
+
diff --git a/lib/prado/framework/Web/Javascripts/source/prototype-1.7/prototype.js b/lib/prado/framework/Web/Javascripts/source/prototype-1.7/prototype.js
new file mode 100644
index 0000000..de5fff4
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/prototype-1.7/prototype.js
@@ -0,0 +1,7039 @@
+/* Prototype JavaScript framework, version 1.7.1
+ * (c) 2005-2010 Sam Stephenson
+ *
+ * Prototype is freely distributable under the terms of an MIT-style license.
+ * For details, see the Prototype web site: http://www.prototypejs.org/
+ *
+ *--------------------------------------------------------------------------*/
+
+var Prototype = {
+
+ Version: '1.7.1',
+
+ Browser: (function(){
+ var ua = navigator.userAgent;
+ var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
+ return {
+ IE: !!window.attachEvent && !isOpera,
+ Opera: isOpera,
+ WebKit: ua.indexOf('AppleWebKit/') > -1,
+ Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
+ MobileSafari: /Apple.*Mobile/.test(ua)
+ }
+ })(),
+
+ BrowserFeatures: {
+ XPath: !!document.evaluate,
+
+ SelectorsAPI: !!document.querySelector,
+
+ ElementExtensions: (function() {
+ var constructor = window.Element || window.HTMLElement;
+ return !!(constructor && constructor.prototype);
+ })(),
+ SpecificElementExtensions: (function() {
+ if (typeof window.HTMLDivElement !== 'undefined')
+ return true;
+
+ var div = document.createElement('div'),
+ form = document.createElement('form'),
+ isSupported = false;
+
+ if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
+ isSupported = true;
+ }
+
+ div = form = null;
+
+ return isSupported;
+ })()
+ },
+
+ ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script\\s*>',
+ JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
+
+ emptyFunction: function() { },
+
+ K: function(x) { return x }
+};
+
+if (Prototype.Browser.MobileSafari)
+ Prototype.BrowserFeatures.SpecificElementExtensions = false;
+/* Based on Alex Arnell's inheritance implementation. */
+
+var Class = (function() {
+
+ var IS_DONTENUM_BUGGY = (function(){
+ for (var p in { toString: 1 }) {
+ if (p === 'toString') return false;
+ }
+ return true;
+ })();
+
+ function subclass() {};
+ function create() {
+ var parent = null, properties = $A(arguments);
+ if (Object.isFunction(properties[0]))
+ parent = properties.shift();
+
+ function klass() {
+ this.initialize.apply(this, arguments);
+ }
+
+ Object.extend(klass, Class.Methods);
+ klass.superclass = parent;
+ klass.subclasses = [];
+
+ if (parent) {
+ subclass.prototype = parent.prototype;
+ klass.prototype = new subclass;
+ parent.subclasses.push(klass);
+ }
+
+ for (var i = 0, length = properties.length; i < length; i++)
+ klass.addMethods(properties[i]);
+
+ if (!klass.prototype.initialize)
+ klass.prototype.initialize = Prototype.emptyFunction;
+
+ klass.prototype.constructor = klass;
+ return klass;
+ }
+
+ function addMethods(source) {
+ var ancestor = this.superclass && this.superclass.prototype,
+ properties = Object.keys(source);
+
+ if (IS_DONTENUM_BUGGY) {
+ if (source.toString != Object.prototype.toString)
+ properties.push("toString");
+ if (source.valueOf != Object.prototype.valueOf)
+ properties.push("valueOf");
+ }
+
+ for (var i = 0, length = properties.length; i < length; i++) {
+ var property = properties[i], value = source[property];
+ if (ancestor && Object.isFunction(value) &&
+ value.argumentNames()[0] == "$super") {
+ var method = value;
+ value = (function(m) {
+ return function() { return ancestor[m].apply(this, arguments); };
+ })(property).wrap(method);
+
+ value.valueOf = (function(method) {
+ return function() { return method.valueOf.call(method); };
+ })(method);
+
+ value.toString = (function(method) {
+ return function() { return method.toString.call(method); };
+ })(method);
+ }
+ this.prototype[property] = value;
+ }
+
+ return this;
+ }
+
+ return {
+ create: create,
+ Methods: {
+ addMethods: addMethods
+ }
+ };
+})();
+(function() {
+
+ var _toString = Object.prototype.toString,
+ _hasOwnProperty = Object.prototype.hasOwnProperty,
+ NULL_TYPE = 'Null',
+ UNDEFINED_TYPE = 'Undefined',
+ BOOLEAN_TYPE = 'Boolean',
+ NUMBER_TYPE = 'Number',
+ STRING_TYPE = 'String',
+ OBJECT_TYPE = 'Object',
+ FUNCTION_CLASS = '[object Function]',
+ BOOLEAN_CLASS = '[object Boolean]',
+ NUMBER_CLASS = '[object Number]',
+ STRING_CLASS = '[object String]',
+ ARRAY_CLASS = '[object Array]',
+ DATE_CLASS = '[object Date]',
+ NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON &&
+ typeof JSON.stringify === 'function' &&
+ JSON.stringify(0) === '0' &&
+ typeof JSON.stringify(Prototype.K) === 'undefined';
+
+
+
+ var DONT_ENUMS = ['toString', 'toLocaleString', 'valueOf',
+ 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor'];
+
+ var IS_DONTENUM_BUGGY = (function(){
+ for (var p in { toString: 1 }) {
+ if (p === 'toString') return false;
+ }
+ return true;
+ })();
+
+ function Type(o) {
+ switch(o) {
+ case null: return NULL_TYPE;
+ case (void 0): return UNDEFINED_TYPE;
+ }
+ var type = typeof o;
+ switch(type) {
+ case 'boolean': return BOOLEAN_TYPE;
+ case 'number': return NUMBER_TYPE;
+ case 'string': return STRING_TYPE;
+ }
+ return OBJECT_TYPE;
+ }
+
+ function extend(destination, source) {
+ for (var property in source)
+ destination[property] = source[property];
+ return destination;
+ }
+
+ function inspect(object) {
+ try {
+ if (isUndefined(object)) return 'undefined';
+ if (object === null) return 'null';
+ return object.inspect ? object.inspect() : String(object);
+ } catch (e) {
+ if (e instanceof RangeError) return '...';
+ throw e;
+ }
+ }
+
+ function toJSON(value) {
+ return Str('', { '': value }, []);
+ }
+
+ function Str(key, holder, stack) {
+ var value = holder[key];
+ if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
+
+ var _class = _toString.call(value);
+
+ switch (_class) {
+ case NUMBER_CLASS:
+ case BOOLEAN_CLASS:
+ case STRING_CLASS:
+ value = value.valueOf();
+ }
+
+ switch (value) {
+ case null: return 'null';
+ case true: return 'true';
+ case false: return 'false';
+ }
+
+ var type = typeof value;
+ switch (type) {
+ case 'string':
+ return value.inspect(true);
+ case 'number':
+ return isFinite(value) ? String(value) : 'null';
+ case 'object':
+
+ for (var i = 0, length = stack.length; i < length; i++) {
+ if (stack[i] === value) {
+ throw new TypeError("Cyclic reference to '" + value + "' in object");
+ }
+ }
+ stack.push(value);
+
+ var partial = [];
+ if (_class === ARRAY_CLASS) {
+ for (var i = 0, length = value.length; i < length; i++) {
+ var str = Str(i, value, stack);
+ partial.push(typeof str === 'undefined' ? 'null' : str);
+ }
+ partial = '[' + partial.join(',') + ']';
+ } else {
+ var keys = Object.keys(value);
+ for (var i = 0, length = keys.length; i < length; i++) {
+ var key = keys[i], str = Str(key, value, stack);
+ if (typeof str !== "undefined") {
+ partial.push(key.inspect(true)+ ':' + str);
+ }
+ }
+ partial = '{' + partial.join(',') + '}';
+ }
+ stack.pop();
+ return partial;
+ }
+ }
+
+ function stringify(object) {
+ return JSON.stringify(object);
+ }
+
+ function toQueryString(object) {
+ return $H(object).toQueryString();
+ }
+
+ function toHTML(object) {
+ return object && object.toHTML ? object.toHTML() : String.interpret(object);
+ }
+
+ function keys(object) {
+ if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); }
+ var results = [];
+ for (var property in object) {
+ if (_hasOwnProperty.call(object, property))
+ results.push(property);
+ }
+
+ if (IS_DONTENUM_BUGGY) {
+ for (var i = 0; property = DONT_ENUMS[i]; i++) {
+ if (_hasOwnProperty.call(object, property))
+ results.push(property);
+ }
+ }
+
+ return results;
+ }
+
+ function values(object) {
+ var results = [];
+ for (var property in object)
+ results.push(object[property]);
+ return results;
+ }
+
+ function clone(object) {
+ return extend({ }, object);
+ }
+
+ function isElement(object) {
+ return !!(object && object.nodeType == 1);
+ }
+
+ function isArray(object) {
+ return _toString.call(object) === ARRAY_CLASS;
+ }
+
+ var hasNativeIsArray = (typeof Array.isArray == 'function')
+ && Array.isArray([]) && !Array.isArray({});
+
+ if (hasNativeIsArray) {
+ isArray = Array.isArray;
+ }
+
+ function isHash(object) {
+ return object instanceof Hash;
+ }
+
+ function isFunction(object) {
+ return _toString.call(object) === FUNCTION_CLASS;
+ }
+
+ function isString(object) {
+ return _toString.call(object) === STRING_CLASS;
+ }
+
+ function isNumber(object) {
+ return _toString.call(object) === NUMBER_CLASS;
+ }
+
+ function isDate(object) {
+ return _toString.call(object) === DATE_CLASS;
+ }
+
+ function isUndefined(object) {
+ return typeof object === "undefined";
+ }
+
+ extend(Object, {
+ extend: extend,
+ inspect: inspect,
+ toJSON: NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON,
+ toQueryString: toQueryString,
+ toHTML: toHTML,
+ keys: Object.keys || keys,
+ values: values,
+ clone: clone,
+ isElement: isElement,
+ isArray: isArray,
+ isHash: isHash,
+ isFunction: isFunction,
+ isString: isString,
+ isNumber: isNumber,
+ isDate: isDate,
+ isUndefined: isUndefined
+ });
+})();
+Object.extend(Function.prototype, (function() {
+ var slice = Array.prototype.slice;
+
+ function update(array, args) {
+ var arrayLength = array.length, length = args.length;
+ while (length--) array[arrayLength + length] = args[length];
+ return array;
+ }
+
+ function merge(array, args) {
+ array = slice.call(array, 0);
+ return update(array, args);
+ }
+
+ function argumentNames() {
+ var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
+ .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
+ .replace(/\s+/g, '').split(',');
+ return names.length == 1 && !names[0] ? [] : names;
+ }
+
+
+ function bind(context) {
+ if (arguments.length < 2 && Object.isUndefined(arguments[0]))
+ return this;
+
+ if (!Object.isFunction(this))
+ throw new TypeError("The object is not callable.");
+
+ var nop = function() {};
+ var __method = this, args = slice.call(arguments, 1);
+
+ var bound = function() {
+ var a = merge(args, arguments), c = context;
+ var c = this instanceof bound ? this : context;
+ return __method.apply(c, a);
+ };
+
+ nop.prototype = this.prototype;
+ bound.prototype = new nop();
+
+ return bound;
+ }
+
+ function bindAsEventListener(context) {
+ var __method = this, args = slice.call(arguments, 1);
+ return function(event) {
+ var a = update([event || window.event], args);
+ return __method.apply(context, a);
+ }
+ }
+
+ function curry() {
+ if (!arguments.length) return this;
+ var __method = this, args = slice.call(arguments, 0);
+ return function() {
+ var a = merge(args, arguments);
+ return __method.apply(this, a);
+ }
+ }
+
+ function delay(timeout) {
+ var __method = this, args = slice.call(arguments, 1);
+ timeout = timeout * 1000;
+ return window.setTimeout(function() {
+ return __method.apply(__method, args);
+ }, timeout);
+ }
+
+ function defer() {
+ var args = update([0.01], arguments);
+ return this.delay.apply(this, args);
+ }
+
+ function wrap(wrapper) {
+ var __method = this;
+ return function() {
+ var a = update([__method.bind(this)], arguments);
+ return wrapper.apply(this, a);
+ }
+ }
+
+ function methodize() {
+ if (this._methodized) return this._methodized;
+ var __method = this;
+ return this._methodized = function() {
+ var a = update([this], arguments);
+ return __method.apply(null, a);
+ };
+ }
+
+ var extensions = {
+ argumentNames: argumentNames,
+ bindAsEventListener: bindAsEventListener,
+ curry: curry,
+ delay: delay,
+ defer: defer,
+ wrap: wrap,
+ methodize: methodize
+ };
+
+ if (!Function.prototype.bind)
+ extensions.bind = bind;
+
+ return extensions;
+})());
+
+
+
+(function(proto) {
+
+
+ function toISOString() {
+ return this.getUTCFullYear() + '-' +
+ (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
+ this.getUTCDate().toPaddedString(2) + 'T' +
+ this.getUTCHours().toPaddedString(2) + ':' +
+ this.getUTCMinutes().toPaddedString(2) + ':' +
+ this.getUTCSeconds().toPaddedString(2) + 'Z';
+ }
+
+
+ function toJSON() {
+ return this.toISOString();
+ }
+
+ if (!proto.toISOString) proto.toISOString = toISOString;
+ if (!proto.toJSON) proto.toJSON = toJSON;
+
+})(Date.prototype);
+
+
+RegExp.prototype.match = RegExp.prototype.test;
+
+RegExp.escape = function(str) {
+ return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
+};
+var PeriodicalExecuter = Class.create({
+ initialize: function(callback, frequency) {
+ this.callback = callback;
+ this.frequency = frequency;
+ this.currentlyExecuting = false;
+
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ execute: function() {
+ this.callback(this);
+ },
+
+ stop: function() {
+ if (!this.timer) return;
+ clearInterval(this.timer);
+ this.timer = null;
+ },
+
+ onTimerEvent: function() {
+ if (!this.currentlyExecuting) {
+ try {
+ this.currentlyExecuting = true;
+ this.execute();
+ this.currentlyExecuting = false;
+ } catch(e) {
+ this.currentlyExecuting = false;
+ throw e;
+ }
+ }
+ }
+});
+Object.extend(String, {
+ interpret: function(value) {
+ return value == null ? '' : String(value);
+ },
+ specialChar: {
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '\\': '\\\\'
+ }
+});
+
+Object.extend(String.prototype, (function() {
+ var NATIVE_JSON_PARSE_SUPPORT = window.JSON &&
+ typeof JSON.parse === 'function' &&
+ JSON.parse('{"test": true}').test;
+
+ function prepareReplacement(replacement) {
+ if (Object.isFunction(replacement)) return replacement;
+ var template = new Template(replacement);
+ return function(match) { return template.evaluate(match) };
+ }
+
+ function gsub(pattern, replacement) {
+ var result = '', source = this, match;
+ replacement = prepareReplacement(replacement);
+
+ if (Object.isString(pattern))
+ pattern = RegExp.escape(pattern);
+
+ if (!(pattern.length || pattern.source)) {
+ replacement = replacement('');
+ return replacement + source.split('').join(replacement) + replacement;
+ }
+
+ while (source.length > 0) {
+ if (match = source.match(pattern)) {
+ result += source.slice(0, match.index);
+ result += String.interpret(replacement(match));
+ source = source.slice(match.index + match[0].length);
+ } else {
+ result += source, source = '';
+ }
+ }
+ return result;
+ }
+
+ function sub(pattern, replacement, count) {
+ replacement = prepareReplacement(replacement);
+ count = Object.isUndefined(count) ? 1 : count;
+
+ return this.gsub(pattern, function(match) {
+ if (--count < 0) return match[0];
+ return replacement(match);
+ });
+ }
+
+ function scan(pattern, iterator) {
+ this.gsub(pattern, iterator);
+ return String(this);
+ }
+
+ function truncate(length, truncation) {
+ length = length || 30;
+ truncation = Object.isUndefined(truncation) ? '...' : truncation;
+ return this.length > length ?
+ this.slice(0, length - truncation.length) + truncation : String(this);
+ }
+
+ function strip() {
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
+ }
+
+ function stripTags() {
+ return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, '');
+ }
+
+ function stripScripts() {
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+ }
+
+ function extractScripts() {
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img'),
+ matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+ return (this.match(matchAll) || []).map(function(scriptTag) {
+ return (scriptTag.match(matchOne) || ['', ''])[1];
+ });
+ }
+
+ function evalScripts() {
+ return this.extractScripts().map(function(script) { return eval(script); });
+ }
+
+ function escapeHTML() {
+ return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
+ }
+
+ function unescapeHTML() {
+ return this.stripTags().replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
+ }
+
+
+ function toQueryParams(separator) {
+ var match = this.strip().match(/([^?#]*)(#.*)?$/);
+ if (!match) return { };
+
+ return match[1].split(separator || '&').inject({ }, function(hash, pair) {
+ if ((pair = pair.split('='))[0]) {
+ var key = decodeURIComponent(pair.shift()),
+ value = pair.length > 1 ? pair.join('=') : pair[0];
+
+ if (value != undefined) value = decodeURIComponent(value);
+
+ if (key in hash) {
+ if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
+ hash[key].push(value);
+ }
+ else hash[key] = value;
+ }
+ return hash;
+ });
+ }
+
+ function toArray() {
+ return this.split('');
+ }
+
+ function succ() {
+ return this.slice(0, this.length - 1) +
+ String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
+ }
+
+ function times(count) {
+ return count < 1 ? '' : new Array(count + 1).join(this);
+ }
+
+ function camelize() {
+ return this.replace(/-+(.)?/g, function(match, chr) {
+ return chr ? chr.toUpperCase() : '';
+ });
+ }
+
+ function capitalize() {
+ return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
+ }
+
+ function underscore() {
+ return this.replace(/::/g, '/')
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
+ .replace(/([a-z\d])([A-Z])/g, '$1_$2')
+ .replace(/-/g, '_')
+ .toLowerCase();
+ }
+
+ function dasherize() {
+ return this.replace(/_/g, '-');
+ }
+
+ function inspect(useDoubleQuotes) {
+ var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) {
+ if (character in String.specialChar) {
+ return String.specialChar[character];
+ }
+ return '\\u00' + character.charCodeAt().toPaddedString(2, 16);
+ });
+ if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+ }
+
+ function unfilterJSON(filter) {
+ return this.replace(filter || Prototype.JSONFilter, '$1');
+ }
+
+ function isJSON() {
+ var str = this;
+ if (str.blank()) return false;
+ str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
+ str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
+ str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
+ return (/^[\],:{}\s]*$/).test(str);
+ }
+
+ function evalJSON(sanitize) {
+ var json = this.unfilterJSON(),
+ cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
+ if (cx.test(json)) {
+ json = json.replace(cx, function (a) {
+ return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+ try {
+ if (!sanitize || json.isJSON()) return eval('(' + json + ')');
+ } catch (e) { }
+ throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
+ }
+
+ function parseJSON() {
+ var json = this.unfilterJSON();
+ return JSON.parse(json);
+ }
+
+ function include(pattern) {
+ return this.indexOf(pattern) > -1;
+ }
+
+ function startsWith(pattern) {
+ return this.lastIndexOf(pattern, 0) === 0;
+ }
+
+ function endsWith(pattern) {
+ var d = this.length - pattern.length;
+ return d >= 0 && this.indexOf(pattern, d) === d;
+ }
+
+ function empty() {
+ return this == '';
+ }
+
+ function blank() {
+ return /^\s*$/.test(this);
+ }
+
+ function interpolate(object, pattern) {
+ return new Template(this, pattern).evaluate(object);
+ }
+
+ return {
+ gsub: gsub,
+ sub: sub,
+ scan: scan,
+ truncate: truncate,
+ strip: String.prototype.trim || strip,
+ stripTags: stripTags,
+ stripScripts: stripScripts,
+ extractScripts: extractScripts,
+ evalScripts: evalScripts,
+ escapeHTML: escapeHTML,
+ unescapeHTML: unescapeHTML,
+ toQueryParams: toQueryParams,
+ parseQuery: toQueryParams,
+ toArray: toArray,
+ succ: succ,
+ times: times,
+ camelize: camelize,
+ capitalize: capitalize,
+ underscore: underscore,
+ dasherize: dasherize,
+ inspect: inspect,
+ unfilterJSON: unfilterJSON,
+ isJSON: isJSON,
+ evalJSON: NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON,
+ include: include,
+ startsWith: startsWith,
+ endsWith: endsWith,
+ empty: empty,
+ blank: blank,
+ interpolate: interpolate
+ };
+})());
+
+var Template = Class.create({
+ initialize: function(template, pattern) {
+ this.template = template.toString();
+ this.pattern = pattern || Template.Pattern;
+ },
+
+ evaluate: function(object) {
+ if (object && Object.isFunction(object.toTemplateReplacements))
+ object = object.toTemplateReplacements();
+
+ return this.template.gsub(this.pattern, function(match) {
+ if (object == null) return (match[1] + '');
+
+ var before = match[1] || '';
+ if (before == '\\') return match[2];
+
+ var ctx = object, expr = match[3],
+ pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
+
+ match = pattern.exec(expr);
+ if (match == null) return before;
+
+ while (match != null) {
+ var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1];
+ ctx = ctx[comp];
+ if (null == ctx || '' == match[3]) break;
+ expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
+ match = pattern.exec(expr);
+ }
+
+ return before + String.interpret(ctx);
+ });
+ }
+});
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+
+var $break = { };
+
+var Enumerable = (function() {
+ function each(iterator, context) {
+ try {
+ this._each(iterator, context);
+ } catch (e) {
+ if (e != $break) throw e;
+ }
+ return this;
+ }
+
+ function eachSlice(number, iterator, context) {
+ var index = -number, slices = [], array = this.toArray();
+ if (number < 1) return array;
+ while ((index += number) < array.length)
+ slices.push(array.slice(index, index+number));
+ return slices.collect(iterator, context);
+ }
+
+ function all(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var result = true;
+ this.each(function(value, index) {
+ result = result && !!iterator.call(context, value, index, this);
+ if (!result) throw $break;
+ }, this);
+ return result;
+ }
+
+ function any(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var result = false;
+ this.each(function(value, index) {
+ if (result = !!iterator.call(context, value, index, this))
+ throw $break;
+ }, this);
+ return result;
+ }
+
+ function collect(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var results = [];
+ this.each(function(value, index) {
+ results.push(iterator.call(context, value, index, this));
+ }, this);
+ return results;
+ }
+
+ function detect(iterator, context) {
+ var result;
+ this.each(function(value, index) {
+ if (iterator.call(context, value, index, this)) {
+ result = value;
+ throw $break;
+ }
+ }, this);
+ return result;
+ }
+
+ function findAll(iterator, context) {
+ var results = [];
+ this.each(function(value, index) {
+ if (iterator.call(context, value, index, this))
+ results.push(value);
+ }, this);
+ return results;
+ }
+
+ function grep(filter, iterator, context) {
+ iterator = iterator || Prototype.K;
+ var results = [];
+
+ if (Object.isString(filter))
+ filter = new RegExp(RegExp.escape(filter));
+
+ this.each(function(value, index) {
+ if (filter.match(value))
+ results.push(iterator.call(context, value, index, this));
+ }, this);
+ return results;
+ }
+
+ function include(object) {
+ if (Object.isFunction(this.indexOf))
+ if (this.indexOf(object) != -1) return true;
+
+ var found = false;
+ this.each(function(value) {
+ if (value == object) {
+ found = true;
+ throw $break;
+ }
+ });
+ return found;
+ }
+
+ function inGroupsOf(number, fillWith) {
+ fillWith = Object.isUndefined(fillWith) ? null : fillWith;
+ return this.eachSlice(number, function(slice) {
+ while(slice.length < number) slice.push(fillWith);
+ return slice;
+ });
+ }
+
+ function inject(memo, iterator, context) {
+ this.each(function(value, index) {
+ memo = iterator.call(context, memo, value, index, this);
+ }, this);
+ return memo;
+ }
+
+ function invoke(method) {
+ var args = $A(arguments).slice(1);
+ return this.map(function(value) {
+ return value[method].apply(value, args);
+ });
+ }
+
+ function max(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var result;
+ this.each(function(value, index) {
+ value = iterator.call(context, value, index, this);
+ if (result == null || value >= result)
+ result = value;
+ }, this);
+ return result;
+ }
+
+ function min(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var result;
+ this.each(function(value, index) {
+ value = iterator.call(context, value, index, this);
+ if (result == null || value < result)
+ result = value;
+ }, this);
+ return result;
+ }
+
+ function partition(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var trues = [], falses = [];
+ this.each(function(value, index) {
+ (iterator.call(context, value, index, this) ?
+ trues : falses).push(value);
+ }, this);
+ return [trues, falses];
+ }
+
+ function pluck(property) {
+ var results = [];
+ this.each(function(value) {
+ results.push(value[property]);
+ });
+ return results;
+ }
+
+ function reject(iterator, context) {
+ var results = [];
+ this.each(function(value, index) {
+ if (!iterator.call(context, value, index, this))
+ results.push(value);
+ }, this);
+ return results;
+ }
+
+ function sortBy(iterator, context) {
+ return this.map(function(value, index) {
+ return {
+ value: value,
+ criteria: iterator.call(context, value, index, this)
+ };
+ }, this).sort(function(left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ }).pluck('value');
+ }
+
+ function toArray() {
+ return this.map();
+ }
+
+ function zip() {
+ var iterator = Prototype.K, args = $A(arguments);
+ if (Object.isFunction(args.last()))
+ iterator = args.pop();
+
+ var collections = [this].concat(args).map($A);
+ return this.map(function(value, index) {
+ return iterator(collections.pluck(index));
+ });
+ }
+
+ function size() {
+ return this.toArray().length;
+ }
+
+ function inspect() {
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
+ }
+
+
+
+
+
+
+
+
+
+ return {
+ each: each,
+ eachSlice: eachSlice,
+ all: all,
+ every: all,
+ any: any,
+ some: any,
+ collect: collect,
+ map: collect,
+ detect: detect,
+ findAll: findAll,
+ select: findAll,
+ filter: findAll,
+ grep: grep,
+ include: include,
+ member: include,
+ inGroupsOf: inGroupsOf,
+ inject: inject,
+ invoke: invoke,
+ max: max,
+ min: min,
+ partition: partition,
+ pluck: pluck,
+ reject: reject,
+ sortBy: sortBy,
+ toArray: toArray,
+ entries: toArray,
+ zip: zip,
+ size: size,
+ inspect: inspect,
+ find: detect
+ };
+})();
+
+function $A(iterable) {
+ if (!iterable) return [];
+ if ('toArray' in Object(iterable)) return iterable.toArray();
+ var length = iterable.length || 0, results = new Array(length);
+ while (length--) results[length] = iterable[length];
+ return results;
+}
+
+
+function $w(string) {
+ if (!Object.isString(string)) return [];
+ string = string.strip();
+ return string ? string.split(/\s+/) : [];
+}
+
+Array.from = $A;
+
+
+(function() {
+ var arrayProto = Array.prototype,
+ slice = arrayProto.slice,
+ _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available
+
+ function each(iterator, context) {
+ for (var i = 0, length = this.length >>> 0; i < length; i++) {
+ if (i in this) iterator.call(context, this[i], i, this);
+ }
+ }
+ if (!_each) _each = each;
+
+ function clear() {
+ this.length = 0;
+ return this;
+ }
+
+ function first() {
+ return this[0];
+ }
+
+ function last() {
+ return this[this.length - 1];
+ }
+
+ function compact() {
+ return this.select(function(value) {
+ return value != null;
+ });
+ }
+
+ function flatten() {
+ return this.inject([], function(array, value) {
+ if (Object.isArray(value))
+ return array.concat(value.flatten());
+ array.push(value);
+ return array;
+ });
+ }
+
+ function without() {
+ var values = slice.call(arguments, 0);
+ return this.select(function(value) {
+ return !values.include(value);
+ });
+ }
+
+ function reverse(inline) {
+ return (inline === false ? this.toArray() : this)._reverse();
+ }
+
+ function uniq(sorted) {
+ return this.inject([], function(array, value, index) {
+ if (0 == index || (sorted ? array.last() != value : !array.include(value)))
+ array.push(value);
+ return array;
+ });
+ }
+
+ function intersect(array) {
+ return this.uniq().findAll(function(item) {
+ return array.indexOf(item) !== -1;
+ });
+ }
+
+
+ function clone() {
+ return slice.call(this, 0);
+ }
+
+ function size() {
+ return this.length;
+ }
+
+ function inspect() {
+ return '[' + this.map(Object.inspect).join(', ') + ']';
+ }
+
+ function indexOf(item, i) {
+ if (this == null) throw new TypeError();
+
+ var array = Object(this), length = array.length >>> 0;
+ if (length === 0) return -1;
+
+ i = Number(i);
+ if (isNaN(i)) {
+ i = 0;
+ } else if (i !== 0 && isFinite(i)) {
+ i = (i > 0 ? 1 : -1) * Math.floor(Math.abs(i));
+ }
+
+ if (i > length) return -1;
+
+ var k = i >= 0 ? i : Math.max(length - Math.abs(i), 0);
+ for (; k < length; k++)
+ if (k in array && array[k] === item) return k;
+ return -1;
+ }
+
+
+ function lastIndexOf(item, i) {
+ if (this == null) throw new TypeError();
+
+ var array = Object(this), length = array.length >>> 0;
+ if (length === 0) return -1;
+
+ if (!Object.isUndefined(i)) {
+ i = Number(i);
+ if (isNaN(i)) {
+ i = 0;
+ } else if (i !== 0 && isFinite(i)) {
+ i = (i > 0 ? 1 : -1) * Math.floor(Math.abs(i));
+ }
+ } else {
+ i = length;
+ }
+
+ var k = i >= 0 ? Math.min(i, length - 1) :
+ length - Math.abs(i);
+
+ for (; k >= 0; k--)
+ if (k in array && array[k] === item) return k;
+ return -1;
+ }
+
+ function concat(_) {
+ var array = [], items = slice.call(arguments, 0), item, n = 0;
+ items.unshift(this);
+ for (var i = 0, length = items.length; i < length; i++) {
+ item = items[i];
+ if (Object.isArray(item) && !('callee' in item)) {
+ for (var j = 0, arrayLength = item.length; j < arrayLength; j++) {
+ if (j in item) array[n] = item[j];
+ n++;
+ }
+ } else {
+ array[n++] = item;
+ }
+ }
+ array.length = n;
+ return array;
+ }
+
+
+ function wrapNative(method) {
+ return function() {
+ if (arguments.length === 0) {
+ return method.call(this, Prototype.K);
+ } else if (arguments[0] === undefined) {
+ var args = slice.call(arguments, 1);
+ args.unshift(Prototype.K);
+ return method.apply(this, args);
+ } else {
+ return method.apply(this, arguments);
+ }
+ };
+ }
+
+
+ function map(iterator) {
+ if (this == null) throw new TypeError();
+ iterator = iterator || Prototype.K;
+
+ var object = Object(this);
+ var results = [], context = arguments[1], n = 0;
+
+ for (var i = 0, length = object.length >>> 0; i < length; i++) {
+ if (i in object) {
+ results[n] = iterator.call(context, object[i], i, object);
+ }
+ n++;
+ }
+ results.length = n;
+ return results;
+ }
+
+ if (arrayProto.map) {
+ map = wrapNative(Array.prototype.map);
+ }
+
+ function filter(iterator) {
+ if (this == null || !Object.isFunction(iterator))
+ throw new TypeError();
+
+ var object = Object(this);
+ var results = [], context = arguments[1], value;
+
+ for (var i = 0, length = object.length >>> 0; i < length; i++) {
+ if (i in object) {
+ value = object[i];
+ if (iterator.call(context, value, i, object)) {
+ results.push(value);
+ }
+ }
+ }
+ return results;
+ }
+
+ if (arrayProto.filter) {
+ filter = Array.prototype.filter;
+ }
+
+ function some(iterator) {
+ if (this == null) throw new TypeError();
+ iterator = iterator || Prototype.K;
+ var context = arguments[1];
+
+ var object = Object(this);
+ for (var i = 0, length = object.length >>> 0; i < length; i++) {
+ if (i in object && iterator.call(context, object[i], i, object)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ if (arrayProto.some) {
+ var some = wrapNative(Array.prototype.some);
+ }
+
+
+ function every(iterator) {
+ if (this == null) throw new TypeError();
+ iterator = iterator || Prototype.K;
+ var context = arguments[1];
+
+ var object = Object(this);
+ for (var i = 0, length = object.length >>> 0; i < length; i++) {
+ if (i in object && !iterator.call(context, object[i], i, object)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ if (arrayProto.every) {
+ var every = wrapNative(Array.prototype.every);
+ }
+
+ var _reduce = arrayProto.reduce;
+ function inject(memo, iterator) {
+ iterator = iterator || Prototype.K;
+ var context = arguments[2];
+ return _reduce.call(this, iterator.bind(context), memo);
+ }
+
+ if (!arrayProto.reduce) {
+ var inject = Enumerable.inject;
+ }
+
+ Object.extend(arrayProto, Enumerable);
+
+ if (!arrayProto._reverse)
+ arrayProto._reverse = arrayProto.reverse;
+
+ Object.extend(arrayProto, {
+ _each: _each,
+
+ map: map,
+ collect: map,
+ select: filter,
+ filter: filter,
+ findAll: filter,
+ some: some,
+ any: some,
+ every: every,
+ all: every,
+ inject: inject,
+
+ clear: clear,
+ first: first,
+ last: last,
+ compact: compact,
+ flatten: flatten,
+ without: without,
+ reverse: reverse,
+ uniq: uniq,
+ intersect: intersect,
+ clone: clone,
+ toArray: clone,
+ size: size,
+ inspect: inspect
+ });
+
+ var CONCAT_ARGUMENTS_BUGGY = (function() {
+ return [].concat(arguments)[0][0] !== 1;
+ })(1,2);
+
+ if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;
+
+ if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;
+ if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf;
+})();
+function $H(object) {
+ return new Hash(object);
+};
+
+var Hash = Class.create(Enumerable, (function() {
+ function initialize(object) {
+ this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
+ }
+
+
+ function _each(iterator, context) {
+ for (var key in this._object) {
+ var value = this._object[key], pair = [key, value];
+ pair.key = key;
+ pair.value = value;
+ iterator.call(context, pair);
+ }
+ }
+
+ function set(key, value) {
+ return this._object[key] = value;
+ }
+
+ function get(key) {
+ if (this._object[key] !== Object.prototype[key])
+ return this._object[key];
+ }
+
+ function unset(key) {
+ var value = this._object[key];
+ delete this._object[key];
+ return value;
+ }
+
+ function toObject() {
+ return Object.clone(this._object);
+ }
+
+
+
+ function keys() {
+ return this.pluck('key');
+ }
+
+ function values() {
+ return this.pluck('value');
+ }
+
+ function index(value) {
+ var match = this.detect(function(pair) {
+ return pair.value === value;
+ });
+ return match && match.key;
+ }
+
+ function merge(object) {
+ return this.clone().update(object);
+ }
+
+ function update(object) {
+ return new Hash(object).inject(this, function(result, pair) {
+ result.set(pair.key, pair.value);
+ return result;
+ });
+ }
+
+ function toQueryPair(key, value) {
+ if (Object.isUndefined(value)) return key;
+
+ var value = String.interpret(value);
+
+ value = value.gsub(/(\r)?\n/, '\r\n');
+ value = encodeURIComponent(value);
+ value = value.gsub(/%20/, '+');
+ return key + '=' + value;
+ }
+
+ function toQueryString() {
+ return this.inject([], function(results, pair) {
+ var key = encodeURIComponent(pair.key), values = pair.value;
+
+ if (values && typeof values == 'object') {
+ if (Object.isArray(values)) {
+ var queryValues = [];
+ for (var i = 0, len = values.length, value; i < len; i++) {
+ value = values[i];
+ queryValues.push(toQueryPair(key, value));
+ }
+ return results.concat(queryValues);
+ }
+ } else results.push(toQueryPair(key, values));
+ return results;
+ }).join('&');
+ }
+
+ function inspect() {
+ return '#<Hash:{' + this.map(function(pair) {
+ return pair.map(Object.inspect).join(': ');
+ }).join(', ') + '}>';
+ }
+
+ function clone() {
+ return new Hash(this);
+ }
+
+ return {
+ initialize: initialize,
+ _each: _each,
+ set: set,
+ get: get,
+ unset: unset,
+ toObject: toObject,
+ toTemplateReplacements: toObject,
+ keys: keys,
+ values: values,
+ index: index,
+ merge: merge,
+ update: update,
+ toQueryString: toQueryString,
+ inspect: inspect,
+ toJSON: toObject,
+ clone: clone
+ };
+})());
+
+Hash.from = $H;
+Object.extend(Number.prototype, (function() {
+ function toColorPart() {
+ return this.toPaddedString(2, 16);
+ }
+
+ function succ() {
+ return this + 1;
+ }
+
+ function times(iterator, context) {
+ $R(0, this, true).each(iterator, context);
+ return this;
+ }
+
+ function toPaddedString(length, radix) {
+ var string = this.toString(radix || 10);
+ return '0'.times(length - string.length) + string;
+ }
+
+ function abs() {
+ return Math.abs(this);
+ }
+
+ function round() {
+ return Math.round(this);
+ }
+
+ function ceil() {
+ return Math.ceil(this);
+ }
+
+ function floor() {
+ return Math.floor(this);
+ }
+
+ return {
+ toColorPart: toColorPart,
+ succ: succ,
+ times: times,
+ toPaddedString: toPaddedString,
+ abs: abs,
+ round: round,
+ ceil: ceil,
+ floor: floor
+ };
+})());
+
+function $R(start, end, exclusive) {
+ return new ObjectRange(start, end, exclusive);
+}
+
+var ObjectRange = Class.create(Enumerable, (function() {
+ function initialize(start, end, exclusive) {
+ this.start = start;
+ this.end = end;
+ this.exclusive = exclusive;
+ }
+
+ function _each(iterator, context) {
+ var value = this.start;
+ while (this.include(value)) {
+ iterator.call(context, value);
+ value = value.succ();
+ }
+ }
+
+ function include(value) {
+ if (value < this.start)
+ return false;
+ if (this.exclusive)
+ return value < this.end;
+ return value <= this.end;
+ }
+
+ return {
+ initialize: initialize,
+ _each: _each,
+ include: include
+ };
+})());
+
+
+
+var Abstract = { };
+
+
+var Try = {
+ these: function() {
+ var returnValue;
+
+ for (var i = 0, length = arguments.length; i < length; i++) {
+ var lambda = arguments[i];
+ try {
+ returnValue = lambda();
+ break;
+ } catch (e) { }
+ }
+
+ return returnValue;
+ }
+};
+
+var Ajax = {
+ getTransport: function() {
+ return Try.these(
+ function() {return new XMLHttpRequest()},
+ function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')}
+ ) || false;
+ },
+
+ activeRequestCount: 0
+};
+
+Ajax.Responders = {
+ responders: [],
+
+ _each: function(iterator, context) {
+ this.responders._each(iterator, context);
+ },
+
+ register: function(responder) {
+ if (!this.include(responder))
+ this.responders.push(responder);
+ },
+
+ unregister: function(responder) {
+ this.responders = this.responders.without(responder);
+ },
+
+ dispatch: function(callback, request, transport, json) {
+ this.each(function(responder) {
+ if (Object.isFunction(responder[callback])) {
+ try {
+ responder[callback].apply(responder, [request, transport, json]);
+ } catch (e) { }
+ }
+ });
+ }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+ onCreate: function() { Ajax.activeRequestCount++ },
+ onComplete: function() { Ajax.activeRequestCount-- }
+});
+Ajax.Base = Class.create({
+ initialize: function(options) {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ contentType: 'application/x-www-form-urlencoded',
+ encoding: 'UTF-8',
+ parameters: '',
+ evalJSON: true,
+ evalJS: true
+ };
+ Object.extend(this.options, options || { });
+
+ this.options.method = this.options.method.toLowerCase();
+
+ if (Object.isHash(this.options.parameters))
+ this.options.parameters = this.options.parameters.toObject();
+ }
+});
+Ajax.Request = Class.create(Ajax.Base, {
+ _complete: false,
+
+ initialize: function($super, url, options) {
+ $super(options);
+ this.transport = Ajax.getTransport();
+ this.request(url);
+ },
+
+ request: function(url) {
+ this.url = url;
+ this.method = this.options.method;
+ var params = Object.isString(this.options.parameters) ?
+ this.options.parameters :
+ Object.toQueryString(this.options.parameters);
+
+ if (!['get', 'post'].include(this.method)) {
+ params += (params ? '&' : '') + "_method=" + this.method;
+ this.method = 'post';
+ }
+
+ if (params && this.method === 'get') {
+ this.url += (this.url.include('?') ? '&' : '?') + params;
+ }
+
+ this.parameters = params.toQueryParams();
+
+ try {
+ var response = new Ajax.Response(this);
+ if (this.options.onCreate) this.options.onCreate(response);
+ Ajax.Responders.dispatch('onCreate', this, response);
+
+ this.transport.open(this.method.toUpperCase(), this.url,
+ this.options.asynchronous);
+
+ if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
+
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
+ this.setRequestHeaders();
+
+ this.body = this.method == 'post' ? (this.options.postBody || params) : null;
+ this.transport.send(this.body);
+
+ /* Force Firefox to handle ready state 4 for synchronous requests */
+ if (!this.options.asynchronous && this.transport.overrideMimeType)
+ this.onStateChange();
+
+ }
+ catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState > 1 && !((readyState == 4) && this._complete))
+ this.respondToReadyState(this.transport.readyState);
+ },
+
+ setRequestHeaders: function() {
+ var headers = {
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'X-Prototype-Version': Prototype.Version,
+ 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+ };
+
+ if (this.method == 'post') {
+ headers['Content-type'] = this.options.contentType +
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+ /* Force "Connection: close" for older Mozilla browsers to work
+ * around a bug where XMLHttpRequest sends an incorrect
+ * Content-length header. See Mozilla Bugzilla #246651.
+ */
+ if (this.transport.overrideMimeType &&
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+ headers['Connection'] = 'close';
+ }
+
+ if (typeof this.options.requestHeaders == 'object') {
+ var extras = this.options.requestHeaders;
+
+ if (Object.isFunction(extras.push))
+ for (var i = 0, length = extras.length; i < length; i += 2)
+ headers[extras[i]] = extras[i+1];
+ else
+ $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+ }
+
+ for (var name in headers)
+ this.transport.setRequestHeader(name, headers[name]);
+ },
+
+ success: function() {
+ var status = this.getStatus();
+ return !status || (status >= 200 && status < 300) || status == 304;
+ },
+
+ getStatus: function() {
+ try {
+ if (this.transport.status === 1223) return 204;
+ return this.transport.status || 0;
+ } catch (e) { return 0 }
+ },
+
+ respondToReadyState: function(readyState) {
+ var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
+
+ if (state == 'Complete') {
+ try {
+ this._complete = true;
+ (this.options['on' + response.status]
+ || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+ || Prototype.emptyFunction)(response, response.headerJSON);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ var contentType = response.getHeader('Content-type');
+ if (this.options.evalJS == 'force'
+ || (this.options.evalJS && this.isSameOrigin() && contentType
+ && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
+ this.evalResponse();
+ }
+
+ try {
+ (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
+ Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if (state == 'Complete') {
+ this.transport.onreadystatechange = Prototype.emptyFunction;
+ }
+ },
+
+ isSameOrigin: function() {
+ var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
+ return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
+ protocol: location.protocol,
+ domain: document.domain,
+ port: location.port ? ':' + location.port : ''
+ }));
+ },
+
+ getHeader: function(name) {
+ try {
+ return this.transport.getResponseHeader(name) || null;
+ } catch (e) { return null; }
+ },
+
+ evalResponse: function() {
+ try {
+ return eval((this.transport.responseText || '').unfilterJSON());
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ dispatchException: function(exception) {
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
+ Ajax.Responders.dispatch('onException', this, exception);
+ }
+});
+
+Ajax.Request.Events =
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+
+
+
+
+
+
+
+Ajax.Response = Class.create({
+ initialize: function(request){
+ this.request = request;
+ var transport = this.transport = request.transport,
+ readyState = this.readyState = transport.readyState;
+
+ if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
+ this.status = this.getStatus();
+ this.statusText = this.getStatusText();
+ this.responseText = String.interpret(transport.responseText);
+ this.headerJSON = this._getHeaderJSON();
+ }
+
+ if (readyState == 4) {
+ var xml = transport.responseXML;
+ this.responseXML = Object.isUndefined(xml) ? null : xml;
+ this.responseJSON = this._getResponseJSON();
+ }
+ },
+
+ status: 0,
+
+ statusText: '',
+
+ getStatus: Ajax.Request.prototype.getStatus,
+
+ getStatusText: function() {
+ try {
+ return this.transport.statusText || '';
+ } catch (e) { return '' }
+ },
+
+ getHeader: Ajax.Request.prototype.getHeader,
+
+ getAllHeaders: function() {
+ try {
+ return this.getAllResponseHeaders();
+ } catch (e) { return null }
+ },
+
+ getResponseHeader: function(name) {
+ return this.transport.getResponseHeader(name);
+ },
+
+ getAllResponseHeaders: function() {
+ return this.transport.getAllResponseHeaders();
+ },
+
+ _getHeaderJSON: function() {
+ var json = this.getHeader('X-JSON');
+ if (!json) return null;
+
+ try {
+ json = decodeURIComponent(escape(json));
+ } catch(e) {
+ }
+
+ try {
+ return json.evalJSON(this.request.options.sanitizeJSON ||
+ !this.request.isSameOrigin());
+ } catch (e) {
+ this.request.dispatchException(e);
+ }
+ },
+
+ _getResponseJSON: function() {
+ var options = this.request.options;
+ if (!options.evalJSON || (options.evalJSON != 'force' &&
+ !(this.getHeader('Content-type') || '').include('application/json')) ||
+ this.responseText.blank())
+ return null;
+ try {
+ return this.responseText.evalJSON(options.sanitizeJSON ||
+ !this.request.isSameOrigin());
+ } catch (e) {
+ this.request.dispatchException(e);
+ }
+ }
+});
+
+Ajax.Updater = Class.create(Ajax.Request, {
+ initialize: function($super, container, url, options) {
+ this.container = {
+ success: (container.success || container),
+ failure: (container.failure || (container.success ? null : container))
+ };
+
+ options = Object.clone(options);
+ var onComplete = options.onComplete;
+ options.onComplete = (function(response, json) {
+ this.updateContent(response.responseText);
+ if (Object.isFunction(onComplete)) onComplete(response, json);
+ }).bind(this);
+
+ $super(url, options);
+ },
+
+ updateContent: function(responseText) {
+ var receiver = this.container[this.success() ? 'success' : 'failure'],
+ options = this.options;
+
+ if (!options.evalScripts) responseText = responseText.stripScripts();
+
+ if (receiver = $(receiver)) {
+ if (options.insertion) {
+ if (Object.isString(options.insertion)) {
+ var insertion = { }; insertion[options.insertion] = responseText;
+ receiver.insert(insertion);
+ }
+ else options.insertion(receiver, responseText);
+ }
+ else receiver.update(responseText);
+ }
+ }
+});
+
+Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
+ initialize: function($super, container, url, options) {
+ $super(options);
+ this.onComplete = this.options.onComplete;
+
+ this.frequency = (this.options.frequency || 2);
+ this.decay = (this.options.decay || 1);
+
+ this.updater = { };
+ this.container = container;
+ this.url = url;
+
+ this.start();
+ },
+
+ start: function() {
+ this.options.onComplete = this.updateComplete.bind(this);
+ this.onTimerEvent();
+ },
+
+ stop: function() {
+ this.updater.options.onComplete = undefined;
+ clearTimeout(this.timer);
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+ },
+
+ updateComplete: function(response) {
+ if (this.options.decay) {
+ this.decay = (response.responseText == this.lastText ?
+ this.decay * this.options.decay : 1);
+
+ this.lastText = response.responseText;
+ }
+ this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
+ },
+
+ onTimerEvent: function() {
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
+ }
+});
+
+(function(GLOBAL) {
+
+ var UNDEFINED;
+ var SLICE = Array.prototype.slice;
+
+ var DIV = document.createElement('div');
+
+
+ function $(element) {
+ if (arguments.length > 1) {
+ for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+ elements.push($(arguments[i]));
+ return elements;
+ }
+
+ if (Object.isString(element))
+ element = document.getElementById(element);
+ return Element.extend(element);
+ }
+
+ GLOBAL.$ = $;
+
+
+ if (!GLOBAL.Node) GLOBAL.Node = {};
+
+ if (!GLOBAL.Node.ELEMENT_NODE) {
+ Object.extend(GLOBAL.Node, {
+ ELEMENT_NODE: 1,
+ ATTRIBUTE_NODE: 2,
+ TEXT_NODE: 3,
+ CDATA_SECTION_NODE: 4,
+ ENTITY_REFERENCE_NODE: 5,
+ ENTITY_NODE: 6,
+ PROCESSING_INSTRUCTION_NODE: 7,
+ COMMENT_NODE: 8,
+ DOCUMENT_NODE: 9,
+ DOCUMENT_TYPE_NODE: 10,
+ DOCUMENT_FRAGMENT_NODE: 11,
+ NOTATION_NODE: 12
+ });
+ }
+
+ var ELEMENT_CACHE = {};
+
+ function shouldUseCreationCache(tagName, attributes) {
+ if (tagName === 'select') return false;
+ if ('type' in attributes) return false;
+ return true;
+ }
+
+ var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){
+ try {
+ var el = document.createElement('<input name="x">');
+ return el.tagName.toLowerCase() === 'input' && el.name === 'x';
+ }
+ catch(err) {
+ return false;
+ }
+ })();
+
+
+ var oldElement = GLOBAL.Element;
+ function Element(tagName, attributes) {
+ attributes = attributes || {};
+ tagName = tagName.toLowerCase();
+
+ if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) {
+ tagName = '<' + tagName + ' name="' + attributes.name + '">';
+ delete attributes.name;
+ return Element.writeAttribute(document.createElement(tagName), attributes);
+ }
+
+ if (!ELEMENT_CACHE[tagName])
+ ELEMENT_CACHE[tagName] = Element.extend(document.createElement(tagName));
+
+ var node = shouldUseCreationCache(tagName, attributes) ?
+ ELEMENT_CACHE[tagName].cloneNode(false) : document.createElement(tagName);
+
+ return Element.writeAttribute(node, attributes);
+ }
+
+ GLOBAL.Element = Element;
+
+ Object.extend(GLOBAL.Element, oldElement || {});
+ if (oldElement) GLOBAL.Element.prototype = oldElement.prototype;
+
+ Element.Methods = { ByTag: {}, Simulated: {} };
+
+ var methods = {};
+
+ var INSPECT_ATTRIBUTES = { id: 'id', className: 'class' };
+ function inspect(element) {
+ element = $(element);
+ var result = '<' + element.tagName.toLowerCase();
+
+ var attribute, value;
+ for (var property in INSPECT_ATTRIBUTES) {
+ attribute = INSPECT_ATTRIBUTES[property];
+ value = (element[property] || '').toString();
+ if (value) result += ' ' + attribute + '=' + value.inspect(true);
+ }
+
+ return result + '>';
+ }
+
+ methods.inspect = inspect;
+
+
+ function visible(element) {
+ return $(element).style.display !== 'none';
+ }
+
+ function toggle(element, bool) {
+ element = $(element);
+ if (Object.isUndefined(bool))
+ bool = !Element.visible(element);
+ Element[bool ? 'show' : 'hide'](element);
+
+ return element;
+ }
+
+ function hide(element) {
+ element = $(element);
+ element.style.display = 'none';
+ return element;
+ }
+
+ function show(element) {
+ element = $(element);
+ element.style.display = '';
+ return element;
+ }
+
+
+ Object.extend(methods, {
+ visible: visible,
+ toggle: toggle,
+ hide: hide,
+ show: show
+ });
+
+
+ function remove(element) {
+ element = $(element);
+ element.parentNode.removeChild(element);
+ return element;
+ }
+
+ var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){
+ var el = document.createElement("select"),
+ isBuggy = true;
+ el.innerHTML = "<option value=\"test\">test</option>";
+ if (el.options && el.options[0]) {
+ isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
+ }
+ el = null;
+ return isBuggy;
+ })();
+
+ var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){
+ try {
+ var el = document.createElement("table");
+ if (el && el.tBodies) {
+ el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
+ var isBuggy = typeof el.tBodies[0] == "undefined";
+ el = null;
+ return isBuggy;
+ }
+ } catch (e) {
+ return true;
+ }
+ })();
+
+ var LINK_ELEMENT_INNERHTML_BUGGY = (function() {
+ try {
+ var el = document.createElement('div');
+ el.innerHTML = "<link />";
+ var isBuggy = (el.childNodes.length === 0);
+ el = null;
+ return isBuggy;
+ } catch(e) {
+ return true;
+ }
+ })();
+
+ var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY ||
+ TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY;
+
+ var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
+ var s = document.createElement("script"),
+ isBuggy = false;
+ try {
+ s.appendChild(document.createTextNode(""));
+ isBuggy = !s.firstChild ||
+ s.firstChild && s.firstChild.nodeType !== 3;
+ } catch (e) {
+ isBuggy = true;
+ }
+ s = null;
+ return isBuggy;
+ })();
+
+ function update(element, content) {
+ element = $(element);
+
+ var descendants = element.getElementsByTagName('*'),
+ i = descendants.length;
+ while (i--) purgeElement(descendants[i]);
+
+ if (content && content.toElement)
+ content = content.toElement();
+
+ if (Object.isElement(content))
+ return element.update().insert(content);
+
+
+ content = Object.toHTML(content);
+ var tagName = element.tagName.toUpperCase();
+
+ if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
+ element.text = content;
+ return element;
+ }
+
+ if (ANY_INNERHTML_BUGGY) {
+ if (tagName in INSERTION_TRANSLATIONS.tags) {
+ while (element.firstChild)
+ element.removeChild(element.firstChild);
+
+ var nodes = getContentFromAnonymousElement(tagName, content.stripScripts());
+ for (var i = 0, node; node = nodes[i]; i++)
+ element.appendChild(node);
+
+ } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf('<link') > -1) {
+ while (element.firstChild)
+ element.removeChild(element.firstChild);
+
+ var nodes = getContentFromAnonymousElement(tagName,
+ content.stripScripts(), true);
+
+ for (var i = 0, node; node = nodes[i]; i++)
+ element.appendChild(node);
+ } else {
+ element.innerHTML = content.stripScripts();
+ }
+ } else {
+ element.innerHTML = content.stripScripts();
+ }
+
+ content.evalScripts.bind(content).defer();
+ return element;
+ }
+
+ function replace(element, content) {
+ element = $(element);
+
+ if (content && content.toElement) {
+ content = content.toElement();
+ } else if (!Object.isElement(content)) {
+ content = Object.toHTML(content);
+ var range = element.ownerDocument.createRange();
+ range.selectNode(element);
+ content.evalScripts.bind(content).defer();
+ content = range.createContextualFragment(content.stripScripts());
+ }
+
+ element.parentNode.replaceChild(content, element);
+ return element;
+ }
+
+ var INSERTION_TRANSLATIONS = {
+ before: function(element, node) {
+ element.parentNode.insertBefore(node, element);
+ },
+ top: function(element, node) {
+ element.insertBefore(node, element.firstChild);
+ },
+ bottom: function(element, node) {
+ element.appendChild(node);
+ },
+ after: function(element, node) {
+ element.parentNode.insertBefore(node, element.nextSibling);
+ },
+
+ tags: {
+ TABLE: ['<table>', '</table>', 1],
+ TBODY: ['<table><tbody>', '</tbody></table>', 2],
+ TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
+ TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
+ SELECT: ['<select>', '</select>', 1]
+ }
+ };
+
+ var tags = INSERTION_TRANSLATIONS.tags;
+
+ Object.extend(tags, {
+ THEAD: tags.TBODY,
+ TFOOT: tags.TBODY,
+ TH: tags.TD
+ });
+
+ function replace_IE(element, content) {
+ element = $(element);
+ if (content && content.toElement)
+ content = content.toElement();
+ if (Object.isElement(content)) {
+ element.parentNode.replaceChild(content, element);
+ return element;
+ }
+
+ content = Object.toHTML(content);
+ var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
+
+ if (tagName in INSERTION_TRANSLATIONS.tags) {
+ var nextSibling = Element.next(element);
+ var fragments = getContentFromAnonymousElement(
+ tagName, content.stripScripts());
+
+ parent.removeChild(element);
+
+ var iterator;
+ if (nextSibling)
+ iterator = function(node) { parent.insertBefore(node, nextSibling) };
+ else
+ iterator = function(node) { parent.appendChild(node); }
+
+ fragments.each(iterator);
+ } else {
+ element.outerHTML = content.stripScripts();
+ }
+
+ content.evalScripts.bind(content).defer();
+ return element;
+ }
+
+ if ('outerHTML' in document.documentElement)
+ replace = replace_IE;
+
+ function isContent(content) {
+ if (Object.isUndefined(content) || content === null) return false;
+
+ if (Object.isString(content) || Object.isNumber(content)) return true;
+ if (Object.isElement(content)) return true;
+ if (content.toElement || content.toHTML) return true;
+
+ return false;
+ }
+
+ function insertContentAt(element, content, position) {
+ position = position.toLowerCase();
+ var method = INSERTION_TRANSLATIONS[position];
+
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) {
+ method(element, content);
+ return element;
+ }
+
+ content = Object.toHTML(content);
+ var tagName = ((position === 'before' || position === 'after') ?
+ element.parentNode : element).tagName.toUpperCase();
+
+ var childNodes = getContentFromAnonymousElement(tagName, content.stripScripts());
+
+ if (position === 'top' || position === 'after') childNodes.reverse();
+
+ for (var i = 0, node; node = childNodes[i]; i++)
+ method(element, node);
+
+ content.evalScripts.bind(content).defer();
+ }
+
+ function insert(element, insertions) {
+ element = $(element);
+
+ if (isContent(insertions))
+ insertions = { bottom: insertions };
+
+ for (var position in insertions)
+ insertContentAt(element, insertions[position], position);
+
+ return element;
+ }
+
+ function wrap(element, wrapper, attributes) {
+ element = $(element);
+
+ if (Object.isElement(wrapper)) {
+ $(wrapper).writeAttribute(attributes || {});
+ } else if (Object.isString(wrapper)) {
+ wrapper = new Element(wrapper, attributes);
+ } else {
+ wrapper = new Element('div', wrapper);
+ }
+
+ if (element.parentNode)
+ element.parentNode.replaceChild(wrapper, element);
+
+ wrapper.appendChild(element);
+
+ return wrapper;
+ }
+
+ function cleanWhitespace(element) {
+ element = $(element);
+ var node = element.firstChild;
+
+ while (node) {
+ var nextNode = node.nextSibling;
+ if (node.nodeType === Node.TEXT_NODE && !/\S/.test(node.nodeValue))
+ element.removeChild(node);
+ node = nextNode;
+ }
+ return element;
+ }
+
+ function empty(element) {
+ return $(element).innerHTML.blank();
+ }
+
+ function getContentFromAnonymousElement(tagName, html, force) {
+ var t = INSERTION_TRANSLATIONS.tags[tagName], div = DIV;
+
+ var workaround = !!t;
+ if (!workaround && force) {
+ workaround = true;
+ t = ['', '', 0];
+ }
+
+ if (workaround) {
+ div.innerHTML = '&#160;' + t[0] + html + t[1];
+ div.removeChild(div.firstChild);
+ for (var i = t[2]; i--; )
+ div = div.firstChild;
+ } else {
+ div.innerHTML = html;
+ }
+
+ return $A(div.childNodes);
+ }
+
+ function clone(element, deep) {
+ if (!(element = $(element))) return;
+ var clone = element.cloneNode(deep);
+ if (!HAS_UNIQUE_ID_PROPERTY) {
+ clone._prototypeUID = UNDEFINED;
+ if (deep) {
+ var descendants = Element.select(clone, '*'),
+ i = descendants.length;
+ while (i--)
+ descendants[i]._prototypeUID = UNDEFINED;
+ }
+ }
+ return Element.extend(clone);
+ }
+
+ function purgeElement(element) {
+ var uid = getUniqueElementID(element);
+ if (uid) {
+ Element.stopObserving(element);
+ if (!HAS_UNIQUE_ID_PROPERTY)
+ element._prototypeUID = UNDEFINED;
+ delete Element.Storage[uid];
+ }
+ }
+
+ function purgeCollection(elements) {
+ var i = elements.length;
+ while (i--)
+ purgeElement(elements[i]);
+ }
+
+ function purgeCollection_IE(elements) {
+ var i = elements.length, element, uid;
+ while (i--) {
+ element = elements[i];
+ uid = getUniqueElementID(element);
+ delete Element.Storage[uid];
+ delete Event.cache[uid];
+ }
+ }
+
+ if (HAS_UNIQUE_ID_PROPERTY) {
+ purgeCollection = purgeCollection_IE;
+ }
+
+
+ function purge(element) {
+ if (!(element = $(element))) return;
+ purgeElement(element);
+
+ var descendants = element.getElementsByTagName('*'),
+ i = descendants.length;
+
+ while (i--) purgeElement(descendants[i]);
+
+ return null;
+ }
+
+ Object.extend(methods, {
+ remove: remove,
+ update: update,
+ replace: replace,
+ insert: insert,
+ wrap: wrap,
+ cleanWhitespace: cleanWhitespace,
+ empty: empty,
+ clone: clone,
+ purge: purge
+ });
+
+
+
+ function recursivelyCollect(element, property, maximumLength) {
+ element = $(element);
+ maximumLength = maximumLength || -1;
+ var elements = [];
+
+ while (element = element[property]) {
+ if (element.nodeType === Node.ELEMENT_NODE)
+ elements.push(Element.extend(element));
+
+ if (elements.length === maximumLength) break;
+ }
+
+ return elements;
+ }
+
+
+ function ancestors(element) {
+ return recursivelyCollect(element, 'parentNode');
+ }
+
+ function descendants(element) {
+ return Element.select(element, '*');
+ }
+
+ function firstDescendant(element) {
+ element = $(element).firstChild;
+ while (element && element.nodeType !== Node.ELEMENT_NODE)
+ element = element.nextSibling;
+
+ return $(element);
+ }
+
+ function immediateDescendants(element) {
+ var results = [], child = $(element).firstChild;
+
+ while (child) {
+ if (child.nodeType === Node.ELEMENT_NODE)
+ results.push(Element.extend(child));
+
+ child = child.nextSibling;
+ }
+
+ return results;
+ }
+
+ function previousSiblings(element) {
+ return recursivelyCollect(element, 'previousSibling');
+ }
+
+ function nextSiblings(element) {
+ return recursivelyCollect(element, 'nextSibling');
+ }
+
+ function siblings(element) {
+ element = $(element);
+ var previous = previousSiblings(element),
+ next = nextSiblings(element);
+ return previous.reverse().concat(next);
+ }
+
+ function match(element, selector) {
+ element = $(element);
+
+ if (Object.isString(selector))
+ return Prototype.Selector.match(element, selector);
+
+ return selector.match(element);
+ }
+
+
+ function _recursivelyFind(element, property, expression, index) {
+ element = $(element), expression = expression || 0, index = index || 0;
+ if (Object.isNumber(expression)) {
+ index = expression, expression = null;
+ }
+
+ while (element = element[property]) {
+ if (element.nodeType !== 1) continue;
+ if (expression && !Prototype.Selector.match(element, expression))
+ continue;
+ if (--index >= 0) continue;
+
+ return Element.extend(element);
+ }
+ }
+
+
+ function up(element, expression, index) {
+ element = $(element);
+
+ if (arguments.length === 1) return $(element.parentNode);
+ return _recursivelyFind(element, 'parentNode', expression, index);
+ }
+
+ function down(element, expression, index) {
+ element = $(element), expression = expression || 0, index = index || 0;
+
+ if (Object.isNumber(expression))
+ index = expression, expression = '*';
+
+ var node = Prototype.Selector.select(expression, element)[index];
+ return Element.extend(node);
+ }
+
+ function previous(element, expression, index) {
+ return _recursivelyFind(element, 'previousSibling', expression, index);
+ }
+
+ function next(element, expression, index) {
+ return _recursivelyFind(element, 'nextSibling', expression, index);
+ }
+
+ function select(element) {
+ element = $(element);
+ var expressions = SLICE.call(arguments, 1).join(', ');
+ return Prototype.Selector.select(expressions, element);
+ }
+
+ function adjacent(element) {
+ element = $(element);
+ var expressions = SLICE.call(arguments, 1).join(', ');
+ var siblings = Element.siblings(element), results = [];
+ for (var i = 0, sibling; sibling = siblings[i]; i++) {
+ if (Prototype.Selector.match(sibling, expressions))
+ results.push(sibling);
+ }
+
+ return results;
+ }
+
+ function descendantOf_DOM(element, ancestor) {
+ element = $(element), ancestor = $(ancestor);
+ while (element = element.parentNode)
+ if (element === ancestor) return true;
+ return false;
+ }
+
+ function descendantOf_contains(element, ancestor) {
+ element = $(element), ancestor = $(ancestor);
+ if (!ancestor.contains) return descendantOf_DOM(element, ancestor);
+ return ancestor.contains(element) && ancestor !== element;
+ }
+
+ function descendantOf_compareDocumentPosition(element, ancestor) {
+ element = $(element), ancestor = $(ancestor);
+ return (element.compareDocumentPosition(ancestor) & 8) === 8;
+ }
+
+ var descendantOf;
+ if (DIV.compareDocumentPosition) {
+ descendantOf = descendantOf_compareDocumentPosition;
+ } else if (DIV.contains) {
+ descendantOf = descendantOf_contains;
+ } else {
+ descendantOf = descendantOf_DOM;
+ }
+
+
+ Object.extend(methods, {
+ recursivelyCollect: recursivelyCollect,
+ ancestors: ancestors,
+ descendants: descendants,
+ firstDescendant: firstDescendant,
+ immediateDescendants: immediateDescendants,
+ previousSiblings: previousSiblings,
+ nextSiblings: nextSiblings,
+ siblings: siblings,
+ match: match,
+ up: up,
+ down: down,
+ previous: previous,
+ next: next,
+ select: select,
+ adjacent: adjacent,
+ descendantOf: descendantOf,
+
+ getElementsBySelector: select,
+
+ childElements: immediateDescendants
+ });
+
+
+ var idCounter = 1;
+ function identify(element) {
+ element = $(element);
+ var id = Element.readAttribute(element, 'id');
+ if (id) return id;
+
+ do { id = 'anonymous_element_' + idCounter++ } while ($(id));
+
+ Element.writeAttribute(element, 'id', id);
+ return id;
+ }
+
+
+ function readAttribute(element, name) {
+ return $(element).getAttribute(name);
+ }
+
+ function readAttribute_IE(element, name) {
+ element = $(element);
+
+ var table = ATTRIBUTE_TRANSLATIONS.read;
+ if (table.values[name])
+ return table.values[name](element, name);
+
+ if (table.names[name]) name = table.names[name];
+
+ if (name.include(':')) {
+ if (!element.attributes || !element.attributes[name]) return null;
+ return element.attributes[name].value;
+ }
+
+ return element.getAttribute(name);
+ }
+
+ function readAttribute_Opera(element, name) {
+ if (name === 'title') return element.title;
+ return element.getAttribute(name);
+ }
+
+ var PROBLEMATIC_ATTRIBUTE_READING = (function() {
+ // This test used to set 'onclick' to `Prototype.emptyFunction`, but that
+ // caused an (uncatchable) error in IE 10. For some reason, switching to
+ // an empty array prevents this issue.
+ DIV.setAttribute('onclick', []);
+ var value = DIV.getAttribute('onclick');
+ var isFunction = Object.isArray(value);
+ DIV.removeAttribute('onclick');
+ return isFunction;
+ })();
+
+ if (PROBLEMATIC_ATTRIBUTE_READING) {
+ readAttribute = readAttribute_IE;
+ } else if (Prototype.Browser.Opera) {
+ readAttribute = readAttribute_Opera;
+ }
+
+
+ function writeAttribute(element, name, value) {
+ element = $(element);
+ var attributes = {}, table = ATTRIBUTE_TRANSLATIONS.write;
+
+ if (typeof name === 'object') {
+ attributes = name;
+ } else {
+ attributes[name] = Object.isUndefined(value) ? true : value;
+ }
+
+ for (var attr in attributes) {
+ name = table.names[attr] || attr;
+ value = attributes[attr];
+ if (table.values[attr])
+ name = table.values[attr](element, value);
+ if (value === false || value === null)
+ element.removeAttribute(name);
+ else if (value === true)
+ element.setAttribute(name, name);
+ else element.setAttribute(name, value);
+ }
+
+ return element;
+ }
+
+ function hasAttribute(element, attribute) {
+ attribute = ATTRIBUTE_TRANSLATIONS.has[attribute] || attribute;
+ var node = $(element).getAttributeNode(attribute);
+ return !!(node && node.specified);
+ }
+
+ GLOBAL.Element.Methods.Simulated.hasAttribute = hasAttribute;
+
+ function classNames(element) {
+ return new Element.ClassNames(element);
+ }
+
+ var regExpCache = {};
+ function getRegExpForClassName(className) {
+ if (regExpCache[className]) return regExpCache[className];
+
+ var re = new RegExp("(^|\\s+)" + className + "(\\s+|$)");
+ regExpCache[className] = re;
+ return re;
+ }
+
+ function hasClassName(element, className) {
+ if (!(element = $(element))) return;
+
+ var elementClassName = element.className;
+
+ if (elementClassName.length === 0) return false;
+ if (elementClassName === className) return true;
+
+ return getRegExpForClassName(className).test(elementClassName);
+ }
+
+ function addClassName(element, className) {
+ if (!(element = $(element))) return;
+
+ if (!hasClassName(element, className))
+ element.className += (element.className ? ' ' : '') + className;
+
+ return element;
+ }
+
+ function removeClassName(element, className) {
+ if (!(element = $(element))) return;
+
+ element.className = element.className.replace(
+ getRegExpForClassName(className), ' ').strip();
+
+ return element;
+ }
+
+ function toggleClassName(element, className, bool) {
+ if (!(element = $(element))) return;
+
+ if (Object.isUndefined(bool))
+ bool = !hasClassName(element, className);
+
+ var method = Element[bool ? 'addClassName' : 'removeClassName'];
+ return method(element, className);
+ }
+
+ var ATTRIBUTE_TRANSLATIONS = {};
+
+ var classProp = 'className', forProp = 'for';
+
+ DIV.setAttribute(classProp, 'x');
+ if (DIV.className !== 'x') {
+ DIV.setAttribute('class', 'x');
+ if (DIV.className === 'x')
+ classProp = 'class';
+ }
+
+ var LABEL = document.createElement('label');
+ LABEL.setAttribute(forProp, 'x');
+ if (LABEL.htmlFor !== 'x') {
+ LABEL.setAttribute('htmlFor', 'x');
+ if (LABEL.htmlFor === 'x')
+ forProp = 'htmlFor';
+ }
+ LABEL = null;
+
+ function _getAttr(element, attribute) {
+ return element.getAttribute(attribute);
+ }
+
+ function _getAttr2(element, attribute) {
+ return element.getAttribute(attribute, 2);
+ }
+
+ function _getAttrNode(element, attribute) {
+ var node = element.getAttributeNode(attribute);
+ return node ? node.value : '';
+ }
+
+ function _getFlag(element, attribute) {
+ return $(element).hasAttribute(attribute) ? attribute : null;
+ }
+
+ DIV.onclick = Prototype.emptyFunction;
+ var onclickValue = DIV.getAttribute('onclick');
+
+ var _getEv;
+
+ if (String(onclickValue).indexOf('{') > -1) {
+ _getEv = function(element, attribute) {
+ var value = element.getAttribute(attribute);
+ if (!value) return null;
+ value = value.toString();
+ value = value.split('{')[1];
+ value = value.split('}')[0];
+ return value.strip();
+ };
+ }
+ else if (onclickValue === '') {
+ _getEv = function(element, attribute) {
+ var value = element.getAttribute(attribute);
+ if (!value) return null;
+ return value.strip();
+ };
+ }
+
+ ATTRIBUTE_TRANSLATIONS.read = {
+ names: {
+ 'class': classProp,
+ 'className': classProp,
+ 'for': forProp,
+ 'htmlFor': forProp
+ },
+
+ values: {
+ style: function(element) {
+ return element.style.cssText.toLowerCase();
+ },
+ title: function(element) {
+ return element.title;
+ }
+ }
+ };
+
+ ATTRIBUTE_TRANSLATIONS.write = {
+ names: {
+ className: 'class',
+ htmlFor: 'for',
+ cellpadding: 'cellPadding',
+ cellspacing: 'cellSpacing'
+ },
+
+ values: {
+ checked: function(element, value) {
+ element.checked = !!value;
+ },
+
+ style: function(element, value) {
+ element.style.cssText = value ? value : '';
+ }
+ }
+ };
+
+ ATTRIBUTE_TRANSLATIONS.has = { names: {} };
+
+ Object.extend(ATTRIBUTE_TRANSLATIONS.write.names,
+ ATTRIBUTE_TRANSLATIONS.read.names);
+
+ var CAMEL_CASED_ATTRIBUTE_NAMES = $w('colSpan rowSpan vAlign dateTime ' +
+ 'accessKey tabIndex encType maxLength readOnly longDesc frameBorder');
+
+ for (var i = 0, attr; attr = CAMEL_CASED_ATTRIBUTE_NAMES[i]; i++) {
+ ATTRIBUTE_TRANSLATIONS.write.names[attr.toLowerCase()] = attr;
+ ATTRIBUTE_TRANSLATIONS.has.names[attr.toLowerCase()] = attr;
+ }
+
+ Object.extend(ATTRIBUTE_TRANSLATIONS.read.values, {
+ href: _getAttr2,
+ src: _getAttr2,
+ type: _getAttr,
+ action: _getAttrNode,
+ disabled: _getFlag,
+ checked: _getFlag,
+ readonly: _getFlag,
+ multiple: _getFlag,
+ onload: _getEv,
+ onunload: _getEv,
+ onclick: _getEv,
+ ondblclick: _getEv,
+ onmousedown: _getEv,
+ onmouseup: _getEv,
+ onmouseover: _getEv,
+ onmousemove: _getEv,
+ onmouseout: _getEv,
+ onfocus: _getEv,
+ onblur: _getEv,
+ onkeypress: _getEv,
+ onkeydown: _getEv,
+ onkeyup: _getEv,
+ onsubmit: _getEv,
+ onreset: _getEv,
+ onselect: _getEv,
+ onchange: _getEv
+ });
+
+
+ Object.extend(methods, {
+ identify: identify,
+ readAttribute: readAttribute,
+ writeAttribute: writeAttribute,
+ classNames: classNames,
+ hasClassName: hasClassName,
+ addClassName: addClassName,
+ removeClassName: removeClassName,
+ toggleClassName: toggleClassName
+ });
+
+
+ function normalizeStyleName(style) {
+ if (style === 'float' || style === 'styleFloat')
+ return 'cssFloat';
+ return style.camelize();
+ }
+
+ function normalizeStyleName_IE(style) {
+ if (style === 'float' || style === 'cssFloat')
+ return 'styleFloat';
+ return style.camelize();
+ }
+
+ function setStyle(element, styles) {
+ element = $(element);
+ var elementStyle = element.style, match;
+
+ if (Object.isString(styles)) {
+ elementStyle.cssText += ';' + styles;
+ if (styles.include('opacity')) {
+ var opacity = styles.match(/opacity:\s*(\d?\.?\d*)/)[1];
+ Element.setOpacity(element, opacity);
+ }
+ return element;
+ }
+
+ for (var property in styles) {
+ if (property === 'opacity') {
+ Element.setOpacity(element, styles[property]);
+ } else {
+ var value = styles[property];
+ if (property === 'float' || property === 'cssFloat') {
+ property = Object.isUndefined(elementStyle.styleFloat) ?
+ 'cssFloat' : 'styleFloat';
+ }
+ elementStyle[property] = value;
+ }
+ }
+
+ return element;
+ }
+
+
+ function getStyle(element, style) {
+ element = $(element);
+ style = normalizeStyleName(style);
+
+ var value = element.style[style];
+ if (!value || value === 'auto') {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css[style] : null;
+ }
+
+ if (style === 'opacity') return value ? parseFloat(value) : 1.0;
+ return value === 'auto' ? null : value;
+ }
+
+ function getStyle_Opera(element, style) {
+ switch (style) {
+ case 'height': case 'width':
+ if (!Element.visible(element)) return null;
+
+ var dim = parseInt(getStyle(element, style), 10);
+
+ if (dim !== element['offset' + style.capitalize()])
+ return dim + 'px';
+
+ return Element.measure(element, style);
+
+ default: return getStyle(element, style);
+ }
+ }
+
+ function getStyle_IE(element, style) {
+ element = $(element);
+ style = normalizeStyleName_IE(style);
+
+ var value = element.style[style];
+ if (!value && element.currentStyle) {
+ value = element.currentStyle[style];
+ }
+
+ if (style === 'opacity' && !STANDARD_CSS_OPACITY_SUPPORTED)
+ return getOpacity_IE(element);
+
+ if (value === 'auto') {
+ if ((style === 'width' || style === 'height') && Element.visible(element))
+ return Element.measure(element, style) + 'px';
+ return null;
+ }
+
+ return value;
+ }
+
+ function stripAlphaFromFilter_IE(filter) {
+ return (filter || '').replace(/alpha\([^\)]*\)/gi, '');
+ }
+
+ function hasLayout_IE(element) {
+ if (!element.currentStyle.hasLayout)
+ element.style.zoom = 1;
+ return element;
+ }
+
+ var STANDARD_CSS_OPACITY_SUPPORTED = (function() {
+ DIV.style.cssText = "opacity:.55";
+ return /^0.55/.test(DIV.style.opacity);
+ })();
+
+ function setOpacity(element, value) {
+ element = $(element);
+ if (value == 1 || value === '') value = '';
+ else if (value < 0.00001) value = 0;
+ element.style.opacity = value;
+ return element;
+ }
+
+ function setOpacity_IE(element, value) {
+ if (STANDARD_CSS_OPACITY_SUPPORTED)
+ return setOpacity(element, value);
+
+ element = hasLayout_IE($(element));
+ var filter = Element.getStyle(element, 'filter'),
+ style = element.style;
+
+ if (value == 1 || value === '') {
+ filter = stripAlphaFromFilter_IE(filter);
+ if (filter) style.filter = filter;
+ else style.removeAttribute('filter');
+ return element;
+ }
+
+ if (value < 0.00001) value = 0;
+
+ style.filter = stripAlphaFromFilter_IE(filter) +
+ 'alpha(opacity=' + (value * 100) + ')';
+
+ return element;
+ }
+
+
+ function getOpacity(element) {
+ return Element.getStyle(element, 'opacity');
+ }
+
+ function getOpacity_IE(element) {
+ if (STANDARD_CSS_OPACITY_SUPPORTED)
+ return getOpacity(element);
+
+ var filter = Element.getStyle(element, 'filter');
+ if (filter.length === 0) return 1.0;
+ var match = (filter || '').match(/alpha\(opacity=(.*)\)/);
+ if (match[1]) return parseFloat(match[1]) / 100;
+ return 1.0;
+ }
+
+
+ Object.extend(methods, {
+ setStyle: setStyle,
+ getStyle: getStyle,
+ setOpacity: setOpacity,
+ getOpacity: getOpacity
+ });
+
+ if ('styleFloat' in DIV.style) {
+ methods.getStyle = getStyle_IE;
+ methods.setOpacity = setOpacity_IE;
+ methods.getOpacity = getOpacity_IE;
+ }
+
+ var UID = 0;
+
+ GLOBAL.Element.Storage = { UID: 1 };
+
+ function getUniqueElementID(element) {
+ if (element === window) return 0;
+
+ if (typeof element._prototypeUID === 'undefined')
+ element._prototypeUID = Element.Storage.UID++;
+ return element._prototypeUID;
+ }
+
+ function getUniqueElementID_IE(element) {
+ if (element === window) return 0;
+ if (element == document) return 1;
+ return element.uniqueID;
+ }
+
+ var HAS_UNIQUE_ID_PROPERTY = ('uniqueID' in DIV);
+ if (HAS_UNIQUE_ID_PROPERTY)
+ getUniqueElementID = getUniqueElementID_IE;
+
+ function getStorage(element) {
+ if (!(element = $(element))) return;
+
+ var uid = getUniqueElementID(element);
+
+ if (!Element.Storage[uid])
+ Element.Storage[uid] = $H();
+
+ return Element.Storage[uid];
+ }
+
+ function store(element, key, value) {
+ if (!(element = $(element))) return;
+ var storage = getStorage(element);
+ if (arguments.length === 2) {
+ storage.update(key);
+ } else {
+ storage.set(key, value);
+ }
+ return element;
+ }
+
+ function retrieve(element, key, defaultValue) {
+ if (!(element = $(element))) return;
+ var storage = getStorage(element), value = storage.get(key);
+
+ if (Object.isUndefined(value)) {
+ storage.set(key, defaultValue);
+ value = defaultValue;
+ }
+
+ return value;
+ }
+
+
+ Object.extend(methods, {
+ getStorage: getStorage,
+ store: store,
+ retrieve: retrieve
+ });
+
+
+ var Methods = {}, ByTag = Element.Methods.ByTag,
+ F = Prototype.BrowserFeatures;
+
+ if (!F.ElementExtensions && ('__proto__' in DIV)) {
+ GLOBAL.HTMLElement = {};
+ GLOBAL.HTMLElement.prototype = DIV['__proto__'];
+ F.ElementExtensions = true;
+ }
+
+ function checkElementPrototypeDeficiency(tagName) {
+ if (typeof window.Element === 'undefined') return false;
+ var proto = window.Element.prototype;
+ if (proto) {
+ var id = '_' + (Math.random() + '').slice(2),
+ el = document.createElement(tagName);
+ proto[id] = 'x';
+ var isBuggy = (el[id] !== 'x');
+ delete proto[id];
+ el = null;
+ return isBuggy;
+ }
+
+ return false;
+ }
+
+ var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY =
+ checkElementPrototypeDeficiency('object');
+
+ function extendElementWith(element, methods) {
+ for (var property in methods) {
+ var value = methods[property];
+ if (Object.isFunction(value) && !(property in element))
+ element[property] = value.methodize();
+ }
+ }
+
+ var EXTENDED = {};
+ function elementIsExtended(element) {
+ var uid = getUniqueElementID(element);
+ return (uid in EXTENDED);
+ }
+
+ function extend(element) {
+ if (!element || elementIsExtended(element)) return element;
+ if (element.nodeType !== Node.ELEMENT_NODE || element == window)
+ return element;
+
+ var methods = Object.clone(Methods),
+ tagName = element.tagName.toUpperCase();
+
+ if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
+
+ extendElementWith(element, methods);
+ EXTENDED[getUniqueElementID(element)] = true;
+ return element;
+ }
+
+ function extend_IE8(element) {
+ if (!element || elementIsExtended(element)) return element;
+
+ var t = element.tagName;
+ if (t && (/^(?:object|applet|embed)$/i.test(t))) {
+ extendElementWith(element, Element.Methods);
+ extendElementWith(element, Element.Methods.Simulated);
+ extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
+ }
+
+ return element;
+ }
+
+ if (F.SpecificElementExtensions) {
+ extend = HTMLOBJECTELEMENT_PROTOTYPE_BUGGY ? extend_IE8 : Prototype.K;
+ }
+
+ function addMethodsToTagName(tagName, methods) {
+ tagName = tagName.toUpperCase();
+ if (!ByTag[tagName]) ByTag[tagName] = {};
+ Object.extend(ByTag[tagName], methods);
+ }
+
+ function mergeMethods(destination, methods, onlyIfAbsent) {
+ if (Object.isUndefined(onlyIfAbsent)) onlyIfAbsent = false;
+ for (var property in methods) {
+ var value = methods[property];
+ if (!Object.isFunction(value)) continue;
+ if (!onlyIfAbsent || !(property in destination))
+ destination[property] = value.methodize();
+ }
+ }
+
+ function findDOMClass(tagName) {
+ var klass;
+ var trans = {
+ "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
+ "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
+ "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
+ "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
+ "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
+ "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
+ "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
+ "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
+ "FrameSet", "IFRAME": "IFrame"
+ };
+ if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
+ if (window[klass]) return window[klass];
+ klass = 'HTML' + tagName + 'Element';
+ if (window[klass]) return window[klass];
+ klass = 'HTML' + tagName.capitalize() + 'Element';
+ if (window[klass]) return window[klass];
+
+ var element = document.createElement(tagName),
+ proto = element['__proto__'] || element.constructor.prototype;
+
+ element = null;
+ return proto;
+ }
+
+ function addMethods(methods) {
+ if (arguments.length === 0) addFormMethods();
+
+ if (arguments.length === 2) {
+ var tagName = methods;
+ methods = arguments[1];
+ }
+
+ if (!tagName) {
+ Object.extend(Element.Methods, methods || {});
+ } else {
+ if (Object.isArray(tagName)) {
+ for (var i = 0, tag; tag = tagName[i]; i++)
+ addMethodsToTagName(tag, methods);
+ } else {
+ addMethodsToTagName(tagName, methods);
+ }
+ }
+
+ var ELEMENT_PROTOTYPE = window.HTMLElement ? HTMLElement.prototype :
+ Element.prototype;
+
+ if (F.ElementExtensions) {
+ mergeMethods(ELEMENT_PROTOTYPE, Element.Methods);
+ mergeMethods(ELEMENT_PROTOTYPE, Element.Methods.Simulated, true);
+ }
+
+ if (F.SpecificElementExtensions) {
+ for (var tag in Element.Methods.ByTag) {
+ var klass = findDOMClass(tag);
+ if (Object.isUndefined(klass)) continue;
+ mergeMethods(klass.prototype, ByTag[tag]);
+ }
+ }
+
+ Object.extend(Element, Element.Methods);
+ Object.extend(Element, Element.Methods.Simulated);
+ delete Element.ByTag;
+ delete Element.Simulated;
+
+ Element.extend.refresh();
+
+ ELEMENT_CACHE = {};
+ }
+
+ Object.extend(GLOBAL.Element, {
+ extend: extend,
+ addMethods: addMethods
+ });
+
+ if (extend === Prototype.K) {
+ GLOBAL.Element.extend.refresh = Prototype.emptyFunction;
+ } else {
+ GLOBAL.Element.extend.refresh = function() {
+ if (Prototype.BrowserFeatures.ElementExtensions) return;
+ Object.extend(Methods, Element.Methods);
+ Object.extend(Methods, Element.Methods.Simulated);
+
+ EXTENDED = {};
+ };
+ }
+
+ function addFormMethods() {
+ Object.extend(Form, Form.Methods);
+ Object.extend(Form.Element, Form.Element.Methods);
+ Object.extend(Element.Methods.ByTag, {
+ "FORM": Object.clone(Form.Methods),
+ "INPUT": Object.clone(Form.Element.Methods),
+ "SELECT": Object.clone(Form.Element.Methods),
+ "TEXTAREA": Object.clone(Form.Element.Methods),
+ "BUTTON": Object.clone(Form.Element.Methods)
+ });
+ }
+
+ Element.addMethods(methods);
+
+})(this);
+(function() {
+
+ function toDecimal(pctString) {
+ var match = pctString.match(/^(\d+)%?$/i);
+ if (!match) return null;
+ return (Number(match[1]) / 100);
+ }
+
+ function getRawStyle(element, style) {
+ element = $(element);
+
+ var value = element.style[style];
+ if (!value || value === 'auto') {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css[style] : null;
+ }
+
+ if (style === 'opacity') return value ? parseFloat(value) : 1.0;
+ return value === 'auto' ? null : value;
+ }
+
+ function getRawStyle_IE(element, style) {
+ var value = element.style[style];
+ if (!value && element.currentStyle) {
+ value = element.currentStyle[style];
+ }
+ return value;
+ }
+
+ function getContentWidth(element, context) {
+ var boxWidth = element.offsetWidth;
+
+ var bl = getPixelValue(element, 'borderLeftWidth', context) || 0;
+ var br = getPixelValue(element, 'borderRightWidth', context) || 0;
+ var pl = getPixelValue(element, 'paddingLeft', context) || 0;
+ var pr = getPixelValue(element, 'paddingRight', context) || 0;
+
+ return boxWidth - bl - br - pl - pr;
+ }
+
+ if ('currentStyle' in document.documentElement) {
+ getRawStyle = getRawStyle_IE;
+ }
+
+
+ function getPixelValue(value, property, context) {
+ var element = null;
+ if (Object.isElement(value)) {
+ element = value;
+ value = getRawStyle(element, property);
+ }
+
+ if (value === null || Object.isUndefined(value)) {
+ return null;
+ }
+
+ if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) {
+ return window.parseFloat(value);
+ }
+
+ var isPercentage = value.include('%'), isViewport = (context === document.viewport);
+
+ if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) {
+ var style = element.style.left, rStyle = element.runtimeStyle.left;
+ element.runtimeStyle.left = element.currentStyle.left;
+ element.style.left = value || 0;
+ value = element.style.pixelLeft;
+ element.style.left = style;
+ element.runtimeStyle.left = rStyle;
+
+ return value;
+ }
+
+ if (element && isPercentage) {
+ context = context || element.parentNode;
+ var decimal = toDecimal(value), whole = null;
+
+ var isHorizontal = property.include('left') || property.include('right') ||
+ property.include('width');
+
+ var isVertical = property.include('top') || property.include('bottom') ||
+ property.include('height');
+
+ if (context === document.viewport) {
+ if (isHorizontal) {
+ whole = document.viewport.getWidth();
+ } else if (isVertical) {
+ whole = document.viewport.getHeight();
+ }
+ } else {
+ if (isHorizontal) {
+ whole = $(context).measure('width');
+ } else if (isVertical) {
+ whole = $(context).measure('height');
+ }
+ }
+
+ return (whole === null) ? 0 : whole * decimal;
+ }
+
+ return 0;
+ }
+
+ function toCSSPixels(number) {
+ if (Object.isString(number) && number.endsWith('px'))
+ return number;
+ return number + 'px';
+ }
+
+ function isDisplayed(element) {
+ while (element && element.parentNode) {
+ var display = element.getStyle('display');
+ if (display === 'none') {
+ return false;
+ }
+ element = $(element.parentNode);
+ }
+ return true;
+ }
+
+ var hasLayout = Prototype.K;
+ if ('currentStyle' in document.documentElement) {
+ hasLayout = function(element) {
+ if (!element.currentStyle.hasLayout) {
+ element.style.zoom = 1;
+ }
+ return element;
+ };
+ }
+
+ function cssNameFor(key) {
+ if (key.include('border')) key = key + '-width';
+ return key.camelize();
+ }
+
+ Element.Layout = Class.create(Hash, {
+ initialize: function($super, element, preCompute) {
+ $super();
+ this.element = $(element);
+
+ Element.Layout.PROPERTIES.each( function(property) {
+ this._set(property, null);
+ }, this);
+
+ if (preCompute) {
+ this._preComputing = true;
+ this._begin();
+ Element.Layout.PROPERTIES.each( this._compute, this );
+ this._end();
+ this._preComputing = false;
+ }
+ },
+
+ _set: function(property, value) {
+ return Hash.prototype.set.call(this, property, value);
+ },
+
+ set: function(property, value) {
+ throw "Properties of Element.Layout are read-only.";
+ },
+
+ get: function($super, property) {
+ var value = $super(property);
+ return value === null ? this._compute(property) : value;
+ },
+
+ _begin: function() {
+ if (this._isPrepared()) return;
+
+ var element = this.element;
+ if (isDisplayed(element)) {
+ this._setPrepared(true);
+ return;
+ }
+
+
+ var originalStyles = {
+ position: element.style.position || '',
+ width: element.style.width || '',
+ visibility: element.style.visibility || '',
+ display: element.style.display || ''
+ };
+
+ element.store('prototype_original_styles', originalStyles);
+
+ var position = getRawStyle(element, 'position'), width = element.offsetWidth;
+
+ if (width === 0 || width === null) {
+ element.style.display = 'block';
+ width = element.offsetWidth;
+ }
+
+ var context = (position === 'fixed') ? document.viewport :
+ element.parentNode;
+
+ var tempStyles = {
+ visibility: 'hidden',
+ display: 'block'
+ };
+
+ if (position !== 'fixed') tempStyles.position = 'absolute';
+
+ element.setStyle(tempStyles);
+
+ var positionedWidth = element.offsetWidth, newWidth;
+ if (width && (positionedWidth === width)) {
+ newWidth = getContentWidth(element, context);
+ } else if (position === 'absolute' || position === 'fixed') {
+ newWidth = getContentWidth(element, context);
+ } else {
+ var parent = element.parentNode, pLayout = $(parent).getLayout();
+
+ newWidth = pLayout.get('width') -
+ this.get('margin-left') -
+ this.get('border-left') -
+ this.get('padding-left') -
+ this.get('padding-right') -
+ this.get('border-right') -
+ this.get('margin-right');
+ }
+
+ element.setStyle({ width: newWidth + 'px' });
+
+ this._setPrepared(true);
+ },
+
+ _end: function() {
+ var element = this.element;
+ var originalStyles = element.retrieve('prototype_original_styles');
+ element.store('prototype_original_styles', null);
+ element.setStyle(originalStyles);
+ this._setPrepared(false);
+ },
+
+ _compute: function(property) {
+ var COMPUTATIONS = Element.Layout.COMPUTATIONS;
+ if (!(property in COMPUTATIONS)) {
+ throw "Property not found.";
+ }
+
+ return this._set(property, COMPUTATIONS[property].call(this, this.element));
+ },
+
+ _isPrepared: function() {
+ return this.element.retrieve('prototype_element_layout_prepared', false);
+ },
+
+ _setPrepared: function(bool) {
+ return this.element.store('prototype_element_layout_prepared', bool);
+ },
+
+ toObject: function() {
+ var args = $A(arguments);
+ var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
+ args.join(' ').split(' ');
+ var obj = {};
+ keys.each( function(key) {
+ if (!Element.Layout.PROPERTIES.include(key)) return;
+ var value = this.get(key);
+ if (value != null) obj[key] = value;
+ }, this);
+ return obj;
+ },
+
+ toHash: function() {
+ var obj = this.toObject.apply(this, arguments);
+ return new Hash(obj);
+ },
+
+ toCSS: function() {
+ var args = $A(arguments);
+ var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
+ args.join(' ').split(' ');
+ var css = {};
+
+ keys.each( function(key) {
+ if (!Element.Layout.PROPERTIES.include(key)) return;
+ if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return;
+
+ var value = this.get(key);
+ if (value != null) css[cssNameFor(key)] = value + 'px';
+ }, this);
+ return css;
+ },
+
+ inspect: function() {
+ return "#<Element.Layout>";
+ }
+ });
+
+ Object.extend(Element.Layout, {
+ PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'),
+
+ COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
+
+ COMPUTATIONS: {
+ 'height': function(element) {
+ if (!this._preComputing) this._begin();
+
+ var bHeight = this.get('border-box-height');
+ if (bHeight <= 0) {
+ if (!this._preComputing) this._end();
+ return 0;
+ }
+
+ var bTop = this.get('border-top'),
+ bBottom = this.get('border-bottom');
+
+ var pTop = this.get('padding-top'),
+ pBottom = this.get('padding-bottom');
+
+ if (!this._preComputing) this._end();
+
+ return bHeight - bTop - bBottom - pTop - pBottom;
+ },
+
+ 'width': function(element) {
+ if (!this._preComputing) this._begin();
+
+ var bWidth = this.get('border-box-width');
+ if (bWidth <= 0) {
+ if (!this._preComputing) this._end();
+ return 0;
+ }
+
+ var bLeft = this.get('border-left'),
+ bRight = this.get('border-right');
+
+ var pLeft = this.get('padding-left'),
+ pRight = this.get('padding-right');
+
+ if (!this._preComputing) this._end();
+ return bWidth - bLeft - bRight - pLeft - pRight;
+ },
+
+ 'padding-box-height': function(element) {
+ var height = this.get('height'),
+ pTop = this.get('padding-top'),
+ pBottom = this.get('padding-bottom');
+
+ return height + pTop + pBottom;
+ },
+
+ 'padding-box-width': function(element) {
+ var width = this.get('width'),
+ pLeft = this.get('padding-left'),
+ pRight = this.get('padding-right');
+
+ return width + pLeft + pRight;
+ },
+
+ 'border-box-height': function(element) {
+ if (!this._preComputing) this._begin();
+ var height = element.offsetHeight;
+ if (!this._preComputing) this._end();
+ return height;
+ },
+
+ 'border-box-width': function(element) {
+ if (!this._preComputing) this._begin();
+ var width = element.offsetWidth;
+ if (!this._preComputing) this._end();
+ return width;
+ },
+
+ 'margin-box-height': function(element) {
+ var bHeight = this.get('border-box-height'),
+ mTop = this.get('margin-top'),
+ mBottom = this.get('margin-bottom');
+
+ if (bHeight <= 0) return 0;
+
+ return bHeight + mTop + mBottom;
+ },
+
+ 'margin-box-width': function(element) {
+ var bWidth = this.get('border-box-width'),
+ mLeft = this.get('margin-left'),
+ mRight = this.get('margin-right');
+
+ if (bWidth <= 0) return 0;
+
+ return bWidth + mLeft + mRight;
+ },
+
+ 'top': function(element) {
+ var offset = element.positionedOffset();
+ return offset.top;
+ },
+
+ 'bottom': function(element) {
+ var offset = element.positionedOffset(),
+ parent = element.getOffsetParent(),
+ pHeight = parent.measure('height');
+
+ var mHeight = this.get('border-box-height');
+
+ return pHeight - mHeight - offset.top;
+ },
+
+ 'left': function(element) {
+ var offset = element.positionedOffset();
+ return offset.left;
+ },
+
+ 'right': function(element) {
+ var offset = element.positionedOffset(),
+ parent = element.getOffsetParent(),
+ pWidth = parent.measure('width');
+
+ var mWidth = this.get('border-box-width');
+
+ return pWidth - mWidth - offset.left;
+ },
+
+ 'padding-top': function(element) {
+ return getPixelValue(element, 'paddingTop');
+ },
+
+ 'padding-bottom': function(element) {
+ return getPixelValue(element, 'paddingBottom');
+ },
+
+ 'padding-left': function(element) {
+ return getPixelValue(element, 'paddingLeft');
+ },
+
+ 'padding-right': function(element) {
+ return getPixelValue(element, 'paddingRight');
+ },
+
+ 'border-top': function(element) {
+ return getPixelValue(element, 'borderTopWidth');
+ },
+
+ 'border-bottom': function(element) {
+ return getPixelValue(element, 'borderBottomWidth');
+ },
+
+ 'border-left': function(element) {
+ return getPixelValue(element, 'borderLeftWidth');
+ },
+
+ 'border-right': function(element) {
+ return getPixelValue(element, 'borderRightWidth');
+ },
+
+ 'margin-top': function(element) {
+ return getPixelValue(element, 'marginTop');
+ },
+
+ 'margin-bottom': function(element) {
+ return getPixelValue(element, 'marginBottom');
+ },
+
+ 'margin-left': function(element) {
+ return getPixelValue(element, 'marginLeft');
+ },
+
+ 'margin-right': function(element) {
+ return getPixelValue(element, 'marginRight');
+ }
+ }
+ });
+
+ if ('getBoundingClientRect' in document.documentElement) {
+ Object.extend(Element.Layout.COMPUTATIONS, {
+ 'right': function(element) {
+ var parent = hasLayout(element.getOffsetParent());
+ var rect = element.getBoundingClientRect(),
+ pRect = parent.getBoundingClientRect();
+
+ return (pRect.right - rect.right).round();
+ },
+
+ 'bottom': function(element) {
+ var parent = hasLayout(element.getOffsetParent());
+ var rect = element.getBoundingClientRect(),
+ pRect = parent.getBoundingClientRect();
+
+ return (pRect.bottom - rect.bottom).round();
+ }
+ });
+ }
+
+ Element.Offset = Class.create({
+ initialize: function(left, top) {
+ this.left = left.round();
+ this.top = top.round();
+
+ this[0] = this.left;
+ this[1] = this.top;
+ },
+
+ relativeTo: function(offset) {
+ return new Element.Offset(
+ this.left - offset.left,
+ this.top - offset.top
+ );
+ },
+
+ inspect: function() {
+ return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
+ },
+
+ toString: function() {
+ return "[#{left}, #{top}]".interpolate(this);
+ },
+
+ toArray: function() {
+ return [this.left, this.top];
+ }
+ });
+
+ function getLayout(element, preCompute) {
+ return new Element.Layout(element, preCompute);
+ }
+
+ function measure(element, property) {
+ return $(element).getLayout().get(property);
+ }
+
+ function getHeight(element) {
+ return Element.getDimensions(element).height;
+ }
+
+ function getWidth(element) {
+ return Element.getDimensions(element).width;
+ }
+
+ function getDimensions(element) {
+ element = $(element);
+ var display = Element.getStyle(element, 'display');
+
+ if (display && display !== 'none') {
+ return { width: element.offsetWidth, height: element.offsetHeight };
+ }
+
+ var style = element.style;
+ var originalStyles = {
+ visibility: style.visibility,
+ position: style.position,
+ display: style.display
+ };
+
+ var newStyles = {
+ visibility: 'hidden',
+ display: 'block'
+ };
+
+ if (originalStyles.position !== 'fixed')
+ newStyles.position = 'absolute';
+
+ Element.setStyle(element, newStyles);
+
+ var dimensions = {
+ width: element.offsetWidth,
+ height: element.offsetHeight
+ };
+
+ Element.setStyle(element, originalStyles);
+
+ return dimensions;
+ }
+
+ function getOffsetParent(element) {
+ element = $(element);
+
+ if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
+ return $(document.body);
+
+ var isInline = (Element.getStyle(element, 'display') === 'inline');
+ if (!isInline && element.offsetParent) return $(element.offsetParent);
+
+ while ((element = element.parentNode) && element !== document.body) {
+ if (Element.getStyle(element, 'position') !== 'static') {
+ return isHtml(element) ? $(document.body) : $(element);
+ }
+ }
+
+ return $(document.body);
+ }
+
+
+ function cumulativeOffset(element) {
+ element = $(element);
+ var valueT = 0, valueL = 0;
+ if (element.parentNode) {
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ } while (element);
+ }
+ return new Element.Offset(valueL, valueT);
+ }
+
+ function positionedOffset(element) {
+ element = $(element);
+
+ var layout = element.getLayout();
+
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ if (element) {
+ if (isBody(element)) break;
+ var p = Element.getStyle(element, 'position');
+ if (p !== 'static') break;
+ }
+ } while (element);
+
+ valueL -= layout.get('margin-top');
+ valueT -= layout.get('margin-left');
+
+ return new Element.Offset(valueL, valueT);
+ }
+
+ function cumulativeScrollOffset(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.scrollTop || 0;
+ valueL += element.scrollLeft || 0;
+ element = element.parentNode;
+ } while (element);
+ return new Element.Offset(valueL, valueT);
+ }
+
+ function viewportOffset(forElement) {
+ var valueT = 0, valueL = 0, docBody = document.body;
+
+ var element = $(forElement);
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ if (element.offsetParent == docBody &&
+ Element.getStyle(element, 'position') == 'absolute') break;
+ } while (element = element.offsetParent);
+
+ element = forElement;
+ do {
+ if (element != docBody) {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ }
+ } while (element = element.parentNode);
+ return new Element.Offset(valueL, valueT);
+ }
+
+ function absolutize(element) {
+ element = $(element);
+
+ if (Element.getStyle(element, 'position') === 'absolute') {
+ return element;
+ }
+
+ var offsetParent = getOffsetParent(element);
+ var eOffset = element.viewportOffset(),
+ pOffset = offsetParent.viewportOffset();
+
+ var offset = eOffset.relativeTo(pOffset);
+ var layout = element.getLayout();
+
+ element.store('prototype_absolutize_original_styles', {
+ left: element.getStyle('left'),
+ top: element.getStyle('top'),
+ width: element.getStyle('width'),
+ height: element.getStyle('height')
+ });
+
+ element.setStyle({
+ position: 'absolute',
+ top: offset.top + 'px',
+ left: offset.left + 'px',
+ width: layout.get('width') + 'px',
+ height: layout.get('height') + 'px'
+ });
+
+ return element;
+ }
+
+ function relativize(element) {
+ element = $(element);
+ if (Element.getStyle(element, 'position') === 'relative') {
+ return element;
+ }
+
+ var originalStyles =
+ element.retrieve('prototype_absolutize_original_styles');
+
+ if (originalStyles) element.setStyle(originalStyles);
+ return element;
+ }
+
+
+ function scrollTo(element) {
+ element = $(element);
+ var pos = Element.cumulativeOffset(element);
+ window.scrollTo(pos.left, pos.top);
+ return element;
+ }
+
+
+ function makePositioned(element) {
+ element = $(element);
+ var position = Element.getStyle(element, 'position'), styles = {};
+ if (position === 'static' || !position) {
+ styles.position = 'relative';
+ if (Prototype.Browser.Opera) {
+ styles.top = 0;
+ styles.left = 0;
+ }
+ Element.setStyle(element, styles);
+ Element.store(element, 'prototype_made_positioned', true);
+ }
+ return element;
+ }
+
+ function undoPositioned(element) {
+ element = $(element);
+ var storage = Element.getStorage(element),
+ madePositioned = storage.get('prototype_made_positioned');
+
+ if (madePositioned) {
+ storage.unset('prototype_made_positioned');
+ Element.setStyle(element, {
+ position: '',
+ top: '',
+ bottom: '',
+ left: '',
+ right: ''
+ });
+ }
+ return element;
+ }
+
+ function makeClipping(element) {
+ element = $(element);
+
+ var storage = Element.getStorage(element),
+ madeClipping = storage.get('prototype_made_clipping');
+
+ if (Object.isUndefined(madeClipping)) {
+ var overflow = Element.getStyle(element, 'overflow');
+ storage.set('prototype_made_clipping', overflow);
+ if (overflow !== 'hidden')
+ element.style.overflow = 'hidden';
+ }
+
+ return element;
+ }
+
+ function undoClipping(element) {
+ element = $(element);
+ var storage = Element.getStorage(element),
+ overflow = storage.get('prototype_made_clipping');
+
+ if (!Object.isUndefined(overflow)) {
+ storage.unset('prototype_made_clipping');
+ element.style.overflow = overflow || '';
+ }
+
+ return element;
+ }
+
+ function clonePosition(element, source, options) {
+ options = Object.extend({
+ setLeft: true,
+ setTop: true,
+ setWidth: true,
+ setHeight: true,
+ offsetTop: 0,
+ offsetLeft: 0
+ }, options || {});
+
+ source = $(source);
+ element = $(element);
+ var p, delta, layout, styles = {};
+
+ if (options.setLeft || options.setTop) {
+ p = Element.viewportOffset(source);
+ delta = [0, 0];
+ if (Element.getStyle(element, 'position') === 'absolute') {
+ var parent = Element.getOffsetParent(element);
+ if (parent !== document.body) delta = Element.viewportOffset(parent);
+ }
+ }
+
+ if (options.setWidth || options.setHeight) {
+ layout = Element.getLayout(source);
+ }
+
+ if (options.setLeft)
+ styles.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
+ if (options.setTop)
+ styles.top = (p[1] - delta[1] + options.offsetTop) + 'px';
+
+ if (options.setWidth)
+ styles.width = layout.get('border-box-width') + 'px';
+ if (options.setHeight)
+ styles.height = layout.get('border-box-height') + 'px';
+
+ return Element.setStyle(element, styles);
+ }
+
+
+ if (Prototype.Browser.IE) {
+ getOffsetParent = getOffsetParent.wrap(
+ function(proceed, element) {
+ element = $(element);
+
+ if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
+ return $(document.body);
+
+ var position = element.getStyle('position');
+ if (position !== 'static') return proceed(element);
+
+ element.setStyle({ position: 'relative' });
+ var value = proceed(element);
+ element.setStyle({ position: position });
+ return value;
+ }
+ );
+
+ positionedOffset = positionedOffset.wrap(function(proceed, element) {
+ element = $(element);
+ if (!element.parentNode) return new Element.Offset(0, 0);
+ var position = element.getStyle('position');
+ if (position !== 'static') return proceed(element);
+
+ var offsetParent = element.getOffsetParent();
+ if (offsetParent && offsetParent.getStyle('position') === 'fixed')
+ hasLayout(offsetParent);
+
+ element.setStyle({ position: 'relative' });
+ var value = proceed(element);
+ element.setStyle({ position: position });
+ return value;
+ });
+ } else if (Prototype.Browser.Webkit) {
+ cumulativeOffset = function(element) {
+ element = $(element);
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ if (element.offsetParent == document.body) {
+ if (Element.getStyle(element, 'position') == 'absolute') break;
+ }
+
+ element = element.offsetParent;
+ } while (element);
+
+ return new Element.Offset(valueL, valueT);
+ };
+ }
+
+
+ Element.addMethods({
+ getLayout: getLayout,
+ measure: measure,
+ getWidth: getWidth,
+ getHeight: getHeight,
+ getDimensions: getDimensions,
+ getOffsetParent: getOffsetParent,
+ cumulativeOffset: cumulativeOffset,
+ positionedOffset: positionedOffset,
+ cumulativeScrollOffset: cumulativeScrollOffset,
+ viewportOffset: viewportOffset,
+ absolutize: absolutize,
+ relativize: relativize,
+ scrollTo: scrollTo,
+ makePositioned: makePositioned,
+ undoPositioned: undoPositioned,
+ makeClipping: makeClipping,
+ undoClipping: undoClipping,
+ clonePosition: clonePosition
+ });
+
+ function isBody(element) {
+ return element.nodeName.toUpperCase() === 'BODY';
+ }
+
+ function isHtml(element) {
+ return element.nodeName.toUpperCase() === 'HTML';
+ }
+
+ function isDocument(element) {
+ return element.nodeType === Node.DOCUMENT_NODE;
+ }
+
+ function isDetached(element) {
+ return element !== document.body &&
+ !Element.descendantOf(element, document.body);
+ }
+
+ if ('getBoundingClientRect' in document.documentElement) {
+ Element.addMethods({
+ viewportOffset: function(element) {
+ element = $(element);
+ if (isDetached(element)) return new Element.Offset(0, 0);
+
+ var rect = element.getBoundingClientRect(),
+ docEl = document.documentElement;
+ return new Element.Offset(rect.left - docEl.clientLeft,
+ rect.top - docEl.clientTop);
+ }
+ });
+ }
+
+
+})();
+
+(function() {
+
+ var IS_OLD_OPERA = Prototype.Browser.Opera &&
+ (window.parseFloat(window.opera.version()) < 9.5);
+ var ROOT = null;
+ function getRootElement() {
+ if (ROOT) return ROOT;
+ ROOT = IS_OLD_OPERA ? document.body : document.documentElement;
+ return ROOT;
+ }
+
+ function getDimensions() {
+ return { width: this.getWidth(), height: this.getHeight() };
+ }
+
+ function getWidth() {
+ return getRootElement().clientWidth;
+ }
+
+ function getHeight() {
+ return getRootElement().clientHeight;
+ }
+
+ function getScrollOffsets() {
+ var x = window.pageXOffset || document.documentElement.scrollLeft ||
+ document.body.scrollLeft;
+ var y = window.pageYOffset || document.documentElement.scrollTop ||
+ document.body.scrollTop;
+
+ return new Element.Offset(x, y);
+ }
+
+ document.viewport = {
+ getDimensions: getDimensions,
+ getWidth: getWidth,
+ getHeight: getHeight,
+ getScrollOffsets: getScrollOffsets
+ };
+
+})();
+window.$$ = function() {
+ var expression = $A(arguments).join(', ');
+ return Prototype.Selector.select(expression, document);
+};
+
+Prototype.Selector = (function() {
+
+ function select() {
+ throw new Error('Method "Prototype.Selector.select" must be defined.');
+ }
+
+ function match() {
+ throw new Error('Method "Prototype.Selector.match" must be defined.');
+ }
+
+ function find(elements, expression, index) {
+ index = index || 0;
+ var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i;
+
+ for (i = 0; i < length; i++) {
+ if (match(elements[i], expression) && index == matchIndex++) {
+ return Element.extend(elements[i]);
+ }
+ }
+ }
+
+ function extendElements(elements) {
+ for (var i = 0, length = elements.length; i < length; i++) {
+ Element.extend(elements[i]);
+ }
+ return elements;
+ }
+
+
+ var K = Prototype.K;
+
+ return {
+ select: select,
+ match: match,
+ find: find,
+ extendElements: (Element.extend === K) ? K : extendElements,
+ extendElement: Element.extend
+ };
+})();
+/*!
+ * Sizzle CSS Selector Engine
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ * More information: http://sizzlejs.com/
+ */
+(function(){
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+ done = 0,
+ toString = Object.prototype.toString,
+ hasDuplicate = false,
+ baseHasDuplicate = true,
+ rBackslash = /\\/g,
+ rNonWord = /\W/;
+
+[0, 0].sort(function() {
+ baseHasDuplicate = false;
+ return 0;
+});
+
+var Sizzle = function( selector, context, results, seed ) {
+ results = results || [];
+ context = context || document;
+
+ var origContext = context;
+
+ if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ var m, set, checkSet, extra, ret, cur, pop, i,
+ prune = true,
+ contextXML = Sizzle.isXML( context ),
+ parts = [],
+ soFar = selector;
+
+ do {
+ chunker.exec( "" );
+ m = chunker.exec( soFar );
+
+ if ( m ) {
+ soFar = m[3];
+
+ parts.push( m[1] );
+
+ if ( m[2] ) {
+ extra = m[3];
+ break;
+ }
+ }
+ } while ( m );
+
+ if ( parts.length > 1 && origPOS.exec( selector ) ) {
+
+ if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+ set = posProcess( parts[0] + parts[1], context );
+
+ } else {
+ set = Expr.relative[ parts[0] ] ?
+ [ context ] :
+ Sizzle( parts.shift(), context );
+
+ while ( parts.length ) {
+ selector = parts.shift();
+
+ if ( Expr.relative[ selector ] ) {
+ selector += parts.shift();
+ }
+
+ set = posProcess( selector, set );
+ }
+ }
+
+ } else {
+ if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
+ Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
+
+ ret = Sizzle.find( parts.shift(), context, contextXML );
+ context = ret.expr ?
+ Sizzle.filter( ret.expr, ret.set )[0] :
+ ret.set[0];
+ }
+
+ if ( context ) {
+ ret = seed ?
+ { expr: parts.pop(), set: makeArray(seed) } :
+ Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
+
+ set = ret.expr ?
+ Sizzle.filter( ret.expr, ret.set ) :
+ ret.set;
+
+ if ( parts.length > 0 ) {
+ checkSet = makeArray( set );
+
+ } else {
+ prune = false;
+ }
+
+ while ( parts.length ) {
+ cur = parts.pop();
+ pop = cur;
+
+ if ( !Expr.relative[ cur ] ) {
+ cur = "";
+ } else {
+ pop = parts.pop();
+ }
+
+ if ( pop == null ) {
+ pop = context;
+ }
+
+ Expr.relative[ cur ]( checkSet, pop, contextXML );
+ }
+
+ } else {
+ checkSet = parts = [];
+ }
+ }
+
+ if ( !checkSet ) {
+ checkSet = set;
+ }
+
+ if ( !checkSet ) {
+ Sizzle.error( cur || selector );
+ }
+
+ if ( toString.call(checkSet) === "[object Array]" ) {
+ if ( !prune ) {
+ results.push.apply( results, checkSet );
+
+ } else if ( context && context.nodeType === 1 ) {
+ for ( i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
+ results.push( set[i] );
+ }
+ }
+
+ } else {
+ for ( i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+ results.push( set[i] );
+ }
+ }
+ }
+
+ } else {
+ makeArray( checkSet, results );
+ }
+
+ if ( extra ) {
+ Sizzle( extra, origContext, results, seed );
+ Sizzle.uniqueSort( results );
+ }
+
+ return results;
+};
+
+Sizzle.uniqueSort = function( results ) {
+ if ( sortOrder ) {
+ hasDuplicate = baseHasDuplicate;
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ for ( var i = 1; i < results.length; i++ ) {
+ if ( results[i] === results[ i - 1 ] ) {
+ results.splice( i--, 1 );
+ }
+ }
+ }
+ }
+
+ return results;
+};
+
+Sizzle.matches = function( expr, set ) {
+ return Sizzle( expr, null, null, set );
+};
+
+Sizzle.matchesSelector = function( node, expr ) {
+ return Sizzle( expr, null, null, [node] ).length > 0;
+};
+
+Sizzle.find = function( expr, context, isXML ) {
+ var set;
+
+ if ( !expr ) {
+ return [];
+ }
+
+ for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
+ var match,
+ type = Expr.order[i];
+
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
+ var left = match[1];
+ match.splice( 1, 1 );
+
+ if ( left.substr( left.length - 1 ) !== "\\" ) {
+ match[1] = (match[1] || "").replace( rBackslash, "" );
+ set = Expr.find[ type ]( match, context, isXML );
+
+ if ( set != null ) {
+ expr = expr.replace( Expr.match[ type ], "" );
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !set ) {
+ set = typeof context.getElementsByTagName !== "undefined" ?
+ context.getElementsByTagName( "*" ) :
+ [];
+ }
+
+ return { set: set, expr: expr };
+};
+
+Sizzle.filter = function( expr, set, inplace, not ) {
+ var match, anyFound,
+ old = expr,
+ result = [],
+ curLoop = set,
+ isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
+
+ while ( expr && set.length ) {
+ for ( var type in Expr.filter ) {
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
+ var found, item,
+ filter = Expr.filter[ type ],
+ left = match[1];
+
+ anyFound = false;
+
+ match.splice(1,1);
+
+ if ( left.substr( left.length - 1 ) === "\\" ) {
+ continue;
+ }
+
+ if ( curLoop === result ) {
+ result = [];
+ }
+
+ if ( Expr.preFilter[ type ] ) {
+ match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+ if ( !match ) {
+ anyFound = found = true;
+
+ } else if ( match === true ) {
+ continue;
+ }
+ }
+
+ if ( match ) {
+ for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
+ if ( item ) {
+ found = filter( item, match, i, curLoop );
+ var pass = not ^ !!found;
+
+ if ( inplace && found != null ) {
+ if ( pass ) {
+ anyFound = true;
+
+ } else {
+ curLoop[i] = false;
+ }
+
+ } else if ( pass ) {
+ result.push( item );
+ anyFound = true;
+ }
+ }
+ }
+ }
+
+ if ( found !== undefined ) {
+ if ( !inplace ) {
+ curLoop = result;
+ }
+
+ expr = expr.replace( Expr.match[ type ], "" );
+
+ if ( !anyFound ) {
+ return [];
+ }
+
+ break;
+ }
+ }
+ }
+
+ if ( expr === old ) {
+ if ( anyFound == null ) {
+ Sizzle.error( expr );
+
+ } else {
+ break;
+ }
+ }
+
+ old = expr;
+ }
+
+ return curLoop;
+};
+
+Sizzle.error = function( msg ) {
+ throw "Syntax error, unrecognized expression: " + msg;
+};
+
+var Expr = Sizzle.selectors = {
+ order: [ "ID", "NAME", "TAG" ],
+
+ match: {
+ ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+ CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+ NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
+ ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
+ TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
+ CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
+ POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
+ PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
+ },
+
+ leftMatch: {},
+
+ attrMap: {
+ "class": "className",
+ "for": "htmlFor"
+ },
+
+ attrHandle: {
+ href: function( elem ) {
+ return elem.getAttribute( "href" );
+ },
+ type: function( elem ) {
+ return elem.getAttribute( "type" );
+ }
+ },
+
+ relative: {
+ "+": function(checkSet, part){
+ var isPartStr = typeof part === "string",
+ isTag = isPartStr && !rNonWord.test( part ),
+ isPartStrNotTag = isPartStr && !isTag;
+
+ if ( isTag ) {
+ part = part.toLowerCase();
+ }
+
+ for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
+ if ( (elem = checkSet[i]) ) {
+ while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
+
+ checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
+ elem || false :
+ elem === part;
+ }
+ }
+
+ if ( isPartStrNotTag ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ },
+
+ ">": function( checkSet, part ) {
+ var elem,
+ isPartStr = typeof part === "string",
+ i = 0,
+ l = checkSet.length;
+
+ if ( isPartStr && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+
+ for ( ; i < l; i++ ) {
+ elem = checkSet[i];
+
+ if ( elem ) {
+ var parent = elem.parentNode;
+ checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
+ }
+ }
+
+ } else {
+ for ( ; i < l; i++ ) {
+ elem = checkSet[i];
+
+ if ( elem ) {
+ checkSet[i] = isPartStr ?
+ elem.parentNode :
+ elem.parentNode === part;
+ }
+ }
+
+ if ( isPartStr ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ }
+ },
+
+ "": function(checkSet, part, isXML){
+ var nodeCheck,
+ doneName = done++,
+ checkFn = dirCheck;
+
+ if ( typeof part === "string" && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+ nodeCheck = part;
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
+ },
+
+ "~": function( checkSet, part, isXML ) {
+ var nodeCheck,
+ doneName = done++,
+ checkFn = dirCheck;
+
+ if ( typeof part === "string" && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+ nodeCheck = part;
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
+ }
+ },
+
+ find: {
+ ID: function( match, context, isXML ) {
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+ return m && m.parentNode ? [m] : [];
+ }
+ },
+
+ NAME: function( match, context ) {
+ if ( typeof context.getElementsByName !== "undefined" ) {
+ var ret = [],
+ results = context.getElementsByName( match[1] );
+
+ for ( var i = 0, l = results.length; i < l; i++ ) {
+ if ( results[i].getAttribute("name") === match[1] ) {
+ ret.push( results[i] );
+ }
+ }
+
+ return ret.length === 0 ? null : ret;
+ }
+ },
+
+ TAG: function( match, context ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ return context.getElementsByTagName( match[1] );
+ }
+ }
+ },
+ preFilter: {
+ CLASS: function( match, curLoop, inplace, result, not, isXML ) {
+ match = " " + match[1].replace( rBackslash, "" ) + " ";
+
+ if ( isXML ) {
+ return match;
+ }
+
+ for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+ if ( elem ) {
+ if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
+ if ( !inplace ) {
+ result.push( elem );
+ }
+
+ } else if ( inplace ) {
+ curLoop[i] = false;
+ }
+ }
+ }
+
+ return false;
+ },
+
+ ID: function( match ) {
+ return match[1].replace( rBackslash, "" );
+ },
+
+ TAG: function( match, curLoop ) {
+ return match[1].replace( rBackslash, "" ).toLowerCase();
+ },
+
+ CHILD: function( match ) {
+ if ( match[1] === "nth" ) {
+ if ( !match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ match[2] = match[2].replace(/^\+|\s*/g, '');
+
+ var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
+ match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
+ !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+ match[2] = (test[1] + (test[2] || 1)) - 0;
+ match[3] = test[3] - 0;
+ }
+ else if ( match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ match[0] = done++;
+
+ return match;
+ },
+
+ ATTR: function( match, curLoop, inplace, result, not, isXML ) {
+ var name = match[1] = match[1].replace( rBackslash, "" );
+
+ if ( !isXML && Expr.attrMap[name] ) {
+ match[1] = Expr.attrMap[name];
+ }
+
+ match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
+
+ if ( match[2] === "~=" ) {
+ match[4] = " " + match[4] + " ";
+ }
+
+ return match;
+ },
+
+ PSEUDO: function( match, curLoop, inplace, result, not ) {
+ if ( match[1] === "not" ) {
+ if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
+ match[3] = Sizzle(match[3], null, null, curLoop);
+
+ } else {
+ var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+
+ if ( !inplace ) {
+ result.push.apply( result, ret );
+ }
+
+ return false;
+ }
+
+ } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+ return true;
+ }
+
+ return match;
+ },
+
+ POS: function( match ) {
+ match.unshift( true );
+
+ return match;
+ }
+ },
+
+ filters: {
+ enabled: function( elem ) {
+ return elem.disabled === false && elem.type !== "hidden";
+ },
+
+ disabled: function( elem ) {
+ return elem.disabled === true;
+ },
+
+ checked: function( elem ) {
+ return elem.checked === true;
+ },
+
+ selected: function( elem ) {
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ parent: function( elem ) {
+ return !!elem.firstChild;
+ },
+
+ empty: function( elem ) {
+ return !elem.firstChild;
+ },
+
+ has: function( elem, i, match ) {
+ return !!Sizzle( match[3], elem ).length;
+ },
+
+ header: function( elem ) {
+ return (/h\d/i).test( elem.nodeName );
+ },
+
+ text: function( elem ) {
+ var attr = elem.getAttribute( "type" ), type = elem.type;
+ return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
+ },
+
+ radio: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
+ },
+
+ checkbox: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
+ },
+
+ file: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
+ },
+
+ password: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
+ },
+
+ submit: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && "submit" === elem.type;
+ },
+
+ image: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
+ },
+
+ reset: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && "reset" === elem.type;
+ },
+
+ button: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && "button" === elem.type || name === "button";
+ },
+
+ input: function( elem ) {
+ return (/input|select|textarea|button/i).test( elem.nodeName );
+ },
+
+ focus: function( elem ) {
+ return elem === elem.ownerDocument.activeElement;
+ }
+ },
+ setFilters: {
+ first: function( elem, i ) {
+ return i === 0;
+ },
+
+ last: function( elem, i, match, array ) {
+ return i === array.length - 1;
+ },
+
+ even: function( elem, i ) {
+ return i % 2 === 0;
+ },
+
+ odd: function( elem, i ) {
+ return i % 2 === 1;
+ },
+
+ lt: function( elem, i, match ) {
+ return i < match[3] - 0;
+ },
+
+ gt: function( elem, i, match ) {
+ return i > match[3] - 0;
+ },
+
+ nth: function( elem, i, match ) {
+ return match[3] - 0 === i;
+ },
+
+ eq: function( elem, i, match ) {
+ return match[3] - 0 === i;
+ }
+ },
+ filter: {
+ PSEUDO: function( elem, match, i, array ) {
+ var name = match[1],
+ filter = Expr.filters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+
+ } else if ( name === "contains" ) {
+ return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;
+
+ } else if ( name === "not" ) {
+ var not = match[3];
+
+ for ( var j = 0, l = not.length; j < l; j++ ) {
+ if ( not[j] === elem ) {
+ return false;
+ }
+ }
+
+ return true;
+
+ } else {
+ Sizzle.error( name );
+ }
+ },
+
+ CHILD: function( elem, match ) {
+ var type = match[1],
+ node = elem;
+
+ switch ( type ) {
+ case "only":
+ case "first":
+ while ( (node = node.previousSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ if ( type === "first" ) {
+ return true;
+ }
+
+ node = elem;
+
+ case "last":
+ while ( (node = node.nextSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ return true;
+
+ case "nth":
+ var first = match[2],
+ last = match[3];
+
+ if ( first === 1 && last === 0 ) {
+ return true;
+ }
+
+ var doneName = match[0],
+ parent = elem.parentNode;
+
+ if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
+ var count = 0;
+
+ for ( node = parent.firstChild; node; node = node.nextSibling ) {
+ if ( node.nodeType === 1 ) {
+ node.nodeIndex = ++count;
+ }
+ }
+
+ parent.sizcache = doneName;
+ }
+
+ var diff = elem.nodeIndex - last;
+
+ if ( first === 0 ) {
+ return diff === 0;
+
+ } else {
+ return ( diff % first === 0 && diff / first >= 0 );
+ }
+ }
+ },
+
+ ID: function( elem, match ) {
+ return elem.nodeType === 1 && elem.getAttribute("id") === match;
+ },
+
+ TAG: function( elem, match ) {
+ return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
+ },
+
+ CLASS: function( elem, match ) {
+ return (" " + (elem.className || elem.getAttribute("class")) + " ")
+ .indexOf( match ) > -1;
+ },
+
+ ATTR: function( elem, match ) {
+ var name = match[1],
+ result = Expr.attrHandle[ name ] ?
+ Expr.attrHandle[ name ]( elem ) :
+ elem[ name ] != null ?
+ elem[ name ] :
+ elem.getAttribute( name ),
+ value = result + "",
+ type = match[2],
+ check = match[4];
+
+ return result == null ?
+ type === "!=" :
+ type === "=" ?
+ value === check :
+ type === "*=" ?
+ value.indexOf(check) >= 0 :
+ type === "~=" ?
+ (" " + value + " ").indexOf(check) >= 0 :
+ !check ?
+ value && result !== false :
+ type === "!=" ?
+ value !== check :
+ type === "^=" ?
+ value.indexOf(check) === 0 :
+ type === "$=" ?
+ value.substr(value.length - check.length) === check :
+ type === "|=" ?
+ value === check || value.substr(0, check.length + 1) === check + "-" :
+ false;
+ },
+
+ POS: function( elem, match, i, array ) {
+ var name = match[2],
+ filter = Expr.setFilters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+ }
+ }
+ }
+};
+
+var origPOS = Expr.match.POS,
+ fescape = function(all, num){
+ return "\\" + (num - 0 + 1);
+ };
+
+for ( var type in Expr.match ) {
+ Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
+ Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
+}
+
+var makeArray = function( array, results ) {
+ array = Array.prototype.slice.call( array, 0 );
+
+ if ( results ) {
+ results.push.apply( results, array );
+ return results;
+ }
+
+ return array;
+};
+
+try {
+ Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
+
+} catch( e ) {
+ makeArray = function( array, results ) {
+ var i = 0,
+ ret = results || [];
+
+ if ( toString.call(array) === "[object Array]" ) {
+ Array.prototype.push.apply( ret, array );
+
+ } else {
+ if ( typeof array.length === "number" ) {
+ for ( var l = array.length; i < l; i++ ) {
+ ret.push( array[i] );
+ }
+
+ } else {
+ for ( ; array[i]; i++ ) {
+ ret.push( array[i] );
+ }
+ }
+ }
+
+ return ret;
+ };
+}
+
+var sortOrder, siblingCheck;
+
+if ( document.documentElement.compareDocumentPosition ) {
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
+ return a.compareDocumentPosition ? -1 : 1;
+ }
+
+ return a.compareDocumentPosition(b) & 4 ? -1 : 1;
+ };
+
+} else {
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+
+ } else if ( a.sourceIndex && b.sourceIndex ) {
+ return a.sourceIndex - b.sourceIndex;
+ }
+
+ var al, bl,
+ ap = [],
+ bp = [],
+ aup = a.parentNode,
+ bup = b.parentNode,
+ cur = aup;
+
+ if ( aup === bup ) {
+ return siblingCheck( a, b );
+
+ } else if ( !aup ) {
+ return -1;
+
+ } else if ( !bup ) {
+ return 1;
+ }
+
+ while ( cur ) {
+ ap.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ cur = bup;
+
+ while ( cur ) {
+ bp.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ al = ap.length;
+ bl = bp.length;
+
+ for ( var i = 0; i < al && i < bl; i++ ) {
+ if ( ap[i] !== bp[i] ) {
+ return siblingCheck( ap[i], bp[i] );
+ }
+ }
+
+ return i === al ?
+ siblingCheck( a, bp[i], -1 ) :
+ siblingCheck( ap[i], b, 1 );
+ };
+
+ siblingCheck = function( a, b, ret ) {
+ if ( a === b ) {
+ return ret;
+ }
+
+ var cur = a.nextSibling;
+
+ while ( cur ) {
+ if ( cur === b ) {
+ return -1;
+ }
+
+ cur = cur.nextSibling;
+ }
+
+ return 1;
+ };
+}
+
+Sizzle.getText = function( elems ) {
+ var ret = "", elem;
+
+ for ( var i = 0; elems[i]; i++ ) {
+ elem = elems[i];
+
+ if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
+ ret += elem.nodeValue;
+
+ } else if ( elem.nodeType !== 8 ) {
+ ret += Sizzle.getText( elem.childNodes );
+ }
+ }
+
+ return ret;
+};
+
+(function(){
+ var form = document.createElement("div"),
+ id = "script" + (new Date()).getTime(),
+ root = document.documentElement;
+
+ form.innerHTML = "<a name='" + id + "'/>";
+
+ root.insertBefore( form, root.firstChild );
+
+ if ( document.getElementById( id ) ) {
+ Expr.find.ID = function( match, context, isXML ) {
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+
+ return m ?
+ m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
+ [m] :
+ undefined :
+ [];
+ }
+ };
+
+ Expr.filter.ID = function( elem, match ) {
+ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+
+ return elem.nodeType === 1 && node && node.nodeValue === match;
+ };
+ }
+
+ root.removeChild( form );
+
+ root = form = null;
+})();
+
+(function(){
+
+ var div = document.createElement("div");
+ div.appendChild( document.createComment("") );
+
+ if ( div.getElementsByTagName("*").length > 0 ) {
+ Expr.find.TAG = function( match, context ) {
+ var results = context.getElementsByTagName( match[1] );
+
+ if ( match[1] === "*" ) {
+ var tmp = [];
+
+ for ( var i = 0; results[i]; i++ ) {
+ if ( results[i].nodeType === 1 ) {
+ tmp.push( results[i] );
+ }
+ }
+
+ results = tmp;
+ }
+
+ return results;
+ };
+ }
+
+ div.innerHTML = "<a href='#'></a>";
+
+ if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+ div.firstChild.getAttribute("href") !== "#" ) {
+
+ Expr.attrHandle.href = function( elem ) {
+ return elem.getAttribute( "href", 2 );
+ };
+ }
+
+ div = null;
+})();
+
+if ( document.querySelectorAll ) {
+ (function(){
+ var oldSizzle = Sizzle,
+ div = document.createElement("div"),
+ id = "__sizzle__";
+
+ div.innerHTML = "<p class='TEST'></p>";
+
+ if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+ return;
+ }
+
+ Sizzle = function( query, context, extra, seed ) {
+ context = context || document;
+
+ if ( !seed && !Sizzle.isXML(context) ) {
+ var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
+
+ if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
+ if ( match[1] ) {
+ return makeArray( context.getElementsByTagName( query ), extra );
+
+ } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
+ return makeArray( context.getElementsByClassName( match[2] ), extra );
+ }
+ }
+
+ if ( context.nodeType === 9 ) {
+ if ( query === "body" && context.body ) {
+ return makeArray( [ context.body ], extra );
+
+ } else if ( match && match[3] ) {
+ var elem = context.getElementById( match[3] );
+
+ if ( elem && elem.parentNode ) {
+ if ( elem.id === match[3] ) {
+ return makeArray( [ elem ], extra );
+ }
+
+ } else {
+ return makeArray( [], extra );
+ }
+ }
+
+ try {
+ return makeArray( context.querySelectorAll(query), extra );
+ } catch(qsaError) {}
+
+ } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ var oldContext = context,
+ old = context.getAttribute( "id" ),
+ nid = old || id,
+ hasParent = context.parentNode,
+ relativeHierarchySelector = /^\s*[+~]/.test( query );
+
+ if ( !old ) {
+ context.setAttribute( "id", nid );
+ } else {
+ nid = nid.replace( /'/g, "\\$&" );
+ }
+ if ( relativeHierarchySelector && hasParent ) {
+ context = context.parentNode;
+ }
+
+ try {
+ if ( !relativeHierarchySelector || hasParent ) {
+ return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
+ }
+
+ } catch(pseudoError) {
+ } finally {
+ if ( !old ) {
+ oldContext.removeAttribute( "id" );
+ }
+ }
+ }
+ }
+
+ return oldSizzle(query, context, extra, seed);
+ };
+
+ for ( var prop in oldSizzle ) {
+ Sizzle[ prop ] = oldSizzle[ prop ];
+ }
+
+ div = null;
+ })();
+}
+
+(function(){
+ var html = document.documentElement,
+ matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
+
+ if ( matches ) {
+ var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
+ pseudoWorks = false;
+
+ try {
+ matches.call( document.documentElement, "[test!='']:sizzle" );
+
+ } catch( pseudoError ) {
+ pseudoWorks = true;
+ }
+
+ Sizzle.matchesSelector = function( node, expr ) {
+ expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
+
+ if ( !Sizzle.isXML( node ) ) {
+ try {
+ if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
+ var ret = matches.call( node, expr );
+
+ if ( ret || !disconnectedMatch ||
+ node.document && node.document.nodeType !== 11 ) {
+ return ret;
+ }
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle(expr, null, null, [node]).length > 0;
+ };
+ }
+})();
+
+(function(){
+ var div = document.createElement("div");
+
+ div.innerHTML = "<div class='test e'></div><div class='test'></div>";
+
+ if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
+ return;
+ }
+
+ div.lastChild.className = "e";
+
+ if ( div.getElementsByClassName("e").length === 1 ) {
+ return;
+ }
+
+ Expr.order.splice(1, 0, "CLASS");
+ Expr.find.CLASS = function( match, context, isXML ) {
+ if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+ return context.getElementsByClassName(match[1]);
+ }
+ };
+
+ div = null;
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+
+ if ( elem ) {
+ var match = false;
+
+ elem = elem[dir];
+
+ while ( elem ) {
+ if ( elem.sizcache === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 && !isXML ){
+ elem.sizcache = doneName;
+ elem.sizset = i;
+ }
+
+ if ( elem.nodeName.toLowerCase() === cur ) {
+ match = elem;
+ break;
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+
+ if ( elem ) {
+ var match = false;
+
+ elem = elem[dir];
+
+ while ( elem ) {
+ if ( elem.sizcache === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 ) {
+ if ( !isXML ) {
+ elem.sizcache = doneName;
+ elem.sizset = i;
+ }
+
+ if ( typeof cur !== "string" ) {
+ if ( elem === cur ) {
+ match = true;
+ break;
+ }
+
+ } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+ match = elem;
+ break;
+ }
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+if ( document.documentElement.contains ) {
+ Sizzle.contains = function( a, b ) {
+ return a !== b && (a.contains ? a.contains(b) : true);
+ };
+
+} else if ( document.documentElement.compareDocumentPosition ) {
+ Sizzle.contains = function( a, b ) {
+ return !!(a.compareDocumentPosition(b) & 16);
+ };
+
+} else {
+ Sizzle.contains = function() {
+ return false;
+ };
+}
+
+Sizzle.isXML = function( elem ) {
+ var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
+
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+var posProcess = function( selector, context ) {
+ var match,
+ tmpSet = [],
+ later = "",
+ root = context.nodeType ? [context] : context;
+
+ while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+ later += match[0];
+ selector = selector.replace( Expr.match.PSEUDO, "" );
+ }
+
+ selector = Expr.relative[selector] ? selector + "*" : selector;
+
+ for ( var i = 0, l = root.length; i < l; i++ ) {
+ Sizzle( selector, root[i], tmpSet );
+ }
+
+ return Sizzle.filter( later, tmpSet );
+};
+
+
+window.Sizzle = Sizzle;
+
+})();
+
+Prototype._original_property = window.Sizzle;
+
+;(function(engine) {
+ var extendElements = Prototype.Selector.extendElements;
+
+ function select(selector, scope) {
+ return extendElements(engine(selector, scope || document));
+ }
+
+ function match(element, selector) {
+ return engine.matches(selector, [element]).length == 1;
+ }
+
+ Prototype.Selector.engine = engine;
+ Prototype.Selector.select = select;
+ Prototype.Selector.match = match;
+})(Sizzle);
+
+window.Sizzle = Prototype._original_property;
+delete Prototype._original_property;
+
+var Form = {
+ reset: function(form) {
+ form = $(form);
+ form.reset();
+ return form;
+ },
+
+ serializeElements: function(elements, options) {
+ if (typeof options != 'object') options = { hash: !!options };
+ else if (Object.isUndefined(options.hash)) options.hash = true;
+ var key, value, submitted = false, submit = options.submit, accumulator, initial;
+
+ if (options.hash) {
+ initial = {};
+ accumulator = function(result, key, value) {
+ if (key in result) {
+ if (!Object.isArray(result[key])) result[key] = [result[key]];
+ result[key].push(value);
+ } else result[key] = value;
+ return result;
+ };
+ } else {
+ initial = '';
+ accumulator = function(result, key, value) {
+ value = value.gsub(/(\r)?\n/, '\r\n');
+ value = encodeURIComponent(value);
+ value = value.gsub(/%20/, '+');
+ return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + value;
+ }
+ }
+
+ return elements.inject(initial, function(result, element) {
+ if (!element.disabled && element.name) {
+ key = element.name; value = $(element).getValue();
+ if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
+ submit !== false && (!submit || key == submit) && (submitted = true)))) {
+ result = accumulator(result, key, value);
+ }
+ }
+ return result;
+ });
+ }
+};
+
+Form.Methods = {
+ serialize: function(form, options) {
+ return Form.serializeElements(Form.getElements(form), options);
+ },
+
+
+ getElements: function(form) {
+ var elements = $(form).getElementsByTagName('*');
+ var element, results = [], serializers = Form.Element.Serializers;
+
+ for (var i = 0; element = elements[i]; i++) {
+ if (serializers[element.tagName.toLowerCase()])
+ results.push(Element.extend(element));
+ }
+ return results;
+ },
+
+ getInputs: function(form, typeName, name) {
+ form = $(form);
+ var inputs = form.getElementsByTagName('input');
+
+ if (!typeName && !name) return $A(inputs).map(Element.extend);
+
+ for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
+ var input = inputs[i];
+ if ((typeName && input.type != typeName) || (name && input.name != name))
+ continue;
+ matchingInputs.push(Element.extend(input));
+ }
+
+ return matchingInputs;
+ },
+
+ disable: function(form) {
+ form = $(form);
+ Form.getElements(form).invoke('disable');
+ return form;
+ },
+
+ enable: function(form) {
+ form = $(form);
+ Form.getElements(form).invoke('enable');
+ return form;
+ },
+
+ findFirstElement: function(form) {
+ var elements = $(form).getElements().findAll(function(element) {
+ return 'hidden' != element.type && !element.disabled;
+ });
+ var firstByIndex = elements.findAll(function(element) {
+ return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
+ }).sortBy(function(element) { return element.tabIndex }).first();
+
+ return firstByIndex ? firstByIndex : elements.find(function(element) {
+ return /^(?:input|select|textarea)$/i.test(element.tagName);
+ });
+ },
+
+ focusFirstElement: function(form) {
+ form = $(form);
+ var element = form.findFirstElement();
+ if (element) element.activate();
+ return form;
+ },
+
+ request: function(form, options) {
+ form = $(form), options = Object.clone(options || { });
+
+ var params = options.parameters, action = form.readAttribute('action') || '';
+ if (action.blank()) action = window.location.href;
+ options.parameters = form.serialize(true);
+
+ if (params) {
+ if (Object.isString(params)) params = params.toQueryParams();
+ Object.extend(options.parameters, params);
+ }
+
+ if (form.hasAttribute('method') && !options.method)
+ options.method = form.method;
+
+ return new Ajax.Request(action, options);
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+
+Form.Element = {
+ focus: function(element) {
+ $(element).focus();
+ return element;
+ },
+
+ select: function(element) {
+ $(element).select();
+ return element;
+ }
+};
+
+Form.Element.Methods = {
+
+ serialize: function(element) {
+ element = $(element);
+ if (!element.disabled && element.name) {
+ var value = element.getValue();
+ if (value != undefined) {
+ var pair = { };
+ pair[element.name] = value;
+ return Object.toQueryString(pair);
+ }
+ }
+ return '';
+ },
+
+ getValue: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ return Form.Element.Serializers[method](element);
+ },
+
+ setValue: function(element, value) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ Form.Element.Serializers[method](element, value);
+ return element;
+ },
+
+ clear: function(element) {
+ $(element).value = '';
+ return element;
+ },
+
+ present: function(element) {
+ return $(element).value != '';
+ },
+
+ activate: function(element) {
+ element = $(element);
+ try {
+ element.focus();
+ if (element.select && (element.tagName.toLowerCase() != 'input' ||
+ !(/^(?:button|reset|submit)$/i.test(element.type))))
+ element.select();
+ } catch (e) { }
+ return element;
+ },
+
+ disable: function(element) {
+ element = $(element);
+ element.disabled = true;
+ return element;
+ },
+
+ enable: function(element) {
+ element = $(element);
+ element.disabled = false;
+ return element;
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Field = Form.Element;
+
+var $F = Form.Element.Methods.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = (function() {
+ function input(element, value) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ return inputSelector(element, value);
+ default:
+ return valueSelector(element, value);
+ }
+ }
+
+ function inputSelector(element, value) {
+ if (Object.isUndefined(value))
+ return element.checked ? element.value : null;
+ else element.checked = !!value;
+ }
+
+ function valueSelector(element, value) {
+ if (Object.isUndefined(value)) return element.value;
+ else element.value = value;
+ }
+
+ function select(element, value) {
+ if (Object.isUndefined(value))
+ return (element.type === 'select-one' ? selectOne : selectMany)(element);
+
+ var opt, currentValue, single = !Object.isArray(value);
+ for (var i = 0, length = element.length; i < length; i++) {
+ opt = element.options[i];
+ currentValue = this.optionValue(opt);
+ if (single) {
+ if (currentValue == value) {
+ opt.selected = true;
+ return;
+ }
+ }
+ else opt.selected = value.include(currentValue);
+ }
+ }
+
+ function selectOne(element) {
+ var index = element.selectedIndex;
+ return index >= 0 ? optionValue(element.options[index]) : null;
+ }
+
+ function selectMany(element) {
+ var values, length = element.length;
+ if (!length) return null;
+
+ for (var i = 0, values = []; i < length; i++) {
+ var opt = element.options[i];
+ if (opt.selected) values.push(optionValue(opt));
+ }
+ return values;
+ }
+
+ function optionValue(opt) {
+ return Element.hasAttribute(opt, 'value') ? opt.value : opt.text;
+ }
+
+ return {
+ input: input,
+ inputSelector: inputSelector,
+ textarea: valueSelector,
+ select: select,
+ selectOne: selectOne,
+ selectMany: selectMany,
+ optionValue: optionValue,
+ button: valueSelector
+ };
+})();
+
+/*--------------------------------------------------------------------------*/
+
+
+Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
+ initialize: function($super, element, frequency, callback) {
+ $super(callback, frequency);
+ this.element = $(element);
+ this.lastValue = this.getValue();
+ },
+
+ execute: function() {
+ var value = this.getValue();
+ if (Object.isString(this.lastValue) && Object.isString(value) ?
+ this.lastValue != value : String(this.lastValue) != String(value)) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ }
+});
+
+Form.Element.Observer = Class.create(Abstract.TimedObserver, {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.Observer = Class.create(Abstract.TimedObserver, {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = Class.create({
+ initialize: function(element, callback) {
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ if (this.element.tagName.toLowerCase() == 'form')
+ this.registerFormCallbacks();
+ else
+ this.registerCallback(this.element);
+ },
+
+ onElementEvent: function() {
+ var value = this.getValue();
+ if (this.lastValue != value) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ },
+
+ registerFormCallbacks: function() {
+ Form.getElements(this.element).each(this.registerCallback, this);
+ },
+
+ registerCallback: function(element) {
+ if (element.type) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
+ break;
+ default:
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
+ break;
+ }
+ }
+ }
+});
+
+Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.EventObserver = Class.create(Abstract.EventObserver, {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+(function(GLOBAL) {
+ var DIV = document.createElement('div');
+ var docEl = document.documentElement;
+ var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
+ && 'onmouseleave' in docEl;
+
+ var Event = {
+ KEY_BACKSPACE: 8,
+ KEY_TAB: 9,
+ KEY_RETURN: 13,
+ KEY_ESC: 27,
+ KEY_LEFT: 37,
+ KEY_UP: 38,
+ KEY_RIGHT: 39,
+ KEY_DOWN: 40,
+ KEY_DELETE: 46,
+ KEY_HOME: 36,
+ KEY_END: 35,
+ KEY_PAGEUP: 33,
+ KEY_PAGEDOWN: 34,
+ KEY_INSERT: 45
+ };
+
+
+ var isIELegacyEvent = function(event) { return false; };
+
+ if (window.attachEvent) {
+ if (window.addEventListener) {
+ isIELegacyEvent = function(event) {
+ return !(event instanceof window.Event);
+ };
+ } else {
+ isIELegacyEvent = function(event) { return true; };
+ }
+ }
+
+ var _isButton;
+
+ function _isButtonForDOMEvents(event, code) {
+ return event.which ? (event.which === code + 1) : (event.button === code);
+ }
+
+ var legacyButtonMap = { 0: 1, 1: 4, 2: 2 };
+ function _isButtonForLegacyEvents(event, code) {
+ return event.button === legacyButtonMap[code];
+ }
+
+ function _isButtonForWebKit(event, code) {
+ switch (code) {
+ case 0: return event.which == 1 && !event.metaKey;
+ case 1: return event.which == 2 || (event.which == 1 && event.metaKey);
+ case 2: return event.which == 3;
+ default: return false;
+ }
+ }
+
+ if (window.attachEvent) {
+ if (!window.addEventListener) {
+ _isButton = _isButtonForLegacyEvents;
+ } else {
+ _isButton = function(event, code) {
+ return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) :
+ _isButtonForDOMEvents(event, code);
+ }
+ }
+ } else if (Prototype.Browser.WebKit) {
+ _isButton = _isButtonForWebKit;
+ } else {
+ _isButton = _isButtonForDOMEvents;
+ }
+
+ function isLeftClick(event) { return _isButton(event, 0) }
+
+ function isMiddleClick(event) { return _isButton(event, 1) }
+
+ function isRightClick(event) { return _isButton(event, 2) }
+
+ function element(event) {
+ return Element.extend(_element(event));
+ }
+
+ function _element(event) {
+ event = Event.extend(event);
+
+ var node = event.target, type = event.type,
+ currentTarget = event.currentTarget;
+
+ if (currentTarget && currentTarget.tagName) {
+ if (type === 'load' || type === 'error' ||
+ (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
+ && currentTarget.type === 'radio'))
+ node = currentTarget;
+ }
+
+ if (node.nodeType == Node.TEXT_NODE)
+ node = node.parentNode;
+
+ return Element.extend(node);
+ }
+
+ function findElement(event, expression) {
+ var element = _element(event), match = Prototype.Selector.match;
+ if (!expression) return Element.extend(element);
+ while (element) {
+ if (Object.isElement(element) && match(element, expression))
+ return Element.extend(element);
+ element = element.parentNode;
+ }
+ }
+
+ function pointer(event) {
+ return { x: pointerX(event), y: pointerY(event) };
+ }
+
+ function pointerX(event) {
+ var docElement = document.documentElement,
+ body = document.body || { scrollLeft: 0 };
+
+ return event.pageX || (event.clientX +
+ (docElement.scrollLeft || body.scrollLeft) -
+ (docElement.clientLeft || 0));
+ }
+
+ function pointerY(event) {
+ var docElement = document.documentElement,
+ body = document.body || { scrollTop: 0 };
+
+ return event.pageY || (event.clientY +
+ (docElement.scrollTop || body.scrollTop) -
+ (docElement.clientTop || 0));
+ }
+
+
+ function stop(event) {
+ Event.extend(event);
+ event.preventDefault();
+ event.stopPropagation();
+
+ event.stopped = true;
+ }
+
+
+ Event.Methods = {
+ isLeftClick: isLeftClick,
+ isMiddleClick: isMiddleClick,
+ isRightClick: isRightClick,
+
+ element: element,
+ findElement: findElement,
+
+ pointer: pointer,
+ pointerX: pointerX,
+ pointerY: pointerY,
+
+ stop: stop
+ };
+
+ var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
+ m[name] = Event.Methods[name].methodize();
+ return m;
+ });
+
+ if (window.attachEvent) {
+ function _relatedTarget(event) {
+ var element;
+ switch (event.type) {
+ case 'mouseover':
+ case 'mouseenter':
+ element = event.fromElement;
+ break;
+ case 'mouseout':
+ case 'mouseleave':
+ element = event.toElement;
+ break;
+ default:
+ return null;
+ }
+ return Element.extend(element);
+ }
+
+ var additionalMethods = {
+ stopPropagation: function() { this.cancelBubble = true },
+ preventDefault: function() { this.returnValue = false },
+ inspect: function() { return '[object Event]' }
+ };
+
+ Event.extend = function(event, element) {
+ if (!event) return false;
+
+ if (!isIELegacyEvent(event)) return event;
+
+ if (event._extendedByPrototype) return event;
+ event._extendedByPrototype = Prototype.emptyFunction;
+
+ var pointer = Event.pointer(event);
+
+ Object.extend(event, {
+ target: event.srcElement || element,
+ relatedTarget: _relatedTarget(event),
+ pageX: pointer.x,
+ pageY: pointer.y
+ });
+
+ Object.extend(event, methods);
+ Object.extend(event, additionalMethods);
+
+ return event;
+ };
+ } else {
+ Event.extend = Prototype.K;
+ }
+
+ if (window.addEventListener) {
+ Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
+ Object.extend(Event.prototype, methods);
+ }
+
+ var EVENT_TRANSLATIONS = {
+ mouseenter: 'mouseover',
+ mouseleave: 'mouseout'
+ };
+
+ function getDOMEventName(eventName) {
+ return EVENT_TRANSLATIONS[eventName] || eventName;
+ }
+
+ if (MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED)
+ getDOMEventName = Prototype.K;
+
+ function getUniqueElementID(element) {
+ if (element === window) return 0;
+
+ if (typeof element._prototypeUID === 'undefined')
+ element._prototypeUID = Element.Storage.UID++;
+ return element._prototypeUID;
+ }
+
+ function getUniqueElementID_IE(element) {
+ if (element === window) return 0;
+ if (element == document) return 1;
+ return element.uniqueID;
+ }
+
+ if ('uniqueID' in DIV)
+ getUniqueElementID = getUniqueElementID_IE;
+
+ function isCustomEvent(eventName) {
+ return eventName.include(':');
+ }
+
+ Event._isCustomEvent = isCustomEvent;
+
+ function getRegistryForElement(element, uid) {
+ var CACHE = GLOBAL.Event.cache;
+ if (Object.isUndefined(uid))
+ uid = getUniqueElementID(element);
+ if (!CACHE[uid]) CACHE[uid] = { element: element };
+ return CACHE[uid];
+ }
+
+ function destroyRegistryForElement(element, uid) {
+ if (Object.isUndefined(uid))
+ uid = getUniqueElementID(element);
+ delete GLOBAL.Event.cache[uid];
+ }
+
+
+ function register(element, eventName, handler) {
+ var registry = getRegistryForElement(element);
+ if (!registry[eventName]) registry[eventName] = [];
+ var entries = registry[eventName];
+
+ var i = entries.length;
+ while (i--)
+ if (entries[i].handler === handler) return null;
+
+ var uid = getUniqueElementID(element);
+ var responder = GLOBAL.Event._createResponder(uid, eventName, handler);
+ var entry = {
+ responder: responder,
+ handler: handler
+ };
+
+ entries.push(entry);
+ return entry;
+ }
+
+ function unregister(element, eventName, handler) {
+ var registry = getRegistryForElement(element);
+ var entries = registry[eventName];
+ if (!entries) return;
+
+ var i = entries.length, entry;
+ while (i--) {
+ if (entries[i].handler === handler) {
+ entry = entries[i];
+ break;
+ }
+ }
+
+ if (!entry) return;
+
+ var index = entries.indexOf(entry);
+ entries.splice(index, 1);
+
+ return entry;
+ }
+
+
+ function observe(element, eventName, handler) {
+ element = $(element);
+ var entry = register(element, eventName, handler);
+
+ if (entry === null) return element;
+
+ var responder = entry.responder;
+ if (isCustomEvent(eventName))
+ observeCustomEvent(element, eventName, responder);
+ else
+ observeStandardEvent(element, eventName, responder);
+
+ return element;
+ }
+
+ function observeStandardEvent(element, eventName, responder) {
+ var actualEventName = getDOMEventName(eventName);
+ if (element.addEventListener) {
+ element.addEventListener(actualEventName, responder, false);
+ } else {
+ element.attachEvent('on' + actualEventName, responder);
+ }
+ }
+
+ function observeCustomEvent(element, eventName, responder) {
+ if (element.addEventListener) {
+ element.addEventListener('dataavailable', responder, false);
+ } else {
+ element.attachEvent('ondataavailable', responder);
+ element.attachEvent('onlosecapture', responder);
+ }
+ }
+
+ function stopObserving(element, eventName, handler) {
+ element = $(element);
+ var handlerGiven = !Object.isUndefined(handler),
+ eventNameGiven = !Object.isUndefined(eventName);
+
+ if (!eventNameGiven && !handlerGiven) {
+ stopObservingElement(element);
+ return element;
+ }
+
+ if (!handlerGiven) {
+ stopObservingEventName(element, eventName);
+ return element;
+ }
+
+ var entry = unregister(element, eventName, handler);
+
+ if (!entry) return element;
+ removeEvent(element, eventName, entry.responder);
+ return element;
+ }
+
+ function stopObservingStandardEvent(element, eventName, responder) {
+ var actualEventName = getDOMEventName(eventName);
+ if (element.removeEventListener) {
+ element.removeEventListener(actualEventName, responder, false);
+ } else {
+ element.detachEvent('on' + actualEventName, responder);
+ }
+ }
+
+ function stopObservingCustomEvent(element, eventName, responder) {
+ if (element.removeEventListener) {
+ element.removeEventListener('dataavailable', responder, false);
+ } else {
+ element.detachEvent('ondataavailable', responder);
+ element.detachEvent('onlosecapture', responder);
+ }
+ }
+
+
+
+ function stopObservingElement(element) {
+ var uid = getUniqueElementID(element),
+ registry = getRegistryForElement(element, uid);
+
+ destroyRegistryForElement(element, uid);
+
+ var entries, i;
+ for (var eventName in registry) {
+ if (eventName === 'element') continue;
+
+ entries = registry[eventName];
+ i = entries.length;
+ while (i--)
+ removeEvent(element, eventName, entries[i].responder);
+ }
+ }
+
+ function stopObservingEventName(element, eventName) {
+ var registry = getRegistryForElement(element);
+ var entries = registry[eventName];
+ if (!entries) return;
+ delete registry[eventName];
+
+ var i = entries.length;
+ while (i--)
+ removeEvent(element, eventName, entries[i].responder);
+ }
+
+
+ function removeEvent(element, eventName, handler) {
+ if (isCustomEvent(eventName))
+ stopObservingCustomEvent(element, eventName, handler);
+ else
+ stopObservingStandardEvent(element, eventName, handler);
+ }
+
+
+
+ function getFireTarget(element) {
+ if (element !== document) return element;
+ if (document.createEvent && !element.dispatchEvent)
+ return document.documentElement;
+ return element;
+ }
+
+ function fire(element, eventName, memo, bubble) {
+ element = getFireTarget($(element));
+ if (Object.isUndefined(bubble)) bubble = true;
+ memo = memo || {};
+
+ var event = fireEvent(element, eventName, memo, bubble);
+ return Event.extend(event);
+ }
+
+ function fireEvent_DOM(element, eventName, memo, bubble) {
+ var event = document.createEvent('HTMLEvents');
+ event.initEvent('dataavailable', bubble, true);
+
+ event.eventName = eventName;
+ event.memo = memo;
+
+ element.dispatchEvent(event);
+ return event;
+ }
+
+ function fireEvent_IE(element, eventName, memo, bubble) {
+ var event = document.createEventObject();
+ event.eventType = bubble ? 'ondataavailable' : 'onlosecapture';
+
+ event.eventName = eventName;
+ event.memo = memo;
+
+ element.fireEvent(event.eventType, event);
+ return event;
+ }
+
+ var fireEvent = document.createEvent ? fireEvent_DOM : fireEvent_IE;
+
+
+
+ Event.Handler = Class.create({
+ initialize: function(element, eventName, selector, callback) {
+ this.element = $(element);
+ this.eventName = eventName;
+ this.selector = selector;
+ this.callback = callback;
+ this.handler = this.handleEvent.bind(this);
+ },
+
+
+ start: function() {
+ Event.observe(this.element, this.eventName, this.handler);
+ return this;
+ },
+
+ stop: function() {
+ Event.stopObserving(this.element, this.eventName, this.handler);
+ return this;
+ },
+
+ handleEvent: function(event) {
+ var element = Event.findElement(event, this.selector);
+ if (element) this.callback.call(this.element, event, element);
+ }
+ });
+
+ function on(element, eventName, selector, callback) {
+ element = $(element);
+ if (Object.isFunction(selector) && Object.isUndefined(callback)) {
+ callback = selector, selector = null;
+ }
+
+ return new Event.Handler(element, eventName, selector, callback).start();
+ }
+
+ Object.extend(Event, Event.Methods);
+
+ Object.extend(Event, {
+ fire: fire,
+ observe: observe,
+ stopObserving: stopObserving,
+ on: on
+ });
+
+ Element.addMethods({
+ fire: fire,
+
+ observe: observe,
+
+ stopObserving: stopObserving,
+
+ on: on
+ });
+
+ Object.extend(document, {
+ fire: fire.methodize(),
+
+ observe: observe.methodize(),
+
+ stopObserving: stopObserving.methodize(),
+
+ on: on.methodize(),
+
+ loaded: false
+ });
+
+ if (GLOBAL.Event) Object.extend(window.Event, Event);
+ else GLOBAL.Event = Event;
+
+ GLOBAL.Event.cache = {};
+
+ function destroyCache_IE() {
+ GLOBAL.Event.cache = null;
+ }
+
+ if (window.attachEvent)
+ window.attachEvent('onunload', destroyCache_IE);
+
+ DIV = null;
+ docEl = null;
+})(this);
+
+(function(GLOBAL) {
+ /* Code for creating leak-free event responders is based on work by
+ John-David Dalton. */
+
+ var docEl = document.documentElement;
+ var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
+ && 'onmouseleave' in docEl;
+
+ function isSimulatedMouseEnterLeaveEvent(eventName) {
+ return !MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &&
+ (eventName === 'mouseenter' || eventName === 'mouseleave');
+ }
+
+ function createResponder(uid, eventName, handler) {
+ if (Event._isCustomEvent(eventName))
+ return createResponderForCustomEvent(uid, eventName, handler);
+ if (isSimulatedMouseEnterLeaveEvent(eventName))
+ return createMouseEnterLeaveResponder(uid, eventName, handler);
+
+ return function(event) {
+ var cacheEntry = Event.cache[uid];
+ var element = cacheEntry.element;
+
+ Event.extend(event, element);
+ handler.call(element, event);
+ };
+ }
+
+ function createResponderForCustomEvent(uid, eventName, handler) {
+ return function(event) {
+ var cacheEntry = Event.cache[uid], element = cacheEntry.element;
+
+ if (Object.isUndefined(event.eventName))
+ return false;
+
+ if (event.eventName !== eventName)
+ return false;
+
+ Event.extend(event, element);
+ handler.call(element, event);
+ };
+ }
+
+ function createMouseEnterLeaveResponder(uid, eventName, handler) {
+ return function(event) {
+ var cacheEntry = Event.cache[uid], element = cacheEntry.element;
+
+ Event.extend(event, element);
+ var parent = event.relatedTarget;
+
+ while (parent && parent !== element) {
+ try { parent = parent.parentNode; }
+ catch(e) { parent = element; }
+ }
+
+ if (parent === element) return;
+ handler.call(element, event);
+ }
+ }
+
+ GLOBAL.Event._createResponder = createResponder;
+ docEl = null;
+})(this);
+
+(function(GLOBAL) {
+ /* Support for the DOMContentLoaded event is based on work by Dan Webb,
+ Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
+
+ var TIMER;
+
+ function fireContentLoadedEvent() {
+ if (document.loaded) return;
+ if (TIMER) window.clearTimeout(TIMER);
+ document.loaded = true;
+ document.fire('dom:loaded');
+ }
+
+ function checkReadyState() {
+ if (document.readyState === 'complete') {
+ document.detachEvent('onreadystatechange', checkReadyState);
+ fireContentLoadedEvent();
+ }
+ }
+
+ function pollDoScroll() {
+ try {
+ document.documentElement.doScroll('left');
+ } catch (e) {
+ TIMER = pollDoScroll.defer();
+ return;
+ }
+
+ fireContentLoadedEvent();
+ }
+
+ if (document.addEventListener) {
+ document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
+ } else {
+ document.attachEvent('onreadystatechange', checkReadyState);
+ if (window == top) TIMER = pollDoScroll.defer();
+ }
+
+ Event.observe(window, 'load', fireContentLoadedEvent);
+})(this);
+
+
+Element.addMethods();
+/*------------------------------- DEPRECATED -------------------------------*/
+
+Hash.toQueryString = Object.toQueryString;
+
+var Toggle = { display: Element.toggle };
+
+Element.Methods.childOf = Element.Methods.descendantOf;
+
+var Insertion = {
+ Before: function(element, content) {
+ return Element.insert(element, {before:content});
+ },
+
+ Top: function(element, content) {
+ return Element.insert(element, {top:content});
+ },
+
+ Bottom: function(element, content) {
+ return Element.insert(element, {bottom:content});
+ },
+
+ After: function(element, content) {
+ return Element.insert(element, {after:content});
+ }
+};
+
+var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
+
+var Position = {
+ includeScrollOffsets: false,
+
+ prepare: function() {
+ this.deltaX = window.pageXOffset
+ || document.documentElement.scrollLeft
+ || document.body.scrollLeft
+ || 0;
+ this.deltaY = window.pageYOffset
+ || document.documentElement.scrollTop
+ || document.body.scrollTop
+ || 0;
+ },
+
+ within: function(element, x, y) {
+ if (this.includeScrollOffsets)
+ return this.withinIncludingScrolloffsets(element, x, y);
+ this.xcomp = x;
+ this.ycomp = y;
+ this.offset = Element.cumulativeOffset(element);
+
+ return (y >= this.offset[1] &&
+ y < this.offset[1] + element.offsetHeight &&
+ x >= this.offset[0] &&
+ x < this.offset[0] + element.offsetWidth);
+ },
+
+ withinIncludingScrolloffsets: function(element, x, y) {
+ var offsetcache = Element.cumulativeScrollOffset(element);
+
+ this.xcomp = x + offsetcache[0] - this.deltaX;
+ this.ycomp = y + offsetcache[1] - this.deltaY;
+ this.offset = Element.cumulativeOffset(element);
+
+ return (this.ycomp >= this.offset[1] &&
+ this.ycomp < this.offset[1] + element.offsetHeight &&
+ this.xcomp >= this.offset[0] &&
+ this.xcomp < this.offset[0] + element.offsetWidth);
+ },
+
+ overlap: function(mode, element) {
+ if (!mode) return 0;
+ if (mode == 'vertical')
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+ element.offsetHeight;
+ if (mode == 'horizontal')
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+ element.offsetWidth;
+ },
+
+
+ cumulativeOffset: Element.Methods.cumulativeOffset,
+
+ positionedOffset: Element.Methods.positionedOffset,
+
+ absolutize: function(element) {
+ Position.prepare();
+ return Element.absolutize(element);
+ },
+
+ relativize: function(element) {
+ Position.prepare();
+ return Element.relativize(element);
+ },
+
+ realOffset: Element.Methods.cumulativeScrollOffset,
+
+ offsetParent: Element.Methods.getOffsetParent,
+
+ page: Element.Methods.viewportOffset,
+
+ clone: function(source, target, options) {
+ options = options || { };
+ return Element.clonePosition(target, source, options);
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
+ function iter(name) {
+ return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
+ }
+
+ instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
+ function(element, className) {
+ className = className.toString().strip();
+ var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
+ return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
+ } : function(element, className) {
+ className = className.toString().strip();
+ var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
+ if (!classNames && !className) return elements;
+
+ var nodes = $(element).getElementsByTagName('*');
+ className = ' ' + className + ' ';
+
+ for (var i = 0, child, cn; child = nodes[i]; i++) {
+ if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
+ (classNames && classNames.all(function(name) {
+ return !name.toString().blank() && cn.include(' ' + name + ' ');
+ }))))
+ elements.push(Element.extend(child));
+ }
+ return elements;
+ };
+
+ return function(className, parentElement) {
+ return $(parentElement || document.body).getElementsByClassName(className);
+ };
+}(Element.Methods);
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+ initialize: function(element) {
+ this.element = $(element);
+ },
+
+ _each: function(iterator, context) {
+ this.element.className.split(/\s+/).select(function(name) {
+ return name.length > 0;
+ })._each(iterator, context);
+ },
+
+ set: function(className) {
+ this.element.className = className;
+ },
+
+ add: function(classNameToAdd) {
+ if (this.include(classNameToAdd)) return;
+ this.set($A(this).concat(classNameToAdd).join(' '));
+ },
+
+ remove: function(classNameToRemove) {
+ if (!this.include(classNameToRemove)) return;
+ this.set($A(this).without(classNameToRemove).join(' '));
+ },
+
+ toString: function() {
+ return $A(this).join(' ');
+ }
+};
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+
+/*--------------------------------------------------------------------------*/
+
+(function() {
+ window.Selector = Class.create({
+ initialize: function(expression) {
+ this.expression = expression.strip();
+ },
+
+ findElements: function(rootElement) {
+ return Prototype.Selector.select(this.expression, rootElement);
+ },
+
+ match: function(element) {
+ return Prototype.Selector.match(element, this.expression);
+ },
+
+ toString: function() {
+ return this.expression;
+ },
+
+ inspect: function() {
+ return "#<Selector: " + this.expression + ">";
+ }
+ });
+
+ Object.extend(Selector, {
+ matchElements: function(elements, expression) {
+ var match = Prototype.Selector.match,
+ results = [];
+
+ for (var i = 0, length = elements.length; i < length; i++) {
+ var element = elements[i];
+ if (match(element, expression)) {
+ results.push(Element.extend(element));
+ }
+ }
+ return results;
+ },
+
+ findElement: function(elements, expression, index) {
+ index = index || 0;
+ var matchIndex = 0, element;
+ for (var i = 0, length = elements.length; i < length; i++) {
+ element = elements[i];
+ if (Prototype.Selector.match(element, expression) && index === matchIndex++) {
+ return Element.extend(element);
+ }
+ }
+ },
+
+ findChildElements: function(element, expressions) {
+ var selector = expressions.toArray().join(', ');
+ return Prototype.Selector.select(selector, element || document);
+ }
+ });
+})();
diff --git a/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/CHANGELOG b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/CHANGELOG
new file mode 100644
index 0000000..3925f1d
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/CHANGELOG
@@ -0,0 +1,1205 @@
+*V1.9.0* (December 23, 2010)
+
+* Update to Prototype 1.7
+
+* Search for all script[src] occurrences rather than just within the head. [pgib]
+
+* Fixed scrolling Sortables for Prototype 1.7 [fragility]
+
+*V1.8.3* (October 8, 2009)
+
+* Update to Prototype 1.6.1
+
+* Effect.toggle to return effect (to be able to do Effect.toggle(element, 'appear', {sync: true});) [RStankov]
+
+* Use element.identify() for fetching element.id in Sortable.create [RStankov]
+
+* Fix deprecated usage of Position.cumulativeOffset. [#182 state:resolved] [James Wheare]
+
+* Make loader work for application/xhtml+xml served documents. Closes #95. [Pavel Sedek]
+
+* Check for Windows Media plugin and RealPlayer plugin in Firefox on Windows to allow sound playback. Closes #36, #86. [Alexander Gavazov et al.]
+
+* Remove dead code in effects.js. Closes #125. [Confusioner]
+
+*V1.8.2* (November 18, 2008)
+
+* Update to Prototype 1.6.0.3
+
+* Make sure InPlaceEditor converts HTML entities to text. [Sean Kirby]
+
+* Fix that Builder.node did not return extended elements on IE. Closes #71 and #77.
+
+* Fix a bug in Sortable.destroy to make sure it's called on the referenced Sortable only, which allows for the correct intialization of nested Sortables. Closes Trac #8615. [Leon Chevalier]
+
+* Change Effect.Base#render not to use eval(), so certain JavaScript runtime environments (like Adobe AIR) that do not support eval() work. [King Maxemilian, John-David Dalton]
+
+* Fixed a calculation error in Effect.Transitions.pulse that could lead to flickering, add easing and change it to be a normal 0 to 1 transition that can be used with any effects; Effect.Pulsate now uses its own implementation. [Thomas Fuchs]
+
+* Fixed Effect.ScrollTo. Changeset 8686 had a typo, document.viewport.getScrollOffsets[0] is always undefined. Removed the max check as it is not a cross-browser way to get scroll height and breaks the effect. Depending on scrollTo to do the right thing. Closes #11306. [Nick Stakenburg]
+
+* Update version check so all Prototype versions can be required, not just x.x.x. Closes #10966. [Nick Stakenburg]
+
+* Using $$ in the loader instead of getElementsByTagName to prevent limitations. Closes #9032. [Nick Stakenburg]
+
+* Fix some missing semicolons. [jdalton]
+
+* Fix an issue with Effect.ScrollTo that caused Firefox to scroll to the wrong offset in some situations. Closes #10245. [nik.wakelin]
+
+* Fixes an issue with IE ghosting on non-absolute elements. Closes #10423. [Tanrikut, tdd]
+
+*V1.8.1* (January 3, 2008)
+
+* Fix Element#getStyles in IE. Closes #10563. [Tobie Langel]
+
+* Update to Prototype 1.6.0.1 as of 8551.
+
+* Fix a regression with autocompleters not responding correctly to cursor keys on both Safari and IE. Closes #10107. [thx Zman771]
+
+*V1.8.0* (November 6, 2007)
+
+* Update to Prototype 1.6.0 final
+
+* Ajax.InPlaceEditor now can deal with callbacks that return an object. Closes #10064. [tdd]
+
+* Fix a potential problem with the loader and Firefox 2.0 on the Mac. Closes #9951. [awaters]
+
+* Add duration and distance options to Effect.Shake. Closes #8637. [amiel, rmm5t]
+
+* Update code to use new Hash implemention in Prototype 1.6. Update InPlaceEditor to use new Class.create syntax. [tdd]
+
+*V1.8.0 preview 0* (October 12, 2007)
+
+* Update to new Class.create syntax in Prototype 1.6; update to latest Prototype 1.6 trunk.
+
+* Fix bottom CSS property reassignment and initialization in queues for Effect#SlideUp. Closes #7412, #7761.
+
+* Fix an issue with String#parseStyle that could sometimes cause errors on Safari 2.
+
+* Refactoring to use Prototype 1.6. Remove dependency of Effect.tagifyText from builder. Use Prototype code style rules more consistently.
+
+* Remove the deprecated Effect2 namespace.
+
+* Update to Prototype 1.6.0_rc0.
+
+* Some effect code refactoring to take advantage of new Prototype 1.6 features.
+
+* Effect.ScrollTo is now no longer a core effect (returns a Effect.Tween instance now).
+
+* Add Effect.Tween, a new core effect. This effect tweens between two values and sets a property or calls a method on an object (including DOM elements); or allows for a callback method, which will be automatically bound to the object.
+ Examples:
+ var whatever = { blech: 0 };
+ new Effect.Tween(whatever, 5, 0, 'blech'); // sets property on the object
+ new Effect.Tween('foo', 10, 20, 'innerHTML'); // sets property on the 'foo' DOM element
+ new Effect.Tween('foo', 10, 20, 'update'); // method call on 'foo' DOM element
+ new Effect.Tween('foo', 50, 0, { duration: 2.0 }, function(p){
+ this.setStyle({border:p.toFixed(3)+'px solid red'});
+ });
+ new Effect.Tween(null, 0, 100, function(p){ scrollTo(0,p) }); // scrolls the window
+
+* Revert the workaround for the Firefox issue that makes autocompleter input field values be remembered correctly when the back button is hit to return to a page that contains autocompleted values, as this can cause "Are you sure you want to navigate away?" popups. Closes #8411. [okada]
+
+* Improve the way deactivating the active droppable is handled. Closes #9072. [Karsten Sperling]
+
+* Next version will be 1.8.0. Update to Prototype 1.6.0_pre1.
+
+* Make draggable initialization faster. Closes #8697. [ssinghi]
+
+* Make BDD-style testing compatible with IE6 and IE7. Closes #8972. [steveluscher]
+
+* Add BDD methods to booleans. Closes #9147. [steveluscher]
+
+* Add support for full CSS inheritance in Effect.Morph. Closes #9054. [Tobie]
+ IMPORTANT: Note that this could potentially change the outcome of classname-based morphs, so be sure to check your morph effects if you use this feature.
+ For this feature, the new method Element#getStyles is introduced, which returns an objects which properties correspond to the CSS properties found in Element.CSS_PROPERTIES. Note that this method doesn't work seemlessly across browsers for certain non-measurable CSS properties, such as float.
+
+* Add the externalControlOnly option to the in-place editors to allow for external controls to exclusively trigger the in-place editing. Closes #9024. [tdd]
+
+* Complete rewrite of Ajax.InPlaceEditor and Ajax.InPlaceCollectionEditor. [tdd]
+ THIS UPDATE MIGHT AFFECT BACKWARDS COMPATIBILITY.
+ Be sure to properly test, especially if you're using multi-line editing and/or monkeypatching.
+ Read more about all the added goodness in this article:
+ http://mir.aculo.us/2007/7/17/in-place-editing-the-summer-2007-rewrite
+
+* Update to Prototype 1.5.2_rc0 r7076:
+ - Works around bugs in Safari 1 and Safari 2 Regexp engines that could cause crashes
+ - Fixes a rendering issue with opacity-based effects and floating elements on Safari
+
+* Mild refactoring of sound.js to take advantage of new Prototype features.
+
+* Add highlight element method as a shortcut to Effect.Highlight.
+ Example:
+ $('message').highlight({startcolor:'#ff0000'}).update('KTHXBYE');
+
+* Improve performance of String.prototype.parseStyle by caching the dummy element used.
+
+* Add combined effects as element methods.
+ Examples:
+ $('message').appear().update('Oh noes!');
+ $('login').shake({ duration: 2 });
+
+* Add Effect.Transitions.spring, which simulates a spring which oscillates while coming to rest. This transition is specifically targeted towards use with Effect.Move, for example as a reverteffect when using Draggables, as it will have return values >1 and cause temporary "overshooting" of the effect. Closes #8474. [edg2s]
+
+* Fix effects initialization if no options are given. Fixes #7809. [thx Kroc Camen]
+
+* Fix incorrect placement on drop for absolute ghosting elements. Update to Prototype 1.5.2_rc0 r6955 (required for #8581). Closes #8581. [tdd]
+
+* Make sure the autocompletion happens on the token where the cursor is, not the last token when using tokenized autocompleting text fields. Closes #8588. [tdd]
+
+* Fix that non-Mozilla browsers would display messages with the autocompleter back-button fix introduced in 1.7.1 beta 2. Fixes #7752, #8411. [josh, stetz]
+
+*V1.7.1 beta 3* (May 19, 2007)
+
+* Update to Prototype 1.5.1 final
+
+* New elements and handles options for Sortable.create which take arrays of elements or element ids. These overrule the normal handle and elements finding options on initialization of the sortable, and can yield huge performance increases in situations where these elements or ids are known at call time. [Thomas Fuchs]
+
+* Major performance improvement of Sortable.create when using the handle option. [Tobie Langel]
+
+* Fix Builder.node double quote escaping in attributes, fixes #8125. [Aa!]
+
+*V1.7.1 beta 2* (April 28, 2007)
+
+* Update to Prototype 1.5.1_rc4
+ - Various optimizations and fixes
+ - http://dev.rubyonrails.org/browser/spinoffs/prototype/trunk/CHANGELOG?rev=6604
+
+* Fix autocompleter indicator not appearing when calling activate() directly. Don't show indicator for local autocompleting. Fixes #7770. [pyro8019]
+
+* Don't clear out autocompleting fields in Mozilla-based browsers when navigating back to a page with the Back button, fixes #7752. [seanc]
+
+*V1.7.1 beta 1* (March 12, 2007)
+
+* Update to Prototype 1.5.1 r6386
+ - Fixes SlideUp/SlideDown on IE
+ - Fixes an opacity problem with IE
+ - Performance optimizations
+ - See http://dev.rubyonrails.org/browser/spinoffs/prototype/trunk/CHANGELOG?rev=6381 for more information
+
+* Make builder unit tests work on IE
+
+* Fix id assignment for sounds on Firefox/Windows, fixes #7709 [Robert Wallis]
+
+* Add Sound.enable() and Sound.disable() to globally turn off Sound.play()
+
+* Added Sound.play(url,options) in new sound.js file. scriptaculous.js automatically includes this file.
+ Based on code by Jules Gravinese, used with permission.
+
+ The sound player uses native sound support on IE, and falls back to using <embed> on other browsers,
+ which means it uses QuickTime for most cases. The recommended format to use is MP3.
+
+ Examples:
+ Sound.play('blah.mp3');
+ // --> plays sound immediately in 'global' track
+ Sound.play('blah.mp3',{replace:true});
+ // --> stop playing all sounds in 'global' track, and play new sound
+ Sound.play('blah.mp3',{track:'mytrack'});
+ // --> places the sound in the 'mytrack' track
+ Sound.play('blah.mp3',{track:'mytrack',replace:true});
+ // --> stop playing all sounds in 'mytrack' track, and play new sound
+
+ The sound effect used in the functional test is "Sword being drawn" by James Greever, released as freeware.
+
+* Various effects engine optimizations [Tobie Langel, Thomas Fuchs]
+
+* Make Ajax.InPlaceEditor more customizable: [thx godlie]
+ - Add an okLink option to Ajax.InPlaceEditor so you can have a link instead of a button. Uses the 'editor_ok_link' CSS class for styling, fixes #6455
+ - Add an cancelButton option to Ajax.InPlaceEditor, uses the 'editor_cancel_button' CSS class
+ - Add textBefore-, textBetween- and textAfterControls (which default to empty strings)
+ - For consistency, cancel link now also gets 'editor_cancel_link' CSS class
+
+* Add an onDropped callback to Draggables, that fires at the end of a drag when the Draggable was dropped on a Droppable
+
+* Add revert: 'failure' option to Draggables to only revert if not dropped on a valid drop target, fixes #6909 [davidw]
+
+* Update to new Prototype Browser detection
+
+* Fix a memory leak with Effect.Morph in Firefox, fixes #7558 [Malard]
+
+* Add ability to nest single nodes in Builder.node in addition to arrays of nodes.
+ Examples:
+ var element = Builder.node('div', Builder.node('span','blah'));
+
+ Builder.dump();
+ var element = DIV(SPAN('blah'));
+
+*V1.7.0* (January 19, 2007)
+
+* Cleanups for Effect.Morph
+
+* Monkeypatch Prototype 1.5.0 to incorporate [6002], fixes setStyle({opacity:0}) for IE
+
+* Fix Effect.inspect() for Prototype 1.5.0 final hash changes
+
+* Update to Prototype 1.5.0 final
+
+* New option keepBackgroundImage: true for Effect.Highlight, fixes #5037 [docwhat, tomg]
+
+* Minor tweaks for issues with application/xhtml+xml documents on Firefox, fixes #6836 [sjinks]
+
+* Fix a possible exception with Sortables, fixes #6828 [craiggwilson]
+
+* Update to Prototype 1.5.0_rc2 revision [5844] (as of Rails 1.2 RC 2)
+
+*V1.7.0 beta 2* (December 18, 2006)
+
+* Change the default setting for effects to support up to 60fps, if renderable by the browser. Add performance info to effects unit test.
+
+* Change get/setOpacity to use Prototype's new support for cross-browser opacity.
+
+* Update to Prototype 1.5.0_rc2 revision [5741], which fixes some of the reported issues with beta 1 (see Prototype's CHANGELOG for more):
+ * Opera 9, while not officially supported, should work now with Prototype and script.aculo.us
+ * Fixes issue with Safari when using Prototype's Ajax helpers with HTTP authorization
+
+* Add hash and CSS className support to Effect.Morph, fixes #6674 [Tobie]
+ Examples:
+ $(element).morph('myClass')
+ // will morph to all the properties specified
+ // in .className (in your external stylesheet).
+ // All properties which cannot be morphed (such as font-style)
+ // will be applied AfterFinish
+ $(element).morph('font-size: 10px') // or
+ $(element).morph({fontSize: '10px'}) // will morph the font-size to 10px
+
+*V1.7.0 beta 1* (November 21, 2006)
+
+* Add Element.morph() and Element.Methods.morph() as a shortcut to Effect.Morph
+ Example:
+ // basic Effect.Morph
+ $('error_message').morph('color:#f00;font-size:17px');
+ // fade out after a while
+ $('error_message').show().morph('font-size:17px').morph('opacity:0',{delay:4});
+
+* Update to Prototype 1.5.0_rc2 revision [5580]
+
+* Add a paramName option to the inplace editor for overriding the default parameter name of "value"
+
+* Add Effect.Transform that generates parallel executing Effect.Morph sets
+ Example:
+ // set up transformation
+ var transformation = new Effect.Transform([
+ { 'div.morphing': 'font-size:20px;padding-left:40em' },
+ { 'blah' : 'width:480px;border-width:10px;border-right-width:20px;margin:200px;margin-bottom:-20px;font-size:30px' }
+ ],{ duration: 0.5 });
+ // play transformation (can be called more than once)
+ transformation.play();
+
+* Add Effect.Morph core effect that morphs to a given CSS style rule. Effect.Morph does take orginal styles given by CSS style rules or the style attribute into consideration when calculating the transforms. It works with all length and color based CSS properties, including margins, paddings, borders, opacity and text/background colors.
+ Example:
+ new Effect.Morph('mydiv',{
+ style: 'font-size:3em;color:#f00;border-width:2em',
+ duration: 2.0
+ });
+
+*V1.6.5* (November 8, 2006)
+
+* Update to Prototype 1.5.0_rc1 revision [5462]
+
+* Support the HTML 'for' attribute in Builder by using 'htmlFor', fixes #6472 [gjones, tdd]
+
+ var node = Builder.node('label', { htmlFor: 'myinput' });
+
+* Add support to run a specific failing unit test by clicking on the corresponding test result, fixes #6290 [leeo]
+
+* Add modifier key support to Event.simulateMouse, fixes #6391 [savetheclocktower]
+
+* Add rails-trunk update task, clean up references to MIT license
+
+* Add new 'with-last' queue position option to queue effects to occur in parallel with the last effect to start in the queue
+
+* Add new special core effect Effect.Event for one-shot events that follow timelines defined by effect queues
+
+ new Effect.Event({ afterFinish:function(){
+ // do some code here
+ }, position: 'end' });
+
+* Do some refactoring to make use of Prototype 1.5 functionalities and save LOC
+
+* Fix an possible crash of IE on Effect.SlideUp, fixes #3192 [thx nel]
+
+* Add Builder.build() to create nodes from strings containing HTML, [DHH]
+
+ var node = Builder.build("<p>this is <b>neat!</b></p>");
+
+* Add a pulses parameter to Effect.Pulsate to control the amount of pulses, fixes #6245 [leeo]
+
+ For example, Effect.Pulsate('d8', {pulses: 2}) would pulsate twice. If the option is not given, it defaults to five pulses.
+
+* Fix an issue with clicking on a slider span resulting in an exception, fixes #4707 [thx sergeykojin]
+
+* Fix an issue with Draggables when no options are supplied, fixes #6045 [thx tdd]
+
+*V1.6.4* (September 6, 2006)
+
+* Hotfix IE issues with patched Prototype V1.5.0_rc1
+
+*V1.6.3* (September 5, 2006)
+
+* Update Prototype to V1.5.0_rc1
+
+* Merge assertElementsMatch and assertElementMatches from Prototype's [4986] unittest.js [Sam Stephenson]
+
+* Update Prototype to revision [4930]
+
+* Fix various issues with IE detection and Opera, and setOpacity, fixes #3886, #5973
+
+* Make Sortable.serialize handle DOM IDs like "some_element_1" correctly, fixes #5324
+
+* Add assertRespondsTo and shouldRespondTo assertions
+
+* Add experimental alternate syntax for unit tests (Behaviour Driven Development-style)
+
+* Add support for onStart, onDrag and onEnd events directly on Draggables (invoked from the Draggables.notify), fixes #4747 [thx scriptkitchen]
+
+* Add element shortcuts to Builder that can be activated by calling Builder.dump() (see the unit test), fixes #4260 [thx napalm]
+
+* Fix selection of correct option in SELECT element generated by InPlaceCollectionEditor for indexed option arrays, fixes #4789 [thx steve]
+
+* Add autoSelect option to Autocompleters to auto select an entry if only one is returned, fixes #5183 [thx cassiano dandrea]
+
+* Added delay option to Draggables and Sortables, see test/functional/dragdrop_delay_test.html for usage, implements #3325 [thx lsimon, tomg]
+
+* Remove revert cache code obsoleted by #4706, fixes #3436 (again) [thx tomg]
+
+* Fix autoscrolling inside scrollable containers when window is scrolled too, fixes #5200 [thx wseitz]
+
+* Make Effect.Puff work correctly for floating elements, fixes #3777 [thx michael hartl]
+
+* Add version and timestamp to indvidual library files for easier identification (the files are preprocessed by the Rake fresh_scriptaculous task), fixes #3015 [thx Tobie]
+
+* Add assertIndentical and assertNotIdentical unit test assertions, which test for equality and common type, fixes #5822 [thx glazedginger]
+
+* Add integration test for Ajax autocompleter for results with no linebreaks, #4149
+
+* Fix an issue with redrawing ghosted draggables that are inside a scrolled container, fixes #3860 [thx gkupps, tsukue]
+
+* Added a custom exception to all base effects when used on non-existing DOM elements, added a assertRaise method to unit tests
+
+* Fix autoscrolling when dragging an element unto a scrollable container, fixes #5017 [thx tomg]
+
+* Fix a condition where overriding the endeffect on Draggables without overriding the starteffect too leads to a Javascript error [thx Javier Martinez]
+
+* Fix a possible error with the drag/drop logic (affects the solution to #4706)
+
+*V1.6.2*
+
+* Fix a problem in the drag and drop logic if an reverting/drag ending draggable was initialized for a new drag (for example by clicking repeatedly) for all cases where the default start/revert/end-effects are used, fixes #4706 [thx tecM0]
+
+* Fix possible memory leaks with Draggables, fixes #3436 [thx aal]
+
+* Throw nicer errors when requires script.aculo.us libraries are not loaded, fixes #5339
+
+* Make slider handles work when not displayed initially by using CSS width/height, fixes #4011 [thx foysavas]
+
+* Update sortable functional test with onUpdate counter
+
+* Make more Element extensions unit tests work on Safari
+
+* Add the assertMatch unit test assertion for asserts with RegExps [thx Ian Tyndall]
+
+* Fix a problem with Effect.Move causing "jumping" elements because of very low float numbers in some situations
+
+* Fix a missing semicolon in dragdrop.js, fixes #5569 [thx mackalicious]
+
+* Fix a slight inaccuracy with Effect.Scale that could lead the scaling to be one pixel off
+
+* Be more prototypish with Effect.Transitions.linear
+
+* Make Effect.Scale recognize font sizes that use the pt unit, fixes #4136 [thx aljoscha]
+
+* Fix IE hack in Effect.Opacity, fixes #5444 [thx nicholas]
+
+* Fix IFRAME layout fix for IE and Autocompleter, fixes #5192 [thx tommy skaue]
+
+* Fix only option in onEmptyHover, fiex #5348 [thx glenn nilsson]
+
+* Fix Effect.BlindDown and SwitchOff handling of supplied callbacks, fixes #5089 [thx martinstrom]
+
+* Fix a problem with field focus on Ajax.InPlaceEditor and loading external text, fixes #4988, #5244 [thx rob]
+
+* Do not attempt to scroll if scrollspeed is 0/0, fixes #5035 [thx tomg]
+
+* Fix a problem with Sortable Tree serialization, fixes #4939, #4688, #4767 [thx Sammi Williams]
+
+* Fix an endless loop with sliders, fixes #3226, #4051, #4765 [thx jeff]
+
+* Make autocompleter work with update DIVs that have scrollbars, fixes #4782 [thx Tommy Skaue]
+
+* Corrected options parsing on switchoff effect, fixes #4710 [thx haldini]
+
+*V1.6.1*
+
+* Update to Prototype 1.5.0_rc0
+
+* Add Draggable object as third parameter to snap, fixes #4074 [thx mdaines]
+
+* Fix an IE flicker with SlideUp/SlideDown, fixes #3774, [thx sbbowers]
+
+* Add parsing/setting of any currently set opacity CSS rule to default opacity effect on draggables, fixes #3682 [thx Mike A. Owens]
+
+* Added prototype $() performance patch from #4477 and updated effects.js to new Element.addMethods() syntax
+
+* Sortable trees [thx Sammi Williams, sammi@oriontransfer.co.nz]
+ - Added functional test (test/functional/sortable_tree_test.html)
+ - removed greedy option
+ - modified the way Droppables.show works - added affected list
+ - added Droppables.findDeepestChild
+ - modified Sortable.options to work for trees
+ - modified Sortable.onEmptyHover with additional logic to insert
+ the element at a certain place according to the overlap
+ - modified Sortable.onHover to avoid DOM Exceptions
+ - modified Sortable.create to support the creation of Sortable trees
+ - added two convenience functions - Sortable.findElements and
+ Sortable.findTreeElements
+ - Added Sortable.tree (and a number of private functions to facilitate it)
+ Returns a tree structure:
+ var root = {
+ id: null,
+ parent: null,
+ children: <children>,
+ container: <sortable element>,
+ }
+ var child = {
+ parent: <node>,
+ children: <array>,
+ id: <string> (as per options.format),
+ element: <element>,
+ container: <element>,
+ position: <integer>
+ }
+ This is intended to become part of the public API, and can be used to manipulate
+ the tree programatically.
+ - Modified Sortable.serialize to use Sortable.tree when set in the options.
+
+* Fix a problem with window scrolling on draggables [thx Gregory Hill]
+
+* Let the benchmark method return the time taken in ms, so it can be used for time-based assertions
+
+* Fix problem with id-based handle names and draggables
+
+* More Element.childrenWithClassName optimization
+
+* Added benchmark method to unittest.js; some cleaning up of unit tests
+
+* Add fix for IE memory leaks in included prototype.js from [4094]
+
+*V1.6.0*
+
+* Major speedup for sortable with handles initialization [thx Jamis Buck]
+
+* Update to latest Prototype 1.5.0_pre1 trunk
+
+* Add functional "random effects" test, also for browser compatibility testing
+
+* Fix two typos introduced with the 1.5 Methods syntax update
+
+* Add functional test for $$-triggered effects with .visualEffect
+
+* Fix shift-tab for autocompleter in Safari, fixes #4423 [thx matt]
+
+* Prepare for script.aculo.us 1.6, add Prototype 1.5 requirement and check that Element.Methods is available in the scriptaculous loader
+
+* Refactor effects.js to use the new Prototype 1.5 Element Methods syntax
+
+* Update to latest Prototype 1.5.0_pre0 trunk
+
+* Fix a problem with the draggable window scrolling code and scrolling inside overflow containers
+
+* Add passing through of scroll options from Sortable to Draggable [thx Gregory Hill]
+
+* Make it possible to scroll window on dragging, #3921 [thx rdmiller]
+
+* Make Element.forceRerendering give up on any exception (this fixes various problems with IE)
+
+* added visualEffect method for the Element Mixin, fixed so you can chain multiple calls. [Rick Olson]
+
+* Fix only option on Sortable.create to accept multiple class names, fixes #3427 [thx glenn nilsson]
+
+* Added workaround for a rendering bug in Safari when using floating elements with Effect.Appear
+
+* Update lib/prototype.js to Prototype 1.5.0_pre0
+
+*V1.5.3*
+
+* Change version number to V1.5.3, prepare Rakefile
+
+* Remove unneeded height restoring in Effect.BlindDown as that is handled internally by the restoreAfterFinish option to Effect.Scale, fixes #3667 [thx Ross Lawley]
+
+* Added Ajax.InPlaceCollectionEditor which uses a SELECT element instead of a text field (see test/functional/ajax_inplacecollectioneditor_test.html for usage), #3491 [thx anna]
+
+* Enable in place editor to use RJS (implements a new evalScripts option for the in place editor), #3490 [thx Richard Livsey]
+
+* Added Sortable.setSequence to programmatically reorder a Sortable, #3711 [thx Mike A. Owens]
+
+* Added unit test for #3732 (currently fails due to Prototype #3877) [thx michal]
+
+* Fix span positioning for sliders with ranges not starting at 0, fixes #3731 [thx michal]
+
+* Make name option on Sortable.serialize work again, fixes #3873
+
+* Make dragging cancel only on ESC key, not on any key, fixes #3817
+
+* Fix Rakefile for V1.5.2
+
+*V1.5.2*
+
+* Change version number to V1.5.2
+
+* Fix a wrong parameter in dragdrop.js, fixes #3555
+
+* Fix two typos in effects.js, fixes #3481 [thx jtolds]
+
+* Add assertEnumEqual for unit testing (from Prototype SVN trunk) [Sam Stephenson]
+
+* Add Sortable.sequence method to extract the current sequence of a Sortable as an array, fixes #3675 [thx sphivo]
+
+* Add limit option to effect queues to limit the maximum number of effects in a queue, new unit tests for scoped effect queues, fixes #3498 [thx Abdur-Rahman Advany]
+
+* Fix Element.collectTextNodesIgnoreClass to correctly filter child nodes, fixes #3380 [thx lam]
+
+* Fix a condition where OPTION elements could cause unwanted dragging on Draggables, fixes #3441 [thx tom]
+
+* Fix a crash because of an IE bug in Effect.SlideDown, fixes #3192 [thx Rob Mayhew]
+
+* Added experimental auto-scroll option to Draggables and Sortables, activate with scroll: 'id_of_scroll_container_element'.
+ Note: needs testing, call syntax might change
+ See test/functional/dragdrop3_test.html for usage/demo
+
+* Added activate method to Autocompleter that allows you to trigger the suggestions through other means than user input [DHH]
+
+*V1.5.1*
+
+* Add select option to Autocompleter to optionally use textnodes from elements with a specific CSS class (see test/functional/ajax_autocompleter_test.html for usage)
+
+* In-place editor: add ok/cancel visibility options and onblur() submission, fixes #3233 [thx pulsation]
+ Note: currently, blur form submission breaks the cancel link functionality, if enabled
+
+* Added Effect.toggle for slide, blind and appear/fade effects, fixes #2704 [thx Azad]
+
+* Added selective component loading to scriptaculous.js, see test/unit/loading_test.html for usage [thx David Zülke]
+
+* Added local/scoped effect queues [thx David Zülke]
+
+* New core effect Effect.Move that can do absolute/relative movement [thx David Zülke]
+
+* Make default effects options modifyable globally by setting Effect.DefaultOptions
+
+* Make Draggables recognize top/left CSS properties defined in an external stylesheet, fixes #3205 [thx ansonparker]
+
+* Fixed draggables starting to drag even if mouse button was released with no movement, [thx topfunky]
+
+* Updated the README to reflect final status
+
+*V1.5.0*
+
+* Prepared for V1.5.0 final
+
+* Update lib/prototype.js to Prototype 1.4.0 final
+
+*V1.5.0_rc6*
+
+* Update lib/prototype.js to Prototype 1.4.0_rc4
+
+* Fix Effect.SlideDown/SlideUp on Internet Explorer, includes a change to Effect.Scale, (should) fix #2962 and others, [thx wyldeone]
+
+* Make Draggables that are reverting cancel the default revert effect when they are dragged again while reverting, fixes #3188, [thx maverick]
+
+* Fix a problem with a wrong reference in Effect.Pulsate, fixes #3184, [thx cyx_]
+
+* Fix Sortable.findElements for XHTML in Gecko, fixes #3081, [thx fgnass]
+
+* Fix a problem with the slider getting NaN results when clicking directly on the track, fixes #3020, [thx rectalogic]
+
+* Fix a problem with Safari not doing sub-pixel rendering when setting opacity to 1 with Element.setOpacity
+
+* Fix slider to make handle width/height count for track length, fixes #3040, fixes #3017, [thx buggedcom]
+
+* Added Basic unit test for Effect.inspect
+
+* Fix Effect.multiple to deal correctly with delays
+
+* Safeguard Effect.Base.render to only do updates when Effect is in running state, fixes #2912
+
+* Added inspect method to Effect.Base
+
+* Added functional test for DOM-based UL sortables #3016
+
+* Added offset option to Effect.ScrollTo
+
+* More effects.js/dragdrop.js refactoring
+
+* Refactoring and optimizations for effects (not complete yet)
+
+* Refactoring and optimizations for Draggables/Droppables/Sortables (not complete yet)
+
+*V1.5.0_rc5*
+
+* Make Droppables.remove accept DOM IDs in addition to elements
+
+* Added some unit tests for drag and drop
+
+* Update lib/prototype.js to Prototype 1.4.0_rc3
+
+* Make 'contents' a synonym for 'content' on Effect.Scale scaleMode option
+
+* Fix some possible exceptions in slider.js
+
+* Support for various snapping options on Draggables, adresses #2826, [thx saimonmoore]
+
+* Support horizontal ghostable Sortables, fixes #2794, [thx johnm]
+
+* Prevent an exception on IE with a functional test, see #2706
+
+* Add functional testing of hoverclasses for sortables
+
+* Add an assert for correct UTF-8 return chars in Autocompleter
+
+* Correct IE detection in Autocompleter for Opera, fixes #2558 [thx gary]
+
+* Add onDrag callback to Draggable observers, #2827 [thx saimonmoore]
+
+* Added Form.Element.DelayedObserver to controls.js for live-search fields
+
+* Remove Element.Class in favour of Prototype Element.ClassNames, new function Element.childrenWithClassName()
+
+* Update Copyright notice in slider.js
+
+* Fix slider firing onChange events to eagerly on dragging a handle [thx wombert]
+
+* Fix a problem with Start/End spans and single handles
+
+* Add event property to Slider object so that callbacks can determine if setValue originated from a UI event or from script
+
+* Fix Builder.node() throwing unresolved errors in IE6, #2707 [thx flwombat]
+
+* Give currently active handle on slider the "selected" CSS class
+
+* Add start and end spans to slider
+
+* Make track clickable for sliders (moves last active handle [or first handle] to nearest possible position)
+
+* Make initial values on slider work for single and multiple handle sliders
+
+*V1.5.0_rc4*
+
+* Abort Effect.Highlight on elements which have display:none set (prevents problem with Safari)
+
+* Make Effect.Queue an Enumerable, fix a problem with Effect.Grow, more unit tests
+
+* Added restricted option to prevent moved of handles prior/after adjacent handles on Sliders with multiple handles
+
+* Update lib/prototype.js to Prototype 1.4.0_rc2
+
+* Fix a bug with wrongly scrolling to the page top in Ajax.InPlaceEditor (circumvents various browser bugs) [Jon Tirsen], #2616
+
+* major slider refactoring, changed slider range to default to [0,1]. Slider Range can be set with range:$R(from,to) option. The increment option is not active for now.
+
+* Added spans support for Control.Slider to mark spans bordered by slider handles, see unit test [thx to www.bartenbach.de for sponsoring this functionality]
+
+* Added preliminary support for optional multiple handles to Control.Slider [thx to www.bartenbach.de for sponsoring this functionality]
+
+* Fixed wrong inclusion of libs in inplace editor functional test
+
+* Fixed Effect.SlideDown/SlideUp to honor refactoring of Effect.Scale, fixes #2523 [thx obiwanki]
+
+* Reset the zIndex on Draggables correctly, #2483 [thx Jon Whitcraft]
+
+* Fix onChange callback on Sortables when dragging between sortables, #2488 [thx Dylan Greene]
+
+* Removed Builder code from effects.js, removed Object.debug (implemented as Test.Unit.inspect)
+
+* Added slider unit tests, fixed handling of values to autocalculate min/max, fixed upper/lower boundaries on setting the value programmatically
+
+* Synced to Rails 1.0 release candidate, update to Prototype 1.4.0_rc1, removed util.js, merged rests of util.js into effects.js to prepare for refactoring
+
+* Give Builder it's own file
+
+* Fix a logic issue with Autocompleter [thx tshinnic], #2457
+
+*V1.5.0_rc3*
+
+* Make Effect position available to callbacks
+
+* Droppables.fire: send event to onDrop callback [François Beausoleil], #2389
+
+* InPlaceEditor: Add disabling the field while loadTextURL loads and add a class while loading, plus fix various bugs with Internet Explorer and InPlaceEditor, [Jon Tirsen] #2302, #2303
+
+* Made Droppables.remove work again [thx Mindaugas Pelionis], #2409
+
+* Fixed that IE6 would incorrectly render the "fix-windowed-elements-overlapping" IFRAME on autocompletion [thx tshinnic], #2403
+
+* Fixed Element.getOpacity throwing an error on Safari in some situations (this caused the autocompleter not to work)
+
+* Added format option to Sortable.create and Sortable.serialize to allow custom id formats. The format option takes a regular expression where the first grouping that matches is used for building the parameters. The default format is /^[^_]*_(.*)$/ which matches the string_identifier format. If you want to use the full id of the elements, use "format: /(.*)/". More examples are available in the sortable unit test file.
+
+* Started refactorings to use the new Prototype features and general code-cleanup
+
+* Update lib/prototype.js to Prototype 1.4.0_pre11
+
+* Fixed a typo breaking the up arrow key for autocompletion [thx tshinnic], #2406
+
+* Changed the handle option on Draggbles to accept classnames, or ids or elements [thx to Andrew West], #2274
+
+* Force indicator to be hidden on hiding autocompletion update element, #2342
+
+* Make Draggables honor external CSS positioning [thx to Mark Shawkey], #2359
+
+* Make zindex handling for Draggables honor external CSS styles
+
+* Fix two Sortable.serialize issues, [thx Avi, Gorou], #2339, #2357
+
+* Make Element.getOpacity work with IE, added unit tests [thx to Greg Hill]
+
+* Make Element.setOpacity honor non-alpha filters on IE (it now works with filters for alpha PNGs)
+
+* Fixed that Element.class.remove wrongly deleted spaces between class names, fixes #2311, #2313
+
+* Fixed Builder for OPTION and OPTGROUP tags on Firefox < 1.5 and Internet Explorer 6, completely fixes #2325
+
+* Improved Builder implementation to deal with Firefox-specific requirements and innerHTML parsing, partly fixes #2325
+
+*V1.5.0_rc2*
+
+* Update lib/prototype.js to corrected Prototype 1.4.0_pre7 (fixed a problem with IE)
+
+* Update lib/prototype.js to Prototype 1.4.0_pre7
+
+* Reverted to patched version of Prototype 1.4.0_pre4 for the time being (getResponseHeader problem on Mozilla)
+
+* Attempt to fix crashes in Safari 2.0.1, probably related to the event registering und unregistering in Draggables, possibly fixes #2310
+
+* Update lib/prototype.js to Prototype 1.4.0_pre6
+
+* Changed effects_test.html functional test to incoporate Firefox anti-flicker overflow:hidden CSS property
+
+*V1.5.0_rc1*
+
+* Prepared Rakefile and README for V1.5.0_rc1 release
+
+* Droppables w/greedy and hoverclass are now reverted when dragged item is no longer over them, fixes #2184
+
+* Let Effect.Highlight correctly parse IE colors, add String.prototype.parseColor() for this, fixes #2037
+
+* Fix Effect.Highlight to restore background image only if there was one
+
+* Made Effect.tagifyText work again on IE
+
+* Added String.prototype.toArray because Strings aren't iterable on IE
+
+* Fixed Element.getOpacity falsely returning 0 on IE
+
+* Some cleaning up in util.js
+
+* Cleaned up Effect.Opacity
+
+* Removed useless line in Position.page
+
+* Make scriptaculous.js work if a query strings are used when calling it
+
+* Fixed typos in slider.js and the functional test
+
+* Fixed a bug with Safari and the InPlaceEditor with form submission. Add support for interpreting simple <br>s into linebreaks. [Jon Tirsen]
+
+* New Control.Slider() for horizontal and vertical sliders [Marty Haught]
+
+* Fixed autoapplying a 'layout' on IE with Effect.Opacity not working for elements given as id string
+
+* Make Effect.Parallel render final frames and call beforeFinish/afterFinish on included effects
+
+* Make Element.setOpacity work correctly again (browser-specific extensions, except for IE, are disabled at this time)
+
+* Added focusing the text field or text area created when using Ajax.InPlaceEditor #2126 [thx to Lee Mallabone]
+
+* Fixed Element.Class.childrenWith not returning the correct elements #2120 [cmees AT rogers DOT com]
+
+* Added MIT-LICENSE header to scriptaculous.js, cut back on license info in other libs to keep files smaller
+
+* Fix issues with form elements inside draggables not clickable with Firefox #2129
+
+* Fixed an error in dragdrop.js with Draggables when no Droppables are defined
+
+* Fixed an issue with Element.makePositioned causing Effect.SlideDown to fail on Safari
+
+* Make effects "stateless" by cleaning up element.style after finish of effect #2133 [agr30 AT uni-koeln DOT de]
+
+* Add "internal" events to effects, to make them more easily extendable [Martin Bialasinski]
+
+* Set container element height to auto on finishing Effect.BlindDown und Effect.SlideDown #2123 [Tony Arnold]
+
+* Fixed a weird char in dragdrop.js
+
+* Controls.js Autocompleter.Base.updateElement() hook #2116 [Rob Wills]
+
+* Refactoring to use the Prototype enumerable extensions
+
+* Update to Prototype 1.4.0_pre4
+
+*V1.5.0_pre4*
+
+* Added a queue option to effects for easy stacking and simple timeline building. Valid values are "front", "end" and "parallel" (default), see for test/functional/effects_queue_test.html for usage
+
+* Added a setup function to the core effects that gets called by Effect.Base when first entering into running state, which allows them to query the current state of an element or other page properties when queuing and/or delays are used
+
+* Added a state instance variable to Effect.Base that indicates whether a effect that uses the queue is idle, running or finished
+
+* Fixed a flicker with Effect.Puff
+
+* General code cleaning to get rid of (legitimate) Mozilla strict javascript warnings
+
+* Changes to assertVisible in unittest.js
+
+* Slight refactoring of Effect.Text, now known as Effect.multiple(), change first parameter to also accept an array of strings or elements, or a NodeList of elements (if a single element or a string is given, defaults to $('element').childNodes)
+
+* Made tagifyText work with IE. defaults to a style of "position: relative; zoom:1;" for the created SPAN wrappers. It also replaces spaces with non-breakable spaces. These sit-ups are required to work around problems with rendering elements with the proprietary IE "layout" and non-quirksmode documents.
+
+* Add a break to scriptaculous.js when the includes are done [thx to Danilo Celic]
+
+* Fixed a problem with the Autocompleter when hitting ESC would select the entry in IE and redisplay the entries box in Safari
+
+* Fixed that the onDrop callback on Droppables didn't receive the dopped element as second parameter
+
+* Make check for correct Prototype version on loading script.aculo.us
+
+* Changed implementation of Builder to an innerHTML-based approach to make it work with IE6 (note: removed special "style" handling for now)
+
+* Changed non-sync Effects to use a common setInterval call for better timing and page update speeds. See the new Effect.Queue object.
+
+* Fixed a problem with setting opacity in Effect.Opacity to very small values
+
+* Changed the implemention of Effect.Base to use setInterval
+
+* Set version number to 1.5_pre4_trunk
+
+* Added experimental Effect.Text function that allows to start delayed text effects, see test/functional/texteffects_test.html.
+
+* Added experimental Effect.tagifyText(element) which wraps an elements text nodes characters in relatively positioned span elements
+
+* Added "delay" option to Effect.Base to start an effect only after a specified delay
+
+* Finetuning unittest.js + even more unit tests
+
+* Added support for Firefox and Konqueror automatic unit testing on Linux [Michael Schuerig]
+
+* Added basic unit test files for Effects, updated unit testing tests
+
+* Fix typo in lib/prototype.js fix in R2069 (whoops)
+
+* Added unit test for Position.clone
+
+* Made the Postition.cumulative override recognize KHTML and AppleWebKit
+
+* Fix the "hide form controls" iframe fix on the Autocompleter on Internet Explorer
+
+*V1.5.0_pre3*
+
+* More positioning fixes, expanded Element.clone [thx to Michael Schuerig]
+
+* Fixed some JavaScript warnings about redeclared vars [Courtenay]
+
+* Fixed a problem with autocompleting update divs not correctly positioned inside positioned elements [thx to Jonathan Feinberg]
+
+* Workaround for a Safari bug on absolutely positioned children of the BODY element
+
+* Added test/run_functional_test.html to more easily find your way around in the functional tests
+
+* Fixed some missing var declarations in effects.js
+
+* Support for automatic unit testing on IE/Win [Jon Tirsen]
+
+* Added loading the text for the Ajax.InPlaceEditor from the server, more CSS support [Richard Livsey, Jon Tirsen]
+
+* Made builder_test.html unit test work with Safari, fixed (one of two) caching issues with javascripttest.rb, added ajax_autocompleter_test.html to Rakefile unittests
+
+* Fixed Element.Class getting false matches on class names like classA-foobar, added unit tests [Martin Bialasinski]
+
+* Added a test to evluate the Fade/Appear effects across browsers and elements (test/functional/effects6_test.html)
+
+* Framework for completely self-running in-browser unit tests on Mac OS X (try "rake unittest") [Jon Tirsen]
+
+* Updates to Ajax.InPlaceEditor (Highlighting, Ajax options, more) [Jon Tirsen]
+
+* Made event registering on Draggables happen per drag for improved performance [thx to Cathy]
+
+* Moved Element.collectTextNodesIgnoreClass to util.js (preparation for refactoring)
+
+* Made sortable onChange option work again
+
+* Fixed a bug with Sortables resulting in wrong result when using Sortable.serialize with onUpdate on ghostly Sortables [thx Richard Livsey, Caleb Buxton]
+
+* Changed version number in scriptaculous.js to 1.5_pre3
+
+* Moved setting focus in Autocompleter to updateElement function to make it overridable [Brian Palmer]
+
+* Added special handling for style attributes to Builder [Michael Schuerig]
+
+* Changed opacity=1.0 check back to be inline with its original (pre 1.5) implementation to prevent flickering in Firefox < 1.1 on opacity-based effects (this also fixes flickering with drag-and-drop, sortable lists and autocompleting text fields). Note that this potentially breaks correct colors in some situations. [thx to David Zülke]
+
+* Automatically deactivate browser built-in autocompletion on autocompleting textfields, fixes part of Rails #1824.
+
+* Fixed a problem with Ajax.InPlaceEditor causing a JavaScript exception on Safari [thx to Patrick Lenz]
+
+*V1.5.0_pre2*
+
+* Fixed a weird character in dragdrop.js, added check to allow empty containers on Sortables (useful with dropOnEmpty option) [thx to Dave Strus]
+
+* Added unit test runner file test/run_unit_tests.html, new unit test files must be listed in test/unit/index.html
+
+* Added unit tests for Prototype string functions
+
+*V1.5.0_pre1*
+
+* Prepared README for V1.5.0_pre1
+
+* Added a main scriptaculous.js file to load in the other libraries transparently:
+
+ <script src="path/to/prototype.js" type="text/javascript"></script>
+ <script src="path/to/scriptaculous.js" type="text/javascript"></script>
+
+ in the HEAD section of an HTML file is now all that's needed to include all of the script.aculo.us libraries,
+ given that they all can be accessed by the same path as scriptaculous.js is.
+
+* Fixed possible problem with greedy Droppables when using the dropOnEmpty option on Sortable.create
+
+* Added new CSS/background color features to Ajax.InPlaceEditor [Jon Tirsen]
+
+* Added unit test for Autocompleter, first Version
+
+* Added Event.simulateKey/s to unittest.js. Note that due to a bug in Firefox this will only work with Firefox up to v1.0.4 (see https://bugzilla.mozilla.org/show_bug.cgi?id=289940)
+
+* Fixed a condition where standard a href=xxx links wouldn't work in autocomplete results. These do now, the onclick event is not cancelled. [thx to Jasper Slits]
+
+* Fix showing ghosting marker only on ghosting Sortables
+
+* Some more Builder stuff, expanded builder unit tests
+
+* Moved stuff that didn't belong into specific libs into util.js; util.js is now required for all script.aculo.us libs
+
+* Corrected weirdness in unittest.js
+
+* Added dropOnEmpty option to Sortables to allow dropping on empty lists (see test/functional/sortable3_test.html)
+
+* Changed algoritm for drag/drop position setting
+
+* Changed workaround for class attributes (fixes a Firefox 1.0 error) from klass to className to be more Javascriptesque [thx to Martin Bialasinski]
+
+* Fixed a typo in ajax_inplaceeditor_test.html
+
+* Updated Rakefile to add unittest.js and util.js to the package
+
+* Added util.js which contains various utlity functions and extensions to Prototype
+
+* Major restructuring
+
+* Added TEXTAREA support to Ajax.InPlaceEditor [Sanford Barr]
+
+* Added Ghost Train alpha 0.1.0. See ghosttrain/test.html.
+
+* More features for Ajax.InPlaceEditor [Jon Tirsen]
+
+* Tweaks to unittest.css [Thomas Fuchs]
+
+* Refactoring and new features in unittest.js [Thomas Fuchs] [Jon Tirsen]
+
+* Fixed a wrong variable reference in Effect.Scale
+
+* Fix Element.makePositioned to recognize the 'static' position
+
+* Allow to choose the parameter name for Ajax.Autocompleter [Cameron Braid]
+
+* Changed resolving indicator DOM element more flexibility [Cameron Braid]
+
+* Fixed a reference in Ajax.InPlaceEditor
+
+* Added contributors to unittest.js
+
+* Souped-up Ajax.InPlaceEditor, added support for a form id and specifying all the texts through options [Jon Tirsen]
+
+* Make unit testing look good [Michael Schuerig]
+
+* Changed default revert duration for Draggables to distance-dependent algorithm [suggested by San]
+
+* Fix double unescaping in Autocompleter
+
+* Refactoring auf Autocompleter classes to use camelCase (note: changes the syntax of some of the options)
+
+* Add updateElement option to Autocompleter [Rob Sharp]
+
+* Updated Ajax.InPlaceEditor, refactoring of unit testing [Jon Tirsen]
+
+* Added preliminary version of Ajax.InPlaceEditor to controls.js; added experimental Firefox only functional testing for it (inplaceeditor_result.html) [Jon Tirsen]
+
+* Added some addtional test files.
+
+* Fixes a bug with Droppables not recognizing a drop if no hoverclass is given [thanks drewie]
+
+* Fixes to ghosting marker, allow a predefined marker (element with id "dropmarker").
+
+* Changed Effect.Opacity to better handle 100% opacity
+
+* Various fixes to ghosting, improves compatiblity with Safari and IE. [thanks to David Zülke]
+
+* Added experimental ghosting option to Sortables. See sortable_functional_ghosting.html for usage.
+
+* Renamed the clone option on Draggables to "ghosting".
+
+* Added experimental "clone" option to Draggable to so that a "clone" stays in place while dragging a translucent version of the draggable element. Currently, this requires relatively positioned elements, and doesn't work with sortable lists (but should after some tweaking). See dragdrop_function_4.html test file for details.
+
+* Added Element.getStyle to find computed CSS styles of an element. Note: doesn't work in all cases in Safari, see my bug report at http://bugzilla.opendarwin.org/show_bug.cgi?id=4125
+
+*1.1beta1*
+
+* Fixed rendering of last frame of animation when from/to is not 0.0/1.0. [thanks to David Zülke]
+
+* Updated internal Prototype JavaScript framework to version 1.4.0_pre2 (patched w/ workaround for Ajax.Updater init bug)
+
+* Some refactoring of controls.js to get rid of "dirty" implementation detail (dont' ask)
+
+* Added returning the generated combined effects to allow for .cancel() on all effects
+
+* Updated internal Prototype JavaScript framework to version 1.4.0_pre2
+
+*Rails 0.13.1*
+
+* Updated Ajax.Autocompleter to deal with parameters options correctly [Martin Marinschek]
+
+* Updated controls.js to allow multple matches in local localcompletion [Ivan Krstic]
+
+* Make version of prototype.js in lib have a nicer Event object [David Zülke]
+
+* Added incremental and local autocompleting and loads of documentation to controls.js [Ivan Krstic]
+
+* Experimental: make version of prototype.js in lib destroy events on page unload to prevent browser memory leaks
+
+* Fixed a possible memory leak in dragdrop.js
+
+* Make version of prototype.js in lib compatible with some 3rd-party JavaScript libraries (like IE7) by refactoring to use Object.extend() for testing [David Zülke]
+
+* Make effects.js, dragdrop.js and controls.js compatible with some 3rd-party JavaScript libraries (like IE7) by refactoring to use Object.extend() [David Zülke]
+
+* Changed some tests to work better
+
+* Always reset background color on Effect.Highlight; this make change backwards-compatibility, to be sure include style="background-color:(target-color)" on your elements or else elements will fall back to their CSS rules (which is a good thing in most circumstances)
+
+* Removed a possible memory leaks with IE with sortables and droppables (removed references from elements)
+
+* Changes to class extension in effects.js
+
+* Make Effect.Highlight restore any previously set background color when finishing (makes effect work with set CSS classes)
+
+* Added capability to remove draggables/droppables and redeclare sortables in dragdrop.js
+
+* Added Effect.ScrollTo to smoothly scroll the page to an element
+
+* Better Firefox flickering handling on SlideUp/SlideDown
+
+* Some cleaning up in effects.js
+
+* Removed a possible memory leak in IE with draggables
+
+* Added support for cancelling dragging my hitting ESC
+
+* Changed logic of drag-and-drop to only include the last referenced droppable when firing a drop event. This change also offers slight performance gains. [Dominik Wagner]
+
+* Added addtional effects test page, added tests for scriptfragment matching
+
+*1.0.0*
+
+* Changed auto-hiding update div in Ajax.Autocompleter
+
+* Changed default serialization on Ajax.Autocompleter to use Form.Element.serialize
+
+* Added test file for drag/drop inside scrolled elements
+
+* Fixed dragging of unpositioned elements in Internet Explorer
+
+* Change default behaviour of Ajax.Autocompleter to do automatic overlapping, sizing and appear/fade effects
+
+* Fixed Internet Explorer hide-windowed-controls iframe handling
+
+* Changed Ajax.Autocompleter event handling
+
+* Added onShow/onHide callbacks to Ajax.Autocompleter to allow for customized handling/effects
+
+* Fixed SlideUp/SlideDown to restore the overflow CSS property (note: Firefox 1.0.X is buggy, set overflow:hidden as a workaround)
+
+* Fixed BlindUp/BlindDown to restore the overflow CSS property (note: Firefox 1.0.X is buggy, set overflow:hidden as a workaround)
+
+* Fixed draggables with revert:false on repeated drags behaving badly
+
+* Expanded the revert option on draggables to optionally take a function and revert only if it returns true
+
+* Added the dragged element as a parameter to the Draggables.notify callbacks [Michael Sokolov]
+
+* Removed a deprecated reference to Effect2 om Effect.Fold
+
+* Make the percentage on Element.setContentZoom absolute
+
+* Corrected rendering of Ajax.AutoCompleter when focus is lost while updating
+
+* Added (crude) functional tests
+
+* Some slight refactoring in controls.js
+
+* Changed dragdrop.js to use the Effect namespace for its effects
+
+* Updated to Prototype 1.3.0: removal of prototype-ext.js; refactoring.
+
+* Fixed behaviour of cursor keys in Safari on autocomplete script
+
+* Fixed Position.within_including_scrolloffsets
+
+* Fixed sortables that are absolutely positioned
+
+* Fixed unhandled whitespace in Ajax.Autocompleter
+
+* Updated prototype-ext.js to include additions for Ajax.Autocompleter
+
+* Added controls.js, contains AJAX autocompleting text fields from #960
+
+* Refactored Event object
+
+* Renamed effects2.js to effects.js
+
+* Fixed draggables on pages with no droppables
+
+* Moved Event, Position and Element.Class to prototype-ext.js in preparation to Rails 0.13
+
+* Added Effect.Transitions.pulse
+
+* Added Effect.Pulsate and Effect.Fold effect by Justin Palmer
+
+* Added transitions by Mark Pilgrim: .full, .none
+
+* Added effects by Mark Pilgrim: Effect.Grow, Effect.Shrink
+
+* Changed effects namespace to Effect. (Effect2 is deprecated, but works too)
+
+* Changed old Effect.ContentZoom class to Element.setContentZoom() function
+
+* Greatly expanded Effect.Highlight to have user-defined colors and autodetecting the background color
+
+* Converted remaining effects (Squish, Highlight) to new format
+
+* Sortable.create now passes the zindex, starteffect, reverteffect and endeffect options to the underlying Draggables
+
+* Sortable.serialize now honors the only option on Sortable.create
+
+* New overridable options on Draggables: zindex, starteffect, reverteffect, endeffect
+
+* Fix a Gecko engine flicker on Sortables in dragdrop.js
+
+* Fixed event.isLeftClick
+
+* Some small changes in effects2.js
+
+* Refactoring of dragdrop.js
+
+* Added an Object.prototype.inspect() and more verbose messages for js unit testing
+
+* Added test/unittest.js and initial tests in test/html.
+
+* Cleaning up of effects2.js (convert tabs to spaces)
+
+* Added Rakefile for distribution packaging (default task = make distribution, rake clean for cleaning up)
+
+* Initial check-in and directory layout for the script.aculo.us JavaScripts
diff --git a/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/MIT-LICENSE b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/MIT-LICENSE
new file mode 100644
index 0000000..da26ff0
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2005-2010 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/builder.js b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/builder.js
new file mode 100644
index 0000000..7325038
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/builder.js
@@ -0,0 +1,136 @@
+// script.aculo.us builder.js v1.9.0, Thu Dec 23 16:54:48 -0500 2010
+
+// Copyright (c) 2005-2010 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+var Builder = {
+ NODEMAP: {
+ AREA: 'map',
+ CAPTION: 'table',
+ COL: 'table',
+ COLGROUP: 'table',
+ LEGEND: 'fieldset',
+ OPTGROUP: 'select',
+ OPTION: 'select',
+ PARAM: 'object',
+ TBODY: 'table',
+ TD: 'table',
+ TFOOT: 'table',
+ TH: 'table',
+ THEAD: 'table',
+ TR: 'table'
+ },
+ // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
+ // due to a Firefox bug
+ node: function(elementName) {
+ elementName = elementName.toUpperCase();
+
+ // try innerHTML approach
+ var parentTag = this.NODEMAP[elementName] || 'div';
+ var parentElement = document.createElement(parentTag);
+ try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
+ parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
+ } catch(e) {}
+ var element = parentElement.firstChild || null;
+
+ // see if browser added wrapping tags
+ if(element && (element.tagName.toUpperCase() != elementName))
+ element = element.getElementsByTagName(elementName)[0];
+
+ // fallback to createElement approach
+ if(!element) element = document.createElement(elementName);
+
+ // abort if nothing could be created
+ if(!element) return;
+
+ // attributes (or text)
+ if(arguments[1])
+ if(this._isStringOrNumber(arguments[1]) ||
+ (arguments[1] instanceof Array) ||
+ arguments[1].tagName) {
+ this._children(element, arguments[1]);
+ } else {
+ var attrs = this._attributes(arguments[1]);
+ if(attrs.length) {
+ try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
+ parentElement.innerHTML = "<" +elementName + " " +
+ attrs + "></" + elementName + ">";
+ } catch(e) {}
+ element = parentElement.firstChild || null;
+ // workaround firefox 1.0.X bug
+ if(!element) {
+ element = document.createElement(elementName);
+ for(attr in arguments[1])
+ element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
+ }
+ if(element.tagName.toUpperCase() != elementName)
+ element = parentElement.getElementsByTagName(elementName)[0];
+ }
+ }
+
+ // text, or array of children
+ if(arguments[2])
+ this._children(element, arguments[2]);
+
+ return $(element);
+ },
+ _text: function(text) {
+ return document.createTextNode(text);
+ },
+
+ ATTR_MAP: {
+ 'className': 'class',
+ 'htmlFor': 'for'
+ },
+
+ _attributes: function(attributes) {
+ var attrs = [];
+ for(attribute in attributes)
+ attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
+ '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'&quot;') + '"');
+ return attrs.join(" ");
+ },
+ _children: function(element, children) {
+ if(children.tagName) {
+ element.appendChild(children);
+ return;
+ }
+ if(typeof children=='object') { // array can hold nodes and text
+ children.flatten().each( function(e) {
+ if(typeof e=='object')
+ element.appendChild(e);
+ else
+ if(Builder._isStringOrNumber(e))
+ element.appendChild(Builder._text(e));
+ });
+ } else
+ if(Builder._isStringOrNumber(children))
+ element.appendChild(Builder._text(children));
+ },
+ _isStringOrNumber: function(param) {
+ return(typeof param=='string' || typeof param=='number');
+ },
+ build: function(html) {
+ var element = this.node('div');
+ $(element).update(html.strip());
+ return element.down();
+ },
+ dump: function(scope) {
+ if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope
+
+ var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
+ "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
+ "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
+ "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
+ "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
+ "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
+
+ tags.each( function(tag){
+ scope[tag] = function() {
+ return Builder.node.apply(Builder, [tag].concat($A(arguments)));
+ };
+ });
+ }
+}; \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/controls.js b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/controls.js
new file mode 100644
index 0000000..5137ab5
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/controls.js
@@ -0,0 +1,965 @@
+// script.aculo.us controls.js v1.9.0, Thu Dec 23 16:54:48 -0500 2010
+
+// Copyright (c) 2005-2010 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005-2010 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
+// (c) 2005-2010 Jon Tirsen (http://www.tirsen.com)
+// Contributors:
+// Richard Livsey
+// Rahul Bhargava
+// Rob Wills
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// Autocompleter.Base handles all the autocompletion functionality
+// that's independent of the data source for autocompletion. This
+// includes drawing the autocompletion menu, observing keyboard
+// and mouse events, and similar.
+//
+// Specific autocompleters need to provide, at the very least,
+// a getUpdatedChoices function that will be invoked every time
+// the text inside the monitored textbox changes. This method
+// should get the text for which to provide autocompletion by
+// invoking this.getToken(), NOT by directly accessing
+// this.element.value. This is to allow incremental tokenized
+// autocompletion. Specific auto-completion logic (AJAX, etc)
+// belongs in getUpdatedChoices.
+//
+// Tokenized incremental autocompletion is enabled automatically
+// when an autocompleter is instantiated with the 'tokens' option
+// in the options parameter, e.g.:
+// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
+// will incrementally autocomplete with a comma as the token.
+// Additionally, ',' in the above example can be replaced with
+// a token array, e.g. { tokens: [',', '\n'] } which
+// enables autocompletion on multiple tokens. This is most
+// useful when one of the tokens is \n (a newline), as it
+// allows smart autocompletion after linebreaks.
+
+if(typeof Effect == 'undefined')
+ throw("controls.js requires including script.aculo.us' effects.js library");
+
+var Autocompleter = { };
+Autocompleter.Base = Class.create({
+ baseInitialize: function(element, update, options) {
+ element = $(element);
+ this.element = element;
+ this.update = $(update);
+ this.hasFocus = false;
+ this.changed = false;
+ this.active = false;
+ this.index = 0;
+ this.entryCount = 0;
+ this.oldElementValue = this.element.value;
+
+ if(this.setOptions)
+ this.setOptions(options);
+ else
+ this.options = options || { };
+
+ this.options.paramName = this.options.paramName || this.element.name;
+ this.options.tokens = this.options.tokens || [];
+ this.options.frequency = this.options.frequency || 0.4;
+ this.options.minChars = this.options.minChars || 1;
+ this.options.onShow = this.options.onShow ||
+ function(element, update){
+ if(!update.style.position || update.style.position=='absolute') {
+ update.style.position = 'absolute';
+ Position.clone(element, update, {
+ setHeight: false,
+ offsetTop: element.offsetHeight
+ });
+ }
+ Effect.Appear(update,{duration:0.15});
+ };
+ this.options.onHide = this.options.onHide ||
+ function(element, update){ new Effect.Fade(update,{duration:0.15}) };
+
+ if(typeof(this.options.tokens) == 'string')
+ this.options.tokens = new Array(this.options.tokens);
+ // Force carriage returns as token delimiters anyway
+ if (!this.options.tokens.include('\n'))
+ this.options.tokens.push('\n');
+
+ this.observer = null;
+
+ this.element.setAttribute('autocomplete','off');
+
+ Element.hide(this.update);
+
+ Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
+ Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
+ },
+
+ show: function() {
+ if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
+ if(!this.iefix &&
+ (Prototype.Browser.IE) &&
+ (Element.getStyle(this.update, 'position')=='absolute')) {
+ new Insertion.After(this.update,
+ '<iframe id="' + this.update.id + '_iefix" '+
+ 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
+ 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
+ this.iefix = $(this.update.id+'_iefix');
+ }
+ if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
+ },
+
+ fixIEOverlapping: function() {
+ Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
+ this.iefix.style.zIndex = 1;
+ this.update.style.zIndex = 2;
+ Element.show(this.iefix);
+ },
+
+ hide: function() {
+ this.stopIndicator();
+ if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
+ if(this.iefix) Element.hide(this.iefix);
+ },
+
+ startIndicator: function() {
+ if(this.options.indicator) Element.show(this.options.indicator);
+ },
+
+ stopIndicator: function() {
+ if(this.options.indicator) Element.hide(this.options.indicator);
+ },
+
+ onKeyPress: function(event) {
+ if(this.active)
+ switch(event.keyCode) {
+ case Event.KEY_TAB:
+ case Event.KEY_RETURN:
+ this.selectEntry();
+ Event.stop(event);
+ case Event.KEY_ESC:
+ this.hide();
+ this.active = false;
+ Event.stop(event);
+ return;
+ case Event.KEY_LEFT:
+ case Event.KEY_RIGHT:
+ return;
+ case Event.KEY_UP:
+ this.markPrevious();
+ this.render();
+ Event.stop(event);
+ return;
+ case Event.KEY_DOWN:
+ this.markNext();
+ this.render();
+ Event.stop(event);
+ return;
+ }
+ else
+ if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
+ (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
+
+ this.changed = true;
+ this.hasFocus = true;
+
+ if(this.observer) clearTimeout(this.observer);
+ this.observer =
+ setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
+ },
+
+ activate: function() {
+ this.changed = false;
+ this.hasFocus = true;
+ this.getUpdatedChoices();
+ },
+
+ onHover: function(event) {
+ var element = Event.findElement(event, 'LI');
+ if(this.index != element.autocompleteIndex)
+ {
+ this.index = element.autocompleteIndex;
+ this.render();
+ }
+ Event.stop(event);
+ },
+
+ onClick: function(event) {
+ var element = Event.findElement(event, 'LI');
+ this.index = element.autocompleteIndex;
+ this.selectEntry();
+ this.hide();
+ },
+
+ onBlur: function(event) {
+ // needed to make click events working
+ setTimeout(this.hide.bind(this), 250);
+ this.hasFocus = false;
+ this.active = false;
+ },
+
+ render: function() {
+ if(this.entryCount > 0) {
+ for (var i = 0; i < this.entryCount; i++)
+ this.index==i ?
+ Element.addClassName(this.getEntry(i),"selected") :
+ Element.removeClassName(this.getEntry(i),"selected");
+ if(this.hasFocus) {
+ this.show();
+ this.active = true;
+ }
+ } else {
+ this.active = false;
+ this.hide();
+ }
+ },
+
+ markPrevious: function() {
+ if(this.index > 0) this.index--;
+ else this.index = this.entryCount-1;
+ this.getEntry(this.index).scrollIntoView(true);
+ },
+
+ markNext: function() {
+ if(this.index < this.entryCount-1) this.index++;
+ else this.index = 0;
+ this.getEntry(this.index).scrollIntoView(false);
+ },
+
+ getEntry: function(index) {
+ return this.update.firstChild.childNodes[index];
+ },
+
+ getCurrentEntry: function() {
+ return this.getEntry(this.index);
+ },
+
+ selectEntry: function() {
+ this.active = false;
+ this.updateElement(this.getCurrentEntry());
+ },
+
+ updateElement: function(selectedElement) {
+ if (this.options.updateElement) {
+ this.options.updateElement(selectedElement);
+ return;
+ }
+ var value = '';
+ if (this.options.select) {
+ var nodes = $(selectedElement).select('.' + this.options.select) || [];
+ if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
+ } else
+ value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
+
+ var bounds = this.getTokenBounds();
+ if (bounds[0] != -1) {
+ var newValue = this.element.value.substr(0, bounds[0]);
+ var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
+ if (whitespace)
+ newValue += whitespace[0];
+ this.element.value = newValue + value + this.element.value.substr(bounds[1]);
+ } else {
+ this.element.value = value;
+ }
+ this.oldElementValue = this.element.value;
+ this.element.focus();
+
+ if (this.options.afterUpdateElement)
+ this.options.afterUpdateElement(this.element, selectedElement);
+ },
+
+ updateChoices: function(choices) {
+ if(!this.changed && this.hasFocus) {
+ this.update.innerHTML = choices;
+ Element.cleanWhitespace(this.update);
+ Element.cleanWhitespace(this.update.down());
+
+ if(this.update.firstChild && this.update.down().childNodes) {
+ this.entryCount =
+ this.update.down().childNodes.length;
+ for (var i = 0; i < this.entryCount; i++) {
+ var entry = this.getEntry(i);
+ entry.autocompleteIndex = i;
+ this.addObservers(entry);
+ }
+ } else {
+ this.entryCount = 0;
+ }
+
+ this.stopIndicator();
+ this.index = 0;
+
+ if(this.entryCount==1 && this.options.autoSelect) {
+ this.selectEntry();
+ this.hide();
+ } else {
+ this.render();
+ }
+ }
+ },
+
+ addObservers: function(element) {
+ Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
+ Event.observe(element, "click", this.onClick.bindAsEventListener(this));
+ },
+
+ onObserverEvent: function() {
+ this.changed = false;
+ this.tokenBounds = null;
+ if(this.getToken().length>=this.options.minChars) {
+ this.getUpdatedChoices();
+ } else {
+ this.active = false;
+ this.hide();
+ }
+ this.oldElementValue = this.element.value;
+ },
+
+ getToken: function() {
+ var bounds = this.getTokenBounds();
+ return this.element.value.substring(bounds[0], bounds[1]).strip();
+ },
+
+ getTokenBounds: function() {
+ if (null != this.tokenBounds) return this.tokenBounds;
+ var value = this.element.value;
+ if (value.strip().empty()) return [-1, 0];
+ var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
+ var offset = (diff == this.oldElementValue.length ? 1 : 0);
+ var prevTokenPos = -1, nextTokenPos = value.length;
+ var tp;
+ for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
+ tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
+ if (tp > prevTokenPos) prevTokenPos = tp;
+ tp = value.indexOf(this.options.tokens[index], diff + offset);
+ if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
+ }
+ return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
+ }
+});
+
+Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
+ var boundary = Math.min(newS.length, oldS.length);
+ for (var index = 0; index < boundary; ++index)
+ if (newS[index] != oldS[index])
+ return index;
+ return boundary;
+};
+
+Ajax.Autocompleter = Class.create(Autocompleter.Base, {
+ initialize: function(element, update, url, options) {
+ this.baseInitialize(element, update, options);
+ this.options.asynchronous = true;
+ this.options.onComplete = this.onComplete.bind(this);
+ this.options.defaultParams = this.options.parameters || null;
+ this.url = url;
+ },
+
+ getUpdatedChoices: function() {
+ this.startIndicator();
+
+ var entry = encodeURIComponent(this.options.paramName) + '=' +
+ encodeURIComponent(this.getToken());
+
+ this.options.parameters = this.options.callback ?
+ this.options.callback(this.element, entry) : entry;
+
+ if(this.options.defaultParams)
+ this.options.parameters += '&' + this.options.defaultParams;
+
+ new Ajax.Request(this.url, this.options);
+ },
+
+ onComplete: function(request) {
+ this.updateChoices(request.responseText);
+ }
+});
+
+// The local array autocompleter. Used when you'd prefer to
+// inject an array of autocompletion options into the page, rather
+// than sending out Ajax queries, which can be quite slow sometimes.
+//
+// The constructor takes four parameters. The first two are, as usual,
+// the id of the monitored textbox, and id of the autocompletion menu.
+// The third is the array you want to autocomplete from, and the fourth
+// is the options block.
+//
+// Extra local autocompletion options:
+// - choices - How many autocompletion choices to offer
+//
+// - partialSearch - If false, the autocompleter will match entered
+// text only at the beginning of strings in the
+// autocomplete array. Defaults to true, which will
+// match text at the beginning of any *word* in the
+// strings in the autocomplete array. If you want to
+// search anywhere in the string, additionally set
+// the option fullSearch to true (default: off).
+//
+// - fullSsearch - Search anywhere in autocomplete array strings.
+//
+// - partialChars - How many characters to enter before triggering
+// a partial match (unlike minChars, which defines
+// how many characters are required to do any match
+// at all). Defaults to 2.
+//
+// - ignoreCase - Whether to ignore case when autocompleting.
+// Defaults to true.
+//
+// It's possible to pass in a custom function as the 'selector'
+// option, if you prefer to write your own autocompletion logic.
+// In that case, the other options above will not apply unless
+// you support them.
+
+Autocompleter.Local = Class.create(Autocompleter.Base, {
+ initialize: function(element, update, array, options) {
+ this.baseInitialize(element, update, options);
+ this.options.array = array;
+ },
+
+ getUpdatedChoices: function() {
+ this.updateChoices(this.options.selector(this));
+ },
+
+ setOptions: function(options) {
+ this.options = Object.extend({
+ choices: 10,
+ partialSearch: true,
+ partialChars: 2,
+ ignoreCase: true,
+ fullSearch: false,
+ selector: function(instance) {
+ var ret = []; // Beginning matches
+ var partial = []; // Inside matches
+ var entry = instance.getToken();
+ var count = 0;
+
+ for (var i = 0; i < instance.options.array.length &&
+ ret.length < instance.options.choices ; i++) {
+
+ var elem = instance.options.array[i];
+ var foundPos = instance.options.ignoreCase ?
+ elem.toLowerCase().indexOf(entry.toLowerCase()) :
+ elem.indexOf(entry);
+
+ while (foundPos != -1) {
+ if (foundPos == 0 && elem.length != entry.length) {
+ ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
+ elem.substr(entry.length) + "</li>");
+ break;
+ } else if (entry.length >= instance.options.partialChars &&
+ instance.options.partialSearch && foundPos != -1) {
+ if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
+ partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
+ elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
+ foundPos + entry.length) + "</li>");
+ break;
+ }
+ }
+
+ foundPos = instance.options.ignoreCase ?
+ elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
+ elem.indexOf(entry, foundPos + 1);
+
+ }
+ }
+ if (partial.length)
+ ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));
+ return "<ul>" + ret.join('') + "</ul>";
+ }
+ }, options || { });
+ }
+});
+
+// AJAX in-place editor and collection editor
+// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).
+
+// Use this if you notice weird scrolling problems on some browsers,
+// the DOM might be a bit confused when this gets called so do this
+// waits 1 ms (with setTimeout) until it does the activation
+Field.scrollFreeActivate = function(field) {
+ setTimeout(function() {
+ Field.activate(field);
+ }, 1);
+};
+
+Ajax.InPlaceEditor = Class.create({
+ initialize: function(element, url, options) {
+ this.url = url;
+ this.element = element = $(element);
+ this.prepareOptions();
+ this._controls = { };
+ arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
+ Object.extend(this.options, options || { });
+ if (!this.options.formId && this.element.id) {
+ this.options.formId = this.element.id + '-inplaceeditor';
+ if ($(this.options.formId))
+ this.options.formId = '';
+ }
+ if (this.options.externalControl)
+ this.options.externalControl = $(this.options.externalControl);
+ if (!this.options.externalControl)
+ this.options.externalControlOnly = false;
+ this._originalBackground = this.element.getStyle('background-color') || 'transparent';
+ this.element.title = this.options.clickToEditText;
+ this._boundCancelHandler = this.handleFormCancellation.bind(this);
+ this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
+ this._boundFailureHandler = this.handleAJAXFailure.bind(this);
+ this._boundSubmitHandler = this.handleFormSubmission.bind(this);
+ this._boundWrapperHandler = this.wrapUp.bind(this);
+ this.registerListeners();
+ },
+ checkForEscapeOrReturn: function(e) {
+ if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
+ if (Event.KEY_ESC == e.keyCode)
+ this.handleFormCancellation(e);
+ else if (Event.KEY_RETURN == e.keyCode)
+ this.handleFormSubmission(e);
+ },
+ createControl: function(mode, handler, extraClasses) {
+ var control = this.options[mode + 'Control'];
+ var text = this.options[mode + 'Text'];
+ if ('button' == control) {
+ var btn = document.createElement('input');
+ btn.type = 'submit';
+ btn.value = text;
+ btn.className = 'editor_' + mode + '_button';
+ if ('cancel' == mode)
+ btn.onclick = this._boundCancelHandler;
+ this._form.appendChild(btn);
+ this._controls[mode] = btn;
+ } else if ('link' == control) {
+ var link = document.createElement('a');
+ link.href = '#';
+ link.appendChild(document.createTextNode(text));
+ link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
+ link.className = 'editor_' + mode + '_link';
+ if (extraClasses)
+ link.className += ' ' + extraClasses;
+ this._form.appendChild(link);
+ this._controls[mode] = link;
+ }
+ },
+ createEditField: function() {
+ var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
+ var fld;
+ if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
+ fld = document.createElement('input');
+ fld.type = 'text';
+ var size = this.options.size || this.options.cols || 0;
+ if (0 < size) fld.size = size;
+ } else {
+ fld = document.createElement('textarea');
+ fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
+ fld.cols = this.options.cols || 40;
+ }
+ fld.name = this.options.paramName;
+ fld.value = text; // No HTML breaks conversion anymore
+ fld.className = 'editor_field';
+ if (this.options.submitOnBlur)
+ fld.onblur = this._boundSubmitHandler;
+ this._controls.editor = fld;
+ if (this.options.loadTextURL)
+ this.loadExternalText();
+ this._form.appendChild(this._controls.editor);
+ },
+ createForm: function() {
+ var ipe = this;
+ function addText(mode, condition) {
+ var text = ipe.options['text' + mode + 'Controls'];
+ if (!text || condition === false) return;
+ ipe._form.appendChild(document.createTextNode(text));
+ };
+ this._form = $(document.createElement('form'));
+ this._form.id = this.options.formId;
+ this._form.addClassName(this.options.formClassName);
+ this._form.onsubmit = this._boundSubmitHandler;
+ this.createEditField();
+ if ('textarea' == this._controls.editor.tagName.toLowerCase())
+ this._form.appendChild(document.createElement('br'));
+ if (this.options.onFormCustomization)
+ this.options.onFormCustomization(this, this._form);
+ addText('Before', this.options.okControl || this.options.cancelControl);
+ this.createControl('ok', this._boundSubmitHandler);
+ addText('Between', this.options.okControl && this.options.cancelControl);
+ this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
+ addText('After', this.options.okControl || this.options.cancelControl);
+ },
+ destroy: function() {
+ if (this._oldInnerHTML)
+ this.element.innerHTML = this._oldInnerHTML;
+ this.leaveEditMode();
+ this.unregisterListeners();
+ },
+ enterEditMode: function(e) {
+ if (this._saving || this._editing) return;
+ this._editing = true;
+ this.triggerCallback('onEnterEditMode');
+ if (this.options.externalControl)
+ this.options.externalControl.hide();
+ this.element.hide();
+ this.createForm();
+ this.element.parentNode.insertBefore(this._form, this.element);
+ if (!this.options.loadTextURL)
+ this.postProcessEditField();
+ if (e) Event.stop(e);
+ },
+ enterHover: function(e) {
+ if (this.options.hoverClassName)
+ this.element.addClassName(this.options.hoverClassName);
+ if (this._saving) return;
+ this.triggerCallback('onEnterHover');
+ },
+ getText: function() {
+ return this.element.innerHTML.unescapeHTML();
+ },
+ handleAJAXFailure: function(transport) {
+ this.triggerCallback('onFailure', transport);
+ if (this._oldInnerHTML) {
+ this.element.innerHTML = this._oldInnerHTML;
+ this._oldInnerHTML = null;
+ }
+ },
+ handleFormCancellation: function(e) {
+ this.wrapUp();
+ if (e) Event.stop(e);
+ },
+ handleFormSubmission: function(e) {
+ var form = this._form;
+ var value = $F(this._controls.editor);
+ this.prepareSubmission();
+ var params = this.options.callback(form, value) || '';
+ if (Object.isString(params))
+ params = params.toQueryParams();
+ params.editorId = this.element.id;
+ if (this.options.htmlResponse) {
+ var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: params,
+ onComplete: this._boundWrapperHandler,
+ onFailure: this._boundFailureHandler
+ });
+ new Ajax.Updater({ success: this.element }, this.url, options);
+ } else {
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: params,
+ onComplete: this._boundWrapperHandler,
+ onFailure: this._boundFailureHandler
+ });
+ new Ajax.Request(this.url, options);
+ }
+ if (e) Event.stop(e);
+ },
+ leaveEditMode: function() {
+ this.element.removeClassName(this.options.savingClassName);
+ this.removeForm();
+ this.leaveHover();
+ this.element.style.backgroundColor = this._originalBackground;
+ this.element.show();
+ if (this.options.externalControl)
+ this.options.externalControl.show();
+ this._saving = false;
+ this._editing = false;
+ this._oldInnerHTML = null;
+ this.triggerCallback('onLeaveEditMode');
+ },
+ leaveHover: function(e) {
+ if (this.options.hoverClassName)
+ this.element.removeClassName(this.options.hoverClassName);
+ if (this._saving) return;
+ this.triggerCallback('onLeaveHover');
+ },
+ loadExternalText: function() {
+ this._form.addClassName(this.options.loadingClassName);
+ this._controls.editor.disabled = true;
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
+ onComplete: Prototype.emptyFunction,
+ onSuccess: function(transport) {
+ this._form.removeClassName(this.options.loadingClassName);
+ var text = transport.responseText;
+ if (this.options.stripLoadedTextTags)
+ text = text.stripTags();
+ this._controls.editor.value = text;
+ this._controls.editor.disabled = false;
+ this.postProcessEditField();
+ }.bind(this),
+ onFailure: this._boundFailureHandler
+ });
+ new Ajax.Request(this.options.loadTextURL, options);
+ },
+ postProcessEditField: function() {
+ var fpc = this.options.fieldPostCreation;
+ if (fpc)
+ $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
+ },
+ prepareOptions: function() {
+ this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
+ Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
+ [this._extraDefaultOptions].flatten().compact().each(function(defs) {
+ Object.extend(this.options, defs);
+ }.bind(this));
+ },
+ prepareSubmission: function() {
+ this._saving = true;
+ this.removeForm();
+ this.leaveHover();
+ this.showSaving();
+ },
+ registerListeners: function() {
+ this._listeners = { };
+ var listener;
+ $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
+ listener = this[pair.value].bind(this);
+ this._listeners[pair.key] = listener;
+ if (!this.options.externalControlOnly)
+ this.element.observe(pair.key, listener);
+ if (this.options.externalControl)
+ this.options.externalControl.observe(pair.key, listener);
+ }.bind(this));
+ },
+ removeForm: function() {
+ if (!this._form) return;
+ this._form.remove();
+ this._form = null;
+ this._controls = { };
+ },
+ showSaving: function() {
+ this._oldInnerHTML = this.element.innerHTML;
+ this.element.innerHTML = this.options.savingText;
+ this.element.addClassName(this.options.savingClassName);
+ this.element.style.backgroundColor = this._originalBackground;
+ this.element.show();
+ },
+ triggerCallback: function(cbName, arg) {
+ if ('function' == typeof this.options[cbName]) {
+ this.options[cbName](this, arg);
+ }
+ },
+ unregisterListeners: function() {
+ $H(this._listeners).each(function(pair) {
+ if (!this.options.externalControlOnly)
+ this.element.stopObserving(pair.key, pair.value);
+ if (this.options.externalControl)
+ this.options.externalControl.stopObserving(pair.key, pair.value);
+ }.bind(this));
+ },
+ wrapUp: function(transport) {
+ this.leaveEditMode();
+ // Can't use triggerCallback due to backward compatibility: requires
+ // binding + direct element
+ this._boundComplete(transport, this.element);
+ }
+});
+
+Object.extend(Ajax.InPlaceEditor.prototype, {
+ dispose: Ajax.InPlaceEditor.prototype.destroy
+});
+
+Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
+ initialize: function($super, element, url, options) {
+ this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
+ $super(element, url, options);
+ },
+
+ createEditField: function() {
+ var list = document.createElement('select');
+ list.name = this.options.paramName;
+ list.size = 1;
+ this._controls.editor = list;
+ this._collection = this.options.collection || [];
+ if (this.options.loadCollectionURL)
+ this.loadCollection();
+ else
+ this.checkForExternalText();
+ this._form.appendChild(this._controls.editor);
+ },
+
+ loadCollection: function() {
+ this._form.addClassName(this.options.loadingClassName);
+ this.showLoadingText(this.options.loadingCollectionText);
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
+ onComplete: Prototype.emptyFunction,
+ onSuccess: function(transport) {
+ var js = transport.responseText.strip();
+ if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
+ throw('Server returned an invalid collection representation.');
+ this._collection = eval(js);
+ this.checkForExternalText();
+ }.bind(this),
+ onFailure: this.onFailure
+ });
+ new Ajax.Request(this.options.loadCollectionURL, options);
+ },
+
+ showLoadingText: function(text) {
+ this._controls.editor.disabled = true;
+ var tempOption = this._controls.editor.firstChild;
+ if (!tempOption) {
+ tempOption = document.createElement('option');
+ tempOption.value = '';
+ this._controls.editor.appendChild(tempOption);
+ tempOption.selected = true;
+ }
+ tempOption.update((text || '').stripScripts().stripTags());
+ },
+
+ checkForExternalText: function() {
+ this._text = this.getText();
+ if (this.options.loadTextURL)
+ this.loadExternalText();
+ else
+ this.buildOptionList();
+ },
+
+ loadExternalText: function() {
+ this.showLoadingText(this.options.loadingText);
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
+ onComplete: Prototype.emptyFunction,
+ onSuccess: function(transport) {
+ this._text = transport.responseText.strip();
+ this.buildOptionList();
+ }.bind(this),
+ onFailure: this.onFailure
+ });
+ new Ajax.Request(this.options.loadTextURL, options);
+ },
+
+ buildOptionList: function() {
+ this._form.removeClassName(this.options.loadingClassName);
+ this._collection = this._collection.map(function(entry) {
+ return 2 === entry.length ? entry : [entry, entry].flatten();
+ });
+ var marker = ('value' in this.options) ? this.options.value : this._text;
+ var textFound = this._collection.any(function(entry) {
+ return entry[0] == marker;
+ }.bind(this));
+ this._controls.editor.update('');
+ var option;
+ this._collection.each(function(entry, index) {
+ option = document.createElement('option');
+ option.value = entry[0];
+ option.selected = textFound ? entry[0] == marker : 0 == index;
+ option.appendChild(document.createTextNode(entry[1]));
+ this._controls.editor.appendChild(option);
+ }.bind(this));
+ this._controls.editor.disabled = false;
+ Field.scrollFreeActivate(this._controls.editor);
+ }
+});
+
+//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
+//**** This only exists for a while, in order to let ****
+//**** users adapt to the new API. Read up on the new ****
+//**** API and convert your code to it ASAP! ****
+
+Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
+ if (!options) return;
+ function fallback(name, expr) {
+ if (name in options || expr === undefined) return;
+ options[name] = expr;
+ };
+ fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
+ options.cancelLink == options.cancelButton == false ? false : undefined)));
+ fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
+ options.okLink == options.okButton == false ? false : undefined)));
+ fallback('highlightColor', options.highlightcolor);
+ fallback('highlightEndColor', options.highlightendcolor);
+};
+
+Object.extend(Ajax.InPlaceEditor, {
+ DefaultOptions: {
+ ajaxOptions: { },
+ autoRows: 3, // Use when multi-line w/ rows == 1
+ cancelControl: 'link', // 'link'|'button'|false
+ cancelText: 'cancel',
+ clickToEditText: 'Click to edit',
+ externalControl: null, // id|elt
+ externalControlOnly: false,
+ fieldPostCreation: 'activate', // 'activate'|'focus'|false
+ formClassName: 'inplaceeditor-form',
+ formId: null, // id|elt
+ highlightColor: '#ffff99',
+ highlightEndColor: '#ffffff',
+ hoverClassName: '',
+ htmlResponse: true,
+ loadingClassName: 'inplaceeditor-loading',
+ loadingText: 'Loading...',
+ okControl: 'button', // 'link'|'button'|false
+ okText: 'ok',
+ paramName: 'value',
+ rows: 1, // If 1 and multi-line, uses autoRows
+ savingClassName: 'inplaceeditor-saving',
+ savingText: 'Saving...',
+ size: 0,
+ stripLoadedTextTags: false,
+ submitOnBlur: false,
+ textAfterControls: '',
+ textBeforeControls: '',
+ textBetweenControls: ''
+ },
+ DefaultCallbacks: {
+ callback: function(form) {
+ return Form.serialize(form);
+ },
+ onComplete: function(transport, element) {
+ // For backward compatibility, this one is bound to the IPE, and passes
+ // the element directly. It was too often customized, so we don't break it.
+ new Effect.Highlight(element, {
+ startcolor: this.options.highlightColor, keepBackgroundImage: true });
+ },
+ onEnterEditMode: null,
+ onEnterHover: function(ipe) {
+ ipe.element.style.backgroundColor = ipe.options.highlightColor;
+ if (ipe._effect)
+ ipe._effect.cancel();
+ },
+ onFailure: function(transport, ipe) {
+ alert('Error communication with the server: ' + transport.responseText.stripTags());
+ },
+ onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
+ onLeaveEditMode: null,
+ onLeaveHover: function(ipe) {
+ ipe._effect = new Effect.Highlight(ipe.element, {
+ startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
+ restorecolor: ipe._originalBackground, keepBackgroundImage: true
+ });
+ }
+ },
+ Listeners: {
+ click: 'enterEditMode',
+ keydown: 'checkForEscapeOrReturn',
+ mouseover: 'enterHover',
+ mouseout: 'leaveHover'
+ }
+});
+
+Ajax.InPlaceCollectionEditor.DefaultOptions = {
+ loadingCollectionText: 'Loading options...'
+};
+
+// Delayed observer, like Form.Element.Observer,
+// but waits for delay after last key input
+// Ideal for live-search fields
+
+Form.Element.DelayedObserver = Class.create({
+ initialize: function(element, delay, callback) {
+ this.delay = delay || 0.5;
+ this.element = $(element);
+ this.callback = callback;
+ this.timer = null;
+ this.lastValue = $F(this.element);
+ Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
+ },
+ delayedListener: function(event) {
+ if(this.lastValue == $F(this.element)) return;
+ if(this.timer) clearTimeout(this.timer);
+ this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
+ this.lastValue = $F(this.element);
+ },
+ onTimerEvent: function() {
+ this.timer = null;
+ this.callback(this.element, $F(this.element));
+ }
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/dragdrop.js b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/dragdrop.js
new file mode 100644
index 0000000..9ebfe24
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/dragdrop.js
@@ -0,0 +1,974 @@
+// script.aculo.us dragdrop.js v1.9.0, Thu Dec 23 16:54:48 -0500 2010
+
+// Copyright (c) 2005-2010 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+if(Object.isUndefined(Effect))
+ throw("dragdrop.js requires including script.aculo.us' effects.js library");
+
+var Droppables = {
+ drops: [],
+
+ remove: function(element) {
+ this.drops = this.drops.reject(function(d) { return d.element==$(element) });
+ },
+
+ add: function(element) {
+ element = $(element);
+ var options = Object.extend({
+ greedy: true,
+ hoverclass: null,
+ tree: false
+ }, arguments[1] || { });
+
+ // cache containers
+ if(options.containment) {
+ options._containers = [];
+ var containment = options.containment;
+ if(Object.isArray(containment)) {
+ containment.each( function(c) { options._containers.push($(c)) });
+ } else {
+ options._containers.push($(containment));
+ }
+ }
+
+ if(options.accept) options.accept = [options.accept].flatten();
+
+ Element.makePositioned(element); // fix IE
+ options.element = element;
+
+ this.drops.push(options);
+ },
+
+ findDeepestChild: function(drops) {
+ deepest = drops[0];
+
+ for (i = 1; i < drops.length; ++i)
+ if (Element.isParent(drops[i].element, deepest.element))
+ deepest = drops[i];
+
+ return deepest;
+ },
+
+ isContained: function(element, drop) {
+ var containmentNode;
+ if(drop.tree) {
+ containmentNode = element.treeNode;
+ } else {
+ containmentNode = element.parentNode;
+ }
+ return drop._containers.detect(function(c) { return containmentNode == c });
+ },
+
+ isAffected: function(point, element, drop) {
+ return (
+ (drop.element!=element) &&
+ ((!drop._containers) ||
+ this.isContained(element, drop)) &&
+ ((!drop.accept) ||
+ (Element.classNames(element).detect(
+ function(v) { return drop.accept.include(v) } ) )) &&
+ Position.within(drop.element, point[0], point[1]) );
+ },
+
+ deactivate: function(drop) {
+ if(drop.hoverclass)
+ Element.removeClassName(drop.element, drop.hoverclass);
+ this.last_active = null;
+ },
+
+ activate: function(drop) {
+ if(drop.hoverclass)
+ Element.addClassName(drop.element, drop.hoverclass);
+ this.last_active = drop;
+ },
+
+ show: function(point, element) {
+ if(!this.drops.length) return;
+ var drop, affected = [];
+
+ this.drops.each( function(drop) {
+ if(Droppables.isAffected(point, element, drop))
+ affected.push(drop);
+ });
+
+ if(affected.length>0)
+ drop = Droppables.findDeepestChild(affected);
+
+ if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
+ if (drop) {
+ Position.within(drop.element, point[0], point[1]);
+ if(drop.onHover)
+ drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
+
+ if (drop != this.last_active) Droppables.activate(drop);
+ }
+ },
+
+ fire: function(event, element) {
+ if(!this.last_active) return;
+ Position.prepare();
+
+ if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
+ if (this.last_active.onDrop) {
+ this.last_active.onDrop(element, this.last_active.element, event);
+ return true;
+ }
+ },
+
+ reset: function() {
+ if(this.last_active)
+ this.deactivate(this.last_active);
+ }
+};
+
+var Draggables = {
+ drags: [],
+ observers: [],
+
+ register: function(draggable) {
+ if(this.drags.length == 0) {
+ this.eventMouseUp = this.endDrag.bindAsEventListener(this);
+ this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
+ this.eventKeypress = this.keyPress.bindAsEventListener(this);
+
+ Event.observe(document, "mouseup", this.eventMouseUp);
+ Event.observe(document, "mousemove", this.eventMouseMove);
+ Event.observe(document, "keypress", this.eventKeypress);
+ }
+ this.drags.push(draggable);
+ },
+
+ unregister: function(draggable) {
+ this.drags = this.drags.reject(function(d) { return d==draggable });
+ if(this.drags.length == 0) {
+ Event.stopObserving(document, "mouseup", this.eventMouseUp);
+ Event.stopObserving(document, "mousemove", this.eventMouseMove);
+ Event.stopObserving(document, "keypress", this.eventKeypress);
+ }
+ },
+
+ activate: function(draggable) {
+ if(draggable.options.delay) {
+ this._timeout = setTimeout(function() {
+ Draggables._timeout = null;
+ window.focus();
+ Draggables.activeDraggable = draggable;
+ }.bind(this), draggable.options.delay);
+ } else {
+ window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
+ this.activeDraggable = draggable;
+ }
+ },
+
+ deactivate: function() {
+ this.activeDraggable = null;
+ },
+
+ updateDrag: function(event) {
+ if(!this.activeDraggable) return;
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ // Mozilla-based browsers fire successive mousemove events with
+ // the same coordinates, prevent needless redrawing (moz bug?)
+ if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
+ this._lastPointer = pointer;
+
+ this.activeDraggable.updateDrag(event, pointer);
+ },
+
+ endDrag: function(event) {
+ if(this._timeout) {
+ clearTimeout(this._timeout);
+ this._timeout = null;
+ }
+ if(!this.activeDraggable) return;
+ this._lastPointer = null;
+ this.activeDraggable.endDrag(event);
+ this.activeDraggable = null;
+ },
+
+ keyPress: function(event) {
+ if(this.activeDraggable)
+ this.activeDraggable.keyPress(event);
+ },
+
+ addObserver: function(observer) {
+ this.observers.push(observer);
+ this._cacheObserverCallbacks();
+ },
+
+ removeObserver: function(element) { // element instead of observer fixes mem leaks
+ this.observers = this.observers.reject( function(o) { return o.element==element });
+ this._cacheObserverCallbacks();
+ },
+
+ notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
+ if(this[eventName+'Count'] > 0)
+ this.observers.each( function(o) {
+ if(o[eventName]) o[eventName](eventName, draggable, event);
+ });
+ if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
+ },
+
+ _cacheObserverCallbacks: function() {
+ ['onStart','onEnd','onDrag'].each( function(eventName) {
+ Draggables[eventName+'Count'] = Draggables.observers.select(
+ function(o) { return o[eventName]; }
+ ).length;
+ });
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Draggable = Class.create({
+ initialize: function(element) {
+ var defaults = {
+ handle: false,
+ reverteffect: function(element, top_offset, left_offset) {
+ var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
+ new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
+ queue: {scope:'_draggable', position:'end'}
+ });
+ },
+ endeffect: function(element) {
+ var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
+ queue: {scope:'_draggable', position:'end'},
+ afterFinish: function(){
+ Draggable._dragging[element] = false
+ }
+ });
+ },
+ zindex: 1000,
+ revert: false,
+ quiet: false,
+ scroll: false,
+ scrollSensitivity: 20,
+ scrollSpeed: 15,
+ snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
+ delay: 0
+ };
+
+ if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
+ Object.extend(defaults, {
+ starteffect: function(element) {
+ element._opacity = Element.getOpacity(element);
+ Draggable._dragging[element] = true;
+ new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
+ }
+ });
+
+ var options = Object.extend(defaults, arguments[1] || { });
+
+ this.element = $(element);
+
+ if(options.handle && Object.isString(options.handle))
+ this.handle = this.element.down('.'+options.handle, 0);
+
+ if(!this.handle) this.handle = $(options.handle);
+ if(!this.handle) this.handle = this.element;
+
+ if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
+ options.scroll = $(options.scroll);
+ this._isScrollChild = Element.childOf(this.element, options.scroll);
+ }
+
+ Element.makePositioned(this.element); // fix IE
+
+ this.options = options;
+ this.dragging = false;
+
+ this.eventMouseDown = this.initDrag.bindAsEventListener(this);
+ Event.observe(this.handle, "mousedown", this.eventMouseDown);
+
+ Draggables.register(this);
+ },
+
+ destroy: function() {
+ Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
+ Draggables.unregister(this);
+ },
+
+ currentDelta: function() {
+ return([
+ parseInt(Element.getStyle(this.element,'left') || '0'),
+ parseInt(Element.getStyle(this.element,'top') || '0')]);
+ },
+
+ initDrag: function(event) {
+ if(!Object.isUndefined(Draggable._dragging[this.element]) &&
+ Draggable._dragging[this.element]) return;
+ if(Event.isLeftClick(event)) {
+ // abort on form elements, fixes a Firefox issue
+ var src = Event.element(event);
+ if((tag_name = src.tagName.toUpperCase()) && (
+ tag_name=='INPUT' ||
+ tag_name=='SELECT' ||
+ tag_name=='OPTION' ||
+ tag_name=='BUTTON' ||
+ tag_name=='TEXTAREA')) return;
+
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var pos = this.element.cumulativeOffset();
+ this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
+
+ Draggables.activate(this);
+ Event.stop(event);
+ }
+ },
+
+ startDrag: function(event) {
+ this.dragging = true;
+ if(!this.delta)
+ this.delta = this.currentDelta();
+
+ if(this.options.zindex) {
+ this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
+ this.element.style.zIndex = this.options.zindex;
+ }
+
+ if(this.options.ghosting) {
+ this._clone = this.element.cloneNode(true);
+ this._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
+ if (!this._originallyAbsolute)
+ Position.absolutize(this.element);
+ this.element.parentNode.insertBefore(this._clone, this.element);
+ }
+
+ if(this.options.scroll) {
+ if (this.options.scroll == window) {
+ var where = this._getWindowScroll(this.options.scroll);
+ this.originalScrollLeft = where.left;
+ this.originalScrollTop = where.top;
+ } else {
+ this.originalScrollLeft = this.options.scroll.scrollLeft;
+ this.originalScrollTop = this.options.scroll.scrollTop;
+ }
+ }
+
+ Draggables.notify('onStart', this, event);
+
+ if(this.options.starteffect) this.options.starteffect(this.element);
+ },
+
+ updateDrag: function(event, pointer) {
+ if(!this.dragging) this.startDrag(event);
+
+ if(!this.options.quiet){
+ Position.prepare();
+ Droppables.show(pointer, this.element);
+ }
+
+ Draggables.notify('onDrag', this, event);
+
+ this.draw(pointer);
+ if(this.options.change) this.options.change(this);
+
+ if(this.options.scroll) {
+ this.stopScrolling();
+
+ var p;
+ if (this.options.scroll == window) {
+ with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
+ } else {
+ p = Position.page(this.options.scroll).toArray();
+ p[0] += this.options.scroll.scrollLeft + Position.deltaX;
+ p[1] += this.options.scroll.scrollTop + Position.deltaY;
+ p.push(p[0]+this.options.scroll.offsetWidth);
+ p.push(p[1]+this.options.scroll.offsetHeight);
+ }
+ var speed = [0,0];
+ if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
+ if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
+ if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
+ if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
+ this.startScrolling(speed);
+ }
+
+ // fix AppleWebKit rendering
+ if(Prototype.Browser.WebKit) window.scrollBy(0,0);
+
+ Event.stop(event);
+ },
+
+ finishDrag: function(event, success) {
+ this.dragging = false;
+
+ if(this.options.quiet){
+ Position.prepare();
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ Droppables.show(pointer, this.element);
+ }
+
+ if(this.options.ghosting) {
+ if (!this._originallyAbsolute)
+ Position.relativize(this.element);
+ delete this._originallyAbsolute;
+ Element.remove(this._clone);
+ this._clone = null;
+ }
+
+ var dropped = false;
+ if(success) {
+ dropped = Droppables.fire(event, this.element);
+ if (!dropped) dropped = false;
+ }
+ if(dropped && this.options.onDropped) this.options.onDropped(this.element);
+ Draggables.notify('onEnd', this, event);
+
+ var revert = this.options.revert;
+ if(revert && Object.isFunction(revert)) revert = revert(this.element);
+
+ var d = this.currentDelta();
+ if(revert && this.options.reverteffect) {
+ if (dropped == 0 || revert != 'failure')
+ this.options.reverteffect(this.element,
+ d[1]-this.delta[1], d[0]-this.delta[0]);
+ } else {
+ this.delta = d;
+ }
+
+ if(this.options.zindex)
+ this.element.style.zIndex = this.originalZ;
+
+ if(this.options.endeffect)
+ this.options.endeffect(this.element);
+
+ Draggables.deactivate(this);
+ Droppables.reset();
+ },
+
+ keyPress: function(event) {
+ if(event.keyCode!=Event.KEY_ESC) return;
+ this.finishDrag(event, false);
+ Event.stop(event);
+ },
+
+ endDrag: function(event) {
+ if(!this.dragging) return;
+ this.stopScrolling();
+ this.finishDrag(event, true);
+ Event.stop(event);
+ },
+
+ draw: function(point) {
+ var pos = this.element.cumulativeOffset();
+ if(this.options.ghosting) {
+ var r = Position.realOffset(this.element);
+ pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
+ }
+
+ var d = this.currentDelta();
+ pos[0] -= d[0]; pos[1] -= d[1];
+
+ if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
+ pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
+ pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
+ }
+
+ var p = [0,1].map(function(i){
+ return (point[i]-pos[i]-this.offset[i])
+ }.bind(this));
+
+ if(this.options.snap) {
+ if(Object.isFunction(this.options.snap)) {
+ p = this.options.snap(p[0],p[1],this);
+ } else {
+ if(Object.isArray(this.options.snap)) {
+ p = p.map( function(v, i) {
+ return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this));
+ } else {
+ p = p.map( function(v) {
+ return (v/this.options.snap).round()*this.options.snap }.bind(this));
+ }
+ }}
+
+ var style = this.element.style;
+ if((!this.options.constraint) || (this.options.constraint=='horizontal'))
+ style.left = p[0] + "px";
+ if((!this.options.constraint) || (this.options.constraint=='vertical'))
+ style.top = p[1] + "px";
+
+ if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
+ },
+
+ stopScrolling: function() {
+ if(this.scrollInterval) {
+ clearInterval(this.scrollInterval);
+ this.scrollInterval = null;
+ Draggables._lastScrollPointer = null;
+ }
+ },
+
+ startScrolling: function(speed) {
+ if(!(speed[0] || speed[1])) return;
+ this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
+ this.lastScrolled = new Date();
+ this.scrollInterval = setInterval(this.scroll.bind(this), 10);
+ },
+
+ scroll: function() {
+ var current = new Date();
+ var delta = current - this.lastScrolled;
+ this.lastScrolled = current;
+ if(this.options.scroll == window) {
+ with (this._getWindowScroll(this.options.scroll)) {
+ if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
+ var d = delta / 1000;
+ this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
+ }
+ }
+ } else {
+ this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
+ this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
+ }
+
+ Position.prepare();
+ Droppables.show(Draggables._lastPointer, this.element);
+ Draggables.notify('onDrag', this);
+ if (this._isScrollChild) {
+ Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
+ Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
+ Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
+ if (Draggables._lastScrollPointer[0] < 0)
+ Draggables._lastScrollPointer[0] = 0;
+ if (Draggables._lastScrollPointer[1] < 0)
+ Draggables._lastScrollPointer[1] = 0;
+ this.draw(Draggables._lastScrollPointer);
+ }
+
+ if(this.options.change) this.options.change(this);
+ },
+
+ _getWindowScroll: function(w) {
+ var T, L, W, H;
+ with (w.document) {
+ if (w.document.documentElement && documentElement.scrollTop) {
+ T = documentElement.scrollTop;
+ L = documentElement.scrollLeft;
+ } else if (w.document.body) {
+ T = body.scrollTop;
+ L = body.scrollLeft;
+ }
+ if (w.innerWidth) {
+ W = w.innerWidth;
+ H = w.innerHeight;
+ } else if (w.document.documentElement && documentElement.clientWidth) {
+ W = documentElement.clientWidth;
+ H = documentElement.clientHeight;
+ } else {
+ W = body.offsetWidth;
+ H = body.offsetHeight;
+ }
+ }
+ return { top: T, left: L, width: W, height: H };
+ }
+});
+
+Draggable._dragging = { };
+
+/*--------------------------------------------------------------------------*/
+
+var SortableObserver = Class.create({
+ initialize: function(element, observer) {
+ this.element = $(element);
+ this.observer = observer;
+ this.lastValue = Sortable.serialize(this.element);
+ },
+
+ onStart: function() {
+ this.lastValue = Sortable.serialize(this.element);
+ },
+
+ onEnd: function() {
+ Sortable.unmark();
+ if(this.lastValue != Sortable.serialize(this.element))
+ this.observer(this.element)
+ }
+});
+
+var Sortable = {
+ SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
+
+ sortables: { },
+
+ _findRootElement: function(element) {
+ while (element.tagName.toUpperCase() != "BODY") {
+ if(element.id && Sortable.sortables[element.id]) return element;
+ element = element.parentNode;
+ }
+ },
+
+ options: function(element) {
+ element = Sortable._findRootElement($(element));
+ if(!element) return;
+ return Sortable.sortables[element.id];
+ },
+
+ destroy: function(element){
+ element = $(element);
+ var s = Sortable.sortables[element.id];
+
+ if(s) {
+ Draggables.removeObserver(s.element);
+ s.droppables.each(function(d){ Droppables.remove(d) });
+ s.draggables.invoke('destroy');
+
+ delete Sortable.sortables[s.element.id];
+ }
+ },
+
+ create: function(element) {
+ element = $(element);
+ var options = Object.extend({
+ element: element,
+ tag: 'li', // assumes li children, override with tag: 'tagname'
+ dropOnEmpty: false,
+ tree: false,
+ treeTag: 'ul',
+ overlap: 'vertical', // one of 'vertical', 'horizontal'
+ constraint: 'vertical', // one of 'vertical', 'horizontal', false
+ containment: element, // also takes array of elements (or id's); or false
+ handle: false, // or a CSS class
+ only: false,
+ delay: 0,
+ hoverclass: null,
+ ghosting: false,
+ quiet: false,
+ scroll: false,
+ scrollSensitivity: 20,
+ scrollSpeed: 15,
+ format: this.SERIALIZE_RULE,
+
+ // these take arrays of elements or ids and can be
+ // used for better initialization performance
+ elements: false,
+ handles: false,
+
+ onChange: Prototype.emptyFunction,
+ onUpdate: Prototype.emptyFunction
+ }, arguments[1] || { });
+
+ // clear any old sortable with same element
+ this.destroy(element);
+
+ // build options for the draggables
+ var options_for_draggable = {
+ revert: true,
+ quiet: options.quiet,
+ scroll: options.scroll,
+ scrollSpeed: options.scrollSpeed,
+ scrollSensitivity: options.scrollSensitivity,
+ delay: options.delay,
+ ghosting: options.ghosting,
+ constraint: options.constraint,
+ handle: options.handle };
+
+ if(options.starteffect)
+ options_for_draggable.starteffect = options.starteffect;
+
+ if(options.reverteffect)
+ options_for_draggable.reverteffect = options.reverteffect;
+ else
+ if(options.ghosting) options_for_draggable.reverteffect = function(element) {
+ element.style.top = 0;
+ element.style.left = 0;
+ };
+
+ if(options.endeffect)
+ options_for_draggable.endeffect = options.endeffect;
+
+ if(options.zindex)
+ options_for_draggable.zindex = options.zindex;
+
+ // build options for the droppables
+ var options_for_droppable = {
+ overlap: options.overlap,
+ containment: options.containment,
+ tree: options.tree,
+ hoverclass: options.hoverclass,
+ onHover: Sortable.onHover
+ };
+
+ var options_for_tree = {
+ onHover: Sortable.onEmptyHover,
+ overlap: options.overlap,
+ containment: options.containment,
+ hoverclass: options.hoverclass
+ };
+
+ // fix for gecko engine
+ Element.cleanWhitespace(element);
+
+ options.draggables = [];
+ options.droppables = [];
+
+ // drop on empty handling
+ if(options.dropOnEmpty || options.tree) {
+ Droppables.add(element, options_for_tree);
+ options.droppables.push(element);
+ }
+
+ (options.elements || this.findElements(element, options) || []).each( function(e,i) {
+ var handle = options.handles ? $(options.handles[i]) :
+ (options.handle ? $(e).select('.' + options.handle)[0] : e);
+ options.draggables.push(
+ new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
+ Droppables.add(e, options_for_droppable);
+ if(options.tree) e.treeNode = element;
+ options.droppables.push(e);
+ });
+
+ if(options.tree) {
+ (Sortable.findTreeElements(element, options) || []).each( function(e) {
+ Droppables.add(e, options_for_tree);
+ e.treeNode = element;
+ options.droppables.push(e);
+ });
+ }
+
+ // keep reference
+ this.sortables[element.identify()] = options;
+
+ // for onupdate
+ Draggables.addObserver(new SortableObserver(element, options.onUpdate));
+
+ },
+
+ // return all suitable-for-sortable elements in a guaranteed order
+ findElements: function(element, options) {
+ return Element.findChildren(
+ element, options.only, options.tree ? true : false, options.tag);
+ },
+
+ findTreeElements: function(element, options) {
+ return Element.findChildren(
+ element, options.only, options.tree ? true : false, options.treeTag);
+ },
+
+ onHover: function(element, dropon, overlap) {
+ if(Element.isParent(dropon, element)) return;
+
+ if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
+ return;
+ } else if(overlap>0.5) {
+ Sortable.mark(dropon, 'before');
+ if(dropon.previousSibling != element) {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = "hidden"; // fix gecko rendering
+ dropon.parentNode.insertBefore(element, dropon);
+ if(dropon.parentNode!=oldParentNode)
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon.parentNode).onChange(element);
+ }
+ } else {
+ Sortable.mark(dropon, 'after');
+ var nextElement = dropon.nextSibling || null;
+ if(nextElement != element) {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = "hidden"; // fix gecko rendering
+ dropon.parentNode.insertBefore(element, nextElement);
+ if(dropon.parentNode!=oldParentNode)
+ Sortable.options(oldParentNode).onChange(element);
+ Sortable.options(dropon.parentNode).onChange(element);
+ }
+ }
+ },
+
+ onEmptyHover: function(element, dropon, overlap) {
+ var oldParentNode = element.parentNode;
+ var droponOptions = Sortable.options(dropon);
+
+ if(!Element.isParent(dropon, element)) {
+ var index;
+
+ var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
+ var child = null;
+
+ if(children) {
+ var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
+
+ for (index = 0; index < children.length; index += 1) {
+ if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
+ offset -= Element.offsetSize (children[index], droponOptions.overlap);
+ } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
+ child = index + 1 < children.length ? children[index + 1] : null;
+ break;
+ } else {
+ child = children[index];
+ break;
+ }
+ }
+ }
+
+ dropon.insertBefore(element, child);
+
+ Sortable.options(oldParentNode).onChange(element);
+ droponOptions.onChange(element);
+ }
+ },
+
+ unmark: function() {
+ if(Sortable._marker) Sortable._marker.hide();
+ },
+
+ mark: function(dropon, position) {
+ // mark on ghosting only
+ var sortable = Sortable.options(dropon.parentNode);
+ if(sortable && !sortable.ghosting) return;
+
+ if(!Sortable._marker) {
+ Sortable._marker =
+ ($('dropmarker') || Element.extend(document.createElement('DIV'))).
+ hide().addClassName('dropmarker').setStyle({position:'absolute'});
+ document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
+ }
+ var offsets = dropon.cumulativeOffset();
+ Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
+
+ if(position=='after')
+ if(sortable.overlap == 'horizontal')
+ Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
+ else
+ Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
+
+ Sortable._marker.show();
+ },
+
+ _tree: function(element, options, parent) {
+ var children = Sortable.findElements(element, options) || [];
+
+ for (var i = 0; i < children.length; ++i) {
+ var match = children[i].id.match(options.format);
+
+ if (!match) continue;
+
+ var child = {
+ id: encodeURIComponent(match ? match[1] : null),
+ element: element,
+ parent: parent,
+ children: [],
+ position: parent.children.length,
+ container: $(children[i]).down(options.treeTag)
+ };
+
+ /* Get the element containing the children and recurse over it */
+ if (child.container)
+ this._tree(child.container, options, child);
+
+ parent.children.push (child);
+ }
+
+ return parent;
+ },
+
+ tree: function(element) {
+ element = $(element);
+ var sortableOptions = this.options(element);
+ var options = Object.extend({
+ tag: sortableOptions.tag,
+ treeTag: sortableOptions.treeTag,
+ only: sortableOptions.only,
+ name: element.id,
+ format: sortableOptions.format
+ }, arguments[1] || { });
+
+ var root = {
+ id: null,
+ parent: null,
+ children: [],
+ container: element,
+ position: 0
+ };
+
+ return Sortable._tree(element, options, root);
+ },
+
+ /* Construct a [i] index for a particular node */
+ _constructIndex: function(node) {
+ var index = '';
+ do {
+ if (node.id) index = '[' + node.position + ']' + index;
+ } while ((node = node.parent) != null);
+ return index;
+ },
+
+ sequence: function(element) {
+ element = $(element);
+ var options = Object.extend(this.options(element), arguments[1] || { });
+
+ return $(this.findElements(element, options) || []).map( function(item) {
+ return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
+ });
+ },
+
+ setSequence: function(element, new_sequence) {
+ element = $(element);
+ var options = Object.extend(this.options(element), arguments[2] || { });
+
+ var nodeMap = { };
+ this.findElements(element, options).each( function(n) {
+ if (n.id.match(options.format))
+ nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
+ n.parentNode.removeChild(n);
+ });
+
+ new_sequence.each(function(ident) {
+ var n = nodeMap[ident];
+ if (n) {
+ n[1].appendChild(n[0]);
+ delete nodeMap[ident];
+ }
+ });
+ },
+
+ serialize: function(element) {
+ element = $(element);
+ var options = Object.extend(Sortable.options(element), arguments[1] || { });
+ var name = encodeURIComponent(
+ (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
+
+ if (options.tree) {
+ return Sortable.tree(element, arguments[1]).children.map( function (item) {
+ return [name + Sortable._constructIndex(item) + "[id]=" +
+ encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
+ }).flatten().join('&');
+ } else {
+ return Sortable.sequence(element, arguments[1]).map( function(item) {
+ return name + "[]=" + encodeURIComponent(item);
+ }).join('&');
+ }
+ }
+};
+
+// Returns true if child is contained within element
+Element.isParent = function(child, element) {
+ if (!child.parentNode || child == element) return false;
+ if (child.parentNode == element) return true;
+ return Element.isParent(child.parentNode, element);
+};
+
+Element.findChildren = function(element, only, recursive, tagName) {
+ if(!element.hasChildNodes()) return null;
+ tagName = tagName.toUpperCase();
+ if(only) only = [only].flatten();
+ var elements = [];
+ $A(element.childNodes).each( function(e) {
+ if(e.tagName && e.tagName.toUpperCase()==tagName &&
+ (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
+ elements.push(e);
+ if(recursive) {
+ var grandchildren = Element.findChildren(e, only, recursive, tagName);
+ if(grandchildren) elements.push(grandchildren);
+ }
+ });
+
+ return (elements.length>0 ? elements.flatten() : []);
+};
+
+Element.offsetSize = function (element, type) {
+ return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
+}; \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/effects.js b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/effects.js
new file mode 100644
index 0000000..860ddc0
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/effects.js
@@ -0,0 +1,1123 @@
+// script.aculo.us effects.js v1.9.0, Thu Dec 23 16:54:48 -0500 2010
+
+// Copyright (c) 2005-2010 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Contributors:
+// Justin Palmer (http://encytemedia.com/)
+// Mark Pilgrim (http://diveintomark.org/)
+// Martin Bialasinki
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// converts rgb() and #xxx to #xxxxxx format,
+// returns self (or first argument) if not convertable
+String.prototype.parseColor = function() {
+ var color = '#';
+ if (this.slice(0,4) == 'rgb(') {
+ var cols = this.slice(4,this.length-1).split(',');
+ var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
+ } else {
+ if (this.slice(0,1) == '#') {
+ if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
+ if (this.length==7) color = this.toLowerCase();
+ }
+ }
+ return (color.length==7 ? color : (arguments[0] || this));
+};
+
+/*--------------------------------------------------------------------------*/
+
+Element.collectTextNodes = function(element) {
+ return $A($(element).childNodes).collect( function(node) {
+ return (node.nodeType==3 ? node.nodeValue :
+ (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
+ }).flatten().join('');
+};
+
+Element.collectTextNodesIgnoreClass = function(element, className) {
+ return $A($(element).childNodes).collect( function(node) {
+ return (node.nodeType==3 ? node.nodeValue :
+ ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
+ Element.collectTextNodesIgnoreClass(node, className) : ''));
+ }).flatten().join('');
+};
+
+Element.setContentZoom = function(element, percent) {
+ element = $(element);
+ element.setStyle({fontSize: (percent/100) + 'em'});
+ if (Prototype.Browser.WebKit) window.scrollBy(0,0);
+ return element;
+};
+
+Element.getInlineOpacity = function(element){
+ return $(element).style.opacity || '';
+};
+
+Element.forceRerendering = function(element) {
+ try {
+ element = $(element);
+ var n = document.createTextNode(' ');
+ element.appendChild(n);
+ element.removeChild(n);
+ } catch(e) { }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Effect = {
+ _elementDoesNotExistError: {
+ name: 'ElementDoesNotExistError',
+ message: 'The specified DOM element does not exist, but is required for this effect to operate'
+ },
+ Transitions: {
+ linear: Prototype.K,
+ sinoidal: function(pos) {
+ return (-Math.cos(pos*Math.PI)/2) + .5;
+ },
+ reverse: function(pos) {
+ return 1-pos;
+ },
+ flicker: function(pos) {
+ var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;
+ return pos > 1 ? 1 : pos;
+ },
+ wobble: function(pos) {
+ return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;
+ },
+ pulse: function(pos, pulses) {
+ return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
+ },
+ spring: function(pos) {
+ return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
+ },
+ none: function(pos) {
+ return 0;
+ },
+ full: function(pos) {
+ return 1;
+ }
+ },
+ DefaultOptions: {
+ duration: 1.0, // seconds
+ fps: 100, // 100= assume 66fps max.
+ sync: false, // true for combining
+ from: 0.0,
+ to: 1.0,
+ delay: 0.0,
+ queue: 'parallel'
+ },
+ tagifyText: function(element) {
+ var tagifyStyle = 'position:relative';
+ if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
+
+ element = $(element);
+ $A(element.childNodes).each( function(child) {
+ if (child.nodeType==3) {
+ child.nodeValue.toArray().each( function(character) {
+ element.insertBefore(
+ new Element('span', {style: tagifyStyle}).update(
+ character == ' ' ? String.fromCharCode(160) : character),
+ child);
+ });
+ Element.remove(child);
+ }
+ });
+ },
+ multiple: function(element, effect) {
+ var elements;
+ if (((typeof element == 'object') ||
+ Object.isFunction(element)) &&
+ (element.length))
+ elements = element;
+ else
+ elements = $(element).childNodes;
+
+ var options = Object.extend({
+ speed: 0.1,
+ delay: 0.0
+ }, arguments[2] || { });
+ var masterDelay = options.delay;
+
+ $A(elements).each( function(element, index) {
+ new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
+ });
+ },
+ PAIRS: {
+ 'slide': ['SlideDown','SlideUp'],
+ 'blind': ['BlindDown','BlindUp'],
+ 'appear': ['Appear','Fade']
+ },
+ toggle: function(element, effect, options) {
+ element = $(element);
+ effect = (effect || 'appear').toLowerCase();
+
+ return Effect[ Effect.PAIRS[ effect ][ element.visible() ? 1 : 0 ] ](element, Object.extend({
+ queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
+ }, options || {}));
+ }
+};
+
+Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
+
+/* ------------- core effects ------------- */
+
+Effect.ScopedQueue = Class.create(Enumerable, {
+ initialize: function() {
+ this.effects = [];
+ this.interval = null;
+ },
+ _each: function(iterator) {
+ this.effects._each(iterator);
+ },
+ add: function(effect) {
+ var timestamp = new Date().getTime();
+
+ var position = Object.isString(effect.options.queue) ?
+ effect.options.queue : effect.options.queue.position;
+
+ switch(position) {
+ case 'front':
+ // move unstarted effects after this effect
+ this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
+ e.startOn += effect.finishOn;
+ e.finishOn += effect.finishOn;
+ });
+ break;
+ case 'with-last':
+ timestamp = this.effects.pluck('startOn').max() || timestamp;
+ break;
+ case 'end':
+ // start effect after last queued effect has finished
+ timestamp = this.effects.pluck('finishOn').max() || timestamp;
+ break;
+ }
+
+ effect.startOn += timestamp;
+ effect.finishOn += timestamp;
+
+ if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
+ this.effects.push(effect);
+
+ if (!this.interval)
+ this.interval = setInterval(this.loop.bind(this), 15);
+ },
+ remove: function(effect) {
+ this.effects = this.effects.reject(function(e) { return e==effect });
+ if (this.effects.length == 0) {
+ clearInterval(this.interval);
+ this.interval = null;
+ }
+ },
+ loop: function() {
+ var timePos = new Date().getTime();
+ for(var i=0, len=this.effects.length;i<len;i++)
+ this.effects[i] && this.effects[i].loop(timePos);
+ }
+});
+
+Effect.Queues = {
+ instances: $H(),
+ get: function(queueName) {
+ if (!Object.isString(queueName)) return queueName;
+
+ return this.instances.get(queueName) ||
+ this.instances.set(queueName, new Effect.ScopedQueue());
+ }
+};
+Effect.Queue = Effect.Queues.get('global');
+
+Effect.Base = Class.create({
+ position: null,
+ start: function(options) {
+ if (options && options.transition === false) options.transition = Effect.Transitions.linear;
+ this.options = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
+ this.currentFrame = 0;
+ this.state = 'idle';
+ this.startOn = this.options.delay*1000;
+ this.finishOn = this.startOn+(this.options.duration*1000);
+ this.fromToDelta = this.options.to-this.options.from;
+ this.totalTime = this.finishOn-this.startOn;
+ this.totalFrames = this.options.fps*this.options.duration;
+
+ this.render = (function() {
+ function dispatch(effect, eventName) {
+ if (effect.options[eventName + 'Internal'])
+ effect.options[eventName + 'Internal'](effect);
+ if (effect.options[eventName])
+ effect.options[eventName](effect);
+ }
+
+ return function(pos) {
+ if (this.state === "idle") {
+ this.state = "running";
+ dispatch(this, 'beforeSetup');
+ if (this.setup) this.setup();
+ dispatch(this, 'afterSetup');
+ }
+ if (this.state === "running") {
+ pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from;
+ this.position = pos;
+ dispatch(this, 'beforeUpdate');
+ if (this.update) this.update(pos);
+ dispatch(this, 'afterUpdate');
+ }
+ };
+ })();
+
+ this.event('beforeStart');
+ if (!this.options.sync)
+ Effect.Queues.get(Object.isString(this.options.queue) ?
+ 'global' : this.options.queue.scope).add(this);
+ },
+ loop: function(timePos) {
+ if (timePos >= this.startOn) {
+ if (timePos >= this.finishOn) {
+ this.render(1.0);
+ this.cancel();
+ this.event('beforeFinish');
+ if (this.finish) this.finish();
+ this.event('afterFinish');
+ return;
+ }
+ var pos = (timePos - this.startOn) / this.totalTime,
+ frame = (pos * this.totalFrames).round();
+ if (frame > this.currentFrame) {
+ this.render(pos);
+ this.currentFrame = frame;
+ }
+ }
+ },
+ cancel: function() {
+ if (!this.options.sync)
+ Effect.Queues.get(Object.isString(this.options.queue) ?
+ 'global' : this.options.queue.scope).remove(this);
+ this.state = 'finished';
+ },
+ event: function(eventName) {
+ if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
+ if (this.options[eventName]) this.options[eventName](this);
+ },
+ inspect: function() {
+ var data = $H();
+ for(property in this)
+ if (!Object.isFunction(this[property])) data.set(property, this[property]);
+ return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
+ }
+});
+
+Effect.Parallel = Class.create(Effect.Base, {
+ initialize: function(effects) {
+ this.effects = effects || [];
+ this.start(arguments[1]);
+ },
+ update: function(position) {
+ this.effects.invoke('render', position);
+ },
+ finish: function(position) {
+ this.effects.each( function(effect) {
+ effect.render(1.0);
+ effect.cancel();
+ effect.event('beforeFinish');
+ if (effect.finish) effect.finish(position);
+ effect.event('afterFinish');
+ });
+ }
+});
+
+Effect.Tween = Class.create(Effect.Base, {
+ initialize: function(object, from, to) {
+ object = Object.isString(object) ? $(object) : object;
+ var args = $A(arguments), method = args.last(),
+ options = args.length == 5 ? args[3] : null;
+ this.method = Object.isFunction(method) ? method.bind(object) :
+ Object.isFunction(object[method]) ? object[method].bind(object) :
+ function(value) { object[method] = value };
+ this.start(Object.extend({ from: from, to: to }, options || { }));
+ },
+ update: function(position) {
+ this.method(position);
+ }
+});
+
+Effect.Event = Class.create(Effect.Base, {
+ initialize: function() {
+ this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
+ },
+ update: Prototype.emptyFunction
+});
+
+Effect.Opacity = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ // make this work on IE on elements without 'layout'
+ if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
+ this.element.setStyle({zoom: 1});
+ var options = Object.extend({
+ from: this.element.getOpacity() || 0.0,
+ to: 1.0
+ }, arguments[1] || { });
+ this.start(options);
+ },
+ update: function(position) {
+ this.element.setOpacity(position);
+ }
+});
+
+Effect.Move = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ x: 0,
+ y: 0,
+ mode: 'relative'
+ }, arguments[1] || { });
+ this.start(options);
+ },
+ setup: function() {
+ this.element.makePositioned();
+ this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
+ this.originalTop = parseFloat(this.element.getStyle('top') || '0');
+ if (this.options.mode == 'absolute') {
+ this.options.x = this.options.x - this.originalLeft;
+ this.options.y = this.options.y - this.originalTop;
+ }
+ },
+ update: function(position) {
+ this.element.setStyle({
+ left: (this.options.x * position + this.originalLeft).round() + 'px',
+ top: (this.options.y * position + this.originalTop).round() + 'px'
+ });
+ }
+});
+
+// for backwards compatibility
+Effect.MoveBy = function(element, toTop, toLeft) {
+ return new Effect.Move(element,
+ Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
+};
+
+Effect.Scale = Class.create(Effect.Base, {
+ initialize: function(element, percent) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ scaleX: true,
+ scaleY: true,
+ scaleContent: true,
+ scaleFromCenter: false,
+ scaleMode: 'box', // 'box' or 'contents' or { } with provided values
+ scaleFrom: 100.0,
+ scaleTo: percent
+ }, arguments[2] || { });
+ this.start(options);
+ },
+ setup: function() {
+ this.restoreAfterFinish = this.options.restoreAfterFinish || false;
+ this.elementPositioning = this.element.getStyle('position');
+
+ this.originalStyle = { };
+ ['top','left','width','height','fontSize'].each( function(k) {
+ this.originalStyle[k] = this.element.style[k];
+ }.bind(this));
+
+ this.originalTop = this.element.offsetTop;
+ this.originalLeft = this.element.offsetLeft;
+
+ var fontSize = this.element.getStyle('font-size') || '100%';
+ ['em','px','%','pt'].each( function(fontSizeType) {
+ if (fontSize.indexOf(fontSizeType)>0) {
+ this.fontSize = parseFloat(fontSize);
+ this.fontSizeType = fontSizeType;
+ }
+ }.bind(this));
+
+ this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
+
+ this.dims = null;
+ if (this.options.scaleMode=='box')
+ this.dims = [this.element.offsetHeight, this.element.offsetWidth];
+ if (/^content/.test(this.options.scaleMode))
+ this.dims = [this.element.scrollHeight, this.element.scrollWidth];
+ if (!this.dims)
+ this.dims = [this.options.scaleMode.originalHeight,
+ this.options.scaleMode.originalWidth];
+ },
+ update: function(position) {
+ var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
+ if (this.options.scaleContent && this.fontSize)
+ this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
+ this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
+ },
+ finish: function(position) {
+ if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
+ },
+ setDimensions: function(height, width) {
+ var d = { };
+ if (this.options.scaleX) d.width = width.round() + 'px';
+ if (this.options.scaleY) d.height = height.round() + 'px';
+ if (this.options.scaleFromCenter) {
+ var topd = (height - this.dims[0])/2;
+ var leftd = (width - this.dims[1])/2;
+ if (this.elementPositioning == 'absolute') {
+ if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
+ if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
+ } else {
+ if (this.options.scaleY) d.top = -topd + 'px';
+ if (this.options.scaleX) d.left = -leftd + 'px';
+ }
+ }
+ this.element.setStyle(d);
+ }
+});
+
+Effect.Highlight = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
+ this.start(options);
+ },
+ setup: function() {
+ // Prevent executing on elements not in the layout flow
+ if (this.element.getStyle('display')=='none') { this.cancel(); return; }
+ // Disable background image during the effect
+ this.oldStyle = { };
+ if (!this.options.keepBackgroundImage) {
+ this.oldStyle.backgroundImage = this.element.getStyle('background-image');
+ this.element.setStyle({backgroundImage: 'none'});
+ }
+ if (!this.options.endcolor)
+ this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
+ if (!this.options.restorecolor)
+ this.options.restorecolor = this.element.getStyle('background-color');
+ // init color calculations
+ this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
+ this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
+ },
+ update: function(position) {
+ this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
+ return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
+ },
+ finish: function() {
+ this.element.setStyle(Object.extend(this.oldStyle, {
+ backgroundColor: this.options.restorecolor
+ }));
+ }
+});
+
+Effect.ScrollTo = function(element) {
+ var options = arguments[1] || { },
+ scrollOffsets = document.viewport.getScrollOffsets(),
+ elementOffsets = $(element).cumulativeOffset();
+
+ if (options.offset) elementOffsets[1] += options.offset;
+
+ return new Effect.Tween(null,
+ scrollOffsets.top,
+ elementOffsets[1],
+ options,
+ function(p){ scrollTo(scrollOffsets.left, p.round()); }
+ );
+};
+
+/* ------------- combination effects ------------- */
+
+Effect.Fade = function(element) {
+ element = $(element);
+ var oldOpacity = element.getInlineOpacity();
+ var options = Object.extend({
+ from: element.getOpacity() || 1.0,
+ to: 0.0,
+ afterFinishInternal: function(effect) {
+ if (effect.options.to!=0) return;
+ effect.element.hide().setStyle({opacity: oldOpacity});
+ }
+ }, arguments[1] || { });
+ return new Effect.Opacity(element,options);
+};
+
+Effect.Appear = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
+ to: 1.0,
+ // force Safari to render floated elements properly
+ afterFinishInternal: function(effect) {
+ effect.element.forceRerendering();
+ },
+ beforeSetup: function(effect) {
+ effect.element.setOpacity(effect.options.from).show();
+ }}, arguments[1] || { });
+ return new Effect.Opacity(element,options);
+};
+
+Effect.Puff = function(element) {
+ element = $(element);
+ var oldStyle = {
+ opacity: element.getInlineOpacity(),
+ position: element.getStyle('position'),
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height
+ };
+ return new Effect.Parallel(
+ [ new Effect.Scale(element, 200,
+ { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
+ new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
+ Object.extend({ duration: 1.0,
+ beforeSetupInternal: function(effect) {
+ Position.absolutize(effect.effects[0].element);
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().setStyle(oldStyle); }
+ }, arguments[1] || { })
+ );
+};
+
+Effect.BlindUp = function(element) {
+ element = $(element);
+ element.makeClipping();
+ return new Effect.Scale(element, 0,
+ Object.extend({ scaleContent: false,
+ scaleX: false,
+ restoreAfterFinish: true,
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping();
+ }
+ }, arguments[1] || { })
+ );
+};
+
+Effect.BlindDown = function(element) {
+ element = $(element);
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, 100, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ scaleFrom: 0,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) {
+ effect.element.makeClipping().setStyle({height: '0px'}).show();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.undoClipping();
+ }
+ }, arguments[1] || { }));
+};
+
+Effect.SwitchOff = function(element) {
+ element = $(element);
+ var oldOpacity = element.getInlineOpacity();
+ return new Effect.Appear(element, Object.extend({
+ duration: 0.4,
+ from: 0,
+ transition: Effect.Transitions.flicker,
+ afterFinishInternal: function(effect) {
+ new Effect.Scale(effect.element, 1, {
+ duration: 0.3, scaleFromCenter: true,
+ scaleX: false, scaleContent: false, restoreAfterFinish: true,
+ beforeSetup: function(effect) {
+ effect.element.makePositioned().makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
+ }
+ });
+ }
+ }, arguments[1] || { }));
+};
+
+Effect.DropOut = function(element) {
+ element = $(element);
+ var oldStyle = {
+ top: element.getStyle('top'),
+ left: element.getStyle('left'),
+ opacity: element.getInlineOpacity() };
+ return new Effect.Parallel(
+ [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
+ new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
+ Object.extend(
+ { duration: 0.5,
+ beforeSetup: function(effect) {
+ effect.effects[0].element.makePositioned();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
+ }
+ }, arguments[1] || { }));
+};
+
+Effect.Shake = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ distance: 20,
+ duration: 0.5
+ }, arguments[1] || {});
+ var distance = parseFloat(options.distance);
+ var split = parseFloat(options.duration) / 10.0;
+ var oldStyle = {
+ top: element.getStyle('top'),
+ left: element.getStyle('left') };
+ return new Effect.Move(element,
+ { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
+ effect.element.undoPositioned().setStyle(oldStyle);
+ }}); }}); }}); }}); }}); }});
+};
+
+Effect.SlideDown = function(element) {
+ element = $(element).cleanWhitespace();
+ // SlideDown need to have the content of the element wrapped in a container element with fixed height!
+ var oldInnerBottom = element.down().getStyle('bottom');
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, 100, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ scaleFrom: window.opera ? 0 : 1,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) {
+ effect.element.makePositioned();
+ effect.element.down().makePositioned();
+ if (window.opera) effect.element.setStyle({top: ''});
+ effect.element.makeClipping().setStyle({height: '0px'}).show();
+ },
+ afterUpdateInternal: function(effect) {
+ effect.element.down().setStyle({bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.undoClipping().undoPositioned();
+ effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
+ }, arguments[1] || { })
+ );
+};
+
+Effect.SlideUp = function(element) {
+ element = $(element).cleanWhitespace();
+ var oldInnerBottom = element.down().getStyle('bottom');
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, window.opera ? 0 : 1,
+ Object.extend({ scaleContent: false,
+ scaleX: false,
+ scaleMode: 'box',
+ scaleFrom: 100,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) {
+ effect.element.makePositioned();
+ effect.element.down().makePositioned();
+ if (window.opera) effect.element.setStyle({top: ''});
+ effect.element.makeClipping().show();
+ },
+ afterUpdateInternal: function(effect) {
+ effect.element.down().setStyle({bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().undoPositioned();
+ effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
+ }
+ }, arguments[1] || { })
+ );
+};
+
+// Bug in opera makes the TD containing this element expand for a instance after finish
+Effect.Squish = function(element) {
+ return new Effect.Scale(element, window.opera ? 1 : 0, {
+ restoreAfterFinish: true,
+ beforeSetup: function(effect) {
+ effect.element.makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping();
+ }
+ });
+};
+
+Effect.Grow = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ direction: 'center',
+ moveTransition: Effect.Transitions.sinoidal,
+ scaleTransition: Effect.Transitions.sinoidal,
+ opacityTransition: Effect.Transitions.full
+ }, arguments[1] || { });
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: element.getInlineOpacity() };
+
+ var dims = element.getDimensions();
+ var initialMoveX, initialMoveY;
+ var moveX, moveY;
+
+ switch (options.direction) {
+ case 'top-left':
+ initialMoveX = initialMoveY = moveX = moveY = 0;
+ break;
+ case 'top-right':
+ initialMoveX = dims.width;
+ initialMoveY = moveY = 0;
+ moveX = -dims.width;
+ break;
+ case 'bottom-left':
+ initialMoveX = moveX = 0;
+ initialMoveY = dims.height;
+ moveY = -dims.height;
+ break;
+ case 'bottom-right':
+ initialMoveX = dims.width;
+ initialMoveY = dims.height;
+ moveX = -dims.width;
+ moveY = -dims.height;
+ break;
+ case 'center':
+ initialMoveX = dims.width / 2;
+ initialMoveY = dims.height / 2;
+ moveX = -dims.width / 2;
+ moveY = -dims.height / 2;
+ break;
+ }
+
+ return new Effect.Move(element, {
+ x: initialMoveX,
+ y: initialMoveY,
+ duration: 0.01,
+ beforeSetup: function(effect) {
+ effect.element.hide().makeClipping().makePositioned();
+ },
+ afterFinishInternal: function(effect) {
+ new Effect.Parallel(
+ [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
+ new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
+ new Effect.Scale(effect.element, 100, {
+ scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
+ sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
+ ], Object.extend({
+ beforeSetup: function(effect) {
+ effect.effects[0].element.setStyle({height: '0px'}).show();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
+ }
+ }, options)
+ );
+ }
+ });
+};
+
+Effect.Shrink = function(element) {
+ element = $(element);
+ var options = Object.extend({
+ direction: 'center',
+ moveTransition: Effect.Transitions.sinoidal,
+ scaleTransition: Effect.Transitions.sinoidal,
+ opacityTransition: Effect.Transitions.none
+ }, arguments[1] || { });
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: element.getInlineOpacity() };
+
+ var dims = element.getDimensions();
+ var moveX, moveY;
+
+ switch (options.direction) {
+ case 'top-left':
+ moveX = moveY = 0;
+ break;
+ case 'top-right':
+ moveX = dims.width;
+ moveY = 0;
+ break;
+ case 'bottom-left':
+ moveX = 0;
+ moveY = dims.height;
+ break;
+ case 'bottom-right':
+ moveX = dims.width;
+ moveY = dims.height;
+ break;
+ case 'center':
+ moveX = dims.width / 2;
+ moveY = dims.height / 2;
+ break;
+ }
+
+ return new Effect.Parallel(
+ [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
+ new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
+ new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
+ ], Object.extend({
+ beforeStartInternal: function(effect) {
+ effect.effects[0].element.makePositioned().makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
+ }, options)
+ );
+};
+
+Effect.Pulsate = function(element) {
+ element = $(element);
+ var options = arguments[1] || { },
+ oldOpacity = element.getInlineOpacity(),
+ transition = options.transition || Effect.Transitions.linear,
+ reverser = function(pos){
+ return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5);
+ };
+
+ return new Effect.Opacity(element,
+ Object.extend(Object.extend({ duration: 2.0, from: 0,
+ afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
+ }, options), {transition: reverser}));
+};
+
+Effect.Fold = function(element) {
+ element = $(element);
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height };
+ element.makeClipping();
+ return new Effect.Scale(element, 5, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ afterFinishInternal: function(effect) {
+ new Effect.Scale(element, 1, {
+ scaleContent: false,
+ scaleY: false,
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().setStyle(oldStyle);
+ } });
+ }}, arguments[1] || { }));
+};
+
+Effect.Morph = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ style: { }
+ }, arguments[1] || { });
+
+ if (!Object.isString(options.style)) this.style = $H(options.style);
+ else {
+ if (options.style.include(':'))
+ this.style = options.style.parseStyle();
+ else {
+ this.element.addClassName(options.style);
+ this.style = $H(this.element.getStyles());
+ this.element.removeClassName(options.style);
+ var css = this.element.getStyles();
+ this.style = this.style.reject(function(style) {
+ return style.value == css[style.key];
+ });
+ options.afterFinishInternal = function(effect) {
+ effect.element.addClassName(effect.options.style);
+ effect.transforms.each(function(transform) {
+ effect.element.style[transform.style] = '';
+ });
+ };
+ }
+ }
+ this.start(options);
+ },
+
+ setup: function(){
+ function parseColor(color){
+ if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
+ color = color.parseColor();
+ return $R(0,2).map(function(i){
+ return parseInt( color.slice(i*2+1,i*2+3), 16 );
+ });
+ }
+ this.transforms = this.style.map(function(pair){
+ var property = pair[0], value = pair[1], unit = null;
+
+ if (value.parseColor('#zzzzzz') != '#zzzzzz') {
+ value = value.parseColor();
+ unit = 'color';
+ } else if (property == 'opacity') {
+ value = parseFloat(value);
+ if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
+ this.element.setStyle({zoom: 1});
+ } else if (Element.CSS_LENGTH.test(value)) {
+ var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
+ value = parseFloat(components[1]);
+ unit = (components.length == 3) ? components[2] : null;
+ }
+
+ var originalValue = this.element.getStyle(property);
+ return {
+ style: property.camelize(),
+ originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
+ targetValue: unit=='color' ? parseColor(value) : value,
+ unit: unit
+ };
+ }.bind(this)).reject(function(transform){
+ return (
+ (transform.originalValue == transform.targetValue) ||
+ (
+ transform.unit != 'color' &&
+ (isNaN(transform.originalValue) || isNaN(transform.targetValue))
+ )
+ );
+ });
+ },
+ update: function(position) {
+ var style = { }, transform, i = this.transforms.length;
+ while(i--)
+ style[(transform = this.transforms[i]).style] =
+ transform.unit=='color' ? '#'+
+ (Math.round(transform.originalValue[0]+
+ (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
+ (Math.round(transform.originalValue[1]+
+ (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
+ (Math.round(transform.originalValue[2]+
+ (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
+ (transform.originalValue +
+ (transform.targetValue - transform.originalValue) * position).toFixed(3) +
+ (transform.unit === null ? '' : transform.unit);
+ this.element.setStyle(style, true);
+ }
+});
+
+Effect.Transform = Class.create({
+ initialize: function(tracks){
+ this.tracks = [];
+ this.options = arguments[1] || { };
+ this.addTracks(tracks);
+ },
+ addTracks: function(tracks){
+ tracks.each(function(track){
+ track = $H(track);
+ var data = track.values().first();
+ this.tracks.push($H({
+ ids: track.keys().first(),
+ effect: Effect.Morph,
+ options: { style: data }
+ }));
+ }.bind(this));
+ return this;
+ },
+ play: function(){
+ return new Effect.Parallel(
+ this.tracks.map(function(track){
+ var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
+ var elements = [$(ids) || $$(ids)].flatten();
+ return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
+ }).flatten(),
+ this.options
+ );
+ }
+});
+
+Element.CSS_PROPERTIES = $w(
+ 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
+ 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
+ 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
+ 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
+ 'fontSize fontWeight height left letterSpacing lineHeight ' +
+ 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
+ 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
+ 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
+ 'right textIndent top width wordSpacing zIndex');
+
+Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
+
+String.__parseStyleElement = document.createElement('div');
+String.prototype.parseStyle = function(){
+ var style, styleRules = $H();
+ if (Prototype.Browser.WebKit)
+ style = new Element('div',{style:this}).style;
+ else {
+ String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
+ style = String.__parseStyleElement.childNodes[0].style;
+ }
+
+ Element.CSS_PROPERTIES.each(function(property){
+ if (style[property]) styleRules.set(property, style[property]);
+ });
+
+ if (Prototype.Browser.IE && this.include('opacity'))
+ styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
+
+ return styleRules;
+};
+
+if (document.defaultView && document.defaultView.getComputedStyle) {
+ Element.getStyles = function(element) {
+ var css = document.defaultView.getComputedStyle($(element), null);
+ return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
+ styles[property] = css[property];
+ return styles;
+ });
+ };
+} else {
+ Element.getStyles = function(element) {
+ element = $(element);
+ var css = element.currentStyle, styles;
+ styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
+ results[property] = css[property];
+ return results;
+ });
+ if (!styles.opacity) styles.opacity = element.getOpacity();
+ return styles;
+ };
+}
+
+Effect.Methods = {
+ morph: function(element, style) {
+ element = $(element);
+ new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
+ return element;
+ },
+ visualEffect: function(element, effect, options) {
+ element = $(element);
+ var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
+ new Effect[klass](element, options);
+ return element;
+ },
+ highlight: function(element, options) {
+ element = $(element);
+ new Effect.Highlight(element, options);
+ return element;
+ }
+};
+
+$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
+ 'pulsate shake puff squish switchOff dropOut').each(
+ function(effect) {
+ Effect.Methods[effect] = function(element, options){
+ element = $(element);
+ Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
+ return element;
+ };
+ }
+);
+
+$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
+ function(f) { Effect.Methods[f] = Element[f]; }
+);
+
+Element.addMethods(Effect.Methods); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/scriptaculous.js b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/scriptaculous.js
new file mode 100644
index 0000000..0ea5c44
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/scriptaculous.js
@@ -0,0 +1,68 @@
+// script.aculo.us scriptaculous.js v1.9.0, Thu Dec 23 16:54:48 -0500 2010
+
+// Copyright (c) 2005-2010 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+var Scriptaculous = {
+ Version: '1.9.0',
+ require: function(libraryName) {
+ try{
+ // inserting via DOM fails in Safari 2.0, so brute force approach
+ document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>');
+ } catch(e) {
+ // for xhtml+xml served content, fall back to DOM methods
+ var script = document.createElement('script');
+ script.type = 'text/javascript';
+ script.src = libraryName;
+ document.getElementsByTagName('head')[0].appendChild(script);
+ }
+ },
+ REQUIRED_PROTOTYPE: '1.6.0.3',
+ load: function() {
+ function convertVersionString(versionString) {
+ var v = versionString.replace(/_.*|\./g, '');
+ v = parseInt(v + '0'.times(4-v.length));
+ return versionString.indexOf('_') > -1 ? v-1 : v;
+ }
+
+ if((typeof Prototype=='undefined') ||
+ (typeof Element == 'undefined') ||
+ (typeof Element.Methods=='undefined') ||
+ (convertVersionString(Prototype.Version) <
+ convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE)))
+ throw("script.aculo.us requires the Prototype JavaScript framework >= " +
+ Scriptaculous.REQUIRED_PROTOTYPE);
+
+ var js = /scriptaculous\.js(\?.*)?$/;
+ $$('script[src]').findAll(function(s) {
+ return s.src.match(js);
+ }).each(function(s) {
+ var path = s.src.replace(js, ''),
+ includes = s.src.match(/\?.*load=([a-z,]*)/);
+ (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each(
+ function(include) { Scriptaculous.require(path+include+'.js') });
+ });
+ }
+};
+
+Scriptaculous.load(); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/slider.js b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/slider.js
new file mode 100644
index 0000000..438e689
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/slider.js
@@ -0,0 +1,275 @@
+// script.aculo.us slider.js v1.9.0, Thu Dec 23 16:54:48 -0500 2010
+
+// Copyright (c) 2005-2010 Marty Haught, Thomas Fuchs
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+if (!Control) var Control = { };
+
+// options:
+// axis: 'vertical', or 'horizontal' (default)
+//
+// callbacks:
+// onChange(value)
+// onSlide(value)
+Control.Slider = Class.create({
+ initialize: function(handle, track, options) {
+ var slider = this;
+
+ if (Object.isArray(handle)) {
+ this.handles = handle.collect( function(e) { return $(e) });
+ } else {
+ this.handles = [$(handle)];
+ }
+
+ this.track = $(track);
+ this.options = options || { };
+
+ this.axis = this.options.axis || 'horizontal';
+ this.increment = this.options.increment || 1;
+ this.step = parseInt(this.options.step || '1');
+ this.range = this.options.range || $R(0,1);
+
+ this.value = 0; // assure backwards compat
+ this.values = this.handles.map( function() { return 0 });
+ this.spans = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
+ this.options.startSpan = $(this.options.startSpan || null);
+ this.options.endSpan = $(this.options.endSpan || null);
+
+ this.restricted = this.options.restricted || false;
+
+ this.maximum = this.options.maximum || this.range.end;
+ this.minimum = this.options.minimum || this.range.start;
+
+ // Will be used to align the handle onto the track, if necessary
+ this.alignX = parseInt(this.options.alignX || '0');
+ this.alignY = parseInt(this.options.alignY || '0');
+
+ this.trackLength = this.maximumOffset() - this.minimumOffset();
+
+ this.handleLength = this.isVertical() ?
+ (this.handles[0].offsetHeight != 0 ?
+ this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) :
+ (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth :
+ this.handles[0].style.width.replace(/px$/,""));
+
+ this.active = false;
+ this.dragging = false;
+ this.disabled = false;
+
+ if (this.options.disabled) this.setDisabled();
+
+ // Allowed values array
+ this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
+ if (this.allowedValues) {
+ this.minimum = this.allowedValues.min();
+ this.maximum = this.allowedValues.max();
+ }
+
+ this.eventMouseDown = this.startDrag.bindAsEventListener(this);
+ this.eventMouseUp = this.endDrag.bindAsEventListener(this);
+ this.eventMouseMove = this.update.bindAsEventListener(this);
+
+ // Initialize handles in reverse (make sure first handle is active)
+ this.handles.each( function(h,i) {
+ i = slider.handles.length-1-i;
+ slider.setValue(parseFloat(
+ (Object.isArray(slider.options.sliderValue) ?
+ slider.options.sliderValue[i] : slider.options.sliderValue) ||
+ slider.range.start), i);
+ h.makePositioned().observe("mousedown", slider.eventMouseDown);
+ });
+
+ this.track.observe("mousedown", this.eventMouseDown);
+ document.observe("mouseup", this.eventMouseUp);
+ document.observe("mousemove", this.eventMouseMove);
+
+ this.initialized = true;
+ },
+ dispose: function() {
+ var slider = this;
+ Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
+ Event.stopObserving(document, "mouseup", this.eventMouseUp);
+ Event.stopObserving(document, "mousemove", this.eventMouseMove);
+ this.handles.each( function(h) {
+ Event.stopObserving(h, "mousedown", slider.eventMouseDown);
+ });
+ },
+ setDisabled: function(){
+ this.disabled = true;
+ },
+ setEnabled: function(){
+ this.disabled = false;
+ },
+ getNearestValue: function(value){
+ if (this.allowedValues){
+ if (value >= this.allowedValues.max()) return(this.allowedValues.max());
+ if (value <= this.allowedValues.min()) return(this.allowedValues.min());
+
+ var offset = Math.abs(this.allowedValues[0] - value);
+ var newValue = this.allowedValues[0];
+ this.allowedValues.each( function(v) {
+ var currentOffset = Math.abs(v - value);
+ if (currentOffset <= offset){
+ newValue = v;
+ offset = currentOffset;
+ }
+ });
+ return newValue;
+ }
+ if (value > this.range.end) return this.range.end;
+ if (value < this.range.start) return this.range.start;
+ return value;
+ },
+ setValue: function(sliderValue, handleIdx){
+ if (!this.active) {
+ this.activeHandleIdx = handleIdx || 0;
+ this.activeHandle = this.handles[this.activeHandleIdx];
+ this.updateStyles();
+ }
+ handleIdx = handleIdx || this.activeHandleIdx || 0;
+ if (this.initialized && this.restricted) {
+ if ((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
+ sliderValue = this.values[handleIdx-1];
+ if ((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
+ sliderValue = this.values[handleIdx+1];
+ }
+ sliderValue = this.getNearestValue(sliderValue);
+ this.values[handleIdx] = sliderValue;
+ this.value = this.values[0]; // assure backwards compat
+
+ this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] =
+ this.translateToPx(sliderValue);
+
+ this.drawSpans();
+ if (!this.dragging || !this.event) this.updateFinished();
+ },
+ setValueBy: function(delta, handleIdx) {
+ this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta,
+ handleIdx || this.activeHandleIdx || 0);
+ },
+ translateToPx: function(value) {
+ return Math.round(
+ ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) *
+ (value - this.range.start)) + "px";
+ },
+ translateToValue: function(offset) {
+ return ((offset/(this.trackLength-this.handleLength) *
+ (this.range.end-this.range.start)) + this.range.start);
+ },
+ getRange: function(range) {
+ var v = this.values.sortBy(Prototype.K);
+ range = range || 0;
+ return $R(v[range],v[range+1]);
+ },
+ minimumOffset: function(){
+ return(this.isVertical() ? this.alignY : this.alignX);
+ },
+ maximumOffset: function(){
+ return(this.isVertical() ?
+ (this.track.offsetHeight != 0 ? this.track.offsetHeight :
+ this.track.style.height.replace(/px$/,"")) - this.alignY :
+ (this.track.offsetWidth != 0 ? this.track.offsetWidth :
+ this.track.style.width.replace(/px$/,"")) - this.alignX);
+ },
+ isVertical: function(){
+ return (this.axis == 'vertical');
+ },
+ drawSpans: function() {
+ var slider = this;
+ if (this.spans)
+ $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
+ if (this.options.startSpan)
+ this.setSpan(this.options.startSpan,
+ $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
+ if (this.options.endSpan)
+ this.setSpan(this.options.endSpan,
+ $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
+ },
+ setSpan: function(span, range) {
+ if (this.isVertical()) {
+ span.style.top = this.translateToPx(range.start);
+ span.style.height = this.translateToPx(range.end - range.start + this.range.start);
+ } else {
+ span.style.left = this.translateToPx(range.start);
+ span.style.width = this.translateToPx(range.end - range.start + this.range.start);
+ }
+ },
+ updateStyles: function() {
+ this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
+ Element.addClassName(this.activeHandle, 'selected');
+ },
+ startDrag: function(event) {
+ if (Event.isLeftClick(event)) {
+ if (!this.disabled){
+ this.active = true;
+
+ var handle = Event.element(event);
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var track = handle;
+ if (track==this.track) {
+ var offsets = this.track.cumulativeOffset();
+ this.event = event;
+ this.setValue(this.translateToValue(
+ (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
+ ));
+ var offsets = this.activeHandle.cumulativeOffset();
+ this.offsetX = (pointer[0] - offsets[0]);
+ this.offsetY = (pointer[1] - offsets[1]);
+ } else {
+ // find the handle (prevents issues with Safari)
+ while((this.handles.indexOf(handle) == -1) && handle.parentNode)
+ handle = handle.parentNode;
+
+ if (this.handles.indexOf(handle)!=-1) {
+ this.activeHandle = handle;
+ this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
+ this.updateStyles();
+
+ var offsets = this.activeHandle.cumulativeOffset();
+ this.offsetX = (pointer[0] - offsets[0]);
+ this.offsetY = (pointer[1] - offsets[1]);
+ }
+ }
+ }
+ Event.stop(event);
+ }
+ },
+ update: function(event) {
+ if (this.active) {
+ if (!this.dragging) this.dragging = true;
+ this.draw(event);
+ if (Prototype.Browser.WebKit) window.scrollBy(0,0);
+ Event.stop(event);
+ }
+ },
+ draw: function(event) {
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ var offsets = this.track.cumulativeOffset();
+ pointer[0] -= this.offsetX + offsets[0];
+ pointer[1] -= this.offsetY + offsets[1];
+ this.event = event;
+ this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
+ if (this.initialized && this.options.onSlide)
+ this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
+ },
+ endDrag: function(event) {
+ if (this.active && this.dragging) {
+ this.finishDrag(event, true);
+ Event.stop(event);
+ }
+ this.active = false;
+ this.dragging = false;
+ },
+ finishDrag: function(event, success) {
+ this.active = false;
+ this.dragging = false;
+ this.updateFinished();
+ },
+ updateFinished: function() {
+ if (this.initialized && this.options.onChange)
+ this.options.onChange(this.values.length>1 ? this.values : this.value, this);
+ this.event = null;
+ }
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/sound.js b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/sound.js
new file mode 100644
index 0000000..d3f8464
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/scriptaculous-1.9.0/sound.js
@@ -0,0 +1,59 @@
+// script.aculo.us sound.js v1.9.0, Thu Dec 23 16:54:48 -0500 2010
+
+// Copyright (c) 2005-2010 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// Based on code created by Jules Gravinese (http://www.webveteran.com/)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+Sound = {
+ tracks: {},
+ _enabled: true,
+ template:
+ new Template('<embed style="height:0" id="sound_#{track}_#{id}" src="#{url}" loop="false" autostart="true" hidden="true"/>'),
+ enable: function(){
+ Sound._enabled = true;
+ },
+ disable: function(){
+ Sound._enabled = false;
+ },
+ play: function(url){
+ if(!Sound._enabled) return;
+ var options = Object.extend({
+ track: 'global', url: url, replace: false
+ }, arguments[1] || {});
+
+ if(options.replace && this.tracks[options.track]) {
+ $R(0, this.tracks[options.track].id).each(function(id){
+ var sound = $('sound_'+options.track+'_'+id);
+ sound.Stop && sound.Stop();
+ sound.remove();
+ });
+ this.tracks[options.track] = null;
+ }
+
+ if(!this.tracks[options.track])
+ this.tracks[options.track] = { id: 0 };
+ else
+ this.tracks[options.track].id++;
+
+ options.id = this.tracks[options.track].id;
+ $$('body')[0].insert(
+ Prototype.Browser.IE ? new Element('bgsound',{
+ id: 'sound_'+options.track+'_'+options.id,
+ src: options.url, loop: 1, autostart: true
+ }) : Sound.template.evaluate(options));
+ }
+};
+
+if(Prototype.Browser.Gecko && navigator.userAgent.indexOf("Win") > 0){
+ if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('QuickTime') != -1 }))
+ Sound.template = new Template('<object id="sound_#{track}_#{id}" width="0" height="0" type="audio/mpeg" data="#{url}"/>');
+ else if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('Windows Media') != -1 }))
+ Sound.template = new Template('<object id="sound_#{track}_#{id}" type="application/x-mplayer2" data="#{url}"></object>');
+ else if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('RealPlayer') != -1 }))
+ Sound.template = new Template('<embed type="audio/x-pn-realaudio-plugin" style="height:0" id="sound_#{track}_#{id}" src="#{url}" loop="false" autostart="true" hidden="true"/>');
+ else
+ Sound.play = function(){};
+} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/changelog.txt b/lib/prado/framework/Web/Javascripts/source/tinymce-405/changelog.txt
new file mode 100755
index 0000000..f7a6c7c
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/changelog.txt
@@ -0,0 +1,213 @@
+Version 4.0.5 (2013-08-27)
+ Added visuals for UL, LI and BR to visualblocks plugin. Patch contributed by Dan Ransom.
+ Added new autosave_restore_when_empty option to autosave plugin. Enabled by default.
+ Fixed bug where an exception was thrown when inserting images if valid_elements didn't include an ID for the image.
+ Fixed bug where the advlist plugin wouldn't properly render the splitbutton controls.
+ Fixed bug where visual blocks menu item wouldn't be marked checked when using the visualblocks_default_state option.
+ Fixed bug where save button in save plugin wouldn't get properly enabled when contents was changed.
+ Fixed bug where it was possible to insert images without any value for it's source attribute.
+ Fixed bug where altering image attributes wouldn't add a new undo level.
+ Fixed bug where import rules in CSS files wouldn't be properly imported by the importcss plugin.
+ Fixed bug where selectors could be imported multiple times. Producing duplicate formats.
+ Fixed bug where IE would throw exception if selection was changed while the editor was hidden.
+ Fixed so complex rules like .class:before doesn't get imported by default in the importcss plugin.
+ Fixed so it's possible to remove images by setting the src attribute to a blank value.
+ Fixed so the save_enablewhendirty setting in the save plugin is enabled by default.
+ Fixed so block formats drop down for classic mode can be translated properly using language packs.
+ Fixed so hr menu item and toolbar button gets the same translation string.
+ Fixed so bullet list toolbar button gets the correct translation from language packs.
+ Fixed issue with Chrome logging CSS warning about border styling for combo boxes.
+ Fixed issue with Chrome logging warnings about deprecated keyLocation property.
+ Fixed issue where custom_elements would not remove the some of the default rules when cloning rules from div and span.
+Version 4.0.4 (2013-08-21)
+ Added new importcss plugin. Lets you auto import classes from CSS files similar to the 3.x behavior.
+ Fixed bug where resize handles would be positioned incorrectly when inline element parent was using position: relative.
+ Fixed bug where IE 8 would throw Unknown runtime error if the editor was placed within a P tag.
+ Fixed bug where removing empty lists wouldn't produce blocks or brs where the old list was in the DOM.
+ Fixed bug where IE 10 wouldn't properly initialize template dialog due to async loading issues.
+ Fixed bug where autosave wouldn't properly display the warning about content not being saved due to isDirty changes.
+ Fixed bug where it wouldn't be possible to type if a touchstart event was bound to the parent document.
+ Fixed bug where code dialog in code plugin wouldn't wouldn't add a proper undo level.
+ Fixed issue where resizing the editor in vertical mode would set the iframe width to a pixel value.
+ Fixed issue with naming of insertdatetime settings. All are now prefixed with the plugin name.
+ Fixed so an initial change event is fired when the user types the first character into the editor.
+ Fixed so swf gets mapped to object element in media plugin. Enables embedding of flash with alternative poster.
+Version 4.0.3 (2013-08-08)
+ Added new code_dialog_width/code_dialog_height options to control code dialog size.
+ Added missing pastetext button that works the same way as the pastetext menu item.
+ Added missing smaller browse button for the classical smaller toolbars.
+ Fixed bug where input method would produce new lines when inserting contents to an empty editor.
+ Fixed bug where pasting single indented list items from Word would cause a JS exception.
+ Fixed bug where applying block formats inside list elements in inline mode would apply them to whole document.
+ Fixed bug where link editing in inline mode would cause exception on IE/WebKit.
+ Fixed bug where IE 10 wouldn't render the last button group properly in inline mode due to wrapping.
+ Fixed bug where localStorage initialization would fail on Firefox/Chrome with disabled support.
+ Fixed bug where image elements would get an __mce id when undo/redo:ing to a level with image changes.
+ Fixed bug where too long template names wouldn't fit the listbox in template plugin.
+ Fixed bug where alignment format options would be marked disabled when forced_root_block was set to false.
+ Fixed bug where UI listboxes such as fontsize, fontfamily wouldn't update properly when switching editors in inline mode.
+ Fixed bug where the formats select box would mark the editable container DIV as a applied format in inline mode.
+ Fixed bug where IE 7/8 would scroll to empty editors when initialized.
+ Fixed bug where IE 7/8 wouldn't display previews of format options.
+ Fixed bug where UI states wasn't properly updated after code was changed in the code dialog.
+ Fixed bug with setting contents in IE would select all contents within the editor.
+ Fixed so the undoManages transact function disables any other undo levels from being added while within the transaction.
+ Fixed so sub/sup elements gets removed when the Clear formatting action is executed.
+ Fixed so text/javascript type value get removed by default from script elements to match the HTML5 spec.
+Version 4.0.2 (2013-07-18)
+ Fixed bug where formatting using menus or toolbars wasn't possible on Opera 12.15.
+ Fixed bug where IE 8 keyboard input would break after paste using the paste plugin.
+ Fixed bug where IE 8 would throw an error when populating image size in image dialog.
+ Fixed bug where image resizing wouldn't work properly on latest IE 10.0.9 version.
+ Fixed bug where focus wasn't moved to the hovered menu button in a menubar container.
+ Fixed bug where paste would produce an extra uneeded undo level on IE and Gecko.
+ Fixed so anchors gets listed in the link dialog as they where in TinyMCE 3.x.
+ Fixed so sub, sup and strike though gets passed through when pasting from Word.
+ Fixed so Ctrl+P can be used to print the current document. Patch contributed by jashua212.
+Version 4.0.1 (2013-06-26)
+ Added new paste_as_text config option to force paste as plaintext mode.
+ Added new pastetext menu item that lets you toggle paste as plain text mode on/off.
+ Added new insertdatetime_element option to insertdatetime plugin. Enables HTML5 time element support.
+ Added new spellchecker_wordchar_pattern option to allow configuration of language specific characters.
+ Added new marker to formats menu displaying the formats used at the current selection/caret location.
+ Fixed bug where the position of the text color picker would be wrong if you switched to fullscreen.
+ Fixed bug where the link plugin would ask to add the mailto: prefix multiple times.
+ Fixed bug where list outdent operation could produce empty list elements on specific selections.
+ Fixed bug where element path wouldn't properly select parent elements on IE.
+ Fixed bug where IE would sometimes throw an exception when extrancting the current selection range.
+ Fixed bug where line feeds wasn't properly rendered in source view on IE.
+ Fixed bug where word count wouldn't be properly rendered on IE 7.
+ Fixed bug where menubuttons/listboxes would have an incorrect height on IE 7.
+ Fixed bug where browser spellchecking was enabled while editing inline on IE 10.
+ Fixed bug where spellchecker wouldn't properly find non English words.
+ Fixed bug where deactivating inline editor instances would force padding-top: 0 on page body.
+ Fixed bug where jQuery would initialize editors multiple times since it didn't check if the editor already existed.
+ Fixed bug where it wasn't possible to paste contents on IE 10 in modern UI mode when paste filtering was enabled.
+ Fixed bug where tabfocus plugin wouldn't work properly on inline editor instances.
+ Fixed bug where fullpage plugin would clear the existing HTML head if contents where inserted into the editor.
+ Fixed bug where deleting all table rows/columns in a table would cause an exception to be thrown on IE.
+ Fixed so color button panels gets toggled on/off when activated/deactivated.
+ Fixed so format menu items that can't be applied to the current selection gets disabled.
+ Fixed so the icon parameter for addButton isn't automatically filled if a button text is provided.
+ Fixed so image size fields gets updated when selecting a new image in the image dialog.
+ Fixed so it doesn't load any language pack if the language option is set to "en".
+ Fixed so ctrl+shift+z works as an alternative redo shortcut to match a common Mac OS X shortcut.
+ Fixed so it's not possible to drag/drop in images in Gecko by default when paste plugin is enabled.
+ Fixed so format menu item texts gets translated using the specified language pack.
+ Fixed so the image dialog title is the same as the insert/edit image button text.
+ Fixed so paste as plain text produces BR:s in PRE block and when forced_root_block is disabled.
+Version 4.0 (2013-06-13)
+ Added new insertdate_dateformat, insertdate_timeformat and insertdate_formats options to insertdatetime.
+ Added new font_formats, fontsize_formats and block_formats options to configure fontselect, fontsizeselect and formatselect.
+ Added new table_clone_elements option to table plugin. Enables you to specify what elements to clone when adding columns/rows.
+ Added new auto detect logic for site and email urls in link plugin to match the logic found in 3.x.
+ Added new getParams/setParams to WindowManager to make it easier to handle params to iframe based dialogs. Contributed by Ryan Demmer.
+ Added new textcolor options that enables you to specify the colors you want to display. Contributed by Jennifer Arsenault.
+ Added new external file support for link_list and image_list options. The file format is a simple JSON file.
+ Added new "both" mode for the resize option. Enables resizing in both width and height.
+ Added new paste_data_images option that allows you to enable/disable paste of data images.
+ Added new fixed_toolbar_container option that allows you to add a fixed container for the inline toolbar.
+ Fixed so font name, font size and block format select boxes gets updated with the current format.
+ Fixed so the resizeTo/resizeBy methods for the theme are exposed as it as in 3.x.
+ Fixed so the textcolor controls are splitbuttons as in 3.x. Patch contributed by toxalot/jashua212.
+ Fixed bug where the theme content css wasn't loaded into the preview dialog.
+ Fixed bug where the template description in template dialog wouldn't display the text correctly.
+ Fixed bug where various UI elements wasn't properly removed when an editor instance was removed.
+ Fixed bug where editing links in inline mode would fail on WebKit.
+ Fixed bug where the pagebreak_separator option in the pagebreak plugin wasn't working properly.
+ Fixed bug where the child panels of the float panel in inline mode wasn't properly placed.
+ Fixed bug where the float panel children of windows wasn't position fixed.
+ Fixed bug where the size of the ok button was hardcoded, caused issues with i18n.
+ Fixed bug where single comment in editor would cause exceptions due to resolve path logic not detecting elements only.
+ Fixed bug where switching alignment of tables in dialogs wouldn't properly remove existing alignments.
+ Fixed bug where the table properties dialog would show columns/rows textboxes.
+ Fixed bug where jQuery wasn't used instead of Sizzle in the jQuery version of TinyMCE.
+ Fixed bug where setting resize option to false whouldn't properly render the word count.
+ Fixed bug where table row type change would produce multiple table section elements.
+ Fixed bug where table row type change on multiple rows would add them in incorrect order.
+ Fixed bug where fullscreen plugin would maximize the editor on resize after toggling it off.
+ Fixed bug where context menu would be position at an incorrect coordinate in inline mode.
+ Fixed bug where inserting lists in inline mode on IE would produce errors since the body would be converted.
+ Fixed bug where the body couldn't be styled properly in custom content_css files.
+ Fixed bug where template plugins menu item would override the image menu item.
+ Fixed bug where IE 7-8 would render the text inside inputs at the wrong vertical location.
+ Fixed bug where IE configured to IE 7 compatibility mode wouldn't render the icons properly.
+ Fixed bug where editor.focus wouldn't properly fire the focusin event on WebKit.
+ Fixed bug where some keyboard shortcuts wouldn't work on IE 8.
+ Fixed bug where the undo state wasn't updated until the end of a typing level.
+ Fixed bug where keyboard shortcuts on Mac OS wasn't working correctly.
+ Fixed bug where empty inline elements would be created when toggling formatting of in empty block.
+ Fixed bug where applying styles on WebKit would fail in inline mode if the user released the mouse button outside the body.
+ Fixed bug where the visual aids menu item wasn't selected if the editor was empty.
+ Fixed so the isDirty/isNotDirty states gets updated to true/false on save() and change events.
+ Fixed so skins have separate CSS files for inline and iframe mode.
+ Fixed so menus and tool tips gets constrained to the current viewport.
+ Fixed so an error is thrown if users load jQuery after the jQuery version of TinyMCE.
+ Fixed so the filetype for media dialog passes out media instead of image as file type.
+ Fixed so it's possible to disable the toolbar by setting it to false.
+ Fixed so autoresize plugin isn't initialized when the editor is in inline mode.
+ Fixed so the inline editing toolbar will be rendered below elements if it doesn't fit above it.
+Version 4.0b3 (2013-05-15)
+ Added new optional advanced tab for image dialog with hspace, vspace, border and style.
+ Added new change event that gets fired when undo levels are added to editor instances.
+ Added new removed_menuitems option enables you to list menu items to remove from menus.
+ Added new external_plugins option enables you to specify external locations for plugins.
+ Added new language_url option enables you to specify an external location for the language pack.
+ Added new table toolbar control that displays a menu for inserting/editing menus.
+ Fixed bug where IE 10 wouldn't load files properly from cache.
+ Fixed bug where image dialog wouldn't properly remove width/height if blanked.
+ Fixed bug where all events wasn't properly unbound when editor instances where removed.
+ Fixed bug where data- attributes wasn't working properly in the SaxParser.
+ Fixed bug where Gecko wouldn't properly render broken images.
+ Fixed bug where Gecko wouldn't produce the same error dialog on paste as other browsers.
+ Fixed bug where is wasn't possible to prevent execCommands in beforeExecCommand event.
+ Fixed bug where the fullpage_hide_in_source_view option wasn't working in the fullpage plugin.
+ Fixed bug where the WindowManager close method wouldn't properly close the top most window.
+ Fixed bug where it wasn't possible to paste in IE 10 due to JS exception.
+ Fixed bug where tab key didn't move to the right child control in tabpanels.
+ Fixed bug where enter inside a form would focus the first button like control in TinyMCE.
+ Fixed bug where it would match scripts that looked like the tinymce base directory incorrectly.
+ Fixed bug where the spellchecker wouldn't properly toggle off the spellcheck mode if no errors where found.
+ Fixed bug in searchreplace plugin where it would remove all spans instead of the marker spans.
+ Fixed issue where selector wouldn't disable existing mode setting.
+ Fixed so it's easier to configure the menu and menubar.
+ Fixed so bodyId/bodyClass is applied to preview as it's done to the editor iframe.
+Version 4.0b2 (2013-04-24)
+ Added new rel_list option to link plugin. Enables you to specify values for a rel drop down.
+ Added new target_list option to link plugin. Enables you to add to or disable the link targets.
+ Added new link_list option to link plugin. Enables you to specify a list of links to pick from.
+ Added new image_list option to image pluigin. Enables you to specify a list of images to pick from.
+ Added new textcolor plugin. This plugin holds the text color and text background color buttons.
+ Fixed bug where alignment of images wasn't working properly on Firefox.
+ Fixed bug where IE 8 would throw error when inserting a table.
+ Fixed bug where IE 8 wouldn't render the element path properly.
+ Fixed bug where old IE versions would render a red focus border.
+ Fixed bug where old IE versions would render a frameborder for iframes.
+ Fixed bug where WebKit wouldn't properly open the cell properties dialog on edge case selection.
+ Fixed bug where charmap wouldn't correctly render all characters in grid.
+ Fixed bug where link dialog wouldn't update the link text properly.
+ Fixed bug where the focus/blur states on inline editors wasn't handled correctly on IE.
+ Fixed bug where IE would throw "unknown error" exception sometimes in ForceBlocks logic.
+ Fixed bug where IE would't properly render disabled buttons in button groups.
+ Fixed bug where tab key wouldn't properly move to next input field in dialogs.
+ Fixed bug where resize handles for tables and images would appear at wrong positions on IE 8.
+ Fixed bug where dialogs would produce stack overflow if title was wider than content.
+ Fixed bug with table cell/row menu items being enabled even if no cell was selected.
+ Fixed so the text to display is after the URL field in the link dialog.
+ Fixed so the width setting applies to the editor panel in modern theme.
+ Fixed so it's easier to make custom icons for buttons using plain old images.
+Version 4.0b1 (2013-04-11)
+ Added new node.js based build process used uglify, amdlc, jake etc.
+ Added new package.json to enable easy installation of dependent npm packages used for building.
+ Added new link, image, charmap, anchor, code, hr plugins since these are now moved out of the theme.
+ Rewrote all plugins and themes from scratch so they match the new UI framework.
+ Replaced all events to use the more common <target>.on/off(<event>) methods instead of <target>.<event>.add/remove.
+ Rewrote the TinyMCE core to use AMD style modules. Gets compiled to an inline library using amdlc.
+ Rewrote all core logic to pass jshint rules. Each file has specific jshint rules.
+ Removed all IE6 specific logic since 4.x will no longer support such an old browser.
+ Reworked the file names and directory structure of the whole project to be more similar to other JS projects.
+ Replaced tinymce.util.Cookie with tinymce.util.LocalStorage. Fallback to userData for IE 7 native localStorage for the rest.
+ Replaced the old 3.x UI with a new modern UI framework.
+ Removed "simple" theme and added new "modern" theme.
+ Removed advhr, advimage, advlink, iespell, inlinepopups, xhtmlxtras and style plugins.
+ Updated Sizzle to the latest version.
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ar.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ar.js
new file mode 100755
index 0000000..5a60b65
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ar.js
@@ -0,0 +1,156 @@
+tinymce.addI18n('ar',{
+"Cut": "\u0642\u0635",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u0645\u062a\u0635\u0641\u062d\u0643 \u0644\u0627 \u064a\u062f\u0639\u0645 \u0627\u0644\u0648\u0635\u0648\u0644 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u0625\u0644\u0649 \u0627\u0644\u062d\u0627\u0641\u0638\u0629. \u0627\u0644\u0631\u062c\u0627\u0621 \u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0627\u062e\u062a\u0635\u0627\u0631\u0627\u062a \u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d Ctrl+X\/C\/V \u0628\u062f\u0644\u0627 \u0645\u0646 \u0630\u0644\u0643.",
+"Paste": "\u0644\u0635\u0642",
+"Close": "\u0625\u063a\u0644\u0627\u0642",
+"Align right": "\u0645\u062d\u0627\u0630\u0627\u0629 \u0627\u0644\u0646\u0635 \u0644\u0644\u064a\u0645\u064a\u0646",
+"New document": "\u0645\u0633\u062a\u0646\u062f \u062c\u062f\u064a\u062f",
+"Numbered list": "\u062a\u0631\u0642\u064a\u0645",
+"Increase indent": "\u0632\u064a\u0627\u062f\u0629 \u0627\u0644\u0645\u0633\u0627\u0641\u0629 \u0627\u0644\u0628\u0627\u062f\u0626\u0629",
+"Formats": "\u0627\u0644\u062a\u0646\u0633\u064a\u0642\u0627\u062a",
+"Select all": "\u062a\u062d\u062f\u064a\u062f \u0627\u0644\u0643\u0644",
+"Undo": "\u062a\u0631\u0627\u062c\u0639",
+"Strikethrough": "\u064a\u062a\u0648\u0633\u0637 \u062e\u0637",
+"Bullet list": "\u062a\u0639\u062f\u0627\u062f \u0646\u0642\u0637\u064a",
+"Superscript": "\u0645\u0631\u062a\u0641\u0639",
+"Clear formatting": "\u0645\u0633\u062d \u0627\u0644\u062a\u0646\u0633\u064a\u0642",
+"Subscript": "\u0645\u0646\u062e\u0641\u0636",
+"Redo": "\u0625\u0639\u0627\u062f\u0629",
+"Ok": "\u0645\u0648\u0627\u0641\u0642",
+"Bold": "\u063a\u0627\u0645\u0642",
+"Italic": "\u0645\u0627\u0626\u0644",
+"Align center": "\u062a\u0648\u0633\u064a\u0637",
+"Decrease indent": "\u0625\u0646\u0642\u0627\u0635 \u0627\u0644\u0645\u0633\u0627\u0641\u0629 \u0627\u0644\u0628\u0627\u062f\u0626\u0629",
+"Underline": "\u062a\u0633\u0637\u064a\u0631",
+"Cancel": "\u0625\u0644\u063a\u0627\u0621",
+"Justify": "\u0636\u0628\u0637",
+"Copy": "\u0646\u0633\u062e",
+"Align left": "\u0645\u062d\u0627\u0630\u0627\u0629 \u0627\u0644\u0646\u0635 \u0644\u0644\u064a\u0633\u0627\u0631",
+"Visual aids": "\u0627\u0644\u0645\u0639\u064a\u0646\u0627\u062a \u0627\u0644\u0628\u0635\u0631\u064a\u0629",
+"Lower Greek": "\u062a\u0631\u0642\u064a\u0645 \u064a\u0648\u0646\u0627\u0646\u064a \u0635\u063a\u064a\u0631",
+"Square": "\u0645\u0631\u0628\u0639",
+"Default": "\u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a",
+"Lower Alpha": "\u062a\u0631\u0642\u064a\u0645 \u0623\u062e\u0631\u0641 \u0635\u063a\u064a\u0631\u0629",
+"Circle": "\u062f\u0627\u0626\u0631\u0629",
+"Disc": "\u0642\u0631\u0635",
+"Upper Alpha": "\u062a\u0631\u0642\u064a\u0645 \u0623\u062d\u0631\u0641 \u0643\u0628\u064a\u0631\u0629",
+"Upper Roman": "\u062a\u0631\u0642\u064a\u0645 \u0631\u0648\u0645\u0627\u0646\u064a \u0643\u0628\u064a\u0631",
+"Lower Roman": "\u062a\u0631\u0642\u064a\u0645 \u0631\u0648\u0645\u0627\u0646\u064a \u0635\u063a\u064a\u0631",
+"Name": "\u0627\u0644\u0627\u0633\u0645",
+"Anchor": "\u0645\u0631\u0633\u0627\u0629",
+"You have unsaved changes are you sure you want to navigate away?": "\u0644\u062f\u064a\u0643 \u062a\u063a\u064a\u064a\u0631\u0627\u062a \u0644\u0645 \u064a\u062a\u0645 \u062d\u0641\u0638\u0647\u0627 \u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0641\u064a \u0627\u0644\u0627\u0646\u062a\u0642\u0627\u0644 \u0628\u0639\u064a\u062f\u0627\u061f",
+"Restore last draft": "\u0627\u0633\u062a\u0639\u0627\u062f\u0629 \u0623\u062e\u0631 \u0645\u0633\u0648\u062f\u0629",
+"Special character": "\u0631\u0645\u0632",
+"Source code": "\u0634\u0641\u0631\u0629 \u0627\u0644\u0645\u0635\u062f\u0631",
+"Right to left": "\u0645\u0646 \u0627\u0644\u064a\u0645\u064a\u0646 \u0644\u0644\u064a\u0633\u0627\u0631",
+"Left to right": "\u0645\u0646 \u0627\u0644\u064a\u0633\u0627\u0631 \u0644\u0644\u064a\u0645\u064a\u0646",
+"Emoticons": "\u0627\u0644\u0631\u0645\u0648\u0632",
+"Robots": "\u0627\u0644\u0631\u0648\u0628\u0648\u062a\u0627\u062a",
+"Document properties": "\u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u0645\u0633\u062a\u0646\u062f",
+"Title": "\u0627\u0644\u0639\u0646\u0648\u0627\u0646",
+"Keywords": "\u0643\u0644\u0645\u0627\u062a \u0627\u0644\u0628\u062d\u062b",
+"Encoding": "\u0627\u0644\u062a\u0631\u0645\u064a\u0632",
+"Description": "\u0627\u0644\u0648\u0635\u0641",
+"Author": "\u0627\u0644\u0643\u0627\u062a\u0628",
+"Fullscreen": "\u0645\u0644\u0621 \u0627\u0644\u0634\u0627\u0634\u0629",
+"Horizontal line": "\u062e\u0637 \u0623\u0641\u0642\u064a",
+"Horizontal space": "\u0645\u0633\u0627\u0641\u0629 \u0623\u0641\u0642\u064a\u0629",
+"Insert\/edit image": "\u0625\u062f\u0631\u0627\u062c\/\u062a\u062d\u0631\u064a\u0631 \u0635\u0648\u0631\u0629",
+"General": "\u0639\u0627\u0645",
+"Advanced": "\u062e\u0635\u0627\u0626\u0635 \u0645\u062a\u0642\u062f\u0645\u0647",
+"Source": "\u0627\u0644\u0645\u0635\u062f\u0631",
+"Border": "\u062d\u062f\u0648\u062f",
+"Constrain proportions": "\u0627\u0644\u062a\u0646\u0627\u0633\u0628",
+"Vertical space": "\u0645\u0633\u0627\u0641\u0629 \u0639\u0645\u0648\u062f\u064a\u0629",
+"Image description": "\u0648\u0635\u0641 \u0627\u0644\u0635\u0648\u0631\u0629",
+"Style": "\u0627\u0644\u0646\u0645\u0637 \/ \u0627\u0644\u0634\u0643\u0644",
+"Dimensions": "\u0627\u0644\u0623\u0628\u0639\u0627\u062f",
+"Insert date\/time": "\u0625\u062f\u0631\u0627\u062c \u062a\u0627\u0631\u064a\u062e\/\u0648\u0642\u062a",
+"Url": "\u0627\u0644\u0639\u0646\u0648\u0627\u0646",
+"Text to display": "\u0627\u0644\u0646\u0635 \u0627\u0644\u0645\u0637\u0644\u0648\u0628 \u0639\u0631\u0636\u0647",
+"Insert link": "\u0625\u062f\u0631\u0627\u062c \u0631\u0627\u0628\u0637",
+"New window": "\u0646\u0627\u0641\u0630\u0629 \u062c\u062f\u064a\u062f\u0629",
+"None": "\u0628\u0644\u0627",
+"Target": "\u0627\u0644\u0625\u0637\u0627\u0631 \u0627\u0644\u0647\u062f\u0641",
+"Insert\/edit link": "\u0625\u062f\u0631\u0627\u062c\/\u062a\u062d\u0631\u064a\u0631 \u0631\u0627\u0628\u0637",
+"Insert\/edit video": "\u0625\u062f\u0631\u0627\u062c\/\u062a\u062d\u0631\u064a\u0631 \u0641\u064a\u062f\u064a\u0648",
+"Poster": "\u0645\u0644\u0635\u0642",
+"Alternative source": "\u0645\u0635\u062f\u0631 \u0628\u062f\u064a\u0644",
+"Paste your embed code below:": "\u0644\u0635\u0642 \u0643\u0648\u062f \u0627\u0644\u062a\u0636\u0645\u064a\u0646 \u0647\u0646\u0627:",
+"Insert video": "\u0625\u062f\u0631\u0627\u062c \u0641\u064a\u062f\u064a\u0648",
+"Embed": "\u062a\u0636\u0645\u064a\u0646",
+"Nonbreaking space": "\u0645\u0633\u0627\u0641\u0629 \u063a\u064a\u0631 \u0645\u0646\u0642\u0633\u0645\u0629",
+"Page break": "\u0641\u0627\u0635\u0644 \u0644\u0644\u0635\u0641\u062d\u0629",
+"Preview": "\u0645\u0639\u0627\u064a\u0646\u0629",
+"Print": "\u0637\u0628\u0627\u0639\u0629",
+"Save": "\u062d\u0641\u0638",
+"Could not find the specified string.": "\u062a\u0639\u0630\u0631 \u0627\u0644\u0639\u062b\u0648\u0631 \u0639\u0644\u0649 \u0627\u0644\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u062d\u062f\u062f\u0629",
+"Replace": "\u0627\u0633\u062a\u0628\u062f\u0627\u0644",
+"Next": "\u0627\u0644\u062a\u0627\u0644\u064a",
+"Whole words": "\u0645\u0637\u0627\u0628\u0642\u0629 \u0627\u0644\u0643\u0644\u0645\u0627\u062a \u0628\u0627\u0644\u0643\u0627\u0645\u0644",
+"Find and replace": "\u0628\u062d\u062b \u0648\u0627\u0633\u062a\u0628\u062f\u0627\u0644",
+"Replace with": "\u0627\u0633\u062a\u0628\u062f\u0627\u0644 \u0628\u0640",
+"Find": "\u0628\u062d\u062b",
+"Replace all": "\u0627\u0633\u062a\u0628\u062f\u0627\u0644 \u0627\u0644\u0643\u0644",
+"Match case": "\u0645\u0637\u0627\u0628\u0642\u0629 \u062d\u0627\u0644\u0629 \u0627\u0644\u0623\u062d\u0631\u0641",
+"Prev": "\u0627\u0644\u0633\u0627\u0628\u0642",
+"Spellcheck": "\u062a\u062f\u0642\u064a\u0642 \u0625\u0645\u0644\u0627\u0626\u064a",
+"Finish": "\u0627\u0646\u062a\u0647\u064a",
+"Ignore all": "\u062a\u062c\u0627\u0647\u0644 \u0627\u0644\u0643\u0644",
+"Ignore": "\u062a\u062c\u0627\u0647\u0644",
+"Insert row before": "\u0625\u062f\u0631\u0627\u062c \u0635\u0641 \u0644\u0644\u0623\u0639\u0644\u0649",
+"Rows": "\u0639\u062f\u062f \u0627\u0644\u0635\u0641\u0648\u0641",
+"Height": "\u0627\u0631\u062a\u0641\u0627\u0639",
+"Paste row after": "\u0644\u0635\u0642 \u0627\u0644\u0635\u0641 \u0644\u0644\u0623\u0633\u0641\u0644",
+"Alignment": "\u0645\u062d\u0627\u0630\u0627\u0629",
+"Column group": "\u0645\u062c\u0645\u0648\u0639\u0629 \u0639\u0645\u0648\u062f",
+"Row": "\u0635\u0641",
+"Insert column before": "\u0625\u062f\u0631\u0627\u062c \u0639\u0645\u0648\u062f \u0644\u0644\u064a\u0633\u0627\u0631",
+"Split cell": "\u062a\u0642\u0633\u064a\u0645 \u0627\u0644\u062e\u0644\u0627\u064a\u0627",
+"Cell padding": "\u062a\u0628\u0627\u0639\u062f \u0627\u0644\u062e\u0644\u064a\u0629",
+"Cell spacing": "\u0627\u0644\u0645\u0633\u0627\u0641\u0629 \u0628\u064a\u0646 \u0627\u0644\u062e\u0644\u0627\u064a\u0627",
+"Row type": "\u0646\u0648\u0639 \u0627\u0644\u0635\u0641",
+"Insert table": "\u0625\u062f\u0631\u0627\u062c \u062c\u062f\u0648\u0644",
+"Body": "\u0647\u064a\u0643\u0644",
+"Caption": "\u0634\u0631\u062d",
+"Footer": "\u062a\u0630\u064a\u064a\u0644",
+"Delete row": "\u062d\u0630\u0641 \u0635\u0641",
+"Paste row before": "\u0644\u0635\u0642 \u0627\u0644\u0635\u0641 \u0644\u0644\u0623\u0639\u0644\u0649",
+"Scope": "\u0627\u0644\u0645\u062c\u0627\u0644",
+"Delete table": "\u062d\u0630\u0641 \u062c\u062f\u0648\u0644",
+"Header cell": "\u0631\u0623\u0633 \u0627\u0644\u062e\u0644\u064a\u0629",
+"Column": "\u0639\u0645\u0648\u062f",
+"Cell": "\u062e\u0644\u064a\u0629",
+"Header": "\u0627\u0644\u0631\u0623\u0633",
+"Cell type": "\u0646\u0648\u0639 \u0627\u0644\u062e\u0644\u064a\u0629",
+"Copy row": "\u0646\u0633\u062e \u0627\u0644\u0635\u0641",
+"Row properties": "\u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u0635\u0641",
+"Table properties": "\u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u062c\u062f\u0648\u0644",
+"Row group": "\u0645\u062c\u0645\u0648\u0639\u0629 \u0635\u0641",
+"Right": "\u064a\u0645\u064a\u0646",
+"Insert column after": "\u0625\u062f\u0631\u0627\u062c \u0639\u0645\u0648\u062f \u0644\u0644\u064a\u0645\u064a\u0646",
+"Cols": "\u0639\u062f\u062f \u0627\u0644\u0623\u0639\u0645\u062f\u0629",
+"Insert row after": "\u0625\u062f\u0631\u0627\u062c \u0635\u0641 \u0644\u0644\u0623\u0633\u0641\u0644",
+"Width": "\u0639\u0631\u0636",
+"Cell properties": "\u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u062e\u0644\u064a\u0629",
+"Left": "\u064a\u0633\u0627\u0631",
+"Cut row": "\u0642\u0635 \u0627\u0644\u0635\u0641",
+"Delete column": "\u062d\u0630\u0641 \u0639\u0645\u0648\u062f",
+"Center": "\u062a\u0648\u0633\u064a\u0637",
+"Merge cells": "\u062f\u0645\u062c \u062e\u0644\u0627\u064a\u0627",
+"Insert template": "\u0625\u062f\u0631\u0627\u062c \u0642\u0627\u0644\u0628",
+"Templates": "\u0642\u0648\u0627\u0644\u0628",
+"Background color": "\u0644\u0648\u0646 \u0627\u0644\u062e\u0644\u0641\u064a\u0629",
+"Text color": "\u0644\u0648\u0646 \u0627\u0644\u0646\u0635",
+"Show blocks": "\u0645\u0634\u0627\u0647\u062f\u0629 \u0627\u0644\u0643\u062a\u0644",
+"Show invisible characters": "\u0623\u0638\u0647\u0631 \u0627\u0644\u0623\u062d\u0631\u0641 \u0627\u0644\u063a\u064a\u0631 \u0645\u0631\u0626\u064a\u0629",
+"Words: {0}": "\u0627\u0644\u0643\u0644\u0645\u0627\u062a:{0}",
+"Insert": "\u0625\u062f\u0631\u0627\u062c",
+"File": "\u0645\u0644\u0641",
+"Edit": "\u062a\u062d\u0631\u064a\u0631",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u0645\u0646\u0637\u0642\u0629 \u0646\u0635 \u0645\u0646\u0633\u0642. \u0627\u0636\u063a\u0637 ALT-F9 \u0644\u0644\u0642\u0627\u0626\u0645\u0629. \u0627\u0636\u063a\u0637 ALT-F10 \u0644\u0634\u0631\u064a\u0637 \u0627\u0644\u0623\u062f\u0648\u0627\u062a. \u0627\u0636\u063a\u0637 ALT-0 \u0644\u0644\u062d\u0635\u0648\u0644 \u0639\u0644\u0649 \u0645\u0633\u0627\u0639\u062f\u0629",
+"Tools": "\u0623\u062f\u0627\u0648\u0627\u062a",
+"View": "\u0639\u0631\u0636",
+"Table": "\u062c\u062f\u0648\u0644",
+"Format": "\u062a\u0646\u0633\u064a\u0642"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/bg_BG.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/bg_BG.js
new file mode 100755
index 0000000..e1f39e9
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/bg_BG.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('bg_BG',{
+"Cut": "\u0418\u0437\u0440\u044f\u0437\u0432\u0430\u043d\u0435",
+"Header 2": "\u0417\u0430\u0433\u043b\u0430\u0432\u0438\u0435 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u0412\u0430\u0448\u0438\u044f\u0442 \u0431\u0440\u0430\u0443\u0437\u044a\u0440 \u043d\u0435 \u043f\u043e\u0434\u0434\u044a\u0440\u0436\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u0435\u043d \u0434\u043e\u0441\u0442\u044a\u043f \u0434\u043e \u043a\u043b\u0438\u043f\u0431\u043e\u0440\u0434\u0430. \u0412\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0432\u0430 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0439\u0442\u0435 \u043a\u043b\u0430\u0432\u0438\u0448\u043d\u0438\u0442\u0435 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 Ctrl+X (\u0437\u0430 \u0438\u0437\u0440\u044f\u0437\u0432\u0430\u043d\u0435), Ctrl+C (\u0437\u0430 \u043a\u043e\u043f\u0438\u0440\u0430\u043d\u0435) \u0438 Ctrl+V (\u0437\u0430 \u043f\u043e\u0441\u0442\u0430\u0432\u044f\u043d\u0435).",
+"Div": "\u0411\u043b\u043e\u043a",
+"Paste": "\u041f\u043e\u0441\u0442\u0430\u0432\u044f\u043d\u0435",
+"Close": "\u0417\u0430\u0442\u0432\u0430\u0440\u044f\u043d\u0435",
+"Pre": "\u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u043d\u043e \u043e\u0444\u043e\u0440\u043c\u0435\u043d \u0442\u0435\u043a\u0441\u0442",
+"Align right": "\u041f\u043e\u0434\u0440\u0430\u0432\u043d\u044f\u0432\u0430\u043d\u0435 \u043e\u0442\u0434\u044f\u0441\u043d\u043e",
+"New document": "\u041d\u043e\u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442",
+"Blockquote": "\u0426\u0438\u0442\u0430\u0442",
+"Numbered list": "\u041d\u043e\u043c\u0435\u0440\u0438\u0440\u0430\u043d \u0441\u043f\u0438\u0441\u044a\u043a",
+"Increase indent": "\u0423\u0432\u0435\u043b\u0438\u0447\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u043e\u0442\u0441\u0442\u044a\u043f\u0430",
+"Formats": "\u0424\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u0430\u043d\u0435",
+"Headers": "\u0417\u0430\u0433\u043b\u0430\u0432\u0438\u044f",
+"Select all": "\u041c\u0430\u0440\u043a\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0446\u044f\u043b\u043e\u0442\u043e \u0441\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435",
+"Header 3": "\u0417\u0430\u0433\u043b\u0430\u0432\u0438\u0435 3",
+"Blocks": "\u0411\u043b\u043e\u043a\u043e\u0432\u0435",
+"Undo": "\u0412\u044a\u0440\u043d\u0438",
+"Strikethrough": "\u0417\u0430\u0447\u0435\u0440\u0442\u0430\u0432\u0430\u043d\u0435",
+"Bullet list": "\u0421\u043f\u0438\u0441\u044a\u043a \u0441 \u0432\u043e\u0434\u0430\u0447\u0438",
+"Header 1": "\u0417\u0430\u0433\u043b\u0430\u0432\u0438\u0435 1",
+"Superscript": "\u0413\u043e\u0440\u0435\u043d \u0438\u043d\u0434\u0435\u043a\u0441",
+"Clear formatting": "\u0418\u0437\u0447\u0438\u0441\u0442\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u0430\u043d\u0435\u0442\u043e",
+"Subscript": "\u0414\u043e\u043b\u0435\u043d \u0438\u043d\u0434\u0435\u043a\u0441",
+"Header 6": "\u0417\u0430\u0433\u043b\u0430\u0432\u0438\u0435 6",
+"Redo": "\u041e\u0442\u043c\u0435\u043d\u0438",
+"Paragraph": "\u041f\u0430\u0440\u0430\u0433\u0440\u0430\u0444",
+"Ok": "\u0414\u043e\u0431\u0440\u0435",
+"Bold": "\u0423\u0434\u0435\u0431\u0435\u043b\u0435\u043d (\u043f\u043e\u043b\u0443\u0447\u0435\u0440)",
+"Code": "\u041a\u043e\u0434",
+"Italic": "\u041d\u0430\u043a\u043b\u043e\u043d\u0435\u043d (\u043a\u0443\u0440\u0441\u0438\u0432)",
+"Align center": "\u0426\u0435\u043d\u0442\u0440\u0438\u0440\u0430\u043d\u043e",
+"Header 5": "\u0417\u0430\u0433\u043b\u0430\u0432\u0438\u0435 5",
+"Decrease indent": "\u041d\u0430\u043c\u0430\u043b\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u043e\u0442\u0441\u0442\u044a\u043f\u0430",
+"Header 4": "\u0417\u0430\u0433\u043b\u0430\u0432\u0438\u0435 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u041f\u043e\u0441\u0442\u0430\u0432\u044f\u043d\u0435\u0442\u043e \u0432 \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0435 \u0432 \u043e\u0431\u0438\u043a\u043d\u043e\u0432\u0435\u043d \u0440\u0435\u0436\u0438\u043c. \u0421\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435\u0442\u043e \u0449\u0435 \u0431\u044a\u0434\u0435 \u043f\u043e\u0441\u0442\u0430\u0432\u0435\u043d\u043e \u043a\u0430\u0442\u043e \u043d\u0435\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u0430\u043d \u0442\u0435\u043a\u0441\u0442, \u0434\u043e\u043a\u0430\u0442\u043e \u0438\u0437\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u0442\u0430\u0437\u0438 \u043e\u043f\u0446\u0438\u044f.",
+"Underline": "\u041f\u043e\u0434\u0447\u0435\u0440\u0442\u0430\u043d",
+"Cancel": "\u041e\u0442\u043a\u0430\u0437",
+"Justify": "\u0414\u0432\u0443\u0441\u0442\u0440\u0430\u043d\u043d\u043e \u043f\u043e\u0434\u0440\u0430\u0432\u043d\u044f\u0432\u0430\u043d\u0435",
+"Inline": "\u041d\u0430 \u0435\u0434\u0438\u043d \u0440\u0435\u0434",
+"Copy": "\u041a\u043e\u043f\u0438\u0440\u0430\u043d\u0435",
+"Align left": "\u041f\u043e\u0434\u0440\u0430\u0432\u043d\u044f\u0432\u0430\u043d\u0435 \u043e\u0442\u043b\u044f\u0432\u043e",
+"Visual aids": "\u0412\u0438\u0437\u0443\u0430\u043b\u043d\u043e \u043e\u0442\u043a\u0440\u043e\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u0438 \u0431\u0435\u0437 \u043a\u0430\u043d\u0442\u043e\u0432\u0435 (\u0440\u0430\u043c\u043a\u0438)",
+"Lower Greek": "\u041c\u0430\u043b\u043a\u0438 \u0433\u0440\u044a\u0446\u043a\u0438 \u0431\u0443\u043a\u0432\u0438",
+"Square": "\u0417\u0430\u043f\u044a\u043b\u043d\u0435\u043d\u0438 \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0438",
+"Default": "\u041f\u043e \u043f\u043e\u0434\u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043d\u0435",
+"Lower Alpha": "\u041c\u0430\u043b\u043a\u0438 \u0431\u0443\u043a\u0432\u0438",
+"Circle": "\u041e\u043a\u0440\u044a\u0436\u043d\u043e\u0441\u0442\u0438",
+"Disc": "\u041a\u0440\u044a\u0433\u0447\u0435\u0442\u0430",
+"Upper Alpha": "\u0413\u043e\u043b\u0435\u043c\u0438 \u043b\u0430\u0442\u0438\u043d\u0441\u043a\u0438 \u0431\u0443\u043a\u0432\u0438",
+"Upper Roman": "\u0413\u043e\u043b\u0435\u043c\u0438 \u0440\u0438\u043c\u0441\u043a\u0438 \u0446\u0438\u0444\u0440\u0438",
+"Lower Roman": "\u041c\u0430\u043b\u043a\u0438 \u0440\u0438\u043c\u0441\u043a\u0438 \u0446\u0438\u0444\u0440\u0438",
+"Name": "\u041d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435",
+"Anchor": "\u041a\u043e\u0442\u0432\u0430 (\u0432\u0440\u044a\u0437\u043a\u0430 \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430)",
+"You have unsaved changes are you sure you want to navigate away?": "\u0412 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430 \u0438\u043c\u0430 \u043d\u0435\u0437\u0430\u043f\u0430\u0437\u0435\u043d\u0438 \u043f\u0440\u043e\u043c\u0435\u043d\u0438. \u0429\u0435 \u043f\u0440\u043e\u0434\u044a\u043b\u0436\u0438\u0442\u0435 \u043b\u0438?",
+"Restore last draft": "\u0412\u044a\u0437\u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0430\u0442\u0430 \u0447\u0435\u0440\u043d\u043e\u0432\u0430",
+"Special character": "\u0421\u043f\u0435\u0446\u0438\u0430\u043b\u0435\u043d \u0437\u043d\u0430\u043a",
+"Source code": "\u0418\u0437\u0445\u043e\u0434\u0435\u043d \u043a\u043e\u0434 \u043d\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430 \u0432 HTML",
+"Right to left": "\u041e\u0442\u0434\u044f\u0441\u043d\u043e \u043d\u0430\u043b\u044f\u0432\u043e",
+"Left to right": "\u041e\u0442\u043b\u044f\u0432\u043e \u043d\u0430\u0434\u044f\u0441\u043d\u043e",
+"Emoticons": "\u0415\u043c\u043e\u0442\u0438\u043a\u043e\u043d\u0438",
+"Robots": "\u0420\u043e\u0431\u043e\u0442\u0438 \u043d\u0430 \u0443\u0435\u0431 \u0442\u044a\u0440\u0441\u0430\u0447\u043a\u0438",
+"Document properties": "\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",
+"Title": "\u041d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435",
+"Keywords": "\u041a\u043b\u044e\u0447\u043e\u0432\u0438 \u0434\u0443\u043c\u0438",
+"Encoding": "\u041a\u043e\u0434\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0437\u043d\u0430\u0446\u0438\u0442\u0435",
+"Description": "\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435",
+"Author": "\u0410\u0432\u0442\u043e\u0440",
+"Fullscreen": "\u041d\u0430 \u0446\u044f\u043b \u0435\u043a\u0440\u0430\u043d",
+"Horizontal line": "\u0425\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u043d\u0430 \u0447\u0435\u0440\u0442\u0430",
+"Horizontal space": "\u0425\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e",
+"Insert\/edit image": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435\/\u043a\u043e\u0440\u0435\u043a\u0446\u0438\u044f \u043d\u0430 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430",
+"General": "\u041e\u0431\u0449\u043e",
+"Advanced": "\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e",
+"Source": "\u0410\u0434\u0440\u0435\u0441",
+"Border": "\u041a\u0430\u043d\u0442 (\u0440\u0430\u043c\u043a\u0430)",
+"Constrain proportions": "\u0417\u0430\u0432\u0430\u0437\u043d\u0430\u0432\u0435 \u043d\u0430 \u043f\u0440\u043e\u043f\u043e\u0440\u0446\u0438\u0438\u0442\u0435",
+"Vertical space": "\u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e",
+"Image description": "\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043d\u0430 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430\u0442\u0430",
+"Style": "\u0421\u0442\u0438\u043b",
+"Dimensions": "\u0420\u0430\u0437\u043c\u0435\u0440",
+"Insert image": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435",
+"Insert date\/time": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 \u0434\u0430\u0442\u0430\/\u0447\u0430\u0441",
+"Remove link": "\u041f\u0440\u0435\u043c\u0430\u0445\u0432\u0430\u043d\u0435 \u043d\u0430 \u0445\u0438\u043f\u0435\u0440\u0432\u0440\u044a\u0437\u043a\u0430",
+"Url": "\u0410\u0434\u0440\u0435\u0441 (URL)",
+"Text to display": "\u0422\u0435\u043a\u0441\u0442",
+"Anchors": "\u041a\u043e\u0442\u0432\u0430 (\u0432\u0440\u044a\u0437\u043a\u0430 \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430)",
+"Insert link": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 \u0445\u0438\u043f\u0435\u0440\u0432\u0440\u044a\u0437\u043a\u0430 (\u043b\u0438\u043d\u043a)",
+"New window": "\u0412 \u043d\u043e\u0432 \u043f\u0440\u043e\u0437\u043e\u0440\u0435\u0446 (\u043f\u043e\u0434\u043f\u0440\u043e\u0437\u043e\u0440\u0435\u0446)",
+"None": "\u0411\u0435\u0437",
+"Target": "\u0426\u0435\u043b \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",
+"Insert\/edit link": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435\/\u043a\u043e\u0440\u0435\u043a\u0446\u0438\u044f \u043d\u0430 \u0445\u0438\u043f\u0435\u0440\u0432\u0440\u044a\u0437\u043a\u0430 (\u043b\u0438\u043d\u043a)",
+"Insert\/edit video": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435\/\u043a\u043e\u0440\u0435\u043a\u0446\u0438\u044f \u043d\u0430 \u0432\u0438\u0434\u0435\u043e",
+"Poster": "\u041f\u043e\u0441\u0442\u0435\u0440",
+"Alternative source": "\u0410\u043b\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0435\u043d \u0430\u0434\u0440\u0435\u0441",
+"Paste your embed code below:": "\u041f\u043e\u0441\u0442\u0430\u0432\u0435\u0442\u0435 \u043a\u043e\u0434\u0430 \u0437\u0430 \u0432\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u0432 \u043f\u043e\u043b\u0435\u0442\u043e \u043f\u043e-\u0434\u043e\u043b\u0443:",
+"Insert video": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 \u0432\u0438\u0434\u0435\u043e",
+"Embed": "\u0412\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435",
+"Nonbreaking space": "\u0418\u043d\u0442\u0435\u0440\u0432\u0430\u043b",
+"Page break": "\u041d\u043e\u0432\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430",
+"Paste as text": "\u041f\u043e\u0441\u0442\u0430\u0432\u0438 \u043a\u0430\u0442\u043e \u0442\u0435\u043a\u0441\u0442",
+"Preview": "\u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u0435\u043d \u0438\u0437\u0433\u043b\u0435\u0434",
+"Print": "\u041f\u0435\u0447\u0430\u0442",
+"Save": "\u0421\u044a\u0445\u0440\u0430\u043d\u044f\u0432\u0430\u043d\u0435",
+"Could not find the specified string.": "\u0422\u044a\u0440\u0441\u0435\u043d\u0438\u044f\u0442 \u0442\u0435\u043a\u0441\u0442 \u043d\u0435 \u0435 \u043d\u0430\u043c\u0435\u0440\u0435\u043d.",
+"Replace": "\u0417\u0430\u043c\u044f\u043d\u0430",
+"Next": "\u0421\u043b\u0435\u0434\u0432\u0430\u0449",
+"Whole words": "\u0421\u0430\u043c\u043e \u0446\u0435\u043b\u0438 \u0434\u0443\u043c\u0438",
+"Find and replace": "\u0422\u044a\u0440\u0441\u0435\u043d\u0435 \u0438 \u0437\u0430\u043c\u044f\u043d\u0430",
+"Replace with": "\u0417\u0430\u043c\u044f\u043d\u0430 \u0441",
+"Find": "\u0422\u044a\u0440\u0441\u0435\u043d\u0435 \u0437\u0430",
+"Replace all": "\u0417\u0430\u043c\u044f\u043d\u0430 \u043d\u0430 \u0432\u0441\u0438\u0447\u043a\u0438 \u0441\u0440\u0435\u0449\u0430\u043d\u0438\u044f",
+"Match case": "\u0421\u044a\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0435 \u043d\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u044a\u0440\u0430 (\u043c\u0430\u043b\u043a\u0438\/\u0433\u043b\u0430\u0432\u043d\u0438 \u0431\u0443\u043a\u0432\u0438)",
+"Prev": "\u041f\u0440\u0435\u0434\u0438\u0448\u0435\u043d",
+"Spellcheck": "\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430",
+"Finish": "\u041a\u0440\u0430\u0439",
+"Ignore all": "\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0432\u0441\u0438\u0447\u043a\u043e",
+"Ignore": "\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u0430\u043d\u0435",
+"Insert row before": "\u0412\u043c\u044a\u043a\u0432\u0430\u043d\u0435 \u043d\u0430 \u0440\u0435\u0434 \u043f\u0440\u0435\u0434\u0438",
+"Rows": "\u0420\u0435\u0434\u043e\u0432\u0435",
+"Height": "\u0412\u0438\u0441\u043e\u0447\u0438\u043d\u0430",
+"Paste row after": "\u041f\u043e\u0441\u0442\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 \u0440\u0435\u0434 \u0441\u043b\u0435\u0434",
+"Alignment": "\u041f\u043e\u0434\u0440\u0430\u0432\u043d\u044f\u0432\u0430\u043d\u0435",
+"Column group": "Column group",
+"Row": "\u0420\u0435\u0434",
+"Insert column before": "\u0412\u043c\u044a\u043a\u0432\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u043b\u043e\u043d\u0430 \u043f\u0440\u0435\u0434\u0438",
+"Split cell": "\u0420\u0430\u0437\u0434\u0435\u043b\u044f\u043d\u0435 \u043d\u0430 \u043a\u043b\u0435\u0442\u043a\u0430",
+"Cell padding": "\u0420\u0430\u0437\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043e \u0441\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435\u0442\u043e",
+"Cell spacing": "\u0420\u0430\u0437\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u043a\u043b\u0435\u0442\u043a\u0438\u0442\u0435",
+"Row type": "\u0422\u0438\u043f \u043d\u0430 \u0440\u0435\u0434\u0430",
+"Insert table": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u0430",
+"Body": "\u0421\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435 (body)",
+"Caption": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 \u0437\u0430\u0433\u043b\u0430\u0432\u0438\u0435 \u043f\u0440\u0435\u0434\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u0442\u0430",
+"Footer": "\u0414\u043e\u043b\u0435\u043d \u043a\u043e\u043b\u043e\u043d\u0442\u0438\u0442\u0443\u043b (footer)",
+"Delete row": "\u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0440\u0435\u0434\u0430",
+"Paste row before": "\u041f\u043e\u0441\u0442\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 \u0440\u0435\u0434 \u043f\u0440\u0435\u0434\u0438",
+"Scope": "\u041e\u0431\u0445\u0432\u0430\u0442",
+"Delete table": "\u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u0442\u0430",
+"Header cell": "\u0417\u0430\u0433\u043b\u0430\u0432\u043d\u0430 \u043a\u043b\u0435\u0442\u043a\u0430 (\u0430\u043d\u0442\u0435\u0442\u043a\u0430)",
+"Column": "\u041a\u043e\u043b\u043e\u043d\u0430",
+"Cell": "\u041a\u043b\u0435\u0442\u043a\u0430",
+"Header": "\u0417\u0430\u0433\u043b\u0430\u0432\u043d\u0430 \u0430\u043d\u0442\u0435\u0442\u043a\u0430 (header)",
+"Cell type": "\u0422\u0438\u043f \u043d\u0430 \u043a\u043b\u0435\u0442\u043a\u0430\u0442\u0430",
+"Copy row": "\u041a\u043e\u043f\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0440\u0435\u0434",
+"Row properties": "\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0430 \u0440\u0435\u0434\u0430",
+"Table properties": "\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u0442\u0430",
+"Row group": "Row group",
+"Right": "\u0414\u044f\u0441\u043d\u043e",
+"Insert column after": "\u0412\u043c\u044a\u043a\u0432\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u043b\u043e\u043d\u0430 \u0441\u043b\u0435\u0434",
+"Cols": "\u041a\u043e\u043b\u043e\u043d\u0438",
+"Insert row after": "\u0412\u043c\u044a\u043a\u0432\u0430\u043d\u0435 \u043d\u0430 \u0440\u0435\u0434 \u0441\u043b\u0435\u0434",
+"Width": "\u0428\u0438\u0440\u0438\u043d\u0430",
+"Cell properties": "\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0430 \u043a\u043b\u0435\u0442\u043a\u0430\u0442\u0430",
+"Left": "\u041b\u044f\u0432\u043e",
+"Cut row": "\u0418\u0437\u0440\u044f\u0437\u0432\u0430\u043d\u0435 \u043d\u0430 \u0440\u0435\u0434",
+"Delete column": "\u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u043b\u043e\u043d\u0430\u0442\u0430",
+"Center": "\u0426\u0435\u043d\u0442\u0440\u0438\u0440\u0430\u043d\u043e",
+"Merge cells": "\u0421\u043b\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u043a\u043b\u0435\u0442\u043a\u0438\u0442\u0435",
+"Insert template": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 \u0448\u0430\u0431\u043b\u043e\u043d",
+"Templates": "\u0428\u0430\u0431\u043b\u043e\u043d\u0438",
+"Background color": "\u0424\u043e\u043d\u043e\u0432 \u0446\u0432\u044f\u0442",
+"Text color": "\u0426\u0432\u044f\u0442 \u043d\u0430 \u0448\u0440\u0438\u0444\u0442\u0430",
+"Show blocks": "\u041f\u043e\u043a\u0430\u0437\u0432\u0430\u043d\u0435 \u043d\u0430 \u0431\u043b\u043e\u043a\u043e\u0432\u0435\u0442\u0435",
+"Show invisible characters": "\u041f\u043e\u043a\u0430\u0437\u0432\u0430\u043d\u0435 \u043d\u0430 \u043d\u0435\u043f\u0435\u0447\u0430\u0442\u0430\u0435\u043c\u0438 \u0437\u043d\u0430\u0446\u0438",
+"Words: {0}": "\u0411\u0440\u043e\u0439 \u0434\u0443\u043c\u0438: {0}",
+"Insert": "\u0412\u043c\u044a\u043a\u0432\u0430\u043d\u0435",
+"File": "\u0424\u0430\u0439\u043b",
+"Edit": "\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u043d\u0435",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u041f\u043e\u043b\u0435 \u0437\u0430 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u0430\u043d \u0442\u0435\u043a\u0441\u0442. \u041d\u0430\u0442\u0438\u0441\u043d\u0435\u0442\u0435 Alt+F9 \u0437\u0430 \u043c\u0435\u043d\u044e; Alt+F10 \u0437\u0430 \u043b\u0435\u043d\u0442\u0430 \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0438; Alt+0 \u0437\u0430 \u043f\u043e\u043c\u043e\u0449.",
+"Tools": "\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0438",
+"View": "\u0418\u0437\u0433\u043b\u0435\u0434",
+"Table": "\u0422\u0430\u0431\u043b\u0438\u0446\u0430",
+"Format": "\u0424\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u0430\u043d\u0435"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/bs.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/bs.js
new file mode 100755
index 0000000..77b8000
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/bs.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('bs',{
+"Cut": "Izre\u017ei",
+"Header 2": "Zaglavlje 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Va\u0161 browser ne podr\u017eava direktan pristup me\u0111umemoriji. Molimo vas da koristite pre\u010dice Ctrl+X\/C\/V na tastaturi.",
+"Div": "Div",
+"Paste": "Zalijepi",
+"Close": "Zatvori",
+"Pre": "Pre",
+"Align right": "Poravnaj desno",
+"New document": "Novi dokument",
+"Blockquote": "Blok citat",
+"Numbered list": "Numerisana lista",
+"Increase indent": "Pove\u0107aj uvlaku",
+"Formats": "Formati",
+"Headers": "Zaglavlja",
+"Select all": "Ozna\u010di sve",
+"Header 3": "Zaglavlje 3",
+"Blocks": "Blokovi",
+"Undo": "Nazad",
+"Strikethrough": "Precrtano",
+"Bullet list": "Bullet lista",
+"Header 1": "Zaglavlje 1",
+"Superscript": "Eksponent",
+"Clear formatting": "Poni\u0161ti formatiranje",
+"Subscript": "Indeks",
+"Header 6": "Zaglavlje 6",
+"Redo": "Naprijed",
+"Paragraph": "Paragraf",
+"Ok": "U redu",
+"Bold": "Podebljano",
+"Code": "Kod",
+"Italic": "Nakrivljen",
+"Align center": "Centriraj",
+"Header 5": "Zaglavlje 5",
+"Decrease indent": "Smanji uvlaku",
+"Header 4": "Zaglavlje 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Lijepljenje je sada u modu obi\u010dnog teksta. Sadr\u017eaj \u0107e sada biti zalijepljen kao obi\u010dni tekst sve dok ovu opciju ne ugasite.",
+"Underline": "Podvu\u010deno",
+"Cancel": "Otka\u017ei",
+"Justify": "Obostrano poravnanje",
+"Inline": "U liniji",
+"Copy": "Kopiraj",
+"Align left": "Poravnaj lijevo",
+"Visual aids": "Vizualna pomo\u0107",
+"Lower Greek": "Mala gr\u010dka slova",
+"Square": "Kvadrat",
+"Default": "Po\u010detno",
+"Lower Alpha": "Mala slova",
+"Circle": "Krug",
+"Disc": "Disk",
+"Upper Alpha": "Velika slova",
+"Upper Roman": "Velika rimska slova",
+"Lower Roman": "Mala rimska slova",
+"Name": "Ime",
+"Anchor": "Anchor",
+"You have unsaved changes are you sure you want to navigate away?": "Niste sa\u010duvali izmjene. Jeste li sigurni da \u017eelite napustiti stranicu?",
+"Restore last draft": "Vrati posljednju skicu",
+"Special character": "Specijalni znak",
+"Source code": "Izvorni kod",
+"Right to left": "S desna na lijevo",
+"Left to right": "S lijeva na desno",
+"Emoticons": "Smajliji",
+"Robots": "Roboti",
+"Document properties": "Svojstva dokumenta",
+"Title": "Naslov",
+"Keywords": "Klju\u010dne rije\u010di",
+"Encoding": "Kodiranje",
+"Description": "Opis",
+"Author": "Autor",
+"Fullscreen": "Cijeli ekran",
+"Horizontal line": "Vodoravna linija",
+"Horizontal space": "Horizontalni razmak",
+"Insert\/edit image": "Umetni\/uredi sliku",
+"General": "Op\u0107enito",
+"Advanced": "Napredno",
+"Source": "Izvor",
+"Border": "Okvir",
+"Constrain proportions": "Ograni\u010di proporcije",
+"Vertical space": "Vertikalni razmak",
+"Image description": "Opis slike",
+"Style": "Stil",
+"Dimensions": "Dimenzije",
+"Insert image": "Umetni sliku",
+"Insert date\/time": "Umetni datum\/vrijeme",
+"Remove link": "Ukloni link",
+"Url": "URL",
+"Text to display": "Tekst za prikaz",
+"Anchors": "Anchori",
+"Insert link": "Umetni link",
+"New window": "Novi prozor",
+"None": "Ni\u0161ta",
+"Target": "Odredi\u0161te",
+"Insert\/edit link": "Umetni\/uredi link",
+"Insert\/edit video": "Umetni\/uredi video",
+"Poster": "Objavio",
+"Alternative source": "Alternativni izvor",
+"Paste your embed code below:": "Zalijepite va\u0161 ugradbeni kod ispod:",
+"Insert video": "Umetni video",
+"Embed": "Ugradi",
+"Nonbreaking space": "Neprijelomni razmak",
+"Page break": "Prijelom stranice",
+"Paste as text": "Zalijepi kao tekst",
+"Preview": "Pregled",
+"Print": "\u0160tampaj",
+"Save": "Sa\u010duvaj",
+"Could not find the specified string.": "Tra\u017eeni string nije prona\u0111en.",
+"Replace": "Zamijeni",
+"Next": "Sljede\u0107e",
+"Whole words": "Cijele rije\u010di",
+"Find and replace": "Prona\u0111i i zamijeni",
+"Replace with": "Zamijena sa",
+"Find": "Prona\u0111i",
+"Replace all": "Zamijeni sve",
+"Match case": "Razlikuj mala i velika slova",
+"Prev": "Prethodno",
+"Spellcheck": "Provjera pravopisa",
+"Finish": "Zavr\u0161i",
+"Ignore all": "Zanemari sve",
+"Ignore": "Zanemari",
+"Insert row before": "Umetni red iznad",
+"Rows": "Redovi",
+"Height": "Visina",
+"Paste row after": "Zalijepi red iznad",
+"Alignment": "Poravnanje",
+"Column group": "Grupa kolone",
+"Row": "Red",
+"Insert column before": "Umetni kolonu iznad",
+"Split cell": "Podijeli \u0107eliju",
+"Cell padding": "Ispunjenje \u0107elije",
+"Cell spacing": "Razmak \u0107elija",
+"Row type": "Vrsta reda",
+"Insert table": "Umetni tabelu",
+"Body": "Tijelo",
+"Caption": "Natpis",
+"Footer": "Podno\u017eje",
+"Delete row": "Obri\u0161i red",
+"Paste row before": "Zalijepi red ispod",
+"Scope": "Opseg",
+"Delete table": "Obri\u0161i tabelu",
+"Header cell": "\u0106elija zaglavlja",
+"Column": "Kolona",
+"Cell": "\u0106elija",
+"Header": "Zaglavlje",
+"Cell type": "Vrsta \u0107elije",
+"Copy row": "Kopiraj red",
+"Row properties": "Svojstva reda",
+"Table properties": "Svojstva tabele",
+"Row group": "Grupa reda",
+"Right": "Desno",
+"Insert column after": "Umetni kolonu ispod",
+"Cols": "Kolone",
+"Insert row after": "Umetni red ispod",
+"Width": "\u0160irina",
+"Cell properties": "Svojstva \u0107elije",
+"Left": "Lijevo",
+"Cut row": "Izre\u017ei red",
+"Delete column": "Obri\u0161i kolonu",
+"Center": "Centrirano",
+"Merge cells": "Spoji \u0107elije",
+"Insert template": "Umetni predlo\u017eak",
+"Templates": "Predlo\u0161ci",
+"Background color": "Boja pozadine",
+"Text color": "Boja tekst",
+"Show blocks": "Prika\u017ei blokove",
+"Show invisible characters": "Prika\u017ei nevidljive znakove",
+"Words: {0}": "Rije\u010di: {0}",
+"Insert": "Umetni",
+"File": "Datoteka",
+"Edit": "Uredi",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Oblast za ure\u0111ivanje teksta. Pritisnite ALT-F9 za meni. Pritisnite ALT-F10 za prikaz alatne trake. Pritisnite ALT-0 za pomo\u0107.",
+"Tools": "Alati",
+"View": "Pregled",
+"Table": "Tabela",
+"Format": "Formatiranje"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ca.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ca.js
new file mode 100755
index 0000000..110b010
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ca.js
@@ -0,0 +1,118 @@
+tinymce.addI18n('ca',{
+"Cut": "Retalla",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "El vostre navegador no suporta l'acc\u00e9s directe al portaobjectes. Si us plau, feu servir les dreceres de teclat Ctrl+X\/C\/V en el seu lloc",
+"Paste": "Pega",
+"Close": "Tanca",
+"Align right": "Aliniat a la dreta",
+"New document": "Nou document",
+"Numbered list": "Llista enumerada",
+"Increase indent": "Augmentar sagnat",
+"Formats": "Formats",
+"Select all": "Seleccionar-ho tot",
+"Undo": "Desfer",
+"Strikethrough": "Ratllat",
+"Bullet list": "Llista no ordenada",
+"Superscript": "Super\u00edndex",
+"Clear formatting": "Eliminar format",
+"Subscript": "Sub\u00edndex",
+"Redo": "Refer",
+"Ok": "Acceptar",
+"Bold": "Negreta",
+"Italic": "Cursiva",
+"Align center": "Centrat",
+"Decrease indent": "Disminuir sagnat",
+"Underline": "Subratllat",
+"Cancel": "Cancel\u00b7la",
+"Justify": "Justificat",
+"Copy": "Copia",
+"Align left": "Aliniat a l'esquerra",
+"Visual aids": "Assist\u00e8ncia visual",
+"Lower Greek": "Grec menor",
+"Square": "Quadrat",
+"Default": "Per defecte",
+"Lower Alpha": "Alfa menor",
+"Circle": "Cercle",
+"Disc": "Disc",
+"Upper Alpha": "Alfa major",
+"Upper Roman": "Roman major",
+"Lower Roman": "Roman menor",
+"Name": "Nom",
+"Anchor": "\u00c0ncora",
+"You have unsaved changes are you sure you want to navigate away?": "Teniu canvis sense desar, esteu segur que voleu deixar-ho ara?",
+"Restore last draft": "Restaurar l'\u00faltim esborrany",
+"Special character": "Car\u00e0cter especial",
+"Source code": "Codi font",
+"Right to left": "De dreta a esquerra",
+"Left to right": "D'esquerra a dreta",
+"Emoticons": "Emoticones",
+"Robots": "Robots",
+"Document properties": "Propietats del document",
+"Title": "T\u00edtol",
+"Keywords": "Paraules clau",
+"Encoding": "Codificaci\u00f3",
+"Description": "Descripci\u00f3",
+"Author": "Autor",
+"Fullscreen": "Pantalla completa",
+"Horizontal line": "L\u00ednia horitzontal",
+"Horizontal space": "Espai horitzontal",
+"Insert\/edit image": "Inserir\/editar imatge",
+"General": "General",
+"Advanced": "Avan\u00e7at",
+"Source": "Font",
+"Border": "Vora",
+"Constrain proportions": "Mantenir proporcions",
+"Vertical space": "Espai vertical",
+"Image description": "Descripci\u00f3 de la imatge",
+"Style": "Estil",
+"Dimensions": "Dimensions",
+"Insert image": "Inserir imatge",
+"Insert date\/time": "Inserir data\/hora",
+"Remove link": "Treure enlla\u00e7",
+"Url": "URL",
+"Text to display": "Text per mostrar",
+"Insert link": "Inserir enlla\u00e7",
+"New window": "Finestra nova",
+"None": "Cap",
+"Target": "Dest\u00ed",
+"Insert\/edit link": "Inserir\/editar enlla\u00e7",
+"Insert\/edit video": "Inserir\/editar v\u00eddeo",
+"Poster": "P\u00f3ster",
+"Alternative source": "Font alternativa",
+"Paste your embed code below:": "Enganxau el codi a sota:",
+"Insert video": "Inserir v\u00eddeo",
+"Embed": "Incloure",
+"Nonbreaking space": "Espai fixe",
+"Page break": "Salt de p\u00e0gina",
+"Preview": "Previsualitzaci\u00f3",
+"Print": "Imprimir",
+"Save": "Desa",
+"Could not find the specified string.": "No es pot trobar el text especificat.",
+"Replace": "Rempla\u00e7ar",
+"Next": "Seg\u00fcent",
+"Whole words": "Paraules senceres",
+"Find and replace": "Buscar i rempla\u00e7ar",
+"Replace with": "Rempla\u00e7ar amb",
+"Find": "Buscar",
+"Replace all": "Rempla\u00e7ar-ho tot",
+"Match case": "Coincidir maj\u00fascules",
+"Prev": "Ant",
+"Spellcheck": "Comprovar ortrografia",
+"Finish": "Finalitzar",
+"Ignore all": "Ignorar tots",
+"Ignore": "Ignorar",
+"Insert template": "Inserir plantilla",
+"Templates": "Plantilles",
+"Background color": "Color del fons",
+"Text color": "Color del text",
+"Show blocks": "Mostrar blocs",
+"Show invisible characters": "Mostrar car\u00e0cters invisibles",
+"Words: {0}": "Paraules: {0}",
+"Insert": "Inserir",
+"File": "Arxiu",
+"Edit": "Edici\u00f3",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u00c0rea de text amb format. Premeu ALT-F9 per mostrar el men\u00fa, ALT F10 per la barra d'eines i ALT-0 per ajuda.",
+"Tools": "Eines",
+"View": "Veure",
+"Table": "Taula",
+"Format": "Format"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/cs.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/cs.js
new file mode 100755
index 0000000..9ab436c
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/cs.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('cs',{
+"Cut": "Vyjmout",
+"Header 2": "Nadpis 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "V\u00e1\u0161 prohl\u00ed\u017ee\u010d nepodporuje p\u0159\u00edm\u00fd p\u0159\u00edstup do schr\u00e1nky. Pou\u017eijte pros\u00edm kl\u00e1vesov\u00e9 zkratky Ctrl+X\/C\/V.",
+"Div": "Div (blok)",
+"Paste": "Vlo\u017eit",
+"Close": "Zav\u0159\u00edt",
+"Pre": "Pre (p\u0159edform\u00e1tov\u00e1no)",
+"Align right": "Zarovnat vpravo",
+"New document": "Nov\u00fd dokument",
+"Blockquote": "Citace",
+"Numbered list": "\u010c\u00edslov\u00e1n\u00ed",
+"Increase indent": "Zv\u011bt\u0161it odsazen\u00ed",
+"Formats": "Form\u00e1ty",
+"Headers": "Nadpisy",
+"Select all": "Vybrat v\u0161e",
+"Header 3": "Nadpis 3",
+"Blocks": "Blokov\u00e9 zobrazen\u00ed (block)",
+"Undo": "Zp\u011bt",
+"Strikethrough": "P\u0159e\u0161rktnut\u00e9",
+"Bullet list": "Odr\u00e1\u017eky",
+"Header 1": "Nadpis 1",
+"Superscript": "Horn\u00ed index",
+"Clear formatting": "Vymazat form\u00e1tov\u00e1n\u00ed",
+"Subscript": "Doln\u00ed index",
+"Header 6": "Nadpis 6",
+"Redo": "Znovu",
+"Paragraph": "Odstavec",
+"Ok": "OK",
+"Bold": "Tu\u010dn\u00e9",
+"Code": "Code (k\u00f3d)",
+"Italic": "Kurz\u00edva",
+"Align center": "Zarovnat na st\u0159ed",
+"Header 5": "Nadpis 5",
+"Decrease indent": "Zmen\u0161it odsazen\u00ed",
+"Header 4": "Nadpis 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Je zapnuto vkl\u00e1d\u00e1n\u00ed \u010dist\u00e9ho textu. Dokud nebude tato volba vypnuta, bude ve\u0161ker\u00fd obsah vlo\u017een jako \u010dist\u00fd text.",
+"Underline": "Podtr\u017een\u00e9",
+"Cancel": "Zru\u0161it",
+"Justify": "Zarovnat do bloku",
+"Inline": "\u0158\u00e1dkov\u00e9 zobrazen\u00ed (inline)",
+"Copy": "Kop\u00edrovat",
+"Align left": "Zarovnat vlevo",
+"Visual aids": "Vizu\u00e1ln\u00ed pom\u016fcky",
+"Lower Greek": "Mal\u00e9 p\u00edsmenkov\u00e1n\u00ed",
+"Square": "\u010ctvere\u010dek",
+"Default": "V\u00fdchoz\u00ed",
+"Lower Alpha": "Norm\u00e1ln\u00ed \u010d\u00edslov\u00e1n\u00ed",
+"Circle": "Kole\u010dko",
+"Disc": "Punt\u00edk",
+"Upper Alpha": "velk\u00e9 p\u00edsmenkov\u00e1n\u00ed",
+"Upper Roman": "\u0158\u00edmsk\u00e9 \u010d\u00edslice",
+"Lower Roman": "Mal\u00e9 \u0159\u00edmsk\u00e9 \u010d\u00edslice",
+"Name": "N\u00e1zev",
+"Anchor": "Kotva",
+"You have unsaved changes are you sure you want to navigate away?": "M\u00e1te neulo\u017een\u00e9 zm\u011bny. Opravdu chcete opustit str\u00e1nku?",
+"Restore last draft": "Obnovit posledn\u00ed koncept",
+"Special character": "Speci\u00e1ln\u00ed znak",
+"Source code": "Zdrojov\u00fd k\u00f3d",
+"Right to left": "Zprava doleva",
+"Left to right": "Zleva doprava",
+"Emoticons": "Emotikony",
+"Robots": "Roboti",
+"Document properties": "Vlastnosti dokumentu",
+"Title": "Titulek",
+"Keywords": "Kl\u00ed\u010dov\u00e1 slova",
+"Encoding": "K\u00f3dov\u00e1n\u00ed",
+"Description": "Popis",
+"Author": "Autor",
+"Fullscreen": "Na celou obrazovku",
+"Horizontal line": "Vodorovn\u00e1 \u010d\u00e1ra",
+"Horizontal space": "Horizont\u00e1ln\u00ed mezera",
+"Insert\/edit image": "Vlo\u017eit \/ upravit obr\u00e1zek",
+"General": "Obecn\u00e9",
+"Advanced": "Pokro\u010dil\u00e9",
+"Source": "Zdroj",
+"Border": "R\u00e1me\u010dek",
+"Constrain proportions": "Zachovat proporce",
+"Vertical space": "Vertik\u00e1ln\u00ed mezera",
+"Image description": "Popis obr\u00e1zku",
+"Style": "Styl",
+"Dimensions": "Rozm\u011bry",
+"Insert image": "Vlo\u017eit obr\u00e1zek",
+"Insert date\/time": "Vlo\u017eit datum \/ \u010das",
+"Remove link": "Odstranit odkaz",
+"Url": "Odkaz",
+"Text to display": "Text k zobrazen\u00ed",
+"Anchors": "Kotvy",
+"Insert link": "Vlo\u017eit odkaz",
+"New window": "Nov\u00e9 okno",
+"None": "\u017d\u00e1dn\u00e9",
+"Target": "C\u00edl",
+"Insert\/edit link": "Vlo\u017eit \/ upravit odkaz",
+"Insert\/edit video": "Vlo\u017eit \/ upravit video",
+"Poster": "N\u00e1hled",
+"Alternative source": "Alternativn\u00ed zdroj",
+"Paste your embed code below:": "Vlo\u017ete k\u00f3d pro vlo\u017een\u00ed n\u00ed\u017ee:",
+"Insert video": "Vlo\u017eit video",
+"Embed": "Vlo\u017eit",
+"Nonbreaking space": "Pevn\u00e1 mezera",
+"Page break": "Konec str\u00e1nky",
+"Paste as text": "Vlo\u017eit jako text",
+"Preview": "N\u00e1hled",
+"Print": "Tisk",
+"Save": "Ulo\u017eit",
+"Could not find the specified string.": "Zadan\u00fd \u0159et\u011bzec nebyl nalezen.",
+"Replace": "Nahradit",
+"Next": "Dal\u0161\u00ed",
+"Whole words": "Cel\u00e1 slova",
+"Find and replace": "Naj\u00edt a nahradit",
+"Replace with": "Nahradit za",
+"Find": "Naj\u00edt",
+"Replace all": "Nahradit v\u0161e",
+"Match case": "Rozli\u0161ovat velikost",
+"Prev": "P\u0159edchoz\u00ed",
+"Spellcheck": "Kontrola pravopisu",
+"Finish": "Ukon\u010dit",
+"Ignore all": "Ignorovat v\u0161e",
+"Ignore": "Ignorovat",
+"Insert row before": "Vlo\u017eit \u0159\u00e1dek nad",
+"Rows": "\u0158\u00e1dek",
+"Height": "V\u00fd\u0161ka",
+"Paste row after": "Vlo\u017eit \u0159\u00e1dek pod",
+"Alignment": "Zarovn\u00e1n\u00ed",
+"Column group": "Skupina sloupc\u016f",
+"Row": "\u0158\u00e1dek",
+"Insert column before": "Vlo\u017eit sloupec vlevo",
+"Split cell": "Rozd\u011blit bu\u0148ky",
+"Cell padding": "Vnit\u0159n\u00ed okraj bun\u011bk",
+"Cell spacing": "Vn\u011bj\u0161\u00ed okraj bun\u011bk",
+"Row type": "Typ \u0159\u00e1dku",
+"Insert table": "Vlo\u017eit tabulku",
+"Body": "T\u011blo",
+"Caption": "Nadpis",
+"Footer": "Pati\u010dka",
+"Delete row": "Smazat \u0159\u00e1dek",
+"Paste row before": "Vlo\u017eit \u0159\u00e1dek nad",
+"Scope": "Rozsah",
+"Delete table": "Smazat tabulku",
+"Header cell": "Hlavi\u010dkov\u00e1 bu\u0148ka",
+"Column": "Sloupec",
+"Cell": "Bu\u0148ka",
+"Header": "Hlavi\u010dka",
+"Cell type": "Typ bu\u0148ky",
+"Copy row": "Kop\u00edrovat \u0159\u00e1dek",
+"Row properties": "Vlastnosti \u0159\u00e1dku",
+"Table properties": "Vlastnosti tabulky",
+"Row group": "Skupina \u0159\u00e1dk\u016f",
+"Right": "Vpravo",
+"Insert column after": "Vlo\u017eit sloupec vpravo",
+"Cols": "Sloupc\u016f",
+"Insert row after": "Vlo\u017eit \u0159\u00e1dek pod",
+"Width": "\u0160\u00ed\u0159ka",
+"Cell properties": "Vlastnosti bu\u0148ky",
+"Left": "Vlevo",
+"Cut row": "Vyjmout \u0159\u00e1dek",
+"Delete column": "Smazat sloupec",
+"Center": "Na st\u0159ed",
+"Merge cells": "Slou\u010dit bu\u0148ky",
+"Insert template": "Vlo\u017eit \u0161ablonu",
+"Templates": "\u0160ablony",
+"Background color": "Barva pozad\u00ed",
+"Text color": "Barva p\u00edsma",
+"Show blocks": "Uk\u00e1zat bloky",
+"Show invisible characters": "Zobrazit speci\u00e1ln\u00ed znaky",
+"Words: {0}": "Po\u010det slov: {0}",
+"Insert": "Vlo\u017eit",
+"File": "Soubor",
+"Edit": "\u00dapravy",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Editor. Stiskn\u011bte ALT-F9 pro menu, ALT-F10 pro n\u00e1strojovou li\u0161tu a ALT-0 pro n\u00e1pov\u011bdu.",
+"Tools": "N\u00e1stroje",
+"View": "Zobrazit",
+"Table": "Tabulka",
+"Format": "Form\u00e1t"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/cy.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/cy.js
new file mode 100755
index 0000000..23e3fb5
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/cy.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('cy',{
+"Cut": "Torri",
+"Header 2": "Pennawd 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Dyw eich porwr ddim yn cynnal mynediad uniongyrchol i'r clipfwrdd. Defnyddiwch yr allweddau llwybr brys Ctrl+X\/C\/V yn lle 'ny.",
+"Div": "Div",
+"Paste": "Gludo",
+"Close": "Cau",
+"Pre": "Pre",
+"Align right": "Aliniad dde",
+"New document": "Dogfen newydd",
+"Blockquote": "Dyfyniad bloc",
+"Numbered list": "Rhestr rifol",
+"Increase indent": "Cynyddu mewnoliad",
+"Formats": "Fformatiau",
+"Headers": "Penawdau",
+"Select all": "Dewis popeth",
+"Header 3": "Pennawd 3",
+"Blocks": "Blociau",
+"Undo": "Dadwneud",
+"Strikethrough": "Llinell drwodd",
+"Bullet list": "Rhestr fwled",
+"Header 1": "Pennawd 1",
+"Superscript": "Uwchsgript",
+"Clear formatting": "Clirio fformatio",
+"Subscript": "Is-sgript",
+"Header 6": "Pennawd 6",
+"Redo": "AIlwneud",
+"Paragraph": "Paragraff",
+"Ok": "Iawn",
+"Bold": "Bras",
+"Code": "Cod",
+"Italic": "Italig",
+"Align center": "Aliniad canol",
+"Header 5": "Pennawd 5",
+"Decrease indent": "Lleinhau mewnoliad",
+"Header 4": "Pennawd 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Mae gludo o fewn modd testun plaen. Caiff y cynnwys ei ludo ar ffurf destun plaen tan gaiff yr opsiwn ei doglo bant.",
+"Underline": "Tanlinellu",
+"Cancel": "Canslo",
+"Justify": "Unioni",
+"Inline": "Mewn llinell",
+"Copy": "Cop\u00efo",
+"Align left": "Aliniad chwith",
+"Visual aids": "Cymorth gweledol",
+"Lower Greek": "Groeg Is",
+"Square": "Sgw\u00e2r",
+"Default": "Diofyn",
+"Lower Alpha": "Alffa Is",
+"Circle": "Cylch",
+"Disc": "Disg",
+"Upper Alpha": "Alffa Uwch",
+"Upper Roman": "Rhufeinig Uwch",
+"Lower Roman": "Rhufeinig Is",
+"Name": "Enw",
+"Anchor": "Angor",
+"You have unsaved changes are you sure you want to navigate away?": "Mae newidiadau heb eu cadw - ydych chi wir am symud i ffwrdd?",
+"Restore last draft": "Adfer y drafft olaf",
+"Special character": "Nod arbennig",
+"Source code": "Cod gwreiddiol",
+"Right to left": "Dde i'r chwith",
+"Left to right": "Chwith i'r dde",
+"Emoticons": "Gwenogluniau",
+"Robots": "Robotiaid",
+"Document properties": "Priodweddau'r ddogfen",
+"Title": "Teitl",
+"Keywords": "Allweddeiriau",
+"Encoding": "Amgodiad",
+"Description": "Disgrifiad",
+"Author": "Awdur",
+"Fullscreen": "Sgrin llawn",
+"Horizontal line": "Llinell lorweddol",
+"Horizontal space": "Gofod llorweddol",
+"Insert\/edit image": "Mewnosod\/golygu delwedd",
+"General": "Cyffredinol",
+"Advanced": "Uwch",
+"Source": "Ffynhonnell",
+"Border": "Ymyl",
+"Constrain proportions": "Gorfodi cyfrannedd",
+"Vertical space": "Gofod fertigol",
+"Image description": "Disgrifiad y ddelwedd",
+"Style": "Arddull",
+"Dimensions": "Dimensiynau",
+"Insert image": "Mewnosod delwedd",
+"Insert date\/time": "Mewnosod dyddiad\/amser",
+"Remove link": "Tynnu dolen",
+"Url": "Url",
+"Text to display": "Testun i'w ddangos",
+"Anchors": "Angorau",
+"Insert link": "Mewnosod dolen",
+"New window": "Ffenest newydd",
+"None": "Dim",
+"Target": "Targed",
+"Insert\/edit link": "Mewnosod\/golygu dolen",
+"Insert\/edit video": "Mewnosod\/golygu fideo",
+"Poster": "Poster",
+"Alternative source": "Ffynhonnell amgen",
+"Paste your embed code below:": "Gludwch eich cod mewnosod isod:",
+"Insert video": "Mewnosod fideo",
+"Embed": "Mewnosod",
+"Nonbreaking space": "Bwlch heb dorri",
+"Page break": "Toriad tudalen",
+"Paste as text": "Gludo fel testun",
+"Preview": "Rhagolwg",
+"Print": "Argraffu",
+"Save": "Cadw",
+"Could not find the specified string.": "Methu ffeindio'r llinyn hwnnw.",
+"Replace": "Amnewid",
+"Next": "Nesaf",
+"Whole words": "Geiriau cyfan",
+"Find and replace": "Chwilio ac amnewid",
+"Replace with": "Amnewid gyda",
+"Find": "Chwilio",
+"Replace all": "Amnewid pob",
+"Match case": "Cydweddu'r un c\u00eas",
+"Prev": "Cynt",
+"Spellcheck": "Sillafydd",
+"Finish": "Gorffen",
+"Ignore all": "Amwybyddu pob",
+"Ignore": "Anwybyddu",
+"Insert row before": "Mewnosod rhes cyn",
+"Rows": "Rhesi",
+"Height": "Uchder",
+"Paste row after": "Gludo rhes ar \u00f4l",
+"Alignment": "Aliniad",
+"Column group": "Gr\u0175p colofn",
+"Row": "Rhes",
+"Insert column before": "Mewnosod colofn cyn",
+"Split cell": "Hollti celloedd",
+"Cell padding": "Padio cell",
+"Cell spacing": "Bylchiau cell",
+"Row type": "Math y rhes",
+"Insert table": "Mewnosod tabl",
+"Body": "Corff",
+"Caption": "Pennawd",
+"Footer": "Troedyn",
+"Delete row": "Dileu rhes",
+"Paste row before": "Gludo rhes cyn",
+"Scope": "Sgop",
+"Delete table": "Dileu'r tabl",
+"Header cell": "Cell bennawd",
+"Column": "Colofn",
+"Cell": "Cell",
+"Header": "Pennyn",
+"Cell type": "Math y gell",
+"Copy row": "Cop\u00efo rhes",
+"Row properties": "Priodweddau rhes",
+"Table properties": "Priodweddau tabl",
+"Row group": "Gr\u0175p rhes",
+"Right": "Dde",
+"Insert column after": "Mewnosod colofn ar \u00f4l",
+"Cols": "Col'u",
+"Insert row after": "Mewnosod rhes ar \u00f4l",
+"Width": "Lled",
+"Cell properties": "Priodweddau'r gell",
+"Left": "Chwith",
+"Cut row": "Torri rhes",
+"Delete column": "Dileu colofn",
+"Center": "Canol",
+"Merge cells": "Cyfuno celloedd",
+"Insert template": "Mewnosod templed",
+"Templates": "Templedi",
+"Background color": "Lliw cefndir",
+"Text color": "Lliw testun",
+"Show blocks": "Dangos blociau",
+"Show invisible characters": "Dangos nodau anweledig",
+"Words: {0}": "Geiriau: {0}",
+"Insert": "Mewnosod",
+"File": "Ffeil",
+"Edit": "Golygu",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Ardal Testun Uwch. Pwyswch ALT-F9 ar gyfer y ddewislen, Pwyswch ALT-F10 ar gyfer y bar offer. Pwyswch ALT-0 am gymorth",
+"Tools": "Offer",
+"View": "Dangos",
+"Table": "Tabl",
+"Format": "Fformat"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/da.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/da.js
new file mode 100755
index 0000000..3cf7acb
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/da.js
@@ -0,0 +1,156 @@
+tinymce.addI18n('da',{
+"Cut": "Klip",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Din browser underst\u00f8tter ikke direkte adgang til clipboard. Benyt Ctrl+X\/C\/ keybord shortcuts i stedet for.",
+"Paste": "Inds\u00e6t",
+"Close": "Luk",
+"Align right": "H\u00f8jrejusteret",
+"New document": "Nyt dokument",
+"Numbered list": "Nummerering",
+"Increase indent": "For\u00f8g indrykning",
+"Formats": "Formater",
+"Select all": "V\u00e6lg alle",
+"Undo": "Fortryd",
+"Strikethrough": "Gennemstreg",
+"Bullet list": "Punkt tegn",
+"Superscript": "Superscript",
+"Clear formatting": "Nulstil formattering",
+"Subscript": "Subscript",
+"Redo": "Genopret",
+"Ok": "Ok",
+"Bold": "Fed",
+"Italic": "Kursiv",
+"Align center": "Centreret",
+"Decrease indent": "Formindsk indrykning",
+"Underline": "Understreg",
+"Cancel": "Fortryd",
+"Justify": "Justering",
+"Copy": "Kopier",
+"Align left": "Venstrejusteret",
+"Visual aids": "Visuel hj\u00e6lp",
+"Lower Greek": "Lower Gr\u00e6sk",
+"Square": "Kvadrat",
+"Default": "Standard",
+"Lower Alpha": "Lower Alpha",
+"Circle": "Cirkel",
+"Disc": "Disk",
+"Upper Alpha": "Upper Alpha",
+"Upper Roman": "Upper Roman",
+"Lower Roman": "Lavere Roman",
+"Name": "Navn",
+"Anchor": "Anchor",
+"You have unsaved changes are you sure you want to navigate away?": "Du har ikke gemte \u00e6ndringer. Er du sikker p\u00e5 at du vil forts\u00e6tte?",
+"Restore last draft": "Genopret sidste kladde",
+"Special character": "Specielle tegn",
+"Source code": "Kildekode",
+"Right to left": "H\u00f8jre til venstre",
+"Left to right": "Venstre til h\u00f8jre",
+"Emoticons": "Emoticons",
+"Robots": "Robotter",
+"Document properties": "Dokument egenskaber",
+"Title": "Titel",
+"Keywords": "S\u00f8geord",
+"Encoding": "Kodning",
+"Description": "Beskrivelse",
+"Author": "Forfatter",
+"Fullscreen": "Fuldsk\u00e6rm",
+"Horizontal line": "Vandret linie",
+"Horizontal space": "Vandret afstand",
+"Insert\/edit image": "Inds\u00e6t\/ret billede",
+"General": "Generet",
+"Advanced": "Avanceret",
+"Source": "Kilde",
+"Border": "Kant",
+"Constrain proportions": "Behold propertioner",
+"Vertical space": "Lodret afstand",
+"Image description": "Billede beskrivelse",
+"Style": "Stil",
+"Dimensions": "Dimensioner",
+"Insert date\/time": "Inds\u00e6t dato\/klokkeslet",
+"Url": "Url",
+"Text to display": "Vis tekst",
+"Insert link": "Inds\u00e6t link",
+"New window": "Nyt vindue",
+"None": "Ingen",
+"Target": "Target",
+"Insert\/edit link": "Inds\u00e6t\/ret link",
+"Insert\/edit video": "Inds\u00e6t\/ret video",
+"Poster": "Poster",
+"Alternative source": "Alternativ kilde",
+"Paste your embed code below:": "Inds\u00e6t din embed kode herunder:",
+"Insert video": "Inds\u00e6t video",
+"Embed": "Integrer",
+"Nonbreaking space": "H\u00e5rd mellemrum",
+"Page break": "Sideskift",
+"Preview": "Forh\u00e5ndsvisning",
+"Print": "Udskriv",
+"Save": "Gem",
+"Could not find the specified string.": "Kunne ikke finde s\u00f8getekst",
+"Replace": "Erstat",
+"Next": "N\u00e6ste",
+"Whole words": "Hele ord",
+"Find and replace": "Find og erstat",
+"Replace with": "Erstat med",
+"Find": "Find",
+"Replace all": "Erstat alt",
+"Match case": "STORE og sm\u00e5 bogstaver",
+"Prev": "Forrige",
+"Spellcheck": "Stavekontrol",
+"Finish": "F\u00e6rdig",
+"Ignore all": "Ignorer alt",
+"Ignore": "Ignorer",
+"Insert row before": "Inds\u00e6t r\u00e6kke f\u00f8r",
+"Rows": "R\u00e6kker",
+"Height": "H\u00f8jde",
+"Paste row after": "Inds\u00e6t r\u00e6kke efter",
+"Alignment": "Tilpasning",
+"Column group": "Kolonne gruppe",
+"Row": "R\u00e6kke",
+"Insert column before": "Inds\u00e6t kolonne f\u00f8r",
+"Split cell": "Split celle",
+"Cell padding": "Celle padding",
+"Cell spacing": "Celle afstand",
+"Row type": "R\u00e6kke type",
+"Insert table": "Inds\u00e6t tabel",
+"Body": "Krop",
+"Caption": "Tekst",
+"Footer": "Sidefod",
+"Delete row": "Slet r\u00e6kke",
+"Paste row before": "Inds\u00e6t r\u00e6kke f\u00f8r",
+"Scope": "Anvendelsesomr\u00e5de",
+"Delete table": "Slet tabel",
+"Header cell": "Header celle",
+"Column": "Kolonne",
+"Cell": "Celle",
+"Header": "Overskrift",
+"Cell type": "Celle type",
+"Copy row": "Kopier r\u00e6kke",
+"Row properties": "R\u00e6kke egenskaber",
+"Table properties": "Tabel egenskaber",
+"Row group": "R\u00e6kke gruppe",
+"Right": "H\u00f8jre",
+"Insert column after": "Inds\u00e6t kolonne efter",
+"Cols": "Kolonne",
+"Insert row after": "Inds\u00e6t r\u00e6kke efter",
+"Width": "Bredde",
+"Cell properties": "Celle egenskaber",
+"Left": "Venstre",
+"Cut row": "Klip r\u00e6kke",
+"Delete column": "Slet kolonne",
+"Center": "Centrering",
+"Merge cells": "Flet celler",
+"Insert template": "Inds\u00e6t skabelon",
+"Templates": "Skabeloner",
+"Background color": "Baggrunds farve",
+"Text color": "Tekst farve",
+"Show blocks": "Vis klokke",
+"Show invisible characters": "Vis usynlige tegn",
+"Words: {0}": "Ord: {0}",
+"Insert": "Inds\u00e6t",
+"File": "Fil",
+"Edit": "\u00c6ndre",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rich Text omr\u00e5de. Tryk ALT-F9 for menu. Tryk ALT-F10 for toolbar. Tryk ALT-0 for hj\u00e6lp",
+"Tools": "V\u00e6rkt\u00f8j",
+"View": "Vis",
+"Table": "Tabel",
+"Format": "Format"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/de.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/de.js
new file mode 100755
index 0000000..5f2dc75
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/de.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('de',{
+"Cut": "Ausschneiden",
+"Header 2": "\u00dcberschrift 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Ihr Browser unterst\u00fctzt leider keinen direkten Zugriff auf die Zwischenablage. Bitte benutzen Sie die Strg + X \/ C \/ V Tastenkombinationen.",
+"Div": "Textblock",
+"Paste": "Einf\u00fcgen",
+"Close": "Schlie\u00dfen",
+"Pre": "Vorformatierter Text",
+"Align right": "Rechts ausrichten ",
+"New document": "Neues Dokument",
+"Blockquote": "Zitat",
+"Numbered list": "Alphabetische Sortierung",
+"Increase indent": "Einr\u00fcckung vergr\u00f6\u00dfern",
+"Formats": "Formate",
+"Headers": "\u00dcberschriften",
+"Select all": "Alles ausw\u00e4hlen",
+"Header 3": "\u00dcberschrift 3",
+"Blocks": "Absatzformate",
+"Undo": "R\u00fcckg\u00e4ngig",
+"Strikethrough": "Durchgestrichen",
+"Bullet list": "Aufz\u00e4hlungszeichen",
+"Header 1": "\u00dcberschrift 1",
+"Superscript": "Hochgestellt",
+"Clear formatting": "Formatierung entfernen",
+"Subscript": "Tiefgestellt",
+"Header 6": "\u00dcberschrift 6",
+"Redo": "Wiederholen",
+"Paragraph": "Absatz",
+"Ok": "Ok",
+"Bold": "Fett",
+"Code": "Quelltext",
+"Italic": "Kursiv",
+"Align center": "Zentriert ausrichten",
+"Header 5": "\u00dcberschrift 5",
+"Decrease indent": "Einzug verringern",
+"Header 4": "\u00dcberschrift 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Einf\u00fcgungen erfolgen bis zum Abschalten dieses Modus als unformatierter Text.",
+"Underline": "Unterstrichen",
+"Cancel": "Abbrechen",
+"Justify": "Blockausrichtung",
+"Inline": "Zeichenformate",
+"Copy": "Kopieren",
+"Align left": "Ausrichtung nach links",
+"Visual aids": "Visuelle Hilfen",
+"Lower Greek": "Lower Greek",
+"Square": "Quadrat",
+"Default": "Standard",
+"Lower Alpha": "Lower Alpha",
+"Circle": "Kreis",
+"Disc": "Disc",
+"Upper Alpha": "Upper Alpha",
+"Upper Roman": "Upper Roman",
+"Lower Roman": "Lower Roman",
+"Name": "Name",
+"Anchor": "Textmarke",
+"You have unsaved changes are you sure you want to navigate away?": "Die \u00c4nderungen wurden noch nicht gespeichert, sind Sie sicher, dass Sie diese Seite verlassen wollen?",
+"Restore last draft": "Zur\u00fcckholen den letzten Entwurf",
+"Special character": "Sonderzeichen",
+"Source code": "Quelltext",
+"Right to left": "Von rechts nach links",
+"Left to right": "Rechts nach Links",
+"Emoticons": "Emoticons",
+"Robots": "Robots",
+"Document properties": "Dokumenteigenschaften",
+"Title": "Titel",
+"Keywords": "Sch\u00fcsselw\u00f6rter",
+"Encoding": "Enkodieren",
+"Description": "Beschreibung",
+"Author": "Verfasser",
+"Fullscreen": "Vollbild",
+"Horizontal line": "Horizontale Linie",
+"Horizontal space": "Horizontaler Abstand",
+"Insert\/edit image": "Bild einf\u00fcgen\/bearbeiten",
+"General": "Allgemein",
+"Advanced": "Erweitert",
+"Source": "Quelle",
+"Border": "Grenze",
+"Constrain proportions": "Seitenverh\u00e4ltnis beibehalten",
+"Vertical space": "Vertikaler Abstand",
+"Image description": "Bildbeschreibung",
+"Style": "Stil",
+"Dimensions": "Abmessungen",
+"Insert image": "Bild einf\u00fcgen",
+"Insert date\/time": "Datum\/Uhrzeit einf\u00fcgen ",
+"Remove link": "Link entfernen",
+"Url": "URL",
+"Text to display": "Anzuzeigender Text",
+"Anchors": "Textmarken",
+"Insert link": "Link einf\u00fcgen",
+"New window": "Neues Fenster",
+"None": "Nichts",
+"Target": "Ziel",
+"Insert\/edit link": "Link einf\u00fcgen\/bearbeiten",
+"Insert\/edit video": "Video einf\u00fcgen\/bearbeiten",
+"Poster": "Poster",
+"Alternative source": "Alternative Quelle",
+"Paste your embed code below:": "F\u00fcgen Sie Ihren Einbettungscode hier ein:",
+"Insert video": "Video einf\u00fcgen",
+"Embed": "Einbetten",
+"Nonbreaking space": "Gesch\u00fctztes Leerzeichen",
+"Page break": "Seitenumbruch",
+"Paste as text": "Als Text einf\u00fcgen",
+"Preview": "Vorschau",
+"Print": "Drucken",
+"Save": "Speichern",
+"Could not find the specified string.": "Die Zeichenfolge wurde nicht gefunden.",
+"Replace": "Ersetzen",
+"Next": "N\u00e4chstes",
+"Whole words": "Ganze W\u00f6rter",
+"Find and replace": "Finden und ersetzen",
+"Replace with": "Ersetzen mit",
+"Find": "Finden",
+"Replace all": "Alles ersetzen",
+"Match case": "Gro\u00df-\/Kleinschreibung beachten",
+"Prev": "Vor",
+"Spellcheck": "Rechtschreibpr\u00fcfung",
+"Finish": "Ende",
+"Ignore all": "Alles Ignorieren",
+"Ignore": "Ignorieren",
+"Insert row before": "Zeile einf\u00fcgen bevor ",
+"Rows": "Zeilen",
+"Height": "H\u00f6he",
+"Paste row after": "Zelle danach einf\u00fcgen",
+"Alignment": "Ausrichtung ",
+"Column group": "Spalten gruppen",
+"Row": "Zeile",
+"Insert column before": "Spalte einf\u00fcgen bevor ",
+"Split cell": "Zellen splitten",
+"Cell padding": "Zellauff\u00fcllung ",
+"Cell spacing": "Zellenabstand",
+"Row type": "Zellentypen",
+"Insert table": "Tabelle einf\u00fcgen",
+"Body": "K\u00f6rper",
+"Caption": "Titel",
+"Footer": "Fu\u00dfzeile",
+"Delete row": "Zelle l\u00f6schen",
+"Paste row before": "Zelle bevor einf\u00fcgen",
+"Scope": "Rahmen",
+"Delete table": "Tabelle l\u00f6schen",
+"Header cell": "Kopfzelle ",
+"Column": "Spalte",
+"Cell": "Zelle",
+"Header": "Kopfzeile",
+"Cell type": "Zellentyp",
+"Copy row": "Zelle Kopieren",
+"Row properties": "Zelle Proportionen",
+"Table properties": "Tabelleneigenschaften",
+"Row group": "Zellen gruppen",
+"Right": "Rechts",
+"Insert column after": "Spalte danach einf\u00fcgen",
+"Cols": "Cols",
+"Insert row after": "Zelle danach einf\u00fcgen",
+"Width": "Breite",
+"Cell properties": "Zellenproportionen",
+"Left": "Links",
+"Cut row": "Zelle schneiden",
+"Delete column": "Spalte l\u00f6schen",
+"Center": "Zentrum",
+"Merge cells": "Zellen verbinden",
+"Insert template": "Vorlage einf\u00fcgen ",
+"Templates": "Vorlagen",
+"Background color": "Hintergrundfarbe",
+"Text color": "Textfarbe",
+"Show blocks": " Bl\u00f6cke anzeigen",
+"Show invisible characters": "Unsichtbare Zeichen anzeigen",
+"Words: {0}": "W\u00f6rter: {0}",
+"Insert": "Einf\u00fcgen",
+"File": "Datei",
+"Edit": "Bearbeiten",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rich-Text- Area. Dr\u00fccken Sie ALT-F9 f\u00fcr das Men\u00fc. Dr\u00fccken Sie ALT-F10 f\u00fcr Symbolleiste. Dr\u00fccken Sie ALT-0 f\u00fcr Hilfe",
+"Tools": "Werkzeuge",
+"View": "Ansicht",
+"Table": "Tabelle",
+"Format": "Format"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/de_AT.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/de_AT.js
new file mode 100755
index 0000000..d41ab6b
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/de_AT.js
@@ -0,0 +1,156 @@
+tinymce.addI18n('de_AT',{
+"Cut": "Ausschneiden",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Ihr Browser unterst\u00fctzt keinen direkten Zugriff auf die Zwischenablage. Bitte nutzen Sie die Tastaturk\u00fcrzel Strg+X\/C\/V stattdessen.",
+"Paste": "Einf\u00fcgen",
+"Close": "Schlie\u00dfen",
+"Align right": "Rechtsb\u00fcndig",
+"New document": "Neues Dokument",
+"Numbered list": "Sortierte Liste",
+"Increase indent": "Einr\u00fccken",
+"Formats": "Formate",
+"Select all": "Alles ausw\u00e4hlen",
+"Undo": "Wiederholen",
+"Strikethrough": "Durchgestrichen",
+"Bullet list": "Unsortierte Liste",
+"Superscript": "Hochgestellt",
+"Clear formatting": "Formatierungen zur\u00fccksetzen",
+"Subscript": "Tiefgestellt",
+"Redo": "R\u00fcckg\u00e4ngig",
+"Ok": "Ok",
+"Bold": "Fett",
+"Italic": "Kursiv",
+"Align center": "Zentriert",
+"Decrease indent": "Ausr\u00fccken",
+"Underline": "Unterstrichen",
+"Cancel": "Abbrechen",
+"Justify": "Blocksatz",
+"Copy": "Kopieren",
+"Align left": "Linksb\u00fcndig",
+"Visual aids": "Hilfslinien und unsichtbare Elemente einblenden",
+"Lower Greek": "Griechische Kleinbuchstaben",
+"Square": "Quadrat",
+"Default": "Standard",
+"Lower Alpha": "Kleinbuchstaben",
+"Circle": "Kreis",
+"Disc": "Scheibe",
+"Upper Alpha": "Griechische Gro\u00dfbuchstaben",
+"Upper Roman": "R\u00f6mische Gro\u00dfbuchstaben",
+"Lower Roman": "R\u00f6mische Kleinbuchstaben",
+"Name": "Name",
+"Anchor": "Anker",
+"You have unsaved changes are you sure you want to navigate away?": "Sie haben ungespeicherte \u00c4nderungen. Sind Sie sicher, dass Sie die Seite verlassen wollen?",
+"Restore last draft": "Letzten Entwurf speichern.",
+"Special character": "Sonderzeichen",
+"Source code": "Quelltext",
+"Right to left": "Rechts nach links",
+"Left to right": "Links nach rechts",
+"Emoticons": "Emoticons",
+"Robots": "Suchmaschinen",
+"Document properties": "Dokumenteigenschaften",
+"Title": "Titel",
+"Keywords": "Schl\u00fcsselw\u00f6rter",
+"Encoding": "Encoding",
+"Description": "Beschreibung",
+"Author": "Author",
+"Fullscreen": "Vollbild",
+"Horizontal line": "Horizontale Trennlinie",
+"Horizontal space": "Horizontaler Abstand",
+"Insert\/edit image": "Bild einf\u00fcgen\/bearbeiten",
+"General": "Allgemein",
+"Advanced": "Erweitert",
+"Source": "Adresse",
+"Border": "Rahmen",
+"Constrain proportions": "Seitenverh\u00e4ltnis beibehalten",
+"Vertical space": "Vertikaler Abstand",
+"Image description": "Bildbeschreibung",
+"Style": "Format",
+"Dimensions": "Ausma\u00dfe",
+"Insert date\/time": "Zeit\/Datum einf\u00fcgen",
+"Url": "Url",
+"Text to display": "Angezeigter Text",
+"Insert link": "Link einf\u00fcgen",
+"New window": "Neues Fenster",
+"None": "Keine",
+"Target": "Ziel",
+"Insert\/edit link": "Link einf\u00fcgen\/bearbeiten",
+"Insert\/edit video": "Video einf\u00fcgen\/bearbeiten",
+"Poster": "Poster",
+"Alternative source": "Alternative Quelle",
+"Paste your embed code below:": "F\u00fcgen unten Sie Ihren Quellcode zum einbetten ein",
+"Insert video": "Video einf\u00fcgen",
+"Embed": "Einbetten",
+"Nonbreaking space": "gesch\u00fctztes Leerzeichen",
+"Page break": "Seitenumbruch",
+"Preview": "Vorschau",
+"Print": "Drucken",
+"Save": "Speichern",
+"Could not find the specified string.": "Keine \u00dcbereinstimmung gefunden",
+"Replace": "Ersetzen",
+"Next": "N\u00e4chstes",
+"Whole words": "Vollst\u00e4ndige W\u00f6rter",
+"Find and replace": "Suchen und ersetzen",
+"Replace with": "Ersetzen mit",
+"Find": "Suchen",
+"Replace all": "Alle ersetzen",
+"Match case": "Gro\u00df-\/Kleinschreibung beachten",
+"Prev": "Vorheriges",
+"Spellcheck": "Rechtschreibung \u00fcberpr\u00fcfen",
+"Finish": "Fertig",
+"Ignore all": "Alle ignorieren",
+"Ignore": "Ignorieren",
+"Insert row before": "Neue Zeile oberhalb einf\u00fcgen",
+"Rows": "Zeilen",
+"Height": "H\u00f6he",
+"Paste row after": "Zeile unterhalb einf\u00fcgen",
+"Alignment": "Ausrichtung",
+"Column group": "Spaltengruppe",
+"Row": "Zeile",
+"Insert column before": "Neue Spalte links einf\u00fcgen",
+"Split cell": "Verbundene Zellen trennen",
+"Cell padding": "Abstand innerhalb der Zellen",
+"Cell spacing": "Zellenabstand",
+"Row type": "Zeilentyp",
+"Insert table": "Tabelle einf\u00fcgen",
+"Body": "Tabellenk\u00f6rper",
+"Caption": "Beschriftung der Tabelle",
+"Footer": "Tabellenfu\u00df",
+"Delete row": "Zeile l\u00f6schen",
+"Paste row before": "Zeile oberhalb einf\u00fcgen",
+"Scope": "Geltungsbereich",
+"Delete table": "Tabelle l\u00f6schen",
+"Header cell": "\u00dcberschrift",
+"Column": "Spalte",
+"Cell": "Zelle",
+"Header": "\u00dcberschrift",
+"Cell type": "Zellentyp",
+"Copy row": "Zeile kopieren",
+"Row properties": "Zeileneigenschaften",
+"Table properties": "Tabelleneigenschaften",
+"Row group": "Zeilengruppe",
+"Right": "Rechts",
+"Insert column after": "Neue Spalte rechts einf\u00fcgen",
+"Cols": "Spalten",
+"Insert row after": "Neue Zeile unterhalb einf\u00fcgen",
+"Width": "Breite",
+"Cell properties": "Zelleneigenschaften",
+"Left": "Links",
+"Cut row": "Zeile ausschneiden",
+"Delete column": "Spalte l\u00f6schen",
+"Center": "Zentriert",
+"Merge cells": "Zellen vereinen",
+"Insert template": "Vorlage einf\u00fcgen",
+"Templates": "Vorlagen",
+"Background color": "Hintergrundfarbe",
+"Text color": "Textfarbe",
+"Show blocks": "Blockelemente einblenden",
+"Show invisible characters": "Unsichtbare Zeichen einblenden",
+"Words: {0}": "W\u00f6rter: {0}",
+"Insert": "Einf\u00fcgen",
+"File": "Datei",
+"Edit": "Bearbeiten",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rich Text Area. Dr\u00fccken Sie ALT-F9 f\u00fcr das Men\u00fc. Dr\u00fccken Sie ALT-F10 f\u00fcr die Werkzeugleiste. Dr\u00fccken Sie ALT-0 f\u00fcr Hilfe",
+"Tools": "Extras",
+"View": "Ansicht",
+"Table": "Tabelle",
+"Format": "Format"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/el.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/el.js
new file mode 100755
index 0000000..9ccd9ec
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/el.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('el',{
+"Cut": "\u0391\u03c0\u03bf\u03ba\u03bf\u03c0\u03ae",
+"Header 2": "\u039a\u03b5\u03c6\u03b1\u03bb\u03af\u03b4\u03b1 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u039f \u03c0\u03b5\u03c1\u03b9\u03b7\u03b3\u03b7\u03c4\u03ae\u03c2 \u03c3\u03b1\u03c2 \u03b4\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03b9 \u03ac\u03bc\u03b5\u03c3\u03b7 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03c3\u03c4\u03bf \u03c0\u03c1\u03cc\u03c7\u03b5\u03b9\u03c1\u03bf. \u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 \u03c4\u03b9\u03c2 \u03c3\u03c5\u03bd\u03c4\u03bf\u03bc\u03b5\u03cd\u03c3\u03b5\u03b9\u03c2 \u03c0\u03bb\u03b7\u03ba\u03c4\u03c1\u03bf\u03bb\u03bf\u03b3\u03af\u03bf\u03c5 Ctrl+X\/C\/V.",
+"Div": "Div",
+"Paste": "\u0395\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7",
+"Close": "\u039a\u03bb\u03b5\u03b9\u03c3\u03b9\u03bc\u03bf",
+"Pre": "Pre",
+"Align right": "\u03a3\u03c4\u03bf\u03af\u03c7\u03b9\u03c3\u03b7 \u03b4\u03b5\u03be\u03b9\u03ac",
+"New document": "\u039d\u03ad\u03bf \u03ad\u03b3\u03b3\u03c1\u03b1\u03c6\u03bf",
+"Blockquote": "\u03a0\u03b5\u03c1\u03b9\u03bf\u03c7\u03ae \u03c0\u03b1\u03c1\u03ac\u03b8\u03b5\u03c3\u03b7\u03c2",
+"Numbered list": "\u0391\u03c1\u03b9\u03b8\u03bc\u03b7\u03bc\u03ad\u03bd\u03b7 \u03bb\u03af\u03c3\u03c4\u03b1",
+"Increase indent": "\u0391\u03cd\u03be\u03b7\u03c3\u03b7 \u03b5\u03c3\u03bf\u03c7\u03ae\u03c2",
+"Formats": "\u039c\u03bf\u03c1\u03c6\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7",
+"Headers": "\u039a\u03b5\u03c6\u03b1\u03bb\u03af\u03b4\u03b5\u03c2",
+"Select all": "\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03b7 \u03bf\u03bb\u03c9\u03bd",
+"Header 3": "\u039a\u03b5\u03c6\u03b1\u03bb\u03af\u03b4\u03b1 3",
+"Blocks": "\u03a4\u03bc\u03ae\u03bc\u03b1\u03c4\u03b1",
+"Undo": "\u0391\u03bd\u03b1\u03af\u03c1\u03b5\u03c3\u03b7",
+"Strikethrough": "\u0394\u03b9\u03b1\u03ba\u03c1\u03b9\u03c4\u03ae \u03b4\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae",
+"Bullet list": "\u039b\u03af\u03c3\u03c4\u03b1 \u03bc\u03b5 \u03ba\u03bf\u03c5\u03ba\u03ba\u03af\u03b4\u03b5\u03c2",
+"Header 1": "\u039a\u03b5\u03c6\u03b1\u03bb\u03af\u03b4\u03b1 1",
+"Superscript": "\u0395\u03ba\u03b8\u03ad\u03c4\u03b7\u03c2",
+"Clear formatting": "\u0391\u03c0\u03b1\u03bb\u03bf\u03b9\u03c6\u03ae \u03bc\u03bf\u03c1\u03c6\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7\u03c2",
+"Subscript": "\u0394\u03b5\u03af\u03ba\u03c4\u03b7\u03c2",
+"Header 6": "\u039a\u03b5\u03c6\u03b1\u03bb\u03af\u03b4\u03b1 6",
+"Redo": "\u0395\u03c0\u03b1\u03bd\u03b1\u03c6\u03bf\u03c1\u03ac",
+"Paragraph": "\u03a0\u03b1\u03c1\u03ac\u03b3\u03c1\u03b1\u03c6\u03bf\u03c2",
+"Ok": "\u0395\u03bd\u03c4\u03ac\u03be\u03b5\u03b9",
+"Bold": "\u0388\u03bd\u03c4\u03bf\u03bd\u03b7",
+"Code": "\u039a\u03ce\u03b4\u03b9\u03ba\u03b1\u03c2",
+"Italic": "\u03a0\u03bb\u03ac\u03b3\u03b9\u03b1",
+"Align center": "\u03a3\u03c4\u03bf\u03af\u03c7\u03b9\u03c3\u03b7 \u03c3\u03c4\u03bf \u03ba\u03ad\u03bd\u03c4\u03c1\u03bf",
+"Header 5": "\u039a\u03b5\u03c6\u03b1\u03bb\u03af\u03b4\u03b1 5",
+"Decrease indent": "\u039c\u03b5\u03af\u03c9\u03c3\u03b7 \u03b5\u03c3\u03bf\u03c7\u03ae\u03c2",
+"Header 4": "\u039a\u03b5\u03c6\u03b1\u03bb\u03af\u03b4\u03b1 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u0397 \u03b5\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7 \u03b5\u03af\u03bd\u03b1\u03b9 \u03c4\u03ce\u03c1\u03b1 \u03c3\u03b5 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u03b1\u03c0\u03bb\u03bf\u03cd \u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5. \u03a4\u03b1 \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03cc\u03bc\u03b5\u03bd\u03b1 \u03c3\u03b5 \u03bc\u03af\u03b1 \u03b5\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7 \u03b8\u03b1 \u03b5\u03c0\u03b9\u03ba\u03bf\u03bb\u03bb\u03bf\u03cd\u03bd\u03c4\u03b1\u03b9 \u03c9\u03c2 \u03b1\u03c0\u03bb\u03cc \u03ba\u03b5\u03af\u03bc\u03b5\u03bd\u03bf \u03cc\u03c3\u03bf \u03b7 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u03b1\u03c5\u03c4\u03ae \u03c0\u03b1\u03c1\u03b1\u03bc\u03ad\u03bd\u03b5\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03ae.",
+"Underline": "\u03a5\u03c0\u03bf\u03b3\u03c1\u03ac\u03bc\u03bc\u03b9\u03c3\u03b7",
+"Cancel": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7",
+"Justify": "\u03a0\u03bb\u03ae\u03c1\u03b7\u03c2 \u03c3\u03c4\u03bf\u03af\u03c7\u03b9\u03c3\u03b7",
+"Inline": "\u0395\u03bd\u03c3\u03c9\u03bc\u03b1\u03c4\u03c9\u03bc\u03ad\u03bd\u03b5\u03c2",
+"Copy": "\u0391\u03bd\u03c4\u03b9\u03b3\u03c1\u03b1\u03c6\u03ae",
+"Align left": "\u03a3\u03c4\u03bf\u03af\u03c7\u03b9\u03c3\u03b7 \u03b1\u03c1\u03b9\u03c3\u03c4\u03b5\u03c1\u03ac",
+"Visual aids": "\u0392\u03bf\u03b7\u03b8\u03ae\u03bc\u03b1\u03c4\u03b1 \u03c7\u03b1\u03bc\u03b7\u03bb\u03ae\u03c2 \u03cc\u03c1\u03b1\u03c3\u03b7\u03c2",
+"Lower Greek": "\u039c\u03b9\u03ba\u03c1\u03ac \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac",
+"Square": "\u03a4\u03b5\u03c4\u03c1\u03ac\u03b3\u03c9\u03bd\u03bf",
+"Default": "\u03a0\u03c1\u03bf\u03ba\u03b1\u03b8\u03bf\u03c1\u03b9\u03c3\u03bc\u03ad\u03bd\u03bf",
+"Lower Alpha": "\u039c\u03b9\u03ba\u03c1\u03ac \u039b\u03b1\u03c4\u03b9\u03bd\u03b9\u03ba\u03ac",
+"Circle": "\u039a\u03cd\u03ba\u03bb\u03bf\u03c2",
+"Disc": "\u0394\u03af\u03c3\u03ba\u03bf\u03c2",
+"Upper Alpha": "\u039a\u03b5\u03c6\u03b1\u03bb\u03b1\u03af\u03b1 \u039b\u03b1\u03c4\u03b9\u03bd\u03b9\u03ba\u03ac",
+"Upper Roman": "\u039a\u03b5\u03c6\u03b1\u03bb\u03b1\u03af\u03b1 \u03a1\u03c9\u03bc\u03b1\u03ca\u03ba\u03ac",
+"Lower Roman": "\u039c\u03b9\u03ba\u03c1\u03ac \u03a1\u03c9\u03bc\u03b1\u03ca\u03ba\u03ac",
+"Name": "\u039f\u03bd\u03bf\u03bc\u03b1",
+"Anchor": "\u0386\u03b3\u03ba\u03c5\u03c1\u03b1 ",
+"You have unsaved changes are you sure you want to navigate away?": "\u0388\u03c7\u03b5\u03c4\u03b5 \u03bc\u03b7 \u03b1\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03c5\u03bc\u03ad\u03bd\u03b5\u03c2 \u03b1\u03bb\u03bb\u03b1\u03b3\u03ad\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u0395\u03af\u03c3\u03c4\u03b5 \u03b2\u03ad\u03b2\u03b1\u03b9\u03bf\u03b9 \u03cc\u03c4\u03b9 \u03b8\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03c6\u03cd\u03b3\u03b5\u03c4\u03b5?",
+"Restore last draft": "\u0395\u03c0\u03b1\u03bd\u03b1\u03c6\u03bf\u03c1\u03ac \u03c4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03bf\u03c5 \u03c3\u03c7\u03ad\u03b4\u03b9\u03bf\u03c5",
+"Special character": "\u0395\u03b9\u03b4\u03b9\u03ba\u03bf\u03c2 \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03b7\u03c1\u03b1\u03c2",
+"Source code": "\u03a0\u03b7\u03b3\u03b1\u03af\u03bf\u03c2 \u03ba\u03ce\u03b4\u03b9\u03ba\u03b1\u03c2",
+"Right to left": "\u0391\u03c0\u03bf \u03c4\u03b1 \u03b4\u03b5\u03be\u03b9\u03b1 \u03c0\u03c1\u03bf\u03c2 \u03c4\u03b1 \u03b1\u03c1\u03b9\u03c3\u03c4\u03b5\u03c1\u03b1",
+"Left to right": "\u0391\u03c0\u03cc \u03b1\u03c1\u03b9\u03c3\u03c4\u03b5\u03c1\u03ac \u03c0\u03c1\u03bf\u03c2 \u03c4\u03b1 \u03b4\u03b5\u03be\u03b9\u03ac ",
+"Emoticons": "\u03a6\u03b1\u03c4\u03c3\u03bf\u03cd\u03bb\u03b5\u03c2",
+"Robots": "Robots",
+"Document properties": "\u0399\u03b4\u03b9\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2 \u03bd\u03c4\u03bf\u03ba\u03bf\u03c5\u03bc\u03b5\u03bd\u03c4\u03bf\u03c5",
+"Title": "\u03a4\u03b9\u03c4\u03bb\u03bf\u03c2",
+"Keywords": "\u039b\u03b5\u03be\u03b5\u03b9\u03c2 \u03ba\u03bb\u03b5\u03b9\u03b4\u03b9\u03b1",
+"Encoding": "\u039a\u03c9\u03b4\u03b9\u03ba\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7",
+"Description": "\u03a0\u03b5\u03c1\u03b9\u03b3\u03c1\u03b1\u03c6\u03ae",
+"Author": "\u0394\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03bf\u03c2",
+"Fullscreen": "\u039f\u03bb\u03bf\u03ba\u03bb\u03b7\u03c1\u03b7 \u03bf\u03b8\u03bf\u03bd\u03b7",
+"Horizontal line": "\u039f\u03c1\u03b9\u03b6\u03bf\u03bd\u03c4\u03b9\u03b1 \u03b3\u03c1\u03b1\u03bc\u03bc\u03b7",
+"Horizontal space": "\u039f\u03c1\u03b9\u03b6\u03cc\u03bd\u03c4\u03b9\u03bf \u03b4\u03b9\u03ac\u03c3\u03c4\u03b7\u03bc\u03b1",
+"Insert\/edit image": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae\/\u03b5\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03b5\u03b9\u03ba\u03cc\u03bd\u03b1\u03c2",
+"General": "\u0393\u03b5\u03bd\u03b9\u03ba\u03b1",
+"Advanced": "\u0393\u03b9\u03b1 \u03a0\u03c1\u03bf\u03c7\u03c9\u03c1\u03b7\u03bc\u03ad\u03bd\u03bf\u03c5\u03c2",
+"Source": "\u03a0\u03b7\u03b3\u03ae",
+"Border": "\u03a3\u03cd\u03bd\u03bf\u03c1\u03bf",
+"Constrain proportions": "\u03a0\u03b5\u03c1\u03b9\u03bf\u03c1\u03b9\u03c3\u03bc\u03cc\u03c2 \u03b1\u03bd\u03b1\u03bb\u03bf\u03b3\u03b9\u03ce\u03bd",
+"Vertical space": "\u039a\u03ac\u03b8\u03b5\u03c4\u03bf \u03b4\u03b9\u03ac\u03c3\u03c4\u03b7\u03bc\u03b1",
+"Image description": "\u03a0\u03b5\u03c1\u03b9\u03b3\u03c1\u03b1\u03c6\u03ae \u03b5\u03b9\u03ba\u03cc\u03bd\u03b1\u03c2",
+"Style": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7",
+"Dimensions": "\u039c\u03b5\u03b3\u03b5\u03b8\u03bf\u03b9",
+"Insert image": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03b5\u03b9\u03ba\u03cc\u03bd\u03b1\u03c2",
+"Insert date\/time": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03b7 \u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03b9\u03b1\u03c2\/\u03c9\u03c1\u03b1\u03c2",
+"Remove link": "\u0391\u03c6\u03b1\u03af\u03c1\u03b5\u03c3\u03b7 \u03c3\u03c5\u03bd\u03b4\u03ad\u03c3\u03bc\u03bf\u03c5",
+"Url": "Url",
+"Text to display": "\u039a\u03b5\u03af\u03bc\u03b5\u03bd\u03bf \u03b3\u03b9\u03b1 \u03b5\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7",
+"Anchors": "\u0386\u03b3\u03ba\u03c5\u03c1\u03b5\u03c2",
+"Insert link": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03b7 \u03c3\u03c5\u03bd\u03b4\u03ad\u03c3\u03bc\u03bf\u03c5",
+"New window": "\u039d\u03ad\u03bf \u03c0\u03b1\u03c1\u03ac\u03b8\u03c5\u03c1\u03bf",
+"None": "\u039a\u03b1\u03bc\u03af\u03b1",
+"Target": "\u03a3\u03c4\u03cc\u03c7\u03bf\u03c2",
+"Insert\/edit link": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae\/\u03b5\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03c3\u03c5\u03bd\u03b4\u03ad\u03c3\u03bc\u03bf\u03c5",
+"Insert\/edit video": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03b7\/\u03b5\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03b9\u03b1 \u0392\u03b9\u03bd\u03c4\u03b5\u03bf",
+"Poster": "\u0391\u03c6\u03af\u03c3\u03b1",
+"Alternative source": "\u0395\u03bd\u03b1\u03bb\u03bb\u03b1\u03ba\u03c4\u03b9\u03ba\u03ae \u03c0\u03b7\u03b3\u03ae",
+"Paste your embed code below:": "\u0395\u03b9\u03c3\u03b1\u03b3\u03b5\u03c4\u03b5 \u03b5\u03b4\u03c9 \u03c4\u03bf\u03bd \u03ba\u03c9\u03b4\u03b9\u03ba\u03bf \u03c3\u03b1\u03c2:",
+"Insert video": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03b7 \u0392\u03b9\u03bd\u03c4\u03b5\u03bf",
+"Embed": "\u0395\u03bd\u03c3\u03c9\u03bc\u03b1\u03c4\u03c9\u03bc\u03b5\u03bd\u03b1",
+"Nonbreaking space": "\u039a\u03b5\u03bd\u03cc \u03c7\u03c9\u03c1\u03af\u03c2 \u03b4\u03b9\u03b1\u03ba\u03bf\u03c0\u03ae",
+"Page break": "\u0391\u03bb\u03bb\u03b1\u03b3\u03ae \u03c3\u03b5\u03bb\u03af\u03b4\u03b1\u03c2",
+"Paste as text": "\u0395\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7 \u03c9\u03c2 \u03ba\u03b5\u03af\u03bc\u03b5\u03bd\u03bf",
+"Preview": "\u03a0\u03c1\u03bf\u03b5\u03c0\u03b9\u03c3\u03ba\u03bf\u03c0\u03b7\u03c3\u03b7",
+"Print": "\u0395\u03ba\u03c4\u03cd\u03c0\u03c9\u03c3\u03b7",
+"Save": "\u0391\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03c5\u03c3\u03b7",
+"Could not find the specified string.": "\u0394\u03b5\u03bd \u03ae\u03c4\u03b1\u03bd \u03b4\u03c5\u03bd\u03b1\u03c4\u03ae \u03b7 \u03b5\u03cd\u03c1\u03b5\u03c3\u03b7 \u03c4\u03bf\u03c5 \u03ba\u03b1\u03b8\u03bf\u03c1\u03b9\u03c3\u03bc\u03ad\u03bd\u03bf\u03c5 string.",
+"Replace": "\u0391\u03bd\u03c4\u03b9\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03b1\u03c3\u03b7",
+"Next": "\u0395\u03c0\u03bf\u03bc\u03b5\u03bd\u03bf",
+"Whole words": "\u039f\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bb\u03b5\u03be\u03b5\u03b9\u03c2",
+"Find and replace": "\u0395\u03c5\u03c1\u03b5\u03c3\u03b7 \u03ba\u03b1\u03b9 \u03b1\u03bd\u03c4\u03b9\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03b1\u03c3\u03b7",
+"Replace with": "\u0391\u03bd\u03c4\u03b9\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03b1\u03c3\u03b7 \u03bc\u03b5",
+"Find": "\u0395\u03c5\u03c1\u03b5\u03c3\u03b7",
+"Replace all": "\u0391\u03bd\u03c4\u03b9\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03b1\u03c3\u03b7 \u03bf\u03bb\u03c9\u03bd",
+"Match case": "\u03a0\u03b5\u03c1\u03af\u03c0\u03c4\u03c9\u03c3\u03b7 ",
+"Prev": "\u03a0\u03c1\u03bf",
+"Spellcheck": "\u039f\u03c1\u03b8\u03bf\u03b3\u03c1\u03b1\u03c6\u03b9\u03ba\u03cc\u03c2 \u03ad\u03bb\u03b5\u03b3\u03c7\u03bf\u03c2 ",
+"Finish": "\u03a4\u03b5\u03bb\u03bf\u03c2",
+"Ignore all": "\u0391\u03b3\u03bd\u03bf\u03b7\u03c3\u03b7 \u03bf\u03bb\u03c9\u03bd",
+"Ignore": "\u0391\u03b3\u03bd\u03bf\u03b7\u03c3\u03b7",
+"Insert row before": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2 \u03c0\u03c1\u03b9\u03bd",
+"Rows": "\u0393\u03c1\u03b1\u03bc\u03bc\u03ad\u03c2",
+"Height": "\u038e\u03c8\u03bf\u03c2",
+"Paste row after": "\u0395\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7 \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2 \u03bc\u03b5\u03c4\u03ac",
+"Alignment": "\u03a3\u03c4\u03bf\u03af\u03c7\u03b9\u03c3\u03b7",
+"Column group": "\u039f\u03bc\u03ac\u03b4\u03b1 \u03c3\u03c4\u03b7\u03bb\u03ce\u03bd",
+"Row": "\u0393\u03c1\u03b1\u03bc\u03bc\u03ae",
+"Insert column before": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03c3\u03c4\u03ae\u03bb\u03b7\u03c2 \u03c0\u03c1\u03b9\u03bd",
+"Split cell": "\u0394\u03b9\u03b1\u03af\u03c1\u03b5\u03c3\u03b7 \u03ba\u03b5\u03bb\u03b9\u03bf\u03cd",
+"Cell padding": "\u03a0\u03b5\u03c1\u03b9\u03b3\u03c1\u03ac\u03bc\u03bc\u03b1\u03c4\u03b1 \u03ba\u03b5\u03bb\u03b9\u03ce\u03bd",
+"Cell spacing": "\u0391\u03c0\u03cc\u03c3\u03c4\u03b1\u03c3\u03b7 \u03ba\u03b5\u03bb\u03b9\u03ce\u03bd",
+"Row type": "\u03a4\u03cd\u03c0\u03bf\u03c2 \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2",
+"Insert table": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03c0\u03af\u03bd\u03b1\u03ba\u03b1",
+"Body": "\u03a3\u03ce\u03bc\u03b1",
+"Caption": "\u0395\u03c0\u03b9\u03ba\u03b5\u03c6\u03b1\u03bb\u03af\u03b4\u03b1",
+"Footer": "\u03a5\u03c0\u03bf\u03c3\u03ad\u03bb\u03b9\u03b4\u03bf",
+"Delete row": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2",
+"Paste row before": "\u0395\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7 \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2 \u03c0\u03c1\u03b9\u03bd",
+"Scope": "\u0388\u03ba\u03c4\u03b1\u03c3\u03b7",
+"Delete table": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03c0\u03af\u03bd\u03b1\u03ba\u03b1",
+"Header cell": "\u039a\u03b5\u03bb\u03af-\u03ba\u03b5\u03c6\u03b1\u03bb\u03af\u03b4\u03b1",
+"Column": "\u03a3\u03c4\u03ae\u03bb\u03b7",
+"Cell": "\u039a\u03b5\u03bb\u03af",
+"Header": "\u039a\u03b5\u03c6\u03b1\u03bb\u03af\u03b4\u03b1",
+"Cell type": "\u03a4\u03cd\u03c0\u03bf\u03c2 \u03ba\u03b5\u03bb\u03b9\u03bf\u03cd",
+"Copy row": "\u0391\u03bd\u03c4\u03b9\u03b3\u03c1\u03b1\u03c6\u03ae \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2",
+"Row properties": "\u0399\u03b4\u03b9\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2 \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2",
+"Table properties": "\u0399\u03b4\u03b9\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2 \u03c0\u03af\u03bd\u03b1\u03ba\u03b1",
+"Row group": "\u039f\u03bc\u03ac\u03b4\u03b1 \u03b3\u03c1\u03b1\u03bc\u03bc\u03ce\u03bd",
+"Right": "\u0394\u03b5\u03be\u03b9\u03ac",
+"Insert column after": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03c3\u03c4\u03ae\u03bb\u03b7\u03c2 \u03bc\u03b5\u03c4\u03ac",
+"Cols": "\u03a3\u03c4\u03ae\u03bb\u03b5\u03c2",
+"Insert row after": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2 \u03bc\u03b5\u03c4\u03ac",
+"Width": "\u03a0\u03bb\u03ac\u03c4\u03bf\u03c2",
+"Cell properties": "\u0399\u03b4\u03b9\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2 \u03ba\u03b5\u03bb\u03b9\u03bf\u03cd",
+"Left": "\u0391\u03c1\u03b9\u03c3\u03c4\u03b5\u03c1\u03ac",
+"Cut row": "\u0391\u03c0\u03bf\u03ba\u03bf\u03c0\u03ae \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2",
+"Delete column": "\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03c3\u03c4\u03ae\u03bb\u03b7\u03c2",
+"Center": "\u039a\u03b5\u03bd\u03c4\u03c1\u03b1\u03c1\u03b9\u03c3\u03bc\u03ad\u03bd\u03b7",
+"Merge cells": "\u03a3\u03c5\u03b3\u03c7\u03ce\u03bd\u03b5\u03c5\u03c3\u03b7 \u03ba\u03b5\u03bb\u03b9\u03ce\u03bd",
+"Insert template": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03c0\u03c1\u03bf\u03c4\u03cd\u03c0\u03bf\u03c5 ",
+"Templates": "\u03a0\u03c1\u03cc\u03c4\u03c5\u03c0\u03b1",
+"Background color": "\u03a7\u03c1\u03ce\u03bc\u03b1 \u03c6\u03cc\u03bd\u03c4\u03bf\u03c5",
+"Text color": "\u03a7\u03c1\u03ce\u03bc\u03b1 \u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5 ",
+"Show blocks": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03c4\u03bc\u03b7\u03bc\u03ac\u03c4\u03c9\u03bd",
+"Show invisible characters": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03b1\u03cc\u03c1\u03b1\u03c4\u03bf\u03bd \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03ae\u03c1\u03c9\u03bd",
+"Words: {0}": "\u039b\u03b5\u03be\u03b5\u03b9\u03c2: {0}",
+"Insert": "\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03b7",
+"File": "\u0391\u03c1\u03c7\u03b5\u03af\u03bf",
+"Edit": "\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03b9\u03b1",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rich Text Area. \u03a0\u03b1\u03c4\u03b7\u03c3\u03c4\u03b5 ALT-F9 \u03b3\u03b9\u03b1 \u03bc\u03b5\u03bd\u03bf\u03c5. \u03a0\u03b1\u03c4\u03b7\u03c3\u03c4\u03b5 ALT-F10 \u03b3\u03b9\u03b1 toolbar. \u03a0\u03b1\u03c4\u03b7\u03c3\u03c4\u03b5 ALT-0 \u03b3\u03b9\u03b1 \u03b2\u03bf\u03b7\u03b8\u03b5\u03b9\u03b1",
+"Tools": "\u0395\u03c1\u03b3\u03b1\u03bb\u03b5\u03b9\u03b1",
+"View": "\u0395\u03bc\u03c6\u03b1\u03bd\u03b9\u03c3\u03b7",
+"Table": "\u03a4\u03b1\u03bc\u03c0\u03b5\u03bb\u03b1",
+"Format": "\u03a4\u03c5\u03c0\u03bf\u03c2"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/es.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/es.js
new file mode 100755
index 0000000..a769617
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/es.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('es',{
+"Cut": "Cortar",
+"Header 2": "Header 2 ",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Tu navegador no soporta acceso directo al portapapeles. Por favor usa las teclas Crtl+X\/C\/V de tu teclado",
+"Div": "Capa",
+"Paste": "Pegar",
+"Close": "Cerrar",
+"Pre": "Pre",
+"Align right": "Alinear a la derecha",
+"New document": "Nuevo documento",
+"Blockquote": "Bloque de cita",
+"Numbered list": "Lista numerada",
+"Increase indent": "Incrementar sangr\u00eda",
+"Formats": "Formatos",
+"Headers": "Headers",
+"Select all": "Seleccionar todo",
+"Header 3": "Header 3",
+"Blocks": "Bloques",
+"Undo": "Deshacer",
+"Strikethrough": "Tachado",
+"Bullet list": "Lista de vi\u00f1etas",
+"Header 1": "Header 1",
+"Superscript": "Super\u00edndice",
+"Clear formatting": "Limpiar formato",
+"Subscript": "Sub\u00edndice",
+"Header 6": "Header 6",
+"Redo": "Rehacer",
+"Paragraph": "P\u00e1rrafo",
+"Ok": "Ok",
+"Bold": "Negrita",
+"Code": "C\u00f3digo",
+"Italic": "It\u00e1lica",
+"Align center": "Alinear al centro",
+"Header 5": "Header 5 ",
+"Decrease indent": "Disminuir sangr\u00eda",
+"Header 4": "Header 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Pegar est\u00e1 ahora en modo de texto plano. El contenido se pegar\u00e1 como texto plano hasta que desactive esta opci\u00f3n.",
+"Underline": "Subrayado",
+"Cancel": "Cancelar",
+"Justify": "Justificar",
+"Inline": "en l\u00ednea",
+"Copy": "Copiar",
+"Align left": "Alinear a la izquierda",
+"Visual aids": "Ayudas visuales",
+"Lower Greek": "Inferior Griega",
+"Square": "Cuadrado",
+"Default": "Por defecto",
+"Lower Alpha": "Inferior Alfa",
+"Circle": "C\u00edrculo",
+"Disc": "Disco",
+"Upper Alpha": "Superior Alfa",
+"Upper Roman": "Superior Romana",
+"Lower Roman": "Inferior Romana",
+"Name": "Nombre",
+"Anchor": "Ancla",
+"You have unsaved changes are you sure you want to navigate away?": "Tiene cambios sin guardar. \u00bfEst\u00e1 seguro de que quiere salir fuera?",
+"Restore last draft": "Restaurar el \u00faltimo borrador",
+"Special character": "Car\u00e1cter especial",
+"Source code": "C\u00f3digo fuente",
+"Right to left": "De derecha a izquierda",
+"Left to right": "De izquierda a derecha",
+"Emoticons": "Emoticonos",
+"Robots": "Robots",
+"Document properties": "Propiedades del documento",
+"Title": "T\u00edtulo",
+"Keywords": "Palabras clave",
+"Encoding": "Codificaci\u00f3n",
+"Description": "Descripci\u00f3n",
+"Author": "Autor",
+"Fullscreen": "Pantalla completa",
+"Horizontal line": "L\u00ednea horizontal",
+"Horizontal space": "Espacio horizontal",
+"Insert\/edit image": "Insertar\/editar imagen",
+"General": "General",
+"Advanced": "Avanzado",
+"Source": "Origen",
+"Border": "Borde",
+"Constrain proportions": "Restringir proporciones",
+"Vertical space": "Espacio vertical",
+"Image description": "Descripci\u00f3n de la imagen",
+"Style": "Estilo",
+"Dimensions": "Dimensiones",
+"Insert image": "Insertar imagen",
+"Insert date\/time": "Insertar fecha\/hora",
+"Remove link": "Quitar enlace",
+"Url": "Url",
+"Text to display": "Texto para mostrar",
+"Anchors": "Anclas",
+"Insert link": "Insertar enlace",
+"New window": "Nueva ventana",
+"None": "Ninguno",
+"Target": "Destino",
+"Insert\/edit link": "Insertar\/editar enlace",
+"Insert\/edit video": "Insertar\/editar video",
+"Poster": "Miniatura",
+"Alternative source": "Fuente alternativa",
+"Paste your embed code below:": "Pega tu c\u00f3digo embebido debajo",
+"Insert video": "Insertar video",
+"Embed": "Incrustado",
+"Nonbreaking space": "Espacio fijo",
+"Page break": "Salto de p\u00e1gina",
+"Paste as text": "Pegar como texto",
+"Preview": "Previsualizar",
+"Print": "Imprimir",
+"Save": "Guardar",
+"Could not find the specified string.": "No se encuentra la cadena de texto especificada",
+"Replace": "Reemplazar",
+"Next": "Siguiente",
+"Whole words": "Palabras completas",
+"Find and replace": "Buscar y reemplazar",
+"Replace with": "Reemplazar con",
+"Find": "Buscar",
+"Replace all": "Reemplazar todo",
+"Match case": "Coincidencia exacta",
+"Prev": "Anterior",
+"Spellcheck": "Corrector ortogr\u00e1fico",
+"Finish": "Finalizar",
+"Ignore all": "Ignorar todos",
+"Ignore": "Ignorar",
+"Insert row before": "Insertar fila antes",
+"Rows": "Filas",
+"Height": "Alto",
+"Paste row after": "Pegar la fila despu\u00e9s",
+"Alignment": "Alineaci\u00f3n",
+"Column group": "Grupo de columnas",
+"Row": "Fila",
+"Insert column before": "Insertar columna antes",
+"Split cell": "Dividir celdas",
+"Cell padding": "Relleno de celda",
+"Cell spacing": "Espacio entre celdas",
+"Row type": "Tipo de fila",
+"Insert table": "Insertar tabla",
+"Body": "Cuerpo",
+"Caption": "Subt\u00edtulo",
+"Footer": "Pie de p\u00e1gina",
+"Delete row": "Eliminar fila",
+"Paste row before": "Pegar la fila antes",
+"Scope": "\u00c1mbito",
+"Delete table": "Eliminar tabla",
+"Header cell": "Celda de la cebecera",
+"Column": "Columna",
+"Cell": "Celda",
+"Header": "Cabecera",
+"Cell type": "Tipo de celda",
+"Copy row": "Copiar fila",
+"Row properties": "Propiedades de la fila",
+"Table properties": "Propiedades de la tabla",
+"Row group": "Grupo de filas",
+"Right": "Derecha",
+"Insert column after": "Insertar columna despu\u00e9s",
+"Cols": "Columnas",
+"Insert row after": "Insertar fila despu\u00e9s ",
+"Width": "Ancho",
+"Cell properties": "Propiedades de la celda",
+"Left": "Izquierda",
+"Cut row": "Cortar fila",
+"Delete column": "Eliminar columna",
+"Center": "Centrado",
+"Merge cells": "Combinar celdas",
+"Insert template": "Insertar plantilla",
+"Templates": "Plantillas",
+"Background color": "Color de fondo",
+"Text color": "Color del texto",
+"Show blocks": "Mostrar bloques",
+"Show invisible characters": "Mostrar caracteres invisibles",
+"Words: {0}": "Palabras: {0}",
+"Insert": "Insertar",
+"File": "Archivo",
+"Edit": "Editar",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u00c1rea de texto enriquecido. Pulse ALT-F9 para el menu. Pulse ALT-F10 para la barra de herramientas. Pulse ALT-0 para ayuda",
+"Tools": "Herramientas",
+"View": "Ver",
+"Table": "Tabla",
+"Format": "Formato"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/et.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/et.js
new file mode 100755
index 0000000..d7f9f07
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/et.js
@@ -0,0 +1,173 @@
+tinymce.addI18n('et',{
+"Cut": "L\u00f5ika",
+"Header 2": "Pealkiri 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Sinu veebilehitseja ei toeta otsest ligip\u00e4\u00e4su l\u00f5ikelauale. Palun kasuta selle asemel klaviatuuri kiirk\u00e4sklusi Ctrl+X\/C\/V.",
+"Div": "Sektsioon",
+"Paste": "Kleebi",
+"Close": "Sulge",
+"Pre": "Eelvormindatud",
+"Align right": "Joonda paremale",
+"New document": "Uus dokument",
+"Blockquote": "Plokktsitaat",
+"Numbered list": "J\u00e4rjestatud loend",
+"Increase indent": "Suurenda taanet",
+"Formats": "Vormingud",
+"Headers": "P\u00e4ised",
+"Select all": "Vali k\u00f5ik",
+"Header 3": "Pealkiri 3",
+"Blocks": "Plokid",
+"Undo": "V\u00f5ta tagasi",
+"Strikethrough": "L\u00e4bikriipsutatud",
+"Bullet list": "J\u00e4rjestamata loend",
+"Header 1": "Pealkiri 1",
+"Superscript": "\u00dclaindeks",
+"Clear formatting": "Puhasta vorming",
+"Subscript": "Alaindeks",
+"Header 6": "Pealkiri 6",
+"Redo": "Tee uuesti",
+"Paragraph": "L\u00f5ik",
+"Ok": "Ok",
+"Bold": "Rasvane",
+"Code": "Kood",
+"Italic": "Kaldkiri",
+"Align center": "Joonda keskele",
+"Header 5": "Pealkiri 5",
+"Decrease indent": "V\u00e4henda taanet",
+"Header 4": "Pealkiri 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Kleepimine on n\u00fc\u00fcd lihtteksti re\u017eiimis. Sisu kleebitakse lihttekstina seni, kuni Sa selle valiku v\u00e4lja l\u00fclitad.",
+"Underline": "Allakriipsutatud",
+"Cancel": "Katkesta",
+"Justify": "Joonda r\u00f6\u00f6pselt",
+"Inline": "Reasisene",
+"Copy": "Kopeeri",
+"Align left": "Joonda vasakule",
+"Visual aids": "N\u00e4itevahendid",
+"Lower Greek": "Kreeka v\u00e4iket\u00e4hed (\u03b1, \u03b2, \u03b3)",
+"Square": "Ruut",
+"Default": "Vaikimisi",
+"Lower Alpha": "V\u00e4iket\u00e4hed (a, b, c)",
+"Circle": "Ring",
+"Disc": "Ketas",
+"Upper Alpha": "Suurt\u00e4hed (A, B, C)",
+"Upper Roman": "Rooma suurt\u00e4hed (I, II, III)",
+"Lower Roman": "Rooma v\u00e4iket\u00e4hed (i, ii, iii)",
+"Name": "Nimi",
+"Anchor": "Ankur",
+"You have unsaved changes are you sure you want to navigate away?": "Sul on salvestamata muudatusi. Oled Sa kindel, et soovid mujale navigeeruda?",
+"Restore last draft": "Taasta viimane mustand",
+"Special character": "Erim\u00e4rk",
+"Source code": "L\u00e4htekood",
+"Right to left": "Paremalt vasakule",
+"Left to right": "Vasakult paremale",
+"Emoticons": "Emotikonid",
+"Robots": "Robotid",
+"Document properties": "Dokumendi omadused",
+"Title": "Pealkiri",
+"Keywords": "M\u00e4rks\u00f5nad",
+"Encoding": "M\u00e4rgistik",
+"Description": "Kirjeldus",
+"Author": "Autor",
+"Fullscreen": "T\u00e4isekraan",
+"Horizontal line": "Horisontaaljoon",
+"Horizontal space": "Reavahe",
+"Insert\/edit image": "Lisa\/muuda pilt",
+"General": "\u00dcldine",
+"Advanced": "T\u00e4iendavad seaded",
+"Source": "Allikas",
+"Border": "\u00c4\u00e4ris",
+"Constrain proportions": "S\u00e4ilita kuvasuhe",
+"Vertical space": "P\u00fcstine vahe",
+"Image description": "Pildi kirjeldus",
+"Style": "Stiil",
+"Dimensions": "M\u00f5\u00f5tmed",
+"Insert image": "Lisa pilt",
+"Insert date\/time": "Lisa kuup\u00e4ev\/kellaaeg",
+"Remove link": "Eemalda link",
+"Url": "Viide (url)",
+"Text to display": "Kuvatav tekst",
+"Insert link": "Lisa link",
+"New window": "Uus aken",
+"None": "Puudub",
+"Target": "Sihtm\u00e4rk",
+"Insert\/edit link": "Lisa\/muuda link",
+"Insert\/edit video": "Lisa\/muuda video",
+"Poster": "Lisaja",
+"Alternative source": "Teine allikas",
+"Paste your embed code below:": "Kleebi oma manustamiskood siia alla:",
+"Insert video": "Lisa video",
+"Embed": "Manusta",
+"Nonbreaking space": "T\u00fchim\u00e4rk (nbsp)",
+"Page break": "Lehevahetus",
+"Preview": "Eelvaade",
+"Print": "Tr\u00fcki",
+"Save": "Salvesta",
+"Could not find the specified string.": "Ei suutnud leida etteantud s\u00f5net.",
+"Replace": "Asenda",
+"Next": "J\u00e4rg",
+"Whole words": "Terviks\u00f5nad",
+"Find and replace": "Otsi ja asenda",
+"Replace with": "Asendus",
+"Find": "Otsi",
+"Replace all": "Asenda k\u00f5ik",
+"Match case": "Erista suur- ja v\u00e4iket\u00e4hti",
+"Prev": "Eelm",
+"Spellcheck": "\u00d5igekirja kontroll",
+"Finish": "L\u00f5peta",
+"Ignore all": "Eira k\u00f5iki",
+"Ignore": "Eira",
+"Insert row before": "Lisa rida enne",
+"Rows": "Read",
+"Height": "K\u00f5rgus",
+"Paste row after": "Kleebi rida j\u00e4rele",
+"Alignment": "Joondus",
+"Column group": "Veergude r\u00fchm",
+"Row": "Rida",
+"Insert column before": "Lisa tulp enne",
+"Split cell": "T\u00fckelda lahter",
+"Cell padding": "Lahtri sisu ja tabeli \u00e4\u00e4rise vahe",
+"Cell spacing": "Lahtrivahe",
+"Row type": "Rea t\u00fc\u00fcp",
+"Insert table": "Lisa tabel",
+"Body": "P\u00f5hiosa",
+"Caption": "Alapealkiri",
+"Footer": "Jalus",
+"Delete row": "Kustuta rida",
+"Paste row before": "Kleebi rida enne",
+"Scope": "Ulatus",
+"Delete table": "Kustuta tabel",
+"Header cell": "P\u00e4islahter",
+"Column": "Tulp",
+"Cell": "Lahter",
+"Header": "P\u00e4is",
+"Cell type": "Lahtri t\u00fc\u00fcp",
+"Copy row": "Kopeeri rida",
+"Row properties": "Rea omadused",
+"Table properties": "Tabeli omadused",
+"Row group": "Ridade r\u00fchm",
+"Right": "Paremal",
+"Insert column after": "Lisa tulp j\u00e4rele",
+"Cols": "Veerud",
+"Insert row after": "Lisa rida j\u00e4rele",
+"Width": "Laius",
+"Cell properties": "Lahtri omadused",
+"Left": "Vasakul",
+"Cut row": "L\u00f5ika rida",
+"Delete column": "Kustuta tulp",
+"Center": "Keskel",
+"Merge cells": "\u00dchenda lahtrid",
+"Insert template": "Lisa mall",
+"Templates": "Mallid",
+"Background color": "Tausta v\u00e4rv",
+"Text color": "Teksti v\u00e4rv",
+"Show blocks": "N\u00e4ita plokke",
+"Show invisible characters": "N\u00e4ita peidetud m\u00e4rke",
+"Words: {0}": "S\u00f5nu: {0}",
+"Insert": "Sisesta",
+"File": "Fail",
+"Edit": "Muuda",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rikastatud teksti ala. Men\u00fc\u00fc jaoks vajuta ALT-F9. T\u00f6\u00f6riistariba jaoks vajuta ALT-F10. Abi saamiseks vajuta ALT-0.",
+"Tools": "T\u00f6\u00f6riistad",
+"View": "Vaade",
+"Table": "Tabel",
+"Format": "Vorming"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/eu.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/eu.js
new file mode 100755
index 0000000..3985de0
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/eu.js
@@ -0,0 +1,174 @@
+tinymce.addI18n('eu',{
+"Cut": "Ebaki",
+"Header 2": "2 Goiburua",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Zure nabigatzaileak ez du arbela zuzenean erabiltzeko euskarririk. Mesedez erabili CTRL+X\/C\/V teklatuko lasterbideak.",
+"Div": "Div",
+"Paste": "Itsatsi",
+"Close": "Itxi",
+"Pre": "Pre",
+"Align right": "Lerrokatu eskuinean",
+"New document": "Dokumentu berria",
+"Blockquote": "Blockquote",
+"Numbered list": "Zerrenda zenbatua",
+"Increase indent": "Handitu koska",
+"Formats": "Formatuak",
+"Headers": "Goiburuak",
+"Select all": "Hautatu dena",
+"Header 3": "3 Goiburua",
+"Blocks": "Blokeak",
+"Undo": "Desegin",
+"Strikethrough": "Marratua",
+"Bullet list": "Bulet zerrenda",
+"Header 1": "1 Goiburua",
+"Superscript": "Goi-indize",
+"Clear formatting": "Garbitu formatua",
+"Subscript": "Azpiindize",
+"Header 6": "6 Goiburua",
+"Redo": "Berregin",
+"Paragraph": "Parrafoa",
+"Ok": "Ondo",
+"Bold": "Lodia",
+"Code": "Kodea",
+"Italic": "Etzana",
+"Align center": "Lerrokatu horizontalki erdian",
+"Header 5": "5 Goiburua",
+"Decrease indent": "Txikitu koska",
+"Header 4": "4 Goiburua",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Txertatzea testu formatu arruntean dago. Orain edukiak testu arrunt moduan txertatuko dira aukera hau kendu bitartean.",
+"Underline": "Azpimarratua",
+"Cancel": "Ezeztatu",
+"Justify": "Justifikatuta",
+"Inline": "Lerroan",
+"Copy": "Kopiatu",
+"Align left": "Lerrokatu ezkerrean",
+"Visual aids": "Laguntza bisualak",
+"Lower Greek": "Behe grekoa",
+"Square": "Karratua",
+"Default": "Lehenetstia",
+"Lower Alpha": "Behe alfa",
+"Circle": "Zirkulua",
+"Disc": "Diskoa",
+"Upper Alpha": "Goi alfa",
+"Upper Roman": "Goi erromatarra",
+"Lower Roman": "Behe erromatarra",
+"Name": "Izena",
+"Anchor": "Esteka",
+"You have unsaved changes are you sure you want to navigate away?": "Gorde gabeko aldaketak dituzu, zihur zaude hemendik irten nahi duzula?",
+"Restore last draft": "Leheneratu azken zirriborroa",
+"Special character": "Karaktere bereziak",
+"Source code": "Iturburu-kodea",
+"Right to left": "Eskuinetik ezkerrera",
+"Left to right": "Eskerretik eskuinera",
+"Emoticons": "Irrifartxoak",
+"Robots": "Robotak",
+"Document properties": "Dokumentuaren propietateak",
+"Title": "Titulua",
+"Keywords": "Hitz gakoak",
+"Encoding": "Encoding",
+"Description": "Deskribapena",
+"Author": "Egilea",
+"Fullscreen": "Pantaila osoa",
+"Horizontal line": "Marra horizontala",
+"Horizontal space": "Hutsune horizontala",
+"Insert\/edit image": "Irudia txertatu\/editatu",
+"General": "Orokorra",
+"Advanced": "Aurreratua",
+"Source": "Iturburua",
+"Border": "Bordea",
+"Constrain proportions": "Zerraditu proportzioak",
+"Vertical space": "Hutsune bertikala",
+"Image description": "Irudiaren deskribapena",
+"Style": "Estiloa",
+"Dimensions": "Neurriak",
+"Insert image": "Irudia txertatu",
+"Insert date\/time": "Data\/ordua txertatu",
+"Remove link": "Kendu esteka",
+"Url": "Url",
+"Text to display": "Bistaratzeko testua",
+"Anchors": "Estekak",
+"Insert link": "Esteka txertatu",
+"New window": "Lehio berria",
+"None": "Bat ere ez",
+"Target": "Target",
+"Insert\/edit link": "Esteka txertatu\/editatu",
+"Insert\/edit video": "Bideoa txertatu\/editatu",
+"Poster": "Poster-a",
+"Alternative source": "Iturburu alternatiboa",
+"Paste your embed code below:": "Itsatsi hemen zure enkapsulatzeko kodea:",
+"Insert video": "Bideoa txertatu",
+"Embed": "Kapsulatu",
+"Nonbreaking space": "Zuriune zatiezina",
+"Page break": "Orrialde-jauzia",
+"Preview": "Aurrebista",
+"Print": "Inprimatu",
+"Save": "Gorde",
+"Could not find the specified string.": "Ezin izan da zehaztutako katea aurkitu.",
+"Replace": "Ordeztu",
+"Next": "Hurrengoa",
+"Whole words": "hitz osoak",
+"Find and replace": "Bilatu eta ordeztu",
+"Replace with": "Honekin ordeztu",
+"Find": "Bilatu",
+"Replace all": "Ordeztu dena",
+"Match case": "Maiuskula\/minuskula",
+"Prev": "Aurrekoa",
+"Spellcheck": "Egiaztapenak",
+"Finish": "Amaitu",
+"Ignore all": "Ez ikusi guztia",
+"Ignore": "Ez ikusi",
+"Insert row before": "Txertatu errenkada aurretik",
+"Rows": "Errenkadak",
+"Height": "Altuera",
+"Paste row after": "Itsatsi errenkada ostean",
+"Alignment": "Lerrokatzea",
+"Column group": "Zutabe taldea",
+"Row": "Errenkada",
+"Insert column before": "Txertatu zutabe aurretik",
+"Split cell": "Gelaxkak banatu",
+"Cell padding": "Gelaxken betegarria",
+"Cell spacing": "Gelaxka arteko tartea",
+"Row type": "Lerro mota",
+"Insert table": "Txertatu taula",
+"Body": "Gorputza",
+"Caption": "Epigrafea",
+"Footer": "Oina",
+"Delete row": "Ezabatu errenkada",
+"Paste row before": "Itsatsi errenkada aurretik",
+"Scope": "Esparrua",
+"Delete table": "Taula ezabatu",
+"Header cell": "Goiburuko gelaxka",
+"Column": "Zutabea",
+"Cell": "Gelaxka",
+"Header": "Goiburua",
+"Cell type": "Gelaxka mota",
+"Copy row": "Kopiatu errenkada",
+"Row properties": "Errenkadaren propietateak",
+"Table properties": "Taularen propietateak",
+"Row group": "Lerro taldea",
+"Right": "Eskuma",
+"Insert column after": "Txertatu zutabea ostean",
+"Cols": "Zutabeak",
+"Insert row after": "Txertatu errenkada ostean",
+"Width": "Zabalera",
+"Cell properties": "Gelaxkaren propietateak",
+"Left": "Ezkerra",
+"Cut row": "Ebaki errenkada",
+"Delete column": "Ezabatu zutabea",
+"Center": "Erdia",
+"Merge cells": "Gelaxkak batu",
+"Insert template": "Txertatu txantiloia",
+"Templates": "Txantiloiak",
+"Background color": "Atzeko kolorea",
+"Text color": "Testuaren kolorea",
+"Show blocks": "Erakutsi blokeak",
+"Show invisible characters": "Erakutsi karaktere izkutuak",
+"Words: {0}": "Hitzak: {0}",
+"Insert": "Sartu",
+"File": "Fitxategia",
+"Edit": "Editatu",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Testu aberastuko area. Sakatu ALT-F9 menurako. Sakatu ALT-F10 tresna-barrarako. Sakatu ALT-0 laguntzarako",
+"Tools": "Tresnak",
+"View": "Ikusi",
+"Table": "Taula",
+"Format": "Formatua"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fa.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fa.js
new file mode 100755
index 0000000..a8fd76b
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fa.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('fa',{
+"Cut": "\u0628\u0631\u062f\u0627\u0634\u062a\u0646",
+"Header 2": "\u0633\u0631\u200c\u0635\u0641\u062d\u0647 \u06f2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u0645\u0631\u0648\u0631\u06af\u0631 \u0634\u0645\u0627 \u0627\u0632 \u062f\u0633\u062a\u0631\u0633\u06cc \u0645\u0633\u062a\u0642\u06cc\u0645 \u0628\u0647 \u062d\u0627\u0641\u0638\u0647 \u06a9\u067e\u06cc \u067e\u0634\u062a\u06cc\u0628\u0627\u0646\u06cc \u0646\u0645\u06cc \u06a9\u0646\u062f. \u0644\u0637\u0641\u0627 \u0627\u0632 \u06a9\u0644\u06cc\u062f \u0647\u0627\u06cc Ctrl+X\/C\/V \u062f\u0631 \u06a9\u06cc\u0628\u0648\u0631\u062f \u0628\u0631\u0627\u06cc \u0627\u06cc\u0646 \u06a9\u0627\u0631 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u06a9\u0646\u06cc\u062f.",
+"Div": "\u062a\u06af Div - \u0628\u062e\u0634",
+"Paste": "\u0686\u0633\u0628\u0627\u0646\u062f\u0646",
+"Close": "\u0628\u0633\u062a\u0646",
+"Pre": "\u062a\u06af Pre",
+"Align right": "\u0631\u0627\u0633\u062a \u0686\u06cc\u0646",
+"New document": "\u0633\u0646\u062f \u062c\u062f\u06cc\u062f",
+"Blockquote": "\u062a\u06af \u0646\u0642\u0644 \u0642\u0648\u0644 - Blockquote",
+"Numbered list": "\u0644\u06cc\u0633\u062a \u0634\u0645\u0627\u0631\u0647 \u0627\u06cc",
+"Increase indent": "\u0627\u0641\u0632\u0627\u06cc\u0634 \u062a\u0648 \u0631\u0641\u062a\u06af\u06cc",
+"Formats": "\u0642\u0627\u0644\u0628",
+"Headers": "\u0633\u0631\u200c\u0635\u0641\u062d\u0647\u200c\u0647\u0627",
+"Select all": "\u0627\u0646\u062a\u062e\u0627\u0628 \u0647\u0645\u0647",
+"Header 3": "\u0633\u0631\u200c\u0635\u0641\u062d\u0647 \u06f3",
+"Blocks": "\u0628\u0644\u0648\u06a9",
+"Undo": "\t\n\u0628\u0627\u0637\u0644 \u06a9\u0631\u062f\u0646",
+"Strikethrough": "\u062e\u0637 \u062e\u0648\u0631\u062f\u0647",
+"Bullet list": "\u0644\u06cc\u0633\u062a \u062f\u0627\u06cc\u0631\u0647 \u0627\u06cc",
+"Header 1": "\u0633\u0631\u200c\u0635\u0641\u062d\u0647 \u06f1",
+"Superscript": "\u0628\u0627\u0644\u0627\u0646\u0648\u06cc\u0633 - \u062d\u0627\u0644\u062a \u062a\u0648\u0627\u0646",
+"Clear formatting": "\u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u0642\u0627\u0644\u0628 \u0628\u0646\u062f\u06cc",
+"Subscript": "\u0632\u06cc\u0631 \u0646\u0648\u06cc\u0633 - \u062d\u0627\u0644\u062a \u0627\u0646\u062f\u06cc\u0633",
+"Header 6": "\u0633\u0631\u200c\u0635\u0641\u062d\u0647 \u06f6",
+"Redo": "\u0627\u0646\u062c\u0627\u0645 \u062f\u0648\u0628\u0627\u0631\u0647",
+"Paragraph": "\u062a\u06af \u067e\u0627\u0631\u0627\u06af\u0631\u0627\u0641 - Paragraph",
+"Ok": "\u0628\u0627\u0634\u0647",
+"Bold": "\u062f\u0631\u0634\u062a",
+"Code": "\u062a\u06af Code",
+"Italic": "\u062e\u0637 \u06a9\u062c",
+"Align center": "\u0648\u0633\u0637 \u0686\u06cc\u0646",
+"Header 5": "\u0633\u0631\u200c\u0635\u0641\u062d\u0647 \u06f5",
+"Decrease indent": "\u06a9\u0627\u0647\u0634 \u062a\u0648 \u0631\u0641\u062a\u06af\u06cc",
+"Header 4": "\u0633\u0631\u200c\u0635\u0641\u062d\u0647 \u06f4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0647\u0645 \u0627\u06a9\u0646\u0648\u0646 \u062f\u0631 \u062d\u0627\u0644\u062a \u0645\u062a\u0646 \u0633\u0627\u062f\u0647 \u0627\u0633\u062a. \u062a\u0627 \u0632\u0645\u0627\u0646\u06cc \u06a9\u0647 \u0627\u06cc\u0646 \u062d\u0627\u0644\u062a \u0631\u0627 \u063a\u06cc\u0631\u200c\u0641\u0639\u0627\u0644 \u0646\u06a9\u0646\u06cc\u062f\u060c \u0645\u062d\u062a\u0648\u0627 \u062f\u0631 \u062d\u0627\u0644\u062a \u0645\u062a\u0646 \u0633\u0627\u062f\u0647 \u0627\u0636\u0627\u0641\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f.",
+"Underline": "\u062e\u0637 \u0632\u06cc\u0631",
+"Cancel": "\u0644\u063a\u0648",
+"Justify": "\u0645\u0633\u0627\u0648\u06cc \u0627\u0632 \u0637\u0631\u0641\u06cc\u0646",
+"Inline": "\u062e\u0637\u06cc",
+"Copy": "\u06a9\u067e\u06cc",
+"Align left": "\u0686\u067e \u0686\u06cc\u0646",
+"Visual aids": "\u06a9\u0645\u06a9 \u0647\u0627\u06cc \u0628\u0635\u0631\u06cc",
+"Lower Greek": "\u06cc\u0648\u0646\u0627\u0646\u06cc \u06a9\u0648\u0686\u06a9",
+"Square": "\u0645\u0631\u0628\u0639",
+"Default": "\u067e\u06cc\u0634\u0641\u0631\u0636",
+"Lower Alpha": "\u0622\u0644\u0641\u0627\u0621 \u06a9\u0648\u0686\u06a9",
+"Circle": "\u062f\u0627\u06cc\u0631\u0647",
+"Disc": "\u062f\u06cc\u0633\u06a9",
+"Upper Alpha": "\u0622\u0644\u0641\u0627\u0621 \u0628\u0632\u0631\u06af",
+"Upper Roman": "\u0631\u0648\u0645\u06cc \u0628\u0632\u0631\u06af",
+"Lower Roman": "\u0631\u0648\u0645\u06cc \u06a9\u0648\u0686\u06a9",
+"Name": "\u0646\u0627\u0645",
+"Anchor": "\u0644\u0646\u06af\u0631 - \u0644\u06cc\u0646\u06a9",
+"You have unsaved changes are you sure you want to navigate away?": "\u0634\u0645\u0627 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u0630\u062e\u06cc\u0631\u0647 \u0646\u0634\u062f\u0647 \u0627\u06cc \u062f\u0627\u0631\u06cc\u062f\u060c \u0622\u06cc\u0627 \u0645\u0637\u0645\u0626\u0646\u06cc\u062f \u06a9\u0647 \u0645\u06cc\u062e\u0648\u0627\u0647\u06cc\u062f \u0627\u0632 \u0627\u06cc\u0646 \u0635\u0641\u062d\u0647 \u0628\u0631\u0648\u06cc\u062f\u061f",
+"Restore last draft": "\u0628\u0627\u0632\u06af\u0631\u062f\u0627\u0646\u062f\u0646 \u0622\u062e\u0631\u06cc\u0646 \u067e\u06cc\u0634 \u0646\u0648\u06cc\u0633",
+"Special character": "\u06a9\u0627\u0631\u0627\u06a9\u062a\u0631 \u0647\u0627\u06cc \u062e\u0627\u0635",
+"Source code": "\u06a9\u062f \u0645\u0646\u0628\u0639",
+"Right to left": "\u0631\u0627\u0633\u062a \u0628\u0647 \u0686\u067e",
+"Left to right": "\u0686\u067e \u0628\u0647 \u0631\u0627\u0633\u062a",
+"Emoticons": "\u0634\u06a9\u0644\u06a9\u200c\u0647\u0627",
+"Robots": "\u0631\u0628\u0627\u062a \u0647\u0627",
+"Document properties": "\u0648\u06cc\u0698\u06af\u06cc\u200c\u0647\u0627\u06cc \u0633\u0646\u062f",
+"Title": "\u0639\u0646\u0648\u0627\u0646",
+"Keywords": "\u06a9\u0644\u0645\u0627\u062a \u06a9\u0644\u06cc\u062f\u06cc",
+"Encoding": "\u0631\u0645\u0632\u06af\u0630\u0627\u0631\u06cc",
+"Description": "\u062a\u0648\u0636\u06cc\u062d\u0627\u062a",
+"Author": "\u0646\u0648\u06cc\u0633\u0646\u062f\u0647",
+"Fullscreen": "\u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647",
+"Horizontal line": "\u062e\u0637 \u0627\u0641\u0642\u06cc",
+"Horizontal space": "\u0641\u0636\u0627\u06cc \u0627\u0641\u0642\u06cc",
+"Insert\/edit image": "\u0627\u0636\u0627\u0641\u0647\/\u0648\u06cc\u0631\u0627\u06cc\u0634 \u06a9\u0631\u062f\u0646 \u062a\u0635\u0648\u06cc\u0631",
+"General": "\u06a9\u0644\u06cc",
+"Advanced": "\u067e\u06cc\u0634\u0631\u0641\u062a\u0647",
+"Source": "\u0645\u0646\u0628\u0639",
+"Border": "\u062d\u0627\u0634\u06cc\u0647",
+"Constrain proportions": "\u062a\u0646\u0627\u0633\u0628",
+"Vertical space": "\u0641\u0636\u0627\u06cc \u0639\u0645\u0648\u062f\u06cc",
+"Image description": "\u062a\u0648\u0636\u06cc\u062d\u0627\u062a \u0639\u06a9\u0633",
+"Style": "\u0633\u0628\u06a9",
+"Dimensions": "\u0627\u0628\u0639\u0627\u062f",
+"Insert image": "\u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646 \u062a\u0635\u0648\u06cc\u0631",
+"Insert date\/time": "\u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646 \u062a\u0627\u0631\u06cc\u062e\/\u0632\u0645\u0627\u0646",
+"Remove link": "\u062d\u0630\u0641 \u0644\u06cc\u0646\u06a9",
+"Url": "\u0627\u062f\u0631\u0633 \u0644\u06cc\u0646\u06a9",
+"Text to display": "\u0645\u062a\u0646 \u0628\u0631\u0627\u06cc \u0646\u0645\u0627\u06cc\u0634",
+"Anchors": "\u0644\u0646\u06af\u0631 - \u0644\u06cc\u0646\u06a9 \u062f\u0627\u062e\u0644 \u0635\u0641\u062d\u0647",
+"Insert link": "\u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646 \u0644\u06cc\u0646\u06a9",
+"New window": "\u067e\u0646\u062c\u0631\u0647 \u062c\u062f\u06cc\u062f",
+"None": "\u0647\u06cc\u0686 \u06a9\u062f\u0627\u0645",
+"Target": "\u0646\u062d\u0648\u0647 \u0628\u0627\u0632 \u0634\u062f\u0646 \u062f\u0631 \u0645\u0631\u0648\u0631\u06af\u0631",
+"Insert\/edit link": "\u0627\u0636\u0627\u0641\u0647\/\u0648\u06cc\u0631\u0627\u06cc\u0634 \u06a9\u0631\u062f\u0646 \u0644\u06cc\u0646\u06a9",
+"Insert\/edit video": "\u0642\u0631\u0627\u0631\u062f\u0627\u062f\u0646\/\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0641\u0627\u06cc\u0644 \u062a\u0635\u0648\u06cc\u0631\u06cc",
+"Poster": "\u067e\u0648\u0633\u062a\u0631",
+"Alternative source": "\u0645\u0646\u0628\u0639 \u062f\u06cc\u06af\u0631",
+"Paste your embed code below:": "\u06a9\u062f \u062c\u0627 \u062f\u0627\u062f\u0646 - embed - \u062e\u0648\u062f \u0631\u0627 \u062f\u0631 \u0632\u06cc\u0631 \u0642\u0631\u0627\u0631 \u062f\u0647\u06cc\u062f:",
+"Insert video": "\u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646 \u0641\u0627\u06cc\u0644 \u062a\u0635\u0648\u06cc\u0631\u06cc",
+"Embed": "\u062c\u0627 \u062f\u0627\u062f\u0646",
+"Nonbreaking space": "\u0641\u0636\u0627\u06cc \u063a\u06cc\u0631 \u0634\u06a9\u0633\u062a\u0646",
+"Page break": "\u0634\u06a9\u0633\u062a\u0646 \u0635\u0641\u062d\u0647",
+"Paste as text": "\u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0628\u0647 \u0639\u0646\u0648\u0627\u0646 \u0645\u062a\u0646",
+"Preview": "\u067e\u06cc\u0634 \u0646\u0645\u0627\u06cc\u0634",
+"Print": "\u0686\u0627\u067e",
+"Save": "\u0630\u062e\u06cc\u0631\u0647",
+"Could not find the specified string.": "\u0631\u0634\u062a\u0647 \u0645\u062a\u0646\u06cc \u0645\u0634\u062e\u0635 \u0634\u062f\u0647 \u067e\u06cc\u062f\u0627 \u0646\u0634\u062f.",
+"Replace": "\u062c\u0627 \u0628\u0647 \u062c\u0627 \u06a9\u0631\u062f\u0646",
+"Next": "\u0628\u0639\u062f\u06cc",
+"Whole words": "\u0647\u0645\u0647 \u06a9\u0644\u0645\u0647 \u0647\u0627",
+"Find and replace": "\u067e\u06cc\u062f\u0627 \u06a9\u0631\u062f\u0646 \u0648 \u062c\u0627 \u0628\u0647 \u062c\u0627 \u06a9\u0631\u062f\u0646",
+"Replace with": "\u062c\u0627 \u0628\u0647 \u062c\u0627 \u06a9\u0631\u062f\u0646 \u0628\u0627",
+"Find": "\u062c\u0633\u062a \u0648 \u062c\u0648",
+"Replace all": "\u062c\u0627 \u0628\u0647 \u062c\u0627 \u06a9\u0631\u062f\u0646 \u0647\u0645\u0647",
+"Match case": "\u0645\u0648\u0627\u0631\u062f \u067e\u06cc\u062f\u0627 \u0634\u062f\u0647",
+"Prev": "\u0642\u0628\u0644\u06cc",
+"Spellcheck": "\u0628\u0631\u0631\u0633\u06cc \u0627\u0645\u0644\u0627\u06cc\u06cc",
+"Finish": "\u067e\u0627\u06cc\u0627\u0646",
+"Ignore all": "\u0646\u0627\u062f\u06cc\u062f\u0647 \u06af\u0631\u0641\u062a\u0646 \u0647\u0645\u0647",
+"Ignore": "\u0646\u0627\u062f\u06cc\u062f\u0647 \u06af\u0631\u0641\u062a\u0646",
+"Insert row before": "\u0633\u0637\u0631 \u062c\u062f\u06cc\u062f\u060c \u067e\u06cc\u0634 \u0627\u0632 \u0627\u06cc\u0646 \u0633\u0637\u0631",
+"Rows": "\u062a\u0639\u062f\u0627\u062f \u0633\u0637\u0631",
+"Height": "\u0627\u0631\u062a\u0641\u0627\u0639",
+"Paste row after": "\u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0633\u0637\u0631\u060c \u0628\u0639\u062f \u0627\u0632 \u0627\u06cc\u0646 \u0633\u0637\u0631",
+"Alignment": "\u0631\u062f\u06cc\u0641 \u0628\u0646\u062f\u06cc \u0646\u0648\u0634\u062a\u0647",
+"Column group": "\u06af\u0631\u0648\u0647 \u0633\u062a\u0648\u0646",
+"Row": "\u0633\u0637\u0631",
+"Insert column before": "\u0633\u062a\u0648\u0646 \u062c\u062f\u06cc\u062f\u060c \u0642\u0628\u0644 \u0627\u0632 \u0627\u06cc\u0646 \u0633\u062a\u0648\u0646",
+"Split cell": "\u062a\u0642\u0633\u06cc\u0645 \u0633\u0644\u0648\u0644 \u062c\u062f\u0648\u0644",
+"Cell padding": "\u062d\u0627\u0634\u06cc\u0647 \u0633\u0644\u0648\u0644\u0647\u0627",
+"Cell spacing": "\u0641\u0627\u0635\u0644\u0647\u200c\u06cc \u0628\u06cc\u0646 \u0633\u0644\u0648\u0644\u0647\u0627",
+"Row type": "\u0646\u0648\u0639 \u0633\u0637\u0631",
+"Insert table": "\u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646 \u062c\u062f\u0648\u0644",
+"Body": "\u0628\u062f\u0646\u0647",
+"Caption": "\u0639\u0646\u0648\u0627\u0646",
+"Footer": "\u067e\u0627\u0646\u0648\u06cc\u0633",
+"Delete row": "\u062d\u0630\u0641 \u0633\u0637\u0631",
+"Paste row before": "\u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0633\u0637\u0631\u060c \u0642\u0628\u0644 \u0627\u0632 \u0627\u06cc\u0646 \u0633\u0637\u0631",
+"Scope": "\u0645\u062d\u062f\u0648\u062f\u0647\u200c\u06cc \u0639\u0646\u0648\u0627\u0646",
+"Delete table": "\u062d\u0630\u0641 \u062c\u062f\u0648\u0644",
+"Header cell": "\u0633\u0631\u0622\u06cc\u0646\u062f \u0633\u0644\u0648\u0644",
+"Column": "\u0633\u062a\u0648\u0646",
+"Cell": "\u0633\u0644\u0648\u0644",
+"Header": "\u0633\u0631\u0622\u06cc\u0646\u062f",
+"Cell type": "\u0646\u0648\u0639 \u0633\u0644\u0648\u0644",
+"Copy row": "\u06a9\u067e\u06cc \u0633\u0637\u0631",
+"Row properties": "\u0648\u06cc\u0698\u06af\u06cc\u0647\u0627\u06cc \u0633\u0637\u0631",
+"Table properties": "\u0648\u06cc\u0698\u06af\u06cc\u0647\u0627\u06cc \u062c\u062f\u0648\u0644",
+"Row group": "\u06af\u0631\u0648\u0647 \u0633\u0637\u0631",
+"Right": "\u0631\u0627\u0633\u062a",
+"Insert column after": "\u0633\u062a\u0648\u0646 \u062c\u062f\u06cc\u062f \u0628\u0639\u062f \u0627\u0632 \u0627\u06cc\u0646 \u0633\u062a\u0648\u0646",
+"Cols": "\u062a\u0639\u062f\u0627\u062f \u0633\u062a\u0648\u0646",
+"Insert row after": "\u0633\u0637\u0631 \u062c\u062f\u06cc\u062f\u060c \u067e\u0633 \u0627\u0632 \u0627\u06cc\u0646 \u0633\u0637\u0631",
+"Width": "\u0639\u0631\u0636",
+"Cell properties": "\u0648\u06cc\u0698\u06af\u06cc\u0647\u0627\u06cc \u0633\u0644\u0648\u0644",
+"Left": "\u0686\u067e",
+"Cut row": "\u0628\u0631\u062f\u0627\u0634\u062a\u0646 \u0633\u0637\u0631",
+"Delete column": "\u062d\u0630\u0641 \u0633\u062a\u0648\u0646",
+"Center": "\u0645\u0631\u06a9\u0632",
+"Merge cells": "\u0627\u062f\u063a\u0627\u0645 \u0633\u0644\u0648\u0644\u0647\u0627",
+"Insert template": "\u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646 \u0627\u0644\u06af\u0648",
+"Templates": "\u0627\u0644\u06af\u0648\u200c\u0647\u0627",
+"Background color": "\u0631\u0646\u06af \u0632\u0645\u06cc\u0646\u0647 \u0645\u062a\u0646",
+"Text color": "\u0631\u0646\u06af \u0645\u062a\u0646",
+"Show blocks": "\u0646\u0645\u0627\u06cc\u0634 \u0628\u062e\u0634\u200c\u0647\u0627",
+"Show invisible characters": "\u0646\u0645\u0627\u06cc\u0634 \u06a9\u0627\u0631\u0627\u06a9\u062a\u0631\u0647\u0627\u06cc \u063a\u06cc\u0631 \u0642\u0627\u0628\u0644 \u0686\u0627\u067e",
+"Words: {0}": "\u06a9\u0644\u0645\u0627\u062a : {0}",
+"Insert": "\u0642\u0631\u0627\u0631 \u062f\u0627\u062f\u0646",
+"File": "\u067e\u0631\u0648\u0646\u062f\u0647",
+"Edit": "\u0648\u06cc\u0631\u0627\u06cc\u0634",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u0648\u06cc\u0631\u0627\u06cc\u0634\u06af\u0631 \u067e\u06cc\u0634\u0631\u0641\u062a\u0647\u200c\u06cc \u0645\u062a\u0646. \u0628\u0631\u0627\u06cc \u062f\u0633\u062a\u0631\u0633\u06cc \u0628\u0647 \u0645\u0646\u0648 \u06a9\u0644\u06cc\u062f\u0647\u0627\u06cc ALT-F9\u060c \u0646\u0648\u0627\u0631 \u0627\u0628\u0632\u0627\u0631 ALT-F10 \u0648 \u0628\u0631\u0627\u06cc \u0645\u0634\u0627\u0647\u062f\u0647\u200c\u06cc \u0631\u0627\u0647\u0646\u0645\u0627 ALT-0 \u0631\u0627 \u0641\u0634\u0627\u0631 \u062f\u0647\u06cc\u062f.",
+"Tools": "\u0627\u0628\u0632\u0627\u0631\u0647\u0627",
+"View": "\u0646\u0645\u0627\u06cc\u0634",
+"Table": "\u062c\u062f\u0648\u0644",
+"Format": "\u0642\u0627\u0644\u0628"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fi.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fi.js
new file mode 100755
index 0000000..d5565d3
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fi.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('fi',{
+"Cut": "Leikkaa",
+"Header 2": "Otsikko 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Selaimesi ei tue leikekirjan suoraa k\u00e4ytt\u00e4mist\u00e4. Ole hyv\u00e4 ja k\u00e4yt\u00e4 n\u00e4pp\u00e4imist\u00f6n Ctrl+X ja Ctrl+V n\u00e4pp\u00e4inyhdistelmi\u00e4.",
+"Div": "Div",
+"Paste": "Liit\u00e4",
+"Close": "Sulje",
+"Pre": "Esimuotoiltu",
+"Align right": "Tasaa oikealle",
+"New document": "Uusi dokumentti",
+"Blockquote": "Lainauslogko",
+"Numbered list": "J\u00e4rjestetty lista",
+"Increase indent": "Loitonna",
+"Formats": "Muotoilut",
+"Headers": "Otsikot",
+"Select all": "Valitse kaikki",
+"Header 3": "Otsikko 3",
+"Blocks": "Lohkot",
+"Undo": "Peru",
+"Strikethrough": "Yliviivaus",
+"Bullet list": "J\u00e4rjest\u00e4m\u00e4t\u00f6n lista",
+"Header 1": "Otsikko 1",
+"Superscript": "Yl\u00e4indeksi",
+"Clear formatting": "Poista muotoilu",
+"Subscript": "Alaindeksi",
+"Header 6": "Otsikko 6",
+"Redo": "Tee uudelleen",
+"Paragraph": "Kappale",
+"Ok": "Ok",
+"Bold": "Lihavointi",
+"Code": "Koodi",
+"Italic": "Kursivointi",
+"Align center": "Keskit\u00e4",
+"Header 5": "Otsikko 5",
+"Decrease indent": "Sisenn\u00e4",
+"Header 4": "Otsikko 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Liitt\u00e4minen on nyt pelk\u00e4n tekstin -tilassa. Sis\u00e4ll\u00f6t liitet\u00e4\u00e4n nyt pelkk\u00e4n\u00e4 tekstin\u00e4, kunnes otat vaihtoehdon pois k\u00e4yt\u00f6st\u00e4.",
+"Underline": "Alleviivaus",
+"Cancel": "Peruuta",
+"Justify": "Tasaa",
+"Inline": "Samalla rivill\u00e4",
+"Copy": "Kopioi",
+"Align left": "Tasaa vasemmalle",
+"Visual aids": "Visuaaliset neuvot",
+"Lower Greek": "pienet kirjaimet: \u03b1, \u03b2, \u03b3",
+"Square": "Neli\u00f6",
+"Default": "Oletus",
+"Lower Alpha": "pienet kirjaimet: a, b, c",
+"Circle": "Pallo",
+"Disc": "Ympyr\u00e4",
+"Upper Alpha": "isot kirjaimet: A, B, C",
+"Upper Roman": "isot kirjaimet: I, II, III",
+"Lower Roman": "pienet kirjaimet: i, ii, iii",
+"Name": "Nimi",
+"Anchor": "Ankkuri",
+"You have unsaved changes are you sure you want to navigate away?": "Sinulla on tallentamattomia muutoksia, haluatko varmasti siirty\u00e4 toiselle sivulle?",
+"Restore last draft": "Palauta aiempi luonnos",
+"Special character": "Erikoismerkki",
+"Source code": "L\u00e4hdekoodi",
+"Right to left": "Oikealta vasemmalle",
+"Left to right": "Vasemmalta oikealle",
+"Emoticons": "Hymi\u00f6t",
+"Robots": "Robotit",
+"Document properties": "Dokumentin ominaisuudet",
+"Title": "Otsikko",
+"Keywords": "Avainsanat",
+"Encoding": "Merkist\u00f6",
+"Description": "Kuvaus",
+"Author": "Tekij\u00e4",
+"Fullscreen": "Koko ruutu",
+"Horizontal line": "Vaakasuora viiva",
+"Horizontal space": "Horisontaalinen tila",
+"Insert\/edit image": "Lis\u00e4\u00e4\/muokkaa kuva",
+"General": "Yleiset",
+"Advanced": "Lis\u00e4asetukset",
+"Source": "L\u00e4hde",
+"Border": "Reunus",
+"Constrain proportions": "S\u00e4ilyt\u00e4 mittasuhteet",
+"Vertical space": "Vertikaalinen tila",
+"Image description": "Kuvaus",
+"Style": "Tyyli",
+"Dimensions": "Mittasuhteet",
+"Insert image": "Lis\u00e4\u00e4 kuva",
+"Insert date\/time": "Lis\u00e4\u00e4 p\u00e4iv\u00e4m\u00e4\u00e4r\u00e4 tai aika",
+"Remove link": "Poista linkki",
+"Url": "Osoite",
+"Text to display": "N\u00e4ytett\u00e4v\u00e4 teksti",
+"Anchors": "Ankkurit",
+"Insert link": "Lis\u00e4\u00e4 linkki",
+"New window": "Uusi ikkuna",
+"None": "Ei mit\u00e4\u00e4n",
+"Target": "Kohde",
+"Insert\/edit link": "Lis\u00e4\u00e4 tai muokkaa linkki",
+"Insert\/edit video": "Lis\u00e4\u00e4 tai muokkaa video",
+"Poster": "L\u00e4hett\u00e4j\u00e4",
+"Alternative source": "Vaihtoehtoinen l\u00e4hde",
+"Paste your embed code below:": "Liit\u00e4 upotuskoodisi alapuolelle:",
+"Insert video": "Lis\u00e4\u00e4 video",
+"Embed": "Upota",
+"Nonbreaking space": "Tyhj\u00e4 merkki (nbsp)",
+"Page break": "Sivunvaihto",
+"Paste as text": "Liit\u00e4 tekstin\u00e4",
+"Preview": "Esikatselu",
+"Print": "Tulosta",
+"Save": "Tallenna",
+"Could not find the specified string.": "Haettua merkkijonoa ei l\u00f6ytynyt.",
+"Replace": "Korvaa",
+"Next": "Seur.",
+"Whole words": "Koko sanat",
+"Find and replace": "Etsi ja korvaa",
+"Replace with": "Korvaa",
+"Find": "Etsi",
+"Replace all": "Korvaa kaikki",
+"Match case": "Erota isot ja pienet kirjaimet",
+"Prev": "Edel.",
+"Spellcheck": "Oikolue",
+"Finish": "Lopeta",
+"Ignore all": "\u00c4l\u00e4 huomioi mit\u00e4\u00e4n",
+"Ignore": "\u00c4l\u00e4 huomioi",
+"Insert row before": "Lis\u00e4\u00e4 rivi ennen",
+"Rows": "Rivit",
+"Height": "Korkeus",
+"Paste row after": "Liit\u00e4 rivi j\u00e4lkeen",
+"Alignment": "Tasaus",
+"Column group": "Sarakeryhm\u00e4",
+"Row": "Rivi",
+"Insert column before": "Lis\u00e4\u00e4 rivi ennen",
+"Split cell": "Jaa solu",
+"Cell padding": "Solun tyhj\u00e4 tila",
+"Cell spacing": "Solun v\u00e4li",
+"Row type": "Rivityyppi",
+"Insert table": "Lis\u00e4\u00e4 taulukko",
+"Body": "Runko",
+"Caption": "Seloste",
+"Footer": "Alaosa",
+"Delete row": "Poista rivi",
+"Paste row before": "Liit\u00e4 rivi ennen",
+"Scope": "Laajuus",
+"Delete table": "Poista taulukko",
+"Header cell": "Otsikkosolu",
+"Column": "Sarake",
+"Cell": "Solu",
+"Header": "Otsikko",
+"Cell type": "Solun tyyppi",
+"Copy row": "Kopioi rivi",
+"Row properties": "Rivin ominaisuudet",
+"Table properties": "Taulukon ominaisuudet",
+"Row group": "Riviryhm\u00e4",
+"Right": "Oikea",
+"Insert column after": "Lis\u00e4\u00e4 rivi j\u00e4lkeen",
+"Cols": "Sarakkeet",
+"Insert row after": "Lis\u00e4\u00e4 rivi j\u00e4lkeen",
+"Width": "Leveys",
+"Cell properties": "Solun ominaisuudet",
+"Left": "Vasen",
+"Cut row": "Leikkaa rivi",
+"Delete column": "Poista sarake",
+"Center": "Keskell\u00e4",
+"Merge cells": "Yhdist\u00e4 solut",
+"Insert template": "Lis\u00e4\u00e4 pohja",
+"Templates": "Pohjat",
+"Background color": "Taustan v\u00e4ri",
+"Text color": "Tekstin v\u00e4ri",
+"Show blocks": "N\u00e4yt\u00e4 lohkot",
+"Show invisible characters": "N\u00e4yt\u00e4 n\u00e4kym\u00e4tt\u00f6m\u00e4t merkit",
+"Words: {0}": "Sanat: {0}",
+"Insert": "Lis\u00e4\u00e4",
+"File": "Tiedosto",
+"Edit": "Muokkaa",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rikastetun tekstin alue. Paina ALT-F9 valikkoon. Paina ALT-F10 ty\u00f6kaluriviin. Paina ALT-0 ohjeeseen.",
+"Tools": "Ty\u00f6kalut",
+"View": "N\u00e4yt\u00e4",
+"Table": "Taulukko",
+"Format": "Muotoilu"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fo.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fo.js
new file mode 100755
index 0000000..c6fc5eb
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fo.js
@@ -0,0 +1,156 @@
+tinymce.addI18n('fo',{
+"Cut": "Klipp",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "T\u00edn kagi hevur ikki beinlei\u00f0is atgongd til setibor\u00f0i\u00f0. Vinarliga br\u00faka CTRL+X\/C\/V snarvegirnar \u00edsta\u00f0in.",
+"Paste": "L\u00edma",
+"Close": "Lat aftur",
+"Align right": "H\u00f8gra stilla",
+"New document": "N\u00fdtt skjal",
+"Numbered list": "Tal listi",
+"Increase indent": "vaks inndr\u00e1tt",
+"Formats": "Sni\u00f0",
+"Select all": "Vel alt",
+"Undo": "Angra ger",
+"Strikethrough": "Strika \u00edgj\u00f8gnum",
+"Bullet list": "Punkt listi",
+"Superscript": "H\u00e1skrift",
+"Clear formatting": "Strika sni\u00f0",
+"Subscript": "L\u00e1gskrift",
+"Redo": "Ger aftur",
+"Ok": "Ok",
+"Bold": "Feit",
+"Italic": "Sk\u00e1ktekstur",
+"Align center": "Mi\u00f0set",
+"Decrease indent": "Minka inndr\u00e1tt",
+"Underline": "Undirstrika",
+"Cancel": "\u00d3gilda",
+"Justify": "L\u00edka breddar",
+"Copy": "Avrita",
+"Align left": "Vinstra stilla",
+"Visual aids": "Sj\u00f3nhj\u00e1lp",
+"Lower Greek": "L\u00edti Grikskt",
+"Square": "Fj\u00f3rhyrningur",
+"Default": "Forsettur",
+"Lower Alpha": "L\u00edti Alfa",
+"Circle": "Ringur",
+"Disc": "Skiva",
+"Upper Alpha": "St\u00f3rt Alfa",
+"Upper Roman": "St\u00f3rt R\u00f3mverskt",
+"Lower Roman": "L\u00edti R\u00f3mverskt",
+"Name": "Navn",
+"Anchor": "Akker",
+"You have unsaved changes are you sure you want to navigate away?": "T\u00fa hevur ikki goymdar broytingar. Ert t\u00fa v\u00edsur \u00ed at t\u00fa vilt halda fram?",
+"Restore last draft": "Endurskapa seinasta uppkast",
+"Special character": "Serst\u00f8k tekn",
+"Source code": "keldukoda",
+"Right to left": "H\u00f8gra til vinstra",
+"Left to right": "Vinstra til h\u00f8gra",
+"Emoticons": "Emotikonur",
+"Robots": "Robottar",
+"Document properties": "Skjal eginleikar",
+"Title": "Heiti",
+"Keywords": "Leitior\u00f0",
+"Encoding": "Koding",
+"Description": "L\u00fdsing",
+"Author": "H\u00f8vundur",
+"Fullscreen": "Fullan sk\u00edggja",
+"Horizontal line": "Vatnr\u00f8tt linja",
+"Horizontal space": "Vatnr\u00e6tt fr\u00e1st\u00f8\u00f0a",
+"Insert\/edit image": "Innset\/r\u00e6tta mynd",
+"General": "Vanligt",
+"Advanced": "Framkomi",
+"Source": "Kelda",
+"Border": "Rammi",
+"Constrain proportions": "Var\u00f0veit lutfall",
+"Vertical space": "Loddr\u00e6t fr\u00e1st\u00f8\u00f0a",
+"Image description": "L\u00fdsing av mynd",
+"Style": "St\u00edlur",
+"Dimensions": "St\u00f8dd",
+"Insert date\/time": "Innset dag\/t\u00ed\u00f0",
+"Url": "Url",
+"Text to display": "Tekstur at v\u00edsa",
+"Insert link": "Innset leinkju",
+"New window": "N\u00fdggjan glugga",
+"None": "Eingin",
+"Target": "M\u00e1l",
+"Insert\/edit link": "Innset\/r\u00e6tta leinkju",
+"Insert\/edit video": "Innset\/r\u00e6tta kykmynd",
+"Poster": "Uppslag",
+"Alternative source": "Onnur kelda",
+"Paste your embed code below:": "Innset ta\u00f0 kodu, sum skal leggjast inn \u00ed, ni\u00f0anfyri:",
+"Insert video": "Innset kykmynd",
+"Embed": "Legg inn \u00ed",
+"Nonbreaking space": "Hart millumr\u00fam",
+"Page break": "S\u00ed\u00f0uskift",
+"Preview": "V\u00eds frammanundan",
+"Print": "Prenta",
+"Save": "Goym",
+"Could not find the specified string.": "Kundi ikki finna leititekst",
+"Replace": "Set \u00edsta\u00f0in",
+"Next": "N\u00e6sta",
+"Whole words": "Heil or\u00f0",
+"Find and replace": "Finn og set \u00edsta\u00f0in",
+"Replace with": "Set hetta \u00edsta\u00f0in",
+"Find": "Finn",
+"Replace all": "Set \u00edsta\u00f0in fyri \u00f8ll",
+"Match case": "ST\u00d3RIR og l\u00edtlir b\u00f3kstavir",
+"Prev": "Fyrra",
+"Spellcheck": "R\u00e6ttstavari",
+"Finish": "Enda",
+"Ignore all": "Leyp alt um",
+"Ignore": "Leyp um",
+"Insert row before": "Innset ra\u00f0 \u00e1\u00f0renn",
+"Rows": "Ra\u00f0ir",
+"Height": "H\u00e6dd",
+"Paste row after": "L\u00edma ra\u00f0 aftan\u00e1",
+"Alignment": "Stilling",
+"Column group": "Teig b\u00f3lkur",
+"Row": "Ra\u00f0",
+"Insert column before": "Innset teig \u00e1\u00f0renn",
+"Split cell": "Syndra puntar",
+"Cell padding": "Punt fylling",
+"Cell spacing": "Punt fr\u00e1st\u00f8\u00f0a",
+"Row type": "Ra\u00f0 slag",
+"Insert table": "Innset talvu",
+"Body": "Likam",
+"Caption": "Tekstur",
+"Footer": "F\u00f3tur",
+"Delete row": "Skrika ra\u00f0",
+"Paste row before": "L\u00edma ra\u00f0 \u00e1\u00f0renn",
+"Scope": "N\u00fdtslu\u00f8ki",
+"Delete table": "Strika talvu",
+"Header cell": "H\u00f8vd puntur",
+"Column": "Teigur",
+"Cell": "Puntur",
+"Header": "H\u00f8vd",
+"Cell type": "Punt slag",
+"Copy row": "Avrita ra\u00f0",
+"Row properties": "Ra\u00f0 eginleikar",
+"Table properties": "Talvu eginleikar",
+"Row group": "Ra\u00f0 b\u00f3lkur",
+"Right": "H\u00f8gra",
+"Insert column after": "Innset teig aftan\u00e1",
+"Cols": "Teigar",
+"Insert row after": "Innset ra\u00f0 aftan\u00e1",
+"Width": "Breidd",
+"Cell properties": "Punt eginleikar",
+"Left": "Vinstra",
+"Cut row": "Klipp ra\u00f0",
+"Delete column": "Strika teig",
+"Center": "Mi\u00f0a",
+"Merge cells": "Fl\u00e6tta puntar",
+"Insert template": "Innset form",
+"Templates": "Formur",
+"Background color": "Bakgrundslitur",
+"Text color": "Tekst litur",
+"Show blocks": "V\u00eds blokkar",
+"Show invisible characters": "V\u00eds \u00f3sj\u00f3nlig tekn",
+"Words: {0}": "Or\u00f0: {0}",
+"Insert": "Innset",
+"File": "F\u00edla",
+"Edit": "Ritstj\u00f3rna",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "R\u00edkt Tekst \u00d8ki. Tr\u00fdst ALT-F9 fyri valmynd. Tr\u00fdst ALT-F10 fyri ambo\u00f0slinju. Tr\u00fdst ALT-0 fyri hj\u00e1lp",
+"Tools": "Ambo\u00f0",
+"View": "V\u00eds",
+"Table": "Talva",
+"Format": "Smi\u00f0"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fr_FR.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fr_FR.js
new file mode 100755
index 0000000..b2978b8
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/fr_FR.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('fr_FR',{
+"Cut": "Couper",
+"Header 2": "En-t\u00eate 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Votre navigateur ne supporte pas la copie directe. Merci d'utiliser les touches Ctrl+X\/C\/V.",
+"Div": "Div",
+"Paste": "Coller",
+"Close": "Fermer",
+"Pre": "Pre",
+"Align right": "Aligner \u00e0 droite",
+"New document": "Nouveau document",
+"Blockquote": "Citation",
+"Numbered list": "Num\u00e9rotation",
+"Increase indent": "Augmenter le retrait",
+"Formats": "Formats",
+"Headers": "En-t\u00eates",
+"Select all": "Tout s\u00e9lectionner",
+"Header 3": "En-t\u00eate 3",
+"Blocks": "Blocs",
+"Undo": "Annuler",
+"Strikethrough": "Barr\u00e9",
+"Bullet list": "Puces",
+"Header 1": "En-t\u00eate 1",
+"Superscript": "Exposant",
+"Clear formatting": "Effacer la mise en forme",
+"Subscript": "Indice",
+"Header 6": "En-t\u00eate 6",
+"Redo": "R\u00e9tablir",
+"Paragraph": "Paragraphe",
+"Ok": "Ok",
+"Bold": "Gras",
+"Code": "Code",
+"Italic": "Italique",
+"Align center": "Aligner au centre",
+"Header 5": "En-t\u00eate 5",
+"Decrease indent": "Diminuer le retrait",
+"Header 4": "En-t\u00eate 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Le presse-papiers est maintenant en mode \"texte plein\". Les contenus seront coll\u00e9s sans retenir les formatages jusqu'\u00e0 ce que vous d\u00e9sactiviez cette option.",
+"Underline": "Soulign\u00e9",
+"Cancel": "Annuler",
+"Justify": "Justifi\u00e9",
+"Inline": "en place",
+"Copy": "Copier",
+"Align left": "Aligner \u00e0 gauche",
+"Visual aids": "Aides visuelle",
+"Lower Greek": "Grec minuscule",
+"Square": "Carr\u00e9",
+"Default": "Par d\u00e9faut",
+"Lower Alpha": "Alpha inf\u00e9rieure",
+"Circle": "Cercle",
+"Disc": "Disque",
+"Upper Alpha": "Alpha majuscule",
+"Upper Roman": "Romain majuscule",
+"Lower Roman": "Romain minuscule",
+"Name": "Nom",
+"Anchor": "Ancre",
+"You have unsaved changes are you sure you want to navigate away?": "Vous avez des modifications non enregistr\u00e9es, \u00eates-vous s\u00fbr de quitter la page?",
+"Restore last draft": "Restaurer le dernier brouillon",
+"Special character": "Caract\u00e8res sp\u00e9ciaux",
+"Source code": "Code source",
+"Right to left": "Droite \u00e0 gauche",
+"Left to right": "Gauche \u00e0 droite",
+"Emoticons": "Emotic\u00f4nes",
+"Robots": "Robots",
+"Document properties": "Propri\u00e9t\u00e9 du document",
+"Title": "Titre",
+"Keywords": "Mots-cl\u00e9s",
+"Encoding": "Encodage",
+"Description": "Description",
+"Author": "Auteur",
+"Fullscreen": "Plein \u00e9cran",
+"Horizontal line": "Ligne horizontale",
+"Horizontal space": "Espacement horizontal",
+"Insert\/edit image": "Ins\u00e9rer\/\u00e9diter une image",
+"General": "G\u00e9n\u00e9ral",
+"Advanced": "Avanc\u00e9",
+"Source": "Source",
+"Border": "Bordure",
+"Constrain proportions": "Contraindre les proportions",
+"Vertical space": "Espacement vertical",
+"Image description": "Description de l'image",
+"Style": "Style",
+"Dimensions": "Dimensions",
+"Insert image": "Ins\u00e9rer une image",
+"Insert date\/time": "Ins\u00e9rer date\/heure",
+"Remove link": "Enlever le lien",
+"Url": "Url",
+"Text to display": "Texte \u00e0 afficher",
+"Anchors": "Ancre",
+"Insert link": "Ins\u00e9rer un lien",
+"New window": "Nouvelle fen\u00eatre",
+"None": "n\/a",
+"Target": "Cible",
+"Insert\/edit link": "Ins\u00e9rer\/\u00e9diter un lien",
+"Insert\/edit video": "Ins\u00e9rer\/\u00e9diter une vid\u00e9o",
+"Poster": "Afficher",
+"Alternative source": "Source alternative",
+"Paste your embed code below:": "Collez votre code d'int\u00e9gration ci-dessous :",
+"Insert video": "Ins\u00e9rer une vid\u00e9o",
+"Embed": "Int\u00e9grer",
+"Nonbreaking space": "Espace ins\u00e9cable",
+"Page break": "Saut de page",
+"Paste as text": "Coller comme texte",
+"Preview": "Pr\u00e9visualiser",
+"Print": "Imprimer",
+"Save": "Enregistrer",
+"Could not find the specified string.": "Impossible de trouver la cha\u00eene sp\u00e9cifi\u00e9e.",
+"Replace": "Remplacer",
+"Next": "Suiv",
+"Whole words": "Mots entiers",
+"Find and replace": "Trouver et remplacer",
+"Replace with": "Remplacer par",
+"Find": "Chercher",
+"Replace all": "Tout remplacer",
+"Match case": "Respecter la casse",
+"Prev": "Pr\u00e9c ",
+"Spellcheck": "V\u00e9rification orthographique",
+"Finish": "Finie",
+"Ignore all": "Tout ignorer",
+"Ignore": "Ignorer",
+"Insert row before": "Ins\u00e9rer une ligne avant",
+"Rows": "Lignes",
+"Height": "Hauteur",
+"Paste row after": "Coller la ligne apr\u00e8s",
+"Alignment": "Alignement",
+"Column group": "Groupe de colonnes",
+"Row": "Ligne",
+"Insert column before": "Ins\u00e9rer une colonne avant",
+"Split cell": "Diviser la cellule",
+"Cell padding": "Espacement interne cellule",
+"Cell spacing": "Espacement inter-cellulles",
+"Row type": "Type de ligne",
+"Insert table": "Ins\u00e9rer un tableau",
+"Body": "Corps",
+"Caption": "Titre",
+"Footer": "Pied",
+"Delete row": "Effacer la ligne",
+"Paste row before": "Coller la ligne avant",
+"Scope": "Etendue",
+"Delete table": "Supprimer le tableau",
+"Header cell": "Cellule d'en-t\u00eate",
+"Column": "Colonne",
+"Cell": "Cellule",
+"Header": "En-t\u00eate",
+"Cell type": "Type de cellule",
+"Copy row": "Copier la ligne",
+"Row properties": "Propri\u00e9t\u00e9s de la ligne",
+"Table properties": "Propri\u00e9t\u00e9s du tableau",
+"Row group": "Groupe de lignes",
+"Right": "Droite",
+"Insert column after": "Ins\u00e9rer une colonne apr\u00e8s",
+"Cols": "Colonnes",
+"Insert row after": "Ins\u00e9rer une ligne apr\u00e8s",
+"Width": "Largeur",
+"Cell properties": "Propri\u00e9t\u00e9s de la cellule",
+"Left": "Gauche",
+"Cut row": "Couper la ligne",
+"Delete column": "Effacer la colonne",
+"Center": "Centr\u00e9",
+"Merge cells": "Fusionner les cellules",
+"Insert template": "Ajouter un th\u00e8me",
+"Templates": "Th\u00e8mes",
+"Background color": "Couleur d'arri\u00e8re-plan",
+"Text color": "Couleur du texte",
+"Show blocks": "Afficher les blocs",
+"Show invisible characters": "Afficher les caract\u00e8res invisibles",
+"Words: {0}": "Mots : {0}",
+"Insert": "Ins\u00e9rer",
+"File": "Fichier",
+"Edit": "Editer",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Zone Texte Riche. Appuyer sur ALT-F9 pour le menu. Appuyer sur ALT-F10 pour la barre d'outils. Appuyer sur ALT-0 pour de l'aide.",
+"Tools": "Outils",
+"View": "Voir",
+"Table": "Tableau",
+"Format": "Format"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/gl.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/gl.js
new file mode 100755
index 0000000..8d7f706
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/gl.js
@@ -0,0 +1,156 @@
+tinymce.addI18n('gl',{
+"Cut": "Cortar",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "O seu navegador non admite o acceso directo ao portapapeis. Empregue os atallos de teclado Crtl+X\/C\/V no seu canto.",
+"Paste": "Pegar",
+"Close": "Pechar",
+"Align right": "Ali\u00f1ar \u00e1 dereita",
+"New document": "Novo documento",
+"Numbered list": "Lista numerada",
+"Increase indent": "Aumentar a sangr\u00eda",
+"Formats": "Formatos",
+"Select all": "Seleccionar todo",
+"Undo": "Desfacer",
+"Strikethrough": "Riscado",
+"Bullet list": "Lista vi\u00f1etada",
+"Superscript": "Super\u00edndice",
+"Clear formatting": "Limpar o formato",
+"Subscript": "Sub\u00edndice",
+"Redo": "Refacer",
+"Ok": "Aceptar",
+"Bold": "Negra",
+"Italic": "Cursiva",
+"Align center": "Ali\u00f1ar ao centro",
+"Decrease indent": "Reducir a sangr\u00eda",
+"Underline": "Subli\u00f1ado",
+"Cancel": "Cancelar",
+"Justify": "Xustificar",
+"Copy": "Copiar",
+"Align left": "Ali\u00f1ar \u00e1 esquerda",
+"Visual aids": "Axudas visuais",
+"Lower Greek": "Inferior grega",
+"Square": "Cadrado",
+"Default": "Predeterminada",
+"Lower Alpha": "Inferior alfa",
+"Circle": "Circulo",
+"Disc": "Disco",
+"Upper Alpha": "Superior alfa",
+"Upper Roman": "Superior romana",
+"Lower Roman": "Inferior romana",
+"Name": "Nome",
+"Anchor": "Ancoraxe",
+"You have unsaved changes are you sure you want to navigate away?": "Ten cambios sen gardar. Confirma que quere sa\u00edr?",
+"Restore last draft": "Restaurar o \u00faltimo borrador",
+"Special character": "Car\u00e1cter especial",
+"Source code": "C\u00f3digo fonte",
+"Right to left": "De dereita a esquerda",
+"Left to right": "De esquerda a dereita",
+"Emoticons": "Emoticonas",
+"Robots": "Robots",
+"Document properties": "Propiedades do documento",
+"Title": "T\u00edtulo",
+"Keywords": "Palabras clave",
+"Encoding": "Codificaci\u00f3n",
+"Description": "Descrici\u00f3n",
+"Author": "Autor",
+"Fullscreen": "Pantalla completa",
+"Horizontal line": "Li\u00f1a horizontal",
+"Horizontal space": "Espazo horizontal",
+"Insert\/edit image": "Inserir\/editar imaxe",
+"General": "Xeral",
+"Advanced": "Avanzado",
+"Source": "Orixe",
+"Border": "Bordo",
+"Constrain proportions": "Restrinxir as proporci\u00f3ns",
+"Vertical space": "Espazo vertical",
+"Image description": "Descrici\u00f3n da imaxe",
+"Style": "Estilo",
+"Dimensions": "Dimensi\u00f3ns",
+"Insert date\/time": "Inserir data\/hora",
+"Url": "URL",
+"Text to display": "Texto que amosar",
+"Insert link": "Inserir ligaz\u00f3n",
+"New window": "Nova xanela",
+"None": "Ning\u00fan",
+"Target": "Destino",
+"Insert\/edit link": "Inserir\/editar ligaz\u00f3n",
+"Insert\/edit video": "Inserir\/editar v\u00eddeo",
+"Poster": "Cartel",
+"Alternative source": "Orixe alternativa",
+"Paste your embed code below:": "Pegue embaixo o c\u00f3digo incrustado",
+"Insert video": "Inserir v\u00eddeo",
+"Embed": "Incrustado",
+"Nonbreaking space": "Espazo irromp\u00edbel",
+"Page break": "Quebra de p\u00e1xina",
+"Preview": "Vista previa",
+"Print": "Imprimir",
+"Save": "Gardar",
+"Could not find the specified string.": "Non foi pos\u00edbel atopar a cadea de texto especificada.",
+"Replace": "Substitu\u00edr",
+"Next": "Seguinte",
+"Whole words": "Palabras completas",
+"Find and replace": "Buscar e substitu\u00edr",
+"Replace with": "Substitu\u00edr con",
+"Find": "Buscar",
+"Replace all": "Substitu\u00edr todo",
+"Match case": "Coincidencia exacta",
+"Prev": "Anterior",
+"Spellcheck": "Corrector ortogr\u00e1fico",
+"Finish": "Rematar",
+"Ignore all": "Ignorar todo",
+"Ignore": "Ignorar",
+"Insert row before": "Inserir unha fila enriba",
+"Rows": "Filas",
+"Height": "Alto",
+"Paste row after": "Pegar fila enriba",
+"Alignment": "Ali\u00f1amento",
+"Column group": "Grupo de columnas",
+"Row": "Fila",
+"Insert column before": "Inserir columna \u00e1 esquerda",
+"Split cell": "Dividir celas",
+"Cell padding": "Marxe interior da cela",
+"Cell spacing": "Marxe entre celas",
+"Row type": "Tipo de fia",
+"Insert table": "Inserir t\u00e1boa",
+"Body": "Corpo",
+"Caption": "Subt\u00edtulo",
+"Footer": "Rodap\u00e9",
+"Delete row": "Eliminar fila",
+"Paste row before": "Pegar fila embaixo",
+"Scope": "\u00c1mbito",
+"Delete table": "Eliminar t\u00e1boa",
+"Header cell": "Cela de cabeceira",
+"Column": "Columna",
+"Cell": "Cela",
+"Header": "Cabeceira",
+"Cell type": "Tipo de cela",
+"Copy row": "Copiar fila",
+"Row properties": "Propiedades das filas",
+"Table properties": "Propiedades da t\u00e1boa",
+"Row group": "Grupo de filas",
+"Right": "Dereita",
+"Insert column after": "Inserir columna \u00e1 dereita",
+"Cols": "Cols.",
+"Insert row after": "Inserir unha fila embaixo",
+"Width": "Largo",
+"Cell properties": "Propiedades da cela",
+"Left": "Esquerda",
+"Cut row": "Cortar fila",
+"Delete column": "Eliminar columna",
+"Center": "Centro",
+"Merge cells": "Combinar celas",
+"Insert template": "Inserir modelo",
+"Templates": "Modelos",
+"Background color": "Cor do fondo",
+"Text color": "Cor do texto",
+"Show blocks": "Amosar os bloques",
+"Show invisible characters": "Amosar caracteres invis\u00edbeis",
+"Words: {0}": "Palabras: {0}",
+"Insert": "Inserir",
+"File": "Ficheiro",
+"Edit": "Editar",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u00c1rea de texto mellorado. Prema ALT-F9 para o men\u00fa. Prema ALT-F10 para a barra de ferramentas. Prema ALT-0 para a axuda",
+"Tools": "Ferramentas",
+"View": "Ver",
+"Table": "T\u00e1boa",
+"Format": "Formato"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/he_IL.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/he_IL.js
new file mode 100755
index 0000000..b80ffc6
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/he_IL.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('he_IL',{
+"Cut": "\u05d2\u05d6\u05d5\u05e8",
+"Header 2": "\u05db\u05d5\u05ea\u05e8\u05ea 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u05d4\u05d3\u05e4\u05d3\u05e4\u05df \u05e9\u05dc\u05da \u05d0\u05d9\u05e0\u05d5 \u05de\u05d0\u05e4\u05e9\u05e8 \u05d2\u05d9\u05e9\u05d4 \u05d9\u05e9\u05d9\u05e8\u05d4 \u05dc\u05dc\u05d5\u05d7. \u05d0\u05e0\u05d0, \u05d4\u05e9\u05ea\u05de\u05e9 \u05d1\u05de\u05e7\u05e9\u05d9\u05dd Ctrl+X\/C\/V ",
+"Div": "\u05de\u05e7\u05d8\u05e2 \u05e7\u05d5\u05d3 Div",
+"Paste": "\u05d4\u05d3\u05d1\u05e7",
+"Close": "\u05e1\u05d2\u05d5\u05e8",
+"Pre": "\u05e7\u05d8\u05e2 \u05de\u05e7\u05d3\u05d9\u05dd Pre",
+"Align right": "\u05d9\u05d9\u05e9\u05e8 \u05dc\u05e9\u05de\u05d0\u05dc",
+"New document": "\u05de\u05e1\u05de\u05da \u05d7\u05d3\u05e9",
+"Blockquote": "\u05de\u05e7\u05d8\u05e2 \u05e6\u05d9\u05d8\u05d5\u05d8",
+"Numbered list": "\u05e8\u05e9\u05d9\u05de\u05d4 \u05de\u05de\u05d5\u05e1\u05e4\u05e8\u05ea",
+"Increase indent": "\u05d4\u05d2\u05d3\u05dc \u05d4\u05d6\u05d7\u05d4",
+"Formats": "\u05e4\u05d5\u05e8\u05de\u05d8\u05d9\u05dd",
+"Headers": "\u05db\u05d5\u05ea\u05e8\u05d5\u05ea",
+"Select all": "\u05d1\u05d7\u05e8 \u05d4\u05db\u05dc",
+"Header 3": "\u05db\u05d5\u05ea\u05e8\u05ea 3",
+"Blocks": "\u05de\u05d1\u05e0\u05d9\u05dd",
+"Undo": "\u05d1\u05d8\u05dc \u05e4\u05e2\u05d5\u05dc\u05d4",
+"Strikethrough": "\u05e7\u05d5 \u05d7\u05d5\u05e6\u05d4",
+"Bullet list": "\u05e8\u05e9\u05d9\u05de\u05d4 \u05de\u05d5\u05d3\u05d2\u05e9\u05ea",
+"Header 1": "\u05db\u05d5\u05ea\u05e8\u05ea 1",
+"Superscript": "\u05db\u05ea\u05d1 \u05e2\u05d9\u05dc\u05d9",
+"Clear formatting": "\u05e0\u05e7\u05d4 \u05e4\u05d5\u05e8\u05de\u05d8\u05d9\u05dd",
+"Subscript": "\u05db\u05ea\u05d1 \u05ea\u05d7\u05ea\u05d9",
+"Header 6": "\u05db\u05d5\u05ea\u05e8\u05ea 6",
+"Redo": "\u05d1\u05e6\u05e2 \u05e9\u05d5\u05d1",
+"Paragraph": "\u05e4\u05d9\u05e1\u05e7\u05d4",
+"Ok": "\u05d1\u05e1\u05d3\u05e8",
+"Bold": "\u05de\u05d5\u05d3\u05d2\u05e9",
+"Code": "\u05e7\u05d5\u05d3",
+"Italic": "\u05e0\u05d8\u05d5\u05d9",
+"Align center": "\u05de\u05e8\u05db\u05d6",
+"Header 5": "\u05db\u05d5\u05ea\u05e8\u05ea 5",
+"Decrease indent": "\u05d4\u05e7\u05d8\u05df \u05d4\u05d6\u05d7\u05d4",
+"Header 4": "\u05db\u05d5\u05ea\u05e8\u05ea 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u05d4\u05d3\u05d1\u05e7\u05d4 \u05d1\u05de\u05e6\u05d1 \u05d8\u05e7\u05e1\u05d8 \u05e8\u05d2\u05d9\u05dc. \u05ea\u05db\u05e0\u05d9\u05dd \u05d9\u05d5\u05d3\u05d1\u05e7\u05d5 \u05de\u05e2\u05ea\u05d4 \u05db\u05d8\u05e7\u05e1\u05d8 \u05e8\u05d2\u05d9\u05dc \u05e2\u05d3 \u05e9\u05ea\u05db\u05d1\u05d4 \u05d0\u05e4\u05e9\u05e8\u05d5\u05ea \u05d6\u05d5.",
+"Underline": "\u05e7\u05d5 \u05ea\u05d7\u05ea\u05d5\u05df",
+"Cancel": "\u05d1\u05d8\u05dc",
+"Justify": "\u05d9\u05d9\u05e9\u05d5\u05e8",
+"Inline": "\u05d1\u05d2\u05d5\u05e3 \u05d4\u05d8\u05e7\u05e1\u05d8",
+"Copy": "\u05d4\u05e2\u05ea\u05e7",
+"Align left": "\u05d9\u05d9\u05e9\u05e8 \u05dc\u05e9\u05de\u05d0\u05dc",
+"Visual aids": "\u05e2\u05d6\u05e8\u05d9\u05dd \u05d7\u05d6\u05d5\u05ea\u05d9\u05d9\u05dd",
+"Lower Greek": "\u05d0\u05d5\u05ea\u05d9\u05d5\u05ea \u05d9\u05d5\u05d5\u05e0\u05d9\u05d5\u05ea \u05e7\u05d8\u05e0\u05d5\u05ea",
+"Square": "\u05e8\u05d9\u05d1\u05d5\u05e2",
+"Default": "\u05d1\u05e8\u05d9\u05e8\u05ea \u05de\u05d7\u05d3\u05dc",
+"Lower Alpha": "\u05d0\u05d5\u05ea\u05d9\u05d5\u05ea \u05d0\u05e0\u05d2\u05dc\u05d9\u05d5\u05ea \u05e7\u05d8\u05e0\u05d5\u05ea",
+"Circle": "\u05e2\u05d9\u05d2\u05d5\u05dc",
+"Disc": "\u05d7\u05d9\u05e9\u05d5\u05e7",
+"Upper Alpha": "\u05d0\u05d5\u05ea\u05d9\u05d5\u05ea \u05d0\u05e0\u05d2\u05dc\u05d9\u05d5\u05ea \u05d2\u05d3\u05d5\u05dc\u05d5\u05ea",
+"Upper Roman": "\u05e1\u05e4\u05e8\u05d5\u05ea \u05e8\u05d5\u05de\u05d9\u05d5\u05ea \u05d2\u05d3\u05d5\u05dc\u05d5\u05ea",
+"Lower Roman": "\u05e1\u05e4\u05e8\u05d5\u05ea \u05e8\u05d5\u05de\u05d9\u05d5\u05ea \u05e7\u05d8\u05e0\u05d5\u05ea",
+"Name": "\u05e9\u05dd",
+"Anchor": "\u05de\u05e7\u05d5\u05dd \u05e2\u05d9\u05d2\u05d5\u05df",
+"You have unsaved changes are you sure you want to navigate away?": "\u05d4\u05e9\u05d9\u05e0\u05d5\u05d9\u05d9\u05dd \u05dc\u05d0 \u05e0\u05e9\u05de\u05e8\u05d5. \u05d1\u05d8\u05d5\u05d7 \u05e9\u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05e6\u05d0\u05ea \u05de\u05d4\u05d3\u05e3?",
+"Restore last draft": "\u05e9\u05d7\u05d6\u05e8 \u05d8\u05d9\u05d5\u05d8\u05d4 \u05d0\u05d7\u05e8\u05d5\u05e0\u05d4",
+"Special character": "\u05ea\u05d5\u05d5\u05d9\u05dd \u05de\u05d9\u05d5\u05d7\u05d3\u05d9\u05dd",
+"Source code": "\u05e7\u05d5\u05d3 \u05de\u05e7\u05d5\u05e8",
+"Right to left": "\u05de\u05d9\u05de\u05d9\u05df \u05dc\u05e9\u05de\u05d0\u05dc",
+"Left to right": "\u05de\u05e9\u05de\u05d0\u05dc \u05dc\u05d9\u05de\u05d9\u05df",
+"Emoticons": "\u05de\u05d7\u05d5\u05d5\u05ea",
+"Robots": "\u05e8\u05d5\u05d1\u05d5\u05d8\u05d9\u05dd",
+"Document properties": "\u05de\u05d0\u05e4\u05d9\u05d9\u05e0\u05d9 \u05de\u05e1\u05de\u05da",
+"Title": "\u05db\u05d5\u05ea\u05e8\u05ea",
+"Keywords": "\u05de\u05d9\u05dc\u05d5\u05ea \u05de\u05e4\u05ea\u05d7",
+"Encoding": "\u05e7\u05d9\u05d3\u05d5\u05d3",
+"Description": "\u05ea\u05d9\u05d0\u05d5\u05e8",
+"Author": "\u05de\u05d7\u05d1\u05e8",
+"Fullscreen": "\u05de\u05e1\u05da \u05de\u05dc\u05d0",
+"Horizontal line": "\u05e7\u05d5 \u05d0\u05d5\u05e4\u05e7\u05d9",
+"Horizontal space": "\u05de\u05e8\u05d5\u05d5\u05d7 \u05d0\u05d5\u05e4\u05e7\u05d9",
+"Insert\/edit image": "\u05d4\u05db\u05e0\u05e1\/\u05e2\u05e8\u05d5\u05da \u05ea\u05de\u05d5\u05e0\u05d4",
+"General": "\u05db\u05dc\u05dc\u05d9",
+"Advanced": "\u05de\u05ea\u05e7\u05d3\u05dd",
+"Source": "\u05de\u05e7\u05d5\u05e8",
+"Border": "\u05de\u05e1\u05d2\u05e8\u05ea",
+"Constrain proportions": "\u05d4\u05d2\u05d1\u05dc\u05ea \u05e4\u05e8\u05d5\u05e4\u05d5\u05e8\u05e6\u05d9\u05d5\u05ea",
+"Vertical space": "\u05de\u05e8\u05d5\u05d5\u05d7 \u05d0\u05e0\u05db\u05d9",
+"Image description": "\u05ea\u05d9\u05d0\u05d5\u05e8 \u05d4\u05ea\u05de\u05d5\u05e0\u05d4",
+"Style": "\u05e1\u05d2\u05e0\u05d5\u05df",
+"Dimensions": "\u05de\u05d9\u05de\u05d3\u05d9\u05dd",
+"Insert image": "\u05d4\u05db\u05e0\u05e1 \u05ea\u05de\u05d5\u05e0\u05d4",
+"Insert date\/time": "\u05d4\u05db\u05e0\u05e1 \u05ea\u05d0\u05e8\u05d9\u05da\/\u05e9\u05e2\u05d4",
+"Remove link": "\u05de\u05d7\u05e7 \u05e7\u05d9\u05e9\u05d5\u05e8",
+"Url": "\u05db\u05ea\u05d5\u05d1\u05ea \u05e7\u05d9\u05e9\u05d5\u05e8",
+"Text to display": "\u05d8\u05e7\u05e1\u05d8 \u05dc\u05d4\u05e6\u05d2\u05d4",
+"Anchors": "\u05e2\u05d5\u05d2\u05e0\u05d9\u05dd",
+"Insert link": "\u05d4\u05db\u05e0\u05e1 \u05e7\u05d9\u05e9\u05d5\u05e8",
+"New window": "\u05d7\u05dc\u05d5\u05df \u05d7\u05d3\u05e9",
+"None": "\u05dc\u05dc\u05d0",
+"Target": "\u05de\u05d8\u05e8\u05d4",
+"Insert\/edit link": "\u05d4\u05db\u05e0\u05e1\/\u05e2\u05e8\u05d5\u05da \u05e7\u05d9\u05e9\u05d5\u05e8",
+"Insert\/edit video": "\u05d4\u05db\u05e0\u05e1\/\u05e2\u05e8\u05d5\u05da \u05e1\u05e8\u05d8\u05d5\u05df",
+"Poster": "\u05e4\u05d5\u05e1\u05d8\u05e8",
+"Alternative source": "\u05de\u05e7\u05d5\u05e8 \u05de\u05e9\u05e0\u05d9",
+"Paste your embed code below:": "\u05d4\u05d3\u05d1\u05e7 \u05e7\u05d5\u05d3 \u05d4\u05d8\u05de\u05e2\u05d4 \u05de\u05ea\u05d7\u05ea:",
+"Insert video": "\u05d4\u05db\u05e0\u05e1 \u05e1\u05e8\u05d8\u05d5\u05df",
+"Embed": "\u05de\u05d5\u05d8\u05de\u05e2",
+"Nonbreaking space": "\u05e8\u05d5\u05d5\u05d7 (\u05dc\u05dc\u05d0 \u05e9\u05d1\u05d9\u05e8\u05ea \u05e9\u05d5\u05e8\u05d4)",
+"Page break": "\u05d3\u05e3 \u05d7\u05d3\u05e9",
+"Paste as text": "\u05d4\u05d3\u05d1\u05e7 \u05db\u05d8\u05e7\u05e1\u05d8",
+"Preview": "\u05ea\u05e6\u05d5\u05d2\u05d4 \u05de\u05e7\u05d3\u05d9\u05de\u05d4",
+"Print": "\u05d4\u05d3\u05e4\u05e1",
+"Save": "\u05e9\u05de\u05d9\u05e8\u05d4",
+"Could not find the specified string.": "\u05de\u05d7\u05e8\u05d5\u05d6\u05ea \u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d4",
+"Replace": "\u05d4\u05d7\u05dc\u05e3",
+"Next": "\u05d4\u05d1\u05d0",
+"Whole words": "\u05de\u05d9\u05dc\u05d4 \u05e9\u05dc\u05de\u05d4",
+"Find and replace": "\u05d7\u05e4\u05e9 \u05d5\u05d4\u05d7\u05dc\u05e3",
+"Replace with": "\u05d4\u05d7\u05dc\u05e3 \u05d1",
+"Find": "\u05d7\u05e4\u05e9",
+"Replace all": "\u05d4\u05d7\u05dc\u05e3 \u05d4\u05db\u05dc",
+"Match case": "\u05d4\u05d1\u05d7\u05df \u05d1\u05d9\u05df \u05d0\u05d5\u05ea\u05d9\u05d5\u05ea \u05e7\u05d8\u05e0\u05d5\u05ea \u05dc\u05d2\u05d3\u05d5\u05dc\u05d5\u05ea",
+"Prev": "\u05e7\u05d5\u05d3\u05dd",
+"Spellcheck": "\u05d1\u05d5\u05d3\u05e7 \u05d0\u05d9\u05d5\u05ea",
+"Finish": "\u05e1\u05d9\u05d9\u05dd",
+"Ignore all": "\u05d4\u05ea\u05e2\u05dc\u05dd \u05de\u05d4\u05db\u05dc",
+"Ignore": "\u05d4\u05ea\u05e2\u05dc\u05dd",
+"Insert row before": "\u05d4\u05d5\u05e1\u05e3 \u05e9\u05d5\u05e8\u05d4 \u05dc\u05e4\u05e0\u05d9",
+"Rows": "\u05e9\u05d5\u05e8\u05d5\u05ea",
+"Height": "\u05d2\u05d5\u05d1\u05d4",
+"Paste row after": "\u05d4\u05e2\u05ea\u05e7 \u05e9\u05d5\u05e8\u05d4 \u05d0\u05d7\u05e8\u05d9",
+"Alignment": "\u05d9\u05d9\u05e9\u05d5\u05e8",
+"Column group": "\u05e7\u05d9\u05d1\u05d5\u05e5 \u05e2\u05de\u05d5\u05d3\u05d5\u05ea",
+"Row": "\u05e9\u05d5\u05e8\u05d4",
+"Insert column before": "\u05d4\u05e2\u05ea\u05e7 \u05e2\u05de\u05d5\u05d3\u05d4 \u05dc\u05e4\u05e0\u05d9",
+"Split cell": "\u05e4\u05e6\u05dc \u05ea\u05d0",
+"Cell padding": "\u05e9\u05d5\u05dc\u05d9\u05d9\u05dd \u05e4\u05e0\u05d9\u05de\u05d9\u05d9\u05dd \u05dc\u05ea\u05d0",
+"Cell spacing": "\u05e9\u05d5\u05dc\u05d9\u05d9\u05dd \u05d7\u05d9\u05e6\u05d5\u05e0\u05d9\u05dd \u05dc\u05ea\u05d0",
+"Row type": "\u05e1\u05d5\u05d2 \u05e9\u05d5\u05e8\u05d4",
+"Insert table": "\u05d4\u05db\u05e0\u05e1 \u05d8\u05d1\u05dc\u05d4",
+"Body": "\u05d2\u05d5\u05e3 \u05d4\u05d8\u05d1\u05dc\u05d0",
+"Caption": "\u05db\u05d9\u05ea\u05d5\u05d1",
+"Footer": "\u05db\u05d5\u05ea\u05e8\u05ea \u05ea\u05d7\u05ea\u05d5\u05e0\u05d4",
+"Delete row": "\u05de\u05d7\u05e7 \u05e9\u05d5\u05e8\u05d4",
+"Paste row before": "\u05d4\u05d3\u05d1\u05e7 \u05e9\u05d5\u05e8\u05d4 \u05dc\u05e4\u05e0\u05d9",
+"Scope": "\u05d4\u05d9\u05e7\u05e3",
+"Delete table": "\u05de\u05d7\u05e7 \u05d8\u05d1\u05dc\u05d4",
+"Header cell": "\u05db\u05d5\u05ea\u05e8\u05ea \u05dc\u05ea\u05d0",
+"Column": "\u05e2\u05de\u05d5\u05d3\u05d4",
+"Cell": "\u05ea\u05d0",
+"Header": "\u05db\u05d5\u05ea\u05e8\u05ea",
+"Cell type": "\u05e1\u05d5\u05d2 \u05ea\u05d0",
+"Copy row": "\u05d4\u05e2\u05ea\u05e7 \u05e9\u05d5\u05e8\u05d4",
+"Row properties": "\u05de\u05d0\u05e4\u05d9\u05d9\u05e0\u05d9 \u05e9\u05d5\u05e8\u05d4",
+"Table properties": "\u05de\u05d0\u05e4\u05d9\u05d9\u05e0\u05d9 \u05d8\u05d1\u05dc\u05d4",
+"Row group": "\u05e7\u05d9\u05d1\u05d5\u05e5 \u05e9\u05d5\u05e8\u05d5\u05ea",
+"Right": "\u05d9\u05de\u05d9\u05df",
+"Insert column after": "\u05d4\u05e2\u05ea\u05e7 \u05e2\u05de\u05d5\u05d3\u05d4 \u05d0\u05d7\u05e8\u05d9",
+"Cols": "\u05e2\u05de\u05d5\u05d3\u05d5\u05ea",
+"Insert row after": "\u05d4\u05d5\u05e1\u05e3 \u05e9\u05d5\u05e8\u05d4 \u05d0\u05d7\u05e8\u05d9",
+"Width": "\u05e8\u05d5\u05d7\u05d1",
+"Cell properties": "\u05de\u05d0\u05e4\u05d9\u05d9\u05e0\u05d9 \u05ea\u05d0",
+"Left": "\u05e9\u05de\u05d0\u05dc",
+"Cut row": "\u05d2\u05d6\u05d5\u05e8 \u05e9\u05d5\u05e8\u05d4",
+"Delete column": "\u05de\u05d7\u05e7 \u05e2\u05de\u05d5\u05d3\u05d4",
+"Center": "\u05de\u05e8\u05db\u05d6",
+"Merge cells": "\u05de\u05d6\u05d2 \u05ea\u05d0\u05d9\u05dd",
+"Insert template": "\u05d4\u05db\u05e0\u05e1 \u05ea\u05d1\u05e0\u05d9\u05ea",
+"Templates": "\u05ea\u05d1\u05e0\u05d9\u05d5\u05ea",
+"Background color": "\u05e6\u05d1\u05e2 \u05e8\u05e7\u05e2",
+"Text color": "\u05e6\u05d1\u05e2 \u05d4\u05db\u05ea\u05d1",
+"Show blocks": "\u05d4\u05e6\u05d2 \u05ea\u05d9\u05d1\u05d5\u05ea",
+"Show invisible characters": "\u05d4\u05e6\u05d2 \u05ea\u05d5\u05d5\u05d9\u05dd \u05dc\u05d0 \u05e0\u05e8\u05d0\u05d9\u05dd",
+"Words: {0}": "\u05de\u05d9\u05dc\u05d9\u05dd: {0}",
+"Insert": "\u05d4\u05d5\u05e1\u05e3",
+"File": "\u05e7\u05d5\u05d1\u05e5",
+"Edit": "\u05e2\u05e8\u05d5\u05da",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u05ea\u05d9\u05d1\u05ea \u05e2\u05e8\u05d9\u05db\u05d4 \u05d7\u05db\u05de\u05d4. \u05dc\u05d7\u05e5 Alt-F9 \u05dc\u05ea\u05e4\u05e8\u05d9\u05d8. Alt-F10 \u05dc\u05ea\u05e6\u05d5\u05d2\u05ea \u05db\u05e4\u05ea\u05d5\u05e8\u05d9\u05dd, Alt-0 \u05dc\u05e2\u05d6\u05e8\u05d4",
+"Tools": "\u05db\u05dc\u05d9\u05dd",
+"View": "\u05ea\u05e6\u05d5\u05d2\u05d4",
+"Table": "\u05d8\u05d1\u05dc\u05d4",
+"Format": "\u05e4\u05d5\u05e8\u05de\u05d8"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/hr.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/hr.js
new file mode 100755
index 0000000..81924b3
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/hr.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('hr',{
+"Cut": "Izre\u017ei",
+"Header 2": "Zaglavlje 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Va\u0161 preglednik ne podr\u017eava direktan pristup me\u0111uspremniku. Molimo Vas da umjesto toga koristite tipkovni\u010dke kratice Ctrl+X\/C\/V.",
+"Div": "DIV",
+"Paste": "Zalijepi",
+"Close": "Zatvori",
+"Pre": "PRE",
+"Align right": "Poravnaj desno",
+"New document": "Novi dokument",
+"Blockquote": "BLOCKQUOTE",
+"Numbered list": "Numerirana lista",
+"Increase indent": "Pove\u0107aj uvla\u010denje",
+"Formats": "Formati",
+"Headers": "Zaglavlja",
+"Select all": "Ozna\u010di sve",
+"Header 3": "Zaglavlje 3",
+"Blocks": "Blokovi",
+"Undo": "Poni\u0161ti",
+"Strikethrough": "Crta kroz sredinu",
+"Bullet list": "Lista",
+"Header 1": "Zaglavlje 1",
+"Superscript": "Natpis",
+"Clear formatting": "Ukloni oblikovanje",
+"Subscript": "Potpis",
+"Header 6": "Zaglavlje 6",
+"Redo": "Vrati",
+"Paragraph": "Paragraf",
+"Ok": "Uredu",
+"Bold": "Masna",
+"Code": "CODE oznaka",
+"Italic": "Kurziv",
+"Align center": "Poravnaj po sredini",
+"Header 5": "Zaglavlje 5",
+"Decrease indent": "Smanji uvla\u010denje",
+"Header 4": "Zaglavlje 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Akcija zalijepi od sada lijepi \u010disti tekst. Sadr\u017eaj \u0107e biti zaljepljen kao \u010disti tekst sve dok ne isklju\u010dite ovu opciju.",
+"Underline": "Crta ispod",
+"Cancel": "Odustani",
+"Justify": "Obostrano poravnanje",
+"Inline": "Unutarnje",
+"Copy": "Kopiraj",
+"Align left": "Poravnaj lijevo",
+"Visual aids": "Vizualna pomo\u0107",
+"Lower Greek": "Mala gr\u010dka slova",
+"Square": "Kvadrat",
+"Default": "Zadano",
+"Lower Alpha": "Mala slova",
+"Circle": "Krug",
+"Disc": "To\u010dka",
+"Upper Alpha": "Velika slova",
+"Upper Roman": "Velika rimska slova",
+"Lower Roman": "Mala rimska slova",
+"Name": "Ime",
+"Anchor": "Sidro",
+"You have unsaved changes are you sure you want to navigate away?": "Postoje ne pohranjene izmjene, jeste li sigurni da \u017eelite oti\u0107i?",
+"Restore last draft": "Vrati posljednju skicu",
+"Special character": "Poseban znak",
+"Source code": "Izvorni kod",
+"Right to left": "S desna na lijevo",
+"Left to right": "S lijeva na desno",
+"Emoticons": "Emotikoni",
+"Robots": "Roboti pretra\u017eiva\u010da",
+"Document properties": "Svojstva dokumenta",
+"Title": "Naslov",
+"Keywords": "Klju\u010dne rije\u010di",
+"Encoding": "Kodna stranica",
+"Description": "Opis",
+"Author": "Autor",
+"Fullscreen": "Cijeli ekran",
+"Horizontal line": "Horizontalna linija",
+"Horizontal space": "Horizontalan razmak",
+"Insert\/edit image": "Umetni\/izmijeni sliku",
+"General": "Op\u0107enito",
+"Advanced": "Napredno",
+"Source": "Izvor",
+"Border": "Rub",
+"Constrain proportions": "Zadr\u017ei proporcije",
+"Vertical space": "Okomit razmak",
+"Image description": "Opis slike",
+"Style": "Stil",
+"Dimensions": "Dimenzije",
+"Insert image": "Umetni sliku",
+"Insert date\/time": "Umetni datum\/vrijeme",
+"Remove link": "Ukloni poveznicu",
+"Url": "Url",
+"Text to display": "Tekst za prikaz",
+"Anchors": "Kra\u0107e poveznice",
+"Insert link": "Umetni poveznicu",
+"New window": "Novi prozor",
+"None": "Ni\u0161ta",
+"Target": "Meta",
+"Insert\/edit link": "Umetni\/izmijeni poveznicu",
+"Insert\/edit video": "Umetni\/izmijeni video",
+"Poster": "Poster",
+"Alternative source": "Alternativni izvor",
+"Paste your embed code below:": "Umetnite va\u0161 kod za ugradnju ispod:",
+"Insert video": "Umetni video",
+"Embed": "Ugradi",
+"Nonbreaking space": "Neprekidaju\u0107i razmak",
+"Page break": "Prijelom stranice",
+"Paste as text": "Zalijepi kao tekst",
+"Preview": "Pregled",
+"Print": "Ispis",
+"Save": "Spremi",
+"Could not find the specified string.": "Tra\u017eeni tekst nije prona\u0111en",
+"Replace": "Zamijeni",
+"Next": "Slijede\u0107i",
+"Whole words": "Cijele rije\u010di",
+"Find and replace": "Prona\u0111i i zamijeni",
+"Replace with": "Zamijeni s",
+"Find": "Tra\u017ei",
+"Replace all": "Zamijeni sve",
+"Match case": "Pazi na mala i velika slova",
+"Prev": "Prethodni",
+"Spellcheck": "Provjeri pravopis",
+"Finish": "Zavr\u0161i",
+"Ignore all": "Zanemari sve",
+"Ignore": "Zanemari",
+"Insert row before": "Umetni redak prije",
+"Rows": "Redci",
+"Height": "Visina",
+"Paste row after": "Zalijepi redak nakon",
+"Alignment": "Poravnanje",
+"Column group": "Grupirani stupci",
+"Row": "Redak",
+"Insert column before": "Umetni stupac prije",
+"Split cell": "Razdvoji polja",
+"Cell padding": "Razmak unutar polja",
+"Cell spacing": "Razmak izme\u0111u polja",
+"Row type": "Vrsta redka",
+"Insert table": "Umetni tablicu",
+"Body": "Sadr\u017eaj",
+"Caption": "Natpis",
+"Footer": "Podno\u017eje",
+"Delete row": "Izbri\u0161i redak",
+"Paste row before": "Zalijepi redak prije",
+"Scope": "Doseg",
+"Delete table": "Izbri\u0161i tablicu",
+"Header cell": "Polje zaglavlja",
+"Column": "Stupac",
+"Cell": "Polje",
+"Header": "Zaglavlje",
+"Cell type": "Vrsta polja",
+"Copy row": "Kopiraj redak",
+"Row properties": "Svojstva redka",
+"Table properties": "Svojstva tablice",
+"Row group": "Grupirani redci",
+"Right": "Desno",
+"Insert column after": "Umetni stupac nakon",
+"Cols": "Stupci",
+"Insert row after": "Umetni redak nakon",
+"Width": "\u0160irina",
+"Cell properties": "Svojstva polja",
+"Left": "Lijevo",
+"Cut row": "Izre\u017ei redak",
+"Delete column": "Izbri\u0161i stupac",
+"Center": "Sredina",
+"Merge cells": "Spoji polja",
+"Insert template": "Umetni predlo\u017eak",
+"Templates": "Predlo\u0161ci",
+"Background color": "Boja pozadine",
+"Text color": "Boja teksta",
+"Show blocks": "Prika\u017ei blokove",
+"Show invisible characters": "Prika\u017ei nevidljive znakove",
+"Words: {0}": "Rije\u010di: {0}",
+"Insert": "Umetni",
+"File": "Datoteka",
+"Edit": "Izmijeni",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Pritisni ALT-F9 za izbornik. Pritisni ALT-F10 za alatnu traku. Pritisni ALT-0 za pomo\u0107",
+"Tools": "Alati",
+"View": "Pogled",
+"Table": "Tablica",
+"Format": "Oblikuj"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/hu_HU.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/hu_HU.js
new file mode 100755
index 0000000..e3705ca
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/hu_HU.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('hu_HU',{
+"Cut": "Kiv\u00e1g\u00e1s",
+"Header 2": "C\u00edmsor 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "A b\u00f6ng\u00e9sz\u0151d nem t\u00e1mogatja a k\u00f6zvetlen hozz\u00e1f\u00e9r\u00e9st a v\u00e1g\u00f3laphoz. K\u00e9rlek haszn\u00e1ld a Ctrl+X\/C\/V billenty\u0171ket.",
+"Div": "Div",
+"Paste": "Beilleszt\u00e9s",
+"Close": "Bez\u00e1r",
+"Pre": "El\u0151",
+"Align right": "Jobbra igaz\u00edt",
+"New document": "\u00daj dokumentum",
+"Blockquote": "Id\u00e9zetblokk",
+"Numbered list": "Sz\u00e1moz\u00e1s",
+"Increase indent": "Beh\u00faz\u00e1s n\u00f6vel\u00e9se",
+"Formats": "Form\u00e1tumok",
+"Headers": "C\u00edmsorok",
+"Select all": "Minden kijel\u00f6l\u00e9se",
+"Header 3": "C\u00edmsor 3",
+"Blocks": "Blokkok",
+"Undo": "Visszavon\u00e1s",
+"Strikethrough": "\u00c1th\u00fazott",
+"Bullet list": "Felsorol\u00e1s",
+"Header 1": "C\u00edmsor 1",
+"Superscript": "Fels\u0151 index",
+"Clear formatting": "Form\u00e1z\u00e1s t\u00f6rl\u00e9se",
+"Subscript": "Als\u00f3 index",
+"Header 6": "C\u00edmsor 6",
+"Redo": "Ism\u00e9t",
+"Paragraph": "Bekezd\u00e9s",
+"Ok": "Rendben",
+"Bold": "F\u00e9lk\u00f6v\u00e9r",
+"Code": "K\u00f3d",
+"Italic": "D\u0151lt",
+"Align center": "K\u00f6z\u00e9pre z\u00e1r",
+"Header 5": "C\u00edmsor 5",
+"Decrease indent": "Beh\u00faz\u00e1s cs\u00f6kkent\u00e9se",
+"Header 4": "C\u00edmsor 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Beilleszt\u00e9s mostant\u00f3l egyszer\u0171 sz\u00f6veg m\u00f3dban. A tartalmak mostant\u00f3l egyszer\u0171 sz\u00f6vegk\u00e9nt lesznek beillesztve, am\u00edg nem kapcsolod ki ezt az opci\u00f3t.",
+"Underline": "Al\u00e1h\u00fazott",
+"Cancel": "M\u00e9gse",
+"Justify": "Sorkiz\u00e1r\u00e1s",
+"Inline": "Vonalon bel\u00fcl",
+"Copy": "M\u00e1sol\u00e1s",
+"Align left": "Balra igaz\u00edt",
+"Visual aids": "Vizu\u00e1lis seg\u00e9deszk\u00f6z\u00f6k",
+"Lower Greek": "Kis g\u00f6r\u00f6g sz\u00e1m",
+"Square": "N\u00e9gyzet",
+"Default": "Alap\u00e9rtelmezett",
+"Lower Alpha": "Kisbet\u0171",
+"Circle": "K\u00f6r",
+"Disc": "Pont",
+"Upper Alpha": "Nagybet\u0171",
+"Upper Roman": "Nagy r\u00f3mai sz\u00e1m",
+"Lower Roman": "Kis r\u00f3mai sz\u00e1m",
+"Name": "N\u00e9v",
+"Anchor": "Horgony",
+"You have unsaved changes are you sure you want to navigate away?": "Nem mentett m\u00f3dos\u00edt\u00e1said vannak, biztos hogy el akarsz navig\u00e1lni?",
+"Restore last draft": "Utols\u00f3 piszkozat vissza\u00e1ll\u00edt\u00e1sa",
+"Special character": "Speci\u00e1lis karakter",
+"Source code": "Forr\u00e1sk\u00f3d",
+"Right to left": "Jobbr\u00f3l balra",
+"Left to right": "Balr\u00f3l jobbra",
+"Emoticons": "Mosolyok",
+"Robots": "Robotok",
+"Document properties": "Dokumentum tulajdons\u00e1gai",
+"Title": "C\u00edm",
+"Keywords": "Kulcsszavak",
+"Encoding": "K\u00f3dol\u00e1s",
+"Description": "Le\u00edr\u00e1s",
+"Author": "Szerz\u0151",
+"Fullscreen": "Teljes k\u00e9perny\u0151",
+"Horizontal line": "V\u00edzszintes vonal",
+"Horizontal space": "Horizont\u00e1lis hely",
+"Insert\/edit image": "K\u00e9p beilleszt\u00e9se\/szerkeszt\u00e9se",
+"General": "\u00c1ltal\u00e1nos",
+"Advanced": "Halad\u00f3",
+"Source": "Forr\u00e1s",
+"Border": "Szeg\u00e9ly",
+"Constrain proportions": "M\u00e9retar\u00e1ny",
+"Vertical space": "Vertik\u00e1lis hely",
+"Image description": "K\u00e9p le\u00edr\u00e1sa",
+"Style": "St\u00edlus",
+"Dimensions": "M\u00e9retek",
+"Insert image": "K\u00e9p besz\u00far\u00e1sa",
+"Insert date\/time": "D\u00e1tum\/id\u0151 beilleszt\u00e9se",
+"Remove link": "Hivatkoz\u00e1s t\u00f6rl\u00e9se",
+"Url": "Url",
+"Text to display": "Megjelen\u0151 sz\u00f6veg",
+"Anchors": "Horgonyok",
+"Insert link": "Link beilleszt\u00e9se",
+"New window": "\u00daj ablak",
+"None": "Nincs",
+"Target": "C\u00e9l",
+"Insert\/edit link": "Link beilleszt\u00e9se\/szerkeszt\u00e9se",
+"Insert\/edit video": "Vide\u00f3 beilleszt\u00e9se\/szerkeszt\u00e9se",
+"Poster": "El\u0151n\u00e9zeti k\u00e9p",
+"Alternative source": "Alternat\u00edv forr\u00e1s",
+"Paste your embed code below:": "Illeszd be a be\u00e1gyaz\u00f3 k\u00f3dot alulra:",
+"Insert video": "Vide\u00f3 beilleszt\u00e9se",
+"Embed": "Be\u00e1gyaz",
+"Nonbreaking space": "Nem t\u00f6rhet\u0151 hely",
+"Page break": "Oldalt\u00f6r\u00e9s",
+"Paste as text": "Beilleszt\u00e9s sz\u00f6vegk\u00e9nt",
+"Preview": "El\u0151n\u00e9zet",
+"Print": "Nyomtat\u00e1s",
+"Save": "Ment\u00e9s",
+"Could not find the specified string.": "A be\u00edrt kifejez\u00e9s nem tal\u00e1lhat\u00f3.",
+"Replace": "Csere",
+"Next": "K\u00f6vetkez\u0151",
+"Whole words": "Csak ha ez a teljes sz\u00f3",
+"Find and replace": "Keres\u00e9s \u00e9s csere",
+"Replace with": "Csere erre",
+"Find": "Keres\u00e9s",
+"Replace all": "Az \u00f6sszes cser\u00e9je",
+"Match case": "Teljes egyez\u00e9s",
+"Prev": "El\u0151z\u0151",
+"Spellcheck": "Helyes\u00edr\u00e1s ellen\u0151rz\u00e9s",
+"Finish": "Befejez\u00e9s",
+"Ignore all": "Mindent figyelmen k\u00edv\u00fcl hagy",
+"Ignore": "Figyelmen k\u00edv\u00fcl hagy",
+"Insert row before": "Sor besz\u00far\u00e1sa el\u00e9",
+"Rows": "Sorok",
+"Height": "Magass\u00e1g",
+"Paste row after": "Sor beilleszt\u00e9se m\u00f6g\u00e9",
+"Alignment": "Igaz\u00edt\u00e1s",
+"Column group": "Oszlop csoport",
+"Row": "Sor",
+"Insert column before": "Oszlop besz\u00far\u00e1sa el\u00e9",
+"Split cell": "Cell\u00e1k sz\u00e9tv\u00e1laszt\u00e1sa",
+"Cell padding": "Cella m\u00e9rete",
+"Cell spacing": "Cell\u00e1k t\u00e1vols\u00e1ga",
+"Row type": "Sor t\u00edpus",
+"Insert table": "T\u00e1bl\u00e1zat beilleszt\u00e9se",
+"Body": "Sz\u00f6vegt\u00f6rzs",
+"Caption": "Felirat",
+"Footer": "L\u00e1bl\u00e9c",
+"Delete row": "Sor t\u00f6rl\u00e9se",
+"Paste row before": "Sor beilleszt\u00e9se el\u00e9",
+"Scope": "Hat\u00f3k\u00f6r",
+"Delete table": "T\u00e1bl\u00e1zat t\u00f6rl\u00e9se",
+"Header cell": "Fejl\u00e9c cella",
+"Column": "Oszlop",
+"Cell": "Cella",
+"Header": "Fejl\u00e9c",
+"Cell type": "Cella t\u00edpusa",
+"Copy row": "Sor m\u00e1sol\u00e1sa",
+"Row properties": "Sor tulajdons\u00e1gai",
+"Table properties": "T\u00e1bl\u00e1zat tulajdons\u00e1gok",
+"Row group": "Sor csoport",
+"Right": "Jobb",
+"Insert column after": "Oszlop besz\u00far\u00e1sa m\u00f6g\u00e9",
+"Cols": "Oszlopok",
+"Insert row after": "Sor besz\u00far\u00e1sa m\u00f6g\u00e9",
+"Width": "Sz\u00e9less\u00e9g",
+"Cell properties": "Cella tulajdons\u00e1gok",
+"Left": "Bal",
+"Cut row": "Sor kiv\u00e1g\u00e1sa",
+"Delete column": "Oszlop t\u00f6rl\u00e9se",
+"Center": "K\u00f6z\u00e9p",
+"Merge cells": "Cell\u00e1k egyes\u00edt\u00e9se",
+"Insert template": "Sablon beilleszt\u00e9se",
+"Templates": "Sablonok",
+"Background color": "H\u00e1tt\u00e9r sz\u00edn",
+"Text color": "Sz\u00f6veg sz\u00edne",
+"Show blocks": "Blokkok mutat\u00e1sa",
+"Show invisible characters": "L\u00e1thatatlan karakterek mutat\u00e1sa",
+"Words: {0}": "Szavak: {0}",
+"Insert": "Beilleszt\u00e9s",
+"File": "F\u00e1jl",
+"Edit": "Szerkeszt\u00e9s",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rich Text ter\u00fclet. Nyomj ALT-F9-et a men\u00fch\u00f6z. Nyomj ALT-F10-et az eszk\u00f6zt\u00e1rhoz. Nyomj ALT-0-t a s\u00fag\u00f3hoz",
+"Tools": "Eszk\u00f6z\u00f6k",
+"View": "N\u00e9zet",
+"Table": "T\u00e1bl\u00e1zat",
+"Format": "Form\u00e1tum"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/id.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/id.js
new file mode 100755
index 0000000..c62179c
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/id.js
@@ -0,0 +1,71 @@
+tinymce.addI18n('id',{
+"Cut": "Penggal",
+"Header 2": "Header 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Browser anda tidak mendukung akses langsung ke clipboard. Silahkan gunakan Ctrl+X\/C\/V dari keyboard.",
+"Div": "Div",
+"Paste": "Tempel",
+"Close": "Tutup",
+"Pre": "Pre",
+"Align right": "Rata kanan",
+"New document": "Dokumen baru",
+"Blockquote": "Kutipan",
+"Numbered list": "list nomor",
+"Increase indent": "Tambah inden",
+"Formats": "Format",
+"Headers": "Header",
+"Select all": "Pilih semua",
+"Header 3": "Header 3",
+"Blocks": "Blok",
+"Undo": "Batal",
+"Strikethrough": "Coret",
+"Bullet list": "list simbol",
+"Header 1": "Header 1",
+"Superscript": "Superskrip",
+"Clear formatting": "Hapus format",
+"Subscript": "Subskrip",
+"Header 6": "Header 6",
+"Redo": "Ulang",
+"Paragraph": "Paragraf",
+"Ok": "Ok",
+"Bold": "Tebal",
+"Code": "Code",
+"Italic": "Miring",
+"Align center": "Rate tengah",
+"Header 5": "Header 5",
+"Decrease indent": "Turunkan inden",
+"Header 4": "Header 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Aksi 'Tempel' sekarang ini dalam mode text. Konten akan 'ditempelkan' sebagai 'Plain Text' hingga anda mematikan opsi ini.",
+"Underline": "Garis bawah",
+"Cancel": "Batal",
+"Justify": "Justifi",
+"Inline": "Inline",
+"Copy": "Salin",
+"Align left": "Rate kiri",
+"Visual aids": "Alat bantu visual",
+"Lower Greek": "Lower Yunani",
+"Square": "Kotak",
+"Default": "Bawaan",
+"Lower Alpha": "Lower Alpha",
+"Circle": "Lingkaran",
+"Disc": "Cakram",
+"Upper Alpha": "Upper Alpha",
+"Upper Roman": "Upper Roman",
+"Lower Roman": "Lower Roman",
+"Name": "Nama",
+"Anchor": "Anjar",
+"You have unsaved changes are you sure you want to navigate away?": "Anda memiliki perubahan yang belum disimpan, yakin ingin beralih ?",
+"Restore last draft": "Muat kembali draft sebelumnya",
+"Special character": "Spesial karakter",
+"Source code": "Kode sumber",
+"Right to left": "Kanan ke kiri",
+"Left to right": "Kiri ke kanan",
+"Emoticons": "Emotikon",
+"Robots": "Robot",
+"Document properties": "Properti dokumwn",
+"Title": "Judul",
+"Keywords": "Kata kunci",
+"Encoding": "Enkoding",
+"Description": "Deskripsi",
+"Author": "Penulis",
+"Fullscreen": "Layar penuh"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/it.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/it.js
new file mode 100755
index 0000000..90a34df
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/it.js
@@ -0,0 +1,174 @@
+tinymce.addI18n('it',{
+"Cut": "Taglia",
+"Header 2": "Header 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Il tuo browser non supporta l'accesso diretto negli Appunti. Per favore usa i tasti di scelta rapida Ctrl+X\/C\/V.",
+"Div": "Div",
+"Paste": "Incolla",
+"Close": "Chiudi",
+"Pre": "Pre",
+"Align right": "Allinea a Destra",
+"New document": "Nuovo Documento",
+"Blockquote": "Blockquote",
+"Numbered list": "Elenchi Numerati",
+"Increase indent": "Aumenta Rientro",
+"Formats": "Formattazioni",
+"Headers": "Intestazioni",
+"Select all": "Seleziona Tutto",
+"Header 3": "Intestazione 3",
+"Blocks": "Blocchi",
+"Undo": "Indietro",
+"Strikethrough": "Barrato",
+"Bullet list": "Elenchi Puntati",
+"Header 1": "Intestazione 1",
+"Superscript": "Apice",
+"Clear formatting": "Cancella Formattazione",
+"Subscript": "Pedice",
+"Header 6": "Intestazione 6",
+"Redo": "Ripeti",
+"Paragraph": "Paragrafo",
+"Ok": "Ok",
+"Bold": "Grassetto",
+"Code": "Codice",
+"Italic": "Corsivo",
+"Align center": "Allinea al Cento",
+"Header 5": "Intestazione 5",
+"Decrease indent": "Riduci Rientro",
+"Header 4": "Intestazione 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Incolla \u00e8 in modalit\u00e0 testo normale. I contenuti sono incollati come testo normale se non disattivi l'opzione.",
+"Underline": "Sottolineato",
+"Cancel": "Cancella",
+"Justify": "Giustifica",
+"Inline": "Inlinea",
+"Copy": "Copia",
+"Align left": "Allinea a Sinistra",
+"Visual aids": "Elementi Visivi",
+"Lower Greek": "Greek Minore",
+"Square": "Quadrato",
+"Default": "Default",
+"Lower Alpha": "Alpha Minore",
+"Circle": "Cerchio",
+"Disc": "Disco",
+"Upper Alpha": "Alpha Superiore",
+"Upper Roman": "Roman Superiore",
+"Lower Roman": "Roman Minore",
+"Name": "Nome",
+"Anchor": "Fissa",
+"You have unsaved changes are you sure you want to navigate away?": "Non hai salvato delle modifiche, sei sicuro di andartene?",
+"Restore last draft": "Ripristina l'ultima bozza.",
+"Special character": "Carattere Speciale",
+"Source code": "Codice Sorgente",
+"Right to left": "Da Destra a Sinistra",
+"Left to right": "Da Sinistra a Destra",
+"Emoticons": "Emoction",
+"Robots": "Robot",
+"Document properties": "Propriet\u00e0 Documento",
+"Title": "Titolo",
+"Keywords": "Parola Chiave",
+"Encoding": "Codifica",
+"Description": "Descrizione",
+"Author": "Autore",
+"Fullscreen": "Schermo Intero",
+"Horizontal line": "Linea Orizzontale",
+"Horizontal space": "Spazio Orizzontale",
+"Insert\/edit image": "Aggiungi\/Modifica Immagine",
+"General": "Generale",
+"Advanced": "Avanzato",
+"Source": "Fonte",
+"Border": "Bordo",
+"Constrain proportions": "Mantieni Proporzioni",
+"Vertical space": "Spazio Verticale",
+"Image description": "Descrizione Immagine",
+"Style": "Stile",
+"Dimensions": "Dimenzioni",
+"Insert image": "Inserisci immagine",
+"Insert date\/time": "Inserisci Data\/Ora",
+"Remove link": "Rimuovi link",
+"Url": "Url",
+"Text to display": "Testo da Visualizzare",
+"Anchors": "Anchors",
+"Insert link": "Inserisci il Link",
+"New window": "Nuova Finestra",
+"None": "No",
+"Target": "Target",
+"Insert\/edit link": "Inserisci\/Modifica Link",
+"Insert\/edit video": "Inserisci\/Modifica Video",
+"Poster": "Anteprima",
+"Alternative source": "Alternativo",
+"Paste your embed code below:": "Incolla il codice d'incorporamento qui:",
+"Insert video": "Inserisci Video",
+"Embed": "Incorporare",
+"Nonbreaking space": "Spazio unificatore",
+"Paste as text": "incolla come testo",
+"Preview": "Anteprima",
+"Print": "Stampa",
+"Save": "Salva",
+"Could not find the specified string.": "Impossibile trovare la parola specifica.",
+"Replace": "Sostituisci",
+"Next": "Successivo",
+"Whole words": "Parole Sbagliate",
+"Find and replace": "Trova e Sostituisci",
+"Replace with": "Sostituisci Con",
+"Find": "Trova",
+"Replace all": "Sostituisci Tutto",
+"Match case": "Maiuscole\/Minuscole ",
+"Prev": "Precedente",
+"Spellcheck": "Controllo ortografico",
+"Finish": "Termina",
+"Ignore all": "Ignora Tutto",
+"Ignore": "Ignora",
+"Insert row before": "Inserisci una Riga Prima",
+"Rows": "Righe",
+"Height": "Altezza",
+"Paste row after": "Incolla una Riga Dopo",
+"Alignment": "Allineamento",
+"Column group": "Gruppo di Colonne",
+"Row": "Riga",
+"Insert column before": "Inserisci una Colonna Prima",
+"Split cell": "Dividi Cella",
+"Cell padding": "Padding della Cella",
+"Cell spacing": "Spaziatura della Cella",
+"Row type": "Tipo di Riga",
+"Insert table": "Inserisci Tabella",
+"Body": "Body",
+"Caption": "Didascalia",
+"Footer": "Footer",
+"Delete row": "Cancella Riga",
+"Paste row before": "Incolla una Riga Prima",
+"Scope": "Campo",
+"Delete table": "Cancella Tabella",
+"Header cell": "cella d'intestazione",
+"Column": "Colonna",
+"Cell": "Cella",
+"Header": "Header",
+"Cell type": "Tipo di Cella",
+"Copy row": "Copia Riga",
+"Row properties": "Propriet\u00e0 della Riga",
+"Table properties": "Propiet\u00e0 della Tabella",
+"Row group": "Gruppo di Righe",
+"Right": "Destra",
+"Insert column after": "Inserisci una Colonna Dopo",
+"Cols": "Colonne",
+"Insert row after": "Inserisci una Riga Dopo",
+"Width": "Larghezza",
+"Cell properties": "Propiet\u00e0 della Cella",
+"Left": "Sinistra",
+"Cut row": "Taglia Riga",
+"Delete column": "Cancella Colonna",
+"Center": "Centro",
+"Merge cells": "Unisci Cella",
+"Insert template": "Inserisci Template",
+"Templates": "Template",
+"Background color": "Colore Background",
+"Text color": "Colore Testo",
+"Show blocks": "Mostra Blocchi",
+"Show invisible characters": "Mostra Caratteri Invisibili",
+"Words: {0}": "Parole: {0}",
+"Insert": "Inserisci",
+"File": "File",
+"Edit": "Modifica",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rich Text Area. Premi ALT-F9 per il men\u00f9. Premi ALT-F10 per la barra degli strumenti. Premi ALT-0 per l'aiuto.",
+"Tools": "Strumenti",
+"View": "Visualiza",
+"Table": "Tabella",
+"Format": "Formato"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ja.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ja.js
new file mode 100755
index 0000000..75a23c3
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ja.js
@@ -0,0 +1,174 @@
+tinymce.addI18n('ja',{
+"Cut": "\u5207\u308a\u53d6\u308a",
+"Header 2": "\u30d8\u30c3\u30c0\u30fc 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u304a\u4f7f\u3044\u306e\u30d6\u30e9\u30a6\u30b6\u3067\u306f\u30af\u30ea\u30c3\u30d7\u30dc\u30fc\u30c9\u6a5f\u80fd\u3092\u5229\u7528\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093\u3002\u30ad\u30fc\u30dc\u30fc\u30c9\u306e\u30b7\u30e7\u30fc\u30c8\u30ab\u30c3\u30c8\uff08Ctrl+X, Ctrl+C, Ctrl+V\uff09\u3092\u304a\u4f7f\u3044\u4e0b\u3055\u3044\u3002",
+"Div": "Div",
+"Paste": "\u8cbc\u308a\u4ed8\u3051",
+"Close": "\u9589\u3058\u308b",
+"Pre": "Pre",
+"Align right": "\u53f3\u5bc4\u305b",
+"New document": "\u65b0\u898f\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8",
+"Blockquote": "Blockquote",
+"Numbered list": "\u756a\u53f7\u4ed8\u304d\u7b87\u6761\u66f8\u304d",
+"Increase indent": "\u30a4\u30f3\u30c7\u30f3\u30c8\u3092\u5897\u3084\u3059",
+"Formats": "\u66f8\u5f0f",
+"Headers": "\u30d8\u30c3\u30c0\u30fc",
+"Select all": "\u5168\u3066\u3092\u9078\u629e",
+"Header 3": "\u30d8\u30c3\u30c0\u30fc 3",
+"Blocks": "\u30d6\u30ed\u30c3\u30af",
+"Undo": "\u5143\u306b\u623b\u3059",
+"Strikethrough": "\u53d6\u308a\u6d88\u3057\u7dda",
+"Bullet list": "\u7b87\u6761\u66f8\u304d",
+"Header 1": "\u30d8\u30c3\u30c0\u30fc 1",
+"Superscript": "\u4e0a\u4ed8\u304d\u6587\u5b57",
+"Clear formatting": "\u66f8\u5f0f\u3092\u30af\u30ea\u30a2",
+"Subscript": "\u4e0b\u4ed8\u304d\u6587\u5b57",
+"Header 6": "\u30d8\u30c3\u30c0\u30fc 6",
+"Redo": "\u3084\u308a\u76f4\u3059",
+"Paragraph": "\u6bb5\u843d",
+"Ok": "OK",
+"Bold": "\u592a\u5b57",
+"Code": "\u30b3\u30fc\u30c9",
+"Italic": "\u659c\u4f53",
+"Align center": "\u4e2d\u592e\u63c3\u3048",
+"Header 5": "\u30d8\u30c3\u30c0\u30fc 5",
+"Decrease indent": "\u30a4\u30f3\u30c7\u30f3\u30c8\u3092\u6e1b\u3089\u3059",
+"Header 4": "\u30d8\u30c3\u30c0\u30fc 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u8cbc\u308a\u4ed8\u3051\u306f\u73fe\u5728\u30d7\u30ec\u30fc\u30f3\u30c6\u30ad\u30b9\u30c8\u30e2\u30fc\u30c9\u3067\u3059\u3002\u3053\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u3092\u30aa\u30d5\u306b\u3057\u306a\u3044\u9650\u308a\u5185\u5bb9\u306f\u30d7\u30ec\u30fc\u30f3\u30c6\u30ad\u30b9\u30c8\u3068\u3057\u3066\u8cbc\u308a\u4ed8\u3051\u3089\u308c\u307e\u3059\u3002",
+"Underline": "\u4e0b\u7dda",
+"Cancel": "\u30ad\u30e3\u30f3\u30bb\u30eb",
+"Justify": "\u4e21\u7aef\u63c3\u3048",
+"Inline": "\u30a4\u30f3\u30e9\u30a4\u30f3",
+"Copy": "\u30b3\u30d4\u30fc",
+"Align left": "\u5de6\u5bc4\u305b",
+"Visual aids": "\u8868\u306e\u67a0\u7dda\u3092\u70b9\u7dda\u3067\u8868\u793a",
+"Lower Greek": "\u5c0f\u6587\u5b57\u306e\u30ae\u30ea\u30b7\u30e3\u6587\u5b57",
+"Square": "\u56db\u89d2",
+"Default": "\u30c7\u30d5\u30a9\u30eb\u30c8",
+"Lower Alpha": "\u5c0f\u6587\u5b57\u306e\u30a2\u30eb\u30d5\u30a1\u30d9\u30c3\u30c8",
+"Circle": "\u5186",
+"Disc": "\u70b9",
+"Upper Alpha": "\u5927\u6587\u5b57\u306e\u30a2\u30eb\u30d5\u30a1\u30d9\u30c3\u30c8",
+"Upper Roman": "\u5927\u6587\u5b57\u306e\u30ed\u30fc\u30de\u6570\u5b57",
+"Lower Roman": "\u5c0f\u6587\u5b57\u306e\u30ed\u30fc\u30de\u6570\u5b57",
+"Name": "\u30a2\u30f3\u30ab\u30fc\u540d",
+"Anchor": "\u30a2\u30f3\u30ab\u30fc\uff08\u30ea\u30f3\u30af\u306e\u5230\u9054\u70b9\uff09",
+"You have unsaved changes are you sure you want to navigate away?": "\u307e\u3060\u4fdd\u5b58\u3057\u3066\u3044\u306a\u3044\u5909\u66f4\u304c\u3042\u308a\u307e\u3059\u304c\u3001\u672c\u5f53\u306b\u3053\u306e\u30da\u30fc\u30b8\u3092\u96e2\u308c\u307e\u3059\u304b\uff1f",
+"Restore last draft": "\u524d\u56de\u306e\u4e0b\u66f8\u304d\u3092\u5fa9\u6d3b\u3055\u305b\u308b",
+"Special character": "\u7279\u6b8a\u6587\u5b57",
+"Source code": "\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9",
+"Right to left": "\u53f3\u304b\u3089\u5de6",
+"Left to right": "\u5de6\u304b\u3089\u53f3",
+"Emoticons": "\u7d75\u6587\u5b57",
+"Robots": "\u30ed\u30dc\u30c3\u30c8",
+"Document properties": "\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306e\u30d7\u30ed\u30d1\u30c6\u30a3",
+"Title": "\u30bf\u30a4\u30c8\u30eb",
+"Keywords": "\u30ad\u30fc\u30ef\u30fc\u30c9",
+"Encoding": "\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0",
+"Description": "\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u5185\u5bb9",
+"Author": "\u8457\u8005",
+"Fullscreen": "\u5168\u753b\u9762\u8868\u793a",
+"Horizontal line": "\u6c34\u5e73\u7f6b\u7dda",
+"Horizontal space": "\u6a2a\u65b9\u5411\u306e\u4f59\u767d",
+"Insert\/edit image": "\u753b\u50cf\u306e\u633f\u5165\u30fb\u7de8\u96c6",
+"General": "\u4e00\u822c",
+"Advanced": "\u8a73\u7d30\u8a2d\u5b9a",
+"Source": "\u753b\u50cf\u306e\u30bd\u30fc\u30b9",
+"Border": "\u67a0\u7dda",
+"Constrain proportions": "\u7e26\u6a2a\u6bd4\u3092\u4fdd\u6301\u3059\u308b",
+"Vertical space": "\u7e26\u65b9\u5411\u306e\u4f59\u767d",
+"Image description": "\u753b\u50cf\u306e\u8aac\u660e\u6587",
+"Style": "\u30b9\u30bf\u30a4\u30eb",
+"Dimensions": "\u753b\u50cf\u30b5\u30a4\u30ba\uff08\u6a2a\u30fb\u7e26\uff09",
+"Insert image": "\u753b\u50cf\u306e\u633f\u5165",
+"Insert date\/time": "\u65e5\u4ed8\u30fb\u6642\u523b",
+"Remove link": "\u30ea\u30f3\u30af\u306e\u524a\u9664",
+"Url": "\u30ea\u30f3\u30af\u5148URL",
+"Text to display": "\u30ea\u30f3\u30af\u5143\u30c6\u30ad\u30b9\u30c8",
+"Anchors": "\u30a2\u30f3\u30ab\u30fc\uff08\u30ea\u30f3\u30af\u306e\u5230\u9054\u70b9\uff09",
+"Insert link": "\u30ea\u30f3\u30af",
+"New window": "\u65b0\u898f\u30a6\u30a3\u30f3\u30c9\u30a6",
+"None": "\u306a\u3057",
+"Target": "\u30bf\u30fc\u30b2\u30c3\u30c8\u5c5e\u6027",
+"Insert\/edit link": "\u30ea\u30f3\u30af\u306e\u633f\u5165\u30fb\u7de8\u96c6",
+"Insert\/edit video": "\u52d5\u753b\u306e\u633f\u5165\u30fb\u7de8\u96c6",
+"Poster": "\u4ee3\u66ff\u753b\u50cf\u306e\u5834\u6240",
+"Alternative source": "\u4ee3\u66ff\u52d5\u753b\u306e\u5834\u6240",
+"Paste your embed code below:": "\u57cb\u3081\u8fbc\u307f\u7528\u30b3\u30fc\u30c9\u3092\u4e0b\u8a18\u306b\u8cbc\u308a\u4ed8\u3051\u3066\u304f\u3060\u3055\u3044\u3002",
+"Insert video": "\u52d5\u753b",
+"Embed": "\u57cb\u3081\u8fbc\u307f",
+"Nonbreaking space": "\u56fa\u5b9a\u30b9\u30da\u30fc\u30b9\uff08&nbsp;\uff09",
+"Page break": "\u30da\u30fc\u30b8\u533a\u5207\u308a",
+"Preview": "\u30d7\u30ec\u30d3\u30e5\u30fc",
+"Print": "\u5370\u5237",
+"Save": "\u4fdd\u5b58",
+"Could not find the specified string.": "\u304a\u63a2\u3057\u306e\u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002",
+"Replace": "\u7f6e\u304d\u63db\u3048",
+"Next": "\u6b21",
+"Whole words": "\u5358\u8a9e\u5358\u4f4d\u3067\u691c\u7d22\u3059\u308b",
+"Find and replace": "\u691c\u7d22\u3068\u7f6e\u304d\u63db\u3048",
+"Replace with": "\u7f6e\u304d\u63db\u3048",
+"Find": "\u691c\u7d22\u3059\u308b\u6587\u5b57",
+"Replace all": "\u5168\u3066\u3092\u7f6e\u304d\u63db\u3048\u308b",
+"Match case": "\u5927\u6587\u5b57\u30fb\u5c0f\u6587\u5b57\u3092\u533a\u5225\u3059\u308b",
+"Prev": "\u524d",
+"Spellcheck": "\u30b9\u30da\u30eb\u30c1\u30a7\u30c3\u30af",
+"Finish": "\u7d42\u4e86",
+"Ignore all": "\u5168\u3066\u3092\u7121\u8996",
+"Ignore": "\u7121\u8996",
+"Insert row before": "\u4e0a\u5074\u306b\u884c\u3092\u633f\u5165",
+"Rows": "\u884c\u6570",
+"Height": "\u9ad8\u3055",
+"Paste row after": "\u4e0b\u5074\u306b\u884c\u3092\u8cbc\u308a\u4ed8\u3051",
+"Alignment": "\u914d\u7f6e",
+"Column group": "\u5217\u30b0\u30eb\u30fc\u30d7",
+"Row": "\u884c",
+"Insert column before": "\u5de6\u5074\u306b\u5217\u3092\u633f\u5165",
+"Split cell": "\u30bb\u30eb\u306e\u5206\u5272",
+"Cell padding": "\u30bb\u30eb\u5185\u4f59\u767d\uff08\u30d1\u30c7\u30a3\u30f3\u30b0\uff09",
+"Cell spacing": "\u30bb\u30eb\u306e\u9593\u9694",
+"Row type": "\u884c\u30bf\u30a4\u30d7",
+"Insert table": "\u8868\u306e\u633f\u5165",
+"Body": "\u30dc\u30c7\u30a3\u30fc",
+"Caption": "\u8868\u984c",
+"Footer": "\u30d5\u30c3\u30bf\u30fc",
+"Delete row": "\u884c\u306e\u524a\u9664",
+"Paste row before": "\u4e0a\u5074\u306b\u884c\u3092\u8cbc\u308a\u4ed8\u3051",
+"Scope": "\u30b9\u30b3\u30fc\u30d7",
+"Delete table": "\u8868\u306e\u524a\u9664",
+"Header cell": "\u30d8\u30c3\u30c0\u30fc\u30bb\u30eb",
+"Column": "\u5217",
+"Cell": "\u30bb\u30eb",
+"Header": "\u30d8\u30c3\u30c0\u30fc",
+"Cell type": "\u30bb\u30eb\u30bf\u30a4\u30d7",
+"Copy row": "\u884c\u306e\u30b3\u30d4\u30fc",
+"Row properties": "\u884c\u306e\u8a73\u7d30\u8a2d\u5b9a",
+"Table properties": "\u8868\u306e\u8a73\u7d30\u8a2d\u5b9a",
+"Row group": "\u884c\u30b0\u30eb\u30fc\u30d7",
+"Right": "\u53f3\u5bc4\u305b",
+"Insert column after": "\u53f3\u5074\u306b\u5217\u3092\u633f\u5165",
+"Cols": "\u5217\u6570",
+"Insert row after": "\u4e0b\u5074\u306b\u884c\u3092\u633f\u5165",
+"Width": "\u5e45",
+"Cell properties": "\u30bb\u30eb\u306e\u8a73\u7d30\u8a2d\u5b9a",
+"Left": "\u5de6\u5bc4\u305b",
+"Cut row": "\u884c\u306e\u5207\u308a\u53d6\u308a",
+"Delete column": "\u5217\u306e\u524a\u9664",
+"Center": "\u4e2d\u592e\u63c3\u3048",
+"Merge cells": "\u30bb\u30eb\u306e\u7d50\u5408",
+"Insert template": "\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u633f\u5165",
+"Templates": "\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u4e00\u89a7",
+"Background color": "\u80cc\u666f\u8272",
+"Text color": "\u6587\u5b57\u306e\u8272",
+"Show blocks": "\u6587\u7ae0\u306e\u533a\u5207\u308a\u3092\u70b9\u7dda\u3067\u8868\u793a",
+"Show invisible characters": "\u4e0d\u53ef\u8996\u6587\u5b57\u3092\u8868\u793a",
+"Words: {0}": "\u5358\u8a9e\u6570: {0}",
+"Insert": "\u633f\u5165",
+"File": "\u30d5\u30a1\u30a4\u30eb",
+"Edit": "\u7de8\u96c6",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u66f8\u5f0f\u4ed8\u304d\u30c6\u30ad\u30b9\u30c8\u306e\u7de8\u96c6\u753b\u9762\u3002ALT-F9\u3067\u30e1\u30cb\u30e5\u30fc\u3001ALT-F10\u3067\u30c4\u30fc\u30eb\u30d0\u30fc\u3001ALT-0\u3067\u30d8\u30eb\u30d7\u304c\u8868\u793a\u3055\u308c\u307e\u3059\u3002",
+"Tools": "\u30c4\u30fc\u30eb",
+"View": "\u8868\u793a",
+"Table": "\u8868",
+"Format": "\u66f8\u5f0f"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ka_GE.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ka_GE.js
new file mode 100755
index 0000000..5846773
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ka_GE.js
@@ -0,0 +1,172 @@
+tinymce.addI18n('ka_GE',{
+"Cut": "\u10d0\u10db\u10dd\u10ed\u10e0\u10d0",
+"Header 2": "\u10e1\u10d0\u10d7\u10d0\u10e3\u10e0\u10d8 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u10d7\u10e5\u10d5\u10d4\u10dc \u10d1\u10e0\u10d0\u10e3\u10d6\u10d4\u10e0\u10e1 \u10d0\u10e0 \u10d0\u10e5\u10d5\u10e1 \u10d1\u10e3\u10e4\u10e0\u10e2\u10e8\u10d8 \u10e8\u10d4\u10ee\u10ec\u10d4\u10d5\u10d8\u10e1 \u10db\u10ee\u10d0\u10e0\u10d3\u10d0\u10ed\u10d4\u10e0\u10d0. \u10d2\u10d7\u10ee\u10dd\u10d5\u10d7 \u10e1\u10d0\u10dc\u10d0\u10ea\u10d5\u10da\u10dd\u10d3 \u10d8\u10e1\u10d0\u10e0\u10d2\u10d4\u10d1\u10da\u10dd\u10d7 Ctrl+X\/C\/V \u10db\u10d0\u10da\u10e1\u10d0\u10ee\u10db\u10dd\u10d1\u10d8 \u10d9\u10dd\u10db\u10d1\u10d8\u10dc\u10d0\u10ea\u10d8\u10d4\u10d1\u10d8\u10d7.",
+"Div": "\u10d2\u10d0\u10dc\u10d0\u10ec\u10d8\u10da\u10d4\u10d1\u10d0",
+"Paste": "\u10e9\u10d0\u10e1\u10db\u10d0",
+"Close": "\u10d3\u10d0\u10ee\u10e3\u10e0\u10d5\u10d0",
+"Pre": "\u10de\u10e0\u10d4\u10e4\u10dd\u10e0\u10db\u10d0\u10e2\u10d8",
+"Align right": "\u10d2\u10d0\u10d0\u10e1\u10ec\u10dd\u10e0\u10d4 \u10db\u10d0\u10e0\u10ef\u10d5\u10dc\u10d8\u10d5",
+"New document": "\u10d0\u10ee\u10d0\u10da\u10d8 \u10d3\u10dd\u10d9\u10e3\u10db\u10d4\u10dc\u10e2\u10d8",
+"Blockquote": "\u10d1\u10da\u10dd\u10d9\u10d8\u10e0\u10d4\u10d1\u10e3\u10da\u10d8 \u10ea\u10d8\u10e2\u10d0\u10e2\u10d0",
+"Numbered list": "\u10d3\u10d0\u10dc\u10dd\u10db\u10e0\u10d8\u10da\u10d8 \u10e1\u10d8\u10d0",
+"Increase indent": "\u10d0\u10d1\u10d6\u10d0\u10ea\u10d8\u10e1 \u10d2\u10d0\u10d6\u10e0\u10d3\u10d0",
+"Formats": "\u10e4\u10dd\u10e0\u10db\u10d0\u10e2\u10d4\u10d1\u10d8",
+"Headers": "\u10e1\u10d0\u10d7\u10d0\u10e3\u10e0\u10d4\u10d1\u10d8",
+"Select all": "\u10e7\u10d5\u10d4\u10da\u10d0\u10e1 \u10db\u10dd\u10e6\u10dc\u10d8\u10e8\u10d5\u10dc\u10d0",
+"Header 3": "\u10e1\u10d0\u10d7\u10d0\u10e3\u10e0\u10d8 3",
+"Blocks": "\u10d1\u10da\u10dd\u10d9\u10d4\u10d1\u10d8",
+"Undo": "\u10d3\u10d0\u10d1\u10e0\u10e3\u10dc\u10d4\u10d1\u10d0",
+"Strikethrough": "\u10e8\u10e3\u10d0 \u10ee\u10d0\u10d6\u10d8",
+"Bullet list": "\u10d1\u10e3\u10da\u10d4\u10e2 \u10e1\u10d8\u10d0",
+"Header 1": "\u10e1\u10d0\u10d7\u10d0\u10e3\u10e0\u10d8 1",
+"Superscript": "\u10d6\u10d4\u10d3\u10d0 \u10d8\u10dc\u10d3\u10d4\u10e5\u10e1\u10d8",
+"Clear formatting": "\u10e4\u10dd\u10e0\u10db\u10d0\u10e2\u10d8\u10e0\u10d4\u10d1\u10d8\u10e1 \u10d2\u10d0\u10e1\u10e3\u10e4\u10d7\u10d0\u10d5\u10d4\u10d1\u10d0",
+"Subscript": "\u10e5\u10d5\u10d4\u10d3\u10d0 \u10d8\u10dc\u10d3\u10d4\u10e5\u10e1\u10d8",
+"Header 6": "\u10e1\u10d0\u10d7\u10d0\u10e3\u10e0\u10d8 6",
+"Redo": "\u10d2\u10d0\u10db\u10d4\u10dd\u10e0\u10d4\u10d1\u10d0",
+"Paragraph": "\u10de\u10d0\u10e0\u10d0\u10d2\u10e0\u10d0\u10e4\u10d8",
+"Ok": "\u10d9\u10d0\u10e0\u10d2\u10d8",
+"Bold": "\u10db\u10d9\u10d5\u10d4\u10d7\u10e0\u10d8",
+"Code": "\u10d9\u10dd\u10d3\u10d8",
+"Italic": "\u10d3\u10d0\u10ee\u10e0\u10d8\u10da\u10d8",
+"Align center": "\u10d2\u10d0\u10d0\u10e1\u10ec\u10dd\u10e0\u10d4 \u10ea\u10d4\u10dc\u10e2\u10e0\u10e8\u10d8",
+"Header 5": "\u10e1\u10d0\u10d7\u10d0\u10e3\u10e0\u10d8 5",
+"Decrease indent": "\u10d0\u10d1\u10d6\u10d0\u10ea\u10d8\u10e1 \u10e8\u10d4\u10db\u10ea\u10d8\u10e0\u10d4\u10d1\u10d0",
+"Header 4": "\u10e1\u10d0\u10d7\u10d0\u10e3\u10e0\u10d8 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u10d0\u10ee\u10da\u10d0 \u10e2\u10d4\u10e5\u10e1\u10e2\u10d8\u10e1 \u10e9\u10d0\u10e1\u10db\u10d0 \u10e9\u10d5\u10d4\u10e3\u10da\u10d4\u10d1\u10e0\u10d8\u10d5 \u10e0\u10d4\u10df\u10d8\u10db\u10e8\u10d8\u10d0. \u10e2\u10d4\u10e5\u10e1\u10e2\u10d8 \u10e9\u10d0\u10d8\u10e1\u10db\u10d4\u10d5\u10d0 \u10e3\u10e4\u10dd\u10e0\u10db\u10d0\u10e2\u10dd\u10d7 \u10e1\u10d0\u10dc\u10d0\u10db \u10d0\u10db \u10d7\u10d5\u10d8\u10e1\u10d4\u10d1\u10d0\u10e1 \u10d0\u10e0 \u10d2\u10d0\u10d7\u10d8\u10e8\u10d0\u10d5\u10d7.",
+"Underline": "\u10e5\u10d5\u10d4\u10d3\u10d0 \u10ee\u10d0\u10d6\u10d8",
+"Cancel": "\u10d2\u10d0\u10e3\u10e5\u10db\u10d4\u10d1\u10d0",
+"Justify": "\u10d2\u10d0\u10db\u10d0\u10e0\u10d7\u10e3\u10da\u10d8",
+"Inline": "\u10ee\u10d0\u10d6\u10e8\u10d8\u10d3\u10d0",
+"Copy": "\u10d9\u10dd\u10de\u10d8\u10e0\u10d4\u10d1\u10d0",
+"Align left": "\u10d2\u10d0\u10d0\u10e1\u10ec\u10dd\u10e0\u10d4 \u10db\u10d0\u10e0\u10ea\u10ee\u10dc\u10d8\u10d5",
+"Visual aids": "\u10d5\u10d8\u10d6\u10e3\u10d0\u10da\u10d8\u10d6\u10d0\u10ea\u10d8\u10d0",
+"Lower Greek": "\u10d3\u10d0\u10d1\u10d0\u10da\u10d8 \u10d1\u10d4\u10e0\u10eb\u10dc\u10e3\u10da\u10d8",
+"Square": "\u10d9\u10d5\u10d0\u10d3\u10e0\u10d0\u10e2\u10d8",
+"Default": "\u10e1\u10e2\u10d0\u10dc\u10d3\u10d0\u10e0\u10e2\u10e3\u10da\u10d8",
+"Lower Alpha": "\u10d3\u10d0\u10d1\u10d0\u10da\u10d8 \u10d0\u10da\u10e4\u10d0",
+"Circle": "\u10ec\u10e0\u10d4",
+"Disc": "\u10d3\u10d8\u10e1\u10d9\u10d8",
+"Upper Alpha": "\u10db\u10d0\u10e6\u10d0\u10da\u10d8 \u10d0\u10da\u10e4\u10d0",
+"Upper Roman": "\u10db\u10d0\u10e6\u10d0\u10da\u10d8 \u10e0\u10dd\u10db\u10d0\u10e3\u10da\u10d8",
+"Lower Roman": "\u10d3\u10d0\u10d1\u10d0\u10da\u10d8 \u10e0\u10dd\u10db\u10d0\u10e3\u10da\u10d8",
+"Name": "\u10e1\u10d0\u10ee\u10d4\u10da\u10d8",
+"Anchor": "\u10e6\u10e3\u10d6\u10d0",
+"You have unsaved changes are you sure you want to navigate away?": "\u10d7\u10e5\u10d5\u10d4\u10dc \u10d2\u10d0\u10e5\u10d5\u10d7 \u10e8\u10d4\u10e3\u10dc\u10d0\u10ee\u10d0\u10d5\u10d8 \u10e8\u10d4\u10e1\u10ec\u10dd\u10e0\u10d4\u10d1\u10d4\u10d1\u10d8, \u10d3\u10d0\u10e0\u10ec\u10db\u10e3\u10dc\u10d4\u10d1\u10e3\u10da\u10d8 \u10ee\u10d0\u10d7 \u10e0\u10dd\u10db \u10e1\u10ee\u10d5\u10d0\u10d2\u10d0\u10dc \u10d2\u10d0\u10d3\u10d0\u10e1\u10d5\u10da\u10d0 \u10d2\u10e1\u10e3\u10e0\u10d7?",
+"Restore last draft": "\u10d1\u10dd\u10da\u10dd\u10e1 \u10e8\u10d4\u10dc\u10d0\u10ee\u10e3\u10da\u10d8\u10e1 \u10d0\u10e6\u10d3\u10d2\u10d4\u10dc\u10d0",
+"Special character": "\u10e1\u10de\u10d4\u10ea\u10d8\u10d0\u10da\u10e3\u10e0\u10d8 \u10e1\u10d8\u10db\u10d1\u10dd\u10da\u10dd",
+"Source code": "\u10ec\u10e7\u10d0\u10e0\u10dd\u10e1 \u10d9\u10dd\u10d3\u10d8",
+"Right to left": "\u10db\u10d0\u10e0\u10ef\u10d5\u10dc\u10d8\u10d3\u10d0\u10dc \u10db\u10d0\u10e0\u10ea\u10ee\u10dc\u10d8\u10d5",
+"Left to right": "\u10db\u10d0\u10e0\u10ea\u10ee\u10dc\u10d8\u10d3\u10d0\u10dc \u10db\u10d0\u10e0\u10ef\u10d5\u10dc\u10d8\u10d5",
+"Emoticons": "\u10e1\u10db\u10d0\u10d8\u10da\u10d8\u10d9\u10d4\u10d1\u10d8",
+"Robots": "\u10e0\u10dd\u10d1\u10dd\u10d4\u10d1\u10d8",
+"Document properties": "\u10d3\u10dd\u10d9\u10e3\u10db\u10d4\u10dc\u10e2\u10d8\u10e1 \u10d7\u10d5\u10d8\u10e1\u10d4\u10d1\u10d4\u10d1\u10d8",
+"Title": "\u10e1\u10d0\u10d7\u10d0\u10e3\u10e0\u10d8",
+"Keywords": "\u10e1\u10d0\u10d9\u10d5\u10d0\u10dc\u10eb\u10dd \u10e1\u10d8\u10e2\u10e7\u10d5\u10d4\u10d1\u10d8",
+"Encoding": "\u10d9\u10dd\u10d3\u10d8\u10e0\u10d4\u10d1\u10d0",
+"Description": "\u10d0\u10ee\u10ec\u10d4\u10e0\u10d0",
+"Author": "\u10d0\u10d5\u10e2\u10dd\u10e0\u10d8",
+"Fullscreen": "\u10e1\u10d0\u10d5\u10e1\u10d4 \u10d4\u10d9\u10e0\u10d0\u10dc\u10d8",
+"Horizontal line": "\u10f0\u10dd\u10e0\u10d8\u10d6\u10dd\u10dc\u10e2\u10d0\u10da\u10e3\u10e0\u10d8 \u10ee\u10d0\u10d6\u10d8",
+"Horizontal space": "\u10f0\u10dd\u10e0\u10d8\u10d6\u10dd\u10dc\u10e2\u10d0\u10da\u10e3\u10e0\u10d8 \u10e1\u10d8\u10d5\u10e0\u10ea\u10d4",
+"Insert\/edit image": "\u10e9\u10d0\u10e1\u10d5\u10d8\/\u10e8\u10d4\u10d0\u10e1\u10ec\u10dd\u10e0\u10d4 \u10e1\u10e3\u10e0\u10d0\u10d7\u10d8",
+"General": "\u10db\u10d7\u10d0\u10d5\u10d0\u10e0\u10d8",
+"Advanced": "\u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d8\u10d7\u10d8",
+"Source": "\u10d1\u10db\u10e3\u10da\u10d8",
+"Border": "\u10e1\u10d0\u10d6\u10e6\u10d5\u10d0\u10e0\u10d8",
+"Constrain proportions": "\u10de\u10e0\u10dd\u10de\u10dd\u10e0\u10ea\u10d8\u10d8\u10e1 \u10d3\u10d0\u10ea\u10d5\u10d0",
+"Vertical space": "\u10d5\u10d4\u10e0\u10e2\u10d8\u10d9\u10d0\u10da\u10e3\u10e0\u10d8 \u10e1\u10d8\u10d5\u10e0\u10ea\u10d4",
+"Image description": "\u10e1\u10e3\u10e0\u10d0\u10d7\u10d8\u10e1 \u10d3\u10d0\u10ee\u10d0\u10e1\u10d8\u10d0\u10d7\u10d4\u10d1\u10d0",
+"Style": "\u10e1\u10e2\u10d8\u10da\u10d8",
+"Dimensions": "\u10d2\u10d0\u10dc\u10d6\u10dd\u10db\u10d8\u10da\u10d4\u10d1\u10d0",
+"Insert image": "\u10e1\u10e3\u10e0\u10d0\u10d7\u10d8\u10e1 \u10e9\u10d0\u10e1\u10db\u10d0",
+"Insert date\/time": "\u10d7\u10d0\u10e0\u10d8\u10e6\u10d8\/\u10d3\u10e0\u10dd\u10d8\u10e1 \u10e9\u10d0\u10e1\u10db\u10d0",
+"Url": "Url",
+"Text to display": "\u10e2\u10d4\u10e5\u10e1\u10e2\u10d8",
+"Insert link": "\u10d1\u10db\u10e3\u10da\u10d8\u10e1 \u10e9\u10d0\u10e1\u10db\u10d0",
+"New window": "\u10d0\u10ee\u10d0\u10da \u10e4\u10d0\u10dc\u10ef\u10d0\u10e0\u10d0\u10e8\u10d8",
+"None": "\u10d0\u10e0\u10ea\u10d4\u10e0\u10d7\u10d8",
+"Target": "\u10d2\u10d0\u10ee\u10e1\u10dc\u10d0",
+"Insert\/edit link": "\u10d1\u10db\u10e3\u10da\u10d8\u10e1 \u10e9\u10d0\u10e1\u10db\u10d0\/\u10e0\u10d4\u10d3\u10d0\u10e5\u10e2\u10d8\u10e0\u10d4\u10d0",
+"Insert\/edit video": "\u10d5\u10d8\u10d3\u10d4\u10dd\u10e1 \u10e9\u10d0\u10e1\u10db\u10d0\/\u10e0\u10d4\u10d3\u10d0\u10e5\u10e2\u10d8\u10e0\u10d4\u10d1\u10d0",
+"Poster": "\u10de\u10da\u10d0\u10d9\u10d0\u10e2\u10d8",
+"Alternative source": "\u10d0\u10da\u10e2\u10d4\u10e0\u10dc\u10d0\u10e2\u10d8\u10e3\u10da\u10d8 \u10ec\u10e7\u10d0\u10e0\u10dd",
+"Paste your embed code below:": "\u10d0\u10e5 \u10e9\u10d0\u10e1\u10d5\u10d8\u10d7 \u10d7\u10e5\u10d5\u10d4\u10dc\u10d8 \u10d9\u10dd\u10d3\u10d8:",
+"Insert video": "\u10d5\u10d8\u10d3\u10d4\u10dd\u10e1 \u10e9\u10d0\u10e1\u10db\u10d0",
+"Embed": "Embed",
+"Nonbreaking space": "\u10e3\u10ec\u10e7\u10d5\u10d4\u10e2\u10d8 \u10e1\u10d8\u10d5\u10e0\u10ea\u10d4",
+"Page break": "\u10d2\u10d5\u10d4\u10e0\u10d3\u10d8\u10e1 \u10d2\u10d0\u10ec\u10e7\u10d5\u10d4\u10e2\u10d0",
+"Preview": "\u10ec\u10d8\u10dc\u10d0\u10e1\u10ec\u10d0\u10e0 \u10dc\u10d0\u10ee\u10d5\u10d0",
+"Print": "\u10d0\u10db\u10dd\u10d1\u10d4\u10ed\u10d5\u10d3\u10d0",
+"Save": "\u10e8\u10d4\u10dc\u10d0\u10ee\u10d5\u10d0",
+"Could not find the specified string.": "\u10db\u10dd\u10ea\u10d4\u10db\u10e3\u10da\u10d8 \u10e9\u10d0\u10dc\u10d0\u10ec\u10d4\u10e0\u10d8 \u10d5\u10d4\u10e0 \u10db\u10dd\u10d8\u10eb\u10d4\u10d1\u10dc\u10d0.",
+"Replace": "\u10e8\u10d4\u10e1\u10ec\u10dd\u10e0\u10d4\u10d1\u10d0",
+"Next": "\u10e8\u10d4\u10db\u10d3\u10d4\u10d2\u10d8",
+"Whole words": "\u10e1\u10e0\u10e3\u10da\u10d8 \u10e1\u10d8\u10e2\u10e7\u10d5\u10d4\u10d1\u10d8",
+"Find and replace": "\u10db\u10dd\u10eb\u10d4\u10d1\u10dc\u10d4 \u10d3\u10d0 \u10e8\u10d4\u10d0\u10e1\u10ec\u10dd\u10e0\u10d4",
+"Replace with": "\u10e8\u10d4\u10e1\u10d0\u10e1\u10ec\u10dd\u10e0\u10d4\u10d1\u10d4\u10da\u10d8 \u10e1\u10d8\u10e2\u10e7\u10d5\u10d0",
+"Find": "\u10eb\u10d4\u10d1\u10dc\u10d0",
+"Replace all": "\u10e7\u10d5\u10d4\u10da\u10d0\u10e1 \u10e8\u10d4\u10e1\u10ec\u10dd\u10e0\u10d4\u10d1\u10d0",
+"Match case": "\u10d3\u10d0\u10d0\u10db\u10d7\u10ee\u10d5\u10d8\u10d4 \u10d0\u10e1\u10dd\u10d4\u10d1\u10d8\u10e1 \u10d6\u10dd\u10db\u10d0",
+"Prev": "\u10ec\u10d8\u10dc\u10d0",
+"Spellcheck": "\u10db\u10d0\u10e0\u10d7\u10da\u10ec\u10d4\u10e0\u10d8\u10e1 \u10e8\u10d4\u10db\u10dd\u10ec\u10db\u10d4\u10d1\u10d0",
+"Finish": "\u10e4\u10d8\u10dc\u10d8\u10e8\u10d8",
+"Ignore all": "\u10e7\u10d5\u10d4\u10da\u10d0\u10e1 \u10d8\u10d2\u10dc\u10dd\u10e0\u10d8\u10e0\u10d4\u10d1\u10d0",
+"Ignore": "\u10d8\u10d2\u10dc\u10dd\u10e0\u10d8\u10e0\u10d4\u10d1\u10d0",
+"Insert row before": "\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10d7\u10d0\u10d5\u10e8\u10d8 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0",
+"Rows": "\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d4\u10d1\u10d8",
+"Height": "\u10e1\u10d8\u10db\u10d0\u10e6\u10da\u10d4",
+"Paste row after": "\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10d1\u10dd\u10da\u10dd\u10e8\u10d8 \u10e9\u10d0\u10e1\u10db\u10d0",
+"Alignment": "\u10e1\u10ec\u10dd\u10e0\u10d4\u10d1\u10d0",
+"Column group": "\u10e1\u10d5\u10d4\u10e2\u10d8\u10e1 \u10ef\u10d2\u10e3\u10e4\u10d8",
+"Row": "\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8",
+"Insert column before": "\u10e1\u10d5\u10d4\u10e2\u10d8\u10e1 \u10d7\u10d0\u10d5\u10e8\u10d8 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0",
+"Split cell": "\u10e3\u10ef\u10e0\u10d8\u10e1 \u10d2\u10d0\u10e7\u10dd\u10e4\u10d0",
+"Cell padding": "\u10e3\u10ef\u10e0\u10d8\u10e1 \u10e4\u10d0\u10e0\u10d7\u10dd\u10d1\u10d8",
+"Cell spacing": "\u10e3\u10ef\u10e0\u10d8\u10e1 \u10d3\u10d0\u10e8\u10dd\u10e0\u10d4\u10d1\u10d0",
+"Row type": "\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10e2\u10d8\u10de\u10d8",
+"Insert table": "\u10ea\u10ee\u10e0\u10d8\u10da\u10d8\u10e1 \u10e9\u10d0\u10e1\u10db\u10d0",
+"Body": "\u10e2\u10d0\u10dc\u10d8",
+"Caption": "\u10ec\u10d0\u10e0\u10ec\u10d4\u10e0\u10d0",
+"Footer": "\u10eb\u10d8\u10e0\u10d8",
+"Delete row": "\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10ec\u10d0\u10e8\u10da\u10d0",
+"Paste row before": "\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10d7\u10d0\u10d5\u10e8\u10d8 \u10e9\u10d0\u10e1\u10db\u10d0",
+"Scope": "\u10e9\u10d0\u10e0\u10e9\u10dd",
+"Delete table": "\u10ea\u10ee\u10e0\u10d8\u10da\u10d8\u10e1 \u10ec\u10d0\u10e8\u10da\u10d0",
+"Header cell": "\u10d7\u10d0\u10d5\u10d8\u10e1 \u10e3\u10ef\u10e0\u10d0",
+"Column": "\u10e1\u10d5\u10d4\u10e2\u10d8",
+"Cell": "\u10e3\u10ef\u10e0\u10d0",
+"Header": "\u10d7\u10d0\u10d5\u10d8",
+"Cell type": "\u10e3\u10ef\u10e0\u10d8\u10e1 \u10e2\u10d8\u10de\u10d8",
+"Copy row": "\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10d9\u10dd\u10de\u10d8\u10e0\u10d4\u10d1\u10d0",
+"Row properties": "\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10d7\u10d5\u10d8\u10e1\u10d4\u10d1\u10d4\u10d1\u10d8",
+"Table properties": "\u10ea\u10ee\u10e0\u10d8\u10da\u10d8\u10e1 \u10d7\u10d5\u10d8\u10e1\u10d4\u10d1\u10d4\u10d1\u10d8",
+"Row group": "\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10ef\u10d2\u10e3\u10e4\u10d8",
+"Right": "\u10db\u10d0\u10e0\u10ef\u10d5\u10dc\u10d8\u10d5",
+"Insert column after": "\u10e1\u10d5\u10d4\u10e2\u10d8\u10e1 \u10d1\u10dd\u10da\u10dd\u10e8\u10d8 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0",
+"Cols": "\u10e1\u10d5\u10d4\u10e2\u10d4\u10d1\u10d8",
+"Insert row after": "\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10d1\u10dd\u10da\u10dd\u10e8\u10d8 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0",
+"Width": "\u10e1\u10d8\u10d2\u10d0\u10dc\u10d4",
+"Cell properties": "\u10e3\u10ef\u10e0\u10d8\u10e1 \u10d7\u10d5\u10d8\u10e1\u10d4\u10d1\u10d4\u10d1\u10d8",
+"Left": "\u10db\u10d0\u10e0\u10ea\u10ee\u10dc\u10d8\u10d5",
+"Cut row": "\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10d0\u10db\u10dd\u10ed\u10e0\u10d0",
+"Delete column": "\u10e1\u10d5\u10d4\u10e2\u10d8\u10e1 \u10ec\u10d0\u10e8\u10da\u10d0",
+"Center": "\u10ea\u10d4\u10dc\u10e2\u10e0\u10e8\u10d8",
+"Merge cells": "\u10e3\u10ef\u10e0\u10d4\u10d1\u10d8\u10e1 \u10d2\u10d0\u10d4\u10e0\u10d7\u10d8\u10d0\u10dc\u10d4\u10d1\u10d0",
+"Insert template": "\u10e8\u10d0\u10d1\u10da\u10dd\u10dc\u10d8\u10e1 \u10e9\u10d0\u10e1\u10db\u10d0",
+"Templates": "\u10e8\u10d0\u10d1\u10da\u10dd\u10dc\u10d4\u10d1\u10d8",
+"Background color": "\u10e3\u10d9\u10d0\u10dc\u10d0 \u10e4\u10d4\u10e0\u10d8",
+"Text color": "\u10e2\u10d4\u10e5\u10e1\u10e2\u10d8\u10e1 \u10e4\u10d4\u10e0\u10d8",
+"Show blocks": "\u10d1\u10da\u10dd\u10d9\u10d4\u10d1\u10d8\u10e1 \u10e9\u10d5\u10d4\u10dc\u10d4\u10d1\u10d0",
+"Show invisible characters": "\u10e3\u10ee\u10d8\u10da\u10d0\u10d5\u10d8 \u10e1\u10d8\u10db\u10d1\u10dd\u10da\u10dd\u10d4\u10d1\u10d8\u10e1 \u10e9\u10d5\u10d4\u10dc\u10d4\u10d1\u10d0",
+"Words: {0}": "\u10e1\u10d8\u10e2\u10e7\u10d5\u10d4\u10d1\u10d8: {0}",
+"Insert": "\u10e9\u10d0\u10e1\u10db\u10d0",
+"File": "\u10e4\u10d0\u10d8\u10da\u10d8",
+"Edit": "\u10e8\u10d4\u10e1\u10ec\u10dd\u10e0\u10d4\u10d1\u10d0",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u10e2\u10d4\u10e5\u10e1\u10e2\u10d8\u10e1 \u10e4\u10d0\u10e0\u10d7\u10d8. \u10d3\u10d0\u10d0\u10ed\u10d8\u10e0\u10d4\u10d7 ALT-F9\u10e1 \u10db\u10d4\u10dc\u10d8\u10e3\u10e1 \u10d2\u10d0\u10db\u10dd\u10e1\u10d0\u10eb\u10d0\u10ee\u10d4\u10d1\u10da\u10d0\u10d3. \u10d3\u10d0\u10d0\u10ed\u10d8\u10e0\u10d4\u10d7 ALT-F10\u10e1 \u10de\u10d0\u10dc\u10d4\u10da\u10d8\u10e1\u10d7\u10d5\u10d8\u10e1. \u10d3\u10d0\u10d0\u10ed\u10d8\u10e0\u10d4\u10d7 ALT-0\u10e1 \u10d3\u10d0\u10ee\u10db\u10d0\u10e0\u10d4\u10d1\u10d8\u10e1\u10d7\u10d5\u10d8\u10e1",
+"Tools": "\u10d8\u10d0\u10e0\u10d0\u10e6\u10d4\u10d1\u10d8",
+"View": "\u10dc\u10d0\u10ee\u10d5\u10d0",
+"Table": "\u10ea\u10ee\u10e0\u10d8\u10da\u10d8",
+"Format": "\u10e4\u10dd\u10e0\u10db\u10d0\u10e2\u10d8"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ko_KR.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ko_KR.js
new file mode 100755
index 0000000..1f89ae4
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ko_KR.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('ko_KR',{
+"Cut": "\uc798\ub77c\ub0b4\uae30",
+"Header 2": "\uc81c\ubaa9 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\ube0c\ub77c\uc6b0\uc838\uac00 \ud074\ub9bd\ubcf4\ub4dc \uc811\uadfc\uc744 \ud5c8\uc6a9\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. Ctrl+X\/C\/V \ud0a4\ub97c \uc774\uc6a9\ud574 \uc8fc\uc138\uc694.",
+"Div": "\uad6c\ubd84",
+"Paste": "\ubd99\uc5ec\ub123\uae30",
+"Close": "\ub2eb\uae30",
+"Pre": "Pre",
+"Align right": "\uc624\ub978\ucabd\uc815\ub82c",
+"New document": "\uc0c8 \ubb38\uc11c",
+"Blockquote": "\uad6c\ud68d",
+"Numbered list": "\uc22b\uc790\ub9ac\uc2a4\ud2b8",
+"Increase indent": "\ub4e4\uc5ec\uc4f0\uae30",
+"Formats": "\ud3ec\ub9f7",
+"Headers": "\uc2a4\ud0c0\uc77c",
+"Select all": "\uc804\uccb4\uc120\ud0dd",
+"Header 3": "\uc81c\ubaa9 3",
+"Blocks": "\ube14\ub85d \uc124\uc815",
+"Undo": "\uc2e4\ud589\ucde8\uc18c",
+"Strikethrough": "\ucde8\uc18c\uc120",
+"Bullet list": "\uc810\ub9ac\uc2a4\ud2b8",
+"Header 1": "\uc81c\ubaa9 1",
+"Superscript": "\uc717\ucca8\uc790",
+"Clear formatting": "\ud3ec\ub9f7\ucd08\uae30\ud654",
+"Subscript": "\uc544\ub798\ucca8\uc790",
+"Header 6": "\uc81c\ubaa9 6",
+"Redo": "\ub2e4\uc2dc\uc2e4\ud589",
+"Paragraph": "\ub2e8\ub77d",
+"Ok": "\ud655\uc778",
+"Bold": "\uad75\uac8c",
+"Code": "\ucf54\ub4dc",
+"Italic": "\uae30\uc6b8\uc784\uaf34",
+"Align center": "\uac00\uc6b4\ub370\uc815\ub82c",
+"Header 5": "\uc81c\ubaa9 5",
+"Decrease indent": "\ub0b4\uc5b4\uc4f0\uae30",
+"Header 4": "\uc81c\ubaa9 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\uc774 \uc635\uc158\uc744 \ub044\uc9c0 \uc54a\uc73c\uba74 \ub0b4\uc6a9\uc774 \uc77c\ubc18 \ud14d\uc2a4\ud2b8\ub85c \ubd99\uc5ec\ub123\uae30 \ub418\uc5b4\uc9d1\ub2c8\ub2e4.",
+"Underline": "\ubc11\uc904",
+"Cancel": "\ucde8\uc18c",
+"Justify": "\uc591\ucabd\uc815\ub82c",
+"Inline": "\ub77c\uc778 \uc124\uc815",
+"Copy": "\ubcf5\uc0ac\ud558\uae30",
+"Align left": "\uc67c\ucabd\uc815\ub82c",
+"Visual aids": "\uc2dc\uac01\uad50\uc7ac",
+"Lower Greek": "\uadf8\ub9ac\uc2a4\uc5b4 \uc18c\ubb38\uc790",
+"Square": "\uc0ac\uac01",
+"Default": "\uae30\ubcf8",
+"Lower Alpha": "\uc54c\ud30c\ubcb3 \uc18c\ubb38\uc790",
+"Circle": "\uc6d0",
+"Disc": "\uc6d0\ubc18",
+"Upper Alpha": "\uc54c\ud30c\ubcb3 \uc18c\ubb38\uc790",
+"Upper Roman": "\ub85c\ub9c8\uc790 \ub300\ubb38\uc790",
+"Lower Roman": "\ub85c\ub9c8\uc790 \uc18c\ubb38\uc790",
+"Name": "\uc774\ub984",
+"Anchor": "\uc575\ucee4",
+"You have unsaved changes are you sure you want to navigate away?": "\uc800\uc7a5\ud558\uc9c0 \uc54a\uc740 \uc815\ubcf4\uac00 \uc788\uc2b5\ub2c8\ub2e4. \uc774 \ud398\uc774\uc9c0\ub97c \ubc97\uc5b4\ub098\uc2dc\uaca0\uc2b5\ub2c8\uae4c?",
+"Restore last draft": "\ub9c8\uc9c0\ub9c9 \ucd08\uc548 \ubcf5\uc6d0",
+"Special character": "\ud2b9\uc218\ubb38\uc790",
+"Source code": "\uc18c\uc2a4\ucf54\ub4dc",
+"Right to left": "\uc624\ub978\ucabd\uc5d0\uc11c \uc67c",
+"Left to right": "\uc67c\ucabd\uc5d0\uc11c \uc624\ub978",
+"Emoticons": "\uc774\ubaa8\ud2f0\ucf58",
+"Robots": "\ub85c\ubd07",
+"Document properties": "\ubb38\uc11c \uc18d\uc131",
+"Title": "\uc81c\ubaa9",
+"Keywords": "\ud0a4\uc6cc\ub4dc",
+"Encoding": "\uc778\ucf54",
+"Description": "\uc124\uba85",
+"Author": "\uc800",
+"Fullscreen": "\uc804\uccb4\ud654",
+"Horizontal line": "\uac00\ub85c",
+"Horizontal space": "\uc218\ud3c9 \uacf5\ubc31",
+"Insert\/edit image": "\uc774\ubbf8\uc9c0 \uc0bd\uc785\/\uc218\uc815",
+"General": "\uc77c\ubc18",
+"Advanced": "\uace0\uae09",
+"Source": "\uc18c\uc2a4",
+"Border": "\ud14c\ub450\ub9ac",
+"Constrain proportions": "\uc791\uc5c5 \uc81c\ud55c",
+"Vertical space": "\uc218\uc9c1 \uacf5\ubc31",
+"Image description": "\uc774\ubbf8\uc9c0 \uc124\uba85",
+"Style": "\uc2a4\ud0c0\uc77c",
+"Dimensions": "\ud06c\uae30",
+"Insert image": "\uc774\ubbf8\uc9c0 \uc0bd\uc785",
+"Insert date\/time": "\ub0a0\uc9dc\/\uc2dc\uac04\uc0bd\uc785",
+"Remove link": "\ub9c1\ud06c\uc0ad\uc81c",
+"Url": "\uc8fc\uc18c",
+"Text to display": "\ubcf8\ubb38",
+"Anchors": "\ucc45\uac08\ud53c",
+"Insert link": "\ub9c1\ud06c\uc0bd\uc785 ",
+"New window": "\uc0c8\ucc3d",
+"None": "\uc5c6\uc74c",
+"Target": "\ub300\uc0c1",
+"Insert\/edit link": "\ub9c1\ud06c \uc0bd\uc785\/\uc218\uc815",
+"Insert\/edit video": "\ube44\ub514\uc624 \uc0bd\uc785\/\uc218\uc815",
+"Poster": "\ud3ec\uc2a4\ud130",
+"Alternative source": "\ub300\uccb4 \uc18c\uc2a4",
+"Paste your embed code below:": "\uc544\ub798\uc5d0 \ucf54\ub4dc\ub97c \ubd99\uc5ec\ub123\uc73c\uc138\uc694:",
+"Insert video": "\ube44\ub514\uc624 \uc0bd\uc785",
+"Embed": "\uc0bd\uc785",
+"Nonbreaking space": "\ub744\uc5b4\uc4f0\uae30",
+"Page break": "\ud398\uc774\uc9c0 \uad6c\ubd84\uc790",
+"Paste as text": "\ud14d\uc2a4\ud2b8\ub85c \ubd99\uc5ec\ub123\uae30",
+"Preview": "\ubbf8\ub9ac\ubcf4\uae30",
+"Print": "\ucd9c\ub825",
+"Save": "\uc800\uc7a5",
+"Could not find the specified string.": "\ubb38\uc790\ub97c \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.",
+"Replace": "\uad50\uccb4",
+"Next": "\ub2e4\uc74c",
+"Whole words": "\uc804\uccb4 \ub2e8\uc5b4",
+"Find and replace": "\ucc3e\uc544\uc11c \uad50\uccb4",
+"Replace with": "\uad50\uccb4",
+"Find": "\ucc3e\uae30",
+"Replace all": "\uc804\uccb4 \uad50\uccb4",
+"Match case": "\ub300\uc18c\ubb38\uc790 \uc77c\uce58",
+"Prev": "\uc774\uc804",
+"Spellcheck": "\ubb38\ubc95\uccb4",
+"Finish": "\ub05d",
+"Ignore all": "\uc804\uccb4\ubb34",
+"Ignore": "\ubb34",
+"Insert row before": "\uc774\uc804\uc5d0 \ud589 \uc0bd\uc785",
+"Rows": "\ud589",
+"Height": "\ub192\uc774",
+"Paste row after": "\ub2e4\uc74c\uc5d0 \ud589 \ubd99\uc5ec\ub123\uae30",
+"Alignment": "\uc815\ub82c",
+"Column group": "\uc5f4 \uadf8\ub8f9",
+"Row": "\uc5f4",
+"Insert column before": "\uc774\uc804\uc5d0 \ud589 \uc0bd\uc785",
+"Split cell": "\uc140 \ub098\ub204\uae30",
+"Cell padding": "\uc140 \uc548\ucabd \uc5ec\ubc31",
+"Cell spacing": "\uc140 \uac04\uaca9",
+"Row type": "\ud589 \ud0c0\uc785",
+"Insert table": "\ud14c\uc774\ube14 \uc0bd\uc785",
+"Body": "\ubc14\ub514",
+"Caption": "\ucea1\uc158",
+"Footer": "\ud478\ud130",
+"Delete row": "\ud589 \uc9c0\uc6b0\uae30",
+"Paste row before": "\uc774\uc804\uc5d0 \ud589 \ubd99\uc5ec\ub123\uae30",
+"Scope": "\ubc94\uc704",
+"Delete table": "\ud14c\uc774\ube14 \uc0ad\uc81c",
+"Header cell": "\ud5e4\ub354 \uc140",
+"Column": "\ud589",
+"Cell": "\uc140",
+"Header": "\ud5e4\ub354",
+"Cell type": "\uc140 \ud0c0\uc785",
+"Copy row": "\ud589 \ubcf5\uc0ac",
+"Row properties": "\ud589 \uc18d\uc131",
+"Table properties": "\ud14c\uc774\ube14 \uc18d\uc131",
+"Row group": "\ud589 \uadf8\ub8f9",
+"Right": "\uc624\ub978\ucabd",
+"Insert column after": "\ub2e4\uc74c\uc5d0 \uc5f4 \uc0bd\uc785",
+"Cols": "\uc5f4",
+"Insert row after": "\ub2e4\uc74c\uc5d0 \ud589 \uc0bd\uc785",
+"Width": "\ub113\uc774",
+"Cell properties": "\uc140 \uc18d",
+"Left": "\uc67c\ucabd",
+"Cut row": "\ud589 \uc798\ub77c\ub0b4\uae30",
+"Delete column": "\uc5f4 \uc9c0\uc6b0\uae30",
+"Center": "\uac00\uc6b4\ub370",
+"Merge cells": "\uc140 \ud569\uce58\uae30",
+"Insert template": "\ud15c\ud50c\ub9bf \uc0bd\uc785",
+"Templates": "\ud15c\ud50c\ub9bf",
+"Background color": "\ubc30\uacbd\uc0c9",
+"Text color": "\ubb38\uc790 \uc0c9\uae54",
+"Show blocks": "\ube14\ub7ed \ubcf4\uc5ec\uc8fc\uae30",
+"Show invisible characters": "\uc548\ubcf4\uc774\ub294 \ubb38\uc790 \ubcf4\uc774\uae30",
+"Words: {0}": "\ub2e8\uc5b4: {0}",
+"Insert": "\uc0bd\uc785",
+"File": "\ud30c\uc77c",
+"Edit": "\uc218\uc815",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\uc11c\uc2dd \uc788\ub294 \ud14d\uc2a4\ud2b8 \ud3b8\uc9d1\uae30 \uc785\ub2c8\ub2e4. ALT-F9\ub97c \ub204\ub974\uba74 \uba54\ub274, ALT-F10\ub97c \ub204\ub974\uba74 \ud234\ubc14, ALT-0\uc744 \ub204\ub974\uba74 \ub3c4\uc6c0\ub9d0\uc744 \ubcfc \uc218 \uc788\uc2b5\ub2c8\ub2e4.",
+"Tools": "\ub3c4\uad6c",
+"View": "\ubcf4\uae30",
+"Table": "\ud14c\uc774\ube14",
+"Format": "\ud3ec\ub9f7"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/lb.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/lb.js
new file mode 100755
index 0000000..76cba87
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/lb.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('lb',{
+"Cut": "Ausschneiden",
+"Header 2": "Titel 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "D\u00e4i Web-Browser \u00ebnnerst\u00ebtzt keen direkten Acc\u00e8s op d'Zw\u00ebschenaplag. Benotz w.e.gl. CTRL+C fir den ausgewielten Text ze kop\u00e9ieren an CTRL+V fir en anzepechen.",
+"Div": "DIV",
+"Paste": "Apechen",
+"Close": "Zoumaachen",
+"Pre": "PRE",
+"Align right": "Riets align\u00e9iert",
+"New document": "Neit Dokument",
+"Blockquote": "Zitat",
+"Numbered list": "Nummer\u00e9iert L\u00ebscht",
+"Increase indent": "Ident\u00e9ierung vergr\u00e9isseren",
+"Formats": "Formater",
+"Headers": "Titelen",
+"Select all": "Alles auswielen",
+"Header 3": "Titel 3",
+"Blocks": "Bl\u00e9ck",
+"Undo": "R\u00e9ckg\u00e4ngeg maachen",
+"Strikethrough": "Duerchgestrach",
+"Bullet list": "Opzielung",
+"Header 1": "Titel 1",
+"Superscript": "H\u00e9ichgestallt",
+"Clear formatting": "Format\u00e9ierung l\u00e4schen",
+"Subscript": "Erofgestallt",
+"Header 6": "Titel 6",
+"Redo": "Widderhuelen",
+"Paragraph": "Paragraph",
+"Ok": "Okee",
+"Bold": "Fett",
+"Code": "CODE",
+"Italic": "Kursiv",
+"Align center": "Zentr\u00e9iert",
+"Header 5": "Titel 5",
+"Decrease indent": "Ident\u00e9ierung verklengeren",
+"Header 4": "Titel 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\"Apechen\" ass elo am Textmodus. Inhalter ginn elo ouni Format\u00e9ierungen agepecht bis du d\u00ebs Optioun ausm\u00e9chs.",
+"Underline": "\u00cbnnerstrach",
+"Cancel": "Ofbriechen",
+"Justify": "Blocksaz",
+"Inline": "Inline",
+"Copy": "Kop\u00e9ieren",
+"Align left": "L\u00e9nks align\u00e9iert",
+"Visual aids": "Visuell H\u00ebllefen",
+"Lower Greek": "Klengt griichescht Alphabet",
+"Square": "Quadrat",
+"Default": "Standard",
+"Lower Alpha": "Klengt Alphabet",
+"Circle": "Krees",
+"Disc": "Scheif",
+"Upper Alpha": "Grousst Alphabet",
+"Upper Roman": "Grousst r\u00e9imescht Alphabet",
+"Lower Roman": "Klengt r\u00e9imescht Alphabet",
+"Name": "Numm",
+"Anchor": "Anker",
+"You have unsaved changes are you sure you want to navigate away?": "Du hues ongesp\u00e4ichert \u00c4nnerungen. W\u00eblls du s\u00e9cher ewechnavig\u00e9ieren?",
+"Restore last draft": "Leschten Entworf er\u00ebm zr\u00e9cksetzen",
+"Special character": "Speziell Zeechen",
+"Source code": "Quelltext",
+"Right to left": "Vu riets no l\u00e9nks",
+"Left to right": "Vu l\u00e9nks no riets",
+"Emoticons": "Smileyen",
+"Robots": "Robotter",
+"Document properties": "Eegeschafte vum Dokument",
+"Title": "Titel",
+"Keywords": "Schl\u00ebsselwierder",
+"Encoding": "Cod\u00e9ierung",
+"Description": "Beschreiwung",
+"Author": "Auteur",
+"Fullscreen": "Vollbildschierm",
+"Horizontal line": "Horizontal Linn",
+"Horizontal space": "Horizontalen Espace",
+"Insert\/edit image": "Bild af\u00fcgen\/\u00e4nneren",
+"General": "Allgemeng",
+"Advanced": "Erweidert",
+"Source": "Quell",
+"Border": "Rand",
+"Constrain proportions": "Proportioune b\u00e4ibehalen",
+"Vertical space": "Vertikalen Espace",
+"Image description": "Bildbeschreiwung",
+"Style": "Stil",
+"Dimensions": "Dimensiounen",
+"Insert image": "Bild af\u00fcgen",
+"Insert date\/time": "Datum\/Z\u00e4it af\u00fcgen",
+"Remove link": "Link l\u00e4schen",
+"Url": "URL",
+"Text to display": "Text deen unzeweisen ass",
+"Anchors": "Ankeren",
+"Insert link": "Link drasetzen",
+"New window": "Nei F\u00ebnster",
+"None": "Keen",
+"Target": "Zil",
+"Insert\/edit link": "Link drasetzen\/\u00e4nneren",
+"Insert\/edit video": "Video drasetzen\/\u00e4nneren",
+"Poster": "Pouster",
+"Alternative source": "Alternativ Quell",
+"Paste your embed code below:": "Abannungscode hei apechen:",
+"Insert video": "Video drasetzen",
+"Embed": "Abannen",
+"Nonbreaking space": "Net-\u00ebmbriechenden Espace",
+"Page break": "S\u00e4iten\u00ebmbroch",
+"Paste as text": "Als Text apechen",
+"Preview": "Kucken",
+"Print": "Dr\u00e9cken",
+"Save": "Sp\u00e4icheren",
+"Could not find the specified string.": "Den Text konnt net fonnt ginn.",
+"Replace": "Ersetzen",
+"Next": "Weider",
+"Whole words": "Ganz Wierder",
+"Find and replace": "Fannen an ersetzen",
+"Replace with": "Ersetze mat",
+"Find": "Fannen",
+"Replace all": "All ersetzen",
+"Match case": "Grouss-\/Klengschreiwung respekt\u00e9ieren",
+"Prev": "Zr\u00e9ck",
+"Spellcheck": "Verbesseren",
+"Finish": "Ofschl\u00e9issen",
+"Ignore all": "All ignor\u00e9ieren",
+"Ignore": "Ignor\u00e9ieren",
+"Insert row before": "Rei virdrun drasetzen",
+"Rows": "Reien",
+"Height": "H\u00e9icht",
+"Paste row after": "Rei herno apechen",
+"Alignment": "Align\u00e9ierung",
+"Column group": "Kolonnegrupp",
+"Row": "Rei",
+"Insert column before": "Kolonn virdrun drasetzen",
+"Split cell": "Zell opspl\u00e9cken",
+"Cell padding": "Zellenopf\u00ebllung",
+"Cell spacing": "Zellenofstand",
+"Row type": "Reientyp",
+"Insert table": "Tabell drasetzen",
+"Body": "Kierper",
+"Caption": "Beschr\u00ebftung",
+"Footer": "Fouss",
+"Delete row": "Rei l\u00e4schen",
+"Paste row before": "Rei virdrun apechen",
+"Scope": "Ber\u00e4ich",
+"Delete table": "Tabell l\u00e4schen",
+"Header cell": "Kappzell",
+"Column": "Kolonn",
+"Cell": "Zell",
+"Header": "Kapp",
+"Cell type": "Zellentyp",
+"Copy row": "Rei kop\u00e9ieren",
+"Row properties": "Eegeschafte vu Reien",
+"Table properties": "Eegeschafte vun Tabellen",
+"Row group": "Reiegrupp",
+"Right": "Riets",
+"Insert column after": "Kolonn herno drasetzen",
+"Cols": "Kolonnen",
+"Insert row after": "Rei herno drasetzen",
+"Width": "Breet",
+"Cell properties": "Eegeschafte vun Zellen",
+"Left": "L\u00e9nks",
+"Cut row": "Rei ausschneiden",
+"Delete column": "Kolonn l\u00e4schen",
+"Center": "M\u00ebtt",
+"Merge cells": "Zelle fusion\u00e9ieren",
+"Insert template": "Virlag drasetzen",
+"Templates": "Virlagen",
+"Background color": "Hanndergrondfaarf",
+"Text color": "Textfaarf",
+"Show blocks": "Bl\u00e9ck weisen",
+"Show invisible characters": "Onsiichtbar Zeeche weisen",
+"Words: {0}": "Wierder: {0}",
+"Insert": "Drasetzen",
+"File": "Fichier",
+"Edit": "\u00c4nneren",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Ber\u00e4ich fir format\u00e9ierten Text. Dr\u00e9ck ALT+F9 fir de Men\u00fc. Dr\u00e9ck ALT+F10 fir d'Geschirleescht. Dr\u00e9ck ALT+0 fir d'H\u00ebllef.",
+"Tools": "Geschir",
+"View": "Kucken",
+"Table": "Tabell",
+"Format": "Format"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/lt.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/lt.js
new file mode 100755
index 0000000..b008f30
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/lt.js
@@ -0,0 +1,76 @@
+tinymce.addI18n('lt',{
+"Cut": "I\u0161kirpti",
+"Header 2": "Antra\u0161t\u0117 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Nar\u0161ykl\u0117s nustatymai neleid\u017eia redaktoriui tiesiogiai pasiekti laikinosios atminties. Pra\u0161ome naudoti klaviat\u016bros klavi\u0161us Ctrl+X\/C\/V.",
+"Div": "Div",
+"Paste": "\u012ed\u0117ti",
+"Close": "U\u017edaryti",
+"Pre": "Pre",
+"Align right": "Lygiuoti de\u0161in\u0117je",
+"New document": "Naujas dokumentas",
+"Blockquote": "Citata",
+"Numbered list": "Skaitmeninis s\u0105ra\u0161as",
+"Increase indent": "Didinti \u012ftrauk\u0105",
+"Formats": "Formatai",
+"Headers": "Antra\u0161t\u0117s",
+"Select all": "Pa\u017eym\u0117ti visk\u0105",
+"Header 3": "Antra\u0161t\u0117 3",
+"Blocks": "Blokai",
+"Undo": "Atstatyti",
+"Strikethrough": "Perbrauktas",
+"Bullet list": "\u017denklinimo s\u0105ra\u0161as",
+"Header 1": "Antra\u0161t\u0117 1",
+"Superscript": "Vir\u0161utinis indeksas",
+"Clear formatting": "Naikinti formatavim\u0105",
+"Subscript": "Apatinis indeksas",
+"Header 6": "Antra\u0161t\u0117 6",
+"Redo": "Gr\u0105\u017einti",
+"Paragraph": "Paragrafas",
+"Ok": "Gerai",
+"Bold": "Pary\u0161kintas",
+"Code": "Kodas",
+"Italic": "Kursyvinis",
+"Align center": "Centruoti",
+"Header 5": "Antra\u0161t\u0117 5",
+"Decrease indent": "Ma\u017einti \u012ftrauk\u0105",
+"Header 4": "Antra\u0161t\u0117 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Dabar \u012fterpiama paprastojo teksto re\u017eimu. Kol \u0161i parinktis \u012fjungta, turinys bus \u012fterptas kaip paprastas tekstas.",
+"Underline": "Pabrauktas",
+"Cancel": "Atsisakyti",
+"Justify": "I\u0161d\u0117styti per vis\u0105 plot\u012f",
+"Inline": "Inline",
+"Copy": "Kopijuoti",
+"Align left": "Lygiuoti kair\u0117je",
+"Visual aids": "Vaizdin\u0117s priemon\u0117s",
+"Lower Greek": "Ma\u017eosios graik\u0173",
+"Square": "Kvadratas",
+"Default": "Pagrindinis",
+"Lower Alpha": "Ma\u017eosios raid\u0117s",
+"Circle": "Apskritimas",
+"Disc": "Diskas",
+"Upper Alpha": "Did\u017eiosios raid\u0117s",
+"Upper Roman": "Did\u017eiosios rom\u0117n\u0173",
+"Lower Roman": "Ma\u017eosios rom\u0117n\u0173",
+"Emoticons": "Jaustukai",
+"Horizontal space": "Horizontalus tarpas",
+"Insert\/edit image": "\u012eterpti|Tvarkyti paveiksl\u0117l\u012f",
+"General": "Pagrindinis",
+"Advanced": "I\u0161pl\u0117stas",
+"Source": "Pirmin\u0117 nuoroda",
+"Border": "R\u0117melis",
+"Constrain proportions": "Taikyti proporcijas",
+"Vertical space": "Vertikalus tarpas",
+"Image description": "Paveiksl\u0117lio apra\u0161as",
+"Style": "Stilius",
+"Dimensions": "Matmenys",
+"Insert image": "\u012eterpti paveiksl\u0117l\u012f",
+"Remove link": "\u0160alinti nuorod\u0105",
+"Url": "Nuoroda",
+"Text to display": "Rodomas tekstas",
+"Insert link": "\u012eterpti nuorod\u0105",
+"New window": "Naujas langas",
+"None": "Niekas",
+"Target": "Tikslin\u0117 nuoroda",
+"Insert\/edit link": "\u012eterpti\/taisyti nuorod\u0105",
+"Show invisible characters": "Rodyti nematomus simbolius"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/lv.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/lv.js
new file mode 100755
index 0000000..e85bed5
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/lv.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('lv',{
+"Cut": "Izgriezt",
+"Header 2": "Otr\u0101 l\u012bme\u0146a virsraksts",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "J\u016bsu p\u0101rl\u016bkprogramma neatbalsta piek\u013cuvi starpliktuvei. L\u016bdzu izmantojiet Ctrl+X\/C\/V klaviat\u016bras sa\u012bsnes.",
+"Div": "Div elements",
+"Paste": "Iel\u012bm\u0113t",
+"Close": "Aizv\u0113rt",
+"Pre": "Pre elements",
+"Align right": "L\u012bdzin\u0101t pa labi",
+"New document": "Jauns dokuments",
+"Blockquote": "Cit\u0101ts",
+"Numbered list": "Numur\u0113ts saraksts",
+"Increase indent": "Palielin\u0101t atk\u0101pi",
+"Formats": "Form\u0101ti",
+"Headers": "Virsraksti",
+"Select all": "Iez\u012bm\u0113t",
+"Header 3": "Tre\u0161\u0101 l\u012bme\u0146a virsraksts",
+"Blocks": "Bloka elements",
+"Undo": "Atsaukt",
+"Strikethrough": "P\u0101rsv\u012btrot",
+"Bullet list": "Nenumuer\u0113ts saraksts",
+"Header 1": "Pirm\u0101 l\u012bme\u0146a virsraksts",
+"Superscript": "Aug\u0161raksts",
+"Clear formatting": "No\u0146emt format\u0113jumu",
+"Subscript": "Apak\u0161raksts",
+"Header 6": "Sest\u0101 l\u012bme\u0146a virsraksts",
+"Redo": "Atcelt atsauk\u0161anu",
+"Paragraph": "Paragr\u0101fs",
+"Ok": "Labi",
+"Bold": "Treknraksts",
+"Code": "Koda elements",
+"Italic": "Kurs\u012bvs",
+"Align center": "Centr\u0113t",
+"Header 5": "Piekt\u0101 l\u012bme\u0146a virsraksts",
+"Decrease indent": "Samazin\u0101t atk\u0101pi",
+"Header 4": "Ceturt\u0101 l\u012bme\u0146a virsraksts",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Iel\u012bm\u0113\u0161ana tagad ir vienk\u0101r\u0161teksta re\u017e\u012bm\u0101. Saturs tiks iel\u012bm\u0113ts k\u0101 vienk\u0101r\u0161teksts, l\u012bdz \u0161\u012b opcija tiks atsl\u0113gta.",
+"Underline": "Pasv\u012btrot",
+"Cancel": "Atcelt",
+"Justify": "L\u012bdzin\u0101t abas malas",
+"Inline": "Rindi\u0146as elements",
+"Copy": "Kop\u0113t",
+"Align left": "L\u012bdzin\u0101t pa kreisi",
+"Visual aids": "Uzskates l\u012bdzek\u013ci",
+"Lower Greek": "Grie\u0137u mazie burti",
+"Square": "Kvadr\u0101ts",
+"Default": "Noklus\u0113juma",
+"Lower Alpha": "Lat\u012b\u0146u mazie burti",
+"Circle": "Aplis",
+"Disc": "Disks",
+"Upper Alpha": "Lat\u012b\u0146u lielie burti",
+"Upper Roman": "Romie\u0161u lielie burti",
+"Lower Roman": "Romie\u0161u mazie burti",
+"Name": "V\u0101rds",
+"Anchor": "Enkurelements",
+"You have unsaved changes are you sure you want to navigate away?": "Jums ir nesaglab\u0101tas izmai\u0146as, esat dro\u0161s, ka v\u0113laties doties prom",
+"Restore last draft": "Atjaunot p\u0113d\u0113jo melnrakstu",
+"Special character": "\u012apa\u0161ais simbols",
+"Source code": "Pirmkods",
+"Right to left": "No lab\u0101s uz kreiso",
+"Left to right": "No kreis\u0101s uz labo",
+"Emoticons": "Emocijas",
+"Robots": "Programmas",
+"Document properties": "Dokumenta uzst\u0101d\u012bjumi",
+"Title": "Nosaukums",
+"Keywords": "Atsl\u0113gv\u0101rdi",
+"Encoding": "Kod\u0113jums",
+"Description": "Apraksts",
+"Author": "Autors",
+"Fullscreen": "Pilnekr\u0101na re\u017e\u012bms",
+"Horizontal line": "Horizont\u0101la l\u012bnija",
+"Horizontal space": "Horizont\u0101l\u0101 vieta",
+"Insert\/edit image": "Ievietot\/labot att\u0113lu",
+"General": "Visp\u0101r\u012bgi",
+"Advanced": "Papildus",
+"Source": "Avots",
+"Border": "Apmale",
+"Constrain proportions": "Saglab\u0101t malu attiec\u012bbu",
+"Vertical space": "Vertik\u0101l\u0101 vieta",
+"Image description": "Att\u0113la apraksts",
+"Style": "Stils",
+"Dimensions": "Izm\u0113ri",
+"Insert image": "Ievietot att\u0113lu",
+"Insert date\/time": "Ievietot datumu\/laiku",
+"Remove link": "No\u0146emt saiti",
+"Url": "Adrese",
+"Text to display": "Teksts",
+"Anchors": "Enkurelements",
+"Insert link": "Ievietot saiti",
+"New window": "Jauns logs",
+"None": "Nek\u0101",
+"Target": "M\u0113r\u0137is",
+"Insert\/edit link": "Ievietot\/labot saiti",
+"Insert\/edit video": "Ievietot\/redi\u0123\u0113t video",
+"Poster": "Att\u0113ls",
+"Alternative source": "Alternat\u012bvs avots",
+"Paste your embed code below:": "Iekop\u0113jiet embed kodu zem\u0101k:",
+"Insert video": "Ievietot video",
+"Embed": "Embed",
+"Nonbreaking space": "L\u012bnij-nedalo\u0161s atstarpes simbols",
+"Page break": "P\u0101rnest jaun\u0101 lap\u0101",
+"Paste as text": "Iel\u012bm\u0113t k\u0101 tekstu",
+"Preview": "Priek\u0161skat\u012bjums",
+"Print": "Print\u0113t",
+"Save": "Saglab\u0101t",
+"Could not find the specified string.": "Mekl\u0113tais teksts netika atrasts",
+"Replace": "Aizvietot",
+"Next": "N\u0101ko\u0161ais",
+"Whole words": "Pilnus v\u0101rdus",
+"Find and replace": "Mekl\u0113t un aizvietot",
+"Replace with": "Aizvietot ar",
+"Find": "Mekl\u0113t",
+"Replace all": "Aizvietot visu",
+"Match case": "Re\u0123istrj\u016bt\u012bgs",
+"Prev": "Iepriek\u0161\u0113jais",
+"Spellcheck": "Pareizrakst\u012bbas p\u0101rbaude",
+"Finish": "Beigt",
+"Ignore all": "Ignor\u0113t visu",
+"Ignore": "Ignor\u0113t",
+"Insert row before": "Ievietot rindu pirms",
+"Rows": "Rindas",
+"Height": "Augstums",
+"Paste row after": "Iel\u012bm\u0113t rindu p\u0113c",
+"Alignment": "L\u012bdzin\u0101jums",
+"Column group": "Kolonnu grupa",
+"Row": "Rinda",
+"Insert column before": "Ievietot kolonu pirms",
+"Split cell": "Sadal\u012bt \u0161\u016bnas",
+"Cell padding": "\u0160\u016bnas atstatumi",
+"Cell spacing": "\u0160\u016bnu atstarpes",
+"Row type": "Rindas tips",
+"Insert table": "Ievietot tabulu",
+"Body": "\u0136ermenis",
+"Caption": "Virsraksts",
+"Footer": "K\u0101jene",
+"Delete row": "Dz\u0113st rindu",
+"Paste row before": "Iel\u012bm\u0113t rindu pirms",
+"Scope": "Apgabals",
+"Delete table": "Dz\u0113st tabulu",
+"Header cell": "Galvenes \u0161\u016bna",
+"Column": "Kolona",
+"Cell": "\u0160\u016bna",
+"Header": "Galvene",
+"Cell type": "\u0160\u016bnas tips",
+"Copy row": "Kop\u0113t rindu",
+"Row properties": "Rindas uzst\u0101d\u012bjumi",
+"Table properties": "Tabulas uzst\u0101d\u012bjumi",
+"Row group": "Rindu grupa",
+"Right": "Pa labi",
+"Insert column after": "Ievietot kolonu p\u0113c",
+"Cols": "Kolonas",
+"Insert row after": "Ievietot rindu p\u0113c",
+"Width": "Platums",
+"Cell properties": "\u0160\u016bnas uzst\u0101d\u012bjumi",
+"Left": "Pa kreisi",
+"Cut row": "Izgriezt rindu",
+"Delete column": "Dz\u0113st kolonu",
+"Center": "Centr\u0113t",
+"Merge cells": "Apvienot \u0161\u016bnas",
+"Insert template": "Ievietot \u0161ablonu",
+"Templates": "\u0160abloni",
+"Background color": "Fona kr\u0101sa",
+"Text color": "Teksta kr\u0101sa",
+"Show blocks": "R\u0101d\u012bt blokus",
+"Show invisible characters": "R\u0101d\u012bt neredzam\u0101s rakstz\u012bmes",
+"Words: {0}": "V\u0101rdi: {0}",
+"Insert": "Ievietot",
+"File": "Fails",
+"Edit": "Labot",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Vizu\u0101li redi\u0123\u0113jama teksta apgabals. Nospiediet ALT-F9 izv\u0113lnei, ALT-F10 r\u012bkjoslai vai ALT-0 pal\u012bdz\u012bbai.",
+"Tools": "R\u012bki",
+"View": "Skat\u012bt",
+"Table": "Tabula",
+"Format": "Form\u0101ts"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/nb_NO.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/nb_NO.js
new file mode 100755
index 0000000..4eb851e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/nb_NO.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('nb_NO',{
+"Cut": "Klipp ut",
+"Header 2": "Overskrift 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Nettleseren din st\u00f8tter ikke direkte tilgang til utklippsboken. Bruk istedet tastatur-snarveiene Ctrl+X\/C\/V, eller Cmd+X\/C\/V p\u00e5 Mac.",
+"Div": "Div",
+"Paste": "Lim inn",
+"Close": "Lukk",
+"Pre": "Pre",
+"Align right": "H\u00f8yrejustert",
+"New document": "Nytt dokument",
+"Blockquote": "Blokksitat",
+"Numbered list": "Nummerliste",
+"Increase indent": "\u00d8k innrykk",
+"Formats": "Stiler",
+"Headers": "Overskrifter",
+"Select all": "Marker alt",
+"Header 3": "Overskrift 3",
+"Blocks": "Blokker",
+"Undo": "Angre",
+"Strikethrough": "Gjennomstreket",
+"Bullet list": "Punktliste",
+"Header 1": "Overskrift 1",
+"Superscript": "Hevet skrift",
+"Clear formatting": "Fjern formateringer",
+"Subscript": "Senket skrift",
+"Header 6": "Overskrift 6",
+"Redo": "Utf\u00f8r likevel",
+"Paragraph": "Avsnitt",
+"Ok": "OK",
+"Bold": "Halvfet",
+"Code": "Kode",
+"Italic": "Kursiv",
+"Align center": "Midtstilt",
+"Header 5": "Overskrift 5",
+"Decrease indent": "Reduser innrykk",
+"Header 4": "Overskrift 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Lim inn - er n\u00e5 i ren-tekst modus. Kopiert innhold vil bli limt inn som ren-tekst inntil du sl\u00e5r av dette valget.",
+"Underline": "Understreket",
+"Cancel": "Avbryt",
+"Justify": "Juster alle linjer",
+"Inline": "Innkapslet - inline",
+"Copy": "Kopier",
+"Align left": "Venstrejustert",
+"Visual aids": "Visuelle hjelpemidler",
+"Lower Greek": "Greske minuskler",
+"Square": "Fylt firkant",
+"Default": "Normal",
+"Lower Alpha": "Minuskler",
+"Circle": "\u00c5pen sirkel",
+"Disc": "Fylt sirkel",
+"Upper Alpha": "Versaler",
+"Upper Roman": "Romerske versaler",
+"Lower Roman": "Romerske minuskler",
+"Name": "Navn",
+"Anchor": "Anker",
+"You have unsaved changes are you sure you want to navigate away?": "Endringer er ikke arkivert. Vil du fortsette uten \u00e5 arkivere endringer?",
+"Restore last draft": "Gjenopprett siste utkast",
+"Special character": "Spesialtegn",
+"Source code": "Kildekode",
+"Right to left": "H\u00f8yre til venstre",
+"Left to right": "Venstre til h\u00f8yre",
+"Emoticons": "Emoticons",
+"Robots": "Roboter",
+"Document properties": "Dokumentegenskaper",
+"Title": "Tittel",
+"Keywords": "N\u00f8kkelord",
+"Encoding": "Tegnkoding",
+"Description": "Beskrivelse",
+"Author": "Forfatter",
+"Fullscreen": "Fullskjerm",
+"Horizontal line": "Horisontal linje",
+"Horizontal space": "Horisontal marg",
+"Insert\/edit image": "Sett inn\/endre bilde",
+"General": "Generelt",
+"Advanced": "Avansert",
+"Source": "Bildelenke",
+"Border": "Ramme",
+"Constrain proportions": "Behold proporsjoner",
+"Vertical space": "Vertikal marg",
+"Image description": "Bildebeskrivelse",
+"Style": "Stil",
+"Dimensions": "Dimensjoner",
+"Insert image": "Sett inn bilde",
+"Insert date\/time": "Sett inn dato\/tid",
+"Remove link": "Fjern lenke",
+"Url": "Url",
+"Text to display": "Tekst som skal vises",
+"Anchors": "Anker",
+"Insert link": "Sett inn lenke",
+"New window": "Nytt vindu",
+"None": "Ingen",
+"Target": "M\u00e5l",
+"Insert\/edit link": "Sett inn\/endre lenke",
+"Insert\/edit video": "Sett inn\/endre video",
+"Poster": "Poster",
+"Alternative source": "Alternativ kilde",
+"Paste your embed code below:": "Lim inn inkluderings-koden nedenfor",
+"Insert video": "Sett inn video",
+"Embed": "Inkluder",
+"Nonbreaking space": "Hardt mellomrom",
+"Page break": "Sideskifte",
+"Paste as text": "Lim inn som tekst",
+"Preview": "Forh\u00e5ndsvisning",
+"Print": "Skriv ut",
+"Save": "Arkiver",
+"Could not find the specified string.": "Kunne ikke finne den spesifiserte teksten",
+"Replace": "Erstatt",
+"Next": "Neste",
+"Whole words": "Hele ord",
+"Find and replace": "Finn og erstatt",
+"Replace with": "Erstatt med",
+"Find": "Finn",
+"Replace all": "Erstatt alle",
+"Match case": "Match store og sm\u00e5 bokstaver",
+"Prev": "Forrige",
+"Spellcheck": "Stavekontroll",
+"Finish": "Avslutt",
+"Ignore all": "Ignorer alle",
+"Ignore": "Ignorer",
+"Insert row before": "Sett inn rad f\u00f8r",
+"Rows": "Rader",
+"Height": "H\u00f8yde",
+"Paste row after": "Lim inn rad etter",
+"Alignment": "Justering",
+"Column group": "Kolonnegruppe",
+"Row": "Rad",
+"Insert column before": "Sett inn kolonne f\u00f8r",
+"Split cell": "Splitt celle",
+"Cell padding": "Celle rammemarg",
+"Cell spacing": "Celleavstand",
+"Row type": "Radtype",
+"Insert table": "Sett inn tabell",
+"Body": "Br\u00f8dtekst",
+"Caption": "Tittel",
+"Footer": "Bunntekst",
+"Delete row": "Slett rad",
+"Paste row before": "Lim inn rad f\u00f8r",
+"Scope": "Omfang",
+"Delete table": "Slett tabell",
+"Header cell": "Topptekst celle",
+"Column": "Kolonne",
+"Cell": "Celle",
+"Header": "Topptekst",
+"Cell type": "Celletype",
+"Copy row": "Kopier rad",
+"Row properties": "Rad egenskaper",
+"Table properties": "Tabell egenskaper",
+"Row group": "Radgruppe",
+"Right": "H\u00f8yre",
+"Insert column after": "Sett inn kolonne etter",
+"Cols": "Kolonner",
+"Insert row after": "Sett in rad etter",
+"Width": "Bredde",
+"Cell properties": "Celle egenskaper",
+"Left": "Venstre",
+"Cut row": "Klipp ut rad",
+"Delete column": "Slett kolonne",
+"Center": "Midtstilt",
+"Merge cells": "Sl\u00e5 sammen celler",
+"Insert template": "Sett inn mal",
+"Templates": "Maler",
+"Background color": "Bakgrunnsfarge",
+"Text color": "Tekstfarge",
+"Show blocks": "Vis blokker",
+"Show invisible characters": "Vis usynlige tegn",
+"Words: {0}": "Antall ord: {0}",
+"Insert": "Sett inn",
+"File": "Arkiv",
+"Edit": "Rediger",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Tekstredigering. Tast ALT-F9 for meny. Tast ALT-F10 for verkt\u00f8ys-rader. Trykk ALT-0 for hjelp.",
+"Tools": "Verkt\u00f8y",
+"View": "Vis",
+"Table": "Tabell",
+"Format": "Format"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/nl.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/nl.js
new file mode 100755
index 0000000..92b6dce
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/nl.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('nl',{
+"Cut": "Knippen",
+"Header 2": "Kop 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Uw browser ondersteunt geen toegang tot het clipboard. Gelieve ctrl+X\/C\/V sneltoetsen te gebruiken.",
+"Div": "Div",
+"Paste": "Plakken",
+"Close": "Sluiten",
+"Pre": "Pre",
+"Align right": "Rechts uitlijnen",
+"New document": "Nieuw document",
+"Blockquote": "Quote",
+"Numbered list": "Nummering",
+"Increase indent": "Inspringen vergroten",
+"Formats": "Opmaak",
+"Headers": "Kopteksten",
+"Select all": "Alles selecteren",
+"Header 3": "Hoofding 3",
+"Blocks": "Blok",
+"Undo": "Ongedaan maken",
+"Strikethrough": "Doorhalen",
+"Bullet list": "Opsommingsteken",
+"Header 1": "Kop 1",
+"Superscript": "Superscript",
+"Clear formatting": "Opmaak verwijderen",
+"Subscript": "Subscript",
+"Header 6": "Hoofding 6",
+"Redo": "Opnieuw",
+"Paragraph": "Paragraaf",
+"Ok": "Ok\u00e9",
+"Bold": "Vet",
+"Code": "Code",
+"Italic": "Schuin",
+"Align center": "Centreren",
+"Header 5": "Hoofding 5",
+"Decrease indent": "Inspringen verkleinen",
+"Header 4": "Hoofding 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Plakken gebeurt nu als platte tekst. Tekst wordt nu ingevoegd zonder opmaak tenzij deze optie uitgeschakeld wordt.",
+"Underline": "Onderstreept",
+"Cancel": "Annuleren",
+"Justify": "Uitlijnen",
+"Inline": "Inlijn",
+"Copy": "Kopi\u00ebren",
+"Align left": "Links uitlijnen",
+"Visual aids": "Hulpmiddelen",
+"Lower Greek": "greek verlagen",
+"Square": "Vierkant",
+"Default": "Standaard",
+"Lower Alpha": "Kleine letters",
+"Circle": "Cirkel",
+"Disc": "Bolletje",
+"Upper Alpha": "Hoofdletters",
+"Upper Roman": "Roman vergroten",
+"Lower Roman": "Roman verlagen",
+"Name": "Naam",
+"Anchor": "Anker",
+"You have unsaved changes are you sure you want to navigate away?": "U hebt niet alles opgeslagen bent u zeker dat u de pagina wenst te verlaten?",
+"Restore last draft": "Herstel het laatste concept",
+"Special character": "Speciale karakters",
+"Source code": "Broncode",
+"Right to left": "Rechts naar links",
+"Left to right": "Links naar rechts",
+"Emoticons": "Emoticons",
+"Robots": "Robots",
+"Document properties": "Document eigenschappen",
+"Title": "Titel",
+"Keywords": "Sleutelwoorden",
+"Encoding": "Codering",
+"Description": "Omschrijving",
+"Author": "Auteur",
+"Fullscreen": "Volledig scherm",
+"Horizontal line": "Horizontale lijn",
+"Horizontal space": "Horizontale spatie",
+"Insert\/edit image": "afbeelding invoegen\/bewerken",
+"General": "Algemeen",
+"Advanced": "geavanceerd",
+"Source": "Bron",
+"Border": "Rand",
+"Constrain proportions": "verhoudingen behouden",
+"Vertical space": "Verticale spatie",
+"Image description": "Afbeelding omschrijving",
+"Style": "Stijl",
+"Dimensions": "Afmetingen",
+"Insert image": "Afbeelding invoegen",
+"Insert date\/time": "Voeg datum\/tijd in",
+"Remove link": "Link verwijderen",
+"Url": "Url",
+"Text to display": "Linktekst",
+"Anchors": "Anker",
+"Insert link": "Hyperlink invoegen",
+"New window": "Nieuw venster",
+"None": "Geen",
+"Target": "doel",
+"Insert\/edit link": "Hyperlink invoegen\/bewerken",
+"Insert\/edit video": "Video invoegen\/bewerken",
+"Poster": "Poster",
+"Alternative source": "Alternatieve bron",
+"Paste your embed code below:": "Plak u in te sluiten code hieronder:",
+"Insert video": "Video invoegen",
+"Embed": "insluiten",
+"Nonbreaking space": "Vaste spatie invoegen",
+"Page break": "Pagina einde",
+"Paste as text": "Plakken",
+"Preview": "Voorbeeld",
+"Print": "Print",
+"Save": "Opslaan",
+"Could not find the specified string.": "Geen resultaten gevonden",
+"Replace": "Vervangen",
+"Next": "Volgende",
+"Whole words": "alleen hele worden",
+"Find and replace": "Zoek en vervang",
+"Replace with": "Vervangen door",
+"Find": "Zoeken",
+"Replace all": "Vervang allemaal",
+"Match case": "Overeenkomen",
+"Prev": "Vorige",
+"Spellcheck": "Spellingscontrole",
+"Finish": "Einde",
+"Ignore all": "Alles negeren",
+"Ignore": "Negeren",
+"Insert row before": "Voeg rij boven toe",
+"Rows": "Rijen",
+"Height": "Hoogte",
+"Paste row after": "Plak rij achter",
+"Alignment": "uitlijning",
+"Column group": "kolom groep",
+"Row": "Rij",
+"Insert column before": "Voeg kolom in voor",
+"Split cell": "Cel splitsen",
+"Cell padding": "cel pading",
+"Cell spacing": "celruimte",
+"Row type": "Rij type",
+"Insert table": "Tabel invoegen",
+"Body": "Body",
+"Caption": "onderschrift",
+"Footer": "voettekst",
+"Delete row": "Verwijder rij",
+"Paste row before": "Plak rij voor",
+"Scope": "wijdte",
+"Delete table": "Verwijder tabel",
+"Header cell": "koptekstcel",
+"Column": "Kolom",
+"Cell": "Cel",
+"Header": "hoofdtekst",
+"Cell type": "cel type",
+"Copy row": "Kopieer rij",
+"Row properties": "Rij eigenschappen",
+"Table properties": "Tabel eigenschappen",
+"Row group": "rij groep",
+"Right": "Rechts",
+"Insert column after": "Voeg kolom in na",
+"Cols": "kollomen",
+"Insert row after": "Voeg rij onder toe",
+"Width": "Breedte",
+"Cell properties": "Cel eigenschappen",
+"Left": "Links",
+"Cut row": "Knip rij",
+"Delete column": "Verwijder kolom",
+"Center": "Midden",
+"Merge cells": "Cellen samenvoegen",
+"Insert template": "Sjabloon invoegen",
+"Templates": "Sjablonen",
+"Background color": "Achtergrondkleur",
+"Text color": "Tekstkleur",
+"Show blocks": "Blokken tonen",
+"Show invisible characters": "Onzichtbare karakters tonen",
+"Words: {0}": "Woorden: {0}",
+"Insert": "Invoegen",
+"File": "Bestand",
+"Edit": "Bewerken",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rich Text Area. Druk ALT-F9 voor de menu. Druk ALT-F10 voor de toolbar. Druk ALT-0 voor de help.",
+"Tools": "gereedschap",
+"View": "Beeld",
+"Table": "Tabel",
+"Format": "Opmaak"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/pl.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/pl.js
new file mode 100755
index 0000000..953966d
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/pl.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('pl',{
+"Cut": "Wytnij",
+"Header 2": "Nag\u0142\u00f3wek 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Twoja przegl\u0105darka nie obs\u0142uguje bezpo\u015bredniego dost\u0119pu do schowka. U\u017cyj zamiast tego kombinacji klawiszy Ctrl+X\/C\/V.",
+"Div": "Div",
+"Paste": "Wklej",
+"Close": "Zamknij",
+"Pre": "Sformatowany tekst",
+"Align right": "Wyr\u00f3wnaj do prawej",
+"New document": "Nowy dokument",
+"Blockquote": "Blok cytatu",
+"Numbered list": "Lista numerowana",
+"Increase indent": "Zwi\u0119ksz wci\u0119cie",
+"Formats": "Formaty",
+"Headers": "Nag\u0142\u00f3wki",
+"Select all": "Zaznacz wszystko",
+"Header 3": "Nag\u0142\u00f3wek 3",
+"Blocks": "Bloki",
+"Undo": "Cofnij",
+"Strikethrough": "Przekre\u015blenie",
+"Bullet list": "Lista wypunktowana",
+"Header 1": "Nag\u0142\u00f3wek 1",
+"Superscript": "Indeks g\u00f3rny",
+"Clear formatting": "Wyczy\u015b\u0107 formatowanie",
+"Subscript": "Indeks dolny",
+"Header 6": "Nag\u0142\u00f3wek 6",
+"Redo": "Pon\u00f3w",
+"Paragraph": "Akapit",
+"Ok": "Ok",
+"Bold": "Pogrubienie",
+"Code": "Kod \u017ar\u00f3d\u0142owy",
+"Italic": "Kursywa",
+"Align center": "Wyr\u00f3wnaj do \u015brodka",
+"Header 5": "Nag\u0142\u00f3wek 5",
+"Decrease indent": "Zmniejsz wci\u0119cie",
+"Header 4": "Nag\u0142\u00f3wek 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Wklejanie jest w trybie tekstowym. Zawarto\u015b\u0107 zostanie wklejona jako zwyk\u0142y tekst dop\u00f3ki nie wy\u0142\u0105czysz tej opcji.",
+"Underline": "Podkre\u015blenie",
+"Cancel": "Anuluj",
+"Justify": "Wyjustuj",
+"Inline": "W tek\u015bcie",
+"Copy": "Kopiuj",
+"Align left": "Wyr\u00f3wnaj do lewej",
+"Visual aids": "Pomoce wizualne",
+"Lower Greek": "Ma\u0142e greckie",
+"Square": "Kwadrat",
+"Default": "Domy\u015blne",
+"Lower Alpha": "Ma\u0142e litery",
+"Circle": "K\u00f3\u0142ko",
+"Disc": "Dysk",
+"Upper Alpha": "Wielkie litery",
+"Upper Roman": "Wielkie rzymskie",
+"Lower Roman": "Ma\u0142e rzymskie",
+"Name": "Nazwa",
+"Anchor": "Kotwica",
+"You have unsaved changes are you sure you want to navigate away?": "Masz niezapisane zmiany. Czy na pewno chcesz opu\u015bci\u0107 stron\u0119?",
+"Restore last draft": "Przywr\u00f3\u0107 ostatni szkic",
+"Special character": "Znak specjalny",
+"Source code": "Kod \u017ar\u00f3d\u0142owy",
+"Right to left": "Od prawej do lewej",
+"Left to right": "Od lewej do prawej",
+"Emoticons": "Emotikony",
+"Robots": "Roboty",
+"Document properties": "W\u0142a\u015bciwo\u015bci dokumentu",
+"Title": "Tytu\u0142",
+"Keywords": "S\u0142owa kluczowe",
+"Encoding": "Kodowanie",
+"Description": "Opis",
+"Author": "Autor",
+"Fullscreen": "Pe\u0142ny ekran",
+"Horizontal line": "Pozioma linia",
+"Horizontal space": "Odst\u0119p poziomy",
+"Insert\/edit image": "Wstaw\/edytuj obrazek",
+"General": "Og\u00f3lne",
+"Advanced": "Zaawansowane",
+"Source": "\u0179r\u00f3d\u0142o",
+"Border": "Ramka",
+"Constrain proportions": "Zachowaj proporcje",
+"Vertical space": "Odst\u0119p pionowy",
+"Image description": "Opis obrazka",
+"Style": "Styl",
+"Dimensions": "Wymiary",
+"Insert image": "Wstaw obrazek",
+"Insert date\/time": "Wstaw dat\u0119\/czas",
+"Remove link": "Usu\u0144 link",
+"Url": "Url",
+"Text to display": "Tekst do wy\u015bwietlenia",
+"Anchors": "Kotwice",
+"Insert link": "Wstaw link",
+"New window": "Nowe okno",
+"None": "\u017baden",
+"Target": "Cel",
+"Insert\/edit link": "Wstaw\/edytuj link",
+"Insert\/edit video": "Wstaw\/edytuj wideo",
+"Poster": "Plakat",
+"Alternative source": "Alternatywne \u017ar\u00f3d\u0142o",
+"Paste your embed code below:": "Wklej tutaj kod do osadzenia:",
+"Insert video": "Wstaw wideo",
+"Embed": "Osad\u017a",
+"Nonbreaking space": "Nie\u0142amliwa spacja",
+"Page break": "Podzia\u0142 strony",
+"Paste as text": "Wklej jako zwyk\u0142y tekst",
+"Preview": "Podgl\u0105d",
+"Print": "Drukuj",
+"Save": "Zapisz",
+"Could not find the specified string.": "Nie znaleziono szukanego tekstu.",
+"Replace": "Zamie\u0144",
+"Next": "Nast.",
+"Whole words": "Ca\u0142e s\u0142owa",
+"Find and replace": "Znajd\u017a i zamie\u0144",
+"Replace with": "Zamie\u0144 na",
+"Find": "Znajd\u017a",
+"Replace all": "Zamie\u0144 wszystko",
+"Match case": "Dopasuj wielko\u015b\u0107 liter",
+"Prev": "Poprz.",
+"Spellcheck": "Sprawdzanie pisowni",
+"Finish": "Zako\u0144cz",
+"Ignore all": "Ignoruj wszystko",
+"Ignore": "Ignoruj",
+"Insert row before": "Wstaw wiersz przed",
+"Rows": "Wiersz.",
+"Height": "Wysoko\u015b\u0107",
+"Paste row after": "Wklej wiersz po",
+"Alignment": "Wyr\u00f3wnanie",
+"Column group": "Grupa kolumn",
+"Row": "Wiersz",
+"Insert column before": "Wstaw kolumn\u0119 przed",
+"Split cell": "Podziel kom\u00f3rk\u0119",
+"Cell padding": "Dope\u0142nienie kom\u00f3rki",
+"Cell spacing": "Odst\u0119py kom\u00f3rek",
+"Row type": "Typ wiersza",
+"Insert table": "Wstaw tabel\u0119",
+"Body": "Tre\u015b\u0107",
+"Caption": "Tytu\u0142",
+"Footer": "Stopka",
+"Delete row": "Usu\u0144 wiersz",
+"Paste row before": "Wklej wiersz przed",
+"Scope": "Kontekst",
+"Delete table": "Usu\u0144 tabel\u0119",
+"Header cell": "Kom\u00f3rka nag\u0142\u00f3wka",
+"Column": "Kolumna",
+"Cell": "Kom\u00f3rka",
+"Header": "Nag\u0142\u00f3wek",
+"Cell type": "Typ kom\u00f3rki",
+"Copy row": "Kopiuj wiersz",
+"Row properties": "W\u0142a\u015bciwo\u015bci wiersza",
+"Table properties": "W\u0142a\u015bciwo\u015bci tabeli",
+"Row group": "Grupa wierszy",
+"Right": "Prawo",
+"Insert column after": "Wstaw kolumn\u0119 po",
+"Cols": "Kol.",
+"Insert row after": "Wstaw wiersz po",
+"Width": "Szeroko\u015b\u0107",
+"Cell properties": "W\u0142a\u015bciwo\u015bci kom\u00f3rki",
+"Left": "Lewo",
+"Cut row": "Wytnij wiersz",
+"Delete column": "Usu\u0144 kolumn\u0119",
+"Center": "\u015arodek",
+"Merge cells": "\u0141\u0105cz kom\u00f3rki",
+"Insert template": "Wstaw szablon",
+"Templates": "Szablony",
+"Background color": "Kolor t\u0142a",
+"Text color": "Kolor tekstu",
+"Show blocks": "Poka\u017c bloki",
+"Show invisible characters": "Poka\u017c niewidoczne znaki",
+"Words: {0}": "S\u0142\u00f3w: {0}",
+"Insert": "Wstaw",
+"File": "Plik",
+"Edit": "Edycja",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Obszar Edycji. ALT-F9 - menu. ALT-F10 - pasek narz\u0119dzi. ALT-0 - pomoc",
+"Tools": "Narz\u0119dzia",
+"View": "Widok",
+"Table": "Tabela",
+"Format": "Format"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/pt_BR.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/pt_BR.js
new file mode 100755
index 0000000..116035b
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/pt_BR.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('pt_BR',{
+"Cut": "Recortar",
+"Header 2": "Cabe\u00e7alho 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Seu navegador n\u00e3o suporta acesso direto \u00e0 \u00e1rea de transfer\u00eancia. Por favor use os atalhos Ctrl+X - C - V do teclado",
+"Div": "Div",
+"Paste": "Colar",
+"Close": "Fechar",
+"Pre": "Pre",
+"Align right": "Alinhar \u00e0 direita",
+"New document": "Novo documento",
+"Blockquote": "Aspas",
+"Numbered list": "Lista ordenada",
+"Increase indent": "Aumentar recuo",
+"Formats": "Formatos",
+"Headers": "Cabe\u00e7alhos",
+"Select all": "Selecionar tudo",
+"Header 3": "Cabe\u00e7alho 3",
+"Blocks": "Blocos",
+"Undo": "Desfazer",
+"Strikethrough": "Riscar",
+"Bullet list": "Lista n\u00e3o ordenada",
+"Header 1": "Cabe\u00e7alho 1",
+"Superscript": "Sobrescrever",
+"Clear formatting": "Limpar formata\u00e7\u00e3o",
+"Subscript": "Subscrever",
+"Header 6": "Cabe\u00e7alho 6",
+"Redo": "Refazer",
+"Paragraph": "Par\u00e1grafo",
+"Ok": "Ok",
+"Bold": "Negrito",
+"Code": "C\u00f3digo",
+"Italic": "It\u00e1lico",
+"Align center": "Centralizar",
+"Header 5": "Cabe\u00e7alho 5",
+"Decrease indent": "Diminuir recuo",
+"Header 4": "Cabe\u00e7alho 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "O comando colar est\u00e1 agora em modo texto plano. O conte\u00fado ser\u00e1 colado como texto plano at\u00e9 voc\u00ea desligar esta op\u00e7\u00e3o.",
+"Underline": "Sublinhar",
+"Cancel": "Cancelar",
+"Justify": "Justificar",
+"Inline": "Em linha",
+"Copy": "Copiar",
+"Align left": "Alinhar \u00e0 esquerda",
+"Visual aids": "Ajuda visual",
+"Lower Greek": "\u03b1. \u03b2. \u03b3. ...",
+"Square": "Quadrado",
+"Default": "Padr\u00e3o",
+"Lower Alpha": "a. b. c. ...",
+"Circle": "C\u00edrculo",
+"Disc": "Disco",
+"Upper Alpha": "A. B. C. ...",
+"Upper Roman": "I. II. III. ...",
+"Lower Roman": "i. ii. iii. ...",
+"Name": "Nome",
+"Anchor": "\u00c2ncora",
+"You have unsaved changes are you sure you want to navigate away?": "Voc\u00ea tem mudan\u00e7as n\u00e3o salvas. Voc\u00ea tem certeza que deseja sair?",
+"Restore last draft": "Restaurar \u00faltimo rascunho",
+"Special character": "Caracteres especiais",
+"Source code": "C\u00f3digo fonte",
+"Right to left": "Da direita para a esquerda",
+"Left to right": "Da esquerda para a direita",
+"Emoticons": "Emoticons",
+"Robots": "Rob\u00f4s",
+"Document properties": "Propriedades do documento",
+"Title": "T\u00edtulo",
+"Keywords": "Palavras-chave",
+"Encoding": "Codifica\u00e7\u00e3o",
+"Description": "Descri\u00e7\u00e3o",
+"Author": "Autor",
+"Fullscreen": "Tela cheia",
+"Horizontal line": "Linha horizontal",
+"Horizontal space": "Espa\u00e7amento horizontal",
+"Insert\/edit image": "Inserir\/editar imagem",
+"General": "Geral",
+"Advanced": "Avan\u00e7ado",
+"Source": "Endere\u00e7o da imagem",
+"Border": "Borda",
+"Constrain proportions": "Manter propor\u00e7\u00f5es",
+"Vertical space": "Espa\u00e7amento vertical",
+"Image description": "Inserir descri\u00e7\u00e3o",
+"Style": "Estilo",
+"Dimensions": "Dimens\u00f5es",
+"Insert image": "Inserir imagem",
+"Insert date\/time": "Inserir data\/hora",
+"Remove link": "Remover link",
+"Url": "Url",
+"Text to display": "Texto para mostrar",
+"Anchors": "\u00c2ncoras",
+"Insert link": "Inserir link",
+"New window": "Nova janela",
+"None": "Nenhum",
+"Target": "Alvo",
+"Insert\/edit link": "Inserir\/editar link",
+"Insert\/edit video": "Inserir\/editar v\u00eddeo",
+"Poster": "Autor",
+"Alternative source": "Fonte alternativa",
+"Paste your embed code below:": "Insira o c\u00f3digo de incorpora\u00e7\u00e3o abaixo:",
+"Insert video": "Inserir v\u00eddeo",
+"Embed": "Incorporar",
+"Nonbreaking space": "Espa\u00e7o n\u00e3o separ\u00e1vel",
+"Page break": "Quebra de p\u00e1gina",
+"Paste as text": "Colar como texto",
+"Preview": "Pr\u00e9-visualizar",
+"Print": "Imprimir",
+"Save": "Salvar",
+"Could not find the specified string.": "N\u00e3o foi poss\u00edvel encontrar o termo especificado",
+"Replace": "Substituir",
+"Next": "Pr\u00f3ximo",
+"Whole words": "Palavras inteiras",
+"Find and replace": "Localizar e substituir",
+"Replace with": "Substituir por",
+"Find": "Localizar",
+"Replace all": "Substituir tudo",
+"Match case": "Diferenciar mai\u00fasculas e min\u00fasculas",
+"Prev": "Anterior",
+"Spellcheck": "Corretor ortogr\u00e1fico",
+"Finish": "Finalizar",
+"Ignore all": "Ignorar tudo",
+"Ignore": "Ignorar",
+"Insert row before": "Inserir linha antes",
+"Rows": "Linhas",
+"Height": "Altura",
+"Paste row after": "Colar linha depois",
+"Alignment": "Alinhamento",
+"Column group": "Agrupar coluna",
+"Row": "Linha",
+"Insert column before": "Inserir coluna antes",
+"Split cell": "Dividir c\u00e9lula",
+"Cell padding": "Espa\u00e7amento interno da c\u00e9lula",
+"Cell spacing": "Espa\u00e7amento da c\u00e9lula",
+"Row type": "Tipo de linha",
+"Insert table": "Inserir tabela",
+"Body": "Corpo",
+"Caption": "Legenda",
+"Footer": "Rodap\u00e9",
+"Delete row": "Excluir linha",
+"Paste row before": "Colar linha antes",
+"Scope": "Escopo",
+"Delete table": "Excluir tabela",
+"Header cell": "C\u00e9lula cabe\u00e7alho",
+"Column": "Coluna",
+"Cell": "C\u00e9lula",
+"Header": "Cabe\u00e7alho",
+"Cell type": "Tipo de c\u00e9lula",
+"Copy row": "Copiar linha",
+"Row properties": "Propriedades da linha",
+"Table properties": "Propriedades da tabela",
+"Row group": "Agrupar linha",
+"Right": "Direita",
+"Insert column after": "Inserir coluna depois",
+"Cols": "Colunas",
+"Insert row after": "Inserir linha depois",
+"Width": "Largura",
+"Cell properties": "Propriedades da c\u00e9lula",
+"Left": "Esquerdo",
+"Cut row": "Recortar linha",
+"Delete column": "Excluir coluna",
+"Center": "Centro",
+"Merge cells": "Agrupar c\u00e9lulas",
+"Insert template": "Inserir modelo",
+"Templates": "Modelos",
+"Background color": "Cor do fundo",
+"Text color": "Cor do texto",
+"Show blocks": "Mostrar blocos",
+"Show invisible characters": "Exibir caracteres invis\u00edveis",
+"Words: {0}": "Palavras: {0}",
+"Insert": "Inserir",
+"File": "Arquivo",
+"Edit": "Editar",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u00c1rea de texto formatado. Pressione ALT-F9 para exibir o menu, ALT-F10 para exibir a barra de ferramentas ou ALT-0 para exibir a ajuda",
+"Tools": "Ferramentas",
+"View": "Visualizar",
+"Table": "Tabela",
+"Format": "Formatar"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/pt_PT.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/pt_PT.js
new file mode 100755
index 0000000..b1abd8e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/pt_PT.js
@@ -0,0 +1,173 @@
+tinymce.addI18n('pt_PT',{
+"Cut": "Cortar",
+"Header 2": "Cabe\u00e7alho 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "O seu navegador n\u00e3o suporta acesso directo \u00e0 \u00e1rea de transfer\u00eancia. Por favor use os atalhos Ctrl+X\/C\/V do seu teclado.",
+"Div": "Div",
+"Paste": "Colar",
+"Close": "Fechar",
+"Pre": "Pre",
+"Align right": "Alinhar \u00e0 direita",
+"New document": "Novo documento",
+"Blockquote": "Cita\u00e7\u00e3o em bloco",
+"Numbered list": "Lista numerada",
+"Increase indent": "Aumentar avan\u00e7o",
+"Formats": "Formatos",
+"Headers": "Cabe\u00e7alhos",
+"Select all": "Seleccionar tudo",
+"Header 3": "Cabe\u00e7alho 3",
+"Blocks": "Blocos",
+"Undo": "Anular",
+"Strikethrough": "Rasurado",
+"Bullet list": "Lista com marcadores",
+"Header 1": "Cabe\u00e7alho 1",
+"Superscript": "Superior \u00e0 linha",
+"Clear formatting": "Limpar formata\u00e7\u00e3o",
+"Subscript": "Inferior \u00e0 linha",
+"Header 6": "Cabe\u00e7alho 6",
+"Redo": "Restaurar",
+"Paragraph": "Par\u00e1grafo",
+"Ok": "Ok",
+"Bold": "Negrito",
+"Code": "C\u00f3digo",
+"Italic": "It\u00e1lico",
+"Align center": "Alinhar ao centro",
+"Header 5": "Cabe\u00e7alho 5",
+"Decrease indent": "Diminuir avan\u00e7o",
+"Header 4": "Cabe\u00e7alho 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "O comando colar est\u00e1 em modo de texto plano. O conte\u00fado ser\u00e1 colado como texto plano at\u00e9 desactivar esta op\u00e7\u00e3o.",
+"Underline": "Sublinhado",
+"Cancel": "Cancelar",
+"Justify": "Justificado",
+"Inline": "Inline",
+"Copy": "Copiar",
+"Align left": "Alinhar \u00e0 esquerda",
+"Visual aids": "Ajuda visual",
+"Lower Greek": "\\u03b1. \\u03b2. \\u03b3. ...",
+"Square": "Quadrado",
+"Default": "Padr\u00e3o",
+"Lower Alpha": "a. b. c. ...",
+"Circle": "C\u00edrculo",
+"Disc": "Disco",
+"Upper Alpha": "A. B. C. ...",
+"Upper Roman": "I. II. III. ...",
+"Lower Roman": "i. ii. iii. ...",
+"Name": "Nome",
+"Anchor": "\u00c2ncora",
+"You have unsaved changes are you sure you want to navigate away?": "Tem altera\u00e7\u00f5es que ainda n\u00e3o foram guardadas, tem a certeza que pretende sair?",
+"Restore last draft": "Restaurar o \u00faltimo rascunho",
+"Special character": "Car\u00e1cter especial",
+"Source code": "C\u00f3digo fonte",
+"Right to left": "Da direita para a esquerda",
+"Left to right": "Da esquerda para a direita",
+"Emoticons": "\u00cdcones expressivos",
+"Robots": "Rob\u00f4s",
+"Document properties": "Propriedades do documento",
+"Title": "T\u00edtulo",
+"Keywords": "Palavras-chave",
+"Encoding": "Codifica\u00e7\u00e3o",
+"Description": "Descri\u00e7\u00e3o",
+"Author": "Autor",
+"Fullscreen": "Ecr\u00e3 completo",
+"Horizontal line": "Linha horizontal",
+"Horizontal space": "Espa\u00e7amento horizontal",
+"Insert\/edit image": "Inserir\/editar imagem",
+"General": "Geral",
+"Advanced": "Avan\u00e7ado",
+"Source": "Localiza\u00e7\u00e3o",
+"Border": "Contorno",
+"Constrain proportions": "Manter propor\u00e7\u00f5es",
+"Vertical space": "Espa\u00e7amento vertical",
+"Image description": "Descri\u00e7\u00e3o da imagem",
+"Style": "Estilo",
+"Dimensions": "Dimens\u00f5es",
+"Insert image": "Inserir imagem",
+"Insert date\/time": "Inserir data\/hora",
+"Remove link": "Remover link",
+"Url": "Url",
+"Text to display": "Texto a exibir",
+"Insert link": "Inserir link",
+"New window": "Nova janela",
+"None": "Nenhum",
+"Target": "Alvo",
+"Insert\/edit link": "Inserir\/editar link",
+"Insert\/edit video": "Inserir\/editar v\u00eddeo",
+"Poster": "Autor",
+"Alternative source": "Localiza\u00e7\u00e3o alternativa",
+"Paste your embed code below:": "Insira o c\u00f3digo de incorpora\u00e7\u00e3o abaixo:",
+"Insert video": "Inserir v\u00eddeo",
+"Embed": "Incorporar",
+"Nonbreaking space": "Espa\u00e7amento n\u00e3o separ\u00e1vel",
+"Page break": "Quebra de p\u00e1gina",
+"Preview": "Pr\u00e9-visualizar",
+"Print": "Imprimir",
+"Save": "Guardar",
+"Could not find the specified string.": "N\u00e3o foi poss\u00edvel localizar o termo especificado.",
+"Replace": "Substituir",
+"Next": "Pr\u00f3ximo",
+"Whole words": "Palavras completas",
+"Find and replace": "Localizar e substituir",
+"Replace with": "Substituir por",
+"Find": "Localizar",
+"Replace all": "Substituir tudo",
+"Match case": "Diferenciar mai\u00fasculas e min\u00fasculas",
+"Prev": "Anterior",
+"Spellcheck": "Corrector ortogr\u00e1fico",
+"Finish": "Concluir",
+"Ignore all": "Ignorar tudo",
+"Ignore": "Ignorar",
+"Insert row before": "Inserir linha antes",
+"Rows": "Linhas",
+"Height": "Altura",
+"Paste row after": "Colar linha depois",
+"Alignment": "Alinhamento",
+"Column group": "Agrupar coluna",
+"Row": "Linha",
+"Insert column before": "Inserir coluna antes",
+"Split cell": "Dividir c\u00e9lula",
+"Cell padding": "Espa\u00e7amento interno da c\u00e9lula",
+"Cell spacing": "Espa\u00e7amento da c\u00e9lula",
+"Row type": "Tipo de linha",
+"Insert table": "Inserir tabela",
+"Body": "Corpo",
+"Caption": "Legenda",
+"Footer": "Rodap\u00e9",
+"Delete row": "Eliminar linha",
+"Paste row before": "Colar linha antes",
+"Scope": "Escopo",
+"Delete table": "Eliminar tabela",
+"Header cell": "Cabe\u00e7alho da c\u00e9lula",
+"Column": "Coluna",
+"Cell": "C\u00e9lula",
+"Header": "Cabe\u00e7alho",
+"Cell type": "Tipo de c\u00e9lula",
+"Copy row": "Copiar linha",
+"Row properties": "Propriedades da linha",
+"Table properties": "Propriedades da tabela",
+"Row group": "Agrupar linha",
+"Right": "Direita",
+"Insert column after": "Inserir coluna depois",
+"Cols": "Colunas",
+"Insert row after": "Inserir linha depois",
+"Width": "Largura",
+"Cell properties": "Propriedades da c\u00e9lula",
+"Left": "Esquerda",
+"Cut row": "Cortar linha",
+"Delete column": "Eliminar coluna",
+"Center": "Centro",
+"Merge cells": "Unir c\u00e9lulas",
+"Insert template": "Inserir modelo",
+"Templates": "Modelos",
+"Background color": "Cor de fundo",
+"Text color": "Cor do texto",
+"Show blocks": "Mostrar blocos",
+"Show invisible characters": "Mostrar caracteres \u00ednvisiveis",
+"Words: {0}": "Palavras: {0}",
+"Insert": "Inserir",
+"File": "Ficheiro",
+"Edit": "Editar",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u00c1rea de texto formatado. Pressione ALT-F9 para exibir o menu. Pressione ALT-F10 para exibir a barra de ferramentas. Pressione ALT-0 para exibir a ajuda",
+"Tools": "Ferramentas",
+"View": "Ver",
+"Table": "Tabela",
+"Format": "Formatar"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ro.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ro.js
new file mode 100755
index 0000000..b3f4973
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ro.js
@@ -0,0 +1,174 @@
+tinymce.addI18n('ro',{
+"Cut": "Decupeaz\u0103",
+"Header 2": "Antet 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Browserul dumneavoastr\u0103 nu support\u0103 acces direct la clipboard. Folosi\u0163i combina\u0163ile de tastatur\u0103 Ctrl+X\/C\/V.",
+"Div": "Div",
+"Paste": "Lipe\u015fte",
+"Close": "\u00cenchide",
+"Pre": "Pre",
+"Align right": "Aliniere la dreapta",
+"New document": "Document nou",
+"Blockquote": "Men\u0163iune bloc",
+"Numbered list": "List\u0103 ordonat\u0103",
+"Increase indent": "Indenteaz\u0103",
+"Formats": "Formate",
+"Headers": "Antete",
+"Select all": "Selecteaz\u0103 tot",
+"Header 3": "Antet 3",
+"Blocks": "Blocuri",
+"Undo": "Reexecut\u0103",
+"Strikethrough": "T\u0103iat",
+"Bullet list": "List\u0103 neordonat\u0103",
+"Header 1": "Antet 1",
+"Superscript": "Superscript",
+"Clear formatting": "\u015eterge format\u0103rile",
+"Subscript": "Subscript",
+"Header 6": "Antet 6",
+"Redo": "Dezexecut\u0103",
+"Paragraph": "Paragraf",
+"Ok": "Ok",
+"Bold": "\u00cengro\u015fat",
+"Code": "Cod",
+"Italic": "Italic",
+"Align center": "Centrare",
+"Header 5": "Antet 5",
+"Decrease indent": "De-indenteaz\u0103",
+"Header 4": "Antet 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Inserarea este acum \u00een modul text simplu. Con\u021binutul va fi inserat ca \u0219i text simplu p\u00e2n\u0103 c\u00e2nd nu schimba\u021bi \u00eenapoi op\u021biune.",
+"Underline": "Subliniat",
+"Cancel": "Anuleaz\u0103",
+"Justify": "Aliniere pe toat\u0103 l\u0103\u021bimea",
+"Inline": "Inline",
+"Copy": "Copiaz\u0103",
+"Align left": "Aliniere la st\u00e2nga",
+"Visual aids": "Ajutor vizual",
+"Lower Greek": "Minuscule Grecesti",
+"Square": "P\u0103trat",
+"Default": "Implicit",
+"Lower Alpha": "Minuscule Alfanumerice",
+"Circle": "Cerc",
+"Disc": "Disc",
+"Upper Alpha": "Majuscule Alfanumerice",
+"Upper Roman": "Majuscule Romane",
+"Lower Roman": "Minuscule Romane",
+"Name": "Nume",
+"Anchor": "Ancor\u0103",
+"You have unsaved changes are you sure you want to navigate away?": "Ave\u021bi modific\u0103ri nesalvate! Sunte\u0163i sigur c\u0103 dori\u0163i s\u0103 ie\u015fiti?",
+"Restore last draft": "Restaurare la ultima salvare",
+"Special character": "Caractere speciale",
+"Source code": "Codul surs\u0103",
+"Right to left": "Dreapta la st\u00e2nga",
+"Left to right": "St\u00e2nga la dreapta",
+"Emoticons": "Emoticoane",
+"Robots": "Robo\u021bi",
+"Document properties": "Propriet\u0103\u021bi document",
+"Title": "Titlu",
+"Keywords": "Cuvinte cheie",
+"Encoding": "Codare",
+"Description": "Descriere",
+"Author": "Autor",
+"Fullscreen": "Pe tot ecranul",
+"Horizontal line": "Linie orizontal\u0103",
+"Horizontal space": "Spa\u021biul orizontal",
+"Insert\/edit image": "Inserare\/editarea imaginilor",
+"General": "General",
+"Advanced": "Avansat",
+"Source": "Surs\u0103",
+"Border": "Bordur\u0103",
+"Constrain proportions": "Constr\u00e2nge propor\u021biile",
+"Vertical space": "Spa\u021biul vertical",
+"Image description": "Descrierea imaginii",
+"Style": "Stil",
+"Dimensions": "Dimensiuni",
+"Insert image": "Inserare imagine",
+"Insert date\/time": "Insereaz\u0103 data\/ora",
+"Remove link": "\u0218terge link-ul",
+"Url": "Url",
+"Text to display": "Text de afi\u0219at",
+"Anchors": "Ancor\u0103",
+"Insert link": "Inserare link",
+"New window": "Fereastr\u0103 nou\u0103",
+"None": "Nici unul",
+"Target": "\u021aint\u0103",
+"Insert\/edit link": "Inserare\/editare link",
+"Insert\/edit video": "Inserare\/editare video",
+"Poster": "Poster",
+"Alternative source": "Surs\u0103 alternativ\u0103",
+"Paste your embed code below:": "Insera\u021bi codul:",
+"Insert video": "Inserare video",
+"Embed": "Embed",
+"Nonbreaking space": "Spa\u021biu neseparator",
+"Page break": "\u00centrerupere de pagin\u0103",
+"Preview": "Previzualizare",
+"Print": "Tip\u0103re\u0219te",
+"Save": "Salveaz\u0103",
+"Could not find the specified string.": "Nu am putut g\u0103si \u0219irul specificat.",
+"Replace": "\u00cenlocuie\u015fte",
+"Next": "Precedent",
+"Whole words": "Doar cuv\u00eentul \u00eentreg",
+"Find and replace": "Caut\u0103 \u015fi \u00eenlocuie\u015fte",
+"Replace with": "\u00cenlocuie\u015fte cu",
+"Find": "Caut\u0103",
+"Replace all": "\u00cenlocuie\u015fte toate",
+"Match case": "Distinge majuscule\/minuscule",
+"Prev": "Anterior",
+"Spellcheck": "Verificarea ortografic\u0103",
+"Finish": "Finalizeaz\u0103",
+"Ignore all": "Ignor\u0103 toate",
+"Ignore": "Ignor\u0103",
+"Insert row before": "Insereaz\u0103 \u00eenainte de linie",
+"Rows": "Linii",
+"Height": "\u00cen\u0103l\u0163ime",
+"Paste row after": "Lipe\u015fte linie dup\u0103",
+"Alignment": "Aliniament",
+"Column group": "Grup de coloane",
+"Row": "Linie",
+"Insert column before": "Insereaza \u00eenainte de coloan\u0103",
+"Split cell": "\u00cemp\u0103r\u021birea celulelor",
+"Cell padding": "Spa\u021biere",
+"Cell spacing": "Spa\u021biere celule",
+"Row type": "Tip de linie",
+"Insert table": "Insereaz\u0103 tabel\u0103",
+"Body": "Corp",
+"Caption": "Titlu",
+"Footer": "Subsol",
+"Delete row": "\u0218terge linia",
+"Paste row before": "Lipe\u015fte \u00eenainte de linie",
+"Scope": "Domeniu",
+"Delete table": "\u0218terge tabel\u0103",
+"Header cell": "Antet celul\u0103",
+"Column": "Coloan\u0103",
+"Cell": "Celul\u0103",
+"Header": "Antet",
+"Cell type": "Tip celul\u0103",
+"Copy row": "Copiaz\u0103 linie",
+"Row properties": "Propriet\u0103\u021bi linie",
+"Table properties": "Propriet\u0103\u021bi tabel\u0103",
+"Row group": "Grup de linii",
+"Right": "Dreapta",
+"Insert column after": "Insereaza dup\u0103 coloan\u0103",
+"Cols": "Coloane",
+"Insert row after": "Insereaz\u0103 dup\u0103 linie",
+"Width": "L\u0103\u0163ime",
+"Cell properties": "Propriet\u0103\u021bi celul\u0103",
+"Left": "St\u00e2nga",
+"Cut row": "Taie linie",
+"Delete column": "\u0218terge coloana",
+"Center": "Centru",
+"Merge cells": "\u00cembinarea celulelor",
+"Insert template": "Insereaz\u0103 \u0219ablon",
+"Templates": "\u015eabloane",
+"Background color": "Culoare fundal",
+"Text color": "Culoare text",
+"Show blocks": "Afi\u0219are blocuri",
+"Show invisible characters": "Afi\u0219are caractere invizibile",
+"Words: {0}": "Cuvinte: {0}",
+"Insert": "Insereaz\u0103",
+"File": "Fil\u0103",
+"Edit": "Editeaz\u0103",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Zon\u0103 cu Rich Text. Apas\u0103 ALT-F9 pentru meniu. Apas\u0103 ALT-F10 pentru bara de unelte. Apas\u0103 ALT-0 pentru ajutor",
+"Tools": "Unelte",
+"View": "Vezi",
+"Table": "Tabel\u0103",
+"Format": "Formateaz\u0103"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ru.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ru.js
new file mode 100755
index 0000000..618a9a2
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ru.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('ru',{
+"Cut": "\u0412\u044b\u0440\u0435\u0437\u0430\u0442\u044c",
+"Header 2": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u0412\u0430\u0448 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043f\u0440\u044f\u043c\u043e\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0431\u0443\u0444\u0435\u0440\u0443 \u043e\u0431\u043c\u0435\u043d\u0430. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0432\u0438\u0448: Ctrl+X\/C\/V.",
+"Div": "\u0411\u043b\u043e\u043a",
+"Paste": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c",
+"Close": "\u0417\u0430\u043a\u0440\u044b\u0442\u044c",
+"Pre": "\u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435",
+"Align right": "\u041f\u043e \u043f\u0440\u0430\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e",
+"New document": "\u041d\u043e\u0432\u044b\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442",
+"Blockquote": "\u0426\u0438\u0442\u0430\u0442\u0430",
+"Numbered list": "\u041d\u0443\u043c\u0435\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a",
+"Increase indent": "\u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c \u043e\u0442\u0441\u0442\u0443\u043f",
+"Formats": "\u0424\u043e\u0440\u043c\u0430\u0442",
+"Headers": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438",
+"Select all": "\u0412\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u0432\u0441\u0435",
+"Header 3": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 3",
+"Blocks": "\u0411\u043b\u043e\u043a\u0438",
+"Undo": "\u0412\u0435\u0440\u043d\u0443\u0442\u044c",
+"Strikethrough": "\u0417\u0430\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u044b\u0439",
+"Bullet list": "\u041c\u0430\u0440\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a",
+"Header 1": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 1",
+"Superscript": "\u0412\u0435\u0440\u0445\u043d\u0438\u0439 \u0438\u043d\u0434\u0435\u043a\u0441",
+"Clear formatting": "\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442",
+"Subscript": "\u041d\u0438\u0436\u043d\u0438\u0439 \u0438\u043d\u0434\u0435\u043a\u0441",
+"Header 6": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 6",
+"Redo": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c",
+"Paragraph": "\u041f\u0430\u0440\u0430\u0433\u0440\u0430\u0444",
+"Ok": "\u041e\u043a",
+"Bold": "\u041f\u043e\u043b\u0443\u0436\u0438\u0440\u043d\u044b\u0439",
+"Code": "\u041a\u043e\u0434",
+"Italic": "\u041a\u0443\u0440\u0441\u0438\u0432",
+"Align center": "\u041f\u043e \u0446\u0435\u043d\u0442\u0440\u0443",
+"Header 5": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 5",
+"Decrease indent": "\u0423\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u043e\u0442\u0441\u0442\u0443\u043f",
+"Header 4": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u0412\u0441\u0442\u0430\u0432\u043a\u0430 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430, \u043f\u043e\u043a\u0430 \u043d\u0435 \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u0443\u044e \u043e\u043f\u0446\u0438\u044e.",
+"Underline": "\u041f\u043e\u0434\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u044b\u0439",
+"Cancel": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c",
+"Justify": "\u041f\u043e \u0448\u0438\u0440\u0438\u043d\u0435",
+"Inline": "\u0421\u0442\u0440\u043e\u0447\u043d\u044b\u0435",
+"Copy": "\u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c",
+"Align left": "\u041f\u043e \u043b\u0435\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e",
+"Visual aids": "\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0443\u0440\u044b",
+"Lower Greek": "\u0421\u0442\u0440\u043e\u0447\u043d\u044b\u0435 \u0433\u0440\u0435\u0447\u0435\u0441\u043a\u0438\u0435 \u0431\u0443\u043a\u0432\u044b",
+"Square": "\u041a\u0432\u0430\u0434\u0440\u0430\u0442\u044b",
+"Default": "\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439",
+"Lower Alpha": "\u0421\u0442\u0440\u043e\u0447\u043d\u044b\u0435 \u043b\u0430\u0442\u0438\u043d\u0441\u043a\u0438\u0435 \u0431\u0443\u043a\u0432\u044b",
+"Circle": "\u041e\u043a\u0440\u0443\u0436\u043d\u043e\u0441\u0442\u0438",
+"Disc": "\u041a\u0440\u0443\u0433\u0438",
+"Upper Alpha": "\u0417\u0430\u0433\u043b\u0430\u0432\u043d\u044b\u0435 \u043b\u0430\u0442\u0438\u043d\u0441\u043a\u0438\u0435 \u0431\u0443\u043a\u0432\u044b",
+"Upper Roman": "\u0417\u0430\u0433\u043b\u0430\u0432\u043d\u044b\u0435 \u0440\u0438\u043c\u0441\u043a\u0438\u0435 \u0446\u0438\u0444\u0440\u044b",
+"Lower Roman": "\u0421\u0442\u0440\u043e\u0447\u043d\u044b\u0435 \u0440\u0438\u043c\u0441\u043a\u0438\u0435 \u0446\u0438\u0444\u0440\u044b",
+"Name": "\u0418\u043c\u044f",
+"Anchor": "\u042f\u043a\u043e\u0440\u044c",
+"You have unsaved changes are you sure you want to navigate away?": "\u0423 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f. \u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0439\u0442\u0438?",
+"Restore last draft": "\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430",
+"Special character": "\u0421\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b",
+"Source code": "\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434",
+"Right to left": "\u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043f\u0440\u0430\u0432\u0430 \u043d\u0430\u043b\u0435\u0432\u043e",
+"Left to right": "\u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043b\u0435\u0432\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043e",
+"Emoticons": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043c\u0430\u0439\u043b",
+"Robots": "\u0420\u043e\u0431\u043e\u0442\u044b",
+"Document properties": "\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",
+"Title": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a",
+"Keywords": "\u041a\u043b\u044e\u0447\u0438\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430",
+"Encoding": "\u041a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430",
+"Description": "\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435",
+"Author": "\u0410\u0432\u0442\u043e\u0440",
+"Fullscreen": "\u041f\u043e\u043b\u043d\u043e\u044d\u043a\u0440\u0430\u043d\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c",
+"Horizontal line": "\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u043b\u0438\u043d\u0438\u044f",
+"Horizontal space": "\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b",
+"Insert\/edit image": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c\/\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435",
+"General": "\u041e\u0431\u0449\u0435\u0435",
+"Advanced": "\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0435",
+"Source": "\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a",
+"Border": "\u0420\u0430\u043c\u043a\u0430",
+"Constrain proportions": "\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043f\u0440\u043e\u043f\u043e\u0440\u0446\u0438\u0438",
+"Vertical space": "\u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b",
+"Image description": "\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f",
+"Style": "\u0421\u0442\u0438\u043b\u044c",
+"Dimensions": "\u0420\u0430\u0437\u043c\u0435\u0440",
+"Insert image": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435",
+"Insert date\/time": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0434\u0430\u0442\u0443\/\u0432\u0440\u0435\u043c\u044f",
+"Remove link": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443",
+"Url": "\u0410\u0434\u0440\u0435\u0441 \u0441\u0441\u044b\u043b\u043a\u0438",
+"Text to display": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u044b\u0439 \u0442\u0435\u043a\u0441\u0442",
+"Anchors": "\u042f\u043a\u043e\u0440\u044f",
+"Insert link": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443",
+"New window": "\u0412 \u043d\u043e\u0432\u043e\u043c \u043e\u043a\u043d\u0435",
+"None": "\u041d\u0435\u0442",
+"Target": "\u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443",
+"Insert\/edit link": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c\/\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443",
+"Insert\/edit video": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c\/\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0438\u0434\u0435\u043e",
+"Poster": "\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435",
+"Alternative source": "\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a",
+"Paste your embed code below:": "\u0412\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u0432\u0430\u0448 \u043a\u043e\u0434 \u043d\u0438\u0436\u0435:",
+"Insert video": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u0438\u0434\u0435\u043e",
+"Embed": "\u041a\u043e\u0434 \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438",
+"Nonbreaking space": "\u041d\u0435\u0440\u0430\u0437\u0440\u044b\u0432\u043d\u044b\u0439 \u043f\u0440\u043e\u0431\u0435\u043b",
+"Page break": "\u0420\u0430\u0437\u0440\u044b\u0432 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b",
+"Paste as text": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u0430\u043a \u0442\u0435\u043a\u0441\u0442",
+"Preview": "\u041f\u0440\u0435\u0434\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440",
+"Print": "\u041f\u0435\u0447\u0430\u0442\u044c",
+"Save": "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c",
+"Could not find the specified string.": "\u0417\u0430\u0434\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430",
+"Replace": "\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c",
+"Next": "\u0412\u043d\u0438\u0437",
+"Whole words": "\u0421\u043b\u043e\u0432\u043e \u0446\u0435\u043b\u0438\u043a\u043e\u043c",
+"Find and replace": "\u041f\u043e\u0438\u0441\u043a \u0438 \u0437\u0430\u043c\u0435\u043d\u0430",
+"Replace with": "\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430",
+"Find": "\u041d\u0430\u0439\u0442\u0438",
+"Replace all": "\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u0441\u0435",
+"Match case": "\u0423\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0440\u0435\u0433\u0438\u0441\u0442\u0440",
+"Prev": "\u0412\u0432\u0435\u0440\u0445",
+"Spellcheck": "\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435",
+"Finish": "\u0417\u0430\u043a\u043e\u043d\u0447\u0438\u0442\u044c",
+"Ignore all": "\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435",
+"Ignore": "\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c",
+"Insert row before": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u0443\u0441\u0442\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u0441\u0432\u0435\u0440\u0445\u0443",
+"Rows": "\u0421\u0442\u0440\u043e\u043a\u0438",
+"Height": "\u0412\u044b\u0441\u043e\u0442\u0430",
+"Paste row after": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0441\u043d\u0438\u0437\u0443",
+"Alignment": "\u0412\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435",
+"Column group": "\u0413\u0440\u0443\u043f\u043f\u0430 \u043a\u043e\u043b\u043e\u043d\u043e\u043a",
+"Row": "\u0421\u0442\u0440\u043e\u043a\u0430",
+"Insert column before": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446 \u0441\u043b\u0435\u0432\u0430",
+"Split cell": "\u0420\u0430\u0437\u0431\u0438\u0442\u044c \u044f\u0447\u0435\u0439\u043a\u0443",
+"Cell padding": "\u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u043e\u0442\u0441\u0442\u0443\u043f",
+"Cell spacing": "\u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u043e\u0442\u0441\u0442\u0443\u043f",
+"Row type": "\u0422\u0438\u043f \u0441\u0442\u0440\u043e\u043a\u0438",
+"Insert table": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443",
+"Body": "\u0422\u0435\u043b\u043e",
+"Caption": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a",
+"Footer": "\u041d\u0438\u0437",
+"Delete row": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443",
+"Paste row before": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0441\u0432\u0435\u0440\u0445\u0443",
+"Scope": "Scope",
+"Delete table": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443",
+"Header cell": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a",
+"Column": "\u0421\u0442\u043e\u043b\u0431\u0435\u0446",
+"Cell": "\u042f\u0447\u0435\u0439\u043a\u0430",
+"Header": "\u0428\u0430\u043f\u043a\u0430",
+"Cell type": "\u0422\u0438\u043f \u044f\u0447\u0435\u0439\u043a\u0438",
+"Copy row": "\u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443",
+"Row properties": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u0442\u0440\u043e\u043a\u0438",
+"Table properties": "\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u044b",
+"Row group": "\u0413\u0440\u0443\u043f\u043f\u0430 \u0441\u0442\u0440\u043e\u043a",
+"Right": "\u041f\u043e \u043f\u0440\u0430\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e",
+"Insert column after": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446 \u0441\u043f\u0440\u0430\u0432\u0430",
+"Cols": "\u0421\u0442\u043e\u043b\u0431\u0446\u044b",
+"Insert row after": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u0443\u0441\u0442\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u0441\u043d\u0438\u0437\u0443",
+"Width": "\u0428\u0438\u0440\u0438\u043d\u0430",
+"Cell properties": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u044f\u0447\u0435\u0439\u043a\u0438",
+"Left": "\u041f\u043e \u043b\u0435\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e",
+"Cut row": "\u0412\u044b\u0440\u0435\u0437\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443",
+"Delete column": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446",
+"Center": "\u041f\u043e \u0446\u0435\u043d\u0442\u0440\u0443",
+"Merge cells": "\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u044f\u0447\u0435\u0439\u043a\u0438",
+"Insert template": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d",
+"Templates": "\u0428\u0430\u0431\u043b\u043e\u043d\u044b",
+"Background color": "\u0426\u0432\u0435\u0442 \u0444\u043e\u043d\u0430",
+"Text color": "\u0426\u0432\u0435\u0442 \u0442\u0435\u043a\u0441\u0442\u0430",
+"Show blocks": "\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0431\u043b\u043e\u043a\u0438",
+"Show invisible characters": "\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0435\u0432\u0438\u0434\u0438\u043c\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b",
+"Words: {0}": "\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043b\u043e\u0432: {0}",
+"Insert": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c",
+"File": "\u0424\u0430\u0439\u043b",
+"Edit": "\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u0422\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435. \u041d\u0430\u0436\u043c\u0438\u0442\u0435 ALT-F9 \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043c\u0435\u043d\u044e, ALT-F10 \u043f\u0430\u043d\u0435\u043b\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, ALT-0 \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u043f\u043e\u043c\u043e\u0449\u0438.",
+"Tools": "\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b",
+"View": "\u0412\u0438\u0434",
+"Table": "\u0422\u0430\u0431\u043b\u0438\u0446\u0430",
+"Format": "\u0424\u043e\u0440\u043c\u0430\u0442"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/si_LK.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/si_LK.js
new file mode 100755
index 0000000..7ea4207
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/si_LK.js
@@ -0,0 +1,156 @@
+tinymce.addI18n('si_LK',{
+"Cut": "\u0d9a\u0db4\u0db1\u0dca\u0db1",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u0d9c\u0dca\u200d\u0dbb\u0dcf\u0dc4\u0d9a \u0db4\u0dd4\u0dc0\u0dbb\u0dd4\u0dc0\u0da7 \u0d8d\u0da2\u0dd4 \u0db4\u0dca\u200d\u0dbb\u0dc0\u0dda\u0dc1\u0dba\u0d9a\u0dca \u0dbd\u0db6\u0dcf\u0daf\u0dd3\u0db8\u0da7 \u0d94\u0db6\u0d9c\u0dda \u0db6\u0dca\u200d\u0dbb\u0dc0\u0dd4\u0dc3\u0dbb\u0dba \u0dc3\u0dc4\u0dba\u0d9a\u0dca \u0db1\u0ddc\u0daf\u0d9a\u0dca\u0dc0\u0dba\u0dd3. \u0d9a\u0dbb\u0dd4\u0dab\u0dcf\u0d9a\u0dbb \u0d92\u0dc0\u0dd9\u0db1\u0dd4\u0dc0\u0da7 Ctrl+X\/C\/V \u0dba\u0db1 \u0dba\u0dad\u0dd4\u0dbb\u0dd4\u0db4\u0dd4\u0dc0\u0dbb\u0dd4 \u0d9a\u0dd9\u0da7\u0dd2\u0db8\u0d9f \u0db7\u0dcf\u0dc0\u0dd2\u0dad\u0dcf \u0d9a\u0dbb\u0db1\u0dca\u0db1.",
+"Paste": "\u0d85\u0dbd\u0dc0\u0db1\u0dca\u0db1",
+"Close": "\u0dc0\u0dc3\u0db1\u0dca\u0db1",
+"Align right": "\u0daf\u0d9a\u0dd4\u0dab\u0dd4\u0db4\u0dc3\u0da7 \u0db4\u0dd9\u0dc5\u0d9c\u0dc3\u0dca\u0dc0\u0db1\u0dca\u0db1",
+"New document": "\u0db1\u0dc0 \u0dbd\u0dda\u0d9b\u0db1\u0dba\u0d9a\u0dca",
+"Numbered list": "\u0d85\u0d82\u0d9a\u0db1\u0dba \u0d9a\u0dbd \u0dbd\u0dd0\u0dba\u0dd2\u0dc3\u0dca\u0dad\u0dd4\u0dc0",
+"Increase indent": "\u0dc0\u0dd0\u0da9\u0dd2\u0dc0\u0db1 \u0d91\u0db6\u0dd4\u0db8",
+"Formats": "\u0d86\u0d9a\u0dd8\u0dad\u0dd2",
+"Select all": "\u0dc3\u0dd2\u0dba\u0dbd\u0dca\u0dbd \u0dad\u0ddd\u0dbb\u0db1\u0dca\u0db1",
+"Undo": "\u0db1\u0dd2\u0dc2\u0dca\u0db4\u0dca\u200d\u0dbb\u0db7\u0dcf \u0d9a\u0dbb\u0db1\u0dc0\u0dcf",
+"Strikethrough": "\u0db8\u0dd0\u0daf\u0dd2 \u0d89\u0dbb\u0dd0\u0dad\u0dd2",
+"Bullet list": "\u0dbd\u0dd0\u0dba\u0dd2\u0dc3\u0dca\u0dad\u0dd4\u0dc0",
+"Superscript": "\u0d8b\u0da9\u0dd4\u0dbd\u0d9a\u0dd4\u0dab\u0dd4",
+"Clear formatting": "\u0db4\u0dd0\u0dc4\u0dd0\u0daf\u0dd2\u0dbd\u0dd2 \u0d86\u0d9a\u0dd8\u0dad\u0dd2\u0d9a\u0dbb\u0dab\u0dba",
+"Subscript": "\u0dba\u0da7\u0dd2\u0dbd\u0d9a\u0dd4\u0dab\u0dd4",
+"Redo": "\t\u0db1\u0dd0\u0dc0\u0dad \u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Ok": "\u0d85\u0db1\u0dd4\u0db8\u0dad \u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Bold": "\u0db4\u0dd0\u0dc4\u0dd0\u0daf\u0dd2\u0dbd\u0dd2 \u0dc3\u0dda \u0db4\u0dd9\u0db1\u0dd9\u0db1",
+"Italic": "\u0d87\u0dbd\u0d9a\u0dd4\u0dbb\u0dd4",
+"Align center": "\u0db8\u0dd0\u0daf\u0dd2 \u0d9a\u0ddc\u0da7 \u0db4\u0dd9\u0dc5\u0d9c\u0dc3\u0dca\u0dc0\u0db1\u0dca\u0db1",
+"Decrease indent": "\u0d85\u0da9\u0dd4\u0dc0\u0db1 \u0d91\u0db6\u0dd4\u0db8",
+"Underline": "\u0dba\u0da7\u0dd2\u0db1\u0dca \u0d89\u0dbb\u0d9a\u0dca \u0d85\u0db3\u0dd2\u0db1\u0dca\u0db1",
+"Cancel": "\u0d85\u0dc4\u0ddd\u0dc3\u0dd2 \u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Justify": "\u0dc3\u0db8\u0dc0 \u0db4\u0dd9\u0dc5\u0d9c\u0dc3\u0dca\u0dc0\u0db1\u0dca\u0db1",
+"Copy": "\u0db4\u0dd2\u0da7\u0db4\u0dad\u0dca \u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Align left": "\u0dc0\u0db8\u0dca\u0db4\u0dc3\u0da7 \u0db4\u0dd9\u0dc5\u0d9c\u0dc3\u0dca\u0dc0\u0db1\u0dca\u0db1",
+"Visual aids": "\u0daf\u0dd8\u0dc1\u0dca\u200d\u0dba\u0dcf\u0db0\u0dcf\u0dbb",
+"Lower Greek": "\u0d9a\u0dd4\u0da9\u0dcf \u0d9c\u0dca\u200d\u0dbb\u0dd3\u0d9a ",
+"Square": "\u0d9a\u0ddc\u0da7\u0dd4\u0dc0",
+"Default": "\u0db4\u0dd9\u0dbb\u0db1\u0dd2\u0db8\u0dd2\u0dba ",
+"Lower Alpha": "\u0d9a\u0dd4\u0da9\u0dcf \u0d87\u0dbd\u0dca\u0dc6\u0dcf ",
+"Circle": "\u0dc0\u0d9a\u0dca\u200d\u0dbb\u0dba",
+"Disc": "\u0dad\u0dd0\u0da7\u0dd2\u0dba ",
+"Upper Alpha": "\u0dc0\u0dd2\u0dc1\u0dcf\u0dbd \u0d87\u0dbd\u0dca\u0dc6\u0dcf ",
+"Upper Roman": "\u0dc0\u0dd2\u0dc1\u0dcf\u0dbd \u0dbb\u0ddd\u0db8\u0dcf\u0db1\u0dd4 ",
+"Lower Roman": "\u0d9a\u0dd4\u0da9\u0dcf \u0dbb\u0ddd\u0db8\u0dcf\u0db1\u0dd4 ",
+"Name": "\u0db1\u0dcf\u0db8\u0dba ",
+"Anchor": "\u0d87\u0db1\u0dca\u0d9a\u0dbb\u0dba",
+"You have unsaved changes are you sure you want to navigate away?": "\u0d94\u0db6\u0d9c\u0dda \u0dc3\u0dd4\u0dbb\u0d9a\u0dd2\u0db1 \u0db1\u0ddc\u0dbd\u0daf \u0dc0\u0dd9\u0db1\u0dc3\u0dca\u0d9a\u0dd2\u0dbb\u0dd3\u0db8\u0dca \u0d87\u0dad,\u0d94\u0db6\u0da7 \u0dc0\u0dd2\u0dc1\u0dca\u0dc0\u0dcf\u0dc3\u0daf \u0d89\u0dc0\u0dad\u0da7 \u0dba\u0dcf\u0dba\u0dd4\u0dad\u0dd4\u0dba\u0dd2 \u0d9a\u0dd2\u0dba\u0dcf?",
+"Restore last draft": "\u0d85\u0dc0\u0dc3\u0dcf\u0db1\u0dba\u0da7 \u0db7\u0dcf\u0dc0\u0dd2\u0dad\u0dcf\u0d9a\u0dc5 \u0d9a\u0dd9\u0da7\u0dd4\u0db8\u0dca\u0db4\u0dad \u0db4\u0dd2\u0dc5\u0dd2\u0db1\u0d9c\u0db1\u0dca\u0db1 ",
+"Special character": "\u0dc0\u0dd2\u0dc1\u0dda\u0dc2 \u0d85\u0db1\u0dd4\u0dbd\u0d9a\u0dd4\u0dab ",
+"Source code": "\u0db8\u0dd6\u0dbd \u0d9a\u0dda\u0dad\u0dba ",
+"Right to left": "\u0daf\u0d9a\u0dd4\u0dab\u0dd4\u0db4\u0dc3 \u0dc3\u0dd2\u0da7 \u0dc0\u0db8\u0dca\u0db4\u0dc3\u0da7 ",
+"Left to right": "\u0dc0\u0db8\u0dca\u0db4\u0dc3 \u0dc3\u0dd2\u0da7 \u0daf\u0d9a\u0dd4\u0db1\u0dd4\u0db4\u0dc3\u0da7 ",
+"Emoticons": "\u0db7\u0dcf\u0dc0 \u0db1\u0dd2\u0dbb\u0dd4\u0db4\u0d9a",
+"Robots": "\u0dbb\u0ddc\u0db6\u0ddd",
+"Document properties": "\u0dbd\u0dda\u0d9b\u0db1\u0dba\u0dda \u0d9c\u0dd4\u0dab\u0dcf\u0d82\u0d9c ",
+"Title": "\u0db8\u0dcf\u0dad\u0dd8\u0d9a\u0dcf\u0dc0",
+"Keywords": "\u0db8\u0dd6\u0dbd \u0db4\u0daf\u0dba ",
+"Encoding": "\u0d9a\u0dda\u0dad\u0db1\u0dba",
+"Description": "\u0dc0\u0dd2\u0dc3\u0dca\u0dad\u0dbb\u0dba ",
+"Author": "\u0d9a\u0dad\u0dd8 ",
+"Fullscreen": "\u0db4\u0dd6\u0dbb\u0dca\u0dab \u0dad\u0dd2\u0dbb\u0dba ",
+"Horizontal line": "\u0dad\u0dd2\u0dbb\u0dc3\u0dca \u0d89\u0dbb ",
+"Horizontal space": "\u0dad\u0dd2\u0dbb\u0dc3\u0dca \u0dc4\u0dd2\u0dc3\u0dca \u0d89\u0da9",
+"Insert\/edit image": "\u0db4\u0dd2\u0db1\u0dca\u0dad\u0dd4\u0dbb\u0dba \u0d87\u0dad\u0dd4\u0dbd\u0dca\u0d9a\u0dbb\u0db1\u0dca\u0db1 \/ \u0dc3\u0d9a\u0dc3\u0dca\u0d9a\u0dbb\u0db1\u0dca\u0db1 ",
+"General": "\u0db4\u0ddc\u0daf\u0dd4",
+"Advanced": "\u0db4\u0dca\u200d\u0dbb\u0d9c\u0dad",
+"Source": "\u0db8\u0dd6\u0dbd\u0dba ",
+"Border": "\u0dc3\u0dd3\u0db8\u0dcf\u0dc0 ",
+"Constrain proportions": "\u0dc3\u0d82\u0dbb\u0ddd\u0daf\u0d9a \u0db4\u0dca\u200d\u0dbb\u0db8\u0dcf\u0dab\u0db1",
+"Vertical space": "\u0dc3\u0dd2\u0dbb\u0dc3\u0dca \u0dc4\u0dd2\u0dc3\u0dca \u0d89\u0da9",
+"Image description": "\u0db4\u0dd2\u0db1\u0dca\u0dad\u0dd4\u0dbb\u0dba\u0dda \u0dc0\u0dd2\u0dc3\u0dca\u0dad\u0dbb\u0dba ",
+"Style": "\u0dc0\u0dd2\u0dbd\u0dcf\u0dc3\u0dba",
+"Dimensions": "\u0db8\u0dcf\u0db1",
+"Insert date\/time": "\u0daf\u0dd2\u0db1\u0dba \/ \u0dc0\u0dda\u0dbd\u0dcf\u0dc0 \u0d87\u0dad\u0dd4\u0dbd\u0dca\u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Url": "Url",
+"Text to display": "\u0db4\u0dd9\u0dc5 - \u0dc3\u0d82\u0daf\u0dbb\u0dca\u0dc1\u0d9a\u0dba",
+"Insert link": "\u0dc3\u0db6\u0dd0\u0db3\u0dd2\u0dba \u0d87\u0dad\u0dd4\u0dbd\u0dca\u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"New window": "\u0db1\u0dc0 \u0d9a\u0dc0\u0dd4\u0dc5\u0dd4\u0dc0\u0d9a\u0dca",
+"None": "\u0d9a\u0dd2\u0dc3\u0dd2\u0dc0\u0d9a\u0dca \u0db1\u0dd0\u0dad",
+"Target": "\u0d89\u0dbd\u0d9a\u0dca\u0d9a\u0dba",
+"Insert\/edit link": "\u0dc3\u0db6\u0dd0\u0db3\u0dd2\u0dba \u0d87\u0dad\u0dd4\u0dbd\u0dca\u0d9a\u0dbb\u0db1\u0dca\u0db1 \/ \u0dc0\u0dd9\u0db1\u0dc3\u0dca\u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Insert\/edit video": "\u0dc0\u0dd3\u0da9\u0dd2\u0dba\u0ddd\u0dc0 \u0d87\u0dad\u0dd4\u0dbd\u0dca\u0d9a\u0dbb\u0db1\u0dca\u0db1 \/ \u0dc0\u0dd9\u0db1\u0dc3\u0dca\u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Poster": "\u0db4\u0ddd\u0dc3\u0dca\u0da7\u0dbb\u0dba",
+"Alternative source": "\u0dc0\u0dd2\u0d9a\u0dbd\u0dca\u0db4 \u0db8\u0dd6\u0dbd\u0dba",
+"Paste your embed code below:": "\u0d94\u0db6\u0d9c\u0dda \u0d9a\u0dcf\u0dc0\u0dd0\u0daf\u0dca\u0daf\u0dd6 \u0d9a\u0dda\u0dad\u0dba \u0db4\u0dc4\u0dad\u0dd2\u0db1\u0dca \u0daf\u0db8\u0db1\u0dca\u0db1",
+"Insert video": "\u0dc0\u0dd3\u0da9\u0dd2\u0dba\u0ddd\u0dc0 \u0d87\u0dad\u0dd4\u0dbd\u0dca\u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Embed": "\u0d9a\u0dcf\u0dc0\u0daf\u0dca\u0daf\u0db1\u0dca\u0db1",
+"Nonbreaking space": "\u0db1\u0ddc\u0d9a\u0dd0\u0da9\u0dd4\u0dab\u0dd4 \u0dc4\u0dd2\u0dc3\u0dca \u0d89\u0dbb",
+"Page break": "\u0db4\u0dd2\u0da7\u0dd4 \u0d9a\u0da9\u0db1\u0dba",
+"Preview": "\u0db4\u0dd9\u0dbb\u0daf\u0dc3\u0dd4\u0db1",
+"Print": "\u0db8\u0dd4\u0daf\u0dca\u200d\u0dbb\u0dab\u0dba \u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Save": "\u0dc3\u0dd4\u0dbb\u0d9a\u0dd2\u0db1\u0dca\u0db1",
+"Could not find the specified string.": "\u0db1\u0dd2\u0dbb\u0dd6\u0db4\u0dd2\u0dad \u0d85\u0db1\u0dd4\u0dbd\u0d9a\u0dd4\u0dab\u0dd4 \u0dc0\u0dd0\u0dbd \u0dc3\u0ddc\u0dba\u0dcf \u0d9c\u0dad \u0db1\u0ddc\u0dc4\u0dd0\u0d9a\u0dd2 \u0dc0\u0dd2\u0dba",
+"Replace": "\u0db4\u0dca\u200d\u0dbb\u0dad\u0dd2\u0dc3\u0dca\u0dae\u0dcf\u0db4\u0db1\u0dba \u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Next": "\u0db4\u0dc3\u0dd4",
+"Whole words": "\u0dc3\u0db8\u0dc3\u0dca\u0dad \u0db4\u0daf",
+"Find and replace": "\u0dc3\u0ddc\u0dba\u0dcf \u0db4\u0dc3\u0dd4\u0dc0 \u0db4\u0dca\u200d\u0dbb\u0dad\u0dd2\u0dc3\u0dca\u0dae\u0dcf\u0db4\u0db1\u0dba \u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Replace with": "\u0db8\u0dd9\u0dba \u0dc3\u0db8\u0d9f \u0db4\u0dca\u200d\u0dbb\u0dad\u0dd2\u0dc3\u0dca\u0dae\u0dcf\u0db4\u0db1\u0dba \u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Find": "\u0dc3\u0ddc\u0dba\u0db1\u0dca\u0db1",
+"Replace all": "\u0dc3\u0dd2\u0dba\u0dbd\u0dca\u0dbd\u0db8 \u0db4\u0dca\u200d\u0dbb\u0dad\u0dd2\u0dc3\u0dca\u0dae\u0dcf\u0db4\u0db1\u0dba \u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Match case": "\u0d9a\u0dcf\u0dbb\u0dab\u0dba \u0d9c\u0dbd\u0db4\u0db1\u0dca\u0db1",
+"Prev": "\u0db4\u0dd9\u0dbb",
+"Spellcheck": "\u0d85\u0d9a\u0dca\u0dc2\u0dbb \u0dc0\u0dd2\u0db1\u0dca\u200d\u0dba\u0dcf\u0dc3\u0dba \u0db4\u0dbb\u0dd3\u0d9a\u0dca\u0dc2\u0dcf \u0d9a\u0dbb \u0db6\u0dd0\u0dbd\u0dd3\u0db8",
+"Finish": "\u0d85\u0dc0\u0dc3\u0db1\u0dca",
+"Ignore all": "\u0dc3\u0dd2\u0dba\u0dbd\u0dca\u0dbd\u0db8 \u0db1\u0ddc\u0dc3\u0dbd\u0d9a\u0dcf \u0dc4\u0dbb\u0dd2\u0db1\u0dca\u0db1",
+"Ignore": "\u0db1\u0ddc\u0dc3\u0dbd\u0d9a\u0dcf \u0dc4\u0dd0\u0dbb\u0dd3\u0db8",
+"Insert row before": "\u0db8\u0dda \u0dad\u0dd0\u0db1\u0da7 \u0db4\u0dd9\u0dbb \u0db4\u0dda\u0dc5\u0dd2\u0dba\u0d9a\u0dca \u0d91\u0d9a\u0dca \u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Rows": "\u0db4\u0dda\u0dc5\u0dd2",
+"Height": "\u0d8b\u0dc3 ",
+"Paste row after": "\u0db8\u0dda \u0dad\u0dd0\u0db1\u0da7 \u0db4\u0dc3\u0dd4 \u0db4\u0dda\u0dc5\u0dd2\u0dba \u0d85\u0db8\u0dd4\u0dab\u0db1\u0dca\u0db1 ",
+"Alignment": "\u0db4\u0dd9\u0dc5 \u0d9c\u0dd0\u0dc3\u0dd4\u0db8",
+"Column group": "\u0dad\u0dd3\u0dbb\u0dd4 \u0d9a\u0dcf\u0dab\u0dca\u0da9\u0dba",
+"Row": "\u0db4\u0dda\u0dc5\u0dd2\u0dba ",
+"Insert column before": "\u0db8\u0dda \u0dad\u0dd0\u0db1\u0da7 \u0db4\u0dd9\u0dbb \u0dad\u0dd3\u0dbb\u0dd4\u0dc0 \u0d91\u0d9a\u0dca \u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Split cell": "\u0d9a\u0ddc\u0da7\u0dd4 \u0dc0\u0dd9\u0db1\u0dca\u0d9a\u0dbb\u0db1\u0dca\u0db1 ",
+"Cell padding": "\u0d9a\u0ddc\u0da7\u0dd4\u0dc0\u0dd9\u0dc4\u0dd2 \u0db4\u0dd2\u0dbb\u0dc0\u0dd4\u0db8",
+"Cell spacing": "\u0d9a\u0ddc\u0da7\u0dd4\u0dc0\u0dd9\u0dc4\u0dd2 \u0d89\u0da9 \u0dc3\u0dd3\u0db8\u0dcf\u0dc0 ",
+"Row type": "\u0db4\u0dda\u0dc5\u0dd2\u0dba\u0dd9\u0dc4\u0dd2 \u0dc0\u0dbb\u0dca\u0d9c\u0dba",
+"Insert table": "\u0dc0\u0d9c\u0dd4\u0dc0\u0da7 \u0d87\u0dad\u0dd4\u0dbd\u0dca \u0d9a\u0dbb\u0db1\u0dca\u0db1 ",
+"Body": "\u0db4\u0dca\u200d\u0dbb\u0db0\u0dcf\u0db1 \u0d9a\u0ddc\u0da7\u0dc3",
+"Caption": "\u0dba\u0da7\u0dd2 \u0dbd\u0dd2\u0dba\u0db8\u0db1 ",
+"Footer": "\u0db4\u0dcf\u0daf\u0d9a\u0dba",
+"Delete row": "\u0db4\u0dda\u0dc5\u0dd2\u0dba \u0db8\u0d9a\u0db1\u0dca\u0db1 ",
+"Paste row before": "\u0db8\u0dda \u0dad\u0dd0\u0db1\u0da7 \u0db4\u0dd9\u0dbb \u0db4\u0dda\u0dc5\u0dd2\u0dba \u0d85\u0db8\u0dd4\u0dab\u0db1\u0dca\u0db1 ",
+"Scope": "\u0dc0\u0dd2\u0dc2\u0dba\u0db4\u0dae\u0dba",
+"Delete table": "\u0dc0\u0d9c\u0dd4\u0dc0 \u0db8\u0d9a\u0db1\u0dca\u0db1 ",
+"Header cell": "\u0dc1\u0dd3\u0dbb\u0dca\u0dc2 \u0d9a\u0ddc\u0da7\u0dd4\u0dc0",
+"Column": "\u0dad\u0dd3\u0dbb\u0dd4\u0dc0",
+"Cell": "\u0d9a\u0ddc\u0da7\u0dd4\u0dc0 ",
+"Header": "\u0dc1\u0dd3\u0dbb\u0dca\u0dc2\u0d9a\u0dba",
+"Cell type": "\u0d9a\u0ddc\u0da7\u0dd4\u0dc0\u0dd9\u0dc4\u0dd2 \u0dc0\u0dbb\u0dca\u0d9c\u0dba",
+"Copy row": "\u0db4\u0dda\u0dc5\u0dd2\u0dba \u0db4\u0dd2\u0da7\u0db4\u0dad\u0dca \u0d9a\u0dbb\u0d9c\u0db1\u0dca\u0db1 ",
+"Row properties": "\u0db4\u0dda\u0dc5\u0dd2\u0dba\u0dd9\u0dc4\u0dd2 \u0d9c\u0dd4\u0dab\u0dcf\u0d82\u0d9c ",
+"Table properties": "\u0dc0\u0d9c\u0dd4\u0dc0\u0dd9\u0dc4\u0dd2 \u0d9c\u0dd4\u0dab\u0dcf\u0d82\u0d9c ",
+"Row group": "\u0db4\u0dda\u0dc5\u0dd2 \u0d9a\u0dcf\u0dab\u0dca\u0da9\u0dba",
+"Right": "\u0daf\u0d9a\u0dd4\u0dab",
+"Insert column after": "\u0db8\u0dda \u0dad\u0dd0\u0db1\u0da7 \u0db4\u0dc3\u0dd4 \u0dad\u0dd3\u0dbb\u0dd4\u0dc0 \u0d91\u0d9a\u0dca \u0d9a\u0dbb\u0db1\u0dca\u0db1 ",
+"Cols": "\u0dad\u0dd3\u0dbb\u0dd4 ",
+"Insert row after": "\u0db8\u0dda \u0dad\u0dd0\u0db1\u0da7 \u0db4\u0dc3\u0dd4 \u0db4\u0dda\u0dc5\u0dd2\u0dba\u0d9a\u0dca \u0d91\u0d9a\u0dca \u0d9a\u0dbb\u0db1\u0dca\u0db1 ",
+"Width": "\u0db4\u0dc5\u0dbd",
+"Cell properties": "\u0d9a\u0ddc\u0da7\u0dd4\u0dc0\u0dd9\u0dc4\u0dd2 \u0d9c\u0dd4\u0dab\u0dcf\u0d82\u0d9c ",
+"Left": "\u0dc0\u0db8",
+"Cut row": "\u0db4\u0dda\u0dc5\u0dd2\u0dba \u0d9a\u0db4\u0dcf\u0d9c\u0db1\u0dca\u0db1 ",
+"Delete column": "\u0dad\u0dd3\u0dbb\u0dd4\u0dc0 \u0db8\u0d9a\u0db1\u0dca\u0db1 ",
+"Center": "\u0db8\u0dd0\u0daf",
+"Merge cells": "\u0d9a\u0ddc\u0da7\u0dd4 \u0d91\u0d9a\u0dca \u0d9a\u0dbb\u0db1\u0dca\u0db1 ",
+"Insert template": "\u0d85\u0da0\u0dca\u0da0\u0dd4\u0dc0 \u0d87\u0dad\u0dd4\u0dbd\u0dca \u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"Templates": "\u0d85\u0da0\u0dca\u0da0\u0dd4",
+"Background color": "\u0db4\u0dc3\u0dd4\u0db6\u0dd2\u0db8\u0dd9\u0dc4\u0dd2 \u0dc0\u0dbb\u0dca\u0dab\u0dba",
+"Text color": "\u0db4\u0dd9\u0dc5 \u0dc3\u0da7\u0dc4\u0db1\u0dda \u0dc0\u0dbb\u0dca\u0dab\u0dba",
+"Show blocks": "\u0d9a\u0ddc\u0da7\u0dc3\u0dca \u0db4\u0dd9\u0db1\u0dca\u0dc0\u0db1\u0dca\u0db1",
+"Show invisible characters": "\u0db1\u0ddc\u0db4\u0dd9\u0db1\u0dd9\u0db1 \u0d85\u0db1\u0dd4\u0dbd\u0d9a\u0dd4\u0dab\u0dd4 \u0db4\u0dd9\u0db1\u0dca\u0dc0\u0db1\u0dca\u0db1",
+"Words: {0}": "\u0dc0\u0da0\u0db1: {0}",
+"Insert": "\u0d91\u0d9a\u0dca \u0d9a\u0dbb\u0db1\u0dca\u0db1",
+"File": "\u0d9c\u0ddc\u0db1\u0dd4\u0dc0",
+"Edit": "\u0dc3\u0d9a\u0dc3\u0db1\u0dca\u0db1",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u0db4\u0dd9\u0dc5 \u0dc3\u0da7\u0dc4\u0db1\u0dca \u0db6\u0dc4\u0dd4\u0dbd \u0db4\u0dca\u200d\u0dbb\u0daf\u0dda\u0dc1\u0dba. \u0db8\u0dd9\u0db1\u0dd4\u0dc0 \u0dc3\u0db3\u0dc4\u0dcf ALT-F9 \u0d94\u0db6\u0db1\u0dca\u0db1. \u0db8\u0dd9\u0dc0\u0dbd\u0db8\u0dca \u0dad\u0dd3\u0dbb\u0dd4\u0dc0 \u0dc3\u0db3\u0dc4\u0dcf ALT-F10 \u0d94\u0db6\u0db1\u0dca\u0db1. \u0dc3\u0dc4\u0dba \u0dbd\u0db6\u0dcf\u0d9c\u0dd0\u0db1\u0dd3\u0db8 \u0dc3\u0db3\u0dc4\u0dcf ALT-0 \u0d94\u0db6\u0db1\u0dca\u0db1.",
+"Tools": "\u0db8\u0dd9\u0dc0\u0dbd\u0db8\u0dca",
+"View": "\u0db4\u0dd9\u0db1\u0dca\u0dc0\u0db1\u0dca\u0db1",
+"Table": "\u0dc0\u0d9c\u0dd4\u0dc0",
+"Format": "\u0dc4\u0dd0\u0da9\u0dad\u0dbd\u0dba"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sk.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sk.js
new file mode 100755
index 0000000..b07a1c0
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sk.js
@@ -0,0 +1,174 @@
+tinymce.addI18n('sk',{
+"Cut": "Vystrihn\u00fa\u0165",
+"Header 2": "Nadpis 2. \u00farovne",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "V\u00e1\u0161 prehliada\u010d nepodporuje priamy pr\u00edstup do schr\u00e1nky. Pou\u017eite kl\u00e1vesov\u00e9 skratky Ctrl+X\/C\/V.",
+"Div": "Blok",
+"Paste": "Vlo\u017ei\u0165",
+"Close": "Zatvori\u0165",
+"Pre": "Preform\u00e1tovan\u00fd",
+"Align right": "Zarovna\u0165 vpravo",
+"New document": "Nov\u00fd dokument",
+"Blockquote": "Cit\u00e1cia",
+"Numbered list": "\u010c\u00edslovan\u00fd zoznam",
+"Increase indent": "Zv\u00e4\u010d\u0161i\u0165 odsadenie",
+"Formats": "Form\u00e1ty",
+"Headers": "Nadpisy",
+"Select all": "Ozna\u010di\u0165 v\u0161etko",
+"Header 3": "Nadpis 3. \u00farovne",
+"Blocks": "Bloky",
+"Undo": "Vr\u00e1ti\u0165",
+"Strikethrough": "Pre\u010diarknut\u00e9",
+"Bullet list": "Odr\u00e1\u017eky",
+"Header 1": "Nadpis 1. \u00farovne",
+"Superscript": "Horn\u00fd index",
+"Clear formatting": "Vymaza\u0165 form\u00e1tovanie",
+"Subscript": "Spodn\u00fd index",
+"Header 6": "Nadpis 6. \u00farovne",
+"Redo": "Znova",
+"Paragraph": "Odsek",
+"Ok": "Ok",
+"Bold": "Tu\u010dn\u00e9",
+"Code": "K\u00f3d",
+"Italic": "Kurz\u00edva",
+"Align center": "Zarovna\u0165 na stred",
+"Header 5": "Nadpis 5. \u00farovne",
+"Decrease indent": "Zmen\u0161i\u0165 odsadenie",
+"Header 4": "Nadpis 4. \u00farovne",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Vkladanie je v m\u00f3de neform\u00e1tovan\u00e9ho textu. Vkladan\u00fd obsah bude vlo\u017een\u00fd ako neform\u00e1tovan\u00fd, a\u017e pok\u00fdm t\u00fato mo\u017enos\u0165 nevypnete.",
+"Underline": "Pod\u010diarknut\u00e9",
+"Cancel": "Zru\u0161i\u0165",
+"Justify": "Zarovna\u0165",
+"Inline": "Do riadku",
+"Copy": "Kop\u00edrova\u0165",
+"Align left": "Zarovna\u0165 v\u013eavo",
+"Visual aids": "Vizu\u00e1lne pom\u00f4cky",
+"Lower Greek": "Mal\u00e9 gr\u00e9cke p\u00edsmen\u00e1",
+"Square": "\u0160tvorec",
+"Default": "V\u00fdchodzie",
+"Lower Alpha": "Mal\u00e9 p\u00edsmen\u00e1",
+"Circle": "Kruh",
+"Disc": "Disk",
+"Upper Alpha": "Ve\u013ek\u00e9 p\u00edsmen\u00e1",
+"Upper Roman": "Ve\u013ek\u00e9 r\u00edmske \u010d\u00edslice",
+"Lower Roman": "Mal\u00e9 r\u00edmske \u010d\u00edslice",
+"Name": "N\u00e1zov",
+"Anchor": "Odkaz",
+"You have unsaved changes are you sure you want to navigate away?": "M\u00e1te neulo\u017een\u00e9 zmeny, naozaj chcete opusti\u0165 str\u00e1nku?",
+"Restore last draft": "Obnovi\u0165 posledn\u00fd koncept",
+"Special character": "\u0160peci\u00e1lny znak",
+"Source code": "Zdrojov\u00fd k\u00f3d",
+"Right to left": "Sprava do\u013eava",
+"Left to right": "Z\u013eava doprava",
+"Emoticons": "Smajl\u00edci",
+"Robots": "Preh\u013ead\u00e1vacie roboty",
+"Document properties": "Vlastnosti dokumentu",
+"Title": "Nadpis",
+"Keywords": "K\u013e\u00fa\u010dov\u00e9 slov\u00e1",
+"Encoding": "K\u00f3dovanie",
+"Description": "Popis",
+"Author": "Autor",
+"Fullscreen": "Na cel\u00fa obrazovku",
+"Horizontal line": "Horizont\u00e1lna \u010diara",
+"Horizontal space": "Horizont\u00e1lny priestor",
+"Insert\/edit image": "Vlo\u017ei\u0165\/upravi\u0165 obr\u00e1zok",
+"General": "Hlavn\u00e9",
+"Advanced": "Pokro\u010dil\u00e9",
+"Source": "Zdroj",
+"Border": "Or\u00e1movanie",
+"Constrain proportions": "Vymedzen\u00e9 proporcie",
+"Vertical space": "Vertik\u00e1lny priestor",
+"Image description": "Popis obr\u00e1zku",
+"Style": "\u0160t\u00fdl",
+"Dimensions": "Rozmery",
+"Insert image": "Vlo\u017ei\u0165 obr\u00e1zok",
+"Insert date\/time": "Vlo\u017ei\u0165 d\u00e1tum\/\u010das",
+"Remove link": "Odstr\u00e1ni\u0165 odkaz",
+"Url": "Url",
+"Text to display": "Zobrazen\u00fd text",
+"Anchors": "Kotvy",
+"Insert link": "Vlo\u017ei\u0165 odkaz",
+"New window": "Nov\u00e9 okno",
+"None": "\u017diadne",
+"Target": "Cie\u013e",
+"Insert\/edit link": "Vlo\u017ei\u0165\/upravi\u0165 odkaz",
+"Insert\/edit video": "Vlo\u017ei\u0165\/upravi\u0165 video",
+"Poster": "Uk\u00e1\u017eka",
+"Alternative source": "Alternat\u00edvny zdroj",
+"Paste your embed code below:": "Vlo\u017ete k\u00f3d pre vlo\u017eenie na str\u00e1nku:",
+"Insert video": "Vlo\u017ei\u0165 video",
+"Embed": "Vlo\u017een\u00e9",
+"Nonbreaking space": "Nedelite\u013en\u00e1 medzera",
+"Page break": "Zalomenie str\u00e1nky",
+"Preview": "N\u00e1h\u013ead",
+"Print": "Tla\u010di\u0165",
+"Save": "Ulo\u017ei\u0165",
+"Could not find the specified string.": "Zadan\u00fd re\u0165azec sa nena\u0161iel.",
+"Replace": "Nahradi\u0165",
+"Next": "Nasleduj\u00face",
+"Whole words": "Cel\u00e9 slov\u00e1",
+"Find and replace": "Vyh\u013eada\u0165 a nahradi\u0165",
+"Replace with": "Nahradi\u0165 za",
+"Find": "H\u013eada\u0165",
+"Replace all": "Nahradi\u0165 v\u0161etko",
+"Match case": "Rozli\u0161ova\u0165 ve\u013ek\u00e9\/mal\u00e9",
+"Prev": "Predch\u00e1dzaj\u00face",
+"Spellcheck": "Kontrola pravopisu",
+"Finish": "Dokon\u010di\u0165",
+"Ignore all": "Ignorova\u0165 v\u0161etko",
+"Ignore": "Ignorova\u0165",
+"Insert row before": "Vlo\u017ei\u0165 nov\u00fd riadok pred",
+"Rows": "Riadky",
+"Height": "V\u00fd\u0161ka",
+"Paste row after": "Vlo\u017ei\u0165 riadok za",
+"Alignment": "Zarovnanie",
+"Column group": "Skupina st\u013apcov",
+"Row": "Riadok",
+"Insert column before": "Prida\u0165 nov\u00fd st\u013apec pred",
+"Split cell": "Rozdeli\u0165 bunku",
+"Cell padding": "Odsadenie v bunk\u00e1ch",
+"Cell spacing": "Priestor medzi bunkami",
+"Row type": "Typ riadku",
+"Insert table": "Vlo\u017ei\u0165 tabu\u013eku",
+"Body": "Telo",
+"Caption": "Popisok",
+"Footer": "P\u00e4ti\u010dka",
+"Delete row": "Zmaza\u0165 riadok",
+"Paste row before": "Vlo\u017ei\u0165 riadok pred",
+"Scope": "Oblas\u0165",
+"Delete table": "Zmaza\u0165 tabu\u013eku",
+"Header cell": "Bunka hlavi\u010dky",
+"Column": "St\u013apec",
+"Cell": "Bunka",
+"Header": "Z\u00e1hlavie",
+"Cell type": "Typ bunky",
+"Copy row": "Kop\u00edrova\u0165 riadok",
+"Row properties": "Vlastnosti riadku",
+"Table properties": "Nastavenia tabu\u013eky",
+"Row group": "Skupina riadkov",
+"Right": "Vpravo",
+"Insert column after": "Prida\u0165 nov\u00fd st\u013apec za",
+"Cols": "St\u013apce",
+"Insert row after": "Vlo\u017ei\u0165 nov\u00fd riadok za",
+"Width": "\u0160\u00edrka",
+"Cell properties": "Vlastnosti bunky",
+"Left": "V\u013eavo",
+"Cut row": "Vystrihn\u00fa\u0165 riadok",
+"Delete column": "Vymaza\u0165 st\u013apec",
+"Center": "Na stred",
+"Merge cells": "Spoji\u0165 bunky",
+"Insert template": "Vlo\u017ei\u0165 \u0161abl\u00f3nu",
+"Templates": "\u0160abl\u00f3ny",
+"Background color": "Farba pozadia",
+"Text color": "Farba textu",
+"Show blocks": "Zobrazi\u0165 bloky",
+"Show invisible characters": "Zobrazi\u0165 skryt\u00e9 znaky",
+"Words: {0}": "Slov: {0}",
+"Insert": "Vlo\u017ei\u0165",
+"File": "S\u00fabor",
+"Edit": "Upravi\u0165",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Textov\u00e9 pole. Stla\u010dte ALT-F9 pre zobrazenie menu, ALT-F10 pre zobrazenie panela n\u00e1strojov, ALT-0 pre n\u00e1povedu.",
+"Tools": "N\u00e1stroje",
+"View": "Zobrazi\u0165",
+"Table": "Tabu\u013eka",
+"Format": "Form\u00e1t"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sl_SI.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sl_SI.js
new file mode 100755
index 0000000..1ded0d0
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sl_SI.js
@@ -0,0 +1,152 @@
+tinymce.addI18n('sl_SI',{
+"Cut": "Izre\u017ei",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Varnostne nastavitve brskalnika ne dopu\u0161\u010dajo direktnega dostopa do odlo\u017ei\u0161\u010da. Uporabite kombinacijo tipk Ctrl+X\/C\/V na tipkovnici.",
+"Paste": "Prilepi",
+"Close": "Zapri",
+"Align right": "Desna poravnava",
+"New document": "Nov dokument",
+"Numbered list": "O\u0161tevil\u010den seznam",
+"Increase indent": "Pove\u010daj zamik",
+"Formats": "Oblika",
+"Select all": "Izberi vse",
+"Undo": "Razveljavi",
+"Strikethrough": "Pre\u010drtano",
+"Bullet list": "Ozna\u010den seznam",
+"Superscript": "Nadpisano",
+"Clear formatting": "Odstrani oblikovanje",
+"Subscript": "Podpisano",
+"Redo": "Ponovi",
+"Ok": "V redu",
+"Bold": "Krepko",
+"Italic": "Le\u017ee\u010de",
+"Align center": "Sredinska poravnava",
+"Decrease indent": "Zmanj\u0161aj zamik",
+"Underline": "Pod\u010drtano",
+"Cancel": "Prekli\u010di",
+"Justify": "Obojestranska poravnava",
+"Copy": "Kopiraj",
+"Align left": "Leva poravnava",
+"Visual aids": "Vizualni pripomo\u010dki",
+"Lower Greek": "Male gr\u0161ke \u010drke",
+"Square": "Kvadratek",
+"Default": "Privzeto",
+"Lower Alpha": "Male tiskane \u010drke",
+"Circle": "Pikica",
+"Disc": "Kroglica",
+"Upper Alpha": "Velike tiskane \u010drke",
+"Upper Roman": "Velike rimske \u0161tevilke",
+"Lower Roman": "Male rimske \u0161tevilke",
+"Name": "Naziv zaznamka",
+"Anchor": "Zaznamek",
+"You have unsaved changes are you sure you want to navigate away?": "Imate neshranjene spremembe. Ste prepri\u010dati, da \u017eelite zapustiti stran?",
+"Restore last draft": "Obnovi zadnji osnutek",
+"Special character": "Posebni znaki",
+"Source code": "Izvorna koda",
+"Right to left": "Od desne proti levi",
+"Left to right": "Od leve proti desni",
+"Emoticons": "Sme\u0161ki",
+"Robots": "Robotki",
+"Document properties": "Lastnosti dokumenta",
+"Title": "Naslov",
+"Keywords": "Klju\u010dne besede",
+"Encoding": "Kodiranje",
+"Description": "Opis",
+"Author": "Avtor",
+"Fullscreen": "\u010cez cel zaslon",
+"Horizontal line": "Vodoravna \u010drta",
+"Source": "Pot",
+"Constrain proportions": "Obdr\u017ei razmerje",
+"Dimensions": "Dimenzije",
+"Insert\/edit image": "Vstavi\/uredi sliko",
+"Image description": "Opis slike",
+"Insert date\/time": "Vstavi datum\/\u010das",
+"Url": "Povezava",
+"Text to display": "Prikazno besedilo",
+"Insert link": "Vstavi povezavo",
+"New window": "Novo okno",
+"None": "Brez",
+"Target": "Cilj",
+"Insert\/edit link": "Vstavi\/uredi povezavo",
+"Insert\/edit video": "Vstavi\/uredi video",
+"General": "Splo\u0161no",
+"Poster": "Poster",
+"Alternative source": "Alternativni vir",
+"Paste your embed code below:": "Vstavite kodo predvajalnika z videom:",
+"Insert video": "Vstavi video",
+"Embed": "Vdelaj",
+"Nonbreaking space": "Nedeljivi presledek",
+"Page break": "Prelom strani",
+"Preview": "Predogled",
+"Print": "Natisni",
+"Save": "Shrani",
+"Could not find the specified string.": "Iskanje ni vrnilo rezultatov.",
+"Replace": "Zamenjaj",
+"Next": "Naprej",
+"Whole words": "Cele besede",
+"Find and replace": "Poi\u0161\u010di in zamenjaj",
+"Replace with": "Zamenjaj z",
+"Find": "I\u0161\u010di",
+"Replace all": "Zamenjaj vse",
+"Match case": "Ujemanje malih in velikih \u010drk",
+"Prev": "Nazaj",
+"Spellcheck": "Preverjanje \u010drkovanja",
+"Finish": "Zaklju\u010di",
+"Ignore all": "Prezri vse",
+"Ignore": "Prezri",
+"Insert row before": "Vstavi vrstico pred",
+"Rows": "Vrstice",
+"Height": "Vi\u0161ina",
+"Paste row after": "Prilepi vrstico za",
+"Alignment": "Poravnava",
+"Column group": "Grupiranje stolpcev",
+"Row": "Vrstica",
+"Insert column before": "Vstavi stolpec pred",
+"Split cell": "Razdeli celico",
+"Cell padding": "Polnilo med celicami",
+"Cell spacing": "Razmik med celicami",
+"Row type": "Tip vrstice",
+"Insert table": "Vstavi tabelo",
+"Body": "Vsebina",
+"Caption": "Naslov",
+"Footer": "Noga",
+"Delete row": "Izbri\u0161i vrstico",
+"Paste row before": "Prilepi vrstico pred",
+"Scope": "Obseg",
+"Delete table": "Izbri\u0161i tabelo",
+"Header cell": "Celica glave",
+"Column": "Stolpec",
+"Cell": "Celica",
+"Header": "Glava",
+"Border": "Obroba",
+"Cell type": "Tip celice",
+"Copy row": "Kopiraj vrstico",
+"Row properties": "Lastnosti vrstice",
+"Table properties": "Lastnosti tabele",
+"Row group": "Grupiranje vrstic",
+"Right": "Desno",
+"Insert column after": "Vstavi stolpec za",
+"Cols": "Stolpci",
+"Insert row after": "Vstavi vrstico za",
+"Width": "\u0160irina",
+"Cell properties": "Lastnosti celice",
+"Left": "Levo",
+"Cut row": "Izre\u017ei vrstico",
+"Delete column": "Izbri\u0161i stolpec",
+"Center": "Sredinsko",
+"Merge cells": "Zdru\u017ei celice",
+"Insert template": "Vstavi predlogo",
+"Templates": "Predloge",
+"Background color": "Barva ozadja",
+"Text color": "Barva besedila",
+"Show blocks": "Prika\u017ei bloke",
+"Show invisible characters": "Prika\u017ei skrite znake",
+"Words: {0}": "Besed: {0}",
+"Insert": "Vstavi",
+"File": "Datoteka",
+"Edit": "Uredi",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Bogato besedilo. Pritisnite ALT-F9 za meni. Pritisnite ALT-F10 za orodno vrstico. Pritisnite ALT-0 za pomo\u010d",
+"Tools": "Orodja",
+"View": "Pogled",
+"Table": "Tabela",
+"Format": "Oblika"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sr.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sr.js
new file mode 100755
index 0000000..93fe66e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sr.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('sr',{
+"Cut": "Ise\u0107i",
+"Header 2": "Zaglavlje 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Va\u0161 pretra\u017eiva\u010d nepodr\u017eava direktan pristup prenosu.Koristite Ctrl+X\/C\/V pre\u010dice na tastaturi",
+"Div": "Div",
+"Paste": "Nalepiti",
+"Close": "Zatvori",
+"Pre": "pre",
+"Align right": "Poravnano desno",
+"New document": "Novi dokument",
+"Blockquote": "navodnici",
+"Numbered list": "Numerisana lista",
+"Increase indent": "Pove\u0107aj uvla\u010denje",
+"Formats": "Forrmatiraj",
+"Headers": "Zaglavlje",
+"Select all": "Obele\u017ei sve",
+"Header 3": "Zaglavlje 3",
+"Blocks": "blokovi",
+"Undo": "Korak unazad",
+"Strikethrough": "Precrtan",
+"Bullet list": "Lista nabrajanja",
+"Header 1": "Zaglavlje 1",
+"Superscript": "Natpis",
+"Clear formatting": "Brisanje formatiranja",
+"Subscript": "Potpisan",
+"Header 6": "Zaglavlje 6",
+"Redo": "Korak napred",
+"Paragraph": "Paragraf",
+"Ok": "Ok",
+"Bold": "Podebljan",
+"Code": "kod",
+"Italic": "isko\u0161en",
+"Align center": "Poravnano centar",
+"Header 5": "Zaglavlje 5",
+"Decrease indent": "Smanji uvla\u010denje",
+"Header 4": "Zaglavlje 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Nalepiti je sada u obi\u010dnom text modu.Sadr\u017eaj \u0107e biti nalepljen kao obi\u010dan tekst dok ne ugasite ovu opciju.",
+"Underline": "Podvu\u010den",
+"Cancel": "Opozovi",
+"Justify": "Poravnanje",
+"Inline": "u liniji",
+"Copy": "kopirati",
+"Align left": "Poravnano levo",
+"Visual aids": "Vizuelna pomagala",
+"Lower Greek": "Ni\u017ei gr\u010dki",
+"Square": "Kvadrat",
+"Default": "Podrazumevano",
+"Lower Alpha": "Donja Alpha",
+"Circle": "Krug",
+"Disc": "Disk",
+"Upper Alpha": "Gornji Alpha",
+"Upper Roman": "Gornji Roman",
+"Lower Roman": "Donji Roman",
+"Name": "Ime",
+"Anchor": "Sidro",
+"You have unsaved changes are you sure you want to navigate away?": "Imate nesa\u010duvane promene dali ste sigurni da \u017eelite da iza\u0111ete?",
+"Restore last draft": "Vrati poslednji nacrt",
+"Special character": "Specijalni karakter",
+"Source code": "Izvorni kod",
+"Right to left": "Sa desne na levu",
+"Left to right": "Sa leve na desnu",
+"Emoticons": "Smajliji",
+"Robots": "Roboti",
+"Document properties": "Postavke dokumenta",
+"Title": "Naslov",
+"Keywords": "Klju\u010dne re\u010di",
+"Encoding": "Kodiranje",
+"Description": "Opis",
+"Author": "Autor",
+"Fullscreen": "Pun ekran",
+"Horizontal line": "Horizontalna linija",
+"Horizontal space": "Horizontalni razmak",
+"Insert\/edit image": "Ubaci\/Promeni sliku",
+"General": "Op\u0161te",
+"Advanced": "Napredno",
+"Source": "Izvor",
+"Border": "Okvir",
+"Constrain proportions": "Ograni\u010dene proporcije",
+"Vertical space": "Vertikalni razmak",
+"Image description": "Opis slike",
+"Style": "Stil",
+"Dimensions": "Dimenzije",
+"Insert image": "Ubaci sliku",
+"Insert date\/time": "Ubaci datum\/vreme",
+"Remove link": "Ukloni link",
+"Url": "Url",
+"Text to display": "Tekst za prikaz",
+"Anchors": "sidro",
+"Insert link": "Ubaci vezu",
+"New window": "Novi prozor",
+"None": "Ni\u0161ta",
+"Target": "Meta",
+"Insert\/edit link": "Ubaci\/promeni vezu",
+"Insert\/edit video": "Ubaci\/promeni video",
+"Poster": "Poster",
+"Alternative source": "Alternativni izvor",
+"Paste your embed code below:": "Nalepite ugra\u0111eni kod ispod:",
+"Insert video": "Ubaci video",
+"Embed": "Ugra\u0111eno",
+"Nonbreaking space": "bez ramaka",
+"Page break": "Lomljenje stranice",
+"Paste as text": "Nalepi kao tekst",
+"Preview": "Pregled",
+"Print": "\u0160tampanje",
+"Save": "Sa\u010duvati",
+"Could not find the specified string.": "Nije mogu\u0107e prona\u0107i navedeni niz.",
+"Replace": "Zameni",
+"Next": "Slede\u0107i",
+"Whole words": "Cele re\u010di",
+"Find and replace": "Na\u0111i i zameni",
+"Replace with": "Zameni sa",
+"Find": "Na\u0111i",
+"Replace all": "Zameni sve",
+"Match case": "Predmet za upore\u0111ivanje",
+"Prev": "Prethodni",
+"Spellcheck": "Provera pravopisa",
+"Finish": "Kraj",
+"Ignore all": "Ignori\u0161i sve",
+"Ignore": "ignori\u0161i",
+"Insert row before": "Ubaci red pre",
+"Rows": "Redovi",
+"Height": "Visina",
+"Paste row after": "Nalepi red posle",
+"Alignment": "Svrstavanje",
+"Column group": "Grupa kolone",
+"Row": "Red",
+"Insert column before": "Ubaci kolonu pre",
+"Split cell": "Razdvoji \u0107elije",
+"Cell padding": "Razmak \u0107elije",
+"Cell spacing": "Prostor \u0107elije",
+"Row type": "Tip reda",
+"Insert table": "ubaci tabelu",
+"Body": "Telo",
+"Caption": "Natpis",
+"Footer": "Podno\u017eje",
+"Delete row": "Obri\u0161i red",
+"Paste row before": "Nalepi red pre",
+"Scope": "Obim",
+"Delete table": "Obri\u0161i tabelu",
+"Header cell": "Visina \u0107elije",
+"Column": "Kolona",
+"Cell": "\u0106elija",
+"Header": "Zaglavlje",
+"Cell type": "Tip \u0107elije",
+"Copy row": "Kopiraj red",
+"Row properties": "Postavke reda",
+"Table properties": "Postavke tabele",
+"Row group": "Grupa reda",
+"Right": "Desno",
+"Insert column after": "Ubaci kolonu posle",
+"Cols": "Kolone",
+"Insert row after": "Ubaci red posle",
+"Width": "\u0160irina",
+"Cell properties": "Postavke \u0107elije",
+"Left": "Levo",
+"Cut row": "Iseci red",
+"Delete column": "Obri\u0161i kolonu",
+"Center": "Centar",
+"Merge cells": "Spoji \u0107elije",
+"Insert template": "Ubaci \u0161ablon",
+"Templates": "\u0160abloni",
+"Background color": "Boja pozadine",
+"Text color": "Boja tekst",
+"Show blocks": "Prikaz blokova",
+"Show invisible characters": "Prika\u017ei nevidljive karaktere",
+"Words: {0}": "Re\u010di:{0}",
+"Insert": "Umetni",
+"File": "Datoteka",
+"Edit": "Ure\u0111ivanje",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Oboga\u0107en tekst. Pritisni te ALT-F9 za meni.Pritisnite ALT-F10 za traku sa alatkama.Pritisnite ALT-0 za pomo\u0107",
+"Tools": "Alatke",
+"View": "Prikaz",
+"Table": "Tabela",
+"Format": "Format"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sv_SE.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sv_SE.js
new file mode 100755
index 0000000..5bc6756
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/sv_SE.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('sv_SE',{
+"Cut": "Klipp ut",
+"Header 2": "Rubrik 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Din browser st\u00f6der inte direkt acess till klippboken. V\u00e4nligen anv\u00e4nd Ctrl+X\/C\/V kortkomandon i st\u00e4llet.",
+"Div": "Div",
+"Paste": "Klistra in",
+"Close": "St\u00e4ng",
+"Pre": "Pre",
+"Align right": "H\u00f6gerst\u00e4ll",
+"New document": "Nytt dokument",
+"Blockquote": "Blockcitat",
+"Numbered list": "Nummerlista",
+"Increase indent": "\u00d6ka indrag",
+"Formats": "Format",
+"Headers": "Rubriker",
+"Select all": "Markera allt",
+"Header 3": "Rubrik 3",
+"Blocks": "Block",
+"Undo": "\u00c5ngra",
+"Strikethrough": "Genomstruken",
+"Bullet list": "Punktlista",
+"Header 1": "Rubrik 1",
+"Superscript": "Upph\u00f6jd text",
+"Clear formatting": "Avformattera",
+"Subscript": "Neds\u00e4nkt text",
+"Header 6": "Rubrik 6",
+"Redo": "G\u00f6r om",
+"Paragraph": "Paragraf",
+"Ok": "Ok",
+"Bold": "Fetstil",
+"Code": "K\u00e5d",
+"Italic": "Kurisvstil",
+"Align center": "Centrera",
+"Header 5": "Rubrik 5",
+"Decrease indent": "Minska indrag",
+"Header 4": "Rubrik 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Klistra in \u00e4r nu i textl\u00e4ge. Inneh\u00e5ll kommer att konverteras till text tills du sl\u00e5r av detta l\u00e4ge.",
+"Underline": "Understruken",
+"Cancel": "Avbryt",
+"Justify": "Justera",
+"Inline": "Inline",
+"Copy": "Kopiera",
+"Align left": "V\u00e4nsterst\u00e4ll",
+"Visual aids": "Visuella hj\u00e4lpmedel",
+"Lower Greek": "Grekiska gemener",
+"Square": "Fyrkant",
+"Default": "Orginal",
+"Lower Alpha": "Gemener",
+"Circle": "Cirkel",
+"Disc": "Disk",
+"Upper Alpha": "Varsaler",
+"Upper Roman": "Romerskaversaler",
+"Lower Roman": "Romerskagemener",
+"Name": "Namn",
+"Anchor": "Ankare",
+"You have unsaved changes are you sure you want to navigate away?": "Du har f\u00f6r\u00e4ndringar som du inte har sparat. \u00c4r du s\u00e4ker p\u00e5 att du vill navigera vidare?",
+"Restore last draft": "\u00c5terst\u00e4ll senaste utkast",
+"Special character": "Specialtecken",
+"Source code": "K\u00e4llkod",
+"Right to left": "H\u00f6ger till v\u00e4nster",
+"Left to right": "V\u00e4nster till h\u00f6ger",
+"Emoticons": "Emoticons",
+"Robots": "Robotar",
+"Document properties": "Dokumentegenskaper",
+"Title": "Titel",
+"Keywords": "Nyckelord",
+"Encoding": "Encoding",
+"Description": "Beskrivning",
+"Author": "F\u00f6rfattare",
+"Fullscreen": "Fullsk\u00e4rm",
+"Horizontal line": "Horizontell linie",
+"Horizontal space": "Horizontelltutrymme",
+"Insert\/edit image": "Infoga\/redigera bild",
+"General": "Generella",
+"Advanced": "Avancerat",
+"Source": "K\u00e4lla",
+"Border": "Ram",
+"Constrain proportions": "Begr\u00e4nsa proportioner",
+"Vertical space": "Vertikaltutrymme",
+"Image description": "Bildbeskrivning",
+"Style": "Stil",
+"Dimensions": "Dimensioner",
+"Insert image": "Infoga bild",
+"Insert date\/time": "Infoga datum\/tid",
+"Remove link": "Tabort l\u00e4nk",
+"Url": "Url",
+"Text to display": "Text att visa",
+"Anchors": "Bokm\u00e4rken",
+"Insert link": "Infoga l\u00e4nk",
+"New window": "Nytt f\u00f6nster",
+"None": "Ingen",
+"Target": "M\u00e5l",
+"Insert\/edit link": "Infoga\/redigera l\u00e4nk",
+"Insert\/edit video": "Infoga\/redigera video",
+"Poster": "Affish",
+"Alternative source": "Alternativ k\u00e4lla",
+"Paste your embed code below:": "Klistra in din inb\u00e4ddningsk\u00e5d nedan:",
+"Insert video": "Infoga video",
+"Embed": "Inb\u00e4ddning",
+"Nonbreaking space": "Avbrottsfritt mellanrum",
+"Page break": "Sydbrytning",
+"Paste as text": "Klistra in som text",
+"Preview": "F\u00f6rhandsgranska",
+"Print": "Skriv ut",
+"Save": "Spara",
+"Could not find the specified string.": "Kunde inte hitta den specifierade st\u00e4ngen.",
+"Replace": "Ers\u00e4tt",
+"Next": "N\u00e4sta",
+"Whole words": "Hela ord",
+"Find and replace": "S\u00f6k och ers\u00e4tt",
+"Replace with": "Ers\u00e4tt med",
+"Find": "S\u00f6k",
+"Replace all": "Ers\u00e4tt alla",
+"Match case": "Matcha gemener\/versaler",
+"Prev": "F\u00f6reg\u00e5ende",
+"Spellcheck": "R\u00e4ttstava",
+"Finish": "Avsluta",
+"Ignore all": "Ignorera alla",
+"Ignore": "Ignorera",
+"Insert row before": "Infoga rad f\u00f6re",
+"Rows": "Rader",
+"Height": "H\u00f6jd",
+"Paste row after": "Klistra in rad efter",
+"Alignment": "Justering",
+"Column group": "Kolumngrupp",
+"Row": "Rad",
+"Insert column before": "Infoga kollumn f\u00f6re",
+"Split cell": "Bryt is\u00e4r celler",
+"Cell padding": "Cellpaddning",
+"Cell spacing": "Cellmellanrum",
+"Row type": "Radtyp",
+"Insert table": "Infoga tabell",
+"Body": "Kropp",
+"Caption": "Rubrik",
+"Footer": "Fot",
+"Delete row": "Radera rad",
+"Paste row before": "Klista in rad f\u00f6re",
+"Scope": "Omf\u00e5ng",
+"Delete table": "Radera tabell",
+"Header cell": "Huvudcell",
+"Column": "Kolumn",
+"Cell": "Cell",
+"Header": "Huvud",
+"Cell type": "Celltyp",
+"Copy row": "Kopiera rad",
+"Row properties": "Radegenskaper",
+"Table properties": "Tabell egenskaper",
+"Row group": "Radgrupp",
+"Right": "H\u00f6ger",
+"Insert column after": "Infoga kolumn efter",
+"Cols": "Kolumner",
+"Insert row after": "Infoga rad efter",
+"Width": "Bredd",
+"Cell properties": "Cellegenskaper",
+"Left": "V\u00e4nster",
+"Cut row": "Klipp ut rad",
+"Delete column": "Radera kolumn",
+"Center": "Centrum",
+"Merge cells": "Sammanfoga celler",
+"Insert template": "Infoga mall",
+"Templates": "Mallar",
+"Background color": "Bakgrundsf\u00e4rg",
+"Text color": "Textf\u00e4rg",
+"Show blocks": "Visa block",
+"Show invisible characters": "Visa onsynliga tecken",
+"Words: {0}": "Ord: {0}",
+"Insert": "Infoga",
+"File": "Fil",
+"Edit": "Redigera",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Textredigerare. Tryck ALT-F9 f\u00f6r menyn. Tryck ALT-F10 f\u00f6r verktygsrader. Tryck ALT-0 f\u00f6r hj\u00e4lp.",
+"Tools": "Verktyg",
+"View": "Vy",
+"Table": "Tabell",
+"Format": "Format"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ta.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ta.js
new file mode 100755
index 0000000..d8210c1
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ta.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('ta',{
+"Cut": "\u0bb5\u0bc6\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Header 2": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u0ba8\u0b95\u0bb2\u0b95\u0ba4\u0bcd\u0ba4\u0bbf\u0bb1\u0bcd\u0b95\u0bc1 \u0ba8\u0bc7\u0bb0\u0b9f\u0bbf \u0b85\u0ba3\u0bc1\u0b95\u0bb2\u0bc8 \u0ba4\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b89\u0bb2\u0bbe\u0bb5\u0bbf \u0b86\u0ba4\u0bb0\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bbf\u0bb2\u0bcd\u0bb2\u0bc8. \u0b86\u0b95\u0bb5\u0bc7 \u0bb5\u0bbf\u0b9a\u0bc8\u0baa\u0bcd\u0baa\u0bb2\u0b95\u0bc8 \u0b95\u0bc1\u0bb1\u0bc1\u0b95\u0bcd\u0b95\u0bc1\u0bb5\u0bb4\u0bbf\u0b95\u0bb3\u0bbe\u0ba9 Ctrl+X\/C\/V \u0b87\u0bb5\u0bb1\u0bcd\u0bb1\u0bc8 \u0ba4\u0baf\u0bb5\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd\u0ba4\u0bc1 \u0baa\u0baf\u0ba9\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1\u0b95.",
+"Div": "\u0baa\u0bbf\u0bb0\u0bbf\u0bb5\u0bc1 (Div)",
+"Paste": "\u0b92\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Close": "\u0bae\u0bc2\u0b9f\u0bc1\u0b95",
+"Pre": "\u0bae\u0bc1\u0ba9\u0bcd \u0bb5\u0b9f\u0bbf\u0bb5\u0bae\u0bc8\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1 (Pre)",
+"Align right": "\u0bb5\u0bb2\u0ba4\u0bc1 \u0b9a\u0bc0\u0bb0\u0bae\u0bc8",
+"New document": "\u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0b86\u0bb5\u0ba3\u0bae\u0bcd",
+"Blockquote": "\u0ba4\u0bca\u0b95\u0bc1\u0ba4\u0bbf \u0bae\u0bc7\u0bb1\u0bcd\u0b95\u0bcb\u0bb3\u0bcd",
+"Numbered list": "\u0b8e\u0ba3\u0bcd\u0ba3\u0bbf\u0b9f\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f \u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0baf\u0bb2\u0bcd",
+"Increase indent": "\u0b89\u0bb3\u0bcd\u0ba4\u0bb3\u0bcd\u0bb3\u0bc1\u0ba4\u0bb2\u0bc8 \u0b85\u0ba4\u0bbf\u0b95\u0bb0\u0bbf\u0b95\u0bcd\u0b95",
+"Formats": "\u0bb5\u0b9f\u0bbf\u0bb5\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd",
+"Headers": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd",
+"Select all": "\u0b85\u0ba9\u0bc8\u0ba4\u0bcd\u0ba4\u0bc8\u0baf\u0bc1\u0bae\u0bcd \u0ba4\u0bc7\u0bb0\u0bcd\u0bb5\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd\u0b95",
+"Header 3": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1 3",
+"Blocks": "\u0ba4\u0bca\u0b95\u0bc1\u0ba4\u0bbf\u0b95\u0bb3\u0bcd",
+"Undo": "\u0bae\u0bc1\u0ba9\u0bcd\u0b9a\u0bc6\u0baf\u0bb2\u0bc8 \u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0bc1\u0b95",
+"Strikethrough": "\u0ba8\u0b9f\u0bc1\u0b95\u0bcd\u0b95\u0bcb\u0b9f\u0bc1",
+"Bullet list": "\u0baa\u0bca\u0b9f\u0bcd\u0b9f\u0bbf\u0b9f\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f \u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0baf\u0bb2\u0bcd",
+"Header 1": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1 1",
+"Superscript": "\u0bae\u0bc7\u0bb2\u0bcd\u0b92\u0b9f\u0bcd\u0b9f\u0bc1",
+"Clear formatting": "\u0bb5\u0b9f\u0bbf\u0bb5\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc8 \u0b85\u0bb4\u0bbf\u0b95\u0bcd\u0b95",
+"Subscript": "\u0b95\u0bc0\u0bb4\u0bcd\u0b92\u0b9f\u0bcd\u0b9f\u0bc1",
+"Header 6": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1 6",
+"Redo": "\u0bae\u0bc0\u0ba3\u0bcd\u0b9f\u0bc1\u0bae\u0bcd \u0b9a\u0bc6\u0baf\u0bcd\u0b95",
+"Paragraph": "\u0baa\u0ba4\u0bcd\u0ba4\u0bbf",
+"Ok": "\u0b9a\u0bb0\u0bbf",
+"Bold": "\u0ba4\u0b9f\u0bbf\u0baa\u0bcd\u0baa\u0bc1",
+"Code": "\u0b95\u0bc1\u0bb1\u0bbf\u0baf\u0bc0\u0b9f\u0bc1",
+"Italic": "\u0b9a\u0bbe\u0baf\u0bcd\u0bb5\u0bc1",
+"Align center": "\u0bae\u0bc8\u0baf \u0b9a\u0bc0\u0bb0\u0bae\u0bc8",
+"Header 5": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1 5",
+"Decrease indent": "\u0b89\u0bb3\u0bcd\u0ba4\u0bb3\u0bcd\u0bb3\u0bc1\u0ba4\u0bb2\u0bc8 \u0b95\u0bc1\u0bb1\u0bc8\u0b95\u0bcd\u0b95",
+"Header 4": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u0b87\u0baf\u0bb2\u0bcd\u0baa\u0bc1 \u0b89\u0bb0\u0bc8 \u0bae\u0bc1\u0bb1\u0bc8\u0bae\u0bc8\u0baf\u0bbf\u0bb2\u0bcd \u0ba4\u0bb1\u0bcd\u0baa\u0bcb\u0ba4\u0bc1 \u0b92\u0b9f\u0bcd\u0b9f\u0bc1\u0ba4\u0bb2\u0bcd \u0b89\u0bb3\u0bcd\u0bb3\u0ba4\u0bc1. \u0ba4\u0bbe\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b87\u0ba8\u0bcd\u0ba4 \u0bb5\u0bbf\u0bb0\u0bc1\u0baa\u0bcd\u0baa\u0bc8 \u0bae\u0bbe\u0bb1\u0bcd\u0bb1\u0bc1\u0bae\u0bcd \u0bb5\u0bb0\u0bc8 \u0b89\u0bb3\u0bcd\u0bb3\u0b9f\u0b95\u0bcd\u0b95\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b87\u0baf\u0bb2\u0bcd\u0baa\u0bc1 \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b95 \u0b92\u0b9f\u0bcd\u0b9f\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0bae\u0bcd.",
+"Underline": "\u0b85\u0b9f\u0bbf\u0b95\u0bcd\u0b95\u0bcb\u0b9f\u0bc1",
+"Cancel": "\u0bb0\u0ba4\u0bcd\u0ba4\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd\u0b95",
+"Justify": "\u0ba8\u0bc7\u0bb0\u0bcd\u0ba4\u0bcd\u0ba4\u0bbf \u0b9a\u0bc6\u0baf\u0bcd\u0b95",
+"Inline": "\u0b89\u0bb3\u0bcd\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8",
+"Copy": "\u0ba8\u0b95\u0bb2\u0bc6\u0b9f\u0bc1\u0b95\u0bcd\u0b95",
+"Align left": "\u0b87\u0b9f\u0ba4\u0bc1 \u0b9a\u0bc0\u0bb0\u0bae\u0bc8",
+"Visual aids": "\u0b95\u0bbe\u0b9f\u0bcd\u0b9a\u0bbf\u0ba4\u0bcd \u0ba4\u0bc1\u0ba3\u0bc8\u0baf\u0ba9\u0bcd\u0b95\u0bb3\u0bcd",
+"Lower Greek": "\u0b95\u0bc0\u0bb4\u0bcd \u0b95\u0bbf\u0bb0\u0bc7\u0b95\u0bcd\u0b95\u0bae\u0bcd",
+"Square": "\u0b9a\u0ba4\u0bc1\u0bb0\u0bae\u0bcd",
+"Default": "\u0b89\u0bb3\u0bcd\u0bb3\u0bbf\u0bb0\u0bc1\u0baa\u0bcd\u0baa\u0bc1",
+"Lower Alpha": "\u0b95\u0bc0\u0bb4\u0bcd \u0b8e\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1",
+"Circle": "\u0bb5\u0b9f\u0bcd\u0b9f\u0bae\u0bcd",
+"Disc": "\u0bb5\u0b9f\u0bcd\u0b9f\u0bc1",
+"Upper Alpha": "\u0bae\u0bc7\u0bb2\u0bcd \u0b8e\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1",
+"Upper Roman": "\u0bae\u0bc7\u0bb2\u0bcd \u0bb0\u0bcb\u0bae\u0bbe\u0ba9\u0bbf\u0baf\u0bae\u0bcd",
+"Lower Roman": "\u0b95\u0bc0\u0bb4\u0bcd \u0bb0\u0bcb\u0bae\u0bbe\u0ba9\u0bbf\u0baf\u0bae\u0bcd",
+"Name": "\u0baa\u0bc6\u0baf\u0bb0\u0bcd",
+"Anchor": "\u0ba8\u0b99\u0bcd\u0b95\u0bc2\u0bb0\u0bae\u0bcd",
+"You have unsaved changes are you sure you want to navigate away?": "\u0b9a\u0bc7\u0bae\u0bbf\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bbe\u0ba4 \u0bae\u0bbe\u0bb1\u0bcd\u0bb1\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b89\u0bb3\u0bcd\u0bb3\u0ba9; \u0ba4\u0bbe\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b89\u0bb1\u0bc1\u0ba4\u0bbf\u0baf\u0bbe\u0b95 \u0bb5\u0bc6\u0bb3\u0bbf\u0baf\u0bc7\u0bb1 \u0bb5\u0bbf\u0bb0\u0bc1\u0bae\u0bcd\u0baa\u0bc1\u0b95\u0bbf\u0bb1\u0bc0\u0bb0\u0bcd\u0b95\u0bbe\u0bb3\u0bbe?",
+"Restore last draft": "\u0b95\u0b9f\u0ba8\u0bcd\u0ba4 \u0bb5\u0bb0\u0bc8\u0bb5\u0bc8 \u0bae\u0bc0\u0b9f\u0bcd\u0b9f\u0bc6\u0b9f\u0bc1\u0b95\u0bcd\u0b95",
+"Special character": "\u0b9a\u0bbf\u0bb1\u0baa\u0bcd\u0baa\u0bc1 \u0b8e\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1\u0bb0\u0bc1",
+"Source code": "\u0bae\u0bc2\u0bb2 \u0b95\u0bc1\u0bb1\u0bbf\u0baf\u0bc0\u0b9f\u0bc1",
+"Right to left": "\u0bb5\u0bb2\u0bae\u0bbf\u0bb0\u0bc1\u0ba8\u0bcd\u0ba4\u0bc1 \u0b87\u0b9f\u0bae\u0bcd",
+"Left to right": "\u0b87\u0b9f\u0bae\u0bbf\u0bb0\u0bc1\u0ba8\u0bcd\u0ba4\u0bc1 \u0bb5\u0bb2\u0bae\u0bcd",
+"Emoticons": "\u0b89\u0ba3\u0bb0\u0bcd\u0b9a\u0bcd\u0b9a\u0bbf\u0baa\u0bcd\u0baa\u0b9f\u0bbf\u0bae\u0b99\u0bcd\u0b95\u0bb3\u0bcd",
+"Robots": "Robots",
+"Document properties": "\u0b86\u0bb5\u0ba3\u0ba4\u0bcd\u0ba4\u0bbf\u0ba9\u0bcd \u0baa\u0ba3\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd",
+"Title": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1",
+"Keywords": "\u0bae\u0bc1\u0ba4\u0ba9\u0bcd\u0bae\u0bc8\u0b9a\u0bcd\u0b9a\u0bca\u0bb1\u0bcd\u0b95\u0bb3\u0bcd",
+"Encoding": "\u0b95\u0bc1\u0bb1\u0bbf\u0baf\u0bc0\u0b9f\u0bbe\u0b95\u0bcd\u0b95\u0bae\u0bcd",
+"Description": "\u0bb5\u0bbf\u0bb5\u0bb0\u0bae\u0bcd",
+"Author": "\u0b8e\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bbe\u0bb3\u0bb0\u0bcd",
+"Fullscreen": "\u0bae\u0bc1\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bbf\u0bb0\u0bc8",
+"Horizontal line": "\u0b95\u0bbf\u0b9f\u0bc8 \u0b95\u0bcb\u0b9f\u0bc1",
+"Horizontal space": "\u0b95\u0bbf\u0b9f\u0bc8\u0bae\u0b9f\u0bcd\u0b9f \u0b87\u0b9f\u0bc8\u0bb5\u0bc6\u0bb3\u0bbf",
+"Insert\/edit image": "\u0baa\u0b9f\u0ba4\u0bcd\u0ba4\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95\/\u0ba4\u0bca\u0b95\u0bc1\u0b95\u0bcd\u0b95",
+"General": "\u0baa\u0bca\u0ba4\u0bc1",
+"Advanced": "\u0bae\u0bc7\u0bae\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1",
+"Source": "\u0bae\u0bc2\u0bb2\u0bae\u0bcd",
+"Border": "\u0b95\u0bb0\u0bc8",
+"Constrain proportions": "\u0bb5\u0bbf\u0b95\u0bbf\u0ba4\u0bbe\u0b9a\u0bcd\u0b9a\u0bbe\u0bb0\u0ba4\u0bcd\u0ba4\u0bbf\u0bb2\u0bcd \u0b95\u0b9f\u0bcd\u0b9f\u0bc1\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1\u0b95",
+"Vertical space": "\u0ba8\u0bc6\u0b9f\u0bc1\u0ba4\u0bb3 \u0b87\u0b9f\u0bc8\u0bb5\u0bc6\u0bb3\u0bbf",
+"Image description": "\u0baa\u0b9f \u0bb5\u0bbf\u0bb5\u0bb0\u0bae\u0bcd",
+"Style": "\u0baa\u0bbe\u0ba3\u0bbf",
+"Dimensions": "\u0baa\u0bb0\u0bbf\u0bae\u0bbe\u0ba3\u0b99\u0bcd\u0b95\u0bb3\u0bcd",
+"Insert image": "\u0baa\u0b9f\u0ba4\u0bcd\u0ba4\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Insert date\/time": "\u0ba4\u0bc7\u0ba4\u0bbf\/\u0ba8\u0bc7\u0bb0\u0bae\u0bcd \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Remove link": "\u0b87\u0ba3\u0bc8\u0baa\u0bcd\u0baa\u0bc8 \u0b85\u0b95\u0bb1\u0bcd\u0bb1\u0bc1\u0b95",
+"Url": "\u0b87\u0ba3\u0bc8\u0baf\u0bae\u0bc1\u0b95\u0bb5\u0bb0\u0bbf",
+"Text to display": "\u0b95\u0bbe\u0b9f\u0bcd\u0b9a\u0bbf\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4 \u0bb5\u0bc7\u0ba3\u0bcd\u0b9f\u0bbf\u0baf \u0b89\u0bb0\u0bc8",
+"Anchors": "\u0ba8\u0b99\u0bcd\u0b95\u0bc2\u0bb0\u0b99\u0bcd\u0b95\u0bb3\u0bcd",
+"Insert link": "\u0b87\u0ba3\u0bc8\u0baa\u0bcd\u0baa\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"New window": "\u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0b9a\u0bbe\u0bb3\u0bb0\u0bae\u0bcd",
+"None": "\u0b8f\u0ba4\u0bc1\u0bae\u0bbf\u0bb2\u0bcd\u0bb2\u0bc8",
+"Target": "\u0b87\u0bb2\u0b95\u0bcd\u0b95\u0bc1",
+"Insert\/edit link": "\u0b87\u0ba3\u0bc8\u0baa\u0bcd\u0baa\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95\/\u0ba4\u0bca\u0b95\u0bc1\u0b95\u0bcd\u0b95",
+"Insert\/edit video": "\u0b95\u0bbe\u0ba3\u0bca\u0bb3\u0bbf\u0baf\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95\/\u0ba4\u0bca\u0b95\u0bc1\u0b95\u0bcd\u0b95",
+"Poster": "\u0b9a\u0bc1\u0bb5\u0bb0\u0bca\u0b9f\u0bcd\u0b9f\u0bbf",
+"Alternative source": "\u0bae\u0bbe\u0bb1\u0bcd\u0bb1\u0bc1 \u0bae\u0bc2\u0bb2\u0bae\u0bcd",
+"Paste your embed code below:": "\u0ba4\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b89\u0b9f\u0bcd\u0baa\u0bc6\u0bbe\u0ba4\u0bbf \u0b95\u0bc1\u0bb1\u0bbf\u0baf\u0bc0\u0b9f\u0bcd\u0b9f\u0bc8 \u0b95\u0bc0\u0bb4\u0bc7 \u0b92\u0b9f\u0bcd\u0b9f\u0bb5\u0bc1\u0bae\u0bcd:",
+"Insert video": "\u0b95\u0bbe\u0ba3\u0bca\u0bb3\u0bbf\u0baf\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Embed": "\u0b89\u0b9f\u0bcd\u0baa\u0bca\u0ba4\u0bbf",
+"Nonbreaking space": "\u0baa\u0bbf\u0bb0\u0bbf\u0baf\u0bbe\u0ba4 \u0b87\u0b9f\u0bc8\u0bb5\u0bc6\u0bb3\u0bbf",
+"Page break": "\u0baa\u0b95\u0bcd\u0b95 \u0baa\u0bbf\u0bb0\u0bbf\u0baa\u0bcd\u0baa\u0bc1",
+"Paste as text": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b95 \u0b92\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Preview": "\u0bae\u0bc1\u0ba9\u0bcd\u0ba8\u0bcb\u0b95\u0bcd\u0b95\u0bc1",
+"Print": "\u0b85\u0b9a\u0bcd\u0b9a\u0bbf\u0b9f\u0bc1\u0b95",
+"Save": "\u0b9a\u0bc7\u0bae\u0bbf\u0b95\u0bcd\u0b95",
+"Could not find the specified string.": "\u0b95\u0bc1\u0bb1\u0bbf\u0baa\u0bcd\u0baa\u0bbf\u0b9f\u0bcd\u0b9f \u0b9a\u0bb0\u0bae\u0bcd \u0b95\u0ba3\u0bcd\u0b9f\u0bc1\u0baa\u0bbf\u0b9f\u0bbf\u0b95\u0bcd\u0b95 \u0bae\u0bc1\u0b9f\u0bbf\u0baf\u0bb5\u0bbf\u0bb2\u0bcd\u0bb2\u0bc8",
+"Replace": "\u0bae\u0bbe\u0bb1\u0bcd\u0bb1\u0bc1\u0b95",
+"Next": "\u0b85\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4",
+"Whole words": "\u0bae\u0bc1\u0bb4\u0bc1 \u0b9a\u0bca\u0bb1\u0bcd\u0b95\u0bb3\u0bcd",
+"Find and replace": "\u0b95\u0ba3\u0bcd\u0b9f\u0bc1\u0baa\u0bbf\u0b9f\u0bbf\u0ba4\u0bcd\u0ba4\u0bc1 \u0bae\u0bbe\u0bb1\u0bcd\u0bb1\u0bc1\u0b95",
+"Replace with": "\u0b87\u0ba4\u0ba9\u0bc1\u0b9f\u0ba9\u0bcd \u0bae\u0bbe\u0bb1\u0bcd\u0bb1\u0bc1\u0b95",
+"Find": "\u0b95\u0ba3\u0bcd\u0b9f\u0bc1\u0baa\u0bbf\u0b9f\u0bbf\u0b95\u0bcd\u0b95",
+"Replace all": "\u0b85\u0ba9\u0bc8\u0ba4\u0bcd\u0ba4\u0bc8\u0baf\u0bc1\u0bae\u0bcd \u0bae\u0bbe\u0bb1\u0bcd\u0bb1\u0bc1\u0b95",
+"Match case": "\u0bb5\u0b9f\u0bbf\u0bb5\u0ba4\u0bcd\u0ba4\u0bc8 \u0baa\u0bca\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1\u0b95",
+"Prev": "\u0bae\u0bc1\u0ba8\u0bcd\u0ba4\u0bc8\u0baf",
+"Spellcheck": "\u0b8e\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1\u0baa\u0bcd\u0baa\u0bbf\u0bb4\u0bc8\u0baf\u0bc8 \u0b9a\u0bb0\u0bbf\u0baa\u0bbe\u0bb0\u0bcd\u0b95\u0bcd\u0b95",
+"Finish": "\u0bae\u0bc1\u0b9f\u0bbf\u0b95\u0bcd\u0b95",
+"Ignore all": "\u0b85\u0ba9\u0bc8\u0ba4\u0bcd\u0ba4\u0bc8\u0baf\u0bc1\u0bae\u0bcd \u0baa\u0bc1\u0bb1\u0b95\u0bcd\u0b95\u0ba3\u0bbf\u0b95\u0bcd\u0b95",
+"Ignore": "\u0baa\u0bc1\u0bb1\u0b95\u0bcd\u0b95\u0ba3\u0bbf\u0b95\u0bcd\u0b95",
+"Insert row before": "\u0b87\u0ba4\u0bb1\u0bcd\u0b95\u0bc1 \u0bae\u0bc1\u0ba9\u0bcd \u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Rows": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0b95\u0bb3\u0bcd",
+"Height": "\u0b89\u0baf\u0bb0\u0bae\u0bcd",
+"Paste row after": "\u0b87\u0ba4\u0bb1\u0bcd\u0b95\u0bc1 \u0baa\u0bbf\u0ba9\u0bcd \u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0b92\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Alignment": "\u0b9a\u0bc0\u0bb0\u0bae\u0bc8\u0bb5\u0bc1",
+"Column group": "\u0ba8\u0bc6\u0b9f\u0bc1\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8 \u0b95\u0bc1\u0bb4\u0bc1",
+"Row": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8",
+"Insert column before": "\u0b87\u0ba4\u0bb1\u0bcd\u0b95\u0bc1 \u0bae\u0bc1\u0ba9\u0bcd \u0ba8\u0bc6\u0b9f\u0bc1\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Split cell": "\u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8\u0b95\u0bb3\u0bc8 \u0baa\u0bbf\u0bb0\u0bbf\u0b95\u0bcd\u0b95",
+"Cell padding": "\u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8 \u0ba8\u0bbf\u0bb0\u0baa\u0bcd\u0baa\u0bb2\u0bcd",
+"Cell spacing": "\u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8 \u0b87\u0b9f\u0bc8\u0bb5\u0bc6\u0bb3\u0bbf",
+"Row type": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8 \u0bb5\u0b95\u0bc8",
+"Insert table": "\u0b85\u0b9f\u0bcd\u0b9f\u0bb5\u0ba3\u0bc8\u0baf\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Body": "\u0b89\u0b9f\u0bb2\u0bcd",
+"Caption": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1",
+"Footer": "\u0b85\u0b9f\u0bbf\u0b95\u0bcd\u0b95\u0bc1\u0bb1\u0bbf\u0baa\u0bcd\u0baa\u0bc1",
+"Delete row": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0bc1\u0b95",
+"Paste row before": "\u0b87\u0ba4\u0bb1\u0bcd\u0b95\u0bc1 \u0bae\u0bc1\u0ba9\u0bcd \u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0b92\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Scope": "\u0bb5\u0bb0\u0bc8\u0baf\u0bc6\u0bb2\u0bcd\u0bb2\u0bc8",
+"Delete table": "\u0b85\u0b9f\u0bcd\u0b9f\u0bb5\u0ba3\u0bc8\u0baf\u0bc8 \u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0bc1\u0b95",
+"Header cell": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1 \u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8",
+"Column": "\u0ba8\u0bc6\u0b9f\u0bc1\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8",
+"Cell": "\u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8",
+"Header": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1",
+"Cell type": "\u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8 \u0bb5\u0b95\u0bc8",
+"Copy row": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0ba8\u0b95\u0bb2\u0bc6\u0b9f\u0bc1\u0b95\u0bcd\u0b95",
+"Row properties": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8 \u0baa\u0ba3\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd",
+"Table properties": "\u0b85\u0b9f\u0bcd\u0b9f\u0bb5\u0ba3\u0bc8 \u0baa\u0ba3\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd",
+"Row group": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8 \u0b95\u0bc1\u0bb4\u0bc1",
+"Right": "\u0bb5\u0bb2\u0bae\u0bcd",
+"Insert column after": "\u0b87\u0ba4\u0bb1\u0bcd\u0b95\u0bc1 \u0baa\u0bbf\u0ba9\u0bcd \u0ba8\u0bc6\u0b9f\u0bc1\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Cols": "\u0ba8\u0bc6\u0b9f\u0bc1\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0b95\u0bb3\u0bcd",
+"Insert row after": "\u0b87\u0ba4\u0bb1\u0bcd\u0b95\u0bc1 \u0baa\u0bbf\u0ba9\u0bcd \u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Width": "\u0b85\u0b95\u0bb2\u0bae\u0bcd",
+"Cell properties": "\u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8 \u0baa\u0ba3\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd",
+"Left": "\u0b87\u0b9f\u0bae\u0bcd",
+"Cut row": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0bb5\u0bc6\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Delete column": "\u0ba8\u0bc6\u0b9f\u0bc1\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0bc1\u0b95",
+"Center": "\u0bae\u0bc8\u0baf\u0bae\u0bcd",
+"Merge cells": "\u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8\u0b95\u0bb3\u0bc8 \u0b9a\u0bc7\u0bb0\u0bcd\u0b95\u0bcd\u0b95",
+"Insert template": "\u0bb5\u0bbe\u0bb0\u0bcd\u0baa\u0bcd\u0baa\u0bc1\u0bb0\u0bc1\u0bb5\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Templates": "\u0bb5\u0bbe\u0bb0\u0bcd\u0baa\u0bcd\u0baa\u0bc1\u0bb0\u0bc1\u0b95\u0bcd\u0b95\u0bb3\u0bcd",
+"Background color": "\u0baa\u0bbf\u0ba9\u0bcd\u0ba9\u0ba3\u0bbf \u0ba8\u0bbf\u0bb1\u0bae\u0bcd",
+"Text color": "\u0b89\u0bb0\u0bc8\u0baf\u0bbf\u0ba9\u0bcd \u0ba8\u0bbf\u0bb1\u0bae\u0bcd",
+"Show blocks": "\u0ba4\u0bca\u0b95\u0bc1\u0ba4\u0bbf\u0b95\u0bb3\u0bc8 \u0b95\u0bbe\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Show invisible characters": "\u0b95\u0ba3\u0bcd\u0ba3\u0bc1\u0b95\u0bcd\u0b95\u0bc1\u0ba4\u0bcd \u0ba4\u0bc6\u0bb0\u0bbf\u0baf\u0bbe\u0ba4 \u0b89\u0bb0\u0bc1\u0b95\u0bcd\u0b95\u0bb3\u0bc8 \u0b95\u0bbe\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Words: {0}": "\u0b9a\u0bca\u0bb1\u0bcd\u0b95\u0bb3\u0bcd: {0}",
+"Insert": "\u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"File": "\u0b95\u0bcb\u0baa\u0bcd\u0baa\u0bc1",
+"Edit": "\u0ba4\u0bca\u0b95\u0bc1\u0b95\u0bcd\u0b95",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u0b89\u0baf\u0bb0\u0bcd \u0b89\u0bb0\u0bc8 \u0baa\u0b95\u0bc1\u0ba4\u0bbf. \u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0b95\u0bcd\u0b95\u0bc1 ALT-F9 , \u0b95\u0bb0\u0bc1\u0bb5\u0bbf\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0bc8\u0b95\u0bcd\u0b95\u0bc1 ALT-F10 , \u0b89\u0ba4\u0bb5\u0bbf\u0b95\u0bcd\u0b95\u0bc1 ALT-0",
+"Tools": "\u0b95\u0bb0\u0bc1\u0bb5\u0bbf\u0b95\u0bb3\u0bcd",
+"View": "\u0ba8\u0bcb\u0b95\u0bcd\u0b95\u0bc1\u0b95",
+"Table": "\u0b85\u0b9f\u0bcd\u0b9f\u0bb5\u0ba3\u0bc8",
+"Format": "\u0bb5\u0b9f\u0bbf\u0bb5\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ta_IN.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ta_IN.js
new file mode 100755
index 0000000..92821d1
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ta_IN.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('ta_IN',{
+"Cut": "\u0bb5\u0bc6\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Header 2": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u0ba8\u0b95\u0bb2\u0b95\u0ba4\u0bcd\u0ba4\u0bbf\u0bb1\u0bcd\u0b95\u0bc1 \u0ba8\u0bc7\u0bb0\u0b9f\u0bbf \u0b85\u0ba3\u0bc1\u0b95\u0bb2\u0bc8 \u0ba4\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b89\u0bb2\u0bbe\u0bb5\u0bbf \u0b86\u0ba4\u0bb0\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bbf\u0bb2\u0bcd\u0bb2\u0bc8. \u0b86\u0b95\u0bb5\u0bc7 \u0bb5\u0bbf\u0b9a\u0bc8\u0baa\u0bcd\u0baa\u0bb2\u0b95\u0bc8 \u0b95\u0bc1\u0bb1\u0bc1\u0b95\u0bcd\u0b95\u0bc1\u0bb5\u0bb4\u0bbf\u0b95\u0bb3\u0bbe\u0ba9 Ctrl+X\/C\/V \u0b87\u0bb5\u0bb1\u0bcd\u0bb1\u0bc8 \u0ba4\u0baf\u0bb5\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd\u0ba4\u0bc1 \u0baa\u0baf\u0ba9\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1\u0b95.",
+"Div": "Div",
+"Paste": "\u0b92\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Close": "\u0bae\u0bc2\u0b9f\u0bc1\u0b95",
+"Pre": "Pre",
+"Align right": "\u0bb5\u0bb2\u0ba4\u0bc1 \u0b9a\u0bc0\u0bb0\u0bae\u0bc8",
+"New document": "\u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0b86\u0bb5\u0ba3\u0bae\u0bcd",
+"Blockquote": "\u0ba4\u0bca\u0b95\u0bc1\u0ba4\u0bbf \u0bae\u0bc7\u0bb1\u0bcd\u0b95\u0bcb\u0bb3\u0bcd",
+"Numbered list": "\u0b8e\u0ba3\u0bcd\u0ba3\u0bbf\u0b9f\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f \u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0baf\u0bb2\u0bcd",
+"Increase indent": "\u0b89\u0bb3\u0bcd\u0ba4\u0bb3\u0bcd\u0bb3\u0bc1\u0ba4\u0bb2\u0bc8 \u0b85\u0ba4\u0bbf\u0b95\u0bb0\u0bbf\u0b95\u0bcd\u0b95",
+"Formats": "\u0bb5\u0b9f\u0bbf\u0bb5\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd",
+"Headers": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd",
+"Select all": "\u0b85\u0ba9\u0bc8\u0ba4\u0bcd\u0ba4\u0bc8\u0baf\u0bc1\u0bae\u0bcd \u0ba4\u0bc7\u0bb0\u0bcd\u0bb5\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd\u0b95",
+"Header 3": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1 3",
+"Blocks": "\u0ba4\u0bca\u0b95\u0bc1\u0ba4\u0bbf\u0b95\u0bb3\u0bcd",
+"Undo": "\u0bae\u0bc1\u0ba9\u0bcd\u0b9a\u0bc6\u0baf\u0bb2\u0bc8 \u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0bc1\u0b95",
+"Strikethrough": "\u0ba8\u0b9f\u0bc1\u0b95\u0bcd\u0b95\u0bcb\u0b9f\u0bc1",
+"Bullet list": "\u0baa\u0bca\u0b9f\u0bcd\u0b9f\u0bbf\u0b9f\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f \u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0baf\u0bb2\u0bcd",
+"Header 1": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1 1",
+"Superscript": "\u0bae\u0bc7\u0bb2\u0bcd\u0b92\u0b9f\u0bcd\u0b9f\u0bc1",
+"Clear formatting": "\u0bb5\u0b9f\u0bbf\u0bb5\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc8 \u0b85\u0bb4\u0bbf\u0b95\u0bcd\u0b95",
+"Subscript": "\u0b95\u0bc0\u0bb4\u0bcd\u0b92\u0b9f\u0bcd\u0b9f\u0bc1",
+"Header 6": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1 6",
+"Redo": "\u0bae\u0bc0\u0ba3\u0bcd\u0b9f\u0bc1\u0bae\u0bcd \u0b9a\u0bc6\u0baf\u0bcd\u0b95",
+"Paragraph": "\u0baa\u0ba4\u0bcd\u0ba4\u0bbf",
+"Ok": "\u0b9a\u0bb0\u0bbf",
+"Bold": "\u0ba4\u0b9f\u0bbf\u0baa\u0bcd\u0baa\u0bc1",
+"Code": "\u0b95\u0bc1\u0bb1\u0bbf\u0baf\u0bc0\u0b9f\u0bc1",
+"Italic": "\u0b9a\u0bbe\u0baf\u0bcd\u0bb5\u0bc1",
+"Align center": "\u0bae\u0bc8\u0baf \u0b9a\u0bc0\u0bb0\u0bae\u0bc8",
+"Header 5": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1 5",
+"Decrease indent": "\u0b89\u0bb3\u0bcd\u0ba4\u0bb3\u0bcd\u0bb3\u0bc1\u0ba4\u0bb2\u0bc8 \u0b95\u0bc1\u0bb1\u0bc8\u0b95\u0bcd\u0b95",
+"Header 4": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u0b87\u0baf\u0bb2\u0bcd\u0baa\u0bc1 \u0b89\u0bb0\u0bc8 \u0bae\u0bc1\u0bb1\u0bc8\u0bae\u0bc8\u0baf\u0bbf\u0bb2\u0bcd \u0ba4\u0bb1\u0bcd\u0baa\u0bcb\u0ba4\u0bc1 \u0b92\u0b9f\u0bcd\u0b9f\u0bc1\u0ba4\u0bb2\u0bcd \u0b89\u0bb3\u0bcd\u0bb3\u0ba4\u0bc1. \u0ba4\u0bbe\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b87\u0ba8\u0bcd\u0ba4 \u0bb5\u0bbf\u0bb0\u0bc1\u0baa\u0bcd\u0baa\u0bc8 \u0bae\u0bbe\u0bb1\u0bcd\u0bb1\u0bc1\u0bae\u0bcd \u0bb5\u0bb0\u0bc8 \u0b89\u0bb3\u0bcd\u0bb3\u0b9f\u0b95\u0bcd\u0b95\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b87\u0baf\u0bb2\u0bcd\u0baa\u0bc1 \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b95 \u0b92\u0b9f\u0bcd\u0b9f\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0bae\u0bcd.",
+"Underline": "\u0b85\u0b9f\u0bbf\u0b95\u0bcd\u0b95\u0bcb\u0b9f\u0bc1",
+"Cancel": "\u0bb0\u0ba4\u0bcd\u0ba4\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd\u0b95",
+"Justify": "\u0ba8\u0bc7\u0bb0\u0bcd\u0ba4\u0bcd\u0ba4\u0bbf \u0b9a\u0bc6\u0baf\u0bcd\u0b95",
+"Inline": "\u0b89\u0bb3\u0bcd\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8",
+"Copy": "\u0ba8\u0b95\u0bb2\u0bc6\u0b9f\u0bc1\u0b95\u0bcd\u0b95",
+"Align left": "\u0b87\u0b9f\u0ba4\u0bc1 \u0b9a\u0bc0\u0bb0\u0bae\u0bc8",
+"Visual aids": "\u0b95\u0bbe\u0b9f\u0bcd\u0b9a\u0bbf\u0ba4\u0bcd \u0ba4\u0bc1\u0ba3\u0bc8\u0baf\u0ba9\u0bcd\u0b95\u0bb3\u0bcd",
+"Lower Greek": "\u0b95\u0bc0\u0bb4\u0bcd \u0b95\u0bbf\u0bb0\u0bc7\u0b95\u0bcd\u0b95\u0bae\u0bcd",
+"Square": "\u0b9a\u0ba4\u0bc1\u0bb0\u0bae\u0bcd",
+"Default": "\u0b89\u0bb3\u0bcd\u0bb3\u0bbf\u0bb0\u0bc1\u0baa\u0bcd\u0baa\u0bc1",
+"Lower Alpha": "\u0b95\u0bc0\u0bb4\u0bcd \u0b8e\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1",
+"Circle": "\u0bb5\u0b9f\u0bcd\u0b9f\u0bae\u0bcd",
+"Disc": "\u0bb5\u0b9f\u0bcd\u0b9f\u0bc1",
+"Upper Alpha": "\u0bae\u0bc7\u0bb2\u0bcd \u0b8e\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1",
+"Upper Roman": "\u0bae\u0bc7\u0bb2\u0bcd \u0bb0\u0bcb\u0bae\u0bbe\u0ba9\u0bbf\u0baf\u0bae\u0bcd",
+"Lower Roman": "\u0b95\u0bc0\u0bb4\u0bcd \u0bb0\u0bcb\u0bae\u0bbe\u0ba9\u0bbf\u0baf\u0bae\u0bcd",
+"Name": "\u0baa\u0bc6\u0baf\u0bb0\u0bcd",
+"Anchor": "\u0ba8\u0b99\u0bcd\u0b95\u0bc2\u0bb0\u0bae\u0bcd",
+"You have unsaved changes are you sure you want to navigate away?": "\u0b9a\u0bc7\u0bae\u0bbf\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bbe\u0ba4 \u0bae\u0bbe\u0bb1\u0bcd\u0bb1\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b89\u0bb3\u0bcd\u0bb3\u0ba9; \u0ba4\u0bbe\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0bb5\u0bc6\u0bb3\u0bbf\u0baf\u0bc7\u0bb1 \u0b89\u0bb1\u0bc1\u0ba4\u0bbf\u0baf\u0bbe\u0b95 \u0bb5\u0bbf\u0bb0\u0bc1\u0bae\u0bcd\u0baa\u0bc1\u0b95\u0bbf\u0bb1\u0bc0\u0bb0\u0bcd\u0b95\u0bbe\u0bb3\u0bbe?",
+"Restore last draft": "\u0b95\u0b9f\u0ba8\u0bcd\u0ba4 \u0bb5\u0bb0\u0bc8\u0bb5\u0bc8 \u0bae\u0bc0\u0b9f\u0bcd\u0b9f\u0bc6\u0b9f\u0bc1\u0b95\u0bcd\u0b95",
+"Special character": "\u0b9a\u0bbf\u0bb1\u0baa\u0bcd\u0baa\u0bc1 \u0b8e\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1\u0bb0\u0bc1",
+"Source code": "\u0bae\u0bc2\u0bb2 \u0b95\u0bc1\u0bb1\u0bbf\u0baf\u0bc0\u0b9f\u0bc1",
+"Right to left": "\u0bb5\u0bb2\u0bae\u0bbf\u0bb0\u0bc1\u0ba8\u0bcd\u0ba4\u0bc1 \u0b87\u0b9f\u0bae\u0bcd",
+"Left to right": "\u0b87\u0b9f\u0bae\u0bbf\u0bb0\u0bc1\u0ba8\u0bcd\u0ba4\u0bc1 \u0bb5\u0bb2\u0bae\u0bcd",
+"Emoticons": "\u0b89\u0ba3\u0bb0\u0bcd\u0b9a\u0bcd\u0b9a\u0bbf\u0baa\u0bcd\u0baa\u0b9f\u0bbf\u0bae\u0b99\u0bcd\u0b95\u0bb3\u0bcd",
+"Robots": "Robots",
+"Document properties": "\u0b86\u0bb5\u0ba3\u0ba4\u0bcd\u0ba4\u0bbf\u0ba9\u0bcd \u0baa\u0ba3\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd",
+"Title": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1",
+"Keywords": "\u0bae\u0bc1\u0ba4\u0ba9\u0bcd\u0bae\u0bc8\u0b9a\u0bcd\u0b9a\u0bca\u0bb1\u0bcd\u0b95\u0bb3\u0bcd",
+"Encoding": "\u0b95\u0bc1\u0bb1\u0bbf\u0baf\u0bc0\u0b9f\u0bbe\u0b95\u0bcd\u0b95\u0bae\u0bcd",
+"Description": "\u0bb5\u0bbf\u0bb5\u0bb0\u0bae\u0bcd",
+"Author": "\u0b8e\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bbe\u0bb3\u0bb0\u0bcd",
+"Fullscreen": "\u0bae\u0bc1\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bbf\u0bb0\u0bc8",
+"Horizontal line": "\u0b95\u0bbf\u0b9f\u0bc8 \u0b95\u0bcb\u0b9f\u0bc1",
+"Horizontal space": "\u0b95\u0bbf\u0b9f\u0bc8\u0bae\u0b9f\u0bcd\u0b9f \u0b87\u0b9f\u0bc8\u0bb5\u0bc6\u0bb3\u0bbf",
+"Insert\/edit image": "\u0baa\u0b9f\u0ba4\u0bcd\u0ba4\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95\/\u0ba4\u0bca\u0b95\u0bc1\u0b95\u0bcd\u0b95",
+"General": "\u0baa\u0bca\u0ba4\u0bc1",
+"Advanced": "\u0bae\u0bc7\u0bae\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1",
+"Source": "\u0bae\u0bc2\u0bb2\u0bae\u0bcd",
+"Border": "\u0b95\u0bb0\u0bc8",
+"Constrain proportions": "\u0bb5\u0bbf\u0b95\u0bbf\u0ba4\u0bbe\u0b9a\u0bcd\u0b9a\u0bbe\u0bb0\u0ba4\u0bcd\u0ba4\u0bbf\u0bb2\u0bcd \u0b95\u0b9f\u0bcd\u0b9f\u0bc1\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1\u0b95",
+"Vertical space": "\u0ba8\u0bc6\u0b9f\u0bc1\u0ba4\u0bb3 \u0b87\u0b9f\u0bc8\u0bb5\u0bc6\u0bb3\u0bbf",
+"Image description": "\u0baa\u0b9f \u0bb5\u0bbf\u0bb5\u0bb0\u0bae\u0bcd",
+"Style": "\u0baa\u0bbe\u0ba3\u0bbf",
+"Dimensions": "\u0baa\u0bb0\u0bbf\u0bae\u0bbe\u0ba3\u0b99\u0bcd\u0b95\u0bb3\u0bcd",
+"Insert image": "\u0baa\u0b9f\u0ba4\u0bcd\u0ba4\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Insert date\/time": "\u0ba4\u0bc7\u0ba4\u0bbf\/\u0ba8\u0bc7\u0bb0\u0bae\u0bcd \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Remove link": "\u0b87\u0ba3\u0bc8\u0baa\u0bcd\u0baa\u0bc8 \u0b85\u0b95\u0bb1\u0bcd\u0bb1\u0bc1\u0b95",
+"Url": "\u0b87\u0ba3\u0bc8\u0baf\u0bae\u0bc1\u0b95\u0bb5\u0bb0\u0bbf",
+"Text to display": "\u0b95\u0bbe\u0b9f\u0bcd\u0b9a\u0bbf\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4 \u0bb5\u0bc7\u0ba3\u0bcd\u0b9f\u0bbf\u0baf \u0b89\u0bb0\u0bc8",
+"Anchors": "\u0ba8\u0b99\u0bcd\u0b95\u0bc2\u0bb0\u0b99\u0bcd\u0b95\u0bb3\u0bcd",
+"Insert link": "\u0b87\u0ba3\u0bc8\u0baa\u0bcd\u0baa\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"New window": "\u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0b9a\u0bbe\u0bb3\u0bb0\u0bae\u0bcd",
+"None": "\u0b8f\u0ba4\u0bc1\u0bae\u0bbf\u0bb2\u0bcd\u0bb2\u0bc8",
+"Target": "\u0b87\u0bb2\u0b95\u0bcd\u0b95\u0bc1",
+"Insert\/edit link": "\u0b87\u0ba3\u0bc8\u0baa\u0bcd\u0baa\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95\/\u0ba4\u0bca\u0b95\u0bc1\u0b95\u0bcd\u0b95",
+"Insert\/edit video": "\u0b95\u0bbe\u0ba3\u0bca\u0bb3\u0bbf\u0baf\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95\/\u0ba4\u0bca\u0b95\u0bc1\u0b95\u0bcd\u0b95",
+"Poster": "\u0b9a\u0bc1\u0bb5\u0bb0\u0bca\u0b9f\u0bcd\u0b9f\u0bbf",
+"Alternative source": "\u0bae\u0bbe\u0bb1\u0bcd\u0bb1\u0bc1 \u0bae\u0bc2\u0bb2\u0bae\u0bcd",
+"Paste your embed code below:": "\u0b95\u0bc0\u0bb4\u0bc7 \u0ba4\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b89\u0b9f\u0bcd\u0baa\u0bc6\u0bbe\u0ba4\u0bbf \u0b95\u0bc1\u0bb1\u0bbf\u0baf\u0bc0\u0b9f\u0bcd\u0b9f\u0bc8 \u0b92\u0b9f\u0bcd\u0b9f\u0bb5\u0bc1\u0bae\u0bcd:",
+"Insert video": "\u0b95\u0bbe\u0ba3\u0bca\u0bb3\u0bbf\u0baf\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Embed": "\u0b89\u0b9f\u0bcd\u0baa\u0bca\u0ba4\u0bbf",
+"Nonbreaking space": "\u0baa\u0bbf\u0bb0\u0bbf\u0baf\u0bbe\u0ba4 \u0b87\u0b9f\u0bc8\u0bb5\u0bc6\u0bb3\u0bbf",
+"Page break": "\u0baa\u0b95\u0bcd\u0b95 \u0baa\u0bbf\u0bb0\u0bbf\u0baa\u0bcd\u0baa\u0bc1",
+"Paste as text": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b95 \u0b92\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Preview": "\u0bae\u0bc1\u0ba9\u0bcd\u0ba8\u0bcb\u0b95\u0bcd\u0b95\u0bc1",
+"Print": "\u0b85\u0b9a\u0bcd\u0b9a\u0bbf\u0b9f\u0bc1\u0b95",
+"Save": "\u0b9a\u0bc7\u0bae\u0bbf\u0b95\u0bcd\u0b95",
+"Could not find the specified string.": "\u0b95\u0bc1\u0bb1\u0bbf\u0baa\u0bcd\u0baa\u0bbf\u0b9f\u0bcd\u0b9f \u0b9a\u0bb0\u0bae\u0bcd \u0b95\u0ba3\u0bcd\u0b9f\u0bc1\u0baa\u0bbf\u0b9f\u0bbf\u0b95\u0bcd\u0b95 \u0bae\u0bc1\u0b9f\u0bbf\u0baf\u0bb5\u0bbf\u0bb2\u0bcd\u0bb2\u0bc8",
+"Replace": "\u0bae\u0bbe\u0bb1\u0bcd\u0bb1\u0bc1\u0b95",
+"Next": "\u0b85\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4",
+"Whole words": "\u0bae\u0bc1\u0bb4\u0bc1 \u0b9a\u0bca\u0bb1\u0bcd\u0b95\u0bb3\u0bcd",
+"Find and replace": "\u0b95\u0ba3\u0bcd\u0b9f\u0bc1\u0baa\u0bbf\u0b9f\u0bbf\u0ba4\u0bcd\u0ba4\u0bc1 \u0bae\u0bbe\u0bb1\u0bcd\u0bb1\u0bc1\u0b95",
+"Replace with": "\u0b87\u0ba4\u0ba9\u0bc1\u0b9f\u0ba9\u0bcd \u0bae\u0bbe\u0bb1\u0bcd\u0bb1\u0bc1\u0b95",
+"Find": "\u0b95\u0ba3\u0bcd\u0b9f\u0bc1\u0baa\u0bbf\u0b9f\u0bbf\u0b95\u0bcd\u0b95",
+"Replace all": "\u0b85\u0ba9\u0bc8\u0ba4\u0bcd\u0ba4\u0bc8\u0baf\u0bc1\u0bae\u0bcd \u0bae\u0bbe\u0bb1\u0bcd\u0bb1\u0bc1\u0b95",
+"Match case": "\u0bb5\u0b9f\u0bbf\u0bb5\u0ba4\u0bcd\u0ba4\u0bc8 \u0baa\u0bca\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1\u0b95",
+"Prev": "\u0bae\u0bc1\u0ba8\u0bcd\u0ba4\u0bc8\u0baf",
+"Spellcheck": "\u0b8e\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1\u0baa\u0bcd\u0baa\u0bbf\u0bb4\u0bc8\u0baf\u0bc8 \u0b9a\u0bb0\u0bbf\u0baa\u0bbe\u0bb0\u0bcd\u0b95\u0bcd\u0b95",
+"Finish": "\u0bae\u0bc1\u0b9f\u0bbf\u0b95\u0bcd\u0b95",
+"Ignore all": "\u0b85\u0ba9\u0bc8\u0ba4\u0bcd\u0ba4\u0bc8\u0baf\u0bc1\u0bae\u0bcd \u0baa\u0bc1\u0bb1\u0b95\u0bcd\u0b95\u0ba3\u0bbf\u0b95\u0bcd\u0b95",
+"Ignore": "\u0baa\u0bc1\u0bb1\u0b95\u0bcd\u0b95\u0ba3\u0bbf\u0b95\u0bcd\u0b95",
+"Insert row before": "\u0b87\u0ba4\u0bb1\u0bcd\u0b95\u0bc1 \u0bae\u0bc1\u0ba9\u0bcd \u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Rows": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0b95\u0bb3\u0bcd",
+"Height": "\u0b89\u0baf\u0bb0\u0bae\u0bcd",
+"Paste row after": "\u0b87\u0ba4\u0bb1\u0bcd\u0b95\u0bc1 \u0baa\u0bbf\u0ba9\u0bcd \u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0b92\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Alignment": "\u0b9a\u0bc0\u0bb0\u0bae\u0bc8\u0bb5\u0bc1",
+"Column group": "\u0ba8\u0bc6\u0b9f\u0bc1\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8 \u0b95\u0bc1\u0bb4\u0bc1",
+"Row": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8",
+"Insert column before": "\u0b87\u0ba4\u0bb1\u0bcd\u0b95\u0bc1 \u0bae\u0bc1\u0ba9\u0bcd \u0ba8\u0bc6\u0b9f\u0bc1\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Split cell": "\u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8\u0b95\u0bb3\u0bc8 \u0baa\u0bbf\u0bb0\u0bbf\u0b95\u0bcd\u0b95",
+"Cell padding": "\u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8 \u0ba8\u0bbf\u0bb0\u0baa\u0bcd\u0baa\u0bb2\u0bcd",
+"Cell spacing": "\u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8 \u0b87\u0b9f\u0bc8\u0bb5\u0bc6\u0bb3\u0bbf",
+"Row type": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8 \u0bb5\u0b95\u0bc8",
+"Insert table": "\u0b85\u0b9f\u0bcd\u0b9f\u0bb5\u0ba3\u0bc8\u0baf\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Body": "\u0b89\u0b9f\u0bb2\u0bcd",
+"Caption": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1",
+"Footer": "\u0b85\u0b9f\u0bbf\u0b95\u0bcd\u0b95\u0bc1\u0bb1\u0bbf\u0baa\u0bcd\u0baa\u0bc1",
+"Delete row": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0bc1\u0b95",
+"Paste row before": "\u0b87\u0ba4\u0bb1\u0bcd\u0b95\u0bc1 \u0bae\u0bc1\u0ba9\u0bcd \u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0b92\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Scope": "\u0bb5\u0bb0\u0bc8\u0baf\u0bc6\u0bb2\u0bcd\u0bb2\u0bc8",
+"Delete table": "\u0b85\u0b9f\u0bcd\u0b9f\u0bb5\u0ba3\u0bc8\u0baf\u0bc8 \u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0bc1\u0b95",
+"Header cell": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1 \u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8",
+"Column": "\u0ba8\u0bc6\u0b9f\u0bc1\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8",
+"Cell": "\u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8",
+"Header": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bc1",
+"Cell type": "\u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8 \u0bb5\u0b95\u0bc8",
+"Copy row": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0ba8\u0b95\u0bb2\u0bc6\u0b9f\u0bc1\u0b95\u0bcd\u0b95",
+"Row properties": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8 \u0baa\u0ba3\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd",
+"Table properties": "\u0b85\u0b9f\u0bcd\u0b9f\u0bb5\u0ba3\u0bc8 \u0baa\u0ba3\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd",
+"Row group": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8 \u0b95\u0bc1\u0bb4\u0bc1",
+"Right": "\u0bb5\u0bb2\u0bae\u0bcd",
+"Insert column after": "\u0b87\u0ba4\u0bb1\u0bcd\u0b95\u0bc1 \u0baa\u0bbf\u0ba9\u0bcd \u0ba8\u0bc6\u0b9f\u0bc1\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Cols": "\u0ba8\u0bc6\u0b9f\u0bc1\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0b95\u0bb3\u0bcd",
+"Insert row after": "\u0b87\u0ba4\u0bb1\u0bcd\u0b95\u0bc1 \u0baa\u0bbf\u0ba9\u0bcd \u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Width": "\u0b85\u0b95\u0bb2\u0bae\u0bcd",
+"Cell properties": "\u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8 \u0baa\u0ba3\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd",
+"Left": "\u0b87\u0b9f\u0bae\u0bcd",
+"Cut row": "\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0bb5\u0bc6\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Delete column": "\u0ba8\u0bc6\u0b9f\u0bc1\u0bb5\u0bb0\u0bbf\u0b9a\u0bc8\u0baf\u0bc8 \u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0bc1\u0b95",
+"Center": "\u0bae\u0bc8\u0baf\u0bae\u0bcd",
+"Merge cells": "\u0b9a\u0bbf\u0bb1\u0bcd\u0bb1\u0bb1\u0bc8\u0b95\u0bb3\u0bc8 \u0b9a\u0bc7\u0bb0\u0bcd\u0b95\u0bcd\u0b95",
+"Insert template": "\u0bb5\u0bbe\u0bb0\u0bcd\u0baa\u0bcd\u0baa\u0bc1\u0bb0\u0bc1\u0bb5\u0bc8 \u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"Templates": "\u0bb5\u0bbe\u0bb0\u0bcd\u0baa\u0bcd\u0baa\u0bc1\u0bb0\u0bc1\u0b95\u0bcd\u0b95\u0bb3\u0bcd",
+"Background color": "\u0baa\u0bbf\u0ba9\u0bcd\u0ba9\u0ba3\u0bbf \u0ba8\u0bbf\u0bb1\u0bae\u0bcd",
+"Text color": "\u0b89\u0bb0\u0bc8\u0baf\u0bbf\u0ba9\u0bcd \u0ba8\u0bbf\u0bb1\u0bae\u0bcd",
+"Show blocks": "\u0ba4\u0bca\u0b95\u0bc1\u0ba4\u0bbf\u0b95\u0bb3\u0bc8 \u0b95\u0bbe\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Show invisible characters": "\u0b95\u0ba3\u0bcd\u0ba3\u0bc1\u0b95\u0bcd\u0b95\u0bc1\u0ba4\u0bcd \u0ba4\u0bc6\u0bb0\u0bbf\u0baf\u0bbe\u0ba4 \u0b89\u0bb0\u0bc1\u0b95\u0bcd\u0b95\u0bb3\u0bc8 \u0b95\u0bbe\u0b9f\u0bcd\u0b9f\u0bc1\u0b95",
+"Words: {0}": "\u0b9a\u0bca\u0bb1\u0bcd\u0b95\u0bb3\u0bcd: {0}",
+"Insert": "\u0b9a\u0bc6\u0bb0\u0bc1\u0b95\u0bc1\u0b95",
+"File": "\u0b95\u0bcb\u0baa\u0bcd\u0baa\u0bc1",
+"Edit": "\u0ba4\u0bca\u0b95\u0bc1\u0b95\u0bcd\u0b95",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u0b89\u0baf\u0bb0\u0bcd \u0b89\u0bb0\u0bc8 \u0baa\u0b95\u0bc1\u0ba4\u0bbf. \u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0b95\u0bcd\u0b95\u0bc1 ALT-F9 , \u0b95\u0bb0\u0bc1\u0bb5\u0bbf\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0bc8\u0b95\u0bcd\u0b95\u0bc1 ALT-F10 , \u0b89\u0ba4\u0bb5\u0bbf\u0b95\u0bcd\u0b95\u0bc1 ALT-0",
+"Tools": "\u0b95\u0bb0\u0bc1\u0bb5\u0bbf\u0b95\u0bb3\u0bcd",
+"View": "\u0ba8\u0bcb\u0b95\u0bcd\u0b95\u0bc1\u0b95",
+"Table": "\u0b85\u0b9f\u0bcd\u0b9f\u0bb5\u0ba3\u0bc8",
+"Format": "\u0bb5\u0b9f\u0bbf\u0bb5\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/th_TH.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/th_TH.js
new file mode 100755
index 0000000..28d2c8b
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/th_TH.js
@@ -0,0 +1,156 @@
+tinymce.addI18n('th_TH',{
+"Cut": "\u0e15\u0e31\u0e14",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u0e40\u0e1a\u0e23\u0e32\u0e27\u0e4c\u0e40\u0e0b\u0e2d\u0e23\u0e4c\u0e02\u0e2d\u0e07\u0e04\u0e38\u0e13\u0e44\u0e21\u0e48\u0e2a\u0e19\u0e31\u0e1a\u0e2a\u0e19\u0e38\u0e19\u0e01\u0e32\u0e23\u0e40\u0e02\u0e49\u0e32\u0e16\u0e36\u0e07\u0e42\u0e14\u0e22\u0e15\u0e23\u0e07\u0e44\u0e1b\u0e22\u0e31\u0e07\u0e04\u0e25\u0e34\u0e1b\u0e1a\u0e2d\u0e23\u0e4c\u0e14 \u0e01\u0e23\u0e38\u0e13\u0e32\u0e43\u0e0a\u0e49\u0e41\u0e1b\u0e49\u0e19\u0e1e\u0e34\u0e21\u0e1e\u0e4c\u0e25\u0e31\u0e14 Ctrl+X\/C\/V \u0e41\u0e17\u0e19",
+"Paste": "\u0e27\u0e32\u0e07",
+"Close": "\u0e1b\u0e34\u0e14",
+"Align right": "\u0e08\u0e31\u0e14\u0e0a\u0e34\u0e14\u0e02\u0e27\u0e32",
+"New document": "\u0e40\u0e2d\u0e01\u0e2a\u0e32\u0e23\u0e43\u0e2b\u0e21\u0e48",
+"Numbered list": "\u0e23\u0e32\u0e22\u0e01\u0e32\u0e23\u0e25\u0e33\u0e14\u0e31\u0e1a\u0e40\u0e25\u0e02",
+"Increase indent": "\u0e40\u0e1e\u0e34\u0e48\u0e21\u0e01\u0e32\u0e23\u0e40\u0e22\u0e37\u0e49\u0e2d\u0e07",
+"Formats": "\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a",
+"Select all": "\u0e40\u0e25\u0e37\u0e2d\u0e01\u0e17\u0e31\u0e49\u0e07\u0e2b\u0e21\u0e14",
+"Undo": "\u0e40\u0e25\u0e34\u0e01\u0e17\u0e33",
+"Strikethrough": "\u0e02\u0e35\u0e14\u0e17\u0e31\u0e1a",
+"Bullet list": "\u0e23\u0e32\u0e22\u0e01\u0e32\u0e23\u0e2a\u0e31\u0e0d\u0e25\u0e31\u0e01\u0e29\u0e13\u0e4c\u0e2b\u0e31\u0e27\u0e02\u0e49\u0e2d\u0e22\u0e48\u0e2d\u0e22",
+"Superscript": "\u0e15\u0e31\u0e27\u0e22\u0e01",
+"Clear formatting": "\u0e25\u0e49\u0e32\u0e07\u0e01\u0e32\u0e23\u0e08\u0e31\u0e14\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a",
+"Subscript": "\u0e15\u0e31\u0e27\u0e2b\u0e49\u0e2d\u0e22",
+"Redo": "\u0e17\u0e4d\u0e32\u0e0b\u0e49\u0e33",
+"Ok": "\u0e15\u0e01\u0e25\u0e07",
+"Bold": "\u0e15\u0e31\u0e27\u0e2b\u0e19\u0e32",
+"Italic": "\u0e15\u0e31\u0e27\u0e40\u0e2d\u0e35\u0e22\u0e07",
+"Align center": "\u0e08\u0e31\u0e14\u0e01\u0e36\u0e48\u0e07\u0e01\u0e25\u0e32\u0e07",
+"Decrease indent": "\u0e25\u0e14\u0e01\u0e32\u0e23\u0e40\u0e22\u0e37\u0e49\u0e2d\u0e07",
+"Underline": "\u0e02\u0e35\u0e14\u0e40\u0e2a\u0e49\u0e19\u0e43\u0e15\u0e49",
+"Cancel": "\u0e22\u0e01\u0e40\u0e25\u0e34\u0e01",
+"Justify": "\u0e40\u0e15\u0e47\u0e21\u0e41\u0e19\u0e27",
+"Copy": "\u0e04\u0e31\u0e14\u0e25\u0e2d\u0e01",
+"Align left": "\u0e08\u0e31\u0e14\u0e0a\u0e34\u0e14\u0e0b\u0e49\u0e32\u0e22",
+"Visual aids": "\u0e17\u0e31\u0e28\u0e19\u0e39\u0e1b\u0e01\u0e23\u0e13\u0e4c",
+"Lower Greek": "\u0e01\u0e23\u0e35\u0e01\u0e17\u0e35\u0e48\u0e15\u0e48\u0e33\u0e01\u0e27\u0e48\u0e32",
+"Square": "\u0e08\u0e31\u0e15\u0e38\u0e23\u0e31\u0e2a",
+"Default": "\u0e04\u0e48\u0e32\u0e40\u0e23\u0e34\u0e48\u0e21\u0e15\u0e49\u0e19",
+"Lower Alpha": "\u0e2d\u0e31\u0e25\u0e1f\u0e32\u0e17\u0e35\u0e48\u0e15\u0e48\u0e33\u0e01\u0e27\u0e48\u0e32",
+"Circle": "\u0e27\u0e07\u0e01\u0e25\u0e21",
+"Disc": "\u0e14\u0e34\u0e2a\u0e01\u0e4c",
+"Upper Alpha": "\u0e2d\u0e31\u0e25\u0e1f\u0e32\u0e17\u0e35\u0e48\u0e2a\u0e39\u0e07\u0e01\u0e27\u0e48\u0e32",
+"Upper Roman": "\u0e42\u0e23\u0e21\u0e31\u0e19\u0e17\u0e35\u0e48\u0e2a\u0e39\u0e07\u0e01\u0e27\u0e48\u0e32",
+"Lower Roman": "\u0e42\u0e23\u0e21\u0e31\u0e19\u0e17\u0e35\u0e48\u0e15\u0e48\u0e33\u0e01\u0e27\u0e48\u0e32",
+"Name": "\u0e0a\u0e37\u0e48\u0e2d",
+"Anchor": "\u0e08\u0e38\u0e14\u0e22\u0e36\u0e14",
+"You have unsaved changes are you sure you want to navigate away?": "\u0e04\u0e38\u0e13\u0e21\u0e35\u0e01\u0e32\u0e23\u0e40\u0e1b\u0e25\u0e35\u0e48\u0e22\u0e19\u0e41\u0e1b\u0e25\u0e07\u0e17\u0e35\u0e48\u0e44\u0e21\u0e48\u0e44\u0e14\u0e49\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01 \u0e04\u0e38\u0e13\u0e15\u0e49\u0e2d\u0e07\u0e01\u0e32\u0e23\u0e17\u0e35\u0e48\u0e08\u0e30\u0e2d\u0e2d\u0e01\u0e2b\u0e23\u0e37\u0e2d\u0e44\u0e21\u0e48?",
+"Restore last draft": "\u0e04\u0e37\u0e19\u0e04\u0e48\u0e32\u0e41\u0e1a\u0e1a\u0e23\u0e48\u0e32\u0e07\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14",
+"Special character": "\u0e2d\u0e31\u0e01\u0e02\u0e23\u0e30\u0e1e\u0e34\u0e40\u0e28\u0e29",
+"Source code": "\u0e42\u0e04\u0e49\u0e14\u0e15\u0e49\u0e19\u0e09\u0e1a\u0e31\u0e1a",
+"Right to left": "\u0e02\u0e27\u0e32\u0e44\u0e1b\u0e0b\u0e49\u0e32\u0e22",
+"Left to right": "\u0e0b\u0e49\u0e32\u0e22\u0e44\u0e1b\u0e02\u0e27\u0e32",
+"Emoticons": "\u0e2d\u0e34\u0e42\u0e21\u0e15\u0e34\u0e04\u0e2d\u0e19",
+"Robots": "\u0e2b\u0e38\u0e48\u0e19\u0e22\u0e19\u0e15\u0e4c",
+"Document properties": "\u0e04\u0e38\u0e13\u0e2a\u0e21\u0e1a\u0e31\u0e15\u0e34\u0e02\u0e2d\u0e07\u0e40\u0e2d\u0e01\u0e2a\u0e32\u0e23",
+"Title": "\u0e0a\u0e37\u0e48\u0e2d\u0e40\u0e23\u0e37\u0e48\u0e2d\u0e07",
+"Keywords": "\u0e04\u0e33\u0e2a\u0e33\u0e04\u0e31\u0e0d",
+"Encoding": "\u0e01\u0e32\u0e23\u0e40\u0e02\u0e49\u0e32\u0e23\u0e2b\u0e31\u0e2a",
+"Description": "\u0e04\u0e33\u0e2d\u0e18\u0e34\u0e1a\u0e32\u0e22",
+"Author": "\u0e1c\u0e39\u0e49\u0e40\u0e02\u0e35\u0e22\u0e19",
+"Fullscreen": "\u0e40\u0e15\u0e47\u0e21\u0e08\u0e2d",
+"Horizontal line": "\u0e40\u0e2a\u0e49\u0e19\u0e41\u0e19\u0e27\u0e19\u0e2d\u0e19",
+"Horizontal space": "\u0e0a\u0e48\u0e2d\u0e07\u0e27\u0e48\u0e32\u0e07\u0e41\u0e19\u0e27\u0e19\u0e2d\u0e19",
+"Insert\/edit image": "\u0e41\u0e17\u0e23\u0e01\/\u0e41\u0e01\u0e49\u0e44\u0e02\u0e23\u0e39\u0e1b",
+"General": "\u0e17\u0e31\u0e48\u0e27\u0e44\u0e1b",
+"Advanced": "\u0e02\u0e31\u0e49\u0e19\u0e2a\u0e39\u0e07",
+"Source": "\u0e41\u0e2b\u0e25\u0e48\u0e07\u0e17\u0e35\u0e48\u0e21\u0e32",
+"Border": "\u0e40\u0e2a\u0e49\u0e19\u0e02\u0e2d\u0e1a",
+"Constrain proportions": "\u0e08\u0e33\u0e01\u0e31\u0e14\u0e2a\u0e31\u0e14\u0e2a\u0e48\u0e27\u0e19",
+"Vertical space": "\u0e0a\u0e48\u0e2d\u0e07\u0e27\u0e48\u0e32\u0e07\u0e41\u0e19\u0e27\u0e15\u0e31\u0e49\u0e07",
+"Image description": "\u0e04\u0e33\u0e2d\u0e18\u0e34\u0e1a\u0e32\u0e22\u0e23\u0e39\u0e1b",
+"Style": "\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a",
+"Dimensions": "\u0e02\u0e19\u0e32\u0e14",
+"Insert date\/time": "\u0e41\u0e17\u0e23\u0e01\u0e27\u0e31\u0e19\u0e17\u0e35\u0e48\/\u0e40\u0e27\u0e25\u0e32",
+"Url": "URL",
+"Text to display": "\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21\u0e17\u0e35\u0e48\u0e08\u0e30\u0e41\u0e2a\u0e14\u0e07",
+"Insert link": "\u0e41\u0e17\u0e23\u0e01\u0e25\u0e34\u0e07\u0e01\u0e4c",
+"New window": "\u0e40\u0e1b\u0e34\u0e14\u0e2b\u0e19\u0e49\u0e32\u0e15\u0e48\u0e32\u0e07\u0e43\u0e2b\u0e21\u0e48",
+"None": "\u0e44\u0e21\u0e48\u0e21\u0e35",
+"Target": "\u0e40\u0e1b\u0e49\u0e32\u0e2b\u0e21\u0e32\u0e22",
+"Insert\/edit link": "\u0e41\u0e17\u0e23\u0e01\/\u0e41\u0e01\u0e49\u0e44\u0e02\u0e25\u0e34\u0e07\u0e01\u0e4c",
+"Insert\/edit video": "\u0e41\u0e17\u0e23\u0e01\/\u0e41\u0e01\u0e49\u0e44\u0e02\u0e27\u0e34\u0e14\u0e35\u0e42\u0e2d",
+"Poster": "\u0e42\u0e1b\u0e2a\u0e40\u0e15\u0e2d\u0e23\u0e4c",
+"Alternative source": "\u0e41\u0e2b\u0e25\u0e48\u0e07\u0e17\u0e35\u0e48\u0e21\u0e32\u0e2a\u0e33\u0e23\u0e2d\u0e07",
+"Paste your embed code below:": "\u0e27\u0e32\u0e07\u0e42\u0e04\u0e49\u0e14\u0e1d\u0e31\u0e07\u0e15\u0e31\u0e27\u0e02\u0e2d\u0e07\u0e04\u0e38\u0e13\u0e14\u0e49\u0e32\u0e19\u0e25\u0e48\u0e32\u0e07:",
+"Insert video": "\u0e41\u0e17\u0e23\u0e01\u0e27\u0e34\u0e14\u0e35\u0e42\u0e2d",
+"Embed": "\u0e1d\u0e31\u0e07",
+"Nonbreaking space": "\u0e0a\u0e48\u0e2d\u0e07\u0e27\u0e48\u0e32\u0e07\u0e44\u0e21\u0e48\u0e41\u0e22\u0e01",
+"Page break": "\u0e15\u0e31\u0e27\u0e41\u0e1a\u0e48\u0e07\u0e2b\u0e19\u0e49\u0e32",
+"Preview": "\u0e41\u0e2a\u0e14\u0e07\u0e15\u0e31\u0e27\u0e2d\u0e22\u0e48\u0e32\u0e07",
+"Print": "\u0e1e\u0e34\u0e21\u0e1e\u0e4c",
+"Save": "\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01",
+"Could not find the specified string.": "\u0e44\u0e21\u0e48\u0e1e\u0e1a\u0e2a\u0e15\u0e23\u0e34\u0e07\u0e17\u0e35\u0e48\u0e23\u0e30\u0e1a\u0e38",
+"Replace": "\u0e41\u0e17\u0e19\u0e17\u0e35\u0e48",
+"Next": "\u0e16\u0e31\u0e14\u0e44\u0e1b",
+"Whole words": "\u0e17\u0e31\u0e49\u0e07\u0e04\u0e33",
+"Find and replace": "\u0e04\u0e49\u0e19\u0e2b\u0e32\u0e41\u0e25\u0e30\u0e41\u0e17\u0e19\u0e17\u0e35\u0e48",
+"Replace with": "\u0e41\u0e17\u0e19\u0e17\u0e35\u0e48\u0e14\u0e49\u0e27\u0e22",
+"Find": "\u0e04\u0e49\u0e19\u0e2b\u0e32",
+"Replace all": "\u0e41\u0e17\u0e19\u0e17\u0e35\u0e48\u0e17\u0e31\u0e49\u0e07\u0e2b\u0e21\u0e14",
+"Match case": "\u0e15\u0e23\u0e07\u0e15\u0e32\u0e21\u0e15\u0e31\u0e27\u0e1e\u0e34\u0e21\u0e1e\u0e4c\u0e43\u0e2b\u0e0d\u0e48-\u0e40\u0e25\u0e47\u0e01",
+"Prev": "\u0e01\u0e48\u0e2d\u0e19\u0e2b\u0e19\u0e49\u0e32",
+"Spellcheck": "\u0e15\u0e23\u0e27\u0e08\u0e01\u0e32\u0e23\u0e2a\u0e30\u0e01\u0e14",
+"Finish": "\u0e40\u0e2a\u0e23\u0e47\u0e08\u0e2a\u0e34\u0e49\u0e19",
+"Ignore all": "\u0e25\u0e30\u0e40\u0e27\u0e49\u0e19\u0e17\u0e31\u0e49\u0e07\u0e2b\u0e21\u0e14",
+"Ignore": "\u0e25\u0e30\u0e40\u0e27\u0e49\u0e19",
+"Insert row before": "\u0e41\u0e17\u0e23\u0e01\u0e41\u0e16\u0e27\u0e14\u0e49\u0e32\u0e19\u0e1a\u0e19",
+"Rows": "\u0e41\u0e16\u0e27",
+"Height": "\u0e04\u0e27\u0e32\u0e21\u0e2a\u0e39\u0e07",
+"Paste row after": "\u0e27\u0e32\u0e07\u0e41\u0e16\u0e27\u0e14\u0e49\u0e32\u0e19\u0e25\u0e48\u0e32\u0e07",
+"Alignment": "\u0e01\u0e32\u0e23\u0e08\u0e31\u0e14\u0e41\u0e19\u0e27",
+"Column group": "\u0e01\u0e25\u0e38\u0e48\u0e21\u0e04\u0e2d\u0e25\u0e31\u0e21\u0e19\u0e4c",
+"Row": "\u0e41\u0e16\u0e27",
+"Insert column before": "\u0e41\u0e17\u0e23\u0e01\u0e04\u0e2d\u0e25\u0e31\u0e21\u0e19\u0e4c\u0e02\u0e49\u0e32\u0e07\u0e2b\u0e19\u0e49\u0e32",
+"Split cell": "\u0e41\u0e22\u0e01\u0e40\u0e0b\u0e25\u0e25\u0e4c",
+"Cell padding": "\u0e0a\u0e48\u0e2d\u0e07\u0e27\u0e48\u0e32\u0e07\u0e20\u0e32\u0e22\u0e43\u0e19\u0e40\u0e0b\u0e25\u0e25\u0e4c",
+"Cell spacing": "\u0e0a\u0e48\u0e2d\u0e07\u0e27\u0e48\u0e32\u0e07\u0e23\u0e30\u0e2b\u0e27\u0e48\u0e32\u0e07\u0e40\u0e0b\u0e25\u0e25\u0e4c",
+"Row type": "\u0e0a\u0e19\u0e34\u0e14\u0e02\u0e2d\u0e07\u0e41\u0e16\u0e27",
+"Insert table": "\u0e41\u0e17\u0e23\u0e01\u0e15\u0e32\u0e23\u0e32\u0e07",
+"Body": "\u0e40\u0e19\u0e37\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21",
+"Caption": "\u0e1b\u0e49\u0e32\u0e22\u0e04\u0e33\u0e2d\u0e18\u0e34\u0e1a\u0e32\u0e22",
+"Footer": "\u0e2a\u0e48\u0e27\u0e19\u0e17\u0e49\u0e32\u0e22",
+"Delete row": "\u0e25\u0e1a\u0e41\u0e16\u0e27",
+"Paste row before": "\u0e27\u0e32\u0e07\u0e41\u0e16\u0e27\u0e14\u0e49\u0e32\u0e19\u0e1a\u0e19",
+"Scope": "\u0e02\u0e2d\u0e1a\u0e40\u0e02\u0e15",
+"Delete table": "\u0e25\u0e1a\u0e15\u0e32\u0e23\u0e32\u0e07",
+"Header cell": "\u0e40\u0e0b\u0e25\u0e25\u0e4c\u0e2a\u0e48\u0e27\u0e19\u0e2b\u0e31\u0e27",
+"Column": "\u0e04\u0e2d\u0e25\u0e31\u0e21\u0e19\u0e4c",
+"Cell": "\u0e40\u0e0b\u0e25\u0e25\u0e4c",
+"Header": "\u0e2a\u0e48\u0e27\u0e19\u0e2b\u0e31\u0e27",
+"Cell type": "\u0e0a\u0e19\u0e34\u0e14\u0e02\u0e2d\u0e07\u0e40\u0e0b\u0e25\u0e25\u0e4c",
+"Copy row": "\u0e04\u0e31\u0e14\u0e25\u0e2d\u0e01\u0e41\u0e16\u0e27",
+"Row properties": "\u0e04\u0e38\u0e13\u0e2a\u0e21\u0e1a\u0e31\u0e15\u0e34\u0e02\u0e2d\u0e07\u0e41\u0e16\u0e27",
+"Table properties": "\u0e04\u0e38\u0e13\u0e2a\u0e21\u0e1a\u0e31\u0e15\u0e34\u0e02\u0e2d\u0e07\u0e15\u0e32\u0e23\u0e32\u0e07",
+"Row group": "\u0e01\u0e25\u0e38\u0e48\u0e21\u0e41\u0e16\u0e27",
+"Right": "\u0e02\u0e27\u0e32",
+"Insert column after": "\u0e41\u0e17\u0e23\u0e01\u0e04\u0e2d\u0e25\u0e31\u0e21\u0e19\u0e4c\u0e02\u0e49\u0e32\u0e07\u0e2b\u0e25\u0e31\u0e07",
+"Cols": "\u0e04\u0e2d\u0e25\u0e31\u0e21\u0e19\u0e4c",
+"Insert row after": "\u0e41\u0e17\u0e23\u0e01\u0e41\u0e16\u0e27\u0e14\u0e49\u0e32\u0e19\u0e25\u0e48\u0e32\u0e07",
+"Width": "\u0e04\u0e27\u0e32\u0e21\u0e01\u0e27\u0e49\u0e32\u0e07",
+"Cell properties": "\u0e04\u0e38\u0e13\u0e2a\u0e21\u0e1a\u0e31\u0e15\u0e34\u0e02\u0e2d\u0e07\u0e40\u0e0b\u0e25\u0e25\u0e4c",
+"Left": "\u0e0b\u0e49\u0e32\u0e22",
+"Cut row": "\u0e15\u0e31\u0e14\u0e41\u0e16\u0e27",
+"Delete column": "\u0e25\u0e1a\u0e04\u0e2d\u0e25\u0e31\u0e21\u0e19\u0e4c",
+"Center": "\u0e01\u0e36\u0e48\u0e07\u0e01\u0e25\u0e32\u0e07",
+"Merge cells": "\u0e1c\u0e2a\u0e32\u0e19\u0e40\u0e0b\u0e25\u0e25\u0e4c",
+"Insert template": "\u0e41\u0e17\u0e23\u0e01\u0e41\u0e21\u0e48\u0e41\u0e1a\u0e1a",
+"Templates": "\u0e41\u0e21\u0e48\u0e41\u0e1a\u0e1a",
+"Background color": "\u0e2a\u0e35\u0e1e\u0e37\u0e49\u0e19\u0e2b\u0e25\u0e31\u0e07",
+"Text color": "\u0e2a\u0e35\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21",
+"Show blocks": "\u0e41\u0e2a\u0e14\u0e07\u0e1a\u0e25\u0e47\u0e2d\u0e01",
+"Show invisible characters": "\u0e41\u0e2a\u0e14\u0e07\u0e15\u0e31\u0e27\u0e2d\u0e31\u0e01\u0e29\u0e23\u0e17\u0e35\u0e48\u0e21\u0e2d\u0e07\u0e44\u0e21\u0e48\u0e40\u0e2b\u0e47\u0e19",
+"Words: {0}": "\u0e04\u0e33: {0}",
+"Insert": "\u0e41\u0e17\u0e23\u0e01",
+"File": "\u0e44\u0e1f\u0e25\u0e4c",
+"Edit": "\u0e41\u0e01\u0e49\u0e44\u0e02",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u0e1e\u0e37\u0e49\u0e19\u0e17\u0e35\u0e48 Rich Text \u0e01\u0e14 ALT-F9 \u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e40\u0e21\u0e19\u0e39 \u0e01\u0e14 ALT-F10 \u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e41\u0e16\u0e1a\u0e40\u0e04\u0e23\u0e37\u0e48\u0e2d\u0e07\u0e21\u0e37\u0e2d \u0e01\u0e14 ALT-0 \u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e04\u0e27\u0e32\u0e21\u0e0a\u0e48\u0e27\u0e22\u0e40\u0e2b\u0e25\u0e37\u0e2d",
+"Tools": "\u0e40\u0e04\u0e23\u0e37\u0e48\u0e2d\u0e07\u0e21\u0e37\u0e2d",
+"View": "\u0e21\u0e38\u0e21\u0e21\u0e2d\u0e07",
+"Table": "\u0e15\u0e32\u0e23\u0e32\u0e07",
+"Format": "\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/tr_TR.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/tr_TR.js
new file mode 100755
index 0000000..9ca6142
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/tr_TR.js
@@ -0,0 +1,174 @@
+tinymce.addI18n('tr_TR',{
+"Cut": "Kes",
+"Header 2": "Ba\u015fl\u0131k 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Taray\u0131c\u0131n\u0131z panoya direk eri\u015fimi desteklemiyor. L\u00fctfen Ctrl+X\/C\/V klavye k\u0131sayollar\u0131n\u0131 kullan\u0131n.",
+"Div": "Div",
+"Paste": "Yap\u0131\u015ft\u0131r",
+"Close": "Kapat",
+"Pre": "\u00d6n",
+"Align right": "Sa\u011fa hizala",
+"New document": "Yeni dok\u00fcman",
+"Blockquote": "Al\u0131nt\u0131",
+"Numbered list": "S\u0131ral\u0131 liste",
+"Increase indent": "Girintiyi art\u0131r",
+"Formats": "Bi\u00e7imler",
+"Headers": "Ba\u015fl\u0131klar",
+"Select all": "T\u00fcm\u00fcn\u00fc se\u00e7",
+"Header 3": "Ba\u015fl\u0131k 3",
+"Blocks": "Engeller",
+"Undo": "Geri Al",
+"Strikethrough": "\u00dcst\u00fc \u00e7izili",
+"Bullet list": "S\u0131ras\u0131z liste",
+"Header 1": "Ba\u015fl\u0131k 1",
+"Superscript": "\u00dcst simge",
+"Clear formatting": "Bi\u00e7imi temizle",
+"Subscript": "Alt simge",
+"Header 6": "Ba\u015fl\u0131k 6",
+"Redo": "Yinele",
+"Paragraph": "Paragraf",
+"Ok": "Tamam",
+"Bold": "Kal\u0131n",
+"Code": "Kod",
+"Italic": "\u0130talik",
+"Align center": "Ortala",
+"Header 5": "Ba\u015fl\u0131k 5",
+"Decrease indent": "Girintiyi azalt",
+"Header 4": "Ba\u015fl\u0131k 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "D\u00fcz metin modunda yap\u0131\u015ft\u0131r. Bu se\u00e7ene\u011fi kapatana kadar i\u00e7erikler d\u00fcz metin olarak yap\u0131\u015ft\u0131r\u0131l\u0131r.",
+"Underline": "Alt\u0131 \u00e7izili",
+"Cancel": "\u0130ptal",
+"Justify": "\u0130ki yana yasla",
+"Inline": "Sat\u0131r i\u00e7i",
+"Copy": "Kopyala",
+"Align left": "Sola hizala",
+"Visual aids": "G\u00f6rsel ara\u00e7lar",
+"Lower Greek": "K\u00fc\u00e7\u00fck Yunan alfabesi",
+"Square": "Kare",
+"Default": "Varsay\u0131lan",
+"Lower Alpha": "K\u00fc\u00e7\u00fck ABC",
+"Circle": "Daire",
+"Disc": "Disk",
+"Upper Alpha": "B\u00fcy\u00fck ABC",
+"Upper Roman": "B\u00fcy\u00fck Roman alfabesi",
+"Lower Roman": "K\u00fc\u00e7\u00fck Roman alfabesi",
+"Name": "\u0130sim",
+"Anchor": "\u00c7apa",
+"You have unsaved changes are you sure you want to navigate away?": "Kaydedilmemi\u015f de\u011fi\u015fiklikler var, sayfadan ayr\u0131lmak istedi\u011finize emin misiniz?",
+"Restore last draft": "Son tasla\u011f\u0131 kurtar",
+"Special character": "\u00d6zel karakter",
+"Source code": "Kaynak kodu",
+"Right to left": "Sa\u011fdan sola",
+"Left to right": "Soldan sa\u011fa",
+"Emoticons": "G\u00fcl\u00fcc\u00fckler",
+"Robots": "Robotlar",
+"Document properties": "Dok\u00fcman \u00f6zellikleri",
+"Title": "Ba\u015fl\u0131k",
+"Keywords": "Anahtar kelimeler",
+"Encoding": "Kodlama",
+"Description": "A\u00e7\u0131klama",
+"Author": "Yazar",
+"Fullscreen": "Tam ekran",
+"Horizontal line": "Yatay \u00e7izgi",
+"Horizontal space": "Yatay bo\u015fluk",
+"Insert\/edit image": "Resim ekle\/d\u00fczenle",
+"General": "Genel",
+"Advanced": "Geli\u015fmi\u015f",
+"Source": "Kaynak",
+"Border": "\u00c7er\u00e7eve",
+"Constrain proportions": "En - Boy oran\u0131n\u0131 koru",
+"Vertical space": "Dikey bo\u015fluk",
+"Image description": "Resim a\u00e7\u0131klamas\u0131",
+"Style": "Stil",
+"Dimensions": "Boyutlar",
+"Insert image": "Resim ekle",
+"Insert date\/time": "Tarih \/ Zaman ekle",
+"Remove link": "Ba\u011flant\u0131y\u0131 kald\u0131r",
+"Url": "Url",
+"Text to display": "G\u00f6r\u00fcnen yaz\u0131",
+"Anchors": "\u00c7apalar",
+"Insert link": "Ba\u011flant\u0131 ekle",
+"New window": "Yeni pencere",
+"None": "Hi\u00e7biri",
+"Target": "Hedef",
+"Insert\/edit link": "Ba\u011flant\u0131 ekle\/d\u00fczenle",
+"Insert\/edit video": "Video ekle\/d\u00fczenle",
+"Poster": "Poster",
+"Alternative source": "Alternatif kaynak",
+"Paste your embed code below:": "Medya g\u00f6mme kodunu buraya yap\u0131\u015ft\u0131r:",
+"Insert video": "Video ekle",
+"Embed": "G\u00f6mme",
+"Nonbreaking space": "B\u00f6l\u00fcnemez bo\u015fluk",
+"Page break": "Sayfa sonu",
+"Preview": "\u00d6nizleme",
+"Print": "Yazd\u0131r",
+"Save": "Kaydet",
+"Could not find the specified string.": "Herhangi bir sonu\u00e7 bulunamad\u0131.",
+"Replace": "De\u011fi\u015ftir",
+"Next": "Sonraki",
+"Whole words": "Tam s\u00f6zc\u00fckler",
+"Find and replace": "Bul ve de\u011fi\u015ftir",
+"Replace with": "Bununla de\u011fi\u015ftir",
+"Find": "Bul",
+"Replace all": "T\u00fcm\u00fcn\u00fc de\u011fi\u015ftir",
+"Match case": "B\u00fcy\u00fck \/ K\u00fc\u00e7\u00fck harfe duyarl\u0131",
+"Prev": "\u00d6nceki",
+"Spellcheck": "Yaz\u0131m denetimi",
+"Finish": "Bitir",
+"Ignore all": "T\u00fcm\u00fcn\u00fc yoksay",
+"Ignore": "Yoksay",
+"Insert row before": "\u00d6ncesine yeni sat\u0131r ekle",
+"Rows": "Sat\u0131rlar",
+"Height": "Y\u00fckseklik",
+"Paste row after": "Sonras\u0131na sat\u0131r yap\u0131\u015ft\u0131r",
+"Alignment": "Hizalama",
+"Column group": "S\u00fctun grubu",
+"Row": "Sat\u0131r",
+"Insert column before": "\u00d6ncesine yeni s\u00fctun ekle",
+"Split cell": "H\u00fccreleri ay\u0131r",
+"Cell padding": "H\u00fccre i\u00e7 bo\u015flu\u011fu",
+"Cell spacing": "H\u00fccre aral\u0131\u011f\u0131",
+"Row type": "Sat\u0131r tipi",
+"Insert table": "Tablo ekle",
+"Body": "G\u00f6vde",
+"Caption": "Ba\u015fl\u0131k",
+"Footer": "Alt",
+"Delete row": "Sat\u0131r\u0131 sil",
+"Paste row before": "\u00d6ncesine sat\u0131r yap\u0131\u015ft\u0131r",
+"Scope": "Kapsam",
+"Delete table": "Tabloyu sil",
+"Header cell": "Ba\u015fl\u0131k h\u00fccresi",
+"Column": "S\u00fctun",
+"Cell": "H\u00fccre",
+"Header": "Ba\u015fl\u0131k",
+"Cell type": "H\u00fccre tipi",
+"Copy row": "Sat\u0131r\u0131 kopyala",
+"Row properties": "Sat\u0131r \u00f6zellikleri",
+"Table properties": "Tablo \u00f6zellikleri",
+"Row group": "Sat\u0131r grubu",
+"Right": "Sa\u011f",
+"Insert column after": "Sonras\u0131na yeni s\u00fctun ekle",
+"Cols": "S\u00fctunlar",
+"Insert row after": "Sonras\u0131na yeni sat\u0131r ekle",
+"Width": "Geni\u015flik",
+"Cell properties": "H\u00fccre \u00f6zellikleri",
+"Left": "Sol",
+"Cut row": "Sat\u0131r\u0131 kes",
+"Delete column": "S\u00fctunu sil",
+"Center": "Orta",
+"Merge cells": "H\u00fccreleri birle\u015ftir",
+"Insert template": "\u015eablon ekle",
+"Templates": "\u015eablonlar",
+"Background color": "Arkaplan rengi",
+"Text color": "Yaz\u0131 rengi",
+"Show blocks": "Bloklar\u0131 g\u00f6r\u00fcnt\u00fcle",
+"Show invisible characters": "G\u00f6r\u00fcnmez karakterleri g\u00f6ster",
+"Words: {0}": "Kelime: {0}",
+"Insert": "Ekle",
+"File": "Dosya",
+"Edit": "D\u00fczenle",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Zengin Metin Alan\u0131. Men\u00fc i\u00e7in ALT-F9 k\u0131sayolunu kullan\u0131n. Ara\u00e7 \u00e7ubu\u011fu i\u00e7in ALT-F10 k\u0131sayolunu kullan\u0131n. Yard\u0131m i\u00e7in ALT-0 k\u0131sayolunu kullan\u0131n.",
+"Tools": "Ara\u00e7lar",
+"View": "G\u00f6r\u00fcnt\u00fcle",
+"Table": "Tablo",
+"Format": "Bi\u00e7im"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ug.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ug.js
new file mode 100755
index 0000000..b4bd955
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/ug.js
@@ -0,0 +1,156 @@
+tinymce.addI18n('ug',{
+"Cut": "\u0643\u06d0\u0633\u0649\u0634",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u0633\u0649\u0632\u0646\u0649\u06ad \u062a\u0648\u0631 \u0643\u06c6\u0631\u06af\u06c8\u0686\u0649\u06ad\u0649\u0632 \u0642\u0649\u064a\u0649\u067e \u0686\u0627\u067e\u0644\u0627\u0634 \u062a\u0627\u062e\u062a\u0649\u0633\u0649 \u0632\u0649\u064a\u0627\u0631\u06d5\u062a \u0642\u0649\u0644\u0649\u0634\u0646\u0649 \u0642\u0648\u0644\u0644\u0649\u0645\u0627\u064a\u062f\u06c7. Ctrl+X\/C\/V \u062a\u06d0\u0632\u0644\u06d5\u062a\u0645\u06d5 \u0643\u0648\u0646\u06c7\u067e\u0643\u0649\u0633\u0649 \u0626\u0627\u0631\u0642\u0649\u0644\u0649\u0642 \u0643\u06d0\u0633\u0649\u067e \u0686\u0627\u067e\u0644\u0627\u0634 \u0645\u06d5\u0634\u063a\u06c7\u0644\u0627\u062a\u0649 \u0642\u0649\u0644\u0649\u06ad.",
+"Paste": "\u0686\u0627\u067e\u0644\u0627\u0634",
+"Close": "\u062a\u0627\u0642\u0627\u0634",
+"Align right": "\u0626\u0648\u06ad\u063a\u0627 \u062a\u0648\u063a\u06c7\u0631\u0644\u0627\u0634",
+"New document": "\u064a\u06d0\u06ad\u0649 \u06be\u06c6\u062c\u062c\u06d5\u062a \u0642\u06c7\u0631\u06c7\u0634",
+"Numbered list": "\u0633\u0627\u0646\u0644\u0649\u0642 \u062a\u0649\u0632\u0649\u0645\u0644\u0649\u0643",
+"Increase indent": "\u0643\u06d5\u064a\u0646\u0649\u06af\u06d5 \u0633\u06c8\u0631\u06c8\u0634",
+"Formats": "\u0641\u0648\u0631\u0645\u0627\u062a",
+"Select all": "\u06be\u06d5\u0645\u0645\u0649\u0646\u0649 \u062a\u0627\u0644\u0644\u0627\u0634",
+"Undo": "\u0626\u0627\u0631\u0642\u0649\u063a\u0627 \u064a\u06d0\u0646\u0649\u0634",
+"Strikethrough": "\u0626\u06c6\u0686\u06c8\u0631\u06c8\u0634 \u0633\u0649\u0632\u0649\u0642\u0649",
+"Bullet list": "\u0628\u06d5\u0644\u06af\u06d5 \u062a\u0649\u0632\u0649\u0645\u0644\u0649\u0643",
+"Superscript": "\u0626\u06c8\u0633\u062a\u06c8\u0646\u0643\u0649 \u0628\u06d5\u0644\u06af\u06d5",
+"Clear formatting": "\u0641\u0648\u0631\u0645\u0627\u062a\u0646\u0649 \u062a\u0627\u0632\u0644\u0627\u0634",
+"Subscript": "\u0626\u0627\u0633\u062a\u0649\u0646\u0642\u0649 \u0628\u06d5\u0644\u06af\u06d5",
+"Redo": "\u0642\u0627\u064a\u062a\u0627 \u0642\u0649\u0644\u0649\u0634",
+"Ok": "\u062c\u06d5\u0632\u0649\u0645\u0644\u06d5\u0634",
+"Bold": "\u062a\u0648\u0645",
+"Italic": "\u064a\u0627\u0646\u062a\u06c7",
+"Align center": "\u0645\u06d5\u0631\u0643\u06d5\u0632\u06af\u06d5 \u062a\u0648\u063a\u06c7\u0631\u0644\u0627\u0634",
+"Decrease indent": "\u0626\u0627\u0644\u062f\u0649\u063a\u0627 \u0633\u06c8\u0631\u06c8\u0634",
+"Underline": "\u0626\u0627\u0633\u062a\u0649 \u0633\u0649\u0632\u0649\u0642",
+"Cancel": "\u0642\u0627\u0644\u062f\u06c7\u0631\u06c7\u0634",
+"Justify": "\u0626\u0649\u0643\u0643\u0649 \u064a\u0627\u0646\u063a\u0627 \u062a\u0648\u063a\u06c7\u0631\u0644\u0627\u0634",
+"Copy": "\u0643\u06c6\u0686\u06c8\u0631\u06c8\u0634",
+"Align left": "\u0633\u0648\u0644\u063a\u0627 \u062a\u0648\u063a\u0631\u0649\u0644\u0627\u0634",
+"Visual aids": "\u0626\u06d5\u0633\u0643\u06d5\u0631\u062a\u0649\u0634",
+"Lower Greek": "\u06af\u0631\u06d0\u062a\u0633\u0649\u064a\u0649\u0686\u06d5 \u0643\u0649\u0686\u0649\u0643 \u064a\u06d0\u0632\u0649\u0644\u0649\u0634\u0649",
+"Square": "\u0643\u06cb\u0627\u062f\u0631\u0627\u062a",
+"Default": "\u0633\u06c8\u0643\u06c8\u062a",
+"Lower Alpha": "\u0626\u0649\u0646\u06af\u0649\u0644\u0649\u0632\u0686\u06d5 \u0643\u0649\u0686\u0649\u0643 \u064a\u06d0\u0632\u0649\u0644\u0649\u0634\u0649",
+"Circle": "\u0686\u06d5\u0645\u0628\u06d5\u0631",
+"Disc": "\u062f\u06d0\u0633\u0643\u0627",
+"Upper Alpha": "\u0626\u0649\u0646\u06af\u0649\u0644\u0649\u0632\u0686\u06d5 \u0686\u0648\u06ad \u064a\u06d0\u0632\u0649\u0644\u0649\u0634\u0649",
+"Upper Roman": "\u0631\u0649\u0645\u0686\u06d5 \u0686\u0648\u06ad \u064a\u06d0\u0632\u0649\u0644\u0649\u0634\u0649",
+"Lower Roman": "\u0631\u0649\u0645\u0686\u06d5 \u0643\u0649\u0686\u0649\u0643 \u064a\u06d0\u0632\u0649\u0644\u0649\u0634\u0649",
+"Name": "\u0646\u0627\u0645\u0649",
+"Anchor": "\u0626\u06c7\u0644\u0627\u0646\u0645\u0627",
+"You have unsaved changes are you sure you want to navigate away?": "\u0633\u0649\u0632 \u062a\u06d0\u062e\u0649 \u0645\u06d5\u0632\u0645\u06c7\u0646\u0646\u0649 \u0633\u0627\u0642\u0644\u0649\u0645\u0649\u062f\u0649\u06ad\u0649\u0632\u060c \u0626\u0627\u064a\u0631\u0649\u0644\u0627\u0645\u0633\u0649\u0632\u061f",
+"Restore last draft": "\u0626\u0627\u062e\u0649\u0631\u0642\u0649 \u0643\u06c7\u067e\u0649\u064a\u0649\u06af\u06d5 \u0642\u0627\u064a\u062a\u0649\u0634",
+"Special character": "\u0626\u0627\u0644\u0627\u06be\u0649\u062f\u06d5 \u0628\u06d5\u0644\u06af\u0649\u0644\u06d5\u0631",
+"Source code": "\u0626\u06d5\u0633\u0644\u0649 \u0643\u0648\u062f\u0649",
+"Right to left": "\u0626\u0648\u06ad\u062f\u0649\u0646 \u0633\u0648\u0644\u063a\u0627",
+"Left to right": "\u0633\u0648\u0644\u062f\u0649\u0646 \u0626\u0648\u06ad\u063a\u0627 ",
+"Emoticons": "\u0686\u0649\u0631\u0627\u064a \u0626\u0649\u067e\u0627\u062f\u06d5",
+"Robots": "\u0645\u0627\u0634\u0649\u0646\u0627 \u0626\u0627\u062f\u06d5\u0645",
+"Document properties": "\u06be\u06c6\u062c\u062c\u06d5\u062a \u062e\u0627\u0633\u0644\u0649\u0642\u0649",
+"Title": "\u062a\u06d0\u0645\u0627",
+"Keywords": "\u06be\u0627\u0644\u0642\u0649\u0644\u0649\u0642 \u0633\u06c6\u0632",
+"Encoding": "\u0643\u0648\u062f\u0644\u0627\u0634",
+"Description": "\u062a\u06d5\u0633\u0649\u06cb\u0649\u0631",
+"Author": "\u0626\u06c7\u0644\u0627\u0646\u0645\u0627",
+"Fullscreen": "\u067e\u06c8\u062a\u06c8\u0646 \u0626\u06d0\u0643\u0631\u0627\u0646",
+"Horizontal line": "\u06af\u0648\u0631\u0632\u0649\u0646\u062a\u0627\u0644 \u0642\u06c7\u0631",
+"Horizontal space": "\u06af\u0648\u0631\u0632\u0649\u0646\u062a\u0627\u0644 \u0628\u0648\u0634\u0644\u06c7\u0642",
+"Insert\/edit image": "\u0631\u06d5\u0633\u0649\u0645 \u0642\u0649\u0633\u062a\u06c7\u0631\u06c7\u0634 \u064a\u0627\u0643\u0649 \u062a\u06d5\u06be\u0631\u0649\u0631\u0644\u06d5\u0634",
+"General": "\u0626\u0627\u062f\u06d5\u062a\u062a\u0649\u0643\u0649",
+"Advanced": "\u0626\u0627\u0644\u0627\u06be\u0649\u062f\u06d5",
+"Source": "\u0645\u06d5\u0646\u0628\u06d5",
+"Border": "\u064a\u0627\u0642\u0627",
+"Constrain proportions": "\u0626\u06d0\u06af\u0649\u0632\u0644\u0649\u0643-\u0643\u06d5\u06ad\u0644\u0649\u0643 \u0646\u0649\u0633\u067e\u0649\u062a\u0649\u0646\u0649 \u0633\u0627\u0642\u0644\u0627\u0634",
+"Vertical space": "\u06cb\u06d0\u0631\u062a\u0649\u0643\u0627\u0644 \u0628\u0648\u0634\u0644\u06c7\u0642",
+"Image description": "\u0631\u06d5\u0633\u0649\u0645 \u062a\u06d5\u0633\u06cb\u0649\u0631\u0649",
+"Style": "\u0626\u06c7\u0633\u0644\u06c7\u067e",
+"Dimensions": "\u0686\u0648\u06ad-\u0643\u0649\u0686\u0649\u0643",
+"Insert date\/time": "\u0686\u0649\u0633\u0644\u0627\/\u06cb\u0627\u0642\u0649\u062a \u0643\u0649\u0631\u06af\u06c8\u0632\u06c8\u0634",
+"Url": "\u0626\u0627\u062f\u0631\u0649\u0633",
+"Text to display": "\u0643\u06c6\u0631\u06c8\u0646\u0649\u062f\u0649\u063a\u0627\u0646 \u0645\u06d5\u0632\u0645\u06c7\u0646",
+"Insert link": "\u0626\u06c7\u0644\u0649\u0646\u0649\u0634 \u0642\u0649\u0633\u062a\u06c7\u0631\u06c7\u0634",
+"New window": "\u064a\u06d0\u06ad\u0649 \u0643\u06c6\u0632\u0646\u06d5\u0643",
+"None": "\u064a\u0648\u0642",
+"Target": "\u0646\u0649\u0634\u0627\u0646",
+"Insert\/edit link": "\u0626\u06c7\u0644\u0649\u0646\u0649\u0634 \u0642\u06c7\u0633\u062a\u06c7\u0631\u06c7\u0634\/\u062a\u06d5\u06be\u0631\u0649\u0631\u0644\u06d5\u0634",
+"Insert\/edit video": "\u0633\u0649\u0646 \u0642\u0649\u0633\u062a\u06c7\u0631\u06c7\u0634\/\u062a\u06d5\u06be\u0631\u0649\u0631\u0644\u06d5\u0634",
+"Poster": "\u064a\u0648\u0644\u0644\u0649\u063a\u06c7\u0686\u0649",
+"Alternative source": "\u062a\u06d5\u0633\u06cb\u0649\u0631\u0649",
+"Paste your embed code below:": "\u0642\u0649\u0633\u062a\u06c7\u0631\u0645\u0627\u0642\u0686\u0649 \u0628\u0648\u0644\u063a\u0627\u0646 \u0643\u0648\u062f\u0646\u0649 \u0686\u0627\u067e\u0644\u0627\u06ad",
+"Insert video": "\u0633\u0649\u0646 \u0642\u0649\u0633\u062a\u06c7\u0631\u06c7\u0634",
+"Embed": "\u0642\u0649\u0633\u062a\u06c7\u0631\u06c7\u0634",
+"Nonbreaking space": "\u0628\u0648\u0634\u0644\u06c7\u0642",
+"Page break": "\u0628\u06d5\u062a \u0626\u0627\u062e\u0649\u0631\u0644\u0627\u0634\u062a\u06c7\u0631\u06c7\u0634",
+"Preview": "\u0643\u06c6\u0631\u06c8\u0634",
+"Print": "\u0628\u0627\u0633\u0645\u0627\u0642 ",
+"Save": "\u0633\u0627\u0642\u0644\u0627\u0634",
+"Could not find the specified string.": "\u0626\u0649\u0632\u062f\u0649\u0645\u06d5\u0643\u0686\u0649 \u0628\u0648\u0644\u063a\u0627\u0646 \u0645\u06d5\u0632\u0645\u06c7\u0646\u0646\u0649 \u062a\u0627\u067e\u0627\u0644\u0645\u0649\u062f\u0649.",
+"Replace": "\u0626\u0627\u0644\u0645\u0627\u0634\u062a\u06c7\u0631\u06c7\u0634",
+"Next": "\u0643\u06d0\u064a\u0649\u0646\u0643\u0649\u0633\u0649",
+"Whole words": "\u062a\u0648\u0644\u06c7\u0642 \u0645\u0627\u0633\u0644\u0627\u0634\u062a\u06c7\u0631\u06c7\u0634",
+"Find and replace": "\u0626\u0649\u0632\u062f\u06d5\u0634 \u06cb\u06d5 \u0626\u0627\u0644\u0645\u0627\u0634\u062a\u06c7\u0631\u06c7\u0634",
+"Replace with": "\u0626\u0627\u0644\u0645\u0627\u0634\u062a\u06c7\u0631\u06c7\u0634",
+"Find": "\u0626\u0649\u0632\u062f\u06d5\u0634",
+"Replace all": "\u06be\u06d5\u0645\u0645\u0649\u0646\u0649 \u0626\u0627\u0644\u0645\u0627\u0634\u062a\u06c7\u0631\u06c7\u0634",
+"Match case": "\u0686\u0648\u06ad \u0643\u0649\u0686\u0649\u0643 \u06be\u06d5\u0631\u0649\u067e\u0646\u0649 \u067e\u06d5\u0631\u0649\u0642\u0644\u06d5\u0646\u062f\u06c8\u0631\u06c8\u0634",
+"Prev": "\u0626\u0627\u0644\u062f\u0649\u0646\u0642\u0649\u0633\u0649",
+"Spellcheck": "\u0626\u0649\u0645\u0644\u0627 \u062a\u06d5\u0643\u0634\u06c8\u0631\u06c8\u0634",
+"Finish": "\u0626\u0627\u062e\u0649\u0631\u0644\u0627\u0634\u062a\u06c7\u0631\u06c7\u0634",
+"Ignore all": "\u06be\u06d5\u0645\u0645\u0649\u0646\u0649 \u0626\u06c6\u062a\u0643\u06c8\u0632\u06c8\u0634",
+"Ignore": "\u0626\u06c6\u062a\u0643\u06c8\u0632\u06c8\u0634",
+"Insert row before": "\u0626\u0627\u0644\u062f\u0649\u063a\u0627 \u0642\u06c7\u0631 \u0642\u0649\u0633\u062a\u06c7\u0631\u06c7\u0634",
+"Rows": "\u0642\u06c7\u0631",
+"Height": "\u0626\u06d0\u06af\u0649\u0632\u0644\u0649\u0643\u0649",
+"Paste row after": "\u0642\u06c7\u0631 \u0643\u06d5\u064a\u0646\u0649\u06af\u06d5 \u0686\u0627\u067e\u0644\u0627\u0634",
+"Alignment": "\u064a\u06c6\u0644\u0649\u0646\u0649\u0634\u0649",
+"Column group": "\u0631\u06d5\u062a \u06af\u06c7\u0631\u06c7\u067e\u067e\u0649\u0633\u0649",
+"Row": "\u0642\u06c7\u0631",
+"Insert column before": "\u0631\u06d5\u062a \u0626\u0627\u0644\u062f\u0649\u063a\u0627 \u0642\u0649\u0633\u062a\u06c7\u0631\u06c7\u0634",
+"Split cell": "\u0643\u0627\u062a\u06d5\u0643 \u067e\u0627\u0631\u0686\u0649\u0644\u0627\u0634",
+"Cell padding": "\u0643\u0627\u062a\u06d5\u0643 \u0626\u0649\u0686\u0643\u0649 \u0626\u0627\u0631\u0649\u0644\u0649\u0642\u0649",
+"Cell spacing": "\u0643\u0627\u062a\u06d5\u0643 \u0633\u0649\u0631\u062a\u0642\u0649 \u0626\u0627\u0631\u0649\u0644\u0649\u0642\u0649",
+"Row type": "\u0642\u06c7\u0631 \u062a\u0649\u067e\u0649",
+"Insert table": "\u062c\u06d5\u062f\u06cb\u06d5\u0644 \u0642\u0649\u0633\u062a\u06c7\u0631\u06c7\u0634",
+"Body": "\u0628\u06d5\u062f\u0649\u0646\u0649",
+"Caption": "\u0686\u06c8\u0634\u06d5\u0646\u062f\u06c8\u0631\u06c8\u0634",
+"Footer": "\u067e\u06c7\u062a\u0649",
+"Delete row": "\u0642\u06c7\u0631 \u0626\u06c6\u0686\u06c8\u0631\u06c8\u0634",
+"Paste row before": "\u0642\u06c7\u0631 \u0626\u0627\u0644\u062f\u0649\u063a\u0627 \u0686\u0627\u067e\u0644\u0627\u0634",
+"Scope": "\u062f\u0627\u0626\u0649\u0631\u06d5",
+"Delete table": "\u062c\u06d5\u062f\u06cb\u06d5\u0644 \u0626\u06c6\u0686\u06c8\u0631\u0634",
+"Header cell": "\u0628\u0627\u0634 \u0643\u0627\u062a\u06d5\u0643",
+"Column": "\u0631\u06d5\u062a",
+"Cell": "\u0643\u0627\u062a\u06d5\u0643",
+"Header": "\u0628\u06d0\u0634\u0649",
+"Cell type": "\u0643\u0627\u062a\u06d5\u0643 \u062a\u0649\u067e\u0649",
+"Copy row": "\u0642\u06c7\u0631 \u0643\u06c6\u0686\u06c8\u0631\u06c8\u0634",
+"Row properties": "\u0642\u06c7\u0631 \u062e\u0627\u0633\u0644\u0649\u0642\u0649",
+"Table properties": "\u062c\u06d5\u062f\u06cb\u06d5\u0644 \u062e\u0627\u0633\u0644\u0649\u0642\u0649",
+"Row group": "\u0642\u06c7\u0631 \u06af\u06c7\u0631\u06c7\u067e\u067e\u0649\u0633\u0649",
+"Right": "\u0626\u0648\u06ad",
+"Insert column after": "\u0631\u06d5\u062a \u0643\u06d5\u064a\u0646\u0649\u06af\u06d5 \u0642\u0649\u0633\u062a\u06c7\u0631\u06c7\u0634",
+"Cols": "\u0631\u06d5\u062a",
+"Insert row after": "\u0626\u0627\u0631\u0642\u0649\u063a\u0627 \u0642\u06c7\u0631 \u0642\u0649\u0633\u062a\u06c7\u0631\u06c7\u0634",
+"Width": "\u0643\u06d5\u06ad\u0644\u0649\u0643\u0649",
+"Cell properties": "\u0643\u0627\u062a\u06d5\u0643 \u062e\u0627\u0633\u0644\u0649\u0642\u0649",
+"Left": "\u0633\u0648\u0644",
+"Cut row": "\u0642\u06c7\u0631 \u0643\u06d0\u0633\u0649\u0634",
+"Delete column": "\u0631\u06d5\u062a \u0626\u06c6\u0686\u06c8\u0631\u06c8\u0634",
+"Center": "\u0645\u06d5\u0631\u0643\u06d5\u0632",
+"Merge cells": "\u0643\u0627\u062a\u06d5\u0643 \u0628\u0649\u0631\u0644\u06d5\u0634\u062a\u06c8\u0631\u06c8\u0634",
+"Insert template": "\u0626\u06c8\u0644\u06af\u06d5 \u0642\u0649\u0633\u062a\u06c7\u0631\u06c7\u0634",
+"Templates": "\u0626\u06c8\u0644\u06af\u0649\u0644\u06d5\u0631",
+"Background color": "\u0626\u0627\u0631\u0642\u0627 \u0631\u06d5\u06ad\u06af\u0649",
+"Text color": "\u062e\u06d5\u062a \u0631\u06d5\u06ad\u06af\u0649",
+"Show blocks": "\u0631\u0627\u064a\u0648\u0646 \u0643\u06c6\u0631\u0633\u0649\u062a\u0649\u0634",
+"Show invisible characters": "\u0643\u06c6\u0631\u06c8\u0646\u0645\u06d5\u064a\u062f\u0649\u063a\u0627\u0646 \u06be\u06d5\u0631\u0649\u067e\u0644\u06d5\u0631\u0646\u0649 \u0643\u06c6\u0631\u0633\u0649\u062a\u0649\u0634",
+"Words: {0}": "\u0633\u06c6\u0632: {0}",
+"Insert": "\u0642\u0649\u0633\u062a\u06c7\u0631\u06c7\u0634",
+"File": "\u06be\u06c6\u062c\u062c\u06d5\u062a",
+"Edit": "\u062a\u06d5\u06be\u0631\u0649\u0631\u0644\u06d5\u0634",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help",
+"Tools": "\u0642\u06c7\u0631\u0627\u0644",
+"View": "\u0643\u06c6\u0631\u06c8\u0634",
+"Table": "\u062c\u06d5\u062f\u06cb\u06d5\u0644",
+"Format": "\u0641\u0648\u0631\u0645\u0627\u062a"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/uk.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/uk.js
new file mode 100755
index 0000000..d8fccd3
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/uk.js
@@ -0,0 +1,159 @@
+tinymce.addI18n('uk',{
+"Cut": "\u0412\u0438\u0440\u0456\u0437\u0430\u0442\u0438",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u0412\u0430\u0448 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043d\u0435 \u043f\u0456\u0434\u0442\u0440\u0438\u043c\u0443\u0454 \u043f\u0440\u044f\u043c\u0438\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u043e \u0431\u0443\u0444\u0435\u0440\u0443 \u043e\u0431\u043c\u0456\u043d\u0443. \u0411\u0443\u0434\u044c \u043b\u0430\u0441\u043a\u0430, \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0439\u0442\u0435 Ctrl+X\/C\/V \u0437\u0430\u043c\u0456\u0441\u0442\u044c \u0441\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044f \u043a\u043b\u0430\u0432\u0456\u0448.",
+"Paste": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438",
+"Close": "\u0417\u0430\u043a\u0440\u0438\u0442\u0438",
+"Align right": "\u041f\u043e \u043f\u0440\u0430\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e",
+"New document": "\u041d\u043e\u0432\u0438\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442",
+"Numbered list": "\u041d\u0443\u043c\u0435\u0440\u043e\u0432\u0430\u043d\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a",
+"Increase indent": "\u0417\u0431\u0456\u043b\u044c\u0448\u0438\u0442\u0438 \u0432\u0456\u0434\u0441\u0442\u0443\u043f",
+"Formats": "\u0424\u043e\u0440\u043c\u0430\u0442\u0438",
+"Select all": "\u0412\u0438\u0434\u0456\u043b\u0438\u0442\u0438 \u0432\u0441\u0435",
+"Undo": "\u0412\u0456\u0434\u043c\u0456\u043d\u0438\u0442\u0438",
+"Strikethrough": "\u0417\u0430\u043a\u0440\u0435\u0441\u043b\u0435\u043d\u0438\u0439",
+"Bullet list": "\u041d\u0435\u043d\u0443\u043c\u0435\u0440\u043e\u0432\u0430\u043d\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a",
+"Superscript": "\u0412\u0435\u0440\u0445\u043d\u0456\u0439 \u0456\u043d\u0434\u0435\u043a\u0441",
+"Clear formatting": "\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0443\u0432\u0430\u043d\u043d\u044f",
+"Subscript": "\u041d\u0438\u0436\u043d\u0456\u0439 \u0456\u043d\u0434\u0435\u043a\u0441",
+"Redo": "\u041f\u043e\u0432\u0435\u0440\u043d\u0443\u0442\u0438",
+"Ok": "\u0413\u0430\u0440\u0430\u0437\u0434",
+"Bold": "\u0416\u0438\u0440\u043d\u0438\u0439",
+"Italic": "\u041a\u0443\u0440\u0441\u0438\u0432",
+"Align center": "\u041f\u043e \u0446\u0435\u043d\u0442\u0440\u0443",
+"Decrease indent": "\u0417\u043c\u0435\u043d\u0448\u0438\u0442\u0438\u0442\u0438 \u0432\u0456\u0434\u0441\u0442\u0443\u043f",
+"Underline": "\u041f\u0456\u0434\u043a\u0440\u0435\u0441\u043b\u0435\u043d\u0438\u0439",
+"Cancel": "\u0412\u0456\u0434\u043c\u0456\u043d\u0438\u0442\u0438",
+"Justify": "\u0412\u0438\u0440\u0456\u0432\u043d\u044e\u0432\u0430\u043d\u043d\u044f",
+"Copy": "\u041a\u043e\u043f\u0456\u044e\u0432\u0430\u0442\u0438",
+"Align left": "\u041f\u043e \u043b\u0456\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e",
+"Visual aids": "\u041d\u0430\u043e\u0447\u043d\u0456 \u043f\u0440\u0438\u043b\u0430\u0434\u0434\u044f",
+"Lower Greek": "\u041c\u0430\u043b\u0456 \u0433\u0440\u0435\u0446\u044c\u043a\u0456 \u0431\u0443\u043a\u0432\u0438",
+"Square": "\u041a\u0432\u0430\u0434\u0440\u0430\u0442\u0438",
+"Default": "\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u0439",
+"Lower Alpha": "\u041c\u0430\u043b\u0456 \u043b\u0430\u0442\u0438\u043d\u0441\u044c\u043a\u0456 \u0431\u0443\u043a\u0432\u0438",
+"Circle": "\u041e\u043a\u0440\u0443\u0436\u043d\u043e\u0441\u0442\u0456",
+"Disc": "\u041a\u0440\u0443\u0433\u0438",
+"Upper Alpha": "\u0412\u0435\u043b\u0438\u043a\u0456 \u043b\u0430\u0442\u0438\u043d\u0441\u044c\u043a\u0456 \u0431\u0443\u043a\u0432\u0438",
+"Upper Roman": "\u0420\u0438\u043c\u0441\u044c\u043a\u0456 \u0446\u0438\u0444\u0440\u0438",
+"Lower Roman": "\u041c\u0430\u043b\u0456 \u0440\u0438\u043c\u0441\u044c\u043a\u0456 \u0446\u0438\u0444\u0440\u0438",
+"Name": "\u041d\u0430\u0437\u0432\u0430",
+"Anchor": "\u042f\u043a\u0456\u0440",
+"You have unsaved changes are you sure you want to navigate away?": "\u0423 \u0412\u0430\u0441 \u0454 \u043d\u0435\u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043d\u0456 \u0437\u043c\u0456\u043d\u0438. \u0412\u0438 \u0432\u043f\u0435\u0432\u043d\u0435\u043d\u0456, \u0449\u043e \u0445\u043e\u0447\u0435\u0442\u0435 \u043f\u0456\u0442\u0438?",
+"Restore last draft": "\u0412\u0456\u0434\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044f \u043e\u0441\u0442\u0430\u043d\u043d\u044c\u043e\u0433\u043e \u0432\u0430\u0440\u0456\u0430\u043d\u0442\u0443",
+"Special character": "\u0421\u043f\u0435\u0446\u0456\u0430\u043b\u044c\u043d\u0456 \u0441\u0438\u043c\u0432\u043e\u043b\u0438",
+"Source code": "\u0412\u0438\u0445\u0456\u0434\u043d\u0438\u0439 \u043a\u043e\u0434",
+"Right to left": "\u0421\u043f\u0440\u0430\u0432\u0430 \u043d\u0430\u043b\u0456\u0432\u043e",
+"Left to right": "\u0417\u043b\u0456\u0432\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043e",
+"Emoticons": "\u0415\u043c\u043e\u0446\u0456\u0457",
+"Robots": "\u0420\u043e\u0431\u043e\u0442\u0438",
+"Document properties": "\u0412\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",
+"Title": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a",
+"Keywords": "\u041a\u043b\u044e\u0447\u043e\u0432\u0456 \u0441\u043b\u043e\u0432\u0430",
+"Encoding": "\u041a\u043e\u0434\u0443\u0432\u0430\u043d\u043d\u044f",
+"Description": "\u041e\u043f\u0438\u0441",
+"Author": "\u0410\u0432\u0442\u043e\u0440",
+"Fullscreen": "\u041f\u043e\u0432\u043d\u043e\u0435\u043a\u0440\u0430\u043d\u043d\u0438\u0439 \u0440\u0435\u0436\u0438\u043c",
+"Horizontal line": "\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0430 \u043b\u0456\u043d\u0456\u044f",
+"Horizontal space": "\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0438\u0439 \u0456\u043d\u0442\u0435\u0440\u0432\u0430\u043b",
+"Insert\/edit image": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438\/\u0437\u043c\u0456\u043d\u0438\u0442\u0438 \u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f",
+"General": "\u0417\u0430\u0433\u0430\u043b\u044c\u043d\u0456",
+"Advanced": "\u0420\u043e\u0437\u0448\u0438\u0440\u0435\u043d\u0456",
+"Source": "\u0414\u0436\u0435\u0440\u0435\u043b\u043e",
+"Border": "\u041c\u0435\u0436\u0430",
+"Constrain proportions": "\u0417\u0431\u0435\u0440\u0456\u0433\u0430\u0442\u0438 \u043f\u0440\u043e\u043f\u043e\u0440\u0446\u0456\u0457",
+"Vertical space": "\u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u0438\u0439 \u0456\u043d\u0442\u0435\u0440\u0432\u0430\u043b",
+"Image description": "\u041e\u043f\u0438\u0441 \u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f",
+"Style": "\u0421\u0442\u0438\u043b\u044c",
+"Dimensions": "\u0420\u043e\u0437\u043c\u0456\u0440",
+"Insert image": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f",
+"Insert date\/time": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0434\u0430\u0442\u0443\/\u0447\u0430\u0441",
+"Url": "\u0410\u0434\u0440\u0435\u0441\u0430 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f",
+"Text to display": "\u0422\u0435\u043a\u0441\u0442 \u0434\u043b\u044f \u0432\u0456\u0434\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f",
+"Insert link": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f",
+"New window": "\u0423 \u043d\u043e\u0432\u043e\u043c\u0443 \u0432\u0456\u043a\u043d\u0456",
+"None": "\u041d\u0456",
+"Target": "\u0412\u0456\u0434\u043a\u0440\u0438\u0432\u0430\u0442\u0438 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f",
+"Insert\/edit link": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438\/\u0440\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f",
+"Insert\/edit video": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438\/\u0440\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 \u0432\u0456\u0434\u0435\u043e",
+"Poster": "\u0417\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f",
+"Alternative source": "\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u0435 \u0434\u0436\u0435\u0440\u0435\u043b\u043e",
+"Paste your embed code below:": "\u0412\u0441\u0442\u0430\u0432\u0442\u0435 \u0432\u0430\u0448 \u043a\u043e\u0434 \u043d\u0438\u0436\u0447\u0435:",
+"Insert video": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0432\u0456\u0434\u0435\u043e",
+"Embed": "\u041a\u043e\u0434 \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438",
+"Nonbreaking space": "\u041d\u0435\u0440\u043e\u0437\u0440\u0438\u0432\u043d\u0438\u0439 \u043f\u0440\u043e\u0431\u0456\u043b",
+"Page break": "\u0420\u043e\u0437\u0440\u0438\u0432 \u0441\u0442\u043e\u0440\u0456\u043d\u043a\u0438",
+"Paste as text": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u044f\u043a \u0442\u0435\u043a\u0441\u0442",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u0412\u0441\u0442\u0430\u0432\u043a\u0430 \u0437\u0430\u0440\u0430\u0437 \u0432 \u0440\u0435\u0436\u0438\u043c\u0456 \u0437\u0432\u0438\u0447\u0430\u0439\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0443. \u0417\u043c\u0456\u0441\u0442 \u0431\u0443\u0434\u0435 \u0432\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0439 \u044f\u043a \u043f\u0440\u043e\u0441\u0442\u0438\u0439 \u0442\u0435\u043a\u0441\u0442, \u043f\u043e\u043a\u0438 \u0412\u0438 \u043d\u0435 \u0432\u0438\u043c\u043a\u043d\u0435\u0442\u0435 \u0446\u044e \u043e\u043f\u0446\u0456\u044e.",
+"Preview": "\u041f\u043e\u043f\u0435\u0440\u0435\u0434\u043d\u0456\u0439 \u043f\u0435\u0440\u0435\u0433\u043b\u044f\u0434",
+"Print": "\u0414\u0440\u0443\u043a\u0443\u0432\u0430\u0442\u0438",
+"Save": "\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438",
+"Could not find the specified string.": "\u0412\u043a\u0430\u0437\u0430\u043d\u0438\u0439 \u0440\u044f\u0434\u043e\u043a \u043d\u0435 \u0437\u043d\u0430\u0439\u0434\u0435\u043d\u043e",
+"Replace": "\u0417\u0430\u043c\u0456\u043d\u0438\u0442\u0438",
+"Next": "\u0412\u043d\u0438\u0437",
+"Whole words": "\u0426\u0456\u043b\u0456 \u0441\u043b\u043e\u0432\u0430",
+"Find and replace": "\u041f\u043e\u0448\u0443\u043a \u0456 \u0437\u0430\u043c\u0456\u043d\u0430",
+"Replace with": "\u0417\u0430\u043c\u0456\u043d\u0438\u0442\u0438 \u043d\u0430",
+"Find": "\u0417\u043d\u0430\u0439\u0442\u0438",
+"Replace all": "\u0417\u0430\u043c\u0456\u043d\u0438\u0442\u0438 \u0432\u0441\u0435",
+"Match case": "\u0412\u0440\u0430\u0445\u043e\u0432\u0443\u0432\u0430\u0442\u0438 \u0440\u0435\u0433\u0456\u0441\u0442\u0440",
+"Prev": "\u0412\u0433\u043e\u0440\u0443",
+"Spellcheck": "\u041f\u0435\u0440\u0435\u0432\u0456\u0440\u043a\u0430 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0456\u0457",
+"Finish": "\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0438",
+"Ignore all": "\u0406\u0433\u043d\u043e\u0440\u0443\u0432\u0430\u0442\u0438 \u0432\u0441\u0435",
+"Ignore": "\u0406\u0433\u043d\u043e\u0440\u0443\u0432\u0430\u0442\u0438",
+"Insert row before": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u043f\u043e\u0440\u043e\u0436\u043d\u0456\u0439 \u0440\u044f\u0434\u043e\u043a \u0437\u0432\u0435\u0440\u0445\u0443",
+"Rows": "\u0420\u044f\u0434\u043a\u0438",
+"Height": "\u0412\u0438\u0441\u043e\u0442\u0430",
+"Paste row after": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0440\u044f\u0434\u043e\u043a \u0437\u043d\u0438\u0437\u0443",
+"Alignment": "\u0412\u0438\u0440\u0456\u0432\u043d\u044e\u0432\u0430\u043d\u043d\u044f",
+"Column group": "\u0413\u0440\u0443\u043f\u0430 \u0441\u0442\u043e\u0432\u043f\u0446\u0456\u0432",
+"Row": "\u0420\u044f\u0434\u043e\u043a",
+"Insert column before": "\u0414\u043e\u0434\u0430\u0442\u0438 \u0441\u0442\u043e\u0432\u043f\u0435\u0446\u044c \u043b\u0456\u0432\u043e\u0440\u0443\u0447",
+"Split cell": "\u0420\u043e\u0437\u0431\u0438\u0442\u0438 \u043a\u043e\u043c\u0456\u0440\u043a\u0443",
+"Cell padding": "\u041f\u043e\u043b\u044f \u043a\u043e\u043c\u0456\u0440\u043e\u043a",
+"Cell spacing": "\u0412\u0456\u0434\u0441\u0442\u0430\u043d\u044c \u043c\u0456\u0436 \u043a\u043e\u043c\u0456\u0440\u043a\u0430\u043c\u0438",
+"Row type": "\u0422\u0438\u043f \u0440\u044f\u0434\u043a\u0430",
+"Insert table": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044e",
+"Body": "\u0422\u0456\u043b\u043e",
+"Caption": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a",
+"Footer": "\u041d\u0438\u0436\u043d\u0456\u0439 \u043a\u043e\u043b\u043e\u043d\u0442\u0438\u0442\u0443\u043b",
+"Delete row": "\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u0440\u044f\u0434\u043e\u043a",
+"Paste row before": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0440\u044f\u0434\u043e\u043a \u0437\u0432\u0435\u0440\u0445\u0443",
+"Scope": "\u0421\u0444\u0435\u0440\u0430",
+"Delete table": "\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044e",
+"Header cell": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a",
+"Column": "\u0421\u0442\u043e\u0432\u043f\u0435\u0446\u044c",
+"Cell": "\u041a\u043e\u043c\u0456\u0440\u043a\u0430",
+"Header": "\u0428\u0430\u043f\u043a\u0430",
+"Cell type": "\u0422\u0438\u043f \u043a\u043e\u043c\u0456\u0440\u043a\u0438",
+"Copy row": "\u041a\u043e\u043f\u0456\u044e\u0432\u0430\u0442\u0438 \u0440\u044f\u0434\u043e\u043a",
+"Row properties": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438 \u0440\u044f\u0434\u043a\u0430",
+"Table properties": "\u0412\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456 \u0442\u0430\u0431\u043b\u0438\u0446\u0456",
+"Row group": "\u0413\u0440\u0443\u043f\u0430 \u0440\u044f\u0434\u043a\u0456\u0432",
+"Right": "\u041f\u043e \u043f\u0440\u0430\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e",
+"Insert column after": "\u0414\u043e\u0434\u0430\u0442\u0438 \u0441\u0442\u043e\u0432\u043f\u0435\u0446\u044c \u043f\u0440\u0430\u0432\u043e\u0440\u0443\u0447",
+"Cols": "\u0421\u0442\u043e\u0432\u043f\u0446\u0456",
+"Insert row after": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u043f\u043e\u0440\u043e\u0436\u043d\u0456\u0439 \u0440\u044f\u0434\u043e\u043a \u0437\u043d\u0438\u0437\u0443",
+"Width": "\u0428\u0438\u0440\u0438\u043d\u0430",
+"Cell properties": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438 \u043a\u043e\u043c\u0456\u0440\u043a\u0438",
+"Left": "\u041f\u043e \u043b\u0456\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e",
+"Cut row": "\u0412\u0438\u0440\u0456\u0437\u0430\u0442\u0438 \u0440\u044f\u0434\u043e\u043a",
+"Delete column": "\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u0441\u0442\u043e\u0432\u043f\u0435\u0446\u044c",
+"Center": "\u041f\u043e \u0446\u0435\u043d\u0442\u0440\u0443",
+"Merge cells": "\u041e\u0431'\u0454\u0434\u043d\u0430\u0442\u0438 \u043a\u043e\u043c\u0456\u0440\u043a\u0438",
+"Insert template": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0448\u0430\u0431\u043b\u043e\u043d",
+"Templates": "\u0428\u0430\u0431\u043b\u043e\u043d\u0438",
+"Background color": "\u041a\u043e\u043b\u0456\u0440 \u0444\u043e\u043d\u0443",
+"Text color": "\u041a\u043e\u043b\u0456\u0440 \u0442\u0435\u043a\u0441\u0442\u0443",
+"Show blocks": "\u041f\u043e\u043a\u0430\u0437\u0443\u0432\u0430\u0442\u0438 \u0431\u043b\u043e\u043a\u0438",
+"Show invisible characters": "\u041f\u043e\u043a\u0430\u0437\u0443\u0432\u0430\u0442\u0438 \u043d\u0435\u0432\u0438\u0434\u0438\u043c\u0456 \u0441\u0438\u043c\u0432\u043e\u043b\u0438",
+"Words: {0}": "\u041a\u0456\u043b\u044c\u043a\u0456\u0441\u0442\u044c \u0441\u043b\u0456\u0432: {0}",
+"Insert": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438",
+"File": "\u0424\u0430\u0439\u043b",
+"Edit": "\u0417\u043c\u0456\u043d\u0438\u0442\u0438",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u0422\u0435\u043a\u0441\u0442\u043e\u0432\u0435 \u043f\u043e\u043b\u0435. \u041d\u0430\u0442\u0438\u0441\u043d\u0456\u0442\u044c ALT-F9 \u0449\u043e\u0431 \u0432\u0438\u043a\u043b\u0438\u043a\u0430\u0442\u0438 \u043c\u0435\u043d\u044e, ALT-F10 \u043f\u0430\u043d\u0435\u043b\u044c \u0456\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0456\u0432, ALT-0 \u0434\u043b\u044f \u0432\u0438\u043a\u043b\u0438\u043a\u0443 \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u0438.",
+"Tools": "\u0406\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0438",
+"View": "\u0412\u0438\u0433\u043b\u044f\u0434",
+"Table": "\u0422\u0430\u0431\u043b\u0438\u0446\u044f",
+"Format": "\u0424\u043e\u0440\u043c\u0430\u0442"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/uk_UA.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/uk_UA.js
new file mode 100755
index 0000000..e10a5f5
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/uk_UA.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('uk_UA',{
+"Cut": "\u0412\u0438\u0440\u0456\u0437\u0430\u0442\u0438",
+"Header 2": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u0412\u0430\u0448 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043d\u0435 \u043f\u0456\u0434\u0442\u0440\u0438\u043c\u0443\u0454 \u043f\u0440\u044f\u043c\u0438\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u043e \u0431\u0443\u0444\u0435\u0440\u0430 \u043e\u0431\u043c\u0456\u043d\u0443. \u0417\u0430\u043c\u0456\u0441\u0442\u044c \u0446\u044c\u043e\u0433\u043e \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0439\u0442\u0435 \u043f\u043e\u0454\u0434\u043d\u0430\u043d\u043d\u044f \u043a\u043b\u0430\u0432\u0456\u0448 Ctrl + X\/C\/V.",
+"Div": "Div",
+"Paste": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438",
+"Close": "\u0417\u0430\u043a\u0440\u0438\u0442\u0438",
+"Pre": "Pre",
+"Align right": "\u041f\u0440\u0430\u0432\u043e\u0440\u0443\u0447",
+"New document": "\u041d\u043e\u0432\u0438\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442",
+"Blockquote": "\u0426\u0438\u0442\u0430\u0442\u0430",
+"Numbered list": "\u041f\u0440\u043e\u043d\u0443\u043c\u0435\u0440\u043e\u0432\u0430\u043d\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a",
+"Increase indent": "\u0417\u0431\u0456\u043b\u044c\u0448\u0438\u0442\u0438 \u0432\u0456\u0434\u0441\u0442\u0443\u043f",
+"Formats": "\u0424\u043e\u0440\u043c\u0430\u0442\u0438",
+"Headers": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438",
+"Select all": "\u0412\u0438\u0431\u0435\u0440\u0456\u0442\u044c \u0443\u0441\u0435",
+"Header 3": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 3",
+"Blocks": "\u0411\u043b\u043e\u043a\u0438",
+"Undo": "\u0412\u0456\u0434\u043c\u0456\u043d\u0438\u0442\u0438",
+"Strikethrough": "\u041f\u0435\u0440\u0435\u043a\u0440\u0435\u0441\u043b\u0435\u043d\u0438\u0439",
+"Bullet list": "\u041c\u0430\u0440\u043a\u0456\u0440\u043e\u0432\u0430\u043d\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a",
+"Header 1": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 1",
+"Superscript": "\u0412\u0435\u0440\u0445\u043d\u0456\u0439 \u0456\u043d\u0434\u0435\u043a\u0441",
+"Clear formatting": "\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0443\u0432\u0430\u043d\u043d\u044f",
+"Subscript": "\u0406\u043d\u0434\u0435\u043a\u0441",
+"Header 6": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 6",
+"Redo": "\u0412\u0456\u0434\u043d\u043e\u0432\u0438\u0442\u0438",
+"Paragraph": "\u0410\u0431\u0437\u0430\u0446",
+"Ok": "Ok",
+"Bold": "\u0416\u0438\u0440\u043d\u0438\u0439",
+"Code": "\u041a\u043e\u0434",
+"Italic": "\u041a\u0443\u0440\u0441\u0438\u0432",
+"Align center": "\u041f\u043e \u0446\u0435\u043d\u0442\u0440\u0443",
+"Header 5": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 5",
+"Decrease indent": "\u0417\u043c\u0435\u043d\u0448\u0438\u0442\u0438 \u0432\u0456\u0434\u0441\u0442\u0443\u043f",
+"Header 4": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u0412\u0441\u0442\u0430\u0432\u043a\u0430 \u0437\u0430\u0440\u0430\u0437 \u0432 \u0440\u0435\u0436\u0438\u043c\u0456 \u0437\u0432\u0438\u0447\u0430\u0439\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0443. \u0417\u043c\u0456\u0441\u0442 \u0431\u0443\u0434\u0435 \u0432\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0439 \u044f\u043a \u043f\u0440\u043e\u0441\u0442\u0438\u0439 \u0442\u0435\u043a\u0441\u0442, \u043f\u043e\u043a\u0438 \u0412\u0438 \u043d\u0435 \u0432\u0438\u043c\u043a\u043d\u0435\u0442\u0435 \u0446\u044e \u043e\u043f\u0446\u0456\u044e.",
+"Underline": "\u041f\u0456\u0434\u043a\u0440\u0435\u0441\u043b\u0435\u043d\u0438\u0439",
+"Cancel": "\u0412\u0456\u0434\u043c\u0456\u043d\u0438\u0442\u0438",
+"Justify": "\u0412\u0438\u0440\u0456\u0432\u043d\u044f\u0442\u0438",
+"Inline": "\u0412\u0431\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0439",
+"Copy": "\u041a\u043e\u043f\u0456\u044e\u0432\u0430\u0442\u0438",
+"Align left": "\u041b\u0456\u0432\u043e\u0440\u0443\u0447",
+"Visual aids": "\u0412\u0456\u0437\u0443\u0430\u043b\u044c\u043d\u0456 \u0437\u0430\u0441\u043e\u0431\u0438",
+"Lower Greek": "\u041d\u0438\u0436\u043d\u044f \u0433\u0440\u0435\u0446\u044c\u043a\u0430",
+"Square": "\u041a\u0432\u0430\u0434\u0440\u0430\u0442",
+"Default": "\u0423\u043c\u043e\u0432\u0447\u0430\u043d\u043d\u044f",
+"Lower Alpha": "\u041d\u0438\u0436\u0447\u0430 \u0410\u043b\u044c\u0444\u0430",
+"Circle": "\u041a\u0440\u0443\u0433",
+"Disc": "\u0414\u0438\u0441\u043a",
+"Upper Alpha": "\u0412\u0435\u0440\u0445\u043d\u044f \u0410\u043b\u044c\u0444\u0430",
+"Upper Roman": "\u0412\u0435\u0440\u0445\u043d\u0456\u0439 \u0440\u0438\u043c\u0441\u044c\u043a\u0430",
+"Lower Roman": "\u041d\u0438\u0436\u043d\u044f \u0440\u0438\u043c\u0441\u044c\u043a\u0430",
+"Name": "\u0406\u043c'\u044f",
+"Anchor": "\u041f\u0440\u0438\u0432'\u044f\u0437\u043a\u0430",
+"You have unsaved changes are you sure you want to navigate away?": "\u0423 \u0432\u0430\u0441 \u0454 \u043d\u0435\u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043d\u0456 \u0437\u043c\u0456\u043d\u0438, \u0412\u0438 \u0443\u043f\u0435\u0432\u043d\u0435\u043d\u0456, \u0449\u043e \u0445\u043e\u0447\u0435\u0442\u0435 \u043f\u0456\u0442\u0438 ?",
+"Restore last draft": "\u0412\u0456\u0434\u043d\u043e\u0432\u0438\u0442\u0438 \u043e\u0441\u0442\u0430\u043d\u043d\u0456\u0439 \u043f\u0440\u043e\u0435\u043a\u0442",
+"Special character": "\u0421\u043f\u0435\u0446\u0456\u0430\u043b\u044c\u043d\u0438\u0439 \u0441\u0438\u043c\u0432\u043e\u043b",
+"Source code": "\u041f\u043e\u0447\u0430\u0442\u043a\u043e\u0432\u0438\u0439 \u043a\u043e\u0434",
+"Right to left": "\u0421\u043f\u0440\u0430\u0432\u0430 \u043d\u0430\u043b\u0456\u0432\u043e",
+"Left to right": "\u0417\u043b\u0456\u0432\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043e",
+"Emoticons": "\u0421\u043c\u0430\u0439\u043b\u0438\u043a\u0438",
+"Robots": "\u0420\u043e\u0431\u043e\u0442\u0438",
+"Document properties": "\u0412\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0443",
+"Title": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a",
+"Keywords": "\u041a\u043b\u044e\u0447\u043e\u0432\u0456 \u0441\u043b\u043e\u0432\u0430",
+"Encoding": "\u041a\u043e\u0434\u0443\u0432\u0430\u043d\u043d\u044f",
+"Description": "\u041e\u043f\u0438\u0441",
+"Author": "\u0410\u0432\u0442\u043e\u0440",
+"Fullscreen": "\u041f\u043e\u0432\u043d\u043e\u0435\u043a\u0440\u0430\u043d\u043d\u0438\u0439",
+"Horizontal line": "\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c",
+"Horizontal space": "\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0438\u0439 \u043f\u0440\u043e\u043f\u0443\u0441\u043a",
+"Insert\/edit image": "\u0412\u0441\u0442\u0430\u0432\u043a\u0430\/\u043f\u0440\u0430\u0432\u043a\u0430 \u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f",
+"General": "\u0417\u0430\u0433\u0430\u043b\u044c\u043d\u0435",
+"Advanced": "\u0414\u043e\u0434\u0430\u0442\u043a\u043e\u0432\u043e",
+"Source": "\u0414\u0436\u0435\u0440\u0435\u043b\u043e",
+"Border": "\u041c\u0435\u0436\u0430",
+"Constrain proportions": "\u0421\u0442\u0440\u0438\u043c\u0430\u0442\u0438 \u043f\u0440\u043e\u043f\u043e\u0440\u0446\u0456\u0457",
+"Vertical space": "\u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u0438\u0439 \u043f\u0440\u043e\u043f\u0443\u0441\u043a",
+"Image description": "\u041e\u043f\u0438\u0441 \u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f",
+"Style": "\u0421\u0442\u0438\u043b\u044c",
+"Dimensions": "\u0412\u0438\u043c\u0456\u0440\u0438",
+"Insert image": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f",
+"Insert date\/time": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0434\u0430\u0442\u0443\/\u0447\u0430\u0441",
+"Remove link": "\u0412\u0438\u0434\u0430\u043b\u0456\u0442\u044c \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f",
+"Url": "Url",
+"Text to display": "\u0422\u0435\u043a\u0441\u0442 \u0434\u043b\u044f \u0432\u0456\u0434\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f",
+"Anchors": "\u042f\u043a\u043e\u0440\u044f",
+"Insert link": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f",
+"New window": "\u041d\u043e\u0432\u0435 \u0432\u0456\u043a\u043d\u043e",
+"None": "\u041d\u0456",
+"Target": "\u041c\u0435\u0442\u0430",
+"Insert\/edit link": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438\/\u043f\u0440\u0430\u0432\u0438\u0442\u0438 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f",
+"Insert\/edit video": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438\/\u043f\u0440\u0430\u0432\u0438\u0442\u0438 \u0432\u0456\u0434\u0435\u043e",
+"Poster": "\u0410\u0444\u0456\u0448\u0430",
+"Alternative source": "\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u0435 \u0434\u0436\u0435\u0440\u0435\u043b\u043e",
+"Paste your embed code below:": "\u0412\u0441\u0442\u0430\u0432\u0442\u0435 \u0432\u0430\u0448 \u0432\u043f\u0440\u043e\u0432\u0430\u0434\u0436\u0435\u043d\u0438\u0439 \u043a\u043e\u0434 \u043d\u0438\u0436\u0447\u0435:",
+"Insert video": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0432\u0456\u0434\u0435\u043e",
+"Embed": "\u0412\u043f\u0440\u043e\u0432\u0430\u0434\u0438\u0442\u0438",
+"Nonbreaking space": "\u041d\u0435\u0440\u043e\u0437\u0440\u0438\u0432\u043d\u0438\u0439 \u043f\u0440\u043e\u043f\u0443\u0441\u043a",
+"Page break": "\u0420\u043e\u0437\u0440\u0438\u0432 \u0441\u0442\u043e\u0440\u0456\u043d\u043a\u0438",
+"Paste as text": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u044f\u043a \u0442\u0435\u043a\u0441\u0442",
+"Preview": "\u041f\u043e\u043f\u0435\u0440\u0435\u0434\u043d\u0456\u0439 \u043f\u0435\u0440\u0435\u0433\u043b\u044f\u0434",
+"Print": "\u0414\u0440\u0443\u043a",
+"Save": "\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438",
+"Could not find the specified string.": "\u041d\u0435 \u0437\u043c\u0456\u0433 \u0437\u043d\u0430\u0439\u0442\u0438 \u0432\u043a\u0430\u0437\u0430\u043d\u0438\u0439 \u0440\u044f\u0434\u043e\u043a.",
+"Replace": "\u0417\u0430\u043c\u0456\u043d\u0430",
+"Next": "\u041d\u0430\u0441\u0442\u0443\u043f\u043d\u0438\u0439",
+"Whole words": "\u0426\u0456\u043b\u0456 \u0441\u043b\u043e\u0432\u0430",
+"Find and replace": "\u0417\u043d\u0430\u0439\u0442\u0438 \u0456 \u0437\u0430\u043c\u0456\u043d\u0438\u0442\u0438",
+"Replace with": "\u0417\u0430\u043c\u0456\u043d\u0430 \u043d\u0430",
+"Find": "\u0417\u043d\u0430\u0439\u0442\u0438",
+"Replace all": "\u0417\u0430\u043c\u0456\u043d\u0456\u0442\u044c \u0443\u0441\u0435",
+"Match case": "\u0417 \u0443\u0440\u0430\u0445\u0443\u0432\u0430\u043d\u043d\u044f\u043c \u0440\u0435\u0433\u0456\u0441\u0442\u0440\u0430",
+"Prev": "\u041f\u043e\u043f\u0435\u0440\u0435\u0434\u043d\u0456\u0439",
+"Spellcheck": "\u041f\u0435\u0440\u0435\u0432\u0456\u0440\u043a\u0430 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0456\u0457",
+"Finish": "\u0424\u0456\u043d\u0456\u0448",
+"Ignore all": "\u0406\u0433\u043d\u043e\u0440\u0443\u0432\u0430\u0442\u0438 \u0443\u0441\u0435",
+"Ignore": "\u0406\u0433\u043d\u043e\u0440\u0443\u0432\u0430\u0442\u0438",
+"Insert row before": "\u0412\u0441\u0442\u0430\u0432\u0442\u0435 \u0440\u044f\u0434\u043e\u043a \u0440\u0430\u043d\u0456\u0448\u0435",
+"Rows": "\u0420\u044f\u0434\u0438",
+"Height": "\u0412\u0438\u0441\u043e\u0442\u0430",
+"Paste row after": "\u0412\u0441\u0442\u0430\u0432\u0442\u0435 \u0440\u044f\u0434\u043e\u043a \u043f\u0456\u0441\u043b\u044f",
+"Alignment": "\u0412\u0438\u0440\u0456\u0432\u043d\u044e\u0432\u0430\u043d\u043d\u044f",
+"Column group": "\u0413\u0440\u0443\u043f\u0430 \u0441\u0442\u043e\u0432\u043f\u0446\u0456\u0432",
+"Row": "\u0420\u044f\u0434\u043e\u043a",
+"Insert column before": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0441\u0442\u043e\u0432\u043f\u0435\u0446\u044c \u0440\u0430\u043d\u0456\u0448\u0435",
+"Split cell": "\u0420\u043e\u0437\u0431\u0438\u0439\u0442\u0435 \u043e\u0441\u0435\u0440\u0435\u0434\u043e\u043a",
+"Cell padding": "\u0417\u0430\u043f\u043e\u0432\u043d\u0435\u043d\u043d\u044f \u043e\u0441\u0435\u0440\u0435\u0434\u043a\u0456\u0432",
+"Cell spacing": "\u0406\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u043c\u0456\u0436 \u043e\u0441\u0435\u0440\u0435\u0434\u043a\u0430\u043c\u0438",
+"Row type": "\u0422\u0438\u043f \u0440\u044f\u0434\u0443",
+"Insert table": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044e",
+"Body": "\u0422\u0456\u043b\u043e",
+"Caption": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a",
+"Footer": "\u041d\u0438\u0436\u043d\u0456\u0439 \u043a\u043e\u043b\u043e\u043d\u0442\u0438\u0442\u0443\u043b",
+"Delete row": "\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u0440\u044f\u0434\u043e\u043a",
+"Paste row before": "\u0412\u0441\u0442\u0430\u0432\u0442\u0435 \u0440\u044f\u0434\u043e\u043a \u0440\u0430\u043d\u0456\u0448\u0435",
+"Scope": "\u0423 \u043c\u0435\u0436\u0430\u0445",
+"Delete table": "\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044e",
+"Header cell": "\u041e\u0441\u0435\u0440\u0435\u0434\u043e\u043a \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430",
+"Column": "\u0421\u0442\u043e\u0432\u043f\u0435\u0446\u044c",
+"Cell": "\u041e\u0441\u0435\u0440\u0435\u0434\u043e\u043a",
+"Header": "\u0412\u0435\u0440\u0445\u043d\u0456\u0439 \u043a\u043e\u043b\u043e\u043d\u0442\u0438\u0442\u0443\u043b",
+"Cell type": "\u0422\u0438\u043f \u043e\u0441\u0435\u0440\u0435\u0434\u043a\u0443",
+"Copy row": "\u041a\u043e\u043f\u0456\u044e\u0432\u0430\u0442\u0438 \u0440\u044f\u0434\u043e\u043a",
+"Row properties": "\u0412\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456 \u0440\u044f\u0434\u043a\u0430",
+"Table properties": "\u0412\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456 \u0442\u0430\u0431\u043b\u0438\u0446\u0456",
+"Row group": "\u0413\u0440\u0443\u043f\u0430 \u0440\u044f\u0434\u0456\u0432",
+"Right": "\u041f\u0440\u0430\u0432\u043e\u0440\u0443\u0447",
+"Insert column after": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0441\u0442\u043e\u0432\u043f\u0435\u0446\u044c \u043f\u0456\u0441\u043b\u044f",
+"Cols": "\u0421\u0442\u043e\u0432\u043f\u0446\u0456",
+"Insert row after": "\u0412\u0441\u0442\u0430\u0432\u0442\u0435 \u0440\u044f\u0434\u043e\u043a \u043f\u0456\u0441\u043b\u044f",
+"Width": "\u0428\u0438\u0440\u0438\u043d\u0430",
+"Cell properties": "\u0412\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456 \u043e\u0441\u0435\u0440\u0435\u0434\u043a\u0443",
+"Left": "\u041b\u0456\u0432\u043e\u0440\u0443\u0447",
+"Cut row": "\u0412\u0438\u0440\u0456\u0437\u0430\u0442\u0438 \u0440\u044f\u0434\u043e\u043a",
+"Delete column": "\u0412\u0438\u0434\u0430\u043b\u0456\u0442\u044c \u0441\u0442\u043e\u0432\u043f\u0435\u0446\u044c",
+"Center": "\u0426\u0435\u043d\u0442\u0440",
+"Merge cells": "\u041e\u0431'\u0454\u0434\u043d\u0430\u0439\u0442\u0435 \u043e\u0441\u0435\u0440\u0435\u0434\u043a\u0438",
+"Insert template": "\u0412\u0441\u0442\u0430\u0432\u0442\u0435 \u0448\u0430\u0431\u043b\u043e\u043d",
+"Templates": "\u0428\u0430\u0431\u043b\u043e\u043d\u0438",
+"Background color": "\u041a\u043e\u043b\u0456\u0440 \u0444\u043e\u043d\u0443",
+"Text color": "\u041a\u043e\u043b\u0456\u0440 \u0442\u0435\u043a\u0441\u0442\u0443",
+"Show blocks": "\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u0438 \u0431\u043b\u043e\u043a\u0438",
+"Show invisible characters": "\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u0438 \u043d\u0435\u0432\u0438\u0434\u0438\u043c\u0456 \u0441\u0438\u043c\u0432\u043e\u043b\u0438",
+"Words: {0}": "\u0421\u043b\u043e\u0432\u0430: {0}",
+"Insert": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438",
+"File": "\u0424\u0430\u0439\u043b",
+"Edit": "\u041f\u0440\u0430\u0432\u043a\u0430",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u041e\u0431\u043b\u0430\u0441\u0442\u044c Rich \u0442\u0435\u043a\u0441\u0442\u0443. \u041d\u0430\u0442\u0438\u0441\u043d\u0456\u0442\u044c ALT-F9 - \u043c\u0435\u043d\u044e. \u041d\u0430\u0442\u0438\u0441\u043d\u0456\u0442\u044c ALT-F10 - \u043f\u0430\u043d\u0435\u043b\u044c \u0456\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0456\u0432. \u041d\u0430\u0442\u0438\u0441\u043d\u0456\u0442\u044c ALT-0 - \u0434\u043e\u0432\u0456\u0434\u043a\u0430",
+"Tools": "\u0406\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0438",
+"View": "\u0412\u0438\u0434",
+"Table": "\u0422\u0430\u0431\u043b\u0438\u0446\u044f",
+"Format": "\u0424\u043e\u0440\u043c\u0430\u0442"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/vi.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/vi.js
new file mode 100755
index 0000000..cc860c0
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/vi.js
@@ -0,0 +1,96 @@
+tinymce.addI18n('vi',{
+"Cut": "C\u1eaft",
+"Header 2": "Ti\u00eau \u0111\u1ec1 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Tr\u00ecnh duy\u1ec7t c\u1ee7a b\u1ea1n kh\u00f4ng h\u1ed7 tr\u1ee3 truy c\u1eadp truy c\u1eadp b\u1ed9 nh\u1edb \u1ea3o, vui l\u00f2ng s\u1eed d\u1ee5ng c\u00e1c t\u1ed5 h\u1ee3p ph\u00edm Ctrl + X, C, V.",
+"Div": "Khung",
+"Paste": "D\u00e1n",
+"Close": "\u0110\u00f3ng L\u1ea1i",
+"Pre": "\u0110\u1ecbnh d\u1ea1ng",
+"Align right": "Canh ph\u1ea3i",
+"New document": "T\u1ea1o t\u00e0i li\u1ec7u m\u1edbi",
+"Blockquote": "\u0110o\u1ea1n Tr\u00edch D\u1eabn",
+"Numbered list": "Danh s\u00e1ch d\u1ea1ng s\u1ed1",
+"Increase indent": "T\u0103ng kho\u1ea3ng c\u00e1ch d\u00f2ng",
+"Formats": "\u0110\u1ecbnh d\u1ea1ng",
+"Headers": "\u0110\u1ea7u trang",
+"Select all": "Ch\u1ecdn t\u1ea5t c\u1ea3",
+"Header 3": "Ti\u00eau \u0111\u1ec1 3",
+"Blocks": "Bao",
+"Undo": "H\u1ee7y thao t\u00e1c",
+"Strikethrough": "G\u1ea1ch ngang",
+"Bullet list": "Danh s\u00e1ch d\u1ea1ng bi\u1ec3u t\u01b0\u1ee3ng",
+"Header 1": "Ti\u00eau \u0111\u1ec1 1",
+"Superscript": "K\u00fd t\u1ef1 m\u0169",
+"Clear formatting": "L\u01b0\u1ee3c b\u1ecf ph\u1ea7n hi\u1ec7u \u1ee9ng",
+"Subscript": "K\u00fd t\u1ef1 th\u1ea5p",
+"Header 6": "Ti\u00eau \u0111\u1ec1 6",
+"Redo": "L\u00e0m l\u1ea1i",
+"Paragraph": "\u0110o\u1ea1n v\u0103n",
+"Ok": "\u0110\u1ed3ng \u00dd",
+"Bold": "In \u0111\u1eadm",
+"Code": "M\u00e3",
+"Italic": "In nghi\u00eang",
+"Align center": "Canh gi\u1eefa",
+"Header 5": "Ti\u00eau \u0111\u1ec1 5",
+"Decrease indent": "Th\u1ee5t l\u00f9i d\u00f2ng",
+"Header 4": "Ti\u00eau \u0111\u1ec1 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "D\u00e1n \u0111ang trong tr\u1ea1ng th\u00e1i v\u0103n b\u1ea3n thu\u1ea7n. N\u1ed9i dung s\u1ebd \u0111\u01b0\u1ee3c d\u00e1n d\u01b0\u1edbi d\u1ea1ng v\u0103n b\u1ea3n thu\u1ea7n, kh\u00f4ng \u0111\u1ecbnh d\u1ea1ng.",
+"Underline": "G\u1ea1ch d\u01b0\u1edbi",
+"Cancel": "Hu\u1ef7 B\u1ecf",
+"Justify": "Canh \u0111\u1ec1u hai b\u00ean",
+"Inline": "C\u00f9ng d\u00f2ng",
+"Copy": "Sao ch\u00e9p",
+"Align left": "Canh tr\u00e1i",
+"Visual aids": "M\u1edf khung so\u1ea1n th\u1ea3o",
+"Lower Greek": "S\u1ed1 hy l\u1ea1p th\u01b0\u1eddng",
+"Square": "\u00d4 vu\u00f4ng",
+"Default": "Ng\u1ea7m \u0111\u1ecbnh",
+"Lower Alpha": "K\u00fd t\u1ef1 th\u01b0\u1eddng",
+"Circle": "H\u00ecnh tr\u00f2n",
+"Disc": "H\u00ecnh tr\u00f2n m\u1ecfng",
+"Upper Alpha": "K\u00fd t\u1ef1 hoa",
+"Upper Roman": "S\u1ed1 la m\u00e3 hoa",
+"Lower Roman": "S\u1ed1 la m\u00e3 th\u01b0\u1eddng",
+"Insert row before": "Th\u00eam d\u00f2ng ph\u00eda tr\u00ean",
+"Rows": "D\u00f2ng",
+"Height": "Cao",
+"Paste row after": "D\u00e1n v\u00e0o ph\u00eda sau, d\u01b0\u1edbi",
+"Alignment": "Canh ch\u1ec9nh",
+"Column group": "Nh\u00f3m c\u1ed9t",
+"Row": "D\u00f2ng",
+"Insert column before": "Th\u00eam c\u1ed9t b\u00ean tr\u00e1i",
+"Split cell": "Chia \u00f4",
+"Cell padding": "Kho\u1ea3ng c\u00e1ch trong \u00f4",
+"Cell spacing": "Kho\u1ea3ng c\u00e1ch \u00f4",
+"Row type": "Lo\u1ea1i d\u00f2ng",
+"Insert table": "Th\u00eam b\u1ea3ng",
+"Body": "N\u1ed9i dung",
+"Caption": "Ti\u00eau \u0111\u1ec1",
+"Footer": "Ch\u00e2n",
+"Delete row": "Xo\u00e1 d\u00f2ng",
+"Paste row before": "D\u00e1n v\u00e0o ph\u00eda tr\u01b0\u1edbc, tr\u00ean",
+"Scope": "Quy\u1ec1n",
+"Delete table": "Xo\u00e1 b\u1ea3ng",
+"Header cell": "Ti\u00eau \u0111\u1ec1 \u00f4",
+"Column": "C\u1ed9t",
+"None": "Kh\u00f4ng",
+"Cell": "\u00d4",
+"Header": "Ti\u00eau \u0111\u1ec1",
+"Border": "\u0110\u01b0\u1eddng vi\u1ec1n",
+"Cell type": "Lo\u1ea1i \u00f4",
+"Copy row": "Ch\u00e9p d\u00f2ng",
+"Row properties": "Thu\u1ed9c t\u00ednh d\u00f2ng",
+"Table properties": "Thu\u1ed9c t\u00ednh b\u1ea3ng",
+"Row group": "Nh\u00f3m d\u00f2ng",
+"Right": "Ph\u1ea3i",
+"Insert column after": "Th\u00eam c\u1ed9t b\u00ean ph\u1ea3i",
+"Cols": "C\u1ed9t",
+"Insert row after": "Th\u00eam d\u00f2ng ph\u00eda d\u01b0\u1edbi",
+"Width": "R\u1ed9ng",
+"Cell properties": "Thu\u1ed9c t\u00ednh \u00f4",
+"Left": "Tr\u00e1i",
+"Cut row": "C\u1eaft d\u00f2ng",
+"Delete column": "Xo\u00e1 c\u1ed9t",
+"Center": "Gi\u1eefa",
+"Merge cells": "N\u1ed1i \u00f4"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/vi_VN.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/vi_VN.js
new file mode 100755
index 0000000..d1f1bae
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/vi_VN.js
@@ -0,0 +1,173 @@
+tinymce.addI18n('vi_VN',{
+"Cut": "C\u1eaft",
+"Header 2": "Ti\u00eau \u0111\u1ec1 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Tr\u00ecnh duy\u1ec7t c\u1ee7a b\u1ea1n kh\u00f4ng h\u1ed7 tr\u1ee3 truy c\u1eadp clipboard, vui l\u00f2ng s\u1eed d\u1ee5ng c\u00e1c t\u1ed5 h\u1ee3p Ctrl + X, C, V.",
+"Div": "Khung",
+"Paste": "D\u00e1n",
+"Close": "\u0110\u00f3ng",
+"Pre": "\u0110\u1ecbnh d\u1ea1ng",
+"Align right": "Canh ph\u1ea3i",
+"New document": "T\u1ea1o t\u00e0i li\u1ec7u m\u1edbi",
+"Blockquote": "Tr\u00edch",
+"Numbered list": "Danh s\u00e1ch s\u1ed1",
+"Increase indent": "L\u00f9i v\u00e0o",
+"Formats": "\u0110\u1ecbnh d\u1ea1ng",
+"Headers": "\u0110\u1ea7u trang",
+"Select all": "Ch\u1ecdn t\u1ea5t c\u1ea3",
+"Header 3": "Ti\u00eau \u0111\u1ec1 3",
+"Blocks": "Bao",
+"Undo": "Hu\u1ef7 thao t\u00e1c",
+"Strikethrough": "G\u1ea1ch ngang",
+"Bullet list": "D\u1ea5u \u0111\u1ea7u d\u00f2ng",
+"Header 1": "Ti\u00eau \u0111\u1ec1 1",
+"Superscript": "Tr\u00ean d\u00f2ng",
+"Clear formatting": "Xo\u00e1 \u0111\u1ecbnh d\u1ea1ng",
+"Subscript": "D\u01b0\u1edbi d\u00f2ng",
+"Header 6": "Ti\u00eau \u0111\u1ec1 6",
+"Redo": "Ho\u00e0n t\u00e1t",
+"Paragraph": "\u0110o\u1ea1n v\u0103n",
+"Ok": "OK",
+"Bold": "T\u00f4 \u0111\u1eadm",
+"Code": "M\u00e3",
+"Italic": "In nghi\u00eang",
+"Align center": "Canh gi\u1eefa",
+"Header 5": "Ti\u00eau \u0111\u1ec1 5",
+"Decrease indent": "L\u00f9i ra",
+"Header 4": "Ti\u00eau \u0111\u1ec1 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "D\u00e1n \u0111ang trong tr\u1ea1ng th\u00e1i v\u0103n b\u1ea3n thu\u1ea7n. N\u1ed9i dung s\u1ebd \u0111\u01b0\u1ee3c d\u00e1n d\u01b0\u1edbi d\u1ea1ng v\u0103n b\u1ea3n thu\u1ea7n (Kh\u00f4ng \u0111\u1ecbnh d\u1ea1ng)",
+"Underline": "G\u1ea1ch d\u01b0\u1edbi",
+"Cancel": "Hu\u1ef7",
+"Justify": "Canh \u0111\u1ec1u hai b\u00ean",
+"Inline": "C\u00f9ng d\u00f2ng",
+"Copy": "Ch\u00e9p",
+"Align left": "Canh tr\u00e1i",
+"Visual aids": "Hi\u1ec7n khung so\u1ea1n th\u1ea3o",
+"Lower Greek": "S\u1ed1 hy l\u1ea1p th\u01b0\u1eddng",
+"Square": "\u00d4 vu\u00f4ng",
+"Default": "Ng\u1ea7m \u0111\u1ecbnh",
+"Lower Alpha": "K\u00fd t\u1ef1 th\u01b0\u1eddng",
+"Circle": "H\u00ecnh tr\u00f2n",
+"Disc": "H\u00ecnh tr\u00f2n m\u1ecfng",
+"Upper Alpha": "K\u00fd t\u1ef1 hoa",
+"Upper Roman": "S\u1ed1 la m\u00e3 hoa",
+"Lower Roman": "S\u1ed1 la m\u00e3 th\u01b0\u1eddng",
+"Name": "T\u00ean",
+"Anchor": "Neo",
+"You have unsaved changes are you sure you want to navigate away?": "B\u1ea1n ch\u01b0a l\u01b0u c\u00e1c thay \u0111\u1ed5i, b\u1ea1n c\u00f3 th\u1eadt s\u1ef1 mu\u1ed1n \u0111\u00f3ng ?",
+"Restore last draft": "Ph\u1ee5c h\u1ed3i b\u1ea3n l\u01b0u g\u1ea7n nh\u1ea5t",
+"Special character": "K\u00fd t\u1ef1 \u0111\u1eb7c bi\u1ec7t",
+"Source code": "M\u00e3 ngu\u1ed3n",
+"Right to left": "Ph\u1ea3i sang tr\u00e1i",
+"Left to right": "Tr\u00e1i sang ph\u1ea3i",
+"Emoticons": "Bi\u1ec3u t\u01b0\u1ee3ng c\u1ea3m x\u00fac",
+"Robots": "Robots",
+"Document properties": "Thu\u1ed9c t\u00ednh t\u00e0i li\u1ec7u",
+"Title": "Ti\u00eau \u0111\u1ec1",
+"Keywords": "T\u1eeb kho\u00e1",
+"Encoding": "M\u00e3 ho\u00e1",
+"Description": "Mi\u00eau t\u1ea3",
+"Author": "Neo",
+"Fullscreen": "\u0110\u1ea7y m\u00e0n h\u00ecnh",
+"Horizontal line": "G\u1ea1ch ngang",
+"Horizontal space": "Kho\u1ea3ng c\u00e1ch ngang",
+"Insert\/edit image": "Th\u00eam \/ s\u1eeda h\u00ecnh \u1ea3nh",
+"General": "T\u1ed5ng h\u1ee3p",
+"Advanced": "N\u00e2ng cao",
+"Source": "Ngu\u1ed3n",
+"Border": "\u0110\u01b0\u1eddng vi\u1ec1n",
+"Constrain proportions": "H\u1ea1n ch\u1ebf t\u1ef7 l\u1ec7",
+"Vertical space": "Kho\u1ea3ng c\u00e1ch d\u1ecdc",
+"Image description": "Mi\u00eau t\u1ea3 h\u00ecnh \u1ea3nh",
+"Style": "Ki\u1ec3u",
+"Dimensions": "K\u00edch th\u01b0\u1edbc",
+"Insert image": "Ch\u00e8n \u1ea3nh",
+"Insert date\/time": "Th\u00eam ng\u00e0y \/ gi\u1edd",
+"Remove link": "Xo\u00e1 li\u00ean k\u1ebft",
+"Url": "Li\u00ean k\u1ebft",
+"Text to display": "Ch\u1eef hi\u1ec3n th\u1ecb",
+"Insert link": "Th\u00eam li\u00ean k\u1ebft",
+"New window": "C\u1eeda s\u1ed5 m\u1edbi",
+"None": "Kh\u00f4ng",
+"Target": "M\u1ee5c ti\u00eau",
+"Insert\/edit link": "Th\u00eam \/ s\u1eeda li\u00ean k\u1ebft",
+"Insert\/edit video": "Th\u00eam \/ s\u1eeda video",
+"Poster": "Ng\u01b0\u1eddi \u0111\u0103ng",
+"Alternative source": "Ngu\u1ed3n thay th\u1ebf",
+"Paste your embed code below:": "D\u00e1n m\u00e3 embed v\u00e0o:",
+"Insert video": "Th\u00eam video",
+"Embed": "Embed",
+"Nonbreaking space": "Kh\u00f4ng ng\u1eaft kho\u1ea3ng",
+"Page break": "Ng\u1eaft trang",
+"Preview": "Xem tr\u01b0\u1edbc",
+"Print": "In",
+"Save": "L\u01b0u",
+"Could not find the specified string.": "Kh\u00f4ng t\u00ecm th\u1ea5y chu\u1ed7i y\u00eau c\u1ea7u",
+"Replace": "Thay th\u1ebf",
+"Next": "Sau",
+"Whole words": "T\u1ea5t c\u1ea3 \u0111o\u1ea1n",
+"Find and replace": "T\u00ecm v\u00e0 thay th\u1ebf",
+"Replace with": "Thay th\u1ebf b\u1eb1ng",
+"Find": "T\u00ecm",
+"Replace all": "Thay th\u1ebf t\u1ea5t c\u1ea3",
+"Match case": "Ph\u00e2n bi\u1ec7t hoa th\u01b0\u1eddng",
+"Prev": "Tr\u01b0\u1edbc",
+"Spellcheck": "Ki\u1ec3m tra ch\u00ednh t\u1ea3",
+"Finish": "K\u1ebft th\u00fac",
+"Ignore all": "L\u1edd t\u1ea5t c\u1ea3",
+"Ignore": "L\u1edd qua",
+"Insert row before": "Th\u00eam d\u00f2ng ph\u00eda tr\u00ean",
+"Rows": "D\u00f2ng",
+"Height": "Cao",
+"Paste row after": "D\u00e1n v\u00e0o ph\u00eda sau, d\u01b0\u1edbi",
+"Alignment": "Canh ch\u1ec9nh",
+"Column group": "Nh\u00f3m c\u1ed9t",
+"Row": "D\u00f2ng",
+"Insert column before": "Th\u00eam c\u1ed9t b\u00ean tr\u00e1i",
+"Split cell": "Chia \u00f4",
+"Cell padding": "Kho\u1ea3ng c\u00e1ch trong \u00f4",
+"Cell spacing": "Kho\u1ea3ng c\u00e1ch \u00f4",
+"Row type": "Lo\u1ea1i d\u00f2ng",
+"Insert table": "Th\u00eam b\u1ea3ng",
+"Body": "N\u1ed9i dung",
+"Caption": "Ti\u00eau \u0111\u1ec1",
+"Footer": "Ch\u00e2n",
+"Delete row": "Xo\u00e1 d\u00f2ng",
+"Paste row before": "D\u00e1n v\u00e0o ph\u00eda tr\u01b0\u1edbc, tr\u00ean",
+"Scope": "Quy\u1ec1n",
+"Delete table": "Xo\u00e1 b\u1ea3ng",
+"Header cell": "Ti\u00eau \u0111\u1ec1 \u00f4",
+"Column": "C\u1ed9t",
+"Cell": "\u00d4",
+"Header": "Ti\u00eau \u0111\u1ec1",
+"Cell type": "Lo\u1ea1i \u00f4",
+"Copy row": "Ch\u00e9p d\u00f2ng",
+"Row properties": "Thu\u1ed9c t\u00ednh d\u00f2ng",
+"Table properties": "Thu\u1ed9c t\u00ednh b\u1ea3ng",
+"Row group": "Nh\u00f3m d\u00f2ng",
+"Right": "Ph\u1ea3i",
+"Insert column after": "Th\u00eam c\u1ed9t b\u00ean ph\u1ea3i",
+"Cols": "C\u1ed9t",
+"Insert row after": "Th\u00eam d\u00f2ng ph\u00eda d\u01b0\u1edbi",
+"Width": "R\u1ed9ng",
+"Cell properties": "Thu\u1ed9c t\u00ednh \u00f4",
+"Left": "Tr\u00e1i",
+"Cut row": "C\u1eaft d\u00f2ng",
+"Delete column": "Xo\u00e1 c\u1ed9t",
+"Center": "Gi\u1eefa",
+"Merge cells": "N\u1ed1i \u00f4",
+"Insert template": "Th\u00eam giao di\u1ec7n",
+"Templates": "Giao di\u1ec7n",
+"Background color": "M\u00e0u n\u1ec1n",
+"Text color": "M\u00e0u ch\u1eef",
+"Show blocks": "Hi\u1ec3n th\u1ecb kh\u1ed1i",
+"Show invisible characters": "Hi\u1ec3n th\u1ecb c\u00e1c k\u00fd t\u1ef1 \u1ea9n",
+"Words: {0}": "T\u1eeb: {0}",
+"Insert": "Th\u00eam",
+"File": "T\u1eadp tin",
+"Edit": "S\u1eeda",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Khu v\u1ef1c so\u1ea1n th\u1ea3o. Nh\u1ea5n ALT+F9 \u0111\u1ec3 hi\u1ec7n menu, ALT+F10 \u0111\u1ec3 hi\u1ec7n thanh c\u00f4ng c\u1ee5. C\u1ea7n tr\u1ee3 gi\u00fap nh\u1ea5n ALT+0",
+"Tools": "C\u00f4ng c\u1ee5",
+"View": "Xem",
+"Table": "B\u1ea3ng",
+"Format": "\u0110\u1ecbnh d\u1ea1ng"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/zh_CN.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/zh_CN.js
new file mode 100755
index 0000000..a537641
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/zh_CN.js
@@ -0,0 +1,173 @@
+tinymce.addI18n('zh_CN',{
+"Cut": "\u526a\u5207",
+"Header 2": "\u6807\u98982",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\u5bf9\u526a\u8d34\u677f\u7684\u8bbf\u95ee\uff0c\u8bf7\u4f7f\u7528Ctrl+X\/C\/V\u952e\u8fdb\u884c\u590d\u5236\u7c98\u8d34\u3002",
+"Div": "Div\u533a\u5757",
+"Paste": "\u7c98\u8d34",
+"Close": "\u5173\u95ed",
+"Pre": "\u9884\u683c\u5f0f\u6587\u672c",
+"Align right": "\u53f3\u5bf9\u9f50",
+"New document": "\u65b0\u6587\u6863",
+"Blockquote": "\u5f15\u7528",
+"Numbered list": "\u7f16\u53f7\u5217\u8868",
+"Increase indent": "\u589e\u52a0\u7f29\u8fdb",
+"Formats": "\u683c\u5f0f",
+"Headers": "\u6807\u9898",
+"Select all": "\u5168\u9009",
+"Header 3": "\u6807\u98983",
+"Blocks": "\u5757",
+"Undo": "\u64a4\u6d88",
+"Strikethrough": "\u5220\u9664\u7ebf",
+"Bullet list": "\u9879\u76ee\u7b26\u53f7",
+"Header 1": "\u6807\u98981",
+"Superscript": "\u4e0a\u6807",
+"Clear formatting": "\u6e05\u9664\u683c\u5f0f",
+"Subscript": "\u4e0b\u6807",
+"Header 6": "\u6807\u98986",
+"Redo": "\u91cd\u590d",
+"Paragraph": "\u6bb5\u843d",
+"Ok": "\u786e\u5b9a",
+"Bold": "\u7c97\u4f53",
+"Code": "\u4ee3\u7801",
+"Italic": "\u659c\u4f53",
+"Align center": "\u5c45\u4e2d",
+"Header 5": "\u6807\u98985",
+"Decrease indent": "\u51cf\u5c11\u7f29\u8fdb",
+"Header 4": "\u6807\u98984",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u7c98\u8d34\u6a21\u5f0f\uff0c\u518d\u6b21\u70b9\u51fb\u53ef\u4ee5\u56de\u5230\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002",
+"Underline": "\u4e0b\u5212\u7ebf",
+"Cancel": "\u53d6\u6d88",
+"Justify": "\u4e24\u7aef\u5bf9\u9f50",
+"Inline": "\u5185\u5d4c",
+"Copy": "\u590d\u5236",
+"Align left": "\u5de6\u5bf9\u9f50",
+"Visual aids": "\u63d0\u793a",
+"Lower Greek": "\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd",
+"Square": "\u65b9\u5757",
+"Default": "\u9ed8\u8ba4",
+"Lower Alpha": "\u5c0f\u5199\u82f1\u6587\u5b57\u6bcd",
+"Circle": "\u7a7a\u5fc3\u5706",
+"Disc": "\u5b9e\u5fc3\u5706",
+"Upper Alpha": "\u5927\u5199\u82f1\u6587\u5b57\u6bcd",
+"Upper Roman": "\u5927\u5199\u7f57\u9a6c\u5b57\u6bcd",
+"Lower Roman": "\u5c0f\u5199\u7f57\u9a6c\u5b57\u6bcd",
+"Name": "\u540d\u79f0",
+"Anchor": "\u951a\u70b9",
+"You have unsaved changes are you sure you want to navigate away?": "\u4f60\u8fd8\u6709\u6587\u6863\u5c1a\u672a\u4fdd\u5b58\uff0c\u786e\u5b9a\u8981\u79bb\u5f00\uff1f",
+"Restore last draft": "\u6062\u590d\u4e0a\u6b21\u7684\u8349\u7a3f",
+"Special character": "\u7279\u6b8a\u7b26\u53f7",
+"Source code": "\u6e90\u4ee3\u7801",
+"Right to left": "\u4ece\u53f3\u5230\u5de6",
+"Left to right": "\u4ece\u5de6\u5230\u53f3",
+"Emoticons": "\u8868\u60c5",
+"Robots": "\u673a\u5668\u4eba",
+"Document properties": "\u6587\u6863\u5c5e\u6027",
+"Title": "\u6807\u9898",
+"Keywords": "\u5173\u952e\u8bcd",
+"Encoding": "\u7f16\u7801",
+"Description": "\u63cf\u8ff0",
+"Author": "\u4f5c\u8005",
+"Fullscreen": "\u5168\u5c4f",
+"Horizontal line": "\u6c34\u5e73\u5206\u5272\u7ebf",
+"Horizontal space": "\u6c34\u5e73\u8fb9\u8ddd",
+"Insert\/edit image": "\u63d2\u5165\/\u7f16\u8f91\u56fe\u7247",
+"General": "\u666e\u901a",
+"Advanced": "\u9ad8\u7ea7",
+"Source": "\u5730\u5740",
+"Border": "\u8fb9\u6846",
+"Constrain proportions": "\u4fdd\u6301\u7eb5\u6a2a\u6bd4",
+"Vertical space": "\u5782\u76f4\u8fb9\u8ddd",
+"Image description": "\u56fe\u7247\u63cf\u8ff0",
+"Style": "\u6837\u5f0f",
+"Dimensions": "\u5927\u5c0f",
+"Insert image": "\u63d2\u5165\u56fe\u7247",
+"Insert date\/time": "\u63d2\u5165\u65e5\u671f\/\u65f6\u95f4",
+"Remove link": "\u5220\u9664\u94fe\u63a5",
+"Url": "\u5730\u5740",
+"Text to display": "\u663e\u793a\u6587\u5b57",
+"Insert link": "\u63d2\u5165\u94fe\u63a5",
+"New window": "\u5728\u65b0\u7a97\u53e3\u6253\u5f00",
+"None": "\u65e0",
+"Target": "\u6253\u5f00\u65b9\u5f0f",
+"Insert\/edit link": "\u63d2\u5165\/\u7f16\u8f91\u94fe\u63a5",
+"Insert\/edit video": "\u63d2\u5165\/\u7f16\u8f91\u89c6\u9891",
+"Poster": "\u5c01\u9762",
+"Alternative source": "\u955c\u50cf",
+"Paste your embed code below:": "\u5c06\u5185\u5d4c\u4ee3\u7801\u7c98\u8d34\u5728\u4e0b\u9762:",
+"Insert video": "\u63d2\u5165\u89c6\u9891",
+"Embed": "\u5185\u5d4c",
+"Nonbreaking space": "\u4e0d\u95f4\u65ad\u7a7a\u683c",
+"Page break": "\u5206\u9875\u7b26",
+"Preview": "\u9884\u89c8",
+"Print": "\u6253\u5370",
+"Save": "\u4fdd\u5b58",
+"Could not find the specified string.": "\u627e\u4e0d\u5230\u8be5\u5b57\u7b26\u4e32",
+"Replace": "\u66ff\u6362",
+"Next": "\u4e0b\u4e00\u4e2a",
+"Whole words": "\u5b8c\u5168\u5339\u914d",
+"Find and replace": "\u67e5\u627e\u548c\u66ff\u6362",
+"Replace with": "\u66ff\u6362\u4e3a",
+"Find": "\u67e5\u627e",
+"Replace all": "\u5168\u90e8\u66ff\u6362",
+"Match case": "\u5927\u5c0f\u5199\u533a\u5206",
+"Prev": "\u4e0a\u4e00\u4e2a",
+"Spellcheck": "\u62fc\u5199\u68c0\u67e5",
+"Finish": "\u5b8c\u6210",
+"Ignore all": "\u5168\u90e8\u5ffd\u7565",
+"Ignore": "\u5ffd\u7565",
+"Insert row before": "\u5728\u4e0a\u65b9\u63d2\u5165",
+"Rows": "\u884c",
+"Height": "\u9ad8",
+"Paste row after": "\u7c98\u8d34\u5230\u4e0b\u65b9",
+"Alignment": "\u5bf9\u9f50\u65b9\u5f0f",
+"Column group": "\u5217\u7ec4",
+"Row": "\u884c",
+"Insert column before": "\u5728\u5de6\u4fa7\u63d2\u5165",
+"Split cell": "\u62c6\u5206\u5355\u5143\u683c",
+"Cell padding": "\u5355\u5143\u683c\u5185\u8fb9\u8ddd",
+"Cell spacing": "\u5355\u5143\u683c\u5916\u95f4\u8ddd",
+"Row type": "\u884c\u7c7b\u578b",
+"Insert table": "\u63d2\u5165\u8868\u683c",
+"Body": "\u8868\u4f53",
+"Caption": "\u6807\u9898",
+"Footer": "\u8868\u5c3e",
+"Delete row": "\u5220\u9664\u884c",
+"Paste row before": "\u7c98\u8d34\u5230\u4e0a\u65b9",
+"Scope": "\u8303\u56f4",
+"Delete table": "\u5220\u9664\u8868\u683c",
+"Header cell": "\u8868\u5934\u5355\u5143\u683c",
+"Column": "\u5217",
+"Cell": "\u5355\u5143\u683c",
+"Header": "\u8868\u5934",
+"Cell type": "\u5355\u5143\u683c\u7c7b\u578b",
+"Copy row": "\u590d\u5236\u884c",
+"Row properties": "\u884c\u5c5e\u6027",
+"Table properties": "\u8868\u683c\u5c5e\u6027",
+"Row group": "\u884c\u7ec4",
+"Right": "\u53f3\u5bf9\u9f50",
+"Insert column after": "\u63d2\u5165\u5217\u4e8e\u4e4b\u540e",
+"Cols": "\u5217",
+"Insert row after": "\u5728\u4e0b\u65b9\u63d2\u5165",
+"Width": "\u5bbd",
+"Cell properties": "\u5355\u5143\u683c\u5c5e\u6027",
+"Left": "\u5de6\u5bf9\u9f50",
+"Cut row": "\u526a\u5207\u884c",
+"Delete column": "\u5220\u9664\u5217",
+"Center": "\u5c45\u4e2d",
+"Merge cells": "\u5408\u5e76\u5355\u5143\u683c",
+"Insert template": "\u63d2\u5165\u6a21\u677f",
+"Templates": "\u6a21\u677f",
+"Background color": "\u80cc\u666f\u8272",
+"Text color": "\u6587\u5b57\u989c\u8272",
+"Show blocks": "\u663e\u793a\u865a\u7ebf\u6846",
+"Show invisible characters": "\u663e\u793a\u53ef\u89c1\u5b57\u7b26",
+"Words: {0}": "\u5b57\u6570\uff1a{0}",
+"Insert": "\u63d2\u5165",
+"File": "\u6587\u4ef6",
+"Edit": "\u7f16\u8f91",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u5728\u7f16\u8f91\u533a\u6309ALT-F9\u6253\u5f00\u83dc\u5355\uff0c\u6309ALT-F10\u6253\u5f00\u5de5\u5177\u680f\uff0c\u6309ALT-0\u67e5\u770b\u5e2e\u52a9",
+"Tools": "\u5de5\u5177",
+"View": "\u89c6\u56fe",
+"Table": "\u8868\u683c",
+"Format": "\u683c\u5f0f"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/zh_TW.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/zh_TW.js
new file mode 100755
index 0000000..64826fe
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/langs/zh_TW.js
@@ -0,0 +1,175 @@
+tinymce.addI18n('zh_TW',{
+"Cut": "\u526a\u4e0b",
+"Header 2": "\u6a19\u984c 2",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u60a8\u7684\u700f\u89bd\u5668\u4e0d\u652f\u63f4\u5b58\u53d6\u526a\u8cbc\u7c3f\uff0c\u53ef\u4ee5\u4f7f\u7528\u5feb\u901f\u9375 Ctrl + X\/C\/V \u4ee3\u66ff\u526a\u4e0b\u3001\u8907\u88fd\u8207\u8cbc\u4e0a\u3002",
+"Div": "Div",
+"Paste": "\u8cbc\u4e0a",
+"Close": "\u95dc\u9589",
+"Pre": "Pre",
+"Align right": "\u7f6e\u53f3\u5c0d\u9f4a",
+"New document": "\u65b0\u6587\u4ef6",
+"Blockquote": "\u5f15\u7528",
+"Numbered list": "\u6578\u5b57\u6e05\u55ae",
+"Increase indent": "\u589e\u52a0\u7e2e\u6392",
+"Formats": "\u683c\u5f0f",
+"Headers": "\u6a19\u984c",
+"Select all": "\u5168\u9078",
+"Header 3": "\u6a19\u984c 3",
+"Blocks": "\u5340\u584a",
+"Undo": "\u5fa9\u539f",
+"Strikethrough": "\u522a\u9664\u7dda",
+"Bullet list": "\u9805\u76ee\u6e05\u55ae",
+"Header 1": "\u6a19\u984c 1",
+"Superscript": "\u4e0a\u6a19",
+"Clear formatting": "\u6e05\u9664\u683c\u5f0f",
+"Subscript": "\u4e0b\u6a19",
+"Header 6": "\u6a19\u984c 6",
+"Redo": "\u53d6\u6d88\u5fa9\u539f",
+"Paragraph": "\u6bb5\u843d",
+"Ok": "\u78ba\u5b9a",
+"Bold": "\u7c97\u9ad4",
+"Code": "\u7a0b\u5f0f\u78bc",
+"Italic": "\u659c\u9ad4",
+"Align center": "\u7f6e\u4e2d\u5c0d\u9f4a",
+"Header 5": "\u6a19\u984c 5",
+"Decrease indent": "\u6e1b\u5c11\u7e2e\u6392",
+"Header 4": "\u6a19\u984c 4",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u76ee\u524d\u5c07\u4ee5\u7d14\u6587\u5b57\u7684\u6a21\u5f0f\u8cbc\u4e0a\uff0c\u60a8\u53ef\u4ee5\u518d\u9ede\u9078\u4e00\u6b21\u53d6\u6d88\u3002",
+"Underline": "\u5e95\u7dda",
+"Cancel": "\u53d6\u6d88",
+"Justify": "\u5de6\u53f3\u5c0d\u9f4a",
+"Inline": "Inline",
+"Copy": "\u8907\u88fd",
+"Align left": "\u7f6e\u5de6\u5c0d\u9f4a",
+"Visual aids": "\u5c0f\u5e6b\u624b",
+"Lower Greek": "\u5e0c\u81d8\u5b57\u6bcd",
+"Square": "\u6b63\u65b9\u5f62",
+"Default": "\u9810\u8a2d",
+"Lower Alpha": "\u5c0f\u5beb\u82f1\u6587\u5b57\u6bcd",
+"Circle": "\u7a7a\u5fc3\u5713",
+"Disc": "\u5be6\u5fc3\u5713",
+"Upper Alpha": "\u5927\u5beb\u82f1\u6587\u5b57\u6bcd",
+"Upper Roman": "\u5927\u5beb\u7f85\u99ac\u6578\u5b57",
+"Lower Roman": "\u5c0f\u5beb\u7f85\u99ac\u6578\u5b57",
+"Name": "\u540d\u7a31",
+"Anchor": "\u52a0\u5165\u9328\u9ede",
+"You have unsaved changes are you sure you want to navigate away?": "\u7de8\u8f2f\u5c1a\u672a\u88ab\u5132\u5b58\uff0c\u4f60\u78ba\u5b9a\u8981\u96e2\u958b\uff1f",
+"Restore last draft": "\u8f09\u5165\u4e0a\u4e00\u6b21\u7de8\u8f2f\u7684\u8349\u7a3f",
+"Special character": "\u7279\u6b8a\u5b57\u5143",
+"Source code": "\u539f\u59cb\u78bc",
+"Right to left": "\u5f9e\u53f3\u5230\u5de6",
+"Left to right": "\u5f9e\u5de6\u5230\u53f3",
+"Emoticons": "\u8868\u60c5",
+"Robots": "\u6a5f\u5668\u4eba",
+"Document properties": "\u6587\u4ef6\u7684\u5c6c\u6027",
+"Title": "\u6a19\u984c",
+"Keywords": "\u95dc\u9375\u5b57",
+"Encoding": "\u7de8\u78bc",
+"Description": "\u63cf\u8ff0",
+"Author": "\u4f5c\u8005",
+"Fullscreen": "\u5168\u87a2\u5e55",
+"Horizontal line": "\u6c34\u5e73\u7dda",
+"Horizontal space": "\u5bec\u5ea6",
+"Insert\/edit image": "\u63d2\u5165\/\u7de8\u8f2f \u5716\u7247",
+"General": "\u4e00\u822c\u7684",
+"Advanced": "\u9032\u968e",
+"Source": "\u5716\u7247\u7db2\u5740",
+"Border": "\u908a\u6846",
+"Constrain proportions": "\u88ab\u9650\u5236\u7684\u90e8\u5206",
+"Vertical space": "\u9ad8\u5ea6",
+"Image description": "\u5716\u7247\u63cf\u8ff0",
+"Style": "\u985e\u578b",
+"Dimensions": "\u5c3a\u5bf8",
+"Insert image": "\u63d2\u5165\u5716\u7247",
+"Insert date\/time": "\u63d2\u5165 \u65e5\u671f\/\u6642\u9593",
+"Remove link": "\u79fb\u9664\u9023\u7d50",
+"Url": "\u7db2\u5740",
+"Text to display": "\u986f\u793a\u6587\u5b57",
+"Anchors": "\u52a0\u5165\u9328\u9ede",
+"Insert link": "\u63d2\u5165\u9023\u7d50",
+"New window": "\u65b0\u8996\u7a97",
+"None": "\u7121",
+"Target": "\u76ee\u6a19",
+"Insert\/edit link": "\u63d2\u5165\/\u7de8\u8f2f\u9023\u7d50",
+"Insert\/edit video": "\u63d2\u4ef6\u5f0f\/\u53ef\u7de8\u8f2f \u5f71\u97f3",
+"Poster": "\u6a19\u8a9e",
+"Alternative source": "\u984d\u5916\u8cc7\u6e90",
+"Paste your embed code below:": "\u8acb\u5c07\u60a8\u7684\u5d4c\u5165\u5f0f\u7a0b\u5f0f\u78bc\u8cbc\u5728\u4e0b\u9762:",
+"Insert video": "\u63d2\u4ef6\u5f0f\u5f71\u97f3",
+"Embed": "\u5d4c\u5165",
+"Nonbreaking space": "\u4e0d\u5206\u884c\u7684\u7a7a\u683c",
+"Page break": "\u5206\u9801",
+"Paste as text": "\u4ee5\u7d14\u6587\u5b57\u8cbc\u4e0a",
+"Preview": "\u9810\u89bd",
+"Print": "\u5217\u5370",
+"Save": "\u5132\u5b58",
+"Could not find the specified string.": "\u7121\u6cd5\u67e5\u8a62\u5230\u6b64\u7279\u5b9a\u5b57\u4e32",
+"Replace": "\u66ff\u63db",
+"Next": "\u4e0b\u4e00\u500b",
+"Whole words": "\u6574\u500b\u55ae\u5b57",
+"Find and replace": "\u5c0b\u627e\u53ca\u53d6\u4ee3",
+"Replace with": "\u66f4\u63db",
+"Find": "\u641c\u5c0b",
+"Replace all": "\u66ff\u63db\u5168\u90e8",
+"Match case": "\u76f8\u5339\u914d\u6848\u4ef6",
+"Prev": "\u4e0a\u4e00\u500b",
+"Spellcheck": "\u62fc\u5b57\u6aa2\u67e5",
+"Finish": "\u5b8c\u6210",
+"Ignore all": "\u5ffd\u7565\u6240\u6709",
+"Ignore": "\u5ffd\u7565",
+"Insert row before": "\u63d2\u5165\u5217\u5728...\u4e4b\u524d",
+"Rows": "\u5217",
+"Height": "\u9ad8\u5ea6",
+"Paste row after": "\u8cbc\u4e0a\u5217\u5728...\u4e4b\u5f8c",
+"Alignment": "\u5c0d\u9f4a",
+"Column group": "\u6b04\u4f4d\u7fa4\u7d44",
+"Row": "\u5217",
+"Insert column before": "\u63d2\u5165\u6b04\u4f4d\u5728...\u4e4b\u524d",
+"Split cell": "\u5206\u5272\u5132\u5b58\u683c",
+"Cell padding": "\u5132\u5b58\u683c\u7684\u908a\u8ddd",
+"Cell spacing": "\u5132\u5b58\u683c\u5f97\u9593\u8ddd",
+"Row type": "\u884c\u7684\u985e\u578b",
+"Insert table": "\u63d2\u5165\u8868\u683c",
+"Body": "\u4e3b\u9ad4",
+"Caption": "\u8868\u683c\u6a19\u984c",
+"Footer": "\u9801\u5c3e",
+"Delete row": "\u522a\u9664\u5217",
+"Paste row before": "\u8cbc\u4e0a\u5217\u5728...\u4e4b\u524d",
+"Scope": "\u7bc4\u570d",
+"Delete table": "\u522a\u9664\u8868\u683c",
+"Header cell": "\u6a19\u982d\u5132\u5b58\u683c",
+"Column": "\u884c",
+"Cell": "\u5132\u5b58\u683c",
+"Header": "\u6a19\u982d",
+"Cell type": "\u5132\u5b58\u683c\u7684\u985e\u578b",
+"Copy row": "\u8907\u88fd\u5217",
+"Row properties": "\u5217\u5c6c\u6027",
+"Table properties": "\u8868\u683c\u5c6c\u6027",
+"Row group": "\u5217\u7fa4\u7d44",
+"Right": "\u53f3\u908a",
+"Insert column after": "\u63d2\u5165\u6b04\u4f4d\u5728...\u4e4b\u5f8c",
+"Cols": "\u6b04\u4f4d\u6bb5",
+"Insert row after": "\u63d2\u5165\u5217\u5728...\u4e4b\u5f8c",
+"Width": "\u5bec\u5ea6",
+"Cell properties": "\u5132\u5b58\u683c\u5c6c\u6027",
+"Left": "\u5de6\u908a",
+"Cut row": "\u526a\u4e0b\u5217",
+"Delete column": "\u522a\u9664\u884c",
+"Center": "\u4e2d\u9593",
+"Merge cells": "\u5408\u4f75\u5132\u5b58\u683c",
+"Insert template": "\u63d2\u5165\u6a23\u7248",
+"Templates": "\u6a23\u7248",
+"Background color": "\u80cc\u666f\u984f\u8272",
+"Text color": "\u6587\u5b57\u984f\u8272",
+"Show blocks": "\u986f\u793a\u5340\u584a\u8cc7\u8a0a",
+"Show invisible characters": "\u986f\u793a\u96b1\u85cf\u5b57\u5143",
+"Words: {0}": "\u5b57\u6578\uff1a{0}",
+"Insert": "\u63d2\u5165",
+"File": "\u6a94\u6848",
+"Edit": "\u7de8\u8f2f",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u8c50\u5bcc\u7684\u6587\u672c\u5340\u57df\u3002\u6309ALT-F9\u524d\u5f80\u4e3b\u9078\u55ae\u3002\u6309ALT-F10\u547c\u53eb\u5de5\u5177\u6b04\u3002\u6309ALT-0\u5c0b\u6c42\u5e6b\u52a9",
+"Tools": "\u5de5\u5177",
+"View": "\u6aa2\u8996",
+"Table": "\u8868\u683c",
+"Format": "\u683c\u5f0f"
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/license.txt b/lib/prado/framework/Web/Javascripts/source/tinymce-405/license.txt
new file mode 100755
index 0000000..1837b0a
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/license.txt
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/advlist/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/advlist/plugin.min.js
new file mode 100755
index 0000000..da1cdb2
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/advlist/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("advlist",function(t){function e(t,e){var n=[];return tinymce.each(e.split(/[ ,]/),function(t){n.push({text:t.replace(/\-/g," ").replace(/\b\w/g,function(t){return t.toUpperCase()}),data:"default"==t?"":t})}),n}function n(e,n){var i,r=t.dom,a=t.selection;i=r.getParent(a.getNode(),"ol,ul"),i&&i.nodeName==e&&n!==!1||t.execCommand("UL"==e?"InsertUnorderedList":"InsertOrderedList"),n=n===!1?o[e]:n,o[e]=n,i=r.getParent(a.getNode(),"ol,ul"),i&&(r.setStyle(i,"listStyleType",n),i.removeAttribute("data-mce-style")),t.focus()}function i(e){var n=t.dom.getStyle(t.dom.getParent(t.selection.getNode(),"ol,ul"),"listStyleType")||"";e.control.items().each(function(t){t.active(t.settings.data===n)})}var r,a,o={};r=e("OL",t.getParam("advlist_number_styles","default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman")),a=e("UL",t.getParam("advlist_bullet_styles","default,circle,disc,square")),t.addButton("numlist",{type:"splitbutton",tooltip:"Numbered list",menu:r,onshow:i,onselect:function(t){n("OL",t.control.settings.data)},onclick:function(){n("OL",!1)}}),t.addButton("bullist",{type:"splitbutton",tooltip:"Bullet list",menu:a,onshow:i,onselect:function(t){n("UL",t.control.settings.data)},onclick:function(){n("UL",!1)}})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/anchor/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/anchor/plugin.min.js
new file mode 100755
index 0000000..6a3fd79
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/anchor/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("anchor",function(e){function t(){var t=e.selection.getNode();e.windowManager.open({title:"Anchor",body:{type:"textbox",name:"name",size:40,label:"Name",value:t.name||t.id},onsubmit:function(t){e.execCommand("mceInsertContent",!1,e.dom.createHTML("a",{id:t.data.name}))}})}e.addButton("anchor",{icon:"anchor",tooltip:"Anchor",onclick:t,stateSelector:"a:not([href])"}),e.addMenuItem("anchor",{icon:"anchor",text:"Anchor",context:"insert",onclick:t})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/autolink/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/autolink/plugin.min.js
new file mode 100755
index 0000000..3d2f58e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/autolink/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("autolink",function(t){function e(t){o(t,-1,"(",!0)}function n(t){o(t,0,"",!0)}function i(t){o(t,-1,"",!1)}function o(t,e,n){var i,o,r,a,s,l,c,u,d;if(i=t.selection.getRng(!0).cloneRange(),i.startOffset<5){if(u=i.endContainer.previousSibling,!u){if(!i.endContainer.firstChild||!i.endContainer.firstChild.nextSibling)return;u=i.endContainer.firstChild.nextSibling}if(d=u.length,i.setStart(u,d),i.setEnd(u,d),i.endOffset<5)return;o=i.endOffset,a=u}else{if(a=i.endContainer,3!=a.nodeType&&a.firstChild){for(;3!=a.nodeType&&a.firstChild;)a=a.firstChild;3==a.nodeType&&(i.setStart(a,0),i.setEnd(a,a.nodeValue.length))}o=1==i.endOffset?2:i.endOffset-1-e}r=o;do i.setStart(a,o>=2?o-2:0),i.setEnd(a,o>=1?o-1:0),o-=1;while(" "!=i.toString()&&""!==i.toString()&&160!=i.toString().charCodeAt(0)&&o-2>=0&&i.toString()!=n);if(i.toString()==n||160==i.toString().charCodeAt(0)?(i.setStart(a,o),i.setEnd(a,r),o+=1):0===i.startOffset?(i.setStart(a,0),i.setEnd(a,r)):(i.setStart(a,o),i.setEnd(a,r)),l=i.toString(),"."==l.charAt(l.length-1)&&i.setEnd(a,r-1),l=i.toString(),c=l.match(/^(https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.|(?:mailto:)?[A-Z0-9._%+\-]+@)(.+)$/i),c&&("www."==c[1]?c[1]="http://www.":/@$/.test(c[1])&&!/^mailto:/.test(c[1])&&(c[1]="mailto:"+c[1]),s=t.selection.getBookmark(),t.selection.setRng(i),t.execCommand("createlink",!1,c[1]+c[2]),t.selection.moveToBookmark(s),t.nodeChanged(),tinymce.Env.webkit)){t.selection.collapse(!1);var m=Math.min(a.length,r+1);i.setStart(a,m),i.setEnd(a,m),t.selection.setRng(i)}}t.on("keydown",function(e){return 13==e.keyCode?i(t):void 0}),tinymce.Env.ie||(t.on("keypress",function(n){return 41==n.which?e(t):void 0}),t.on("keyup",function(e){return 32==e.keyCode?n(t):void 0}))}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/autoresize/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/autoresize/plugin.min.js
new file mode 100755
index 0000000..12355aa
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/autoresize/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("autoresize",function(e){function t(a){var r,o,c=e.getDoc(),s=c.body,u=c.documentElement,l=tinymce.DOM,m=n.autoresize_min_height;"setcontent"==a.type&&a.initial||e.plugins.fullscreen&&e.plugins.fullscreen.isFullscreen()||(o=tinymce.Env.ie?s.scrollHeight:tinymce.Env.webkit&&0===s.clientHeight?0:s.offsetHeight,o>n.autoresize_min_height&&(m=o),n.autoresize_max_height&&o>n.autoresize_max_height?(m=n.autoresize_max_height,s.style.overflowY="auto",u.style.overflowY="auto"):(s.style.overflowY="hidden",u.style.overflowY="hidden",s.scrollTop=0),m!==i&&(r=m-i,l.setStyle(l.get(e.id+"_ifr"),"height",m+"px"),i=m,tinymce.isWebKit&&0>r&&t(a)))}var n=e.settings,i=0;e.settings.inline||(n.autoresize_min_height=parseInt(e.getParam("autoresize_min_height",e.getElement().offsetHeight),10),n.autoresize_max_height=parseInt(e.getParam("autoresize_max_height",0),10),e.on("init",function(){e.dom.setStyle(e.getBody(),"paddingBottom",e.getParam("autoresize_bottom_margin",50)+"px")}),e.on("change setcontent paste keyup",t),e.getParam("autoresize_on_init",!0)&&e.on("load",t),e.addCommand("mceAutoResize",t))}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/autosave/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/autosave/plugin.min.js
new file mode 100755
index 0000000..93ee1df
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/autosave/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("autosave",function(e){function t(e,t){var n={s:1e3,m:6e4};return e=/^(\d+)([ms]?)$/.exec(""+(e||t)),(e[2]?n[e[2]]:1)*parseInt(e,10)}function n(){var e=parseInt(f.getItem(h+"autosave.time"),10)||0;return(new Date).getTime()-e>d.autosave_retention?(i(!1),!1):!0}function i(t){f.removeItem(h+"autosave.draft"),f.removeItem(h+"autosave.time"),t!==!1&&e.fire("RemoveDraft")}function a(){c()||(f.setItem(h+"autosave.draft",e.getContent({format:"raw",no_events:!0})),f.setItem(h+"autosave.time",(new Date).getTime()),e.fire("StoreDraft"))}function r(){n()&&(e.setContent(f.getItem(h+"autosave.draft"),{format:"raw"}),e.fire("RestoreDraft"))}function o(){m||(setInterval(function(){e.removed||a()},d.autosave_interval),m=!0)}function s(){var t=this;t.disabled(!n()),e.on("StoreDraft RestoreDraft RemoveDraft",function(){t.disabled(!n())}),o()}function l(){e.undoManager.beforeChange(),r(),i(),e.undoManager.add()}function u(){var e;return tinymce.each(tinymce.editors,function(t){t.plugins.autosave&&t.plugins.autosave.storeDraft(),!e&&t.isDirty()&&t.getParam("autosave_ask_before_unload",!0)&&(e=t.translate("You have unsaved changes are you sure you want to navigate away?"))}),e}function c(t){var n=e.settings.forced_root_block;return t=tinymce.trim("undefined"==typeof t?e.getBody().innerHTML:t),""===t||new RegExp("^<"+n+">(( |&nbsp;|[ ]|<br[^>]*>)+?|)</"+n+">|<br>$","i").test(t)}var m,d=e.settings,f=tinymce.util.LocalStorage,h=e.id;d.autosave_interval=t(d.autosave_interval,"30s"),d.autosave_retention=t(d.autosave_retention,"20m"),e.addButton("restoredraft",{title:"Restore last draft",onclick:l,onPostRender:s}),e.addMenuItem("restoredraft",{text:"Restore last draft",onclick:l,onPostRender:s,context:"file"}),e.settings.autosave_restore_when_empty!==!1&&(e.on("init",function(){n()&&c()&&r()}),e.on("saveContent",function(){i()})),window.onbeforeunload=u,this.hasDraft=n,this.storeDraft=a,this.restoreDraft=r,this.removeDraft=i,this.isEmpty=c}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/bbcode/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/bbcode/plugin.min.js
new file mode 100755
index 0000000..70a88a7
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/bbcode/plugin.min.js
@@ -0,0 +1 @@
+!function(){tinymce.create("tinymce.plugins.BBCodePlugin",{init:function(e){var t=this,n=e.getParam("bbcode_dialect","punbb").toLowerCase();e.on("beforeSetContent",function(e){e.content=t["_"+n+"_bbcode2html"](e.content)}),e.on("postProcess",function(e){e.set&&(e.content=t["_"+n+"_bbcode2html"](e.content)),e.get&&(e.content=t["_"+n+"_html2bbcode"](e.content))})},getInfo:function(){return{longname:"BBCode Plugin",author:"Moxiecode Systems AB",authorurl:"http://www.tinymce.com",infourl:"http://www.tinymce.com/wiki.php/Plugin:bbcode"}},_punbb_html2bbcode:function(e){function t(t,n){e=e.replace(t,n)}return e=tinymce.trim(e),t(/<a.*?href=\"(.*?)\".*?>(.*?)<\/a>/gi,"[url=$1]$2[/url]"),t(/<font.*?color=\"(.*?)\".*?class=\"codeStyle\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"),t(/<font.*?color=\"(.*?)\".*?class=\"quoteStyle\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"),t(/<font.*?class=\"codeStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"),t(/<font.*?class=\"quoteStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"),t(/<span style=\"color: ?(.*?);\">(.*?)<\/span>/gi,"[color=$1]$2[/color]"),t(/<font.*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[color=$1]$2[/color]"),t(/<span style=\"font-size:(.*?);\">(.*?)<\/span>/gi,"[size=$1]$2[/size]"),t(/<font>(.*?)<\/font>/gi,"$1"),t(/<img.*?src=\"(.*?)\".*?\/>/gi,"[img]$1[/img]"),t(/<span class=\"codeStyle\">(.*?)<\/span>/gi,"[code]$1[/code]"),t(/<span class=\"quoteStyle\">(.*?)<\/span>/gi,"[quote]$1[/quote]"),t(/<strong class=\"codeStyle\">(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]"),t(/<strong class=\"quoteStyle\">(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]"),t(/<em class=\"codeStyle\">(.*?)<\/em>/gi,"[code][i]$1[/i][/code]"),t(/<em class=\"quoteStyle\">(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]"),t(/<u class=\"codeStyle\">(.*?)<\/u>/gi,"[code][u]$1[/u][/code]"),t(/<u class=\"quoteStyle\">(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]"),t(/<\/(strong|b)>/gi,"[/b]"),t(/<(strong|b)>/gi,"[b]"),t(/<\/(em|i)>/gi,"[/i]"),t(/<(em|i)>/gi,"[i]"),t(/<\/u>/gi,"[/u]"),t(/<span style=\"text-decoration: ?underline;\">(.*?)<\/span>/gi,"[u]$1[/u]"),t(/<u>/gi,"[u]"),t(/<blockquote[^>]*>/gi,"[quote]"),t(/<\/blockquote>/gi,"[/quote]"),t(/<br \/>/gi,"\n"),t(/<br\/>/gi,"\n"),t(/<br>/gi,"\n"),t(/<p>/gi,""),t(/<\/p>/gi,"\n"),t(/&nbsp;|\u00a0/gi," "),t(/&quot;/gi,'"'),t(/&lt;/gi,"<"),t(/&gt;/gi,">"),t(/&amp;/gi,"&"),e},_punbb_bbcode2html:function(e){function t(t,n){e=e.replace(t,n)}return e=tinymce.trim(e),t(/\n/gi,"<br />"),t(/\[b\]/gi,"<strong>"),t(/\[\/b\]/gi,"</strong>"),t(/\[i\]/gi,"<em>"),t(/\[\/i\]/gi,"</em>"),t(/\[u\]/gi,"<u>"),t(/\[\/u\]/gi,"</u>"),t(/\[url=([^\]]+)\](.*?)\[\/url\]/gi,'<a href="$1">$2</a>'),t(/\[url\](.*?)\[\/url\]/gi,'<a href="$1">$1</a>'),t(/\[img\](.*?)\[\/img\]/gi,'<img src="$1" />'),t(/\[color=(.*?)\](.*?)\[\/color\]/gi,'<font color="$1">$2</font>'),t(/\[code\](.*?)\[\/code\]/gi,'<span class="codeStyle">$1</span>&nbsp;'),t(/\[quote.*?\](.*?)\[\/quote\]/gi,'<span class="quoteStyle">$1</span>&nbsp;'),e}}),tinymce.PluginManager.add("bbcode",tinymce.plugins.BBCodePlugin)}(); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/charmap/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/charmap/plugin.min.js
new file mode 100755
index 0000000..dff18e6
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/charmap/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("charmap",function(e){function t(){function t(e){for(;e;){if("TD"==e.nodeName)return e;e=e.parentNode}}var i,a,r,o;i='<table role="presentation" cellspacing="0" class="mce-charmap"><tbody>';var s=25;for(r=0;10>r;r++){for(i+="<tr>",a=0;s>a;a++){var l=n[r*s+a],c="g"+(r*s+a);i+='<td title="'+l[1]+'"><div id="'+c+'" tabIndex="-1">'+(l?String.fromCharCode(parseInt(l[0],10)):"&nbsp;")+"</div></td>"}i+="</tr>"}i+="</tbody></table>";var u={type:"container",html:i,onclick:function(t){var n=t.target;"DIV"==n.nodeName&&e.execCommand("mceInsertContent",!1,n.firstChild.nodeValue)},onmouseover:function(e){var n=t(e.target);n&&o.find("#preview").text(n.firstChild.firstChild.data)}};o=e.windowManager.open({title:"Special character",spacing:10,padding:10,items:[u,{type:"label",name:"preview",text:" ",style:"font-size: 40px; text-align: center",border:1,minWidth:100,minHeight:80}],buttons:[{text:"Close",onclick:function(){o.close()}}]})}var n=[["160","no-break space"],["38","ampersand"],["34","quotation mark"],["162","cent sign"],["8364","euro sign"],["163","pound sign"],["165","yen sign"],["169","copyright sign"],["174","registered sign"],["8482","trade mark sign"],["8240","per mille sign"],["181","micro sign"],["183","middle dot"],["8226","bullet"],["8230","three dot leader"],["8242","minutes / feet"],["8243","seconds / inches"],["167","section sign"],["182","paragraph sign"],["223","sharp s / ess-zed"],["8249","single left-pointing angle quotation mark"],["8250","single right-pointing angle quotation mark"],["171","left pointing guillemet"],["187","right pointing guillemet"],["8216","left single quotation mark"],["8217","right single quotation mark"],["8220","left double quotation mark"],["8221","right double quotation mark"],["8218","single low-9 quotation mark"],["8222","double low-9 quotation mark"],["60","less-than sign"],["62","greater-than sign"],["8804","less-than or equal to"],["8805","greater-than or equal to"],["8211","en dash"],["8212","em dash"],["175","macron"],["8254","overline"],["164","currency sign"],["166","broken bar"],["168","diaeresis"],["161","inverted exclamation mark"],["191","turned question mark"],["710","circumflex accent"],["732","small tilde"],["176","degree sign"],["8722","minus sign"],["177","plus-minus sign"],["247","division sign"],["8260","fraction slash"],["215","multiplication sign"],["185","superscript one"],["178","superscript two"],["179","superscript three"],["188","fraction one quarter"],["189","fraction one half"],["190","fraction three quarters"],["402","function / florin"],["8747","integral"],["8721","n-ary sumation"],["8734","infinity"],["8730","square root"],["8764","similar to"],["8773","approximately equal to"],["8776","almost equal to"],["8800","not equal to"],["8801","identical to"],["8712","element of"],["8713","not an element of"],["8715","contains as member"],["8719","n-ary product"],["8743","logical and"],["8744","logical or"],["172","not sign"],["8745","intersection"],["8746","union"],["8706","partial differential"],["8704","for all"],["8707","there exists"],["8709","diameter"],["8711","backward difference"],["8727","asterisk operator"],["8733","proportional to"],["8736","angle"],["180","acute accent"],["184","cedilla"],["170","feminine ordinal indicator"],["186","masculine ordinal indicator"],["8224","dagger"],["8225","double dagger"],["192","A - grave"],["193","A - acute"],["194","A - circumflex"],["195","A - tilde"],["196","A - diaeresis"],["197","A - ring above"],["198","ligature AE"],["199","C - cedilla"],["200","E - grave"],["201","E - acute"],["202","E - circumflex"],["203","E - diaeresis"],["204","I - grave"],["205","I - acute"],["206","I - circumflex"],["207","I - diaeresis"],["208","ETH"],["209","N - tilde"],["210","O - grave"],["211","O - acute"],["212","O - circumflex"],["213","O - tilde"],["214","O - diaeresis"],["216","O - slash"],["338","ligature OE"],["352","S - caron"],["217","U - grave"],["218","U - acute"],["219","U - circumflex"],["220","U - diaeresis"],["221","Y - acute"],["376","Y - diaeresis"],["222","THORN"],["224","a - grave"],["225","a - acute"],["226","a - circumflex"],["227","a - tilde"],["228","a - diaeresis"],["229","a - ring above"],["230","ligature ae"],["231","c - cedilla"],["232","e - grave"],["233","e - acute"],["234","e - circumflex"],["235","e - diaeresis"],["236","i - grave"],["237","i - acute"],["238","i - circumflex"],["239","i - diaeresis"],["240","eth"],["241","n - tilde"],["242","o - grave"],["243","o - acute"],["244","o - circumflex"],["245","o - tilde"],["246","o - diaeresis"],["248","o slash"],["339","ligature oe"],["353","s - caron"],["249","u - grave"],["250","u - acute"],["251","u - circumflex"],["252","u - diaeresis"],["253","y - acute"],["254","thorn"],["255","y - diaeresis"],["913","Alpha"],["914","Beta"],["915","Gamma"],["916","Delta"],["917","Epsilon"],["918","Zeta"],["919","Eta"],["920","Theta"],["921","Iota"],["922","Kappa"],["923","Lambda"],["924","Mu"],["925","Nu"],["926","Xi"],["927","Omicron"],["928","Pi"],["929","Rho"],["931","Sigma"],["932","Tau"],["933","Upsilon"],["934","Phi"],["935","Chi"],["936","Psi"],["937","Omega"],["945","alpha"],["946","beta"],["947","gamma"],["948","delta"],["949","epsilon"],["950","zeta"],["951","eta"],["952","theta"],["953","iota"],["954","kappa"],["955","lambda"],["956","mu"],["957","nu"],["958","xi"],["959","omicron"],["960","pi"],["961","rho"],["962","final sigma"],["963","sigma"],["964","tau"],["965","upsilon"],["966","phi"],["967","chi"],["968","psi"],["969","omega"],["8501","alef symbol"],["982","pi symbol"],["8476","real part symbol"],["978","upsilon - hook symbol"],["8472","Weierstrass p"],["8465","imaginary part"],["8592","leftwards arrow"],["8593","upwards arrow"],["8594","rightwards arrow"],["8595","downwards arrow"],["8596","left right arrow"],["8629","carriage return"],["8656","leftwards double arrow"],["8657","upwards double arrow"],["8658","rightwards double arrow"],["8659","downwards double arrow"],["8660","left right double arrow"],["8756","therefore"],["8834","subset of"],["8835","superset of"],["8836","not a subset of"],["8838","subset of or equal to"],["8839","superset of or equal to"],["8853","circled plus"],["8855","circled times"],["8869","perpendicular"],["8901","dot operator"],["8968","left ceiling"],["8969","right ceiling"],["8970","left floor"],["8971","right floor"],["9001","left-pointing angle bracket"],["9002","right-pointing angle bracket"],["9674","lozenge"],["9824","black spade suit"],["9827","black club suit"],["9829","black heart suit"],["9830","black diamond suit"],["8194","en space"],["8195","em space"],["8201","thin space"],["8204","zero width non-joiner"],["8205","zero width joiner"],["8206","left-to-right mark"],["8207","right-to-left mark"],["173","soft hyphen"]];e.addButton("charmap",{icon:"charmap",tooltip:"Special character",onclick:t}),e.addMenuItem("charmap",{icon:"charmap",text:"Special character",onclick:t,context:"insert"})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/code/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/code/plugin.min.js
new file mode 100755
index 0000000..ed9646f
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/code/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("code",function(e){function t(){e.windowManager.open({title:"Source code",body:{type:"textbox",name:"code",multiline:!0,minWidth:e.getParam("code_dialog_width",600),minHeight:e.getParam("code_dialog_height",500),value:e.getContent({source_view:!0}),spellcheck:!1},onSubmit:function(t){e.undoManager.transact(function(){e.setContent(t.data.code)}),e.nodeChanged()}})}e.addCommand("mceCodeEditor",t),e.addButton("code",{icon:"code",tooltip:"Source code",onclick:t}),e.addMenuItem("code",{icon:"code",text:"Source code",context:"tools",onclick:t})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/editable_selects.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/editable_selects.js
new file mode 100755
index 0000000..8d30787
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/editable_selects.js
@@ -0,0 +1,70 @@
+/**
+ * editable_selects.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+var TinyMCE_EditableSelects = {
+ editSelectElm : null,
+
+ init : function() {
+ var nl = document.getElementsByTagName("select"), i, d = document, o;
+
+ for (i=0; i<nl.length; i++) {
+ if (nl[i].className.indexOf('mceEditableSelect') != -1) {
+ o = new Option(tinyMCEPopup.editor.translate('value'), '__mce_add_custom__');
+
+ o.className = 'mceAddSelectValue';
+
+ nl[i].options[nl[i].options.length] = o;
+ nl[i].onchange = TinyMCE_EditableSelects.onChangeEditableSelect;
+ }
+ }
+ },
+
+ onChangeEditableSelect : function(e) {
+ var d = document, ne, se = window.event ? window.event.srcElement : e.target;
+
+ if (se.options[se.selectedIndex].value == '__mce_add_custom__') {
+ ne = d.createElement("input");
+ ne.id = se.id + "_custom";
+ ne.name = se.name + "_custom";
+ ne.type = "text";
+
+ ne.style.width = se.offsetWidth + 'px';
+ se.parentNode.insertBefore(ne, se);
+ se.style.display = 'none';
+ ne.focus();
+ ne.onblur = TinyMCE_EditableSelects.onBlurEditableSelectInput;
+ ne.onkeydown = TinyMCE_EditableSelects.onKeyDown;
+ TinyMCE_EditableSelects.editSelectElm = se;
+ }
+ },
+
+ onBlurEditableSelectInput : function() {
+ var se = TinyMCE_EditableSelects.editSelectElm;
+
+ if (se) {
+ if (se.previousSibling.value != '') {
+ addSelectValue(document.forms[0], se.id, se.previousSibling.value, se.previousSibling.value);
+ selectByValue(document.forms[0], se.id, se.previousSibling.value);
+ } else
+ selectByValue(document.forms[0], se.id, '');
+
+ se.style.display = 'inline';
+ se.parentNode.removeChild(se.previousSibling);
+ TinyMCE_EditableSelects.editSelectElm = null;
+ }
+ },
+
+ onKeyDown : function(e) {
+ e = e || window.event;
+
+ if (e.keyCode == 13)
+ TinyMCE_EditableSelects.onBlurEditableSelectInput();
+ }
+};
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/form_utils.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/form_utils.js
new file mode 100755
index 0000000..69d338f
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/form_utils.js
@@ -0,0 +1,210 @@
+/**
+ * form_utils.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+var themeBaseURL = tinyMCEPopup.editor.baseURI.toAbsolute('themes/' + tinyMCEPopup.getParam("theme"));
+
+function getColorPickerHTML(id, target_form_element) {
+ var h = "", dom = tinyMCEPopup.dom;
+
+ if (label = dom.select('label[for=' + target_form_element + ']')[0]) {
+ label.id = label.id || dom.uniqueId();
+ }
+
+ h += '<a role="button" aria-labelledby="' + id + '_label" id="' + id + '_link" href="javascript:;" onclick="tinyMCEPopup.pickColor(event,\'' + target_form_element +'\');" onmousedown="return false;" class="pickcolor">';
+ h += '<span id="' + id + '" title="' + tinyMCEPopup.getLang('browse') + '">&nbsp;<span id="' + id + '_label" class="mceVoiceLabel mceIconOnly" style="display:none;">' + tinyMCEPopup.getLang('browse') + '</span></span></a>';
+
+ return h;
+}
+
+function updateColor(img_id, form_element_id) {
+ document.getElementById(img_id).style.backgroundColor = document.forms[0].elements[form_element_id].value;
+}
+
+function setBrowserDisabled(id, state) {
+ var img = document.getElementById(id);
+ var lnk = document.getElementById(id + "_link");
+
+ if (lnk) {
+ if (state) {
+ lnk.setAttribute("realhref", lnk.getAttribute("href"));
+ lnk.removeAttribute("href");
+ tinyMCEPopup.dom.addClass(img, 'disabled');
+ } else {
+ if (lnk.getAttribute("realhref"))
+ lnk.setAttribute("href", lnk.getAttribute("realhref"));
+
+ tinyMCEPopup.dom.removeClass(img, 'disabled');
+ }
+ }
+}
+
+function getBrowserHTML(id, target_form_element, type, prefix) {
+ var option = prefix + "_" + type + "_browser_callback", cb, html;
+
+ cb = tinyMCEPopup.getParam(option, tinyMCEPopup.getParam("file_browser_callback"));
+
+ if (!cb)
+ return "";
+
+ html = "";
+ html += '<a id="' + id + '_link" href="javascript:openBrowser(\'' + id + '\',\'' + target_form_element + '\', \'' + type + '\',\'' + option + '\');" onmousedown="return false;" class="browse">';
+ html += '<span id="' + id + '" title="' + tinyMCEPopup.getLang('browse') + '">&nbsp;</span></a>';
+
+ return html;
+}
+
+function openBrowser(img_id, target_form_element, type, option) {
+ var img = document.getElementById(img_id);
+
+ if (img.className != "mceButtonDisabled")
+ tinyMCEPopup.openBrowser(target_form_element, type, option);
+}
+
+function selectByValue(form_obj, field_name, value, add_custom, ignore_case) {
+ if (!form_obj || !form_obj.elements[field_name])
+ return;
+
+ if (!value)
+ value = "";
+
+ var sel = form_obj.elements[field_name];
+
+ var found = false;
+ for (var i=0; i<sel.options.length; i++) {
+ var option = sel.options[i];
+
+ if (option.value == value || (ignore_case && option.value.toLowerCase() == value.toLowerCase())) {
+ option.selected = true;
+ found = true;
+ } else
+ option.selected = false;
+ }
+
+ if (!found && add_custom && value != '') {
+ var option = new Option(value, value);
+ option.selected = true;
+ sel.options[sel.options.length] = option;
+ sel.selectedIndex = sel.options.length - 1;
+ }
+
+ return found;
+}
+
+function getSelectValue(form_obj, field_name) {
+ var elm = form_obj.elements[field_name];
+
+ if (elm == null || elm.options == null || elm.selectedIndex === -1)
+ return "";
+
+ return elm.options[elm.selectedIndex].value;
+}
+
+function addSelectValue(form_obj, field_name, name, value) {
+ var s = form_obj.elements[field_name];
+ var o = new Option(name, value);
+ s.options[s.options.length] = o;
+}
+
+function addClassesToList(list_id, specific_option) {
+ // Setup class droplist
+ var styleSelectElm = document.getElementById(list_id);
+ var styles = tinyMCEPopup.getParam('theme_advanced_styles', false);
+ styles = tinyMCEPopup.getParam(specific_option, styles);
+
+ if (styles) {
+ var stylesAr = styles.split(';');
+
+ for (var i=0; i<stylesAr.length; i++) {
+ if (stylesAr != "") {
+ var key, value;
+
+ key = stylesAr[i].split('=')[0];
+ value = stylesAr[i].split('=')[1];
+
+ styleSelectElm.options[styleSelectElm.length] = new Option(key, value);
+ }
+ }
+ } else {
+ tinymce.each(tinyMCEPopup.editor.dom.getClasses(), function(o) {
+ styleSelectElm.options[styleSelectElm.length] = new Option(o.title || o['class'], o['class']);
+ });
+ }
+}
+
+function isVisible(element_id) {
+ var elm = document.getElementById(element_id);
+
+ return elm && elm.style.display != "none";
+}
+
+function convertRGBToHex(col) {
+ var re = new RegExp("rgb\\s*\\(\\s*([0-9]+).*,\\s*([0-9]+).*,\\s*([0-9]+).*\\)", "gi");
+
+ var rgb = col.replace(re, "$1,$2,$3").split(',');
+ if (rgb.length == 3) {
+ r = parseInt(rgb[0]).toString(16);
+ g = parseInt(rgb[1]).toString(16);
+ b = parseInt(rgb[2]).toString(16);
+
+ r = r.length == 1 ? '0' + r : r;
+ g = g.length == 1 ? '0' + g : g;
+ b = b.length == 1 ? '0' + b : b;
+
+ return "#" + r + g + b;
+ }
+
+ return col;
+}
+
+function convertHexToRGB(col) {
+ if (col.indexOf('#') != -1) {
+ col = col.replace(new RegExp('[^0-9A-F]', 'gi'), '');
+
+ r = parseInt(col.substring(0, 2), 16);
+ g = parseInt(col.substring(2, 4), 16);
+ b = parseInt(col.substring(4, 6), 16);
+
+ return "rgb(" + r + "," + g + "," + b + ")";
+ }
+
+ return col;
+}
+
+function trimSize(size) {
+ return size.replace(/([0-9\.]+)(px|%|in|cm|mm|em|ex|pt|pc)/i, '$1$2');
+}
+
+function getCSSSize(size) {
+ size = trimSize(size);
+
+ if (size == "")
+ return "";
+
+ // Add px
+ if (/^[0-9]+$/.test(size))
+ size += 'px';
+ // Sanity check, IE doesn't like broken values
+ else if (!(/^[0-9\.]+(px|%|in|cm|mm|em|ex|pt|pc)$/i.test(size)))
+ return "";
+
+ return size;
+}
+
+function getStyle(elm, attrib, style) {
+ var val = tinyMCEPopup.dom.getAttrib(elm, attrib);
+
+ if (val != '')
+ return '' + val;
+
+ if (typeof(style) == 'undefined')
+ style = attrib;
+
+ return tinyMCEPopup.dom.getStyle(elm, style);
+}
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/mctabs.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/mctabs.js
new file mode 100755
index 0000000..acb5657
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/mctabs.js
@@ -0,0 +1,162 @@
+/**
+ * mctabs.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+function MCTabs() {
+ this.settings = [];
+ this.onChange = tinyMCEPopup.editor.windowManager.createInstance('tinymce.util.Dispatcher');
+};
+
+MCTabs.prototype.init = function(settings) {
+ this.settings = settings;
+};
+
+MCTabs.prototype.getParam = function(name, default_value) {
+ var value = null;
+
+ value = (typeof(this.settings[name]) == "undefined") ? default_value : this.settings[name];
+
+ // Fix bool values
+ if (value == "true" || value == "false")
+ return (value == "true");
+
+ return value;
+};
+
+MCTabs.prototype.showTab =function(tab){
+ tab.className = 'current';
+ tab.setAttribute("aria-selected", true);
+ tab.setAttribute("aria-expanded", true);
+ tab.tabIndex = 0;
+};
+
+MCTabs.prototype.hideTab =function(tab){
+ var t=this;
+
+ tab.className = '';
+ tab.setAttribute("aria-selected", false);
+ tab.setAttribute("aria-expanded", false);
+ tab.tabIndex = -1;
+};
+
+MCTabs.prototype.showPanel = function(panel) {
+ panel.className = 'current';
+ panel.setAttribute("aria-hidden", false);
+};
+
+MCTabs.prototype.hidePanel = function(panel) {
+ panel.className = 'panel';
+ panel.setAttribute("aria-hidden", true);
+};
+
+MCTabs.prototype.getPanelForTab = function(tabElm) {
+ return tinyMCEPopup.dom.getAttrib(tabElm, "aria-controls");
+};
+
+MCTabs.prototype.displayTab = function(tab_id, panel_id, avoid_focus) {
+ var panelElm, panelContainerElm, tabElm, tabContainerElm, selectionClass, nodes, i, t = this;
+
+ tabElm = document.getElementById(tab_id);
+
+ if (panel_id === undefined) {
+ panel_id = t.getPanelForTab(tabElm);
+ }
+
+ panelElm= document.getElementById(panel_id);
+ panelContainerElm = panelElm ? panelElm.parentNode : null;
+ tabContainerElm = tabElm ? tabElm.parentNode : null;
+ selectionClass = t.getParam('selection_class', 'current');
+
+ if (tabElm && tabContainerElm) {
+ nodes = tabContainerElm.childNodes;
+
+ // Hide all other tabs
+ for (i = 0; i < nodes.length; i++) {
+ if (nodes[i].nodeName == "LI") {
+ t.hideTab(nodes[i]);
+ }
+ }
+
+ // Show selected tab
+ t.showTab(tabElm);
+ }
+
+ if (panelElm && panelContainerElm) {
+ nodes = panelContainerElm.childNodes;
+
+ // Hide all other panels
+ for (i = 0; i < nodes.length; i++) {
+ if (nodes[i].nodeName == "DIV")
+ t.hidePanel(nodes[i]);
+ }
+
+ if (!avoid_focus) {
+ tabElm.focus();
+ }
+
+ // Show selected panel
+ t.showPanel(panelElm);
+ }
+};
+
+MCTabs.prototype.getAnchor = function() {
+ var pos, url = document.location.href;
+
+ if ((pos = url.lastIndexOf('#')) != -1)
+ return url.substring(pos + 1);
+
+ return "";
+};
+
+
+//Global instance
+var mcTabs = new MCTabs();
+
+tinyMCEPopup.onInit.add(function() {
+ var tinymce = tinyMCEPopup.getWin().tinymce, dom = tinyMCEPopup.dom, each = tinymce.each;
+
+ each(dom.select('div.tabs'), function(tabContainerElm) {
+ var keyNav;
+
+ dom.setAttrib(tabContainerElm, "role", "tablist");
+
+ var items = tinyMCEPopup.dom.select('li', tabContainerElm);
+ var action = function(id) {
+ mcTabs.displayTab(id, mcTabs.getPanelForTab(id));
+ mcTabs.onChange.dispatch(id);
+ };
+
+ each(items, function(item) {
+ dom.setAttrib(item, 'role', 'tab');
+ dom.bind(item, 'click', function(evt) {
+ action(item.id);
+ });
+ });
+
+ dom.bind(dom.getRoot(), 'keydown', function(evt) {
+ if (evt.keyCode === 9 && evt.ctrlKey && !evt.altKey) { // Tab
+ keyNav.moveFocus(evt.shiftKey ? -1 : 1);
+ tinymce.dom.Event.cancel(evt);
+ }
+ });
+
+ each(dom.select('a', tabContainerElm), function(a) {
+ dom.setAttrib(a, 'tabindex', '-1');
+ });
+
+ keyNav = tinyMCEPopup.editor.windowManager.createInstance('tinymce.ui.KeyboardNavigation', {
+ root: tabContainerElm,
+ items: items,
+ onAction: action,
+ actOnFocus: true,
+ enableLeftRight: true,
+ enableUpDown: true
+ }, tinyMCEPopup.dom);
+ });
+}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/tiny_mce_popup.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/tiny_mce_popup.js
new file mode 100755
index 0000000..6ed0d5e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/tiny_mce_popup.js
@@ -0,0 +1,435 @@
+/**
+ * Popup.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+// Some global instances
+var tinymce = null, tinyMCEPopup, tinyMCE;
+
+/**
+ * TinyMCE popup/dialog helper class. This gives you easy access to the
+ * parent editor instance and a bunch of other things. It's higly recommended
+ * that you load this script into your dialogs.
+ *
+ * @static
+ * @class tinyMCEPopup
+ */
+tinyMCEPopup = {
+ /**
+ * Initializes the popup this will be called automatically.
+ *
+ * @method init
+ */
+ init : function() {
+ var t = this, w, ti, settings;
+
+ // Find window & API
+ w = t.getWin();
+ tinymce = w.tinymce;
+ tinyMCE = w.tinyMCE;
+ t.editor = tinymce.EditorManager.activeEditor;
+ t.params = t.editor.windowManager.params;
+ t.features = t.editor.windowManager.features;
+ settings = t.editor.settings;
+
+ // Setup popup CSS path(s)
+ if (settings.popup_css !== false) {
+ if (settings.popup_css) {
+ settings.popup_css = t.documentBaseURI.toAbsolute(settings.popup_css);
+ } else {
+ settings.popup_css = t.baseURI.toAbsolute("themes/" + settings.theme + "/skins/" + settings.skin + "/dialog.css");
+ }
+ }
+
+ if (settings.popup_css_add) {
+ settings.popup_css += ',' + t.documentBaseURI.toAbsolute(settings.popup_css_add);
+ }
+
+ // Setup local DOM
+ t.dom = t.editor.windowManager.createInstance('tinymce.dom.DOMUtils', document, {ownEvents: true, proxy: tinyMCEPopup._eventProxy});
+ t.dom.bind(window, 'ready', t._onDOMLoaded, t);
+
+ // Enables you to skip loading the default css
+ if (t.features.popup_css !== false)
+ t.dom.loadCSS(t.features.popup_css || t.editor.settings.popup_css);
+
+ // Setup on init listeners
+ t.listeners = [];
+
+ /**
+ * Fires when the popup is initialized.
+ *
+ * @event onInit
+ * @param {tinymce.Editor} editor Editor instance.
+ * @example
+ * // Alerts the selected contents when the dialog is loaded
+ * tinyMCEPopup.onInit.add(function(ed) {
+ * alert(ed.selection.getContent());
+ * });
+ *
+ * // Executes the init method on page load in some object using the SomeObject scope
+ * tinyMCEPopup.onInit.add(SomeObject.init, SomeObject);
+ */
+ t.onInit = {
+ add : function(f, s) {
+ t.listeners.push({func : f, scope : s});
+ }
+ };
+
+ t.isWindow = !t.getWindowArg('mce_inline');
+ t.id = t.getWindowArg('mce_window_id');
+ },
+
+ /**
+ * Returns the reference to the parent window that opened the dialog.
+ *
+ * @method getWin
+ * @return {Window} Reference to the parent window that opened the dialog.
+ */
+ getWin : function() {
+ // Added frameElement check to fix bug: #2817583
+ return (!window.frameElement && window.dialogArguments) || opener || parent || top;
+ },
+
+ /**
+ * Returns a window argument/parameter by name.
+ *
+ * @method getWindowArg
+ * @param {String} n Name of the window argument to retrive.
+ * @param {String} dv Optional default value to return.
+ * @return {String} Argument value or default value if it wasn't found.
+ */
+ getWindowArg : function(n, dv) {
+ var v = this.params[n];
+
+ return tinymce.is(v) ? v : dv;
+ },
+
+ /**
+ * Returns a editor parameter/config option value.
+ *
+ * @method getParam
+ * @param {String} n Name of the editor config option to retrive.
+ * @param {String} dv Optional default value to return.
+ * @return {String} Parameter value or default value if it wasn't found.
+ */
+ getParam : function(n, dv) {
+ return this.editor.getParam(n, dv);
+ },
+
+ /**
+ * Returns a language item by key.
+ *
+ * @method getLang
+ * @param {String} n Language item like mydialog.something.
+ * @param {String} dv Optional default value to return.
+ * @return {String} Language value for the item like "my string" or the default value if it wasn't found.
+ */
+ getLang : function(n, dv) {
+ return this.editor.getLang(n, dv);
+ },
+
+ /**
+ * Executed a command on editor that opened the dialog/popup.
+ *
+ * @method execCommand
+ * @param {String} cmd Command to execute.
+ * @param {Boolean} ui Optional boolean value if the UI for the command should be presented or not.
+ * @param {Object} val Optional value to pass with the comman like an URL.
+ * @param {Object} a Optional arguments object.
+ */
+ execCommand : function(cmd, ui, val, a) {
+ a = a || {};
+ a.skip_focus = 1;
+
+ this.restoreSelection();
+ return this.editor.execCommand(cmd, ui, val, a);
+ },
+
+ /**
+ * Resizes the dialog to the inner size of the window. This is needed since various browsers
+ * have different border sizes on windows.
+ *
+ * @method resizeToInnerSize
+ */
+ resizeToInnerSize : function() {
+ var t = this;
+
+ // Detach it to workaround a Chrome specific bug
+ // https://sourceforge.net/tracker/?func=detail&atid=635682&aid=2926339&group_id=103281
+ setTimeout(function() {
+ var vp = t.dom.getViewPort(window);
+
+ t.editor.windowManager.resizeBy(
+ t.getWindowArg('mce_width') - vp.w,
+ t.getWindowArg('mce_height') - vp.h,
+ t.id || window
+ );
+ }, 10);
+ },
+
+ /**
+ * Will executed the specified string when the page has been loaded. This function
+ * was added for compatibility with the 2.x branch.
+ *
+ * @method executeOnLoad
+ * @param {String} s String to evalutate on init.
+ */
+ executeOnLoad : function(s) {
+ this.onInit.add(function() {
+ eval(s);
+ });
+ },
+
+ /**
+ * Stores the current editor selection for later restoration. This can be useful since some browsers
+ * looses it's selection if a control element is selected/focused inside the dialogs.
+ *
+ * @method storeSelection
+ */
+ storeSelection : function() {
+ this.editor.windowManager.bookmark = tinyMCEPopup.editor.selection.getBookmark(1);
+ },
+
+ /**
+ * Restores any stored selection. This can be useful since some browsers
+ * looses it's selection if a control element is selected/focused inside the dialogs.
+ *
+ * @method restoreSelection
+ */
+ restoreSelection : function() {
+ var t = tinyMCEPopup;
+
+ if (!t.isWindow && tinymce.isIE)
+ t.editor.selection.moveToBookmark(t.editor.windowManager.bookmark);
+ },
+
+ /**
+ * Loads a specific dialog language pack. If you pass in plugin_url as a argument
+ * when you open the window it will load the <plugin url>/langs/<code>_dlg.js lang pack file.
+ *
+ * @method requireLangPack
+ */
+ requireLangPack : function() {
+ var t = this, u = t.getWindowArg('plugin_url') || t.getWindowArg('theme_url');
+
+ if (u && t.editor.settings.language && t.features.translate_i18n !== false && t.editor.settings.language_load !== false) {
+ u += '/langs/' + t.editor.settings.language + '_dlg.js';
+
+ if (!tinymce.ScriptLoader.isDone(u)) {
+ document.write('<script type="text/javascript" src="' + u + '"></script>');
+ tinymce.ScriptLoader.markDone(u);
+ }
+ }
+ },
+
+ /**
+ * Executes a color picker on the specified element id. When the user
+ * then selects a color it will be set as the value of the specified element.
+ *
+ * @method pickColor
+ * @param {DOMEvent} e DOM event object.
+ * @param {string} element_id Element id to be filled with the color value from the picker.
+ */
+ pickColor : function(e, element_id) {
+ this.execCommand('mceColorPicker', true, {
+ color : document.getElementById(element_id).value,
+ func : function(c) {
+ document.getElementById(element_id).value = c;
+
+ try {
+ document.getElementById(element_id).onchange();
+ } catch (ex) {
+ // Try fire event, ignore errors
+ }
+ }
+ });
+ },
+
+ /**
+ * Opens a filebrowser/imagebrowser this will set the output value from
+ * the browser as a value on the specified element.
+ *
+ * @method openBrowser
+ * @param {string} element_id Id of the element to set value in.
+ * @param {string} type Type of browser to open image/file/flash.
+ * @param {string} option Option name to get the file_broswer_callback function name from.
+ */
+ openBrowser : function(element_id, type, option) {
+ tinyMCEPopup.restoreSelection();
+ this.editor.execCallback('file_browser_callback', element_id, document.getElementById(element_id).value, type, window);
+ },
+
+ /**
+ * Creates a confirm dialog. Please don't use the blocking behavior of this
+ * native version use the callback method instead then it can be extended.
+ *
+ * @method confirm
+ * @param {String} t Title for the new confirm dialog.
+ * @param {function} cb Callback function to be executed after the user has selected ok or cancel.
+ * @param {Object} s Optional scope to execute the callback in.
+ */
+ confirm : function(t, cb, s) {
+ this.editor.windowManager.confirm(t, cb, s, window);
+ },
+
+ /**
+ * Creates a alert dialog. Please don't use the blocking behavior of this
+ * native version use the callback method instead then it can be extended.
+ *
+ * @method alert
+ * @param {String} t Title for the new alert dialog.
+ * @param {function} cb Callback function to be executed after the user has selected ok.
+ * @param {Object} s Optional scope to execute the callback in.
+ */
+ alert : function(tx, cb, s) {
+ this.editor.windowManager.alert(tx, cb, s, window);
+ },
+
+ /**
+ * Closes the current window.
+ *
+ * @method close
+ */
+ close : function() {
+ var t = this;
+
+ // To avoid domain relaxing issue in Opera
+ function close() {
+ t.editor.windowManager.close(window);
+ tinymce = tinyMCE = t.editor = t.params = t.dom = t.dom.doc = null; // Cleanup
+ };
+
+ if (tinymce.isOpera)
+ t.getWin().setTimeout(close, 0);
+ else
+ close();
+ },
+
+ // Internal functions
+
+ _restoreSelection : function() {
+ var e = window.event.srcElement;
+
+ if (e.nodeName == 'INPUT' && (e.type == 'submit' || e.type == 'button'))
+ tinyMCEPopup.restoreSelection();
+ },
+
+/* _restoreSelection : function() {
+ var e = window.event.srcElement;
+
+ // If user focus a non text input or textarea
+ if ((e.nodeName != 'INPUT' && e.nodeName != 'TEXTAREA') || e.type != 'text')
+ tinyMCEPopup.restoreSelection();
+ },*/
+
+ _onDOMLoaded : function() {
+ var t = tinyMCEPopup, ti = document.title, bm, h, nv;
+
+ // Translate page
+ if (t.features.translate_i18n !== false) {
+ h = document.body.innerHTML;
+
+ // Replace a=x with a="x" in IE
+ if (tinymce.isIE)
+ h = h.replace(/ (value|title|alt)=([^"][^\s>]+)/gi, ' $1="$2"')
+
+ document.dir = t.editor.getParam('directionality','');
+
+ if ((nv = t.editor.translate(h)) && nv != h)
+ document.body.innerHTML = nv;
+
+ if ((nv = t.editor.translate(ti)) && nv != ti)
+ document.title = ti = nv;
+ }
+
+ if (!t.editor.getParam('browser_preferred_colors', false) || !t.isWindow)
+ t.dom.addClass(document.body, 'forceColors');
+
+ document.body.style.display = '';
+
+ // Restore selection in IE when focus is placed on a non textarea or input element of the type text
+ if (tinymce.isIE) {
+ document.attachEvent('onmouseup', tinyMCEPopup._restoreSelection);
+
+ // Add base target element for it since it would fail with modal dialogs
+ t.dom.add(t.dom.select('head')[0], 'base', {target : '_self'});
+ }
+
+ t.restoreSelection();
+ t.resizeToInnerSize();
+
+ // Set inline title
+ if (!t.isWindow)
+ t.editor.windowManager.setTitle(window, ti);
+ else
+ window.focus();
+
+ if (!tinymce.isIE && !t.isWindow) {
+ t.dom.bind(document, 'focus', function() {
+ t.editor.windowManager.focus(t.id);
+ });
+ }
+
+ // Patch for accessibility
+ tinymce.each(t.dom.select('select'), function(e) {
+ e.onkeydown = tinyMCEPopup._accessHandler;
+ });
+
+ // Call onInit
+ // Init must be called before focus so the selection won't get lost by the focus call
+ tinymce.each(t.listeners, function(o) {
+ o.func.call(o.scope, t.editor);
+ });
+
+ // Move focus to window
+ if (t.getWindowArg('mce_auto_focus', true)) {
+ window.focus();
+
+ // Focus element with mceFocus class
+ tinymce.each(document.forms, function(f) {
+ tinymce.each(f.elements, function(e) {
+ if (t.dom.hasClass(e, 'mceFocus') && !e.disabled) {
+ e.focus();
+ return false; // Break loop
+ }
+ });
+ });
+ }
+
+ document.onkeyup = tinyMCEPopup._closeWinKeyHandler;
+ },
+
+ _accessHandler : function(e) {
+ e = e || window.event;
+
+ if (e.keyCode == 13 || e.keyCode == 32) {
+ var elm = e.target || e.srcElement;
+
+ if (elm.onchange)
+ elm.onchange();
+
+ return tinymce.dom.Event.cancel(e);
+ }
+ },
+
+ _closeWinKeyHandler : function(e) {
+ e = e || window.event;
+
+ if (e.keyCode == 27)
+ tinyMCEPopup.close();
+ },
+
+ _eventProxy: function(id) {
+ return function(evt) {
+ tinyMCEPopup.dom.events.callNativeHandler(id, evt);
+ };
+ }
+};
+
+tinyMCEPopup.init(); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/validate.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/validate.js
new file mode 100755
index 0000000..d13aaa1
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/compat3x/validate.js
@@ -0,0 +1,252 @@
+/**
+ * validate.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ // String validation:
+
+ if (!Validator.isEmail('myemail'))
+ alert('Invalid email.');
+
+ // Form validation:
+
+ var f = document.forms['myform'];
+
+ if (!Validator.isEmail(f.myemail))
+ alert('Invalid email.');
+*/
+
+var Validator = {
+ isEmail : function(s) {
+ return this.test(s, '^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+@[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$');
+ },
+
+ isAbsUrl : function(s) {
+ return this.test(s, '^(news|telnet|nttp|file|http|ftp|https)://[-A-Za-z0-9\\.]+\\/?.*$');
+ },
+
+ isSize : function(s) {
+ return this.test(s, '^[0-9.]+(%|in|cm|mm|em|ex|pt|pc|px)?$');
+ },
+
+ isId : function(s) {
+ return this.test(s, '^[A-Za-z_]([A-Za-z0-9_])*$');
+ },
+
+ isEmpty : function(s) {
+ var nl, i;
+
+ if (s.nodeName == 'SELECT' && s.selectedIndex < 1)
+ return true;
+
+ if (s.type == 'checkbox' && !s.checked)
+ return true;
+
+ if (s.type == 'radio') {
+ for (i=0, nl = s.form.elements; i<nl.length; i++) {
+ if (nl[i].type == "radio" && nl[i].name == s.name && nl[i].checked)
+ return false;
+ }
+
+ return true;
+ }
+
+ return new RegExp('^\\s*$').test(s.nodeType == 1 ? s.value : s);
+ },
+
+ isNumber : function(s, d) {
+ return !isNaN(s.nodeType == 1 ? s.value : s) && (!d || !this.test(s, '^-?[0-9]*\\.[0-9]*$'));
+ },
+
+ test : function(s, p) {
+ s = s.nodeType == 1 ? s.value : s;
+
+ return s == '' || new RegExp(p).test(s);
+ }
+};
+
+var AutoValidator = {
+ settings : {
+ id_cls : 'id',
+ int_cls : 'int',
+ url_cls : 'url',
+ number_cls : 'number',
+ email_cls : 'email',
+ size_cls : 'size',
+ required_cls : 'required',
+ invalid_cls : 'invalid',
+ min_cls : 'min',
+ max_cls : 'max'
+ },
+
+ init : function(s) {
+ var n;
+
+ for (n in s)
+ this.settings[n] = s[n];
+ },
+
+ validate : function(f) {
+ var i, nl, s = this.settings, c = 0;
+
+ nl = this.tags(f, 'label');
+ for (i=0; i<nl.length; i++) {
+ this.removeClass(nl[i], s.invalid_cls);
+ nl[i].setAttribute('aria-invalid', false);
+ }
+
+ c += this.validateElms(f, 'input');
+ c += this.validateElms(f, 'select');
+ c += this.validateElms(f, 'textarea');
+
+ return c == 3;
+ },
+
+ invalidate : function(n) {
+ this.mark(n.form, n);
+ },
+
+ getErrorMessages : function(f) {
+ var nl, i, s = this.settings, field, msg, values, messages = [], ed = tinyMCEPopup.editor;
+ nl = this.tags(f, "label");
+ for (i=0; i<nl.length; i++) {
+ if (this.hasClass(nl[i], s.invalid_cls)) {
+ field = document.getElementById(nl[i].getAttribute("for"));
+ values = { field: nl[i].textContent };
+ if (this.hasClass(field, s.min_cls, true)) {
+ message = ed.getLang('invalid_data_min');
+ values.min = this.getNum(field, s.min_cls);
+ } else if (this.hasClass(field, s.number_cls)) {
+ message = ed.getLang('invalid_data_number');
+ } else if (this.hasClass(field, s.size_cls)) {
+ message = ed.getLang('invalid_data_size');
+ } else {
+ message = ed.getLang('invalid_data');
+ }
+
+ message = message.replace(/{\#([^}]+)\}/g, function(a, b) {
+ return values[b] || '{#' + b + '}';
+ });
+ messages.push(message);
+ }
+ }
+ return messages;
+ },
+
+ reset : function(e) {
+ var t = ['label', 'input', 'select', 'textarea'];
+ var i, j, nl, s = this.settings;
+
+ if (e == null)
+ return;
+
+ for (i=0; i<t.length; i++) {
+ nl = this.tags(e.form ? e.form : e, t[i]);
+ for (j=0; j<nl.length; j++) {
+ this.removeClass(nl[j], s.invalid_cls);
+ nl[j].setAttribute('aria-invalid', false);
+ }
+ }
+ },
+
+ validateElms : function(f, e) {
+ var nl, i, n, s = this.settings, st = true, va = Validator, v;
+
+ nl = this.tags(f, e);
+ for (i=0; i<nl.length; i++) {
+ n = nl[i];
+
+ this.removeClass(n, s.invalid_cls);
+
+ if (this.hasClass(n, s.required_cls) && va.isEmpty(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.number_cls) && !va.isNumber(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.int_cls) && !va.isNumber(n, true))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.url_cls) && !va.isAbsUrl(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.email_cls) && !va.isEmail(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.size_cls) && !va.isSize(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.id_cls) && !va.isId(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.min_cls, true)) {
+ v = this.getNum(n, s.min_cls);
+
+ if (isNaN(v) || parseInt(n.value) < parseInt(v))
+ st = this.mark(f, n);
+ }
+
+ if (this.hasClass(n, s.max_cls, true)) {
+ v = this.getNum(n, s.max_cls);
+
+ if (isNaN(v) || parseInt(n.value) > parseInt(v))
+ st = this.mark(f, n);
+ }
+ }
+
+ return st;
+ },
+
+ hasClass : function(n, c, d) {
+ return new RegExp('\\b' + c + (d ? '[0-9]+' : '') + '\\b', 'g').test(n.className);
+ },
+
+ getNum : function(n, c) {
+ c = n.className.match(new RegExp('\\b' + c + '([0-9]+)\\b', 'g'))[0];
+ c = c.replace(/[^0-9]/g, '');
+
+ return c;
+ },
+
+ addClass : function(n, c, b) {
+ var o = this.removeClass(n, c);
+ n.className = b ? c + (o != '' ? (' ' + o) : '') : (o != '' ? (o + ' ') : '') + c;
+ },
+
+ removeClass : function(n, c) {
+ c = n.className.replace(new RegExp("(^|\\s+)" + c + "(\\s+|$)"), ' ');
+ return n.className = c != ' ' ? c : '';
+ },
+
+ tags : function(f, s) {
+ return f.getElementsByTagName(s);
+ },
+
+ mark : function(f, n) {
+ var s = this.settings;
+
+ this.addClass(n, s.invalid_cls);
+ n.setAttribute('aria-invalid', 'true');
+ this.markLabels(f, n, s.invalid_cls);
+
+ return false;
+ },
+
+ markLabels : function(f, n, ic) {
+ var nl, i;
+
+ nl = this.tags(f, "label");
+ for (i=0; i<nl.length; i++) {
+ if (nl[i].getAttribute("for") == n.id || nl[i].htmlFor == n.id)
+ this.addClass(nl[i], ic);
+ }
+
+ return null;
+ }
+};
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/contextmenu/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/contextmenu/plugin.min.js
new file mode 100755
index 0000000..4aabc70
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/contextmenu/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("contextmenu",function(e){var t;e.on("contextmenu",function(n){var i;if(n.preventDefault(),i=e.settings.contextmenu||"link image inserttable | cell row column deletetable",t)t.show();else{var o=[];tinymce.each(i.split(/[ ,]/),function(t){var n=e.menuItems[t];"|"==t&&(n={text:t}),n&&(n.shortcut="",o.push(n))});for(var a=0;a<o.length;a++)"|"==o[a].text&&(0===a||a==o.length-1)&&o.splice(a,1);t=new tinymce.ui.Menu({items:o,context:"contextmenu"}),t.renderTo(document.body)}var r={x:n.pageX,y:n.pageY};e.inline||(r=tinymce.DOM.getPos(e.getContentAreaContainer()),r.x+=n.clientX,r.y+=n.clientY),t.moveTo(r.x,r.y),e.on("remove",function(){t.remove(),t=null})})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/directionality/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/directionality/plugin.min.js
new file mode 100755
index 0000000..60c7f9d
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/directionality/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("directionality",function(e){function t(t){var n,i=e.dom,a=e.selection.getSelectedBlocks();a.length&&(n=i.getAttrib(a[0],"dir"),tinymce.each(a,function(e){i.getParent(e.parentNode,"*[dir='"+t+"']",i.getRoot())||(n!=t?i.setAttrib(e,"dir",t):i.setAttrib(e,"dir",null))}),e.nodeChanged())}function n(e){var t=[];return tinymce.each("h1 h2 h3 h4 h5 h6 div p".split(" "),function(n){t.push(n+"[dir="+e+"]")}),t.join(",")}e.addCommand("mceDirectionLTR",function(){t("ltr")}),e.addCommand("mceDirectionRTL",function(){t("rtl")}),e.addButton("ltr",{title:"Left to right",cmd:"mceDirectionLTR",stateSelector:n("ltr")}),e.addButton("rtl",{title:"Right to left",cmd:"mceDirectionRTL",stateSelector:n("rtl")})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-cool.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-cool.gif
new file mode 100755
index 0000000..ba90cc3
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-cool.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-cry.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-cry.gif
new file mode 100755
index 0000000..74d897a
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-cry.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-embarassed.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-embarassed.gif
new file mode 100755
index 0000000..963a96b
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-embarassed.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-foot-in-mouth.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-foot-in-mouth.gif
new file mode 100755
index 0000000..c7cf101
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-foot-in-mouth.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-frown.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-frown.gif
new file mode 100755
index 0000000..716f55e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-frown.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-innocent.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-innocent.gif
new file mode 100755
index 0000000..334d49e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-innocent.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-kiss.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-kiss.gif
new file mode 100755
index 0000000..4efd549
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-kiss.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-laughing.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-laughing.gif
new file mode 100755
index 0000000..82c5b18
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-laughing.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-money-mouth.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-money-mouth.gif
new file mode 100755
index 0000000..ca2451e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-money-mouth.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-sealed.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-sealed.gif
new file mode 100755
index 0000000..fe66220
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-sealed.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-smile.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-smile.gif
new file mode 100755
index 0000000..fd27edf
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-smile.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-surprised.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-surprised.gif
new file mode 100755
index 0000000..0cc9bb7
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-surprised.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-tongue-out.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-tongue-out.gif
new file mode 100755
index 0000000..2075dc1
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-tongue-out.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-undecided.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-undecided.gif
new file mode 100755
index 0000000..bef7e25
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-undecided.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-wink.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-wink.gif
new file mode 100755
index 0000000..0631c76
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-wink.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-yell.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-yell.gif
new file mode 100755
index 0000000..648e6e8
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/img/smiley-yell.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/plugin.min.js
new file mode 100755
index 0000000..f70e794
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/emoticons/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("emoticons",function(e,t){function n(){var e;return e='<table role="presentation" class="mce-grid">',tinymce.each(i,function(n){e+="<tr>",tinymce.each(n,function(n){var i=t+"/img/smiley-"+n+".gif";e+='<td><a href="#" data-mce-url="'+i+'" tabindex="-1"><img src="'+i+'" style="width: 18px; height: 18px"></a></td>'}),e+="</tr>"}),e+="</table>"}var i=[["cool","cry","embarassed","foot-in-mouth"],["frown","innocent","kiss","laughing"],["money-mouth","sealed","smile","surprised"],["tongue-out","undecided","wink","yell"]];e.addButton("emoticons",{type:"panelbutton",popoverAlign:"bc-tl",panel:{autohide:!0,html:n,onclick:function(t){var n=e.dom.getParent(t.target,"a");n&&(e.insertContent('<img src="'+n.getAttribute("data-mce-url")+'" />'),this.hide())}},tooltip:"Emoticons"})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/example/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/example/plugin.min.js
new file mode 100755
index 0000000..24a64c8
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/example/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("example",function(e){e.addButton("example",{text:"My button",icon:!1,onclick:function(){e.windowManager.open({title:"Example plugin",body:[{type:"textbox",name:"title",label:"Title"}],onsubmit:function(t){e.insertContent("Title: "+t.data.title)}})}}),e.addMenuItem("example",{text:"Example plugin",context:"tools",onclick:function(){e.windowManager.open({title:"TinyMCE site",url:"http://www.tinymce.com",width:800,height:600,buttons:[{text:"Close",onclick:"close"}]})}})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/example_dependency/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/example_dependency/plugin.min.js
new file mode 100755
index 0000000..e61bf47
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/example_dependency/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("example_dependency",function(){},["example"]); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/fullpage/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/fullpage/plugin.min.js
new file mode 100755
index 0000000..0f15de4
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/fullpage/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("fullpage",function(e){function t(){var t=n();e.windowManager.open({title:"Document properties",data:t,defaults:{type:"textbox",size:40},body:[{name:"title",label:"Title"},{name:"keywords",label:"Keywords"},{name:"description",label:"Description"},{name:"robots",label:"Robots"},{name:"author",label:"Author"},{name:"docencoding",label:"Encoding"}],onSubmit:function(e){i(tinymce.extend(t,e.data))}})}function n(){function t(e,t){var n=e.attr(t);return n||""}var n,i,r=a(),o={};return o.fontface=e.getParam("fullpage_default_fontface",""),o.fontsize=e.getParam("fullpage_default_fontsize",""),n=r.firstChild,7==n.type&&(o.xml_pi=!0,i=/encoding="([^"]+)"/.exec(n.value),i&&(o.docencoding=i[1])),n=r.getAll("#doctype")[0],n&&(o.doctype="<!DOCTYPE"+n.value+">"),n=r.getAll("title")[0],n&&n.firstChild&&(o.title=n.firstChild.value),u(r.getAll("meta"),function(e){var t,n=e.attr("name"),i=e.attr("http-equiv");n?o[n.toLowerCase()]=e.attr("content"):"Content-Type"==i&&(t=/charset\s*=\s*(.*)\s*/gi.exec(e.attr("content")),t&&(o.docencoding=t[1]))}),n=r.getAll("html")[0],n&&(o.langcode=t(n,"lang")||t(n,"xml:lang")),n=r.getAll("link")[0],n&&"stylesheet"==n.attr("rel")&&(o.stylesheet=n.attr("href")),n=r.getAll("body")[0],n&&(o.langdir=t(n,"dir"),o.style=t(n,"style"),o.visited_color=t(n,"vlink"),o.link_color=t(n,"link"),o.active_color=t(n,"alink")),o}function i(t){function n(e,t,n){e.attr(t,n?n:void 0)}function i(e){o.firstChild?o.insert(e,o.firstChild):o.append(e)}var r,o,l,c,m,f=e.dom;r=a(),o=r.getAll("head")[0],o||(c=r.getAll("html")[0],o=new d("head",1),c.firstChild?c.insert(o,c.firstChild,!0):c.append(o)),c=r.firstChild,t.xml_pi?(m='version="1.0"',t.docencoding&&(m+=' encoding="'+t.docencoding+'"'),7!=c.type&&(c=new d("xml",7),r.insert(c,r.firstChild,!0)),c.value=m):c&&7==c.type&&c.remove(),c=r.getAll("#doctype")[0],t.doctype?(c||(c=new d("#doctype",10),t.xml_pi?r.insert(c,r.firstChild):i(c)),c.value=t.doctype.substring(9,t.doctype.length-1)):c&&c.remove(),t.docencoding&&(c=null,u(r.getAll("meta"),function(e){"Content-Type"==e.attr("http-equiv")&&(c=e)}),c||(c=new d("meta",1),c.attr("http-equiv","Content-Type"),c.shortEnded=!0,i(c)),c.attr("content","text/html; charset="+t.docencoding)),c=r.getAll("title")[0],t.title?c||(c=new d("title",1),c.append(new d("#text",3)).value=t.title,i(c)):c&&c.remove(),u("keywords,description,author,copyright,robots".split(","),function(e){var n,a,o=r.getAll("meta"),l=t[e];for(n=0;n<o.length;n++)if(a=o[n],a.attr("name")==e)return l?a.attr("content",l):a.remove(),void 0;l&&(c=new d("meta",1),c.attr("name",e),c.attr("content",l),c.shortEnded=!0,i(c))}),c=r.getAll("link")[0],c&&"stylesheet"==c.attr("rel")?t.stylesheet?c.attr("href",t.stylesheet):c.remove():t.stylesheet&&(c=new d("link",1),c.attr({rel:"stylesheet",text:"text/css",href:t.stylesheet}),c.shortEnded=!0,i(c)),c=r.getAll("body")[0],c&&(n(c,"dir",t.langdir),n(c,"style",t.style),n(c,"vlink",t.visited_color),n(c,"link",t.link_color),n(c,"alink",t.active_color),f.setAttribs(e.getBody(),{style:t.style,dir:t.dir,vLink:t.visited_color,link:t.link_color,aLink:t.active_color})),c=r.getAll("html")[0],c&&(n(c,"lang",t.langcode),n(c,"xml:lang",t.langcode)),o.firstChild||o.remove(),l=new tinymce.html.Serializer({validate:!1,indent:!0,apply_source_formatting:!0,indent_before:"head,html,body,meta,title,script,link,style",indent_after:"head,html,body,meta,title,script,link,style"}).serialize(r),s=l.substring(0,l.indexOf("</body>"))}function a(){return new tinymce.html.DomParser({validate:!1,root_name:"#document"}).parse(s)}function r(t){function n(e){return e.replace(/<\/?[A-Z]+/g,function(e){return e.toLowerCase()})}var i,r,l,d,m=t.content,f="",g=e.dom;t.selection||"raw"==t.format&&s||t.source_view&&e.getParam("fullpage_hide_in_source_view")||(m=m.replace(/<(\/?)BODY/gi,"<$1body"),i=m.indexOf("<body"),-1!=i?(i=m.indexOf(">",i),s=n(m.substring(0,i+1)),r=m.indexOf("</body",i),-1==r&&(r=m.length),t.content=m.substring(i+1,r),c=n(m.substring(r))):(s=o(),c="\n</body>\n</html>"),l=a(),u(l.getAll("style"),function(e){e.firstChild&&(f+=e.firstChild.value)}),d=l.getAll("body")[0],d&&g.setAttribs(e.getBody(),{style:d.attr("style")||"",dir:d.attr("dir")||"",vLink:d.attr("vlink")||"",link:d.attr("link")||"",aLink:d.attr("alink")||""}),g.remove("fullpage_styles"),f&&(g.add(e.getDoc().getElementsByTagName("head")[0],"style",{id:"fullpage_styles"},f),d=g.get("fullpage_styles"),d.styleSheet&&(d.styleSheet.cssText=f)))}function o(){var t,n="",i="";return e.getParam("fullpage_default_xml_pi")&&(n+='<?xml version="1.0" encoding="'+e.getParam("fullpage_default_encoding","ISO-8859-1")+'" ?>\n'),n+=e.getParam("fullpage_default_doctype","<!DOCTYPE html>"),n+="\n<html>\n<head>\n",(t=e.getParam("fullpage_default_title"))&&(n+="<title>"+t+"</title>\n"),(t=e.getParam("fullpage_default_encoding"))&&(n+='<meta http-equiv="Content-Type" content="text/html; charset='+t+'" />\n'),(t=e.getParam("fullpage_default_font_family"))&&(i+="font-family: "+t+";"),(t=e.getParam("fullpage_default_font_size"))&&(i+="font-size: "+t+";"),(t=e.getParam("fullpage_default_text_color"))&&(i+="color: "+t+";"),n+="</head>\n<body"+(i?' style="'+i+'"':"")+">\n"}function l(t){t.selection||t.source_view&&e.getParam("fullpage_hide_in_source_view")||(t.content=tinymce.trim(s)+"\n"+tinymce.trim(t.content)+"\n"+tinymce.trim(c))}var s,c,u=tinymce.each,d=tinymce.html.Node;e.addCommand("mceFullPageProperties",t),e.addButton("fullpage",{title:"Document properties",cmd:"mceFullPageProperties"}),e.addMenuItem("fullpage",{text:"Document properties",cmd:"mceFullPageProperties",context:"file"}),e.on("BeforeSetContent",r),e.on("GetContent",l)}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/fullscreen/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/fullscreen/plugin.min.js
new file mode 100755
index 0000000..92a3b70
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/fullscreen/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("fullscreen",function(e){function t(){var e,t,n=window,i=document,a=i.body;return a.offsetWidth&&(e=a.offsetWidth,t=a.offsetHeight),n.innerWidth&&n.innerHeight&&(e=n.innerWidth,t=n.innerHeight),{w:e,h:t}}function n(){function n(){l.setStyle(c,"height",t().h-(s.clientHeight-c.clientHeight))}var s,c,u,d=document.body,m=document.documentElement;o=!o,s=e.getContainer().firstChild,c=e.getContentAreaContainer().firstChild,u=c.style,o?(i=u.width,a=u.height,u.width=u.height="100%",l.addClass(d,"mce-fullscreen"),l.addClass(m,"mce-fullscreen"),l.addClass(s,"mce-fullscreen"),l.bind(window,"resize",n),n(),r=n):(u.width=i,u.height=a,l.removeClass(d,"mce-fullscreen"),l.removeClass(m,"mce-fullscreen"),l.removeClass(s,"mce-fullscreen"),l.unbind(window,"resize",r)),e.fire("FullscreenStateChanged",{state:o})}var i,a,r,o=!1,l=tinymce.DOM;if(!e.settings.inline)return e.on("init",function(){e.addShortcut("Ctrl+Alt+F","",n)}),e.on("remove",function(){r&&l.unbind(window,"resize",r)}),e.addCommand("mceFullScreen",n),e.addMenuItem("fullscreen",{text:"Fullscreen",shortcut:"Ctrl+Alt+F",selectable:!0,onClick:n,onPostRender:function(){var t=this;e.on("FullscreenStateChanged",function(e){t.active(e.state)})},context:"view"}),e.addButton("fullscreen",{tooltip:"Fullscreen",shortcut:"Ctrl+Alt+F",onClick:n,onPostRender:function(){var t=this;e.on("FullscreenStateChanged",function(e){t.active(e.state)})}}),{isFullscreen:function(){return o}}}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/hr/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/hr/plugin.min.js
new file mode 100755
index 0000000..ca36c92
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/hr/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("hr",function(e){e.addCommand("InsertHorizontalRule",function(){e.execCommand("mceInsertContent",!1,"<hr />")}),e.addButton("hr",{icon:"hr",tooltip:"Horizontal line",cmd:"InsertHorizontalRule"}),e.addMenuItem("hr",{icon:"hr",text:"Horizontal line",cmd:"InsertHorizontalRule",context:"insert"})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/image/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/image/plugin.min.js
new file mode 100755
index 0000000..417dc1b
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/image/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("image",function(e){function t(e,t){function n(e,n){i.parentNode.removeChild(i),t({width:e,height:n})}var i=document.createElement("img");i.onload=function(){n(i.clientWidth,i.clientHeight)},i.onerror=function(){n()},i.src=e;var a=i.style;a.visibility="hidden",a.position="fixed",a.bottom=a.left=0,a.width=a.height="auto",document.body.appendChild(i)}function n(t){return function(){var n=e.settings.image_list;"string"==typeof n?tinymce.util.XHR.send({url:n,success:function(e){t(tinymce.util.JSON.parse(e))}}):t(n)}}function i(n){function i(){var e=[{text:"None",value:""}];return tinymce.each(n,function(t){e.push({text:t.text||t.title,value:t.value||t.url,menu:t.menu})}),e}function a(e){var t,n,i,a;t=c.find("#width")[0],n=c.find("#height")[0],i=t.value(),a=n.value(),c.find("#constrain")[0].checked()&&d&&m&&i&&a&&(e.control==t?(a=Math.round(i/d*a),n.value(a)):(i=Math.round(a/m*i),t.value(i))),d=i,m=a}function o(){function t(t){function i(){t.onload=t.onerror=null,e.selection.select(t),e.nodeChanged()}t.onload=function(){n.width||n.height||h.setAttribs(t,{width:t.clientWidth,height:t.clientHeight}),i()},t.onerror=i}var n=c.toJSON();""===n.width&&(n.width=null),""===n.height&&(n.height=null),""===n.style&&(n.style=null),n={src:n.src,alt:n.alt,width:n.width,height:n.height,style:n.style},e.undoManager.transact(function(){return n.src?(g?h.setAttribs(g,n):(n.id="__mcenew",e.selection.setContent(h.createHTML("img",n)),g=h.get("__mcenew"),h.setAttrib(g,"id",null)),t(g),void 0):(g&&(h.remove(g),e.nodeChanged()),void 0)})}function r(e){return e&&(e=e.replace(/px$/,"")),e}function s(){t(this.value(),function(e){e.width&&e.height&&(d=e.width,m=e.height,c.find("#width").value(d),c.find("#height").value(m))})}function l(){function e(e){return e.length>0&&/^[0-9]+$/.test(e)&&(e+="px"),e}var t=c.toJSON(),n=h.parseStyle(t.style);h.setAttrib(g,"style",""),delete n.margin,n["margin-top"]=n["margin-bottom"]=e(t.vspace),n["margin-left"]=n["margin-right"]=e(t.hspace),n["border-width"]=e(t.border),c.find("#style").value(h.serializeStyle(h.parseStyle(h.serializeStyle(n))))}var c,u,d,m,f,h=e.dom,g=e.selection.getNode();d=h.getAttrib(g,"width"),m=h.getAttrib(g,"height"),"IMG"!=g.nodeName||g.getAttribute("data-mce-object")?g=null:u={src:h.getAttrib(g,"src"),alt:h.getAttrib(g,"alt"),width:d,height:m},n&&(f={name:"target",type:"listbox",label:"Image list",values:i(),onselect:function(e){var t=c.find("#alt");(!t.value()||e.lastControl&&t.value()==e.lastControl.text())&&t.value(e.control.text()),c.find("#src").value(e.control.value())}});var p=[{name:"src",type:"filepicker",filetype:"image",label:"Source",autofocus:!0,onchange:s},f,{name:"alt",type:"textbox",label:"Image description"},{type:"container",label:"Dimensions",layout:"flex",direction:"row",align:"center",spacing:5,items:[{name:"width",type:"textbox",maxLength:3,size:3,onchange:a},{type:"label",text:"x"},{name:"height",type:"textbox",maxLength:3,size:3,onchange:a},{name:"constrain",type:"checkbox",checked:!0,text:"Constrain proportions"}]}];e.settings.image_advtab?(g&&(u.hspace=r(g.style.marginLeft||g.style.marginRight),u.vspace=r(g.style.marginTop||g.style.marginBottom),u.border=r(g.style.borderWidth),u.style=e.dom.serializeStyle(e.dom.parseStyle(e.dom.getAttrib(g,"style")))),c=e.windowManager.open({title:"Insert/edit image",data:u,bodyType:"tabpanel",body:[{title:"General",type:"form",items:p},{title:"Advanced",type:"form",pack:"start",items:[{label:"Style",name:"style",type:"textbox"},{type:"form",layout:"grid",packV:"start",columns:2,padding:0,alignH:["left","right"],defaults:{type:"textbox",maxWidth:50,onchange:l},items:[{label:"Vertical space",name:"vspace"},{label:"Horizontal space",name:"hspace"},{label:"Border",name:"border"}]}]}],onSubmit:o})):c=e.windowManager.open({title:"Edit image",data:u,body:p,onSubmit:o})}e.addButton("image",{icon:"image",tooltip:"Insert/edit image",onclick:n(i),stateSelector:"img:not([data-mce-object])"}),e.addMenuItem("image",{icon:"image",text:"Insert image",onclick:n(i),context:"insert",prependToContext:!0})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/importcss/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/importcss/plugin.min.js
new file mode 100755
index 0000000..0a2b235
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/importcss/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("importcss",function(e){function t(t){function n(e,t){(t||o[e.href])&&(i(e.imports,function(e){n(e,!0)}),i(e.cssRules||e.rules,function(e){e.styleSheet?n(e.styleSheet,!0):e.selectorText&&i(e.selectorText.split(","),function(e){a.push(tinymce.trim(e))})}))}var a=[],o={};i(e.contentCSS,function(e){o[e]=!0});try{i(t.styleSheets,n)}catch(r){}return a}function n(t){var n,i=/^(?:([a-z0-9\-_]+))?(\.[a-z0-9_\-\.]+)$/i.exec(t);if(i){var a=i[1],o=i[2].substr(1).split(".").join(" ");return i[1]?(n={title:t},e.schema.getTextBlockElements()[a]?n.block=a:e.schema.getBlockElements()[a]?n.selector=a:n.inline=a):i[2]&&(n={inline:"span",title:t.substr(1),classes:o}),e.settings.importcss_merge_classes!==!1?n.classes=o:n.attributes={"class":o},n}}var i=tinymce.each;e.settings.style_formats||e.on("renderFormatsMenu",function(a){var o=e.settings.importcss_selector_converter||n,r={};e.settings.importcss_append||a.control.items().remove(),i(t(e.getDoc()),function(t){if(-1===t.indexOf(".mce-")&&!r[t]){var n=o(t);if(n){var i=n.name||tinymce.DOM.uniqueId();e.formatter.register(i,n),a.control.append(tinymce.extend({},a.control.settings.itemDefaults,{text:n.title,format:i}))}r[t]=!0}})})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/insertdatetime/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/insertdatetime/plugin.min.js
new file mode 100755
index 0000000..08e2833
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/insertdatetime/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("insertdatetime",function(e){function t(t,n){function i(e,t){if(e=""+e,e.length<t)for(var n=0;n<t-e.length;n++)e="0"+e;return e}return n=n||new Date,t=t.replace("%D","%m/%d/%Y"),t=t.replace("%r","%I:%M:%S %p"),t=t.replace("%Y",""+n.getFullYear()),t=t.replace("%y",""+n.getYear()),t=t.replace("%m",i(n.getMonth()+1,2)),t=t.replace("%d",i(n.getDate(),2)),t=t.replace("%H",""+i(n.getHours(),2)),t=t.replace("%M",""+i(n.getMinutes(),2)),t=t.replace("%S",""+i(n.getSeconds(),2)),t=t.replace("%I",""+((n.getHours()+11)%12+1)),t=t.replace("%p",""+(n.getHours()<12?"AM":"PM")),t=t.replace("%B",""+e.translate(s[n.getMonth()])),t=t.replace("%b",""+e.translate(o[n.getMonth()])),t=t.replace("%A",""+e.translate(r[n.getDay()])),t=t.replace("%a",""+e.translate(a[n.getDay()])),t=t.replace("%%","%")}function n(n){var i=t(n);if(e.settings.insertdatetime_element){var a;a=/%[HMSIp]/.test(n)?t("%Y-%m-%dT%H:%M"):t("%Y-%m-%d"),i='<time datetime="'+a+'">'+i+"</time>";var r=e.dom.getParent(e.selection.getStart(),"time");if(r)return e.dom.setOuterHTML(r,i),void 0}e.insertContent(i)}var i,a="Sun Mon Tue Wed Thu Fri Sat Sun".split(" "),r="Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" "),o="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),s="January February March April May June July August September October November December".split(" "),l=[];e.addCommand("mceInsertDate",function(){n(e.getParam("insertdatetime_dateformat",e.translate("%Y-%m-%d")))}),e.addCommand("mceInsertTime",function(){n(e.getParam("insertdatetime_timeformat",e.translate("%H:%M:%S")))}),e.addButton("inserttime",{type:"splitbutton",title:"Insert time",onclick:function(){n(i||"%H:%M:%S")},menu:l}),tinymce.each(e.settings.insertdatetime_formats||["%H:%M:%S","%Y-%m-%d","%I:%M:%S %p","%D"],function(e){l.push({text:t(e),onclick:function(){i=e,n(e)}})}),e.addMenuItem("insertdatetime",{icon:"date",text:"Insert date/time",menu:l,context:"insert"})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/layer/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/layer/plugin.min.js
new file mode 100755
index 0000000..eb1ad4b
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/layer/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("layer",function(e){function t(e){do if(e.className&&-1!=e.className.indexOf("mceItemLayer"))return e;while(e=e.parentNode)}function n(t){var n=e.dom;tinymce.each(n.select("div,p",t),function(e){/^(absolute|relative|fixed)$/i.test(e.style.position)&&(e.hasVisual?n.addClass(e,"mceItemVisualAid"):n.removeClass(e,"mceItemVisualAid"),n.addClass(e,"mceItemLayer"))})}function i(n){var i,o,a=[],r=t(e.selection.getNode()),l=-1,s=-1;for(o=[],tinymce.walk(e.getBody(),function(e){1==e.nodeType&&/^(absolute|relative|static)$/i.test(e.style.position)&&o.push(e)},"childNodes"),i=0;i<o.length;i++)a[i]=o[i].style.zIndex?parseInt(o[i].style.zIndex,10):0,0>l&&o[i]==r&&(l=i);if(0>n){for(i=0;i<a.length;i++)if(a[i]<a[l]){s=i;break}s>-1?(o[l].style.zIndex=a[s],o[s].style.zIndex=a[l]):a[l]>0&&(o[l].style.zIndex=a[l]-1)}else{for(i=0;i<a.length;i++)if(a[i]>a[l]){s=i;break}s>-1?(o[l].style.zIndex=a[s],o[s].style.zIndex=a[l]):o[l].style.zIndex=a[l]+1}e.execCommand("mceRepaint")}function o(){var t=e.dom,n=t.getPos(t.getParent(e.selection.getNode(),"*")),i=e.getBody();e.dom.add(i,"div",{style:{position:"absolute",left:n.x,top:n.y>20?n.y:20,width:100,height:100},"class":"mceItemVisualAid mceItemLayer"},e.selection.getContent()||e.getLang("layer.content")),tinymce.Env.ie&&t.setHTML(i,i.innerHTML)}function a(){var n=t(e.selection.getNode());n||(n=e.dom.getParent(e.selection.getNode(),"DIV,P,IMG")),n&&("absolute"==n.style.position.toLowerCase()?(e.dom.setStyles(n,{position:"",left:"",top:"",width:"",height:""}),e.dom.removeClass(n,"mceItemVisualAid"),e.dom.removeClass(n,"mceItemLayer")):(n.style.left||(n.style.left="20px"),n.style.top||(n.style.top="20px"),n.style.width||(n.style.width=n.width?n.width+"px":"100px"),n.style.height||(n.style.height=n.height?n.height+"px":"100px"),n.style.position="absolute",e.dom.setAttrib(n,"data-mce-style",""),e.addVisual(e.getBody())),e.execCommand("mceRepaint"),e.nodeChanged())}e.addCommand("mceInsertLayer",o),e.addCommand("mceMoveForward",function(){i(1)}),e.addCommand("mceMoveBackward",function(){i(-1)}),e.addCommand("mceMakeAbsolute",function(){a()}),e.addButton("moveforward",{title:"layer.forward_desc",cmd:"mceMoveForward"}),e.addButton("movebackward",{title:"layer.backward_desc",cmd:"mceMoveBackward"}),e.addButton("absolute",{title:"layer.absolute_desc",cmd:"mceMakeAbsolute"}),e.addButton("insertlayer",{title:"layer.insertlayer_desc",cmd:"mceInsertLayer"}),e.on("init",function(){tinymce.Env.ie&&e.getDoc().execCommand("2D-Position",!1,!0)}),e.on("mouseup",function(n){var i=t(n.target);i&&e.dom.setAttrib(i,"data-mce-style","")}),e.on("mousedown",function(n){var i,o=n.target,a=e.getDoc();tinymce.Env.gecko&&(t(o)?"on"!==a.designMode&&(a.designMode="on",o=a.body,i=o.parentNode,i.removeChild(o),i.appendChild(o)):"on"==a.designMode&&(a.designMode="off"))}),e.on("NodeChange",n)}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/legacyoutput/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/legacyoutput/plugin.min.js
new file mode 100755
index 0000000..4f6f7c1
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/legacyoutput/plugin.min.js
@@ -0,0 +1 @@
+!function(e){e.on("AddEditor",function(e){e.editor.settings.inline_styles=!1}),e.PluginManager.add("legacyoutput",function(t){t.on("init",function(){var n="p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img",i=e.explode(t.settings.font_size_style_values),o=t.schema;t.formatter.register({alignleft:{selector:n,attributes:{align:"left"}},aligncenter:{selector:n,attributes:{align:"center"}},alignright:{selector:n,attributes:{align:"right"}},alignjustify:{selector:n,attributes:{align:"justify"}},bold:[{inline:"b",remove:"all"},{inline:"strong",remove:"all"},{inline:"span",styles:{fontWeight:"bold"}}],italic:[{inline:"i",remove:"all"},{inline:"em",remove:"all"},{inline:"span",styles:{fontStyle:"italic"}}],underline:[{inline:"u",remove:"all"},{inline:"span",styles:{textDecoration:"underline"},exact:!0}],strikethrough:[{inline:"strike",remove:"all"},{inline:"span",styles:{textDecoration:"line-through"},exact:!0}],fontname:{inline:"font",attributes:{face:"%value"}},fontsize:{inline:"font",attributes:{size:function(t){return e.inArray(i,t.value)+1}}},forecolor:{inline:"font",attributes:{color:"%value"}},hilitecolor:{inline:"font",styles:{backgroundColor:"%value"}}}),e.each("b,i,u,strike".split(","),function(e){o.addValidElements(e+"[*]")}),o.getElementRule("font")||o.addValidElements("font[face|size|color|style]"),e.each(n.split(","),function(e){var t=o.getElementRule(e);t&&(t.attributes.align||(t.attributes.align={},t.attributesOrder.push("align")))})})})}(tinymce); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/link/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/link/plugin.min.js
new file mode 100755
index 0000000..9cd7616
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/link/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("link",function(e){function t(t){return function(){var n=e.settings.link_list;"string"==typeof n?tinymce.util.XHR.send({url:n,success:function(e){t(tinymce.util.JSON.parse(e))}}):t(n)}}function n(t){function n(e){var t=d.find("#text");(!t.value()||e.lastControl&&t.value()==e.lastControl.text())&&t.value(e.control.text()),d.find("#href").value(e.control.value())}function i(){var e=[{text:"None",value:""}];return tinymce.each(t,function(t){e.push({text:t.text||t.title,value:t.value||t.url,menu:t.menu})}),e}function a(t){var n=[{text:"None",value:""}];return tinymce.each(e.settings.rel_list,function(e){n.push({text:e.text||e.title,value:e.value,selected:t===e.value})}),n}function o(t){var n=[{text:"None",value:""}];return e.settings.target_list||n.push({text:"New window",value:"_blank"}),tinymce.each(e.settings.target_list,function(e){n.push({text:e.text||e.title,value:e.value,selected:t===e.value})}),n}function r(t){var i=[];return tinymce.each(e.dom.select("a:not([href])"),function(e){var n=e.name||e.id;n&&i.push({text:n,value:"#"+n,selected:-1!=t.indexOf("#"+n)})}),i.length?(i.unshift({text:"None",value:""}),{name:"anchor",type:"listbox",label:"Anchors",values:i,onselect:n}):void 0}function s(){c||0!==g.text.length||this.parent().parent().find("#text")[0].value(this.value())}var l,u,c,d,m,f,h,g={},p=e.selection,v=e.dom;l=p.getNode(),u=v.getParent(l,"a[href]"),g.text=c=u?u.innerText||u.textContent:p.getContent({format:"text"}),g.href=u?v.getAttrib(u,"href"):"",g.target=u?v.getAttrib(u,"target"):"",g.rel=u?v.getAttrib(u,"rel"):"","IMG"==l.nodeName&&(g.text=c=" "),t&&(m={type:"listbox",label:"Link list",values:i(),onselect:n}),e.settings.target_list!==!1&&(h={name:"target",type:"listbox",label:"Target",values:o(g.target)}),e.settings.rel_list&&(f={name:"rel",type:"listbox",label:"Rel",values:a(g.rel)}),d=e.windowManager.open({title:"Insert link",data:g,body:[{name:"href",type:"filepicker",filetype:"file",size:40,autofocus:!0,label:"Url",onchange:s,onkeyup:s},{name:"text",type:"textbox",size:40,label:"Text to display",onchange:function(){g.text=this.value()}},r(g.href),m,f,h],onSubmit:function(t){function n(t,n){window.setTimeout(function(){e.windowManager.confirm(t,n)},0)}function i(){a.text!=c?u?(e.focus(),u.innerHTML=a.text,v.setAttribs(u,{href:o,target:a.target?a.target:null,rel:a.rel?a.rel:null}),p.select(u)):e.insertContent(v.createHTML("a",{href:o,target:a.target?a.target:null,rel:a.rel?a.rel:null},a.text)):e.execCommand("mceInsertLink",!1,{href:o,target:a.target,rel:a.rel?a.rel:null})}var a=t.data,o=a.href;return o?o.indexOf("@")>0&&-1==o.indexOf("//")&&-1==o.indexOf("mailto:")?(n("The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",function(e){e&&(o="mailto:"+o),i()}),void 0):/^\s*www\./i.test(o)?(n("The URL you entered seems to be an external link. Do you want to add the required http:// prefix?",function(e){e&&(o="http://"+o),i()}),void 0):(i(),void 0):(e.execCommand("unlink"),void 0)}})}e.addButton("link",{icon:"link",tooltip:"Insert/edit link",shortcut:"Ctrl+K",onclick:t(n),stateSelector:"a[href]"}),e.addButton("unlink",{icon:"unlink",tooltip:"Remove link",cmd:"unlink",stateSelector:"a[href]"}),e.addShortcut("Ctrl+K","",t(n)),this.showDialog=n,e.addMenuItem("link",{icon:"link",text:"Insert link",shortcut:"Ctrl+K",onclick:t(n),stateSelector:"a[href]",context:"insert",prependToContext:!0})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/lists/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/lists/plugin.min.js
new file mode 100755
index 0000000..811c46d
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/lists/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("lists",function(e){var t=this;e.on("init",function(){function n(e){function t(t){var i,r,a;r=e[t?"startContainer":"endContainer"],a=e[t?"startOffset":"endOffset"],1==r.nodeType&&(i=b.create("span",{"data-mce-type":"bookmark"}),r.hasChildNodes()?(a=Math.min(a,r.childNodes.length-1),r.insertBefore(i,r.childNodes[a])):r.appendChild(i),r=i,a=0),n[t?"startContainer":"endContainer"]=r,n[t?"startOffset":"endOffset"]=a}var n={};return t(!0),e.collapsed||t(),n}function i(t){function n(n){function i(e){for(var t=e.parentNode.firstChild,n=0;t;){if(t==e)return n;(1!=t.nodeType||"bookmark"!=t.getAttribute("data-mce-type"))&&n++,t=t.nextSibling}return-1}var r,a,o;if(r=o=t[n?"startContainer":"endContainer"],a=t[n?"startOffset":"endOffset"],r){if(1==r.nodeType){if(r.parentNode==e.getBody()){var s,l=e.settings.forced_root_block;l?(s=b.create(l),(!tinymce.Env.ie||tinymce.Env.ie>10)&&s.appendChild(b.create("br",{"data-mce-bogus":"true"})),r.parentNode.insertBefore(s,r),r=s,a=0):(s=b.create("br"),r.parentNode.insertBefore(s,r),r=r.parentNode,a=i(s))}else n?(a=i(r),r=r.parentNode):(a=i(r),r=r.parentNode);b.remove(o)}t[n?"startContainer":"endContainer"]=r,t[n?"startOffset":"endOffset"]=a}}n(!0),n();var i=b.createRng();i.setStart(t.startContainer,t.startOffset),t.endContainer&&i.setEnd(t.endContainer,t.endOffset),C.setRng(i)}function r(e){return e&&/^(OL|UL)$/.test(e.nodeName)}function a(e){return e.parentNode.firstChild==e}function o(e){return e.parentNode.lastChild==e}function s(t){return t&&!!e.schema.getTextBlockElements()[t.nodeName]}function l(t,n){var i,r;if(e.settings.forced_root_block&&(n=n||e.settings.forced_root_block),r=n?b.create(n):b.createFragment(),t)for(;i=t.firstChild;)r.appendChild(i);return e.settings.forced_root_block||r.appendChild(b.create("br")),r.hasChildNodes()||tinymce.Env.ie&&!(tinymce.Env.ie>10)||(r.innerHTML='<br data-mce-bogus="1">'),r}function c(){return tinymce.grep(C.getSelectedBlocks(),function(e){return"LI"==e.nodeName})}function d(){return tinymce.grep(C.getSelectedBlocks(),s)}function u(e,t,n){var i,r,a=b.select('span[data-mce-type="bookmark"]',e);n=n||l(t),i=b.createRng(),i.setStartAfter(t),i.setEndAfter(e),r=i.extractContents(),b.isEmpty(r)||b.insertAfter(r,e),b.isEmpty(n)||b.insertAfter(n,e),b.isEmpty(t.parentNode)&&(tinymce.each(a,function(e){t.parentNode.parentNode.insertBefore(e,t.parentNode)}),b.remove(t.parentNode)),b.remove(t)}function m(e){var t,n;if(t=e.nextSibling,t&&r(t)&&t.nodeName==e.nodeName){for(;n=t.firstChild;)e.appendChild(n);b.remove(t)}if(t=e.previousSibling,t&&r(t)&&t.nodeName==e.nodeName){for(;n=t.firstChild;)e.insertBefore(n,e.firstChild);b.remove(t)}}function f(e){tinymce.each(tinymce.grep(b.select("ol,ul",e)),function(e){var t,n=e.parentNode;"LI"==n.nodeName&&n.firstChild==e&&(t=n.previousSibling,t&&"LI"==t.nodeName&&(t.appendChild(e),b.isEmpty(n)&&b.remove(n))),r(n)&&(t=n.previousSibling,t&&"LI"==t.nodeName&&t.appendChild(e))})}function p(){var e,t=n(C.getRng(!0));return tinymce.each(c(),function(t){var n,i;return n=t.previousSibling,n&&"UL"==n.nodeName?(n.appendChild(t),void 0):n&&"LI"==n.nodeName&&r(n.lastChild)?(n.lastChild.appendChild(t),void 0):(n=t.nextSibling,n&&"UL"==n.nodeName?(n.insertBefore(t,n.firstChild),void 0):(n&&"LI"==n.nodeName&&r(t.lastChild)||(n=t.previousSibling,n&&"LI"==n.nodeName&&(i=b.create(t.parentNode.nodeName),n.appendChild(i),i.appendChild(t)),e=!0),void 0))}),i(t),e}function h(){function e(e){b.isEmpty(e)&&b.remove(e)}var t,s=n(C.getRng(!0));return tinymce.each(c(),function(n){var i,s=n.parentNode,c=s.parentNode;if(a(n)&&o(n))if("LI"==c.nodeName)b.insertAfter(n,c),e(c);else{if(!r(c))return;b.remove(s,!0)}else if(a(n))if("LI"==c.nodeName)b.insertAfter(n,c),i=b.create("LI"),i.appendChild(s),b.insertAfter(i,n),e(c);else{if(!r(c))return;c.insertBefore(n,s)}else if(o(n))if("LI"==c.nodeName)b.insertAfter(n,c);else{if(!r(c))return;b.insertAfter(n,s)}else{if("LI"==c.nodeName)s=c,i=l(n,"LI");else{if(!r(c))return;i=l(n,"LI")}u(s,n,i),f(s.parentNode)}t=!0}),i(s),t}function g(t){function a(){function t(t){var n,i,r=e.getBody();for(n=o[t?"startContainer":"endContainer"],i=o[t?"startOffset":"endOffset"],1==n.nodeType&&(n=n.childNodes[Math.min(i,n.childNodes.length-1)]||n);n.parentNode!=r;){if(s(n))return n;if(/^(TD|TH)$/.test(n.parentNode.nodeName))return n;n=n.parentNode}return n}function n(e,t){var n,i=[];if(!s(e)){for(;e&&(n=e[t?"previousSibling":"nextSibling"],!b.isBlock(n)&&n);)e=n;for(;e;)i.push(e),e=e[t?"nextSibling":"previousSibling"]}return i}var i,r,a=t(!0),l=t();r=n(a,!0),a!=l&&(r=r.concat(n(l).reverse())),tinymce.each(r,function(e){if(!b.isBlock(e)||"BR"==e.nodeName){if(!i||"BR"==e.nodeName){if("BR"==e.nodeName&&(!e.nextSibling||b.isBlock(e.nextSibling)&&"BR"!=e.nextSibling.nodeName))return b.remove(e),!1;i=b.create("p"),c.push(i),e.parentNode.insertBefore(i,e)}return"BR"!=e.nodeName?i.appendChild(e):b.remove(e),e==l?!1:void 0}})}var o=C.getRng(!0),l=n(o),c=d();a(),tinymce.each(c,function(e){var n,i;i=e.previousSibling,i&&r(i)&&i.nodeName==t?(n=i,e=b.rename(e,"LI"),i.appendChild(e)):(n=b.create(t),e.parentNode.insertBefore(n,e),n.appendChild(e),e=b.rename(e,"LI")),m(n)}),i(l)}function v(){var e=n(C.getRng(!0));tinymce.each(c(),function(e){var t,n;for(t=e;t;t=t.parentNode)r(t)&&(n=t);u(n,e)}),i(e)}function y(e){var t=b.getParent(C.getStart(),"OL,UL");if(t)if(t.nodeName==e)v(e);else{var r=n(C.getRng(!0));m(b.rename(t,e)),i(r)}else g(e)}var b=e.dom,C=e.selection;t.backspaceDelete=function(e){function t(e,t){var n=e.startContainer,i=e.startOffset;if(3==n.nodeType&&(t?i<n.data.length:i>0))return n;for(var r=new tinymce.dom.TreeWalker(e.startContainer);n=r[t?"next":"prev"]();)if(3==n.nodeType&&n.data.length>0)return n}function a(e,t){var n,i,a=e.parentNode;for(r(t.lastChild)&&(i=t.lastChild),n=t.lastChild,n&&"BR"==n.nodeName&&e.hasChildNodes()&&b.remove(n);n=e.firstChild;)t.appendChild(n);i&&t.appendChild(i),b.remove(e),b.isEmpty(a)&&b.remove(a)}if(C.isCollapsed()){var o=b.getParent(C.getStart(),"LI");if(o){var s=C.getRng(!0),l=b.getParent(t(s,e),"LI");if(l&&l!=o){var c=n(s);return e?a(l,o):a(o,l),i(c),!0}if(!l&&!e&&v(o.parentNode.nodeName))return!0}}},e.addCommand("Indent",function(){return p()?void 0:!0}),e.addCommand("Outdent",function(){return h()?void 0:!0}),e.addCommand("InsertUnorderedList",function(){y("UL")}),e.addCommand("InsertOrderedList",function(){y("OL")})}),e.on("keydown",function(e){e.keyCode==tinymce.util.VK.BACKSPACE?t.backspaceDelete()&&e.preventDefault():e.keyCode==tinymce.util.VK.DELETE&&t.backspaceDelete(!0)&&e.preventDefault()})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/media/moxieplayer.swf b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/media/moxieplayer.swf
new file mode 100755
index 0000000..19c771b
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/media/moxieplayer.swf
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/media/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/media/plugin.min.js
new file mode 100755
index 0000000..ce8cd0e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/media/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("media",function(e,t){function n(e){return-1!=e.indexOf(".mp3")?"audio/mpeg":-1!=e.indexOf(".wav")?"audio/wav":-1!=e.indexOf(".mp4")?"video/mp4":-1!=e.indexOf(".webm")?"video/webm":-1!=e.indexOf(".ogg")?"video/ogg":-1!=e.indexOf(".swf")?"application/x-shockwave-flash":""}function i(){function t(e){var t,r,a,o;t=n.find("#width")[0],r=n.find("#height")[0],a=t.value(),o=r.value(),n.find("#constrain")[0].checked()&&i&&c&&a&&o&&(e.control==t?(o=Math.round(a/i*o),r.value(o)):(a=Math.round(o/c*a),t.value(a))),i=a,c=o}var n,i,c,l;l=s(e.selection.getNode()),i=l.width,c=l.height,n=e.windowManager.open({title:"Insert/edit video",data:l,bodyType:"tabpanel",body:[{title:"General",type:"form",onShowTab:function(){this.fromJSON(o(this.next().find("#embed").value()))},items:[{name:"source1",type:"filepicker",filetype:"media",size:40,autofocus:!0,label:"Source"},{name:"source2",type:"filepicker",filetype:"media",size:40,label:"Alternative source"},{name:"poster",type:"filepicker",filetype:"image",size:40,label:"Poster"},{type:"container",label:"Dimensions",layout:"flex",direction:"row",align:"center",spacing:5,items:[{name:"width",type:"textbox",maxLength:3,size:3,onchange:t},{type:"label",text:"x"},{name:"height",type:"textbox",maxLength:3,size:3,onchange:t},{name:"constrain",type:"checkbox",checked:!0,text:"Constrain proportions"}]}]},{title:"Embed",type:"panel",layout:"flex",direction:"column",align:"stretch",padding:10,spacing:10,onShowTab:function(){this.find("#embed").value(a(this.parent().toJSON()))},items:[{type:"label",text:"Paste your embed code below:"},{type:"textbox",flex:1,name:"embed",value:r(),multiline:!0,label:"Source"}]}],onSubmit:function(){e.insertContent(a(this.toJSON()))}})}function r(){var t=e.selection.getNode();return t.getAttribute("data-mce-object")?e.selection.getContent():void 0}function a(i){var r="";return i.source1||(tinymce.extend(i,o(i.embed)),i.source1)?(i.source1=e.convertURL(i.source1,"source"),i.source2=e.convertURL(i.source2,"source"),i.source1mime=n(i.source1),i.source2mime=n(i.source2),i.poster=e.convertURL(i.poster,"poster"),i.flashPlayerUrl=e.convertURL(t+"/moxieplayer.swf","movie"),i.embed?r=c(i.embed,i,!0):(tinymce.each(l,function(e){var t,n,r;if(t=e.regex.exec(i.source1)){for(r=e.url,n=0;t[n];n++)r=r.replace("$"+n,function(){return t[n]});i.source1=r,i.type=e.type,i.width=e.w,i.height=e.h}}),i.width=i.width||300,i.height=i.height||150,tinymce.each(i,function(t,n){i[n]=e.dom.encode(t)}),"iframe"==i.type?r+='<iframe src="'+i.source1+'" width="'+i.width+'" height="'+i.height+'"></iframe>':"application/x-shockwave-flash"==i.source1mime?(r+='<object data="'+i.source1+'" width="'+i.width+'" height="'+i.height+'" type="application/x-shockwave-flash">',i.poster&&(r+='<img src="'+i.poster+'" width="'+i.width+'" height="'+i.height+'" />'),r+="</object>"):-1!=i.source1mime.indexOf("audio")?e.settings.audio_template_callback?r=e.settings.audio_template_callback(i):r+='<audio controls="controls" src="'+i.source1+'">'+(i.source2?'\n<source src="'+i.source2+'"'+(i.source2mime?' type="'+i.source2mime+'"':"")+" />\n":"")+"</audio>":r=e.settings.video_template_callback?e.settings.video_template_callback(i):'<video width="'+i.width+'" height="'+i.height+'"'+(i.poster?' poster="'+i.poster+'"':"")+' controls="controls">\n'+'<source src="'+i.source1+'"'+(i.source1mime?' type="'+i.source1mime+'"':"")+" />\n"+(i.source2?'<source src="'+i.source2+'"'+(i.source2mime?' type="'+i.source2mime+'"':"")+" />\n":"")+"</video>"),r):""}function o(e){var t={};return new tinymce.html.SaxParser({validate:!1,special:"script,noscript",start:function(e,n){t.source1||"param"!=e||(t.source1=n.map.movie),("iframe"==e||"object"==e||"embed"==e||"video"==e||"audio"==e)&&(t=tinymce.extend(n.map,t)),"source"==e&&(t.source1?t.source2||(t.source2=n.map.src):t.source1=n.map.src),"img"!=e||t.poster||(t.poster=n.map.src)}}).parse(e),t.source1=t.source1||t.src||t.data,t.source2=t.source2||"",t.poster=t.poster||"",t}function s(t){return t.getAttribute("data-mce-object")?o(e.serializer.serialize(t,{selection:!0})):{}}function c(e,t,n){function i(e,t){var n,i,r,a;for(n in t)if(r=""+t[n],e.map[n])for(i=e.length;i--;)a=e[i],a.name==n&&(r?(e.map[n]=r,a.value=r):(delete e.map[n],e.splice(i,1)));else r&&(e.push({name:n,value:r}),e.map[n]=r)}var r,a=new tinymce.html.Writer,o=0;return new tinymce.html.SaxParser({validate:!1,special:"script,noscript",comment:function(e){a.comment(e)},cdata:function(e){a.cdata(e)},text:function(e,t){a.text(e,t)},start:function(e,s,c){switch(e){case"video":case"object":case"img":case"iframe":i(s,{width:t.width,height:t.height})}if(n)switch(e){case"video":i(s,{poster:t.poster,src:""}),t.source2&&i(s,{src:""});break;case"iframe":i(s,{src:t.source1});break;case"source":if(o++,2>=o&&(i(s,{src:t["source"+o],type:t["source"+o+"mime"]}),!t["source"+o]))return;break;case"img":if(!t.poster)return;r=!0}a.start(e,s,c)},end:function(e){if("video"==e&&n)for(var s=1;2>=s;s++)if(t["source"+s]){var c=[];c.map={},s>o&&(i(c,{src:t["source"+s],type:t["source"+s+"mime"]}),a.start("source",c,!0))}if(t.poster&&"object"==e&&n&&!r){var l=[];l.map={},i(l,{src:t.poster,width:t.width,height:t.height}),a.start("img",l,!0)}a.end(e)}},new tinymce.html.Schema({})).parse(e),a.getContent()}var l=[{regex:/youtu\.be\/([a-z1-9.-_]+)/,type:"iframe",w:425,h:350,url:"http://www.youtube.com/embed/$1"},{regex:/youtube\.com(.+)v=([^&]+)/,type:"iframe",w:425,h:350,url:"http://www.youtube.com/embed/$2"},{regex:/vimeo\.com\/([0-9]+)/,type:"iframe",w:425,h:350,url:"http://player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc"},{regex:/maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,type:"iframe",w:425,h:350,url:'http://maps.google.com/maps/ms?msid=$2&output=embed"'}];e.on("ResolveName",function(e){var t;1==e.target.nodeType&&(t=e.target.getAttribute("data-mce-object"))&&(e.name=t)}),e.on("preInit",function(){var t=e.schema.getSpecialElements();tinymce.each("video audio iframe object".split(" "),function(e){t[e]=new RegExp("</"+e+"[^>]*>","gi")}),e.schema.addValidElements("object[id|style|width|height|classid|codebase|*],embed[id|style|width|height|type|src|*],video[*],audio[*]");var n=e.schema.getBoolAttrs();tinymce.each("webkitallowfullscreen mozallowfullscreen allowfullscreen".split(" "),function(e){n[e]={}}),e.parser.addNodeFilter("iframe,video,audio,object,embed",function(t,n){for(var i,r,a,o,s,c,l,d=t.length;d--;){for(r=t[d],a=new tinymce.html.Node("img",1),a.shortEnded=!0,c=r.attributes,i=c.length;i--;)o=c[i].name,s=c[i].value,"width"!==o&&"height"!==o&&"style"!==o&&(("data"==o||"src"==o)&&(s=e.convertURL(s,o)),a.attr("data-mce-p-"+o,s));l=r.firstChild&&r.firstChild.value,l&&(a.attr("data-mce-html",escape(l)),a.firstChild=null),a.attr({width:r.attr("width")||"300",height:r.attr("height")||("audio"==n?"30":"150"),style:r.attr("style"),src:tinymce.Env.transparentSrc,"data-mce-object":n,"class":"mce-object mce-object-"+n}),r.replace(a)}}),e.serializer.addAttributeFilter("data-mce-object",function(e,t){for(var n,i,r,a,o,s,c=e.length;c--;){for(n=e[c],i=new tinymce.html.Node(n.attr(t),1),"audio"!=n.attr(t)&&i.attr({width:n.attr("width"),height:n.attr("height")}),i.attr({style:n.attr("style")}),a=n.attributes,r=a.length;r--;){var l=a[r].name;0===l.indexOf("data-mce-p-")&&i.attr(l.substr(11),a[r].value)}o=n.attr("data-mce-html"),o&&(s=new tinymce.html.Node("#text",3),s.raw=!0,s.value=unescape(o),i.append(s)),n.replace(i)}})}),e.on("ObjectSelected",function(e){"audio"==e.target.getAttribute("data-mce-object")&&e.preventDefault()}),e.on("objectResized",function(e){var t,n=e.target;n.getAttribute("data-mce-object")&&(t=n.getAttribute("data-mce-html"),t&&(t=unescape(t),n.setAttribute("data-mce-html",escape(c(t,{width:e.width,height:e.height})))))}),e.addButton("media",{tooltip:"Insert/edit video",onclick:i,stateSelector:"img[data-mce-object=video]"}),e.addMenuItem("media",{icon:"media",text:"Insert video",onclick:i,context:"insert",prependToContext:!0})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/nonbreaking/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/nonbreaking/plugin.min.js
new file mode 100755
index 0000000..866339c
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/nonbreaking/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("nonbreaking",function(e){var t=e.getParam("nonbreaking_force_tab");if(e.addCommand("mceNonBreaking",function(){e.insertContent(e.plugins.visualchars&&e.plugins.visualchars.state?'<span data-mce-bogus="1" class="mce-nbsp">&nbsp;</span>':"&nbsp;")}),e.addButton("nonbreaking",{title:"Insert nonbreaking space",cmd:"mceNonBreaking"}),e.addMenuItem("nonbreaking",{text:"Nonbreaking space",cmd:"mceNonBreaking",context:"insert"}),t){var n=+t>1?+t:3;e.on("keydown",function(t){if(9==t.keyCode){if(t.shiftKey)return;t.preventDefault();for(var i=0;n>i;i++)e.execCommand("mceNonBreaking")}})}}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/noneditable/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/noneditable/plugin.min.js
new file mode 100755
index 0000000..dd15d59
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/noneditable/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("noneditable",function(e){function t(){function t(e){var t;if(1===e.nodeType){if(t=e.getAttribute(s),t&&"inherit"!==t)return t;if(t=e.contentEditable,"inherit"!==t)return t}return null}function n(e){for(var n;e;){if(n=t(e))return"false"===n?e:null;e=e.parentNode}}function i(e){for(;e;){if(e.id===g)return e;e=e.parentNode}}function o(e){var t;if(e)for(t=new r(e,e),e=t.current();e;e=t.next())if(3===e.nodeType)return e}function a(n,i){var o,a;return"false"===t(n)&&m.isBlock(n)?(f.select(n),void 0):(a=m.createRng(),"true"===t(n)&&(n.firstChild||n.appendChild(e.getDoc().createTextNode(" ")),n=n.firstChild,i=!0),o=m.create("span",{id:g,"data-mce-bogus":!0},p),i?n.parentNode.insertBefore(o,n):m.insertAfter(o,n),a.setStart(o.firstChild,1),a.collapse(!0),f.setRng(a),o)}function l(e){var t,n,a,r;if(e)t=f.getRng(!0),t.setStartBefore(e),t.setEndBefore(e),n=o(e),n&&n.nodeValue.charAt(0)==p&&(n=n.deleteData(0,1)),m.remove(e,!0),f.setRng(t);else for(a=i(f.getStart());(e=m.get(g))&&e!==r;)a!==e&&(n=o(e),n&&n.nodeValue.charAt(0)==p&&(n=n.deleteData(0,1)),m.remove(e,!0)),r=e}function d(){function e(e,n){var i,o,a,l,s;if(i=c.startContainer,o=c.startOffset,3==i.nodeType){if(s=i.nodeValue.length,o>0&&s>o||(n?o==s:0===o))return}else{if(!(o<i.childNodes.length))return n?null:e;var d=!n&&o>0?o-1:o;i=i.childNodes[d],i.hasChildNodes()&&(i=i.firstChild)}for(a=new r(i,e);l=a[n?"prev":"next"]();){if(3===l.nodeType&&l.nodeValue.length>0)return;if("true"===t(l))return l}return e}var i,o,s,c,d;l(),s=f.isCollapsed(),i=n(f.getStart()),o=n(f.getEnd()),(i||o)&&(c=f.getRng(!0),s?(i=i||o,(d=e(i,!0))?a(d,!0):(d=e(i,!1))?a(d,!1):f.select(i)):(c=f.getRng(!0),i&&c.setStartBefore(i),o&&c.setEndAfter(o),f.setRng(c)))}function u(o){function a(e,t){for(;e=e[t?"previousSibling":"nextSibling"];)if(3!==e.nodeType||e.nodeValue.length>0)return e}function s(e,t){f.select(e),f.collapse(t)}function u(o){function a(e){for(var t=s;t;){if(t===e)return;t=t.parentNode}m.remove(e),d()}function r(){var i,r,l=e.schema.getNonEmptyElements();for(r=new tinymce.dom.TreeWalker(s,e.getBody());(i=o?r.prev():r.next())&&!l[i.nodeName.toLowerCase()]&&!(3===i.nodeType&&tinymce.trim(i.nodeValue).length>0);)if("false"===t(i))return a(i),!0;return n(i)?!0:!1}var l,s,c,u;if(f.isCollapsed()){if(l=f.getRng(!0),s=l.startContainer,c=l.startOffset,s=i(s)||s,u=n(s))return a(u),!1;if(3==s.nodeType&&(o?c>0:c<s.nodeValue.length))return!0;if(1==s.nodeType&&(s=s.childNodes[c]||s),r())return!1}return!0}var g,p,h,y,v=o.keyCode;if(h=f.getStart(),y=f.getEnd(),g=n(h)||n(y),g&&(112>v||v>124)&&v!=c.DELETE&&v!=c.BACKSPACE){if((tinymce.isMac?o.metaKey:o.ctrlKey)&&(67==v||88==v||86==v))return;if(o.preventDefault(),v==c.LEFT||v==c.RIGHT){var b=v==c.LEFT;if(e.dom.isBlock(g)){var x=b?g.previousSibling:g.nextSibling,w=new r(x,x),C=b?w.prev():w.next();s(C,!b)}else s(g,b)}}else if(v==c.LEFT||v==c.RIGHT||v==c.BACKSPACE||v==c.DELETE){if(p=i(h)){if(v==c.LEFT||v==c.BACKSPACE)if(g=a(p,!0),g&&"false"===t(g)){if(o.preventDefault(),v!=c.LEFT)return m.remove(g),void 0;s(g,!0)}else l(p);if(v==c.RIGHT||v==c.DELETE)if(g=a(p),g&&"false"===t(g)){if(o.preventDefault(),v!=c.RIGHT)return m.remove(g),void 0;s(g,!1)}else l(p)}if((v==c.BACKSPACE||v==c.DELETE)&&!u(v==c.BACKSPACE))return o.preventDefault(),!1}}var m=e.dom,f=e.selection,g="mce_noneditablecaret",p="";e.on("mousedown",function(n){var i=e.selection.getNode();"false"===t(i)&&i==n.target&&d()}),e.on("mouseup keyup",d),e.on("keydown",u)}function n(t){var n=a.length,i=t.content,r=tinymce.trim(o);if("raw"!=t.format){for(;n--;)i=i.replace(a[n],function(t){var n=arguments,o=n[n.length-2];return o>0&&'"'==i.charAt(o-1)?t:'<span class="'+r+'" data-mce-content="'+e.dom.encode(n[0])+'">'+e.dom.encode("string"==typeof n[1]?n[1]:n[0])+"</span>"});t.content=i}}var i,o,a,r=tinymce.dom.TreeWalker,l="contenteditable",s="data-mce-"+l,c=tinymce.util.VK;i=" "+tinymce.trim(e.getParam("noneditable_editable_class","mceEditable"))+" ",o=" "+tinymce.trim(e.getParam("noneditable_noneditable_class","mceNonEditable"))+" ",a=e.getParam("noneditable_regexp"),a&&!a.length&&(a=[a]),e.on("PreInit",function(){t(),a&&e.on("BeforeSetContent",n),e.parser.addAttributeFilter("class",function(e){for(var t,n,a=e.length;a--;)n=e[a],t=" "+n.attr("class")+" ",-1!==t.indexOf(i)?n.attr(s,"true"):-1!==t.indexOf(o)&&n.attr(s,"false")}),e.serializer.addAttributeFilter(s,function(e){for(var t,n=e.length;n--;)t=e[n],a&&t.attr("data-mce-content")?(t.name="#text",t.type=3,t.raw=!0,t.value=t.attr("data-mce-content")):(t.attr(l,null),t.attr(s,null))}),e.parser.addAttributeFilter(l,function(e){for(var t,n=e.length;n--;)t=e[n],t.attr(s,t.attr(l)),t.attr(l,null)})})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/pagebreak/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/pagebreak/plugin.min.js
new file mode 100755
index 0000000..8f535fa
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/pagebreak/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("pagebreak",function(e){var t,n="mce-pagebreak",i=e.getParam("pagebreak_separator","<!-- pagebreak -->"),a='<img src="'+tinymce.Env.transparentSrc+'" class="'+n+'" data-mce-resize="false" />';t=new RegExp(i.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,function(e){return"\\"+e}),"gi"),e.addCommand("mcePageBreak",function(){e.execCommand("mceInsertContent",0,a)}),e.addButton("pagebreak",{title:"Page break",cmd:"mcePageBreak"}),e.addMenuItem("pagebreak",{text:"Page break",icon:"pagebreak",cmd:"mcePageBreak",context:"insert"}),e.on("ResolveName",function(t){"IMG"==t.target.nodeName&&e.dom.hasClass(t.target,n)&&(t.name="pagebreak")}),e.on("click",function(t){t=t.target,"IMG"===t.nodeName&&e.dom.hasClass(t,n)&&e.selection.select(t)}),e.on("BeforeSetContent",function(e){e.content=e.content.replace(t,a)}),e.on("PreInit",function(){e.serializer.addNodeFilter("img",function(e){for(var t,n,a=e.length;a--;)t=e[a],n=t.attr("class"),n&&-1!==n.indexOf("mce-pagebreak")&&(t.type=3,t.value=i,t.raw=!0)})})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/paste/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/paste/plugin.min.js
new file mode 100755
index 0000000..68851b2
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/paste/plugin.min.js
@@ -0,0 +1 @@
+!function(e,t){"use strict";function n(e,t){for(var n,r=[],i=0;i<e.length;++i){if(n=s[e[i]]||o(e[i]),!n)throw"module definition dependecy not found: "+e[i];r.push(n)}t.apply(null,r)}function r(e,r,i){if("string"!=typeof e)throw"invalid module definition, module id must be defined and be a string";if(r===t)throw"invalid module definition, dependencies must be specified";if(i===t)throw"invalid module definition, definition function must be specified";n(r,function(){s[e]=i.apply(null,arguments)})}function i(e){return!!s[e]}function o(t){for(var n=e,r=t.split(/[.\/]/),i=0;i<r.length;++i){if(!n[r[i]])return;n=n[r[i]]}return n}function a(n){for(var r=0;r<n.length;r++){for(var i=e,o=n[r],a=o.split(/[.\/]/),l=0;l<a.length-1;++l)i[a[l]]===t&&(i[a[l]]={}),i=i[a[l]];i[a[a.length-1]]=s[o]}}var s={},l="tinymce/pasteplugin/Clipboard",c="tinymce/Env",u="tinymce/util/Tools",d="tinymce/util/VK",f="tinymce/pasteplugin/WordFilter",p="tinymce/html/DomParser",m="tinymce/html/Schema",h="tinymce/html/Serializer",g="tinymce/html/Node",v="tinymce/pasteplugin/Quirks",y="tinymce/pasteplugin/Plugin",b="tinymce/PluginManager";r(l,[c,u,d],function(e,t,n){function r(){return!e.gecko&&("ClipboardEvent"in window||e.webkit&&"FocusEvent"in window)}return function(i){function o(){return(new Date).getTime()}function a(e){return n.metaKeyPressed(e)&&86==e.keyCode||e.shiftKey&&45==e.keyCode}function s(e){return e.innerText||e.textContent}function l(){return o()-h<100||"text"==m.pasteFormat}function c(e,n){return t.each(n,function(t){e=t.constructor==RegExp?e.replace(t,""):e.replace(t[0],t[1])}),e}function u(t){var n=i.fire("PastePreProcess",{content:t});t=n.content,i.settings.paste_data_images||(t=t.replace(/<img src=\"data:image[^>]+>/g,"")),(i.settings.paste_remove_styles||i.settings.paste_remove_styles_if_webkit!==!1&&e.webkit)&&(t=t.replace(/ style=\"[^\"]+\"/g,"")),n.isDefaultPrevented()||i.insertContent(t)}function d(e){e=i.dom.encode(e).replace(/\r\n/g,"\n");var t=i.dom.getParent(i.selection.getStart(),i.dom.isBlock);e=t&&/^(PRE|DIV)$/.test(t.nodeName)||!i.settings.forced_root_block?c(e,[[/\n/g,"<br>"]]):c(e,[[/\n\n/g,"</p><p>"],[/^(.*<\/p>)(<p>)$/,"<p>$1"],[/\n/g,"<br />"]]);var n=i.fire("PastePreProcess",{content:e});n.isDefaultPrevented()||i.insertContent(n.content)}function f(){var e=i.dom.getViewPort().y,t=i.dom.add(i.getBody(),"div",{contentEditable:!1,"data-mce-bogus":"1",style:"position: absolute; top: "+e+"px; left: 0; width: 1px; height: 1px; overflow: hidden"},'<div contentEditable="true" data-mce-bogus="1">X</div>');return i.dom.bind(t,"beforedeactivate focusin focusout",function(e){e.stopPropagation()}),t}function p(e){i.dom.unbind(e),i.dom.remove(e)}var m=this,h;if(i.on("keydown",function(e){n.metaKeyPressed(e)&&e.shiftKey&&86==e.keyCode&&(h=o())}),r())i.on("paste",function(e){function t(e,t){for(var r=0;r<n.types.length;r++)if(n.types[r]==e)return t(n.getData(e)),!0}var n=e.clipboardData;n&&(e.preventDefault(),l()?t("text/plain",d)||t("text/html",u):t("text/html",u)||t("text/plain",d))});else{if(e.ie){var g=0;i.on("keydown",function(e){if(a(e)&&!e.isDefaultPrevented()){e.stopImmediatePropagation();var t=f();g=o(),i.dom.bind(t,"paste",function(){setTimeout(function(){i.selection.setRng(n),p(t),l()?d(s(t.firstChild)):u(t.firstChild.innerHTML)},0)});var n=i.selection.getRng();t.firstChild.focus(),t.firstChild.innerText=""}}),i.on("init",function(){var e=i.dom;i.dom.bind(i.getBody(),"paste",function(t){if(o()-g>100){var n,r=f();t.preventDefault(),e.bind(r,"paste",function(e){e.stopPropagation(),n=!0});var a=i.selection.getRng(),c=e.doc.body.createTextRange();if(c.moveToElementText(r.firstChild),c.execCommand("Paste"),p(r),!n)return i.windowManager.alert("Please use Ctrl+V/Cmd+V keyboard shortcuts to paste contents."),void 0;i.selection.setRng(a),l()?d(s(r.firstChild)):u(r.firstChild.innerHTML)}})})}else i.on("init",function(){i.dom.bind(i.getBody(),"paste",function(e){e.preventDefault(),i.windowManager.alert("Please use Ctrl+V/Cmd+V keyboard shortcuts to paste contents.")})}),i.on("keydown",function(e){if(a(e)&&!e.isDefaultPrevented()){e.stopImmediatePropagation();var t=f(),n=i.selection.getRng();i.selection.select(t,!0),i.dom.bind(t,"paste",function(e){e.stopPropagation(),setTimeout(function(){p(t),i.lastRng=n,i.selection.setRng(n);var e=t.firstChild;e.lastChild&&"BR"==e.lastChild.nodeName&&e.removeChild(e.lastChild),l()?d(s(e)):u(e.innerHTML)},0)})}});i.settings.paste_data_images||i.on("drop",function(e){var t=e.dataTransfer;t&&t.files&&t.files.length>0&&e.preventDefault()})}i.paste_block_drop&&i.on("dragend dragover draggesture dragdrop drop drag",function(e){e.preventDefault(),e.stopPropagation()}),this.paste=u,this.pasteText=d}}),r(f,[u,p,m,h,g],function(e,t,n,r,i){return function(o){var a=e.each;o.on("PastePreProcess",function(s){function l(e){a(e,function(e){d=e.constructor==RegExp?d.replace(e,""):d.replace(e[0],e[1])})}function c(e){function t(e,t,a,s){var l=e._listLevel||o;l!=o&&(o>l?n&&(n=n.parent.parent):(r=n,n=null)),n&&n.name==a?n.append(e):(r=r||n,n=new i(a,1),s>1&&n.attr("start",""+s),e.wrap(n)),e.name="li",t.value="";var c=t.next;c&&3==c.type&&(c.value=c.value.replace(/^\u00a0+/,"")),l>o&&r&&r.lastChild.append(n),o=l}for(var n,r,o=1,a=e.getAll("p"),s=0;s<a.length;s++)if(e=a[s],"p"==e.name&&e.firstChild){for(var l="",c=e.firstChild;c&&!(l=c.value);)c=c.firstChild;if(/^\s*[\u2022\u00b7\u00a7\u00d8o\u25CF]\s*$/.test(l)){t(e,c,"ul");continue}if(/^\s*\w+\./.test(l)){var u=/([0-9])\./.exec(l),d=1;u&&(d=parseInt(u[1],10)),t(e,c,"ol",d);continue}n=null}}function u(t,n){if("p"===t.name){var r=/mso-list:\w+ \w+([0-9]+)/.exec(n);r&&(t._listLevel=parseInt(r[1],10))}if(o.getParam("paste_retain_style_properties","none")){var i="";if(e.each(o.dom.parseStyle(n),function(e,t){switch(t){case"horiz-align":return t="text-align",void 0;case"vert-align":return t="vertical-align",void 0;case"font-color":case"mso-foreground":return t="color",void 0;case"mso-background":case"mso-highlight":t="background"}("all"==f||p&&p[t])&&(i+=t+":"+e+";")}),i)return i}return null}var d=s.content,f,p;if(f=o.settings.paste_retain_style_properties,f&&(p=e.makeMap(f)),o.settings.paste_enable_default_filters!==!1&&/class="?Mso|style="[^"]*\bmso-|style='[^'']*\bmso-|w:WordDocument/i.test(s.content)){s.wordContent=!0,l([/<!--[\s\S]+?-->/gi,/<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi,[/<(\/?)s>/gi,"<$1strike>"],[/&nbsp;/gi,"\xa0"],[/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi,function(e,t){return t.length>0?t.replace(/./," ").slice(Math.floor(t.length/2)).split("").join("\xa0"):""}]]);var m=new n({valid_elements:"@[style],-strong/b,-em/i,-span,-p,-ol,-ul,-li,-h1,-h2,-h3,-h4,-h5,-h6,-table,-tr,-td[colspan|rowspan],-th,-thead,-tfoot,-tbody,-a[!href],sub,sup,strike"}),h=new t({},m);h.addAttributeFilter("style",function(e){for(var t=e.length,n;t--;)n=e[t],n.attr("style",u(n,n.attr("style"))),"span"!=n.name||n.attributes.length||n.unwrap()});var g=h.parse(d);c(g),s.content=new r({},m).serialize(g)}})}}),r(v,[c,u],function(e,t){return function(n){function r(e){n.on("PastePreProcess",function(t){t.content=e(t.content)})}function i(e,n){return t.each(n,function(t){e=t.constructor==RegExp?e.replace(t,""):e.replace(t[0],t[1])}),e}function o(e){return e=i(e,[/^[\s\S]*<!--StartFragment-->|<!--EndFragment-->[\s\S]*$/g,[/<span class="Apple-converted-space">\u00a0<\/span>/g,"\xa0"],/<br>$/])}function a(e){if(!s){var r=[];t.each(n.schema.getBlockElements(),function(e,t){r.push(t)}),s=new RegExp("(?:<br>&nbsp;[\\s\\r\\n]+|<br>)*(<\\/?("+r.join("|")+")[^>]*>)(?:<br>&nbsp;[\\s\\r\\n]+|<br>)*","g")}return e=i(e,[[s,"$1"]]),e=i(e,[[/<br><br>/g,"<BR><BR>"],[/<br>/g," "],[/<BR><BR>/g,"<br>"]])}var s;e.webkit&&r(o),e.ie&&r(a)}}),r(y,[b,l,f,v],function(e,t,n,r){var i;e.add("paste",function(e){function o(){"text"==s.pasteFormat?(this.active(!1),s.pasteFormat="html"):(s.pasteFormat="text",this.active(!0),i||(e.windowManager.alert("Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off."),i=!0))}var a=this,s;a.clipboard=s=new t(e),a.quirks=new r(e),a.wordFilter=new n(e),e.settings.paste_as_text&&(a.clipboard.pasteFormat="text"),e.addCommand("mceInsertClipboardContent",function(e,t){t.content&&a.clipboard.paste(t.content),t.text&&a.clipboard.pasteText(t.text)}),e.addButton("pastetext",{icon:"pastetext",tooltip:"Paste as text",onclick:o,active:"text"==a.clipboard.pasteFormat}),e.addMenuItem("pastetext",{text:"Paste as text",selectable:!0,active:s.pasteFormat,onclick:o})})}),a([l,f,v,y])}(this); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/preview/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/preview/plugin.min.js
new file mode 100755
index 0000000..b8430c6
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/preview/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("preview",function(e){var t=e.settings;e.addCommand("mcePreview",function(){e.windowManager.open({title:"Preview",width:parseInt(e.getParam("plugin_preview_width","650"),10),height:parseInt(e.getParam("plugin_preview_height","500"),10),html:'<iframe src="javascript:\'\'" frameborder="0"></iframe>',buttons:{text:"Close",onclick:function(){this.parent().parent().close()}},onPostRender:function(){var n,i=this.getEl("body").firstChild.contentWindow.document,a="";tinymce.each(e.contentCSS,function(t){a+='<link type="text/css" rel="stylesheet" href="'+e.documentBaseURI.toAbsolute(t)+'">'});var r=t.body_id||"tinymce";-1!=r.indexOf("=")&&(r=e.getParam("body_id","","hash"),r=r[e.id]||r);var o=t.body_class||"";-1!=o.indexOf("=")&&(o=e.getParam("body_class","","hash"),o=o[e.id]||""),n="<!DOCTYPE html><html><head>"+a+"</head>"+'<body id="'+r+'" class="mce-content-body '+o+'">'+e.getContent()+"</body>"+"</html>",i.open(),i.write(n),i.close()}})}),e.addButton("preview",{title:"Preview",cmd:"mcePreview"}),e.addMenuItem("preview",{text:"Preview",cmd:"mcePreview",context:"view"})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/print/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/print/plugin.min.js
new file mode 100755
index 0000000..abc37b5
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/print/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("print",function(t){t.addCommand("mcePrint",function(){t.getWin().print()}),t.addButton("print",{title:"Print",cmd:"mcePrint"}),t.addShortcut("Ctrl+P","","mcePrint"),t.addMenuItem("print",{text:"Print",cmd:"mcePrint",icon:"print",shortcut:"Ctrl+P",context:"file"})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/save/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/save/plugin.min.js
new file mode 100755
index 0000000..bd50cec
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/save/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("save",function(e){function t(){var t,n;return t=tinymce.DOM.getParent(e.id,"form"),!e.getParam("save_enablewhendirty",!0)||e.isDirty()?(tinymce.triggerSave(),(n=e.getParam("save_onsavecallback"))?(e.execCallback("save_onsavecallback",e)&&(e.startContent=tinymce.trim(e.getContent({format:"raw"})),e.nodeChanged()),void 0):(t?(e.isNotDirty=!0,(!t.onsubmit||t.onsubmit())&&("function"==typeof t.submit?t.submit():e.windowManager.alert("Error: Form submit field collision.")),e.nodeChanged()):e.windowManager.alert("Error: No form element found."),void 0)):void 0}function n(){var t,n=tinymce.trim(e.startContent);return(t=e.getParam("save_oncancelcallback"))?(e.execCallback("save_oncancelcallback",e),void 0):(e.setContent(n),e.undoManager.clear(),e.nodeChanged(),void 0)}function i(){var t=this;e.on("nodeChange",function(){t.disabled(e.getParam("save_enablewhendirty",!0)&&!e.isDirty())})}e.addCommand("mceSave",t),e.addCommand("mceCancel",n),e.addButton("save",{icon:"save",text:"Save",cmd:"mceSave",disabled:!0,onPostRender:i}),e.addButton("cancel",{text:"Cancel",icon:!1,cmd:"mceCancel",disabled:!0,onPostRender:i}),e.addShortcut("ctrl+s","","mceSave")}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/searchreplace/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/searchreplace/plugin.min.js
new file mode 100755
index 0000000..b9c4fcc
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/searchreplace/plugin.min.js
@@ -0,0 +1 @@
+!function(){function e(e,t,n,i,a){function r(e,t){if(t=t||0,!e[0])throw"findAndReplaceDOMText cannot handle zero-length matches";var n=e.index;if(t>0){var i=e[t];if(!i)throw"Invalid capture group";n+=e[0].indexOf(i),e[0]=i}return[n,n+e[0].length,[e[0]]]}function o(e){var t;if(3===e.nodeType)return e.data;if(f[e.nodeName])return"";if(t="",(m[e.nodeName]||h[e.nodeName])&&(t+="\n"),e=e.firstChild)do t+=o(e);while(e=e.nextSibling);return t}function c(e,t,n){var i,a,r,o,c=[],s=0,d=e,l=t.shift(),u=0;e:for(;;){if((m[d.nodeName]||h[d.nodeName])&&s++,3===d.nodeType&&(!a&&d.length+s>=l[1]?(a=d,o=l[1]-s):i&&c.push(d),!i&&d.length+s>l[0]&&(i=d,r=l[0]-s),s+=d.length),i&&a){if(d=n({startNode:i,startNodeIndex:r,endNode:a,endNodeIndex:o,innerNodes:c,match:l[2],matchIndex:u}),s-=a.length-o,i=null,a=null,c=[],l=t.shift(),u++,!l)break}else{if(!f[d.nodeName]&&d.firstChild){d=d.firstChild;continue}if(d.nextSibling){d=d.nextSibling;continue}}for(;;){if(d.nextSibling){d=d.nextSibling;break}if(d.parentNode===e)break e;d=d.parentNode}}}function s(e){var t;if("function"!=typeof e){var n=e.nodeType?e:u.createElement(e);t=function(e,t){var i=n.cloneNode(!1);return i.setAttribute("data-mce-index",t),e&&i.appendChild(u.createTextNode(e)),i}}else t=e;return function(e){var n,i,a,r=e.startNode,o=e.endNode,c=e.matchIndex;if(r===o){var s=r;a=s.parentNode,e.startNodeIndex>0&&(n=u.createTextNode(s.data.substring(0,e.startNodeIndex)),a.insertBefore(n,s));var d=t(e.match[0],c);return a.insertBefore(d,s),e.endNodeIndex<s.length&&(i=u.createTextNode(s.data.substring(e.endNodeIndex)),a.insertBefore(i,s)),s.parentNode.removeChild(s),d}n=u.createTextNode(r.data.substring(0,e.startNodeIndex)),i=u.createTextNode(o.data.substring(e.endNodeIndex));for(var l=t(r.data.substring(e.startNodeIndex),c),m=[],f=0,h=e.innerNodes.length;h>f;++f){var p=e.innerNodes[f],g=t(p.data,c);p.parentNode.replaceChild(g,p),m.push(g)}var v=t(o.data.substring(0,e.endNodeIndex),c);return a=r.parentNode,a.insertBefore(n,r),a.insertBefore(l,r),a.removeChild(r),a=o.parentNode,a.insertBefore(v,o),a.insertBefore(i,o),a.removeChild(o),v}}var d,l,u,m,f,h,p=[],g=0;if(u=t.ownerDocument,m=a.getBlockElements(),f=a.getWhiteSpaceElements(),h=a.getShortEndedElements(),l=o(t)){if(e.global)for(;d=e.exec(l);)p.push(r(d,i));else d=l.match(e),p.push(r(d,i));return p.length&&(g=p.length,c(t,p,s(n))),g}}function t(t){function n(){var e=tinymce.ui.Factory.create({type:"window",layout:"flex",pack:"center",align:"center",onClose:function(){t.focus(),o=!1,c.unmarkAllMatches()},buttons:[{text:"Find",onclick:function(){e.find("form")[0].submit()}},{text:"Replace",disabled:!0,onclick:function(){c.replace(e.find("#replace").value())||e.statusbar.items().slice(1).disabled(!0)}},{text:"Replace all",disabled:!0,onclick:function(){c.replaceAll(e.find("#replace").value()),e.statusbar.items().slice(1).disabled(!0)}},{type:"spacer",flex:1},{text:"Prev",disabled:!0,onclick:function(){c.prev()}},{text:"Next",disabled:!0,onclick:function(){c.next()}}],title:"Find and replace",items:{type:"form",padding:20,labelGap:30,spacing:10,onsubmit:function(t){var n,i,a,r,o;return t.preventDefault(),a=e.find("#case").checked(),o=e.find("#words").checked(),r=e.find("#find").value(),r.length?(r=r.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&"),r=o?"\\b"+r+"\\b":r,i=new RegExp(r,a?"g":"gi"),n=c.markAllMatches(i),n?c.first():tinymce.ui.MessageBox.alert("Could not find the specified string."),e.statusbar.items().slice(1).disabled(0===n),void 0):(c.unmarkAllMatches(),e.statusbar.items().slice(1).disabled(!0),void 0)},items:[{type:"textbox",name:"find",size:40,label:"Find",value:t.selection.getNode().src},{type:"textbox",name:"replace",size:40,label:"Replace with"},{type:"checkbox",name:"case",text:"Match case",label:" "},{type:"checkbox",name:"words",text:"Whole words",label:" "}]}}).renderTo().reflow();o=!0}function i(e){var t=e.parentNode;t.insertBefore(e.firstChild,e),e.parentNode.removeChild(e)}function a(e,n){function i(){var i,o;for(i=n?t.getBody()[e?"firstChild":"lastChild"]:c[e?"endContainer":"startContainer"],o=new tinymce.dom.TreeWalker(i,t.getBody());i=o.current();){if(1==i.nodeType&&"SPAN"==i.nodeName&&null!==i.getAttribute("data-mce-index"))for(s=i.getAttribute("data-mce-index"),a=i.firstChild;i=o.current();){if(1==i.nodeType&&"SPAN"==i.nodeName&&null!==i.getAttribute("data-mce-index")){if(i.getAttribute("data-mce-index")!==s)return;r=i.firstChild}o[e?"next":"prev"]()}o[e?"next":"prev"]()}}var a,r,o=t.selection,c=o.getRng(!0),s=-1;return e=e!==!1,i(),a&&r&&(t.focus(),e?(c.setStart(a,0),c.setEnd(r,r.length)):(c.setStart(r,0),c.setEnd(a,a.length)),o.scrollIntoView(a.parentNode),o.setRng(c)),s}function r(e){e.parentNode.removeChild(e)}var o,c=this,s=-1;c.init=function(e){e.addMenuItem("searchreplace",{text:"Find and replace",shortcut:"Ctrl+F",onclick:n,separator:"before",context:"edit"}),e.addButton("searchreplace",{tooltip:"Find and replace",shortcut:"Ctrl+F",onclick:n}),e.addCommand("SearchReplace",n),e.shortcuts.add("Ctrl+F","",n)},c.markAllMatches=function(n){var i,a;return a=t.dom.create("span",{"class":"mce-match-marker","data-mce-bogus":1}),i=t.getBody(),c.unmarkAllMatches(i),e(n,i,a,!1,t.schema)},c.first=function(){return s=a(!0,!0),-1!==s},c.next=function(){return s=a(!0),-1!==s},c.prev=function(){return s=a(!1),-1!==s},c.replace=function(e,n,o){var c,d,l,u,m,f;if(-1===s&&(s=a(n)),f=a(n),l=t.getBody(),d=tinymce.toArray(l.getElementsByTagName("span")),d.length)for(c=0;c<d.length;c++){var h=d[c].getAttribute("data-mce-index");if(null!==h&&h.length&&(u=m=d[c].getAttribute("data-mce-index"),o||u===s))for(e.length?(d[c].firstChild.nodeValue=e,i(d[c])):r(d[c]);d[++c];)if(u=d[c].getAttribute("data-mce-index"),null!==h&&h.length){if(u!==m){c--;break}r(d[c])}}return-1==f&&(f=a(n,!0)),s=f,o&&t.selection.setCursorLocation(t.getBody(),0),t.undoManager.add(),-1!==s},c.replaceAll=function(e){c.replace(e,!0,!0)},c.unmarkAllMatches=function(){var e,n,a;for(a=t.getBody(),n=a.getElementsByTagName("span"),e=n.length;e--;)a=n[e],a.getAttribute("data-mce-index")&&i(a)},t.on("beforeaddundo keydown",function(e){return o?(e.preventDefault(),!1):void 0})}tinymce.PluginManager.add("searchreplace",t)}(); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/spellchecker/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/spellchecker/plugin.min.js
new file mode 100755
index 0000000..9cbf031
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/spellchecker/plugin.min.js
@@ -0,0 +1 @@
+!function(e,t){"use strict";function n(e,t){for(var n,r=[],o=0;o<e.length;++o){if(n=s[e[o]]||i(e[o]),!n)throw"module definition dependecy not found: "+e[o];r.push(n)}t.apply(null,r)}function r(e,r,o){if("string"!=typeof e)throw"invalid module definition, module id must be defined and be a string";if(r===t)throw"invalid module definition, dependencies must be specified";if(o===t)throw"invalid module definition, definition function must be specified";n(r,function(){s[e]=o.apply(null,arguments)})}function o(e){return!!s[e]}function i(t){for(var n=e,r=t.split(/[.\/]/),o=0;o<r.length;++o){if(!n[r[o]])return;n=n[r[o]]}return n}function a(n){for(var r=0;r<n.length;r++){for(var o=e,i=n[r],a=i.split(/[.\/]/),l=0;l<a.length-1;++l)o[a[l]]===t&&(o[a[l]]={}),o=o[a[l]];o[a[a.length-1]]=s[i]}}var s={},l="tinymce/spellcheckerplugin/DomTextMatcher",c="tinymce/spellcheckerplugin/Plugin",d="tinymce/PluginManager",u="tinymce/util/Tools",f="tinymce/ui/Menu",p="tinymce/dom/DOMUtils",m="tinymce/util/JSONRequest",h="tinymce/util/URI";r(l,[],function(){return function(e,t,n){function r(e){if(!e[0])throw"findAndReplaceDOMText cannot handle zero-length matches";var t=e.index;return[t,t+e[0].length,[e[0]]]}function o(e){var t;if(3===e.nodeType)return e.data;if(g[e.nodeName])return"";if(t="",(h[e.nodeName]||v[e.nodeName])&&(t+="\n"),e=e.firstChild)do t+=o(e);while(e=e.nextSibling);return t}function i(e,t,n){var r,o,i,a,s=[],l=0,c=e,d=t.shift(),u=0;e:for(;;){if((h[c.nodeName]||v[c.nodeName])&&l++,3===c.nodeType&&(!o&&c.length+l>=d[1]?(o=c,a=d[1]-l):r&&s.push(c),!r&&c.length+l>d[0]&&(r=c,i=d[0]-l),l+=c.length),r&&o){if(c=n({startNode:r,startNodeIndex:i,endNode:o,endNodeIndex:a,innerNodes:s,match:d[2],matchIndex:u}),l-=o.length-a,r=null,o=null,s=[],d=t.shift(),u++,!d)break}else{if(!g[c.nodeName]&&c.firstChild){c=c.firstChild;continue}if(c.nextSibling){c=c.nextSibling;continue}}for(;;){if(c.nextSibling){c=c.nextSibling;break}if(c.parentNode===e)break e;c=c.parentNode}}}function a(e){var t;if("function"!=typeof e){var n=e.nodeType?e:m.createElement(e);t=function(e,t){var r=n.cloneNode(!1);return r.setAttribute("data-mce-index",t),e&&r.appendChild(m.createTextNode(e)),r}}else t=e;return function r(e){var n,r,o,i=e.startNode,a=e.endNode,s=e.matchIndex;if(i===a){var l=i;o=l.parentNode,e.startNodeIndex>0&&(n=m.createTextNode(l.data.substring(0,e.startNodeIndex)),o.insertBefore(n,l));var c=t(e.match[0],s);return o.insertBefore(c,l),e.endNodeIndex<l.length&&(r=m.createTextNode(l.data.substring(e.endNodeIndex)),o.insertBefore(r,l)),l.parentNode.removeChild(l),c}n=m.createTextNode(i.data.substring(0,e.startNodeIndex)),r=m.createTextNode(a.data.substring(e.endNodeIndex));for(var d=t(i.data.substring(e.startNodeIndex),s),u=[],f=0,p=e.innerNodes.length;p>f;++f){var h=e.innerNodes[f],g=t(h.data,s);h.parentNode.replaceChild(g,h),u.push(g)}var v=t(a.data.substring(0,e.endNodeIndex),s);return o=i.parentNode,o.insertBefore(n,i),o.insertBefore(d,i),o.removeChild(i),o=a.parentNode,o.insertBefore(v,a),o.insertBefore(r,a),o.removeChild(a),v}}function s(e){var t=[];return l(function(n,r){e(n,r)&&t.push(n)}),u=t,this}function l(e){for(var t=0,n=u.length;n>t&&e(u[t],t)!==!1;t++);return this}function c(e){return u.length&&(p=u.length,i(t,u,a(e))),this}var d,u=[],f,p=0,m,h,g,v;if(m=t.ownerDocument,h=n.getBlockElements(),g=n.getWhiteSpaceElements(),v=n.getShortEndedElements(),f=o(t),f&&e.global)for(;d=e.exec(f);)u.push(r(d));return{text:f,count:p,matches:u,each:l,filter:s,mark:c}}}),r(c,[l,d,u,f,p,m,h],function(e,t,n,r,o,i,a){t.add("spellchecker",function(t,s){function l(e){for(var t in e)return!1;return!0}function c(e,i){var a=[],s=g[i];n.each(s,function(e){a.push({text:e,onclick:function(){t.insertContent(e),u()}})}),a.push.apply(a,[{text:"-"},{text:"Ignore",onclick:function(){p(e,i)}},{text:"Ignore all",onclick:function(){p(e,i,!0)}},{text:"Finish",onclick:m}]),y=new r({items:a,context:"contextmenu",onautohide:function(e){-1!=e.target.className.indexOf("spellchecker")&&e.preventDefault()},onhide:function(){y.remove(),y=null}}),y.renderTo(document.body);var l=o.DOM.getPos(t.getContentAreaContainer()),c=t.dom.getPos(e);l.x+=c.x,l.y+=c.y,y.moveTo(l.x,l.y+e.offsetHeight)}function d(){function n(e){return t.setProgressState(!1),l(e)?(t.windowManager.alert("No misspellings found"),v=!1,void 0):(g=e,o.filter(function(t){return!!e[t[2][0]]}).mark(t.dom.create("span",{"class":"mce-spellchecker-word","data-mce-bogus":1})),o=null,t.fire("SpellcheckStart"),void 0)}function r(e,n,r){i.sendRPC({url:new a(s).toAbsolute(b.spellchecker_rpc_url),method:e,params:{lang:b.spellchecker_language||"en",words:n},success:function(e){r(e)},error:function(e,n){e="JSON Parse error."==e?"Non JSON response:"+n.responseText:"Error: "+e,t.windowManager.alert(e),t.setProgressState(!1),o=null,v=!1}})}var o,c=[],d={};if(v)return m(),void 0;v=!0;var u=t.getParam("spellchecker_wordchar_pattern")||new RegExp('[^\\s!"#$%&()*+,-./:;<=>?@[\\]^_{|}`\xa7\xa9\xab\xae\xb1\xb6\xb7\xb8\xbb\xbc\xbd\xbe\xbf\xd7\xf7\xa4\u201d\u201c\u201e]+',"g");o=new e(u,t.getBody(),t.schema).each(function(e){var t=e[2][0];if(!d[t]){if(/^\d+$/.test(t)||1==t.length)return;c.push(t),d[t]=!0}}),t.setProgressState(!0);var f=b.spellchecker_callback||r;f("spellcheck",c,n)}function u(){t.dom.select("span.mce-spellchecker-word").length||m()}function f(e){var t=e.parentNode;t.insertBefore(e.firstChild,e),e.parentNode.removeChild(e)}function p(e,r,o){o?n.each(t.dom.select("span.mce-spellchecker-word"),function(e){var t=e.innerText||e.textContent;t==r&&f(e)}):f(e),u()}function m(){var e,n,r;for(v=!1,r=t.getBody(),n=r.getElementsByTagName("span"),e=n.length;e--;)r=n[e],r.getAttribute("data-mce-index")&&f(r);t.fire("SpellcheckEnd")}function h(e){var n,r,o,i=-1,a,s;for(e=""+e,n=t.getBody().getElementsByTagName("span"),r=0;r<n.length&&(o=n[r],"mce-spellchecker-word"!=o.className||(i=o.getAttribute("data-mce-index"),i===e&&(i=e,a||(a=o.firstChild),s=o.firstChild),i===e||!s));r++);var l=t.dom.createRng();return l.setStart(a,0),l.setEnd(s,s.length),t.selection.setRng(l),l}var g,v,y,b=t.settings;t.on("click",function(e){if("mce-spellchecker-word"==e.target.className){e.preventDefault();var t=h(e.target.getAttribute("data-mce-index"));c(e.target,t.toString())}}),t.addMenuItem("spellchecker",{text:"Spellcheck",context:"tools",onclick:d,selectable:!0,onPostRender:function(){var e=this;t.on("SpellcheckStart SpellcheckEnd",function(){e.active(v)})}}),t.addButton("spellchecker",{tooltip:"Spellcheck",onclick:d,onPostRender:function(){var e=this;t.on("SpellcheckStart SpellcheckEnd",function(){e.active(v)})}}),t.on("remove",function(){y&&(y.remove(),y=null)})})}),a([l,c])}(this); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/tabfocus/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/tabfocus/plugin.min.js
new file mode 100755
index 0000000..bd71785
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/tabfocus/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("tabfocus",function(e){function n(e){9===e.keyCode&&e.preventDefault()}function t(n){function t(n){function t(e){return"BODY"===e.nodeName||"hidden"!=e.type&&"none"!=e.style.display&&"hidden"!=e.style.visibility&&t(e.parentNode)}function r(e){return e.tabIndex||"INPUT"==e.nodeName||"TEXTAREA"==e.nodeName}function a(e){return!r(e)&&"-1"!=e.getAttribute("tabindex")&&t(e)}if(d=i.select(":input:enabled,*[tabindex]:not(iframe)"),o(d,function(n,t){return n.id==e.id?(u=t,!1):void 0}),n>0){for(c=u+1;c<d.length;c++)if(a(d[c]))return d[c]}else for(c=u-1;c>=0;c--)if(a(d[c]))return d[c];return null}var u,d,a,c;if(9===n.keyCode&&(a=r(e.getParam("tab_focus",e.getParam("tabfocus_elements",":prev,:next"))),1==a.length&&(a[1]=a[0],a[0]=":prev"),d=n.shiftKey?":prev"==a[0]?t(-1):i.get(a[0]):":next"==a[1]?t(1):i.get(a[1]))){var f=tinymce.get(d.id||d.name);d.id&&f?f.focus():window.setTimeout(function(){tinymce.Env.webkit||window.focus(),d.focus()},10),n.preventDefault()}}var i=tinymce.DOM,o=tinymce.each,r=tinymce.explode;e.on("init",function(){e.inline&&tinymce.DOM.setAttrib(e.getBody(),"tabIndex",null)}),e.on("keyup",n),tinymce.Env.gecko?e.on("keypress keydown",t):e.on("keydown",t)}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/table/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/table/plugin.min.js
new file mode 100755
index 0000000..c7c2e8e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/table/plugin.min.js
@@ -0,0 +1 @@
+!function(e,t){"use strict";function n(e,t){for(var n,r=[],i=0;i<e.length;++i){if(n=s[e[i]]||o(e[i]),!n)throw"module definition dependecy not found: "+e[i];r.push(n)}t.apply(null,r)}function r(e,r,i){if("string"!=typeof e)throw"invalid module definition, module id must be defined and be a string";if(r===t)throw"invalid module definition, dependencies must be specified";if(i===t)throw"invalid module definition, definition function must be specified";n(r,function(){s[e]=i.apply(null,arguments)})}function i(e){return!!s[e]}function o(t){for(var n=e,r=t.split(/[.\/]/),i=0;i<r.length;++i){if(!n[r[i]])return;n=n[r[i]]}return n}function a(n){for(var r=0;r<n.length;r++){for(var i=e,o=n[r],a=o.split(/[.\/]/),l=0;l<a.length-1;++l)i[a[l]]===t&&(i[a[l]]={}),i=i[a[l]];i[a[a.length-1]]=s[o]}}var s={},l="tinymce/tableplugin/TableGrid",c="tinymce/util/Tools",d="tinymce/Env",u="tinymce/tableplugin/Quirks",f="tinymce/util/VK",p="tinymce/tableplugin/CellSelection",m="tinymce/dom/TreeWalker",h="tinymce/tableplugin/Plugin",g="tinymce/PluginManager";r(l,[c,d],function(e,t){function n(e,t){return parseInt(e.getAttribute(t)||1,10)}var r=e.each;return function(i,o){function a(){var e=0;R=[],r(["thead","tbody","tfoot"],function(t){var i=H.select("> "+t+" tr",o);r(i,function(i,o){o+=e,r(H.select("> td, > th",i),function(e,r){var i,a,s,l;if(R[o])for(;R[o][r];)r++;for(s=n(e,"rowspan"),l=n(e,"colspan"),a=o;o+s>a;a++)for(R[a]||(R[a]=[]),i=r;r+l>i;i++)R[a][i]={part:t,real:a==o&&i==r,elm:e,rowspan:s,colspan:l}})}),e+=i.length})}function s(e,t){return e=e.cloneNode(t),e.removeAttribute("id"),e}function l(e,t){var n;return n=R[t],n?n[e]:void 0}function c(e,t,n){e&&(n=parseInt(n,10),1===n?e.removeAttribute(t,1):e.setAttribute(t,n,1))}function d(e){return e&&(H.hasClass(e.elm,"mce-item-selected")||e==P)}function u(){var e=[];return r(o.rows,function(t){r(t.cells,function(n){return H.hasClass(n,"mce-item-selected")||n==P.elm?(e.push(t),!1):void 0})}),e}function f(){var e=H.createRng();e.setStartAfter(o),e.setEndAfter(o),M.setRng(e),H.remove(o)}function p(n){var o,a={};return i.settings.table_clone_elements!==!1&&(a=e.makeMap((i.settings.table_clone_elements||"strong em b i span font h1 h2 h3 h4 h5 h6 p div").toUpperCase(),/[ ,]/)),e.walk(n,function(e){var i;return 3==e.nodeType?(r(H.getParents(e.parentNode,null,n).reverse(),function(e){a[e.nodeName]&&(e=s(e,!1),o?i&&i.appendChild(e):o=i=e,i=e)}),i&&(i.innerHTML=t.ie?"&nbsp;":'<br data-mce-bogus="1" />'),!1):void 0},"childNodes"),n=s(n,!1),c(n,"rowSpan",1),c(n,"colSpan",1),o?n.appendChild(o):t.ie||(n.innerHTML='<br data-mce-bogus="1" />'),n}function m(){var e=H.createRng(),t;return r(H.select("tr",o),function(e){0===e.cells.length&&H.remove(e)}),0===H.select("tr",o).length?(e.setStartBefore(o),e.setEndBefore(o),M.setRng(e),H.remove(o),void 0):(r(H.select("thead,tbody,tfoot",o),function(e){0===e.rows.length&&H.remove(e)}),a(),t=R[Math.min(R.length-1,A.y)],t&&(M.select(t[Math.min(t.length-1,A.x)].elm,!0),M.collapse(!0)),void 0)}function h(e,t,n,r){var i,o,a,s,l;for(i=R[t][e].elm.parentNode,a=1;n>=a;a++)if(i=H.getNext(i,"tr")){for(o=e;o>=0;o--)if(l=R[t+a][o].elm,l.parentNode==i){for(s=1;r>=s;s++)H.insertAfter(p(l),l);break}if(-1==o)for(s=1;r>=s;s++)i.insertBefore(p(i.cells[0]),i.cells[0])}}function g(){r(R,function(e,t){r(e,function(e,r){var i,o,a;if(d(e)&&(e=e.elm,i=n(e,"colspan"),o=n(e,"rowspan"),i>1||o>1)){for(c(e,"rowSpan",1),c(e,"colSpan",1),a=0;i-1>a;a++)H.insertAfter(p(e),e);h(r,t,o-1,i)}})})}function v(t,n,i){var o,s,u,f,p,h,v,y,b,C,x;if(t?(o=S(t),s=o.x,u=o.y,f=s+(n-1),p=u+(i-1)):(A=B=null,r(R,function(e,t){r(e,function(e,n){d(e)&&(A||(A={x:n,y:t}),B={x:n,y:t})})}),s=A.x,u=A.y,f=B.x,p=B.y),y=l(s,u),b=l(f,p),y&&b&&y.part==b.part){for(g(),a(),y=l(s,u).elm,c(y,"colSpan",f-s+1),c(y,"rowSpan",p-u+1),v=u;p>=v;v++)for(h=s;f>=h;h++)R[v]&&R[v][h]&&(t=R[v][h].elm,t!=y&&(C=e.grep(t.childNodes),r(C,function(e){y.appendChild(e)}),C.length&&(C=e.grep(y.childNodes),x=0,r(C,function(e){"BR"==e.nodeName&&H.getAttrib(e,"data-mce-bogus")&&x++<C.length-1&&y.removeChild(e)})),H.remove(t)));m()}}function y(e){var t,i,o,a,l,u,f,m,h;for(r(R,function(n,i){return r(n,function(n){return d(n)&&(n=n.elm,l=n.parentNode,u=s(l,!1),t=i,e)?!1:void 0}),e?!t:void 0}),a=0;a<R[0].length;a++)if(R[t][a]&&(i=R[t][a].elm,i!=o)){if(e){if(t>0&&R[t-1][a]&&(m=R[t-1][a].elm,h=n(m,"rowSpan"),h>1)){c(m,"rowSpan",h+1);continue}}else if(h=n(i,"rowspan"),h>1){c(i,"rowSpan",h+1);continue}f=p(i),c(f,"colSpan",i.colSpan),u.appendChild(f),o=i}u.hasChildNodes()&&(e?l.parentNode.insertBefore(u,l):H.insertAfter(u,l))}function b(e){var t,i;r(R,function(n){return r(n,function(n,r){return d(n)&&(t=r,e)?!1:void 0}),e?!t:void 0}),r(R,function(r,o){var a,s,l;r[t]&&(a=r[t].elm,a!=i&&(l=n(a,"colspan"),s=n(a,"rowspan"),1==l?e?(a.parentNode.insertBefore(p(a),a),h(t,o,s-1,l)):(H.insertAfter(p(a),a),h(t,o,s-1,l)):c(a,"colSpan",a.colSpan+1),i=a))})}function C(){var t=[];r(R,function(i){r(i,function(i,o){d(i)&&-1===e.inArray(t,o)&&(r(R,function(e){var t=e[o].elm,r;r=n(t,"colSpan"),r>1?c(t,"colSpan",r-1):H.remove(t)}),t.push(o))})}),m()}function x(){function e(e){var t,i,o;t=H.getNext(e,"tr"),r(e.cells,function(e){var t=n(e,"rowSpan");t>1&&(c(e,"rowSpan",t-1),i=S(e),h(i.x,i.y,1,1))}),i=S(e.cells[0]),r(R[i.y],function(e){var t;e=e.elm,e!=o&&(t=n(e,"rowSpan"),1>=t?H.remove(e):c(e,"rowSpan",t-1),o=e)})}var t;t=u(),r(t.reverse(),function(t){e(t)}),m()}function w(){var e=u();return H.remove(e),m(),e}function _(){var e=u();return r(e,function(t,n){e[n]=s(t,!0)}),e}function N(e,t){var n=u(),i=n[t?0:n.length-1],o=i.cells.length;e&&(r(R,function(e){var t;return o=0,r(e,function(e){e.real&&(o+=e.colspan),e.elm.parentNode==i&&(t=1)}),t?!1:void 0}),t||e.reverse(),r(e,function(e){var n,r=e.cells.length,a;for(n=0;r>n;n++)a=e.cells[n],c(a,"colSpan",1),c(a,"rowSpan",1);for(n=r;o>n;n++)e.appendChild(p(e.cells[r-1]));for(n=o;r>n;n++)H.remove(e.cells[n]);t?i.parentNode.insertBefore(e,i):H.insertAfter(e,i)}),H.removeClass(H.select("td.mce-item-selected,th.mce-item-selected"),"mce-item-selected"))}function S(e){var t;return r(R,function(n,i){return r(n,function(n,r){return n.elm==e?(t={x:r,y:i},!1):void 0}),!t}),t}function E(e){A=S(e)}function k(){var e,t;return e=t=0,r(R,function(n,i){r(n,function(n,r){var o,a;d(n)&&(n=R[i][r],r>e&&(e=r),i>t&&(t=i),n.real&&(o=n.colspan-1,a=n.rowspan-1,o&&r+o>e&&(e=r+o),a&&i+a>t&&(t=i+a)))})}),{x:e,y:t}}function T(e){var t,n,r,i,o,a,s,l,c,d;if(B=S(e),A&&B){for(t=Math.min(A.x,B.x),n=Math.min(A.y,B.y),r=Math.max(A.x,B.x),i=Math.max(A.y,B.y),o=r,a=i,d=n;a>=d;d++)e=R[d][t],e.real||t-(e.colspan-1)<t&&(t-=e.colspan-1);for(c=t;o>=c;c++)e=R[n][c],e.real||n-(e.rowspan-1)<n&&(n-=e.rowspan-1);for(d=n;i>=d;d++)for(c=t;r>=c;c++)e=R[d][c],e.real&&(s=e.colspan-1,l=e.rowspan-1,s&&c+s>o&&(o=c+s),l&&d+l>a&&(a=d+l));for(H.removeClass(H.select("td.mce-item-selected,th.mce-item-selected"),"mce-item-selected"),d=n;a>=d;d++)for(c=t;o>=c;c++)R[d][c]&&H.addClass(R[d][c].elm,"mce-item-selected")}}var R,A,B,P,M=i.selection,H=M.dom;o=o||H.getParent(M.getStart(),"table"),a(),P=H.getParent(M.getStart(),"th,td"),P&&(A=S(P),B=k(),P=l(A.x,A.y)),e.extend(this,{deleteTable:f,split:g,merge:v,insertRow:y,insertCol:b,deleteCols:C,deleteRows:x,cutRows:w,copyRows:_,pasteRows:N,getPos:S,setStartCell:E,setEndCell:T})}}),r(u,[f,d,c],function(e,t,n){function r(e,t){return parseInt(e.getAttribute(t)||1,10)}var i=n.each;return function(n){function o(){function t(t){function o(e,r){var i=e?"previousSibling":"nextSibling",o=n.dom.getParent(r,"tr"),s=o[i];if(s)return g(n,r,s,e),t.preventDefault(),!0;var d=n.dom.getParent(o,"table"),u=o.parentNode,f=u.nodeName.toLowerCase();if("tbody"===f||f===(e?"tfoot":"thead")){var p=a(e,d,u,"tbody");if(null!==p)return l(e,p,r)}return c(e,o,i,d)}function a(e,t,r,i){var o=n.dom.select(">"+i,t),a=o.indexOf(r);if(e&&0===a||!e&&a===o.length-1)return s(e,t);if(-1===a){var l="thead"===r.tagName.toLowerCase()?0:o.length-1;return o[l]}return o[a+(e?-1:1)]}function s(e,t){var r=e?"thead":"tfoot",i=n.dom.select(">"+r,t);return 0!==i.length?i[0]:null}function l(e,r,i){var o=d(r,e);return o&&g(n,i,o,e),t.preventDefault(),!0}function c(e,r,i,a){var s=a[i];if(s)return u(s),!0;var l=n.dom.getParent(a,"td,th");if(l)return o(e,l,t);var c=d(r,!e);return u(c),t.preventDefault(),!1}function d(e,t){var r=e&&e[t?"lastChild":"firstChild"];return r&&"BR"===r.nodeName?n.dom.getParent(r,"td,th"):r}function u(e){n.selection.setCursorLocation(e,0)}function f(){return b==e.UP||b==e.DOWN}function p(e){var t=e.selection.getNode(),n=e.dom.getParent(t,"tr");return null!==n}function m(e){for(var t=0,n=e;n.previousSibling;)n=n.previousSibling,t+=r(n,"colspan");return t}function h(e,t){var n=0,o=0;return i(e.children,function(e,i){return n+=r(e,"colspan"),o=i,n>t?!1:void 0}),o}function g(e,t,r,i){var o=m(n.dom.getParent(t,"td,th")),a=h(r,o),s=r.childNodes[a],l=d(s,i);u(l||s)}function v(e){var t=n.selection.getNode(),r=n.dom.getParent(t,"td,th"),i=n.dom.getParent(e,"td,th");return r&&r!==i&&y(r,i)}function y(e,t){return n.dom.getParent(e,"TABLE")===n.dom.getParent(t,"TABLE")}var b=t.keyCode;if(f()&&p(n)){var C=n.selection.getNode();setTimeout(function(){v(C)&&o(!t.shiftKey&&b===e.UP,C,t)},0)}}n.on("KeyDown",function(e){t(e)})}function a(){function e(e,t){var n=t.ownerDocument,r=n.createRange(),i;return r.setStartBefore(t),r.setEnd(e.endContainer,e.endOffset),i=n.createElement("body"),i.appendChild(r.cloneContents()),0===i.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi,"-").replace(/<[^>]+>/g,"").length}n.on("KeyDown",function(t){var r,i,o=n.dom;(37==t.keyCode||38==t.keyCode)&&(r=n.selection.getRng(),i=o.getParent(r.startContainer,"table"),i&&n.getBody().firstChild==i&&e(r,i)&&(r=o.createRng(),r.setStartBefore(i),r.setEndBefore(i),n.selection.setRng(r),t.preventDefault()))})}function s(){n.on("KeyDown SetContent VisualAid",function(){var e;for(e=n.getBody().lastChild;e;e=e.previousSibling)if(3==e.nodeType){if(e.nodeValue.length>0)break}else if(1==e.nodeType&&!e.getAttribute("data-mce-bogus"))break;e&&"TABLE"==e.nodeName&&(n.settings.forced_root_block?n.dom.add(n.getBody(),n.settings.forced_root_block,null,t.ie?"&nbsp;":'<br data-mce-bogus="1" />'):n.dom.add(n.getBody(),"br",{"data-mce-bogus":"1"}))}),n.on("PreProcess",function(e){var t=e.node.lastChild;t&&("BR"==t.nodeName||1==t.childNodes.length&&("BR"==t.firstChild.nodeName||"\xa0"==t.firstChild.nodeValue))&&t.previousSibling&&"TABLE"==t.previousSibling.nodeName&&n.dom.remove(t)})}function l(){function e(e,t,n,r){var i=3,o=e.dom.getParent(t.startContainer,"TABLE"),a,s,l;return o&&(a=o.parentNode),s=t.startContainer.nodeType==i&&0===t.startOffset&&0===t.endOffset&&r&&("TR"==n.nodeName||n==a),l=("TD"==n.nodeName||"TH"==n.nodeName)&&!r,s||l}function t(){var t=n.selection.getRng(),r=n.selection.getNode(),i=n.dom.getParent(t.startContainer,"TD,TH");if(e(n,t,r,i)){i||(i=r);for(var o=i.lastChild;o.lastChild;)o=o.lastChild;t.setEnd(o,o.nodeValue.length),n.selection.setRng(t)}}n.on("KeyDown",function(){t()}),n.on("MouseDown",function(e){2!=e.button&&t()})}t.webkit&&(o(),l()),t.gecko&&(a(),s())}}),r(p,[l,m,c],function(e,t,n){return function(r){function i(){r.getBody().style.webkitUserSelect="",c&&(r.dom.removeClass(r.dom.select("td.mce-item-selected,th.mce-item-selected"),"mce-item-selected"),c=!1)}var o=r.dom,a,s,l,c=!0;return r.on("MouseDown",function(e){2!=e.button&&(i(),s=o.getParent(e.target,"td,th"),l=o.getParent(s,"table"))}),o.bind(r.getDoc(),"mouseover",function(t){var n,i,d=t.target;if(s&&(a||d!=s)&&("TD"==d.nodeName||"TH"==d.nodeName)){i=o.getParent(d,"table"),i==l&&(a||(a=new e(r,i),a.setStartCell(s),r.getBody().style.webkitUserSelect="none"),a.setEndCell(d),c=!0),n=r.selection.getSel();try{n.removeAllRanges?n.removeAllRanges():n.empty()}catch(u){}t.preventDefault()}}),r.on("MouseUp",function(){function e(e,r){var o=new t(e,e);do{if(3==e.nodeType&&0!==n.trim(e.nodeValue).length)return r?i.setStart(e,0):i.setEnd(e,e.nodeValue.length),void 0;if("BR"==e.nodeName)return r?i.setStartBefore(e):i.setEndBefore(e),void 0}while(e=r?o.next():o.prev())}var i,c=r.selection,d,u,f,p,m;if(s){if(a&&(r.getBody().style.webkitUserSelect=""),d=o.select("td.mce-item-selected,th.mce-item-selected"),d.length>0){i=o.createRng(),f=d[0],m=d[d.length-1],i.setStartBefore(f),i.setEndAfter(f),e(f,1),u=new t(f,o.getParent(d[0],"table"));do if("TD"==f.nodeName||"TH"==f.nodeName){if(!o.hasClass(f,"mce-item-selected"))break;p=f}while(f=u.next());e(p),c.setRng(i)}r.nodeChanged(),s=a=l=null}}),r.on("KeyUp",function(){i()}),{clear:i}}}),r(h,[l,u,p,c,m,d,g],function(e,t,n,r,i,o,a){function s(r){function i(e){return e?e.replace(/px$/,""):""}function a(e){return/^[0-9]+$/.test(e)&&(e+="px"),e}function s(e){l("left center right".split(" "),function(t){r.formatter.remove("align"+t,{},e)})}function c(){var e=r.dom,t,n,c;t=r.dom.getParent(r.selection.getStart(),"table"),c=!1,n={width:i(e.getStyle(t,"width")||e.getAttrib(t,"width")),height:i(e.getStyle(t,"height")||e.getAttrib(t,"height")),cellspacing:e.getAttrib(t,"cellspacing"),cellpadding:e.getAttrib(t,"cellpadding"),border:e.getAttrib(t,"border"),caption:!!e.select("caption",t)[0]},l("left center right".split(" "),function(e){r.formatter.matchNode(t,"align"+e)&&(n.align=e)}),r.windowManager.open({title:"Table properties",items:{type:"form",layout:"grid",columns:2,data:n,defaults:{type:"textbox",maxWidth:50},items:[c?{label:"Cols",name:"cols",disabled:!0}:null,c?{label:"Rows",name:"rows",disabled:!0}:null,{label:"Width",name:"width"},{label:"Height",name:"height"},{label:"Cell spacing",name:"cellspacing"},{label:"Cell padding",name:"cellpadding"},{label:"Border",name:"border"},{label:"Caption",name:"caption",type:"checkbox"},{label:"Alignment",minWidth:90,name:"align",type:"listbox",text:"None",maxWidth:null,values:[{text:"None",value:""},{text:"Left",value:"left"},{text:"Center",value:"center"},{text:"Right",value:"right"}]}]},onsubmit:function(){var n=this.toJSON(),i;r.undoManager.transact(function(){r.dom.setAttribs(t,{cellspacing:n.cellspacing,cellpadding:n.cellpadding,border:n.border}),r.dom.setStyles(t,{width:a(n.width),height:a(n.height)}),i=e.select("caption",t)[0],i&&!n.caption&&e.remove(i),!i&&n.caption&&(i=e.create("caption"),o.ie||(i.innerHTML='<br data-mce-bogus="1"/>'),t.insertBefore(i,t.firstChild)),s(t),n.align&&r.formatter.apply("align"+n.align,{},t),r.focus(),r.addVisual()})}})}function d(e,t){r.windowManager.open({title:"Merge cells",body:[{label:"Cols",name:"cols",type:"textbox",size:10},{label:"Rows",name:"rows",type:"textbox",size:10}],onsubmit:function(){var n=this.toJSON();r.undoManager.transact(function(){e.merge(t,n.cols,n.rows)})}})}function u(){var e=r.dom,t,n,o=[];o=r.dom.select("td.mce-item-selected,th.mce-item-selected"),t=r.dom.getParent(r.selection.getStart(),"td,th"),!o.length&&t&&o.push(t),t=t||o[0],n={width:i(e.getStyle(t,"width")||e.getAttrib(t,"width")),height:i(e.getStyle(t,"height")||e.getAttrib(t,"height")),scope:e.getAttrib(t,"scope")},n.type=t.nodeName.toLowerCase(),l("left center right".split(" "),function(e){r.formatter.matchNode(t,"align"+e)&&(n.align=e)}),r.windowManager.open({title:"Cell properties",items:{type:"form",data:n,layout:"grid",columns:2,defaults:{type:"textbox",maxWidth:50},items:[{label:"Width",name:"width"},{label:"Height",name:"height"},{label:"Cell type",name:"type",type:"listbox",text:"None",minWidth:90,maxWidth:null,menu:[{text:"Cell",value:"td"},{text:"Header cell",value:"th"}]},{label:"Scope",name:"scope",type:"listbox",text:"None",minWidth:90,maxWidth:null,menu:[{text:"None",value:""},{text:"Row",value:"row"},{text:"Column",value:"col"},{text:"Row group",value:"rowgroup"},{text:"Column group",value:"colgroup"}]},{label:"Alignment",name:"align",type:"listbox",text:"None",minWidth:90,maxWidth:null,values:[{text:"None",value:""},{text:"Left",value:"left"},{text:"Center",value:"center"},{text:"Right",value:"right"}]}]},onsubmit:function(){var t=this.toJSON();r.undoManager.transact(function(){l(o,function(n){r.dom.setAttrib(n,"scope",t.scope),r.dom.setStyles(n,{width:a(t.width),height:a(t.height)}),t.type&&n.nodeName.toLowerCase()!=t.type&&(n=e.rename(n,t.type)),s(n),t.align&&r.formatter.apply("align"+t.align,{},n)}),r.focus()})}})}function f(){var e=r.dom,t,n,o,c,d=[];t=r.dom.getParent(r.selection.getStart(),"table"),n=r.dom.getParent(r.selection.getStart(),"td,th"),l(t.rows,function(t){l(t.cells,function(r){return e.hasClass(r,"mce-item-selected")||r==n?(d.push(t),!1):void 0})}),o=d[0],c={height:i(e.getStyle(o,"height")||e.getAttrib(o,"height")),scope:e.getAttrib(o,"scope")},c.type=o.parentNode.nodeName.toLowerCase(),l("left center right".split(" "),function(e){r.formatter.matchNode(o,"align"+e)&&(c.align=e)}),r.windowManager.open({title:"Row properties",items:{type:"form",data:c,columns:2,defaults:{type:"textbox"},items:[{type:"listbox",name:"type",label:"Row type",text:"None",maxWidth:null,menu:[{text:"Header",value:"thead"},{text:"Body",value:"tbody"},{text:"Footer",value:"tfoot"}]},{type:"listbox",name:"align",label:"Alignment",text:"None",maxWidth:null,menu:[{text:"None",value:""},{text:"Left",value:"left"},{text:"Center",value:"center"},{text:"Right",value:"right"}]},{label:"Height",name:"height"}]},onsubmit:function(){var t=this.toJSON(),n,i,o;r.undoManager.transact(function(){var c=t.type;l(d,function(l){r.dom.setAttrib(l,"scope",t.scope),r.dom.setStyles(l,{height:a(t.height)}),c!=l.parentNode.nodeName.toLowerCase()&&(n=e.getParent(l,"table"),i=l.parentNode,o=e.select(c,n)[0],o||(o=e.create(c),n.firstChild?n.insertBefore(o,n.firstChild):n.appendChild(o)),o.appendChild(l),i.hasChildNodes()||e.remove(i)),s(l),t.align&&r.formatter.apply("align"+t.align,{},l)}),r.focus()})}})}function p(e){return function(){r.execCommand(e)}}function m(e,t){var n,i,a;for(a="<table><tbody>",n=0;t>n;n++){for(a+="<tr>",i=0;e>i;i++)a+="<td>"+(o.ie?" ":"<br>")+"</td>";a+="</tr>"}a+="</tbody></table>",r.insertContent(a)}function h(e,t){function n(){e.disabled(!r.dom.getParent(r.selection.getStart(),t)),r.selection.selectorChanged(t,function(t){e.disabled(!t)})}r.initialized?n():r.on("init",n)}function g(){h(this,"table")}function v(){h(this,"td,th")}function y(){var e="";e='<table role="presentation" class="mce-grid mce-grid-border">';for(var t=0;10>t;t++){e+="<tr>";for(var n=0;10>n;n++)e+='<td><a href="#" data-mce-index="'+n+","+t+'"></a></td>';e+="</tr>"}return e+="</table>",e+='<div class="mce-text-center">0 x 0</div>'}var b,C,x=this;r.addMenuItem("inserttable",{text:"Insert table",icon:"table",context:"table",onhide:function(){r.dom.removeClass(this.menu.items()[0].getEl().getElementsByTagName("a"),"mce-active")},menu:[{type:"container",html:y(),onmousemove:function(e){var t=e.target;if("A"==t.nodeName){var n=r.dom.getParent(t,"table"),i=t.getAttribute("data-mce-index");if(i!=this.lastPos){i=i.split(","),i[0]=parseInt(i[0],10),i[1]=parseInt(i[1],10);for(var o=0;10>o;o++)for(var a=0;10>a;a++)r.dom.toggleClass(n.rows[o].childNodes[a].firstChild,"mce-active",a<=i[0]&&o<=i[1]);n.nextSibling.innerHTML=i[0]+1+" x "+(i[1]+1),this.lastPos=i}}},onclick:function(e){"A"==e.target.nodeName&&this.lastPos&&(e.preventDefault(),m(this.lastPos[0]+1,this.lastPos[1]+1),this.parent().cancel())}}]}),r.addMenuItem("tableprops",{text:"Table properties",context:"table",onPostRender:g,onclick:c}),r.addMenuItem("deletetable",{text:"Delete table",context:"table",onPostRender:g,cmd:"mceTableDelete"}),r.addMenuItem("cell",{separator:"before",text:"Cell",context:"table",menu:[{text:"Cell properties",onclick:p("mceTableCellProps"),onPostRender:v},{text:"Merge cells",onclick:p("mceTableMergeCells"),onPostRender:v},{text:"Split cell",onclick:p("mceTableSplitCells"),onPostRender:v}]}),r.addMenuItem("row",{text:"Row",context:"table",menu:[{text:"Insert row before",onclick:p("mceTableInsertRowBefore"),onPostRender:v},{text:"Insert row after",onclick:p("mceTableInsertRowAfter"),onPostRender:v},{text:"Delete row",onclick:p("mceTableDeleteRow"),onPostRender:v},{text:"Row properties",onclick:p("mceTableRowProps"),onPostRender:v},{text:"-"},{text:"Cut row",onclick:p("mceTableCutRow"),onPostRender:v},{text:"Copy row",onclick:p("mceTableCopyRow"),onPostRender:v},{text:"Paste row before",onclick:p("mceTablePasteRowBefore"),onPostRender:v},{text:"Paste row after",onclick:p("mceTablePasteRowAfter"),onPostRender:v}]}),r.addMenuItem("column",{text:"Column",context:"table",menu:[{text:"Insert column before",onclick:p("mceTableInsertColBefore"),onPostRender:v},{text:"Insert column after",onclick:p("mceTableInsertColAfter"),onPostRender:v},{text:"Delete column",onclick:p("mceTableDeleteCol"),onPostRender:v}]});var w=[];l("inserttable tableprops deletetable | cell row column".split(" "),function(e){"|"==e?w.push({text:"-"}):w.push(r.menuItems[e])}),r.addButton("table",{type:"menubutton",title:"Table",menu:w}),o.isIE||r.on("click",function(e){e=e.target,"TABLE"===e.nodeName&&(r.selection.select(e),r.nodeChanged())}),x.quirks=new t(r),r.on("Init",function(){b=r.windowManager,x.cellSelection=new n(r)}),l({mceTableSplitCells:function(e){e.split()},mceTableMergeCells:function(e){var t,n,i;i=r.dom.getParent(r.selection.getStart(),"th,td"),i&&(t=i.rowSpan,n=i.colSpan),r.dom.select("td.mce-item-selected,th.mce-item-selected").length?e.merge():d(e,i)},mceTableInsertRowBefore:function(e){e.insertRow(!0)},mceTableInsertRowAfter:function(e){e.insertRow()},mceTableInsertColBefore:function(e){e.insertCol(!0)},mceTableInsertColAfter:function(e){e.insertCol()},mceTableDeleteCol:function(e){e.deleteCols()},mceTableDeleteRow:function(e){e.deleteRows()},mceTableCutRow:function(e){C=e.cutRows()},mceTableCopyRow:function(e){C=e.copyRows()},mceTablePasteRowBefore:function(e){e.pasteRows(C,!0)},mceTablePasteRowAfter:function(e){e.pasteRows(C)},mceTableDelete:function(e){e.deleteTable()}},function(t,n){r.addCommand(n,function(){var n=new e(r);n&&(t(n),r.execCommand("mceRepaint"),x.cellSelection.clear())})}),l({mceInsertTable:function(){c()},mceTableRowProps:f,mceTableCellProps:u},function(e,t){r.addCommand(t,function(t,n){e(n)})})}var l=r.each;a.add("table",s)}),a([l,u,p,h])}(this); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/template/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/template/plugin.min.js
new file mode 100755
index 0000000..eacf712
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/template/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("template",function(e){function t(){function t(e){var t=e.control.value();t.url?tinymce.util.XHR.send({url:t.url,success:function(e){i=e,n.find("iframe")[0].html(e)}}):(i=t.content,n.find("iframe")[0].html(t.content)),n.find("#description")[0].text(e.control.value().description)}var n,i,o=[];return e.settings.templates?(tinymce.each(e.settings.templates,function(e){o.push({selected:!o.length,text:e.title,value:{url:e.url,content:e.content,description:e.description}})}),n=e.windowManager.open({title:"Insert template",body:[{type:"container",label:"Templates",items:{type:"listbox",name:"template",values:o,onselect:t}},{type:"label",name:"description",label:"Description",text:" "},{type:"iframe",minWidth:600,minHeight:400,border:1}],onsubmit:function(){a(!1,i)}}),n.find("listbox")[0].fire("select"),void 0):(e.windowManager.alert("No templates defined"),void 0)}function n(t,n){function i(e,t){if(e=""+e,e.length<t)for(var n=0;n<t-e.length;n++)e="0"+e;return e}var a="Sun Mon Tue Wed Thu Fri Sat Sun".split(" "),o="Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" "),r="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),l="January February March April May June July August September October November December".split(" ");return n=n||new Date,t=t.replace("%D","%m/%d/%Y"),t=t.replace("%r","%I:%M:%S %p"),t=t.replace("%Y",""+n.getFullYear()),t=t.replace("%y",""+n.getYear()),t=t.replace("%m",i(n.getMonth()+1,2)),t=t.replace("%d",i(n.getDate(),2)),t=t.replace("%H",""+i(n.getHours(),2)),t=t.replace("%M",""+i(n.getMinutes(),2)),t=t.replace("%S",""+i(n.getSeconds(),2)),t=t.replace("%I",""+((n.getHours()+11)%12+1)),t=t.replace("%p",""+(n.getHours()<12?"AM":"PM")),t=t.replace("%B",""+e.translate(l[n.getMonth()])),t=t.replace("%b",""+e.translate(r[n.getMonth()])),t=t.replace("%A",""+e.translate(o[n.getDay()])),t=t.replace("%a",""+e.translate(a[n.getDay()])),t=t.replace("%%","%")}function i(t){var n=e.dom,i=e.getParam("template_replace_values");o(n.select("*",t),function(e){o(i,function(t,a){n.hasClass(e,a)&&"function"==typeof i[a]&&i[a](e)})})}function a(t,a){function r(e,t){return new RegExp("\\b"+t+"\\b","g").test(e.className)}var l,c,s=e.dom,u=e.selection.getContent();o(e.getParam("template_replace_values"),function(e,t){"function"!=typeof e&&(a=a.replace(new RegExp("\\{\\$"+t+"\\}","g"),e))}),l=s.create("div",null,a),c=s.select(".mceTmpl",l),c&&c.length>0&&(l=s.create("div",null),l.appendChild(c[0].cloneNode(!0))),o(s.select("*",l),function(t){r(t,e.getParam("template_cdate_classes","cdate").replace(/\s+/g,"|"))&&(t.innerHTML=n(e.getParam("template_cdate_format",e.getLang("template.cdate_format")))),r(t,e.getParam("template_mdate_classes","mdate").replace(/\s+/g,"|"))&&(t.innerHTML=n(e.getParam("template_mdate_format",e.getLang("template.mdate_format")))),r(t,e.getParam("template_selected_content_classes","selcontent").replace(/\s+/g,"|"))&&(t.innerHTML=u)}),i(l),e.execCommand("mceInsertContent",!1,l.innerHTML),e.addVisual()}var o=tinymce.each;e.addCommand("mceInsertTemplate",a),e.addButton("template",{title:"Insert template",onclick:t}),e.addMenuItem("template",{text:"Insert template",onclick:t,context:"insert"}),e.on("PreProcess",function(t){var a=e.dom;o(a.select("div",t.node),function(t){a.hasClass(t,"mceTmpl")&&(o(a.select("*",t),function(t){a.hasClass(t,e.getParam("template_mdate_classes","mdate").replace(/\s+/g,"|"))&&(t.innerHTML=n(e.getParam("template_mdate_format",e.getLang("template.mdate_format"))))}),i(t))})})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/textcolor/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/textcolor/plugin.min.js
new file mode 100755
index 0000000..9f2524f
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/textcolor/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("textcolor",function(e){function t(){var t,n,i=[];for(n=e.settings.textcolor_map||["000000","Black","993300","Burnt orange","333300","Dark olive","003300","Dark green","003366","Dark azure","000080","Navy Blue","333399","Indigo","333333","Very dark gray","800000","Maroon","FF6600","Orange","808000","Olive","008000","Green","008080","Teal","0000FF","Blue","666699","Grayish blue","808080","Gray","FF0000","Red","FF9900","Amber","99CC00","Yellow green","339966","Sea green","33CCCC","Turquoise","3366FF","Royal blue","800080","Purple","999999","Medium gray","FF00FF","Magenta","FFCC00","Gold","FFFF00","Yellow","00FF00","Lime","00FFFF","Aqua","00CCFF","Sky blue","993366","Brown","C0C0C0","Silver","FF99CC","Pink","FFCC99","Peach","FFFF99","Light yellow","CCFFCC","Pale green","CCFFFF","Pale cyan","99CCFF","Light sky blue","CC99FF","Plum","FFFFFF","White"],t=0;t<n.length;t+=2)i.push({text:n[t+1],color:n[t]});return i}function n(){var n,i,a,o,r,l,c,s,u,d=this;for(n=t(),a='<table class="mce-grid mce-grid-border mce-colorbutton-grid" role="presentation" cellspacing="0"><tbody>',o=n.length-1,r=e.settings.textcolor_rows||5,l=e.settings.textcolor_cols||8,s=0;r>s;s++){for(a+="<tr>",c=0;l>c;c++)u=s*l+c,u>o?a+="<td></td>":(i=n[u],a+='<td><div id="'+d._id+"-"+u+'"'+' data-mce-color="'+i.color+'"'+' role="option"'+' tabIndex="-1"'+' style="'+(i?"background-color: #"+i.color:"")+'"'+' title="'+i.text+'">'+"</div>"+"</td>");a+="</tr>"}return a+="</tbody></table>"}function i(t){var n,i=this.parent();(n=t.target.getAttribute("data-mce-color"))&&(i.hidePanel(),n="#"+n,i.color(n),e.execCommand(i.settings.selectcmd,!1,n))}function a(){var t=this;t._color&&e.execCommand(t.settings.selectcmd,!1,t._color)}e.addButton("forecolor",{type:"colorbutton",tooltip:"Text color",popoverAlign:"bc-tl",selectcmd:"ForeColor",panel:{html:n,onclick:i},onclick:a}),e.addButton("backcolor",{type:"colorbutton",tooltip:"Background color",popoverAlign:"bc-tl",selectcmd:"HiliteColor",panel:{html:n,onclick:i},onclick:a})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/visualblocks/css/visualblocks.css b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/visualblocks/css/visualblocks.css
new file mode 100755
index 0000000..30fa34e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/visualblocks/css/visualblocks.css
@@ -0,0 +1,136 @@
+.mce-visualblocks p {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin-left: 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7);
+}
+
+.mce-visualblocks h1 {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin-left: 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==);
+}
+
+.mce-visualblocks h2 {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin-left: 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==);
+}
+
+.mce-visualblocks h3 {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin-left: 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7);
+}
+
+.mce-visualblocks h4 {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin-left: 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==);
+}
+
+.mce-visualblocks h5 {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin-left: 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==);
+}
+
+.mce-visualblocks h6 {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin-left: 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==);
+}
+
+.mce-visualblocks div {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin-left: 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7);
+}
+
+.mce-visualblocks section {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin: 0 0 1em 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=);
+}
+
+.mce-visualblocks article {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin: 0 0 1em 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7);
+}
+
+.mce-visualblocks blockquote {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7);
+}
+
+.mce-visualblocks address {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin: 0 0 1em 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=);
+}
+
+.mce-visualblocks pre {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin-left: 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==);
+}
+
+.mce-visualblocks figure {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin: 0 0 1em 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7);
+}
+
+.mce-visualblocks hgroup {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin: 0 0 1em 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7);
+}
+
+.mce-visualblocks aside {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin: 0 0 1em 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=);
+}
+
+.mce-visualblocks figcaption {
+ border: 1px dashed #BBB;
+}
+
+.mce-visualblocks ul {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin-left: 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAPcAAAAAALu7uwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAAOAAoAAAgsAP8JHEhwYICCCAUe/LewIUGHDBUmhLiwIMWEDCsG2CgR40OPHxVyFLkxQEAAOw==);
+}
+
+.mce-visualblocks ol {
+ padding-top: 10px;
+ border: 1px dashed #BBB;
+ margin-left: 3px;
+ background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAPcAALu7u////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAADgAKAAAILQADCBxIcCCAgggFHlS4MEBDhwojQkS4sGJCixMpNgTAUWJCgg8/ZuS4kSSAgAA7);
+}
+
+.mce-visualblocks br {
+ content:"";
+ padding-left:6px;
+ background: transparent bottom right no-repeat url(data:image/gif;base64,R0lGODlhBgAIAPcAAAAAALu7uwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAAGAAgAAAgYAP8FGDjwn0GDAQ4iVCiQYUKFDw9GPBgQADs=);
+}
+
+.mce-visualblocks br:after { content:"\A"; white-space:pre; }
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/visualblocks/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/visualblocks/plugin.min.js
new file mode 100755
index 0000000..cafa418
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/visualblocks/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("visualblocks",function(e,t){function n(){var t=this;t.active(r),e.on("VisualBlocks",function(){t.active(e.dom.hasClass(e.getBody(),"mce-visualblocks"))})}var i,a,r;window.NodeList&&(e.addCommand("mceVisualBlocks",function(){var n,o=e.dom;i||(i=o.uniqueId(),n=o.create("link",{id:i,rel:"stylesheet",href:t+"/css/visualblocks.css"}),e.getDoc().getElementsByTagName("head")[0].appendChild(n)),e.on("PreviewFormats AfterPreviewFormats",function(t){r&&o.toggleClass(e.getBody(),"mce-visualblocks","afterpreviewformats"==t.type)}),o.toggleClass(e.getBody(),"mce-visualblocks"),r=e.dom.hasClass(e.getBody(),"mce-visualblocks"),a&&a.active(o.hasClass(e.getBody(),"mce-visualblocks")),e.fire("VisualBlocks")}),e.addButton("visualblocks",{title:"Show blocks",cmd:"mceVisualBlocks",onPostRender:n}),e.addMenuItem("visualblocks",{text:"Show blocks",cmd:"mceVisualBlocks",onPostRender:n,selectable:!0,context:"view",prependToContext:!0}),e.on("init",function(){e.settings.visualblocks_default_state&&e.execCommand("mceVisualBlocks",!1,null,{skip_focus:!0})}),e.on("remove",function(){e.dom.removeClass(e.getBody(),"mce-visualblocks")}))}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/visualchars/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/visualchars/plugin.min.js
new file mode 100755
index 0000000..4474238
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/visualchars/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("visualchars",function(e){function t(t){var n,a,r,o,l,s,c=e.getBody(),d=e.selection;if(i=!i,e.fire("VisualChars",{state:i}),t&&(s=d.getBookmark()),i)for(a=[],tinymce.walk(c,function(e){3==e.nodeType&&e.nodeValue&&-1!=e.nodeValue.indexOf(" ")&&a.push(e)},"childNodes"),r=0;r<a.length;r++){for(o=a[r].nodeValue,o=o.replace(/(\u00a0)/g,'<span data-mce-bogus="1" class="mce-nbsp">$1</span>'),l=e.dom.create("div",null,o);n=l.lastChild;)e.dom.insertAfter(n,a[r]);e.dom.remove(a[r])}else for(a=e.dom.select("span.mce-nbsp",c),r=a.length-1;r>=0;r--)e.dom.remove(a[r],1);d.moveToBookmark(s)}function n(){var t=this;e.on("VisualChars",function(e){t.active(e.state)})}var i;e.addCommand("mceVisualChars",t),e.addButton("visualchars",{title:"Show invisible characters",cmd:"mceVisualChars",onPostRender:n}),e.addMenuItem("visualchars",{text:"Show invisible characters",cmd:"mceVisualChars",onPostRender:n,selectable:!0,context:"view",prependToContext:!0}),e.on("beforegetcontent",function(e){i&&"raw"!=e.format&&!e.draft&&(i=!0,t(!1))})}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/wordcount/plugin.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/wordcount/plugin.min.js
new file mode 100755
index 0000000..8c41980
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/plugins/wordcount/plugin.min.js
@@ -0,0 +1 @@
+tinymce.PluginManager.add("wordcount",function(e){function t(){e.theme.panel.find("#wordcount").text(["Words: {0}",a.getCount()])}var n,i,a=this;n=e.getParam("wordcount_countregex",/[\w\u2019\x27\-]+/g),i=e.getParam("wordcount_cleanregex",/[0-9.(),;:!?%#$?\x27\x22_+=\\\/\-]*/g),e.on("init",function(){var n=e.theme.panel&&e.theme.panel.find("#statusbar")[0];n&&window.setTimeout(function(){n.insert({type:"label",name:"wordcount",text:["Words: {0}",a.getCount()],classes:"wordcount"},0),e.on("setcontent beforeaddundo",t),e.on("keyup",function(e){32==e.keyCode&&t()})},0)}),a.getCount=function(){var t=e.getContent({format:"raw"}),a=0;if(t){t=t.replace(/\.\.\./g," "),t=t.replace(/<.[^<>]*?>/g," ").replace(/&nbsp;|&#160;/gi," "),t=t.replace(/(\w+)(&.+?;)+(\w+)/,"$1$3").replace(/&.+?;/g," "),t=t.replace(i,"");var o=t.match(n);o&&(a=o.length)}return a}}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/content.inline.min.css b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/content.inline.min.css
new file mode 100755
index 0000000..771b83e
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/content.inline.min.css
@@ -0,0 +1 @@
+.mce-object{border:1px dotted #3a3a3a;background:#d5d5d5 url(img/object.gif) no-repeat center}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px!important;height:9px!important;border:1px dotted #3a3a3a;background:#d5d5d5 url(img/anchor.gif) no-repeat center}.mce-nbsp{background:#AAA}hr{cursor:default}.mce-match-marker{background:green;color:#fff}.mce-spellchecker-word{background:url(img/wline.gif) repeat-x bottom left;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td.mce-item-selected,th.mce-item-selected{background-color:#39f!important}.mce-edit-focus{outline:1px dotted #333} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/content.min.css b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/content.min.css
new file mode 100755
index 0000000..b9bbab1
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/content.min.css
@@ -0,0 +1 @@
+body{background-color:#fff;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px;scrollbar-3dlight-color:#f0f0ee;scrollbar-arrow-color:#676662;scrollbar-base-color:#f0f0ee;scrollbar-darkshadow-color:#ddd;scrollbar-face-color:#e0e0dd;scrollbar-highlight-color:#f0f0ee;scrollbar-shadow-color:#f0f0ee;scrollbar-track-color:#f5f5f5}td,th{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px}.mce-object{border:1px dotted #3a3a3a;background:#d5d5d5 url(img/object.gif) no-repeat center}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px!important;height:9px!important;border:1px dotted #3a3a3a;background:#d5d5d5 url(img/anchor.gif) no-repeat center}.mce-nbsp{background:#AAA}hr{cursor:default}.mce-match-marker{background:green;color:#fff}.mce-spellchecker-word{background:url(img/wline.gif) repeat-x bottom left;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td.mce-item-selected,th.mce-item-selected{background-color:#39f!important}.mce-edit-focus{outline:1px dotted #333} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.eot b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.eot
new file mode 100755
index 0000000..43a30f9
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.eot
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.svg b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.svg
new file mode 100755
index 0000000..d338114
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.svg
@@ -0,0 +1,175 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>
+This is a custom SVG font generated by IcoMoon.
+<iconset grid="16"></iconset>
+</metadata>
+<defs>
+<font id="icomoon-small" horiz-adv-x="512" >
+<font-face units-per-em="512" ascent="480" descent="-32" />
+<missing-glyph horiz-adv-x="512" />
+<glyph class="hidden" unicode="&#xf000;" d="M0,480L 512 -32L0 -32 z" horiz-adv-x="0" />
+<glyph unicode="&#xe020;" d="M 352,64l0,18.502 c 75.674,30.814, 128,96.91, 128,173.498c0,106.039-100.288,192-224,192S 32,362.039, 32,256
+ c0-76.588, 52.327-142.684, 128-173.498L 160,64 L 64,64 l-32,48l0-112 l 160,0 L 192,111.406 c-50.45,25.681-85.333,80.77-85.333,144.594
+ c0,88.366, 66.859,160, 149.333,160c 82.474,0, 149.333-71.634, 149.333-160c0-63.824-34.883-118.913-85.333-144.594L 320,0 l 160,0 L 480,112 l-32-48
+ L 352,64 z" />
+<glyph unicode="&#xe013;" d="M 128,448l0-448 l 128,128l 128-128L 384,448 L 128,448 z M 352,85.255l-96,96l-96-96L 160,416 l 192,0 L 352,85.255 z" />
+<glyph unicode="&#xe012;" d="M 463.637,364.892l-66.745,66.744C 386.34,442.188, 372.276,448, 357.293,448s-29.047-5.812-39.598-16.363l-82.746-82.745
+ c-21.834-21.834-21.834-57.362,0-79.196l 1.373-1.373l 33.941,33.941l-1.373,1.373c-3.066,3.066-3.066,8.247,0,11.313l 82.746,82.746
+ C 353.641,399.7, 356.040,400, 357.292,400s 3.651-0.299, 5.656-2.305l 66.745-66.744c 3.066-3.067, 3.066-8.249, 0.001-11.314l-82.747-82.747
+ c-2.004-2.004-4.403-2.304-5.655-2.304s-3.651,0.3-5.656,2.306l-1.373,1.373l-33.94-33.942l 1.371-1.371
+ c 10.553-10.554, 24.615-16.364, 39.6-16.364s 29.047,5.812, 39.598,16.363l 82.747,82.746C 485.47,307.53, 485.47,343.057, 463.637,364.892
+ zM 275.678,179.678l-33.941-33.941l 1.373-1.373c 2.004-2.004, 2.305-4.403, 2.305-5.655c0-1.253-0.299-3.651-2.303-5.657
+ l-82.747-82.745c-2.005-2.005-4.405-2.305-5.657-2.305s-3.652,0.3-5.657,2.305L 82.305,117.050C 80.3,119.055, 80,121.455, 80,122.707
+ s 0.299,3.65, 2.305,5.656l 82.745,82.744c 2.005,2.006, 4.405,2.306, 5.657,2.306s 3.652-0.3, 5.657-2.306l 1.373-1.371l 33.941,33.94
+ l-1.373,1.373c-10.552,10.552-24.615,16.363-39.598,16.363s-29.046-5.812-39.598-16.363l-82.744-82.743
+ C 37.812,151.754, 32,137.689, 32,122.707s 5.812-29.047, 16.363-39.599l 66.745-66.745C 125.661,5.812, 139.724,0, 154.707,0
+ s 29.046,5.812, 39.598,16.363l 82.747,82.746c 10.552,10.552, 16.361,24.615, 16.361,39.598s-5.812,29.047-16.363,39.598
+ L 275.678,179.678zM 400,61c-4.862,0-9.725,1.854-13.435,5.565l-64,63.999c-7.422,7.42-7.422,19.449,0,26.869
+ c 7.42,7.422, 19.448,7.422, 26.868,0l 64-64c 7.422-7.42, 7.422-19.448,0-26.868C 409.725,62.854, 404.862,61, 400,61zM 304,0c-8.837,0-16,7.163-16,16l0,64 c0,8.837, 7.163,16, 16,16s 16-7.163, 16-16l0-64 C 320,7.163, 312.837,0, 304,0zM 464,160l-64,0 c-8.837,0-16,7.163-16,16s 7.163,16, 16,16l 64,0 c 8.837,0, 16-7.163, 16-16S 472.837,160, 464,160zM 112,387c 4.862,0, 9.725-1.854, 13.435-5.565l 64-64c 7.421-7.42, 7.421-19.449,0-26.869c-7.42-7.422-19.449-7.422-26.869,0
+ l-64,64c-7.421,7.42-7.421,19.449,0,26.869C 102.275,385.146, 107.138,387, 112,387zM 208,448c 8.837,0, 16-7.163, 16-16l0-64 c0-8.837-7.163-16-16-16s-16,7.163-16,16L 192,432 C 192,440.837, 199.163,448, 208,448zM 48,288l 64,0 c 8.837,0, 16-7.163, 16-16s-7.163-16-16-16L 48,256 c-8.837,0-16,7.163-16,16S 39.163,288, 48,288z" />
+<glyph unicode="&#xe011;" d="M 463.637,364.892l-66.745,66.744C 386.34,442.188, 372.276,448, 357.293,448s-29.047-5.812-39.598-16.363l-82.746-82.745
+ c-21.834-21.834-21.834-57.362,0-79.196l 1.373-1.373l 33.941,33.941l-1.373,1.373c-3.066,3.066-3.066,8.247,0,11.313l 82.746,82.746
+ C 353.641,399.7, 356.040,400, 357.292,400s 3.651-0.299, 5.656-2.305l 66.745-66.744c 3.066-3.067, 3.066-8.249, 0.001-11.314l-82.747-82.747
+ c-2.004-2.004-4.403-2.304-5.655-2.304s-3.651,0.3-5.656,2.306l-1.373,1.373l-33.94-33.942l 1.371-1.371
+ c 10.553-10.554, 24.615-16.364, 39.6-16.364s 29.047,5.812, 39.598,16.363l 82.747,82.746C 485.47,307.53, 485.47,343.057, 463.637,364.892
+ zM 275.678,179.678l-33.941-33.941l 1.373-1.373c 2.004-2.004, 2.305-4.403, 2.305-5.655c0-1.253-0.299-3.651-2.303-5.657
+ l-82.747-82.745c-2.005-2.005-4.405-2.305-5.657-2.305s-3.652,0.3-5.657,2.305L 82.305,117.050C 80.3,119.055, 80,121.455, 80,122.707
+ s 0.299,3.65, 2.305,5.656l 82.745,82.744c 2.005,2.006, 4.405,2.306, 5.657,2.306s 3.652-0.3, 5.657-2.306l 1.373-1.371l 33.941,33.94
+ l-1.373,1.373c-10.552,10.552-24.615,16.363-39.598,16.363s-29.046-5.812-39.598-16.363l-82.744-82.743
+ C 37.812,151.754, 32,137.689, 32,122.707s 5.812-29.047, 16.363-39.599l 66.745-66.745C 125.661,5.812, 139.724,0, 154.707,0
+ s 29.046,5.812, 39.598,16.363l 82.747,82.746c 10.552,10.552, 16.361,24.615, 16.361,39.598s-5.812,29.047-16.363,39.598
+ L 275.678,179.678zM 176,125c-4.862,0-9.725,1.855-13.435,5.564c-7.42,7.42-7.42,19.449,0,26.869l 160,160c 7.42,7.42, 19.448,7.42, 26.868,0
+ c 7.422-7.42, 7.422-19.45,0-26.87l-160-160C 185.725,126.855, 180.862,125, 176,125z" />
+<glyph unicode="&#xe010;" d="M 288,339.337L 288,448 l 168.001-168L 288,112L 288,223.048 C 92.547,227.633, 130.5,99.5, 160,0C 16,160, 53.954,345.437, 288,339.337z" />
+<glyph unicode="&#xe00f;" d="M 352,0c 29.5,99.5, 67.453,227.633-128,223.048L 224,112 L 55.999,280L 224,448l0-108.663 C 458.046,345.437, 496,160, 352,0z" />
+<glyph unicode="&#xe00e;" d="M 128.214,267.637c 52.9,0, 95.786-45.585, 95.786-101.819C 224,109.586, 181.114,64, 128.214,64
+ c-52.901,0-95.786,45.585-95.786,101.818L 32,180.364C 32,292.829, 117.77,384, 223.572,384l0-58.182 c-36.55,0-70.913-15.13-96.758-42.602
+ c-4.977-5.289-9.517-10.917-13.612-16.828C 118.094,267.208, 123.105,267.637, 128.214,267.637zM 384.214,267.637c 52.9,0, 95.786-45.585, 95.786-101.819C 480,109.586, 437.114,64, 384.214,64
+ c-52.901,0-95.786,45.585-95.786,101.818L 288,180.364C 288,292.829, 373.77,384, 479.572,384l0-58.182 c-36.55,0-70.913-15.13-96.758-42.602
+ c-4.978-5.289-9.518-10.917-13.612-16.828C 374.094,267.208, 379.105,267.637, 384.214,267.637z" />
+<glyph unicode="&#xe00c;" d="M 32,384L 480,384L 480,320L 32,320zM 192,192L 480,192L 480,128L 192,128zM 192,288L 480,288L 480,224L 192,224zM 32,96L 480,96L 480,32L 32,32zM 32,288L 144,208L 32,128 z" />
+<glyph unicode="&#xe00d;" d="M 32,384L 480,384L 480,320L 32,320zM 32,192L 320,192L 320,128L 32,128zM 32,288L 320,288L 320,224L 32,224zM 32,96L 480,96L 480,32L 32,32zM 480,288L 368,208L 480,128 z" />
+<glyph unicode="&#xe00b;" d="M 192,416L 480,416L 480,352L 192,352zM 192,256L 480,256L 480,192L 192,192zM 192,96L 480,96L 480,32L 192,32zM 160,215L 160,288L 128,288L 128,448L 64,448L 64,416L 96,416L 96,288L 64,288L 64,256L 128,256L 128,231L 64,201L 64,128L 128,128L 128,96L 64,96L 64,64L 128,64L 128,32L 64,32L 64,0L 160,0L 160,160L 96,160L 96,185 z" />
+<glyph unicode="&#xe00a;" d="M 192,416L 480,416L 480,352L 192,352zM 192,256L 480,256L 480,192L 192,192zM 192,96L 480,96L 480,32L 192,32zM 64,384A32,32 1980 1 1 128,384A32,32 1980 1 1 64,384zM 64,224A32,32 1980 1 1 128,224A32,32 1980 1 1 64,224zM 64,64A32,32 1980 1 1 128,64A32,32 1980 1 1 64,64z" />
+<glyph unicode="&#xe009;" d="M 444,288l-28,0 L 416,416 l 32,0 L 448,448 L 288,448 l0-32 l 32,0 l0-128 L 192,288 L 192,416 l 32,0 L 224,448 L 64,448 l0-32 l 32,0 l0-128 L 68,288 c-19.8,0-36-16.2-36-36l0-216 c0-19.8, 16.2-36, 36-36l 120,0
+ c 19.8,0, 36,16.2, 36,36L 224,192 l 64,0 l0-156 c0-19.8, 16.2-36, 36-36l 120,0 c 19.8,0, 36,16.2, 36,36L 480,252 C 480,271.8, 463.8,288, 444,288z M 174,32L 82,32
+ c-9.9,0-18,7.2-18,16s 8.1,16, 18,16l 92,0 c 9.9,0, 18-7.2, 18-16S 183.9,32, 174,32z M 272,224l-32,0 c-8.8,0-16,7.2-16,16s 7.2,16, 16,16l 32,0
+ c 8.8,0, 16-7.2, 16-16S 280.8,224, 272,224z M 430,32l-92,0 c-9.9,0-18,7.2-18,16s 8.1,16, 18,16l 92,0 c 9.9,0, 18-7.2, 18-16S 439.9,32, 430,32z" />
+<glyph unicode="&#xe008;" d="M 352,288l0,80 c0,8.8-7.2,16-16,16l-80,0 L 256,416 c0,17.6-14.4,32-32,32l-64,0 c-17.602,0-32-14.4-32-32l0-32 L 48,384 c-8.801,0-16-7.2-16-16l0-256
+ c0-8.8, 7.199-16, 16-16l 112,0 l0-96 l 192,0 l 96,96L 448,288 L 352,288 z M 160,415.943c 0.017,0.019, 0.036,0.039, 0.057,0.057l 63.884,0
+ c 0.021-0.018, 0.041-0.038, 0.059-0.057L 224,384 l-64,0 L 160,415.943 L 160,415.943z M 96,320l0,32 l 192,0 l0-32 L 96,320 z M 352,45.255L 352,96 l 50.745,0 L 352,45.255z
+ M 416,128l-96,0 l0-96 L 192,32 L 192,256 l 224,0 L 416,128 z" />
+<glyph unicode="&#xe031;" d="M 416,320l-96,0 l0,32 l-96,96L 32,448 l0-352 l 192,0 l0-96 l 288,0 L 512,224 L 416,320z M 416,274.745L 466.745,224L 416,224 L 416,274.745 z M 224,402.745L 274.745,352
+ L 224,352 L 224,402.745 z M 64,416l 128,0 l0-96 l 96,0 l0-192 L 64,128 L 64,416 z M 480,32L 256,32 l0,64 l 64,0 L 320,288 l 64,0 l0-96 l 96,0 L 480,32 z" />
+<glyph unicode="&#xe007;" d="M 432.204,144.934c-23.235,23.235-53.469,34.002-80.541,31.403L 320,208l 96,96c0,0, 64,64,0,128L 256,272L 96,432
+ c-64-64,0-128,0-128l 96-96l-31.663-31.663c-27.072,2.599-57.305-8.169-80.54-31.403c-37.49-37.49-42.556-93.209-11.313-124.45
+ c 31.241-31.241, 86.96-26.177, 124.45,11.313c 23.235,23.234, 34.001,53.469, 31.403,80.54L 256,144l 31.664-31.664
+ c-2.598-27.072, 8.168-57.305, 31.403-80.539c 37.489-37.49, 93.209-42.556, 124.449-11.313
+ C 474.76,51.725, 469.694,107.443, 432.204,144.934z M 176.562,100.711c-1.106-12.166-7.51-24.913-17.57-34.973
+ C 147.886,54.631, 133.452,48, 120.383,48c-5.262,0-12.649,1.114-17.958,6.424c-10.703,10.702-8.688,36.566, 11.313,56.568
+ c 11.106,11.107, 25.54,17.738, 38.609,17.738c 5.262,0, 12.649-1.114, 17.958-6.424C 176.861,115.751, 177.040,105.962, 176.562,100.711z
+ M 256,176c-17.673,0-32,14.327-32,32s 14.327,32, 32,32s 32-14.327, 32-32S 273.673,176, 256,176z M 409.576,54.424
+ c-5.31-5.31-12.696-6.424-17.958-6.424c-13.069,0-27.503,6.631-38.609,17.738c-10.061,10.060-16.464,22.807-17.569,34.973
+ c-0.479,5.251-0.3,15.040, 6.257,21.596c 5.309,5.311, 12.695,6.424, 17.958,6.424c 13.068,0, 27.503-6.631, 38.608-17.737
+ C 418.265,90.99, 420.279,65.126, 409.576,54.424z" />
+<glyph unicode="&#xe006;" d="M 32,384L 480,384L 480,320L 32,320zM 32,192L 480,192L 480,128L 32,128zM 32,288L 480,288L 480,224L 32,224zM 32,96L 480,96L 480,32L 32,32z" />
+<glyph unicode="&#xe004;" d="M 32,384L 480,384L 480,320L 32,320zM 32,192L 480,192L 480,128L 32,128zM 128,288L 384,288L 384,224L 128,224zM 128,96L 384,96L 384,32L 128,32z" />
+<glyph unicode="&#xe005;" d="M 32,384L 480,384L 480,320L 32,320zM 32,192L 480,192L 480,128L 32,128zM 192,288L 480,288L 480,224L 192,224zM 192,96L 480,96L 480,32L 192,32z" />
+<glyph unicode="&#xe003;" d="M 32,384L 480,384L 480,320L 32,320zM 32,192L 480,192L 480,128L 32,128zM 32,288L 320,288L 320,224L 32,224zM 32,96L 320,96L 320,32L 32,32z" />
+<glyph unicode="&#xe02d;" d="M 480,224l-4.571,0 L 347.062,224 c-25.039,17.71-57.215,27.43-91.062,27.43c-44.603,0-82.286,25.121-82.286,54.856
+ c0,29.735, 37.683,54.857, 82.286,54.857c 37.529,0, 70.154-17.788, 79.56-41.143l 56.508,0 c-3.965,25.322-18.79,48.984-42.029,66.413
+ C 324.599,405.493, 291.201,416, 256,416c-35.202,0-68.598-10.507-94.037-29.587c-27.394-20.545-43.106-49.751-43.106-80.127
+ s 15.712-59.582, 43.106-80.127c 0.978-0.733, 1.971-1.449, 2.973-2.158L 36.571,224.001 L 32,224.001 l0-32 l 256.266,0 c 29.104-8.553, 50.021-28.135, 50.021-50.286
+ c0-29.734-37.684-54.855-82.286-54.855c-37.53,0-70.154,17.787-79.559,41.143l-56.508,0 c 3.965-25.32, 18.791-48.984, 42.030-66.413
+ C 187.402,42.508, 220.798,32, 256,32c 35.201,0, 68.599,10.508, 94.037,29.587c 27.395,20.545, 43.104,49.751, 43.104,80.127
+ c0,17.649-5.327,34.896-15.147,50.286L 480,192 L 480,224 z" />
+<glyph unicode="&#xe02c;" d="M 96,64l 288,0 l0-32 L 96,32 L 96,64 zM 320,416l0-192 c0-15.656-7.35-30.812-20.695-42.676C 283.834,167.573, 262.771,160, 240,160c-22.772,0-43.834,7.573-59.304,21.324
+ C 167.35,193.188, 160,208.344, 160,224L 160,416 L 96,416 l0-192 c0-70.691, 64.471-128, 144-128c 79.529,0, 144,57.309, 144,128L 384,416 L 320,416 z" />
+<glyph unicode="&#xe02b;" d="M 416,416l0-32 l-72,0 L 216,64l 72,0 l0-32 L 64,32 l0,32 l 72,0 L 264,384l-72,0 L 192,416 L 416,416 z" />
+<glyph unicode="&#xe02a;" d="M 312.721,232.909C 336.758,251.984, 352,280.337, 352,312c0,57.438-50.145,104-112,104L 128,416 l0-384 l 144,0
+ c 61.856,0, 112,46.562, 112,104C 384,180.098, 354.441,217.781, 312.721,232.909z M 192,328c0,13.255, 10.745,24, 24,24l 33.602,0
+ C 270.809,352, 288,330.51, 288,304s-17.191-48-38.398-48L 192,256 L 192,328 z M 273.6,96L 216,96 c-13.255,0-24,10.745-24,24l0,72 l 81.6,0
+ c 21.209,0, 38.4-21.49, 38.4-48S 294.809,96, 273.6,96z" />
+<glyph unicode="&#xe001;" d="M 425.373,358.627l-66.746,66.745C 346.183,437.818, 321.6,448, 304,448L 96,448 c-17.6,0-32-14.4-32-32l0-384 c0-17.6, 14.4-32, 32-32l 320,0
+ c 17.6,0, 32,14.4, 32,32L 448,304 C 448,321.6, 437.817,346.182, 425.373,358.627z M 402.745,336.001c 3.396-3.398, 6.896-9.581, 9.447-16.001L 320,320
+ L 320,412.193 c 6.42-2.55, 12.602-6.050, 16-9.448L 402.745,336.001z M 415.942,32L 96.057,32 c-0.020,0.017-0.041,0.038-0.057,0.058L 96,415.943
+ c 0.017,0.020, 0.038,0.041, 0.057,0.057L 288,416 l0-128 l 128,0 l0-255.942 C 415.983,32.038, 415.962,32.017, 415.942,32z" />
+<glyph unicode="&#xe000;" d="M 480,40L 480,335.969 L 368.031,448L 72,448 c-22.091,0-40-17.908-40-40l0-368 c0-22.092, 17.909-40, 40-40l 368,0
+ C 462.092,0, 480,17.908, 480,40z M 288,384l 32,0 l0-96 l-32,0 L 288,384 z M 352,64L 160,64 L 160,191.941 c 0.017,0.021, 0.038,0.041, 0.058,0.059l 191.885,0
+ c 0.020-0.018, 0.041-0.038, 0.058-0.059L 352,64L 352,64z M 416,64l-32,0 L 384,192 c0,17.6-14.4,32-32,32L 160,224 c-17.6,0-32-14.4-32-32l0-128 L 96,64 L 96,384
+ l 32,0 l0-96 c0-17.6, 14.4-32, 32-32l 160,0 c 17.6,0, 32,14.4, 32,32l0,85.505 l 64-64.036L 416,64 z" />
+<glyph unicode="&#xe01b;" d="M 32,384l0-352 l 448,0 L 480,384 L 32,384 z M 192,160l0,64 l 128,0 l0-64 L 192,160 z M 320,128l0-64 L 192,64 l0,64 L 320,128 z M 320,320l0-64 L 192,256 l0,64 L 320,320 z M 160,320l0-64 L 64,256 l0,64 L 160,320
+ z M 64,224l 96,0 l0-64 L 64,160 L 64,224 z M 352,224l 96,0 l0-64 l-96,0 L 352,224 z M 352,256l0,64 l 96,0 l0-64 L 352,256 z M 64,128l 96,0 l0-64 L 64,64 L 64,128 z M 352,64l0,64 l 96,0 l0-64 L 352,64 z" />
+<glyph unicode="&#xe021;" d="M 256,410c 49.683,0, 96.391-19.347, 131.521-54.478S 442,273.683, 442,224s-19.348-96.391-54.479-131.521S 305.683,38, 256,38
+ s-96.391,19.348-131.522,54.479S 70,174.317, 70,224s 19.347,96.391, 54.478,131.522S 206.317,410, 256,410 M 256,448
+ C 132.288,448, 32,347.712, 32,224s 100.288-224, 224-224s 224,100.288, 224,224S 379.712,448, 256,448L 256,448zM 160,288A32,32 1980 1 1 224,288A32,32 1980 1 1 160,288zM 288,288A32,32 1980 1 1 352,288A32,32 1980 1 1 288,288zM 256,152c-50.92,0-96.28,18.437-125.583,47.164C 141.98,140.36, 193.806,96, 256,96c 62.194,0, 114.020,44.36, 125.584,103.164
+ C 352.28,170.437, 306.92,152, 256,152z" />
+<glyph unicode="&#xe023;" d="M 240,288L 144,384L 208,448L 32,448L 32,272L 96,336L 192,240 zM 320,240L 416,336L 480,272L 480,448L 304,448L 368,384L 272,288 zM 272,160L 368,64L 304,0L 480,0L 480,176L 416,112L 320,208 zM 192,208L 96,112L 32,176L 32,0L 208,0L 144,64L 240,160 z" />
+<glyph unicode="&#xe01c;" d="M 32,256L 480,256L 480,192L 32,192z" />
+<glyph unicode="&#xe01d;" d="M 32,96l 256,0 l0-64 L 32,32 L 32,96 z M 384,384L 273.721,384 l-91.883-256l-66.144,0 l 91.881,256L 96,384 L 96,448 l 288,0 L 384,384 z M 464.887,32L 400,96.887
+ L 335.113,32L 304,63.113L 368.887,128L 304,192.887L 335.113,224L 400,159.113L 464.887,224L 496,192.887L 431.113,128L 496,63.113
+ L 464.887,32z" />
+<glyph unicode="&#xe022;" d="M 128,416l 256,0 l0-64 L 128,352 L 128,416 z M 448,320L 64,320 c-17.6,0-32-14.4-32-32l0-128 c0-17.6, 14.398-32, 32-32l 64,0 l0-96 l 256,0 l0,96 l 64,0
+ c 17.6,0, 32,14.4, 32,32L 480,288 C 480,305.6, 465.6,320, 448,320z M 352,64L 160,64 L 160,192 l 192,0 L 352,64 z M 455.2,272c0-12.813-10.387-23.2-23.199-23.2
+ S 408.8,259.187, 408.8,272s 10.389,23.2, 23.201,23.2C 444.814,295.2, 455.2,284.813, 455.2,272z" />
+<glyph unicode="&#xe02e;" d="M 192,416c-61.856,0-112-50.144-112-112s 50.144-112, 112-112l0-160 l 64,0 L 256,352 l 32,0 l0-320 l 64,0 L 352,352 l 64,0 L 416,416 L 192,416 z" />
+<glyph unicode="&#xe02f;" d="M 224,416c-61.856,0-112-50.144-112-112s 50.144-112, 112-112l0-160 l 64,0 L 288,352 l 32,0 l0-320 l 64,0 L 384,352 l 64,0 L 448,416 L 224,416 zM 32,32L 144,128L 32,224 z" />
+<glyph unicode="&#xe030;" d="M 160,416C 98.144,416, 48,365.856, 48,304s 50.144-112, 112-112l0-160 l 64,0 L 224,352 l 32,0 l0-320 l 64,0 L 320,352 l 64,0 L 384,416 L 160,416 zM 480,224L 368,128L 480,32 z" />
+<glyph unicode="&#xe026;" d="M 256,288L 320,288L 320,256L 256,256zM 256,96L 320,96L 320,64L 256,64zM 288,192L 352,192L 352,160L 288,160zM 384,192L 384,96L 352,96L 352,64L 416,64L 416,192 zM 192,192L 256,192L 256,160L 192,160zM 160,96L 224,96L 224,64L 160,64zM 160,288L 224,288L 224,256L 160,256zM 96,384L 96,256L 128,256L 128,352L 160,352L 160,384 zM 352,256L 416,256L 416,384L 384,384L 384,288L 352,288 zM 32,448l0-448 l 448,0 L 480,448 L 32,448 z M 448,32L 64,32 L 64,416 l 384,0 L 448,32 zM 96,192L 96,64L 128,64L 128,160L 160,160L 160,192 zM 288,384L 352,384L 352,352L 288,352zM 192,384L 256,384L 256,352L 192,352z" />
+<glyph unicode="&#xe027;" d="M 408,448l 8-192L 96,256 l 8,192l 16,0 l 8-160l 256,0 l 8,160L 408,448 z M 104,0l-8,160l 320,0 l-8-160l-16,0 l-8,128L 128,128 l-8-128L 104,0 zM 32,224L 96,224L 96,192L 32,192zM 128,224L 192,224L 192,192L 128,192zM 224,224L 288,224L 288,192L 224,192zM 320,224L 384,224L 384,192L 320,192zM 416,224L 480,224L 480,192L 416,192z" />
+<glyph unicode="&#xe024;" d="M 480,416L 480,448 l-96,0 c-17.601,0-32-14.4-32-32l0-160 c0-7.928, 2.929-15.201, 7.748-20.807L 208,105l-71,74l-41-35l 112-144l 208,224l 64,0
+ l0,32 l-96,0 L 384,416 L 480,416 zM 128,224l 32,0 L 160,416 c0,17.6-14.4,32-32,32L 64,448 c-17.6,0-32-14.4-32-32l0-192 l 32,0 l0,96 l 64,0 L 128,224 z M 64,352L 64,416 l 64,0 l0-64 L 64,352 zM 320,256l0,48 c0,17.6-4.4,32-22,32c 17.6,0, 22,14.4, 22,32L 320,416 c0,17.6-14.4,32-32,32l-96,0 l0-224 l 96,0 C 305.6,224, 320,238.4, 320,256z
+ M 224,416l 64,0 l0-64 l-64,0 L 224,416 z M 224,320l 64,0 l0-64 l-64,0 L 224,320 z" />
+<glyph unicode="&#xe025;" d="M 224,224l-64,0 l0,64 l 64,0 l0,64 l 64,0 l0-64 l 64,0 l0-64 l-64,0 l0-64 l-64,0 L 224,224 z M 480,192l0-160 L 32,32 L 32,192 l 64,0 l0-96 l 320,0 l0,96 L 480,192 z" />
+<glyph unicode="&#xe017;" d="M 208,128L 112,224L 208,320L 176,352L 48,224L 176,96 zM 336,352L 304,320L 400,224L 304,128L 336,96L 464,224 z" />
+<glyph unicode="&#xe016;" d="M 224,128l 64,0 l0-64 l-64,0 L 224,128 z M 352,352c 17.673,0, 32-14.327, 32-32l0-83 l-114-77l-46,0 l0,32 l 96,64l0,32 L 160,288 l0,64 L 352,352 z M 256,448
+ c-59.833,0-116.083-23.3-158.392-65.608C 55.301,340.083, 32,283.833, 32,224c0-59.832, 23.301-116.084, 65.608-158.392
+ C 139.917,23.3, 196.167,0, 256,0c 59.832,0, 116.084,23.3, 158.392,65.608C 456.7,107.916, 480,164.168, 480,224
+ c0,59.833-23.3,116.083-65.608,158.392C 372.084,424.7, 315.832,448, 256,448z" />
+<glyph unicode="&#xe014;" d="M 448,416L 64,416 c-17.6,0-32-14.4-32-32l0-320 c0-17.6, 14.4-32, 32-32l 384,0 c 17.6,0, 32,14.4, 32,32L 480,384 C 480,401.6, 465.6,416, 448,416z
+ M 448,64.058c-0.006-0.007-0.015-0.014-0.021-0.021L 352,224l-80-64L 160,304L 64.016,64.042c-0.005,0.005-0.011,0.011-0.016,0.016
+ L 64,383.943 c 0.017,0.020, 0.038,0.041, 0.057,0.057l 383.885,0 c 0.020-0.017, 0.041-0.038, 0.058-0.058L 448,64.058 zM 320,304A48,48 1980 1 1 416,304A48,48 1980 1 1 320,304z" />
+<glyph unicode="&#xe015;" d="M 448,416L 64,416 c-17.6,0-32-14.4-32-32l0-320 c0-17.6, 14.4-32, 32-32l 384,0 c 17.6,0, 32,14.4, 32,32L 480,384 C 480,401.6, 465.6,416, 448,416z
+ M 128,64L 64,64 l0,64 l 64,0 L 128,64 z M 128,192L 64,192 l0,64 l 64,0 L 128,192 z M 128,320L 64,320 L 64,384 l 64,0 L 128,320 z M 352,64L 160,64 L 160,384 l 192,0 L 352,64 z M 448,64l-64,0 l0,64 l 64,0 L 448,64 z
+ M 448,192l-64,0 l0,64 l 64,0 L 448,192 z M 448,320l-64,0 L 384,384 l 64,0 L 448,320 zM 192,320L 192,128L 336,224 z" />
+<glyph unicode="&#xe018;" d="M 38.899,327.688l 40.707-25.441C 105.007,342.804, 144,373.974, 190.21,389.37l-15.183,45.547
+ C 118.153,415.968, 70.163,377.604, 38.899,327.688zM 336.973,434.917L 321.79,389.37c 46.211-15.396, 85.202-46.566, 110.604-87.124l 40.706,25.441
+ C 441.837,377.604, 393.847,415.968, 336.973,434.917zM 303.987,127.996c-2.404,0-4.846,0.545-7.143,1.693L 224,166.111L 224,272 c0,8.836, 7.164,16, 16,16s 16-7.164, 16-16l0-86.111
+ l 55.155-27.578c 7.903-3.951, 11.107-13.562, 7.155-21.466C 315.508,131.238, 309.856,127.997, 303.987,127.996zM 256,384C 149.961,384, 64,298.039, 64,192c0-106.039, 85.961-192, 192-192c 106.039,0, 192,85.961, 192,192
+ C 448,298.039, 362.039,384, 256,384z M 256,48c-79.529,0-144,64.471-144,144c0,79.529, 64.471,144, 144,144c 79.529,0, 144-64.471, 144-144
+ C 400,112.471, 335.529,48, 256,48z" />
+<glyph unicode="&#xe019;" d="M 32,252.127c 22.659,24.96, 48.581,46.18, 76.636,62.562C 153.802,341.061, 204.759,355, 256,355
+ c 51.24,0, 102.198-13.939, 147.363-40.312c 28.056-16.382, 53.978-37.602, 76.637-62.562l0,58.716
+ c-16.505,14.059-34.062,26.57-52.434,37.297C 375.063,378.796, 315.737,395, 256,395s-119.064-16.204-171.567-46.86
+ C 66.062,337.413, 48.505,324.901, 32,310.842L 32,252.127 zM 256,320c-91.598,0-172.919-50.278-224-128c 51.081-77.724, 132.402-128, 224-128c 91.598,0, 172.919,50.276, 224,128
+ C 428.919,269.722, 347.598,320, 256,320z M 256,224c0-17.673-14.327-32-32-32s-32,14.327-32,32c0,17.674, 14.327,32, 32,32
+ S 256,241.674, 256,224z M 364.033,131.669C 330.316,111.982, 293.969,102, 256,102s-74.316,9.982-108.033,29.669
+ C 122.19,146.721, 98.659,167.324, 78.91,192c 19.749,24.675, 43.28,45.279, 69.058,60.33c 6.638,3.876, 13.379,7.37, 20.213,10.491
+ C 162.925,250.95, 160,237.817, 160,224c0-53.020, 42.981-96, 96-96c 53.020,0, 96,42.98, 96,96c0,13.817-2.925,26.95-8.18,38.821
+ c 6.834-3.122, 13.575-6.615, 20.213-10.491c 25.777-15.051, 49.308-35.655, 69.058-60.33
+ C 413.342,167.324, 389.811,146.721, 364.033,131.669z" />
+<glyph unicode="&#xe01a;" d="M 325.584,338.083C 313.278,379.064, 311.146,384, 272,384l-32,0 c-39.809,0-41.332-5.076-54.209-48c0-0.001,0-0.001-0.001-0.002
+ L 113.791,96l 56.818,0 l 28.8,96l 113.183,0 l 28.8-96l 56.815,0 L 325.584,338.083z M 218.609,256l 19.2,68c 5.043,16.809, 18.19,15, 18.19,15
+ s 13.147,1.809, 18.19-15l 0.002,0 l 19.2-68L 218.609,256 z" />
+<glyph unicode="&#xe028;" d="M 288,448 C 411.712,448 512,347.712 512,224 C 512,100.288 411.712,0 288,0 L 288,48 C 335.012,48 379.209,66.307 412.451,99.549 C 445.693,132.791 464,176.988 464,224 C 464,271.011 445.693,315.209 412.451,348.451 C 379.209,381.693 335.012,400 288,400 C 240.989,400 196.791,381.693 163.549,348.451 C 137.979,322.882 121.258,290.828 114.896,256 L 208,256 L 96,128 L -16,256 L 66.285,256 C 81.815,364.551 175.154,448 288,448 ZM 384,256 L 384,192 L 256,192 L 256,352 L 320,352 L 320,256 Z" />
+<glyph unicode="&#xe002;" d="M 512,183.771l0,80.458 l-79.572,7.957c-4.093,15.021-10.044,29.274-17.605,42.49l 52.298,63.919L 410.595,435.12l-63.918-52.298
+ c-13.217,7.562-27.471,13.513-42.491,17.604L 296.229,480l-80.458,0 l-7.957-79.573c-15.021-4.093-29.274-10.043-42.49-17.604
+ L 101.405,435.12L 44.88,378.595l 52.298-63.918c-7.562-13.216-13.513-27.47-17.605-42.49L0,264.229l0-80.458 l 79.573-7.957
+ c 4.093-15.021, 10.043-29.274, 17.605-42.491L 44.88,69.405l 56.524-56.524l 63.919,52.298c 13.216-7.562, 27.47-13.514, 42.49-17.605
+ L 215.771-32l 80.458,0 l 7.957,79.572c 15.021,4.093, 29.274,10.044, 42.491,17.605l 63.918-52.298l 56.524,56.524l-52.298,63.918
+ c 7.562,13.217, 13.514,27.471, 17.605,42.49L 512,183.771z M 352,192l-64-64l-64,0 l-64,64l0,64 l 64,64l 64,0 l 64-64L 352,192 z" />
+<glyph unicode="&#xe01f;" d="M 384,377 L 384,352 L 448,352 L 448,320 L 352,320 L 352,393 L 416,423 L 416,448 L 352,448 L 352,480 L 448,480 L 448,407 ZM 338,352L 270,352L 176,258L 82,352L 14,352L 142,224L 14,96L 82,96L 176,190L 270,96L 338,96L 210,224 z" />
+<glyph unicode="&#xe01e;" d="M 384,25 L 384,0 L 448,0 L 448-32 L 352-32 L 352,41 L 416,71 L 416,96 L 352,96 L 352,128 L 448,128 L 448,55 ZM 338,352L 270,352L 176,258L 82,352L 14,352L 142,224L 14,96L 82,96L 176,190L 270,96L 338,96L 210,224 z" />
+<glyph unicode="&#xe035;" d="M 352,288l0,80 c0,8.8-7.2,16-16,16l-80,0 L 256,416 c0,17.6-14.4,32-32,32l-64,0 c-17.602,0-32-14.4-32-32l0-32 L 48,384 c-8.801,0-16-7.2-16-16
+ l0-256 c0-8.8, 7.199-16, 16-16l 112,0 l0-96 l 288,0 L 448,288 L 352,288 z M 160,415.943c 0.017,0.019, 0.036,0.039, 0.057,0.057l 63.884,0
+ c 0.021-0.018, 0.041-0.038, 0.059-0.057L 224,384 l-64,0 L 160,415.943 z M 96,320l0,32 l 192,0 l0-32 L 96,320 z M 416,32L 192,32 L 192,256 l 224,0 L 416,32 zM 224,224L 224,160L 240,160L 256,192L 288,192L 288,96L 264,96L 264,64L 344,64L 344,96L 320,96L 320,192L 352,192L 368,160L 384,160L 384,224 z" />
+<glyph unicode="&#xe032;" d="M 384,352L 416,352L 416,320L 384,320zM 320,288L 352,288L 352,256L 320,256zM 320,224L 352,224L 352,192L 320,192zM 320,160L 352,160L 352,128L 320,128zM 256,224L 288,224L 288,192L 256,192zM 256,160L 288,160L 288,128L 256,128zM 192,160L 224,160L 224,128L 192,128zM 384,288L 416,288L 416,256L 384,256zM 384,224L 416,224L 416,192L 384,192zM 384,160L 416,160L 416,128L 384,128zM 384,96L 416,96L 416,64L 384,64zM 320,96L 352,96L 352,64L 320,64zM 256,96L 288,96L 288,64L 256,64zM 192,96L 224,96L 224,64L 192,64zM 128,96L 160,96L 160,64L 128,64z" />
+<glyph unicode="&#xe034;" d="M 464,416L 256,416L 240,448L 64,448L 32,384L 480,384 zM 420.17,128L 464,128 l 16,224L 32,352 l 32-320l 178.040,0 C 189.599,50.888, 152,101.133, 152,160c0,74.991, 61.009,136, 136,136
+ c 74.99,0, 136-61.009, 136-136C 424,149.161, 422.689,138.425, 420.17,128zM 437.498,55.125l-67.248,55.346C 378.977,124.932, 384,141.878, 384,160c0,53.020-42.98,96-96,96s-96-42.98-96-96
+ s 42.98-96, 96-96c 18.122,0, 35.069,5.023, 49.529,13.75l 55.346-67.248c 11.481-13.339, 31.059-14.070, 43.503-1.626l 2.746,2.746
+ C 451.568,24.066, 450.837,43.644, 437.498,55.125z M 288,98c-34.242,0-62,27.758-62,62s 27.758,62, 62,62s 62-27.758, 62-62
+ S 322.242,98, 288,98z" />
+<glyph unicode="&#x20;" horiz-adv-x="256" />
+</font></defs></svg> \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.ttf b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.ttf
new file mode 100755
index 0000000..841c79c
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.ttf
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.woff b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.woff
new file mode 100755
index 0000000..ad14a24
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon-small.woff
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.eot b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.eot
new file mode 100755
index 0000000..eed4f81
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.eot
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.svg b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.svg
new file mode 100755
index 0000000..727f61a
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.svg
@@ -0,0 +1,153 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>
+This is a custom SVG font generated by IcoMoon.
+<iconset grid="16"></iconset>
+</metadata>
+<defs>
+<font id="icomoon" horiz-adv-x="512" >
+<font-face units-per-em="512" ascent="480" descent="-32" />
+<missing-glyph horiz-adv-x="512" />
+<glyph class="hidden" unicode="&#xf000;" d="M0,480L 512 -32L0 -32 z" horiz-adv-x="0" />
+<glyph unicode="&#xe034;" d="M 464,416L 256,416L 240,448L 64,448L 32,384L 480,384 zM 452.17,128l 37.43,0 L 512,352L0,352 l 32-320l 242.040,0 C 221.599,50.888, 184,101.133, 184,160c0,74.991, 61.009,136, 136,136
+ c 74.99,0, 136-61.009, 136-136C 456,149.161, 454.689,138.425, 452.17,128zM 501.498,23.125l-99.248,87.346C 410.977,124.931, 416,141.878, 416,160c0,53.020-42.98,96-96,96s-96-42.98-96-96
+ s 42.98-96, 96-96c 18.122,0, 35.069,5.023, 49.529,13.75l 87.346-99.248c 11.481-13.339, 31.059-14.070, 43.503-1.626l 2.746,2.746
+ C 515.568-7.934, 514.837,11.644, 501.498,23.125z M 320,98c-34.242,0-62,27.758-62,62s 27.758,62, 62,62s 62-27.758, 62-62
+ S 354.242,98, 320,98z" />
+<glyph unicode="&#xe032;" d="M 384,352L 416,352L 416,320L 384,320zM 320,288L 352,288L 352,256L 320,256zM 320,224L 352,224L 352,192L 320,192zM 320,160L 352,160L 352,128L 320,128zM 256,224L 288,224L 288,192L 256,192zM 256,160L 288,160L 288,128L 256,128zM 192,160L 224,160L 224,128L 192,128zM 384,288L 416,288L 416,256L 384,256zM 384,224L 416,224L 416,192L 384,192zM 384,160L 416,160L 416,128L 384,128zM 384,96L 416,96L 416,64L 384,64zM 320,96L 352,96L 352,64L 320,64zM 256,96L 288,96L 288,64L 256,64zM 192,96L 224,96L 224,64L 192,64zM 128,96L 160,96L 160,64L 128,64z" />
+<glyph unicode="&#xe031;" d="M 416,352l-96,0 L 320,384 L 224,480L0,480 l0-384 l 192,0 l0-128 l 320,0 L 512,256 L 416,352z M 416,306.745L 466.745,256L 416,256 L 416,306.745 z M 224,434.745L 274.745,384L 224,384
+ L 224,434.745 z M 32,448l 160,0 l0-96 l 96,0 l0-224 L 32,128 L 32,448 z M 480,0L 224,0 l0,96 l 96,0 L 320,320 l 64,0 l0-96 l 96,0 L 480,0 z" />
+<glyph unicode="&#xe030;" d="M 128,448 L 384,448 L 384,384 L 320,384 L 320,0 L 256,0 L 256,384 L 192,384 L 192,0 L 128,0 L 128,224 C 66.144,224 16,274.144 16,336 C 16,397.856 66.144,448 128,448 ZM 480,32L 352,144L 480,256 z" />
+<glyph unicode="&#xe02f;" d="M 224,448 L 480,448 L 480,384 L 416,384 L 416,0 L 352,0 L 352,384 L 288,384 L 288,0 L 224,0 L 224,224 C 162.144,224 112,274.144 112,336 C 112,397.856 162.144,448 224,448 ZM 32,256L 160,144L 32,32 z" />
+<glyph unicode="&#xe02e;" d="M 192,448 L 448,448 L 448,384 L 384,384 L 384,0 L 320,0 L 320,384 L 256,384 L 256,0 L 192,0 L 192,224 C 130.144,224 80,274.144 80,336 C 80,397.856 130.144,448 192,448 Z" />
+<glyph unicode="&#xe02d;" d="M 365.71,221.482 C 397.67,197.513 416,163.439 416,128 C 416,92.561 397.67,58.487 365.71,34.518 C 336.031,12.259 297.068,0 256,0 C 214.931,0 175.969,12.259 146.29,34.518 C 114.33,58.487 96,92.561 96,128 L 160,128 C 160,93.309 203.963,64 256,64 C 308.037,64 352,93.309 352,128 C 352,162.691 308.037,192 256,192 C 214.931,192 175.969,204.259 146.29,226.518 C 114.33,250.488 96,284.561 96,320 C 96,355.439 114.33,389.512 146.29,413.482 C 175.969,435.741 214.931,448 256,448 C 297.068,448 336.031,435.741 365.71,413.482 C 397.67,389.512 416,355.439 416,320 L 352,320 C 352,354.691 308.037,384 256,384 C 203.963,384 160,354.691 160,320 C 160,285.309 203.963,256 256,256 C 297.068,256 336.031,243.741 365.71,221.482 ZM0,224L 512,224L 512,192L0,192z" />
+<glyph unicode="&#xe02c;" d="M 352,448 L 416,448 L 416,240 C 416,160.471 344.366,96 256,96 C 167.635,96 96,160.471 96,240 L 96,448 L 160,448 L 160,240 C 160,219.917 169.119,200.648 185.677,185.747 C 204.125,169.145 229.1,160 256,160 C 282.9,160 307.875,169.145 326.323,185.747 C 342.881,200.648 352,219.917 352,240 L 352,448 ZM 96,64L 416,64L 416,0L 96,0z" />
+<glyph unicode="&#xe02b;" d="M 448,448 L 448,416 L 384,416 L 224,32 L 288,32 L 288,0 L 64,0 L 64,32 L 128,32 L 288,416 L 224,416 L 224,448 Z" />
+<glyph unicode="&#xe02a;" d="M 353.94,237.674C 372.689,259.945, 384,288.678, 384,320c0,70.58-57.421,128-128,128l-64,0 l-64,0 L 96,448 l0-448 l 32,0 l 64,0 l 96,0
+ c 70.579,0, 128,57.421, 128,128C 416,174.478, 391.101,215.248, 353.94,237.674z M 192,384l 50.75,0 c 27.984,0, 50.75-28.71, 50.75-64
+ s-22.766-64-50.75-64L 192,256 L 192,384 z M 271.5,64L 192,64 L 192,192 l 79.5,0 c 29.225,0, 53-28.71, 53-64S 300.725,64, 271.5,64z" />
+<glyph unicode="&#xe029;" d="M 192,64L 288,64L 288-32L 192-32zM 400,448 C 426.51,448 448,426.51 448,400 L 448,256 L 288,160 L 288,96 L 192,96 L 192,192 L 352,288 L 352,352 L 96,352 L 96,448 L 400,448 Z" />
+<glyph unicode="&#xe028;" d="M 288,448 C 411.712,448 512,347.712 512,224 C 512,100.288 411.712,0 288,0 L 288,48 C 335.012,48 379.209,66.307 412.451,99.549 C 445.693,132.791 464,176.988 464,224 C 464,271.011 445.693,315.209 412.451,348.451 C 379.209,381.693 335.012,400 288,400 C 240.989,400 196.791,381.693 163.549,348.451 C 137.979,322.882 121.258,290.828 114.896,256 L 208,256 L 96,128 L -16,256 L 66.285,256 C 81.815,364.551 175.154,448 288,448 ZM 384,256 L 384,192 L 256,192 L 256,352 L 320,352 L 320,256 Z" />
+<glyph unicode="&#xe027;" d="M0,224L 64,224L 64,192L0,192zM 96,224L 192,224L 192,192L 96,192zM 224,224L 288,224L 288,192L 224,192zM 320,224L 416,224L 416,192L 320,192zM 448,224L 512,224L 512,192L 448,192zM 440,480 L 448,256 L 64,256 L 72,480 L 88,480 L 96,288 L 416,288 L 424,480 ZM 72-32 L 64,160 L 448,160 L 440-32 L 424-32 L 416,128 L 96,128 L 88-32 Z" />
+<glyph unicode="&#xe026;" d="M 192,384L 256,384L 256,352L 192,352zM 288,384L 352,384L 352,352L 288,352zM 448,384 L 448,256 L 352,256 L 352,288 L 416,288 L 416,352 L 384,352 L 384,384 ZM 160,288L 224,288L 224,256L 160,256zM 256,288L 320,288L 320,256L 256,256zM 96,352 L 96,288 L 128,288 L 128,256 L 64,256 L 64,384 L 160,384 L 160,352 ZM 192,192L 256,192L 256,160L 192,160zM 288,192L 352,192L 352,160L 288,160zM 448,192 L 448,64 L 352,64 L 352,96 L 416,96 L 416,160 L 384,160 L 384,192 ZM 160,96L 224,96L 224,64L 160,64zM 256,96L 320,96L 320,64L 256,64zM 96,160 L 96,96 L 128,96 L 128,64 L 64,64 L 64,192 L 160,192 L 160,160 ZM 480,448 L 32,448 L 32,0 L 480,0 L 480,448 Z M 512,480 L 512,480 L 512-32 L 0-32 L 0,480 L 512,480 Z" />
+<glyph unicode="&#xe025;" d="M 224,192 L 128,192 L 128,256 L 224,256 L 224,352 L 288,352 L 288,256 L 384,256 L 384,192 L 288,192 L 288,96 L 224,96 ZM 512,160 L 512-32 L 0-32 L 0,160 L 64,160 L 64,32 L 448,32 L 448,160 Z" />
+<glyph unicode="&#xe024;" d="M 64,352l 64,0 l0-96 l 32,0 L 160,448 c0,17.6-14.4,32-32,32L 64,480 C 46.4,480, 32,465.6, 32,448l0-192 l 32,0 L 64,352 z M 64,448l 64,0 l0-64 L 64,384 L 64,448 z M 480,448L 480,480 l-96,0
+ c-17.601,0-32-14.4-32-32l0-160 c0-17.6, 14.399-32, 32-32l 96,0 l0,32 l-96,0 L 384,448 L 480,448 z M 320,400L 320,448 c0,17.6-14.4,32-32,32l-96,0 l0-224 l 96,0
+ c 17.6,0, 32,14.4, 32,32l0,48 c0,17.6-4.4,32-22,32C 315.6,368, 320,382.4, 320,400z M 288,288l-64,0 l0,64 l 64,0 L 288,288 z M 288,384l-64,0 L 224,448 l 64,0 L 288,384 zM 416,192 L 208-32 L 96,112 L 137,147 L 208,73 L 384,224 Z" />
+<glyph unicode="&#xe023;" d="M 512,480 L 512,288 L 442.87,357.13 L 336.87,251.13 L 283.13,304.87 L 389.13,410.87 L 320,480 ZM 122.87,410.87 L 228.87,304.87 L 175.13,251.13 L 69.13,357.13 L 0,288 L 0,480 L 192,480 ZM 442.87,90.87 L 512,160 L 512-32 L 320-32 L 389.13,37.13 L 283.13,143.13 L 336.87,196.87 ZM 228.87,143.13 L 122.87,37.13 L 192-32 L 0-32 L 0,160 L 69.13,90.87 L 175.13,196.87 Z" />
+<glyph unicode="&#xe022;" d="M 128,448L 384,448L 384,384L 128,384zM 480,352L 32,352 C 14.4,352,0,337.6,0,320l0-160 c0-17.6, 14.398-32, 32-32l 96,0 l0-128 l 256,0 L 384,128 l 96,0 c 17.6,0, 32,14.4, 32,32L 512,320
+ C 512,337.6, 497.6,352, 480,352z M 352,32L 160,32 L 160,192 l 192,0 L 352,32 z M 487.2,304c0-12.813-10.387-23.2-23.199-23.2
+ c-12.813,0-23.201,10.387-23.201,23.2s 10.388,23.2, 23.201,23.2C 476.814,327.2, 487.2,316.813, 487.2,304z" />
+<glyph unicode="&#xe021;" d="M 256,480C 114.615,480,0,365.386,0,224c0-141.385, 114.614-256, 256-256c 141.385,0, 256,114.615, 256,256
+ C 512,365.386, 397.385,480, 256,480z M 256,8c-119.293,0-216,96.706-216,216c0,119.293, 96.707,216, 216,216c 119.295,0, 216-96.707, 216-216
+ C 472,104.706, 375.295,8, 256,8z M 192,320c0-17.673-14.327-32-32-32s-32,14.327-32,32s 14.327,32, 32,32S 192,337.673, 192,320z
+ M 384,320c0-17.673-14.326-32-32-32s-32,14.327-32,32s 14.326,32, 32,32S 384,337.673, 384,320zM 256,154 C 326.537,154 387.344,182.766 415.231,215.596 C 404.795,129.986 337.087,64 256,64 C 174.941,64 107.251,130.013 96.778,215.584 C 124.671,182.761 185.471,154 256,154 Z" />
+<glyph unicode="&#xe020;" d="M 352,32 L 480,32 L 512,96 L 512-32 L 320-32 L 320,75.107 C 385.556,103.349 432,173.688 432,256 C 432,363.216 353.201,447.133 256,447.133 C 158.797,447.133 80,363.217 80,256 C 80,173.688 126.443,103.349 192,75.107 L 192-32 L 0-32 L 0,96 L 32,32 L 160,32 L 160,48.295 C 66.185,81.525 0,161.996 0,256 C 0,379.712 114.615,480 256,480 C 397.385,480 512,379.712 512,256 C 512,161.996 445.815,81.525 352,48.295 L 352,32 Z" />
+<glyph unicode="&#xe01f;" d="M 384,377 L 384,352 L 448,352 L 448,320 L 352,320 L 352,393 L 416,423 L 416,448 L 352,448 L 352,480 L 448,480 L 448,407 ZM 338,352L 270,352L 176,258L 82,352L 14,352L 142,224L 14,96L 82,96L 176,190L 270,96L 338,96L 210,224 z" />
+<glyph unicode="&#xe01e;" d="M 384,25 L 384,0 L 448,0 L 448-32 L 352-32 L 352,41 L 416,71 L 416,96 L 352,96 L 352,128 L 448,128 L 448,55 ZM 338,352L 270,352L 176,258L 82,352L 14,352L 142,224L 14,96L 82,96L 176,190L 270,96L 338,96L 210,224 z" />
+<glyph unicode="&#xe01d;" d="M0,32L 288,32L 288-32L0-32zM 96,480L 448,480L 448,416L 96,416zM 138.694,64 L 241.038,456.082 L 302.963,439.918 L 204.838,64 ZM 464.887-32 L 400,32.887 L 335.113-32 L 304-0.887 L 368.887,64 L 304,128.887 L 335.113,160 L 400,95.113 L 464.887,160 L 496,128.887 L 431.113,64 L 496-0.887 Z" />
+<glyph unicode="&#xe01c;" d="M0,256L 512,256L 512,192L0,192z" />
+<glyph unicode="&#xe01b;" d="M0,448l0-448 l 512,0 L 512,448 L0,448 z M 192,160l0,96 l 128,0 l0-96 L 192,160 z M 320,128l0-96 L 192,32 l0,96 L 320,128 z M 320,384l0-96 L 192,288 L 192,384 L 320,384 z M 160,384l0-96 L 32,288 L 32,384 L 160,384 z
+ M 32,256l 128,0 l0-96 L 32,160 L 32,256 z M 352,256l 128,0 l0-96 L 352,160 L 352,256 z M 352,288L 352,384 l 128,0 l0-96 L 352,288 z M 32,128l 128,0 l0-96 L 32,32 L 32,128 z M 352,32l0,96 l 128,0 l0-96 L 352,32 z" />
+<glyph unicode="&#xe01a;" d="M 161.009,64l 28.8,96l 132.382,0 l 28.8-96l 56.816,0 L 311.809,384L 200.191,384 l-96-320L 161.009,64 z M 237.809,320l 36.382,0 l 28.8-96l-93.982,0
+ L 237.809,320z" />
+<glyph unicode="&#xe019;" d="M 256,320C 151.316,320, 58.378,269.722,0,192c 58.378-77.723, 151.316-128, 256-128c 104.684,0, 197.622,50.277, 256,128
+ C 453.622,269.722, 360.684,320, 256,320z M 224,256c 17.673,0, 32-14.327, 32-32s-14.327-32-32-32s-32,14.327-32,32S 206.327,256, 224,256z
+ M 386.808,127.352c-19.824-10.129-40.826-17.931-62.423-23.188C 302.141,98.746, 279.134,96, 256,96
+ c-23.133,0-46.141,2.746-68.384,8.162c-21.597,5.259-42.599,13.061-62.423,23.188c-31.51,16.101-60.111,38.205-83.82,64.649
+ c 23.709,26.444, 52.31,48.55, 83.82,64.649c 16.168,8.261, 33.121,14.973, 50.541,20.020C 165.79,261.547, 160,243.451, 160,224
+ c0-53.020, 42.981-96, 96-96c 53.019,0, 96,42.98, 96,96c0,19.451-5.791,37.547-15.733,52.67c 17.419-5.048, 34.372-11.76, 50.541-20.021
+ c 31.511-16.099, 60.109-38.204, 83.819-64.649C 446.917,165.557, 418.318,143.45, 386.808,127.352z M 430.459,358.139
+ C 376.099,385.916, 317.403,400, 256,400c-61.403,0-120.099-14.084-174.459-41.861C 52.155,343.123, 24.675,324.187,0,302.101l0-54.603
+ c 27.669,29.283, 60.347,53.877, 96.097,72.145C 145.907,345.095, 199.706,358, 256,358s 110.093-12.905, 159.902-38.358
+ c 35.751-18.268, 68.429-42.862, 96.098-72.145L 512,302.1 C 487.325,324.187, 459.846,343.123, 430.459,358.139z" />
+<glyph unicode="&#xe018;" d="M 256,384C 149.962,384, 64,298.039, 64,192s 85.961-192, 192-192c 106.037,0, 192,85.961, 192,192S 362.037,384, 256,384z
+ M 357.822,90.177C 330.626,62.979, 294.464,48, 256,48s-74.625,14.979-101.823,42.177C 126.979,117.374, 112,153.536, 112,192
+ s 14.979,74.625, 42.177,101.823C 181.375,321.021, 217.536,336, 256,336s 74.626-14.979, 101.821-42.177
+ C 385.022,266.625, 400,230.464, 400,192S 385.021,117.374, 357.822,90.177zM 162.965,378.069l-21.47,42.939C 92.058,396.24, 51.76,355.942, 26.992,306.504l 42.938-21.47
+ C 90.054,325.202, 122.796,357.945, 162.965,378.069zM 442.067,285.035l 42.939,21.469C 460.24,355.942, 419.943,396.24, 370.504,421.008l-21.472-42.939
+ C 389.201,357.945, 421.944,325.203, 442.067,285.035zM 256,288l-32,0 l0-96 c0-5.055, 2.35-9.555, 6.011-12.486l-0.006-0.008l 80-64l 19.988,24.988L 256,199.689L 256,288 z" />
+<glyph unicode="&#xe017;" d="M 160,352L 32,224L 160,96L 224,96L 96,224L 224,352 zM 352,352L 288,352L 416,224L 288,96L 352,96L 480,224 z" />
+<glyph unicode="&#xe016;" d="M 224,128L 288,128L 288,64L 224,64zM 352,352 C 369.673,352 384,337.673 384,320 L 384,224 L 288,160 L 224,160 L 224,192 L 320,256 L 320,288 L 160,288 L 160,352 L 352,352 ZM 256,432 C 200.441,432 148.208,410.364 108.922,371.078 C 69.636,331.792 48,279.559 48,224 C 48,168.441 69.636,116.208 108.922,76.922 C 148.208,37.636 200.441,16 256,16 C 311.559,16 363.792,37.636 403.078,76.922 C 442.364,116.208 464,168.441 464,224 C 464,279.559 442.364,331.792 403.078,371.078 C 363.792,410.364 311.559,432 256,432 Z M 256,480 L 256,480 C 397.385,480 512,365.385 512,224 C 512,82.615 397.385-32 256-32 C 114.615-32 0,82.615 0,224 C 0,365.385 114.615,480 256,480 Z" />
+<glyph unicode="&#xe015;" d="M0,416l0-384 l 512,0 L 512,416 L0,416 z M 96,64L 32,64 l0,64 l 64,0 L 96,64 z M 96,192L 32,192 l0,64 l 64,0 L 96,192 z M 96,320L 32,320 L 32,384 l 64,0 L 96,320 z M 384,64L 128,64 L 128,384 l 256,0 L 384,64 z
+ M 480,64l-64,0 l0,64 l 64,0 L 480,64 z M 480,192l-64,0 l0,64 l 64,0 L 480,192 z M 480,320l-64,0 L 416,384 l 64,0 L 480,320 zM 192,320L 192,128L 320,224 z" />
+<glyph unicode="&#xe014;" d="M0,416l0-416 l 512,0 L 512,416 L0,416 z M 480,32L 32,32 L 32,384 l 448,0 L 480,32 zM 352,304A48,48 1980 1 0 448,304A48,48 1980 1 0 352,304zM 448,64 L 64,64 L 160,320 L 288,160 L 352,208 Z" />
+<glyph unicode="&#xe013;" d="M 96,480l0-512 l 160,160l 160-160L 416,480 L 96,480 z M 384,45.255l-128,128l-128-128L 128,448 l 256,0 L 384,45.255 z" />
+<glyph unicode="&#xe012;" d="M 238.444,142.443c 2.28-4.524, 3.495-9.579, 3.495-14.848c0-8.808-3.372-17.029-9.496-23.154l-81.69-81.69
+ c-6.124-6.124-14.348-9.496-23.154-9.496s-17.030,3.372-23.154,9.496l-49.69,49.69c-6.124,6.125-9.496,14.348-9.496,23.154
+ s 3.372,17.030, 9.496,23.154l 81.69,81.691c 6.124,6.123, 14.348,9.496, 23.154,9.496c 5.269,0, 10.322-1.215, 14.848-3.494l 32.669,32.668
+ c-13.935,10.705-30.72,16.080-47.517,16.080c-19.993,0-39.986-7.583-55.154-22.751l-81.69-81.691
+ c-30.335-30.335-30.335-79.975,0-110.309l 49.69-49.691c 15.167-15.166, 35.16-22.75, 55.153-22.75
+ c 19.994,0, 39.987,7.584, 55.154,22.751l 81.69,81.69c 27.91,27.91, 30.119,72.149, 6.672,102.673L 238.444,142.443zM 489.248,407.558l-49.69,49.691C 424.391,472.417, 404.398,480, 384.404,480c-19.993,0-39.985-7.583-55.153-22.751l-81.691-81.691
+ c-27.91-27.91-30.119-72.149-6.671-102.671l 32.669,32.67c-2.279,4.525-3.494,9.58-3.494,14.847c0,8.808, 3.372,17.030, 9.496,23.154
+ l 81.691,81.691c 6.123,6.124, 14.347,9.497, 23.153,9.497c 8.808,0, 17.030-3.373, 23.154-9.497l 49.69-49.691
+ c 6.124-6.124, 9.496-14.347, 9.496-23.154c0-8.807-3.372-17.030-9.496-23.154l-81.69-81.691c-6.124-6.124-14.347-9.496-23.154-9.496
+ c-5.268,0-10.322,1.215-14.848,3.495l-32.669-32.669c 13.936-10.705, 30.72-16.080, 47.517-16.080c 19.994,0, 39.987,7.584, 55.154,22.752
+ l 81.69,81.69C 519.584,327.584, 519.584,377.223, 489.248,407.558zM 116.684,340.688L 20.687,436.685L 43.315,459.313L 139.312,363.316zM 192,480L 224,480L 224,384L 192,384zM0,288L 96,288L 96,256L0,256zM 395.316,107.312L 491.314,11.314L 468.686-11.314L 372.688,84.684zM 288,64L 320,64L 320-32L 288-32zM 416,192L 512,192L 512,160L 416,160z" />
+<glyph unicode="&#xe011;" d="M 160,128c 8.8-8.8, 23.637-8.363, 32.971,0.971L 351.030,287.029C 360.364,296.363, 360.8,311.2, 352,320
+ s-23.637,8.363-32.971-0.971L 160.971,160.971C 151.637,151.637, 151.2,136.8, 160,128zM 238.444,142.444c 2.28-4.525, 3.495-9.58, 3.495-14.848c0-8.808-3.372-17.030-9.496-23.154l-81.691-81.691
+ c-6.124-6.124-14.347-9.496-23.154-9.496s-17.030,3.372-23.154,9.496l-49.691,49.691c-6.124,6.124-9.496,14.347-9.496,23.154
+ s 3.372,17.030, 9.496,23.154l 81.691,81.691c 6.124,6.124, 14.347,9.497, 23.154,9.497c 5.268,0, 10.322-1.215, 14.848-3.495l 32.669,32.669
+ c-13.935,10.705-30.72,16.080-47.517,16.080c-19.993,0-39.986-7.583-55.154-22.751l-81.691-81.691
+ c-30.335-30.335-30.335-79.974,0-110.309l 49.691-49.691C 87.611-24.416, 107.604-32, 127.597-32
+ c 19.994,0, 39.987,7.584, 55.154,22.751l 81.691,81.691c 27.91,27.91, 30.119,72.149, 6.672,102.672L 238.444,142.444zM 489.249,407.558l-49.691,49.691C 424.391,472.417, 404.398,480, 384.404,480c-19.993,0-39.986-7.583-55.154-22.751l-81.691-81.691
+ c-27.91-27.91-30.119-72.149-6.671-102.671l 32.669,32.67c-2.279,4.525-3.494,9.58-3.494,14.847c0,8.808, 3.372,17.030, 9.496,23.154
+ l 81.691,81.691c 6.124,6.124, 14.347,9.497, 23.154,9.497s 17.030-3.373, 23.154-9.497l 49.691-49.691
+ c 6.124-6.124, 9.496-14.347, 9.496-23.154s-3.372-17.030-9.496-23.154l-81.691-81.691c-6.124-6.124-14.347-9.496-23.154-9.496
+ c-5.268,0-10.322,1.215-14.848,3.495l-32.669-32.669c 13.936-10.705, 30.72-16.080, 47.517-16.080c 19.994,0, 39.987,7.584, 55.154,22.751
+ l 81.691,81.691C 519.584,327.584, 519.584,377.223, 489.249,407.558z" />
+<glyph unicode="&#xe010;" d="M 288,355.814L 288,480 l 192-192L 288,96L 288,222.912 C 64.625,228.153, 74.206,71.016, 131.070-32
+ C-9.286,119.707, 20.52,362.785, 288,355.814z" />
+<glyph unicode="&#xe00f;" d="M 380.931-32C 437.794,71.016, 447.375,228.153, 224,222.912L 224,96 L 32,288L 224,480l0-124.186
+ C 491.481,362.785, 521.285,119.707, 380.931-32z" />
+<glyph unicode="&#xe00e;" d="M 112.5,256 C 174.356,256 224.5,205.855 224.5,144 C 224.5,82.144 174.356,32 112.5,32 C 50.644,32 0.5,82.144 0.5,144 L 0,160 C 0,283.712 100.288,384 224,384 L 224,320 C 181.263,320 141.083,303.357 110.863,273.137 C 105.046,267.319 99.737,261.129 94.948,254.627 C 100.667,255.527 106.528,256 112.5,256 ZM 400.5,256 C 462.355,256 512.5,205.855 512.5,144 C 512.5,82.144 462.355,32 400.5,32 C 338.645,32 288.5,82.144 288.5,144 L 288,160 C 288,283.712 388.288,384 512,384 L 512,320 C 469.263,320 429.083,303.357 398.863,273.137 C 393.045,267.319 387.736,261.129 382.947,254.627 C 388.667,255.527 394.527,256 400.5,256 Z" />
+<glyph unicode="&#xe00d;" d="M0,448L 512,448L 512,384L0,384zM 192,352L 512,352L 512,288L 192,288zM 192,256L 512,256L 512,192L 192,192zM 192,160L 512,160L 512,96L 192,96zM0,64L 512,64L 512,0L0,0zM 128,320 L 128,128 L 0,224 Z" />
+<glyph unicode="&#xe00c;" d="M0,448L 512,448L 512,384L0,384zM 192,352L 512,352L 512,288L 192,288zM 192,256L 512,256L 512,192L 192,192zM 192,160L 512,160L 512,96L 192,96zM0,64L 512,64L 512,0L0,0zM 0,128 L 0,320 L 128,224 Z" />
+<glyph unicode="&#xe00b;" d="M 192,64L 512,64L 512,0L 192,0zM 192,256L 512,256L 512,192L 192,192zM 192,448L 512,448L 512,384L 192,384zM 96,480 L 96,352 L 64,352 L 64,448 L 32,448 L 32,480 ZM 64,217 L 64,192 L 128,192 L 128,160 L 32,160 L 32,233 L 96,263 L 96,288 L 32,288 L 32,320 L 128,320 L 128,247 ZM 128,128 L 128-32 L 32-32 L 32,0 L 96,0 L 96,32 L 32,32 L 32,64 L 96,64 L 96,96 L 32,96 L 32,128 Z" />
+<glyph unicode="&#xe00a;" d="M 192,448l 320,0 l0-64 L 192,384 L 192,448 z M 192,256l 320,0 l0-64 L 192,192 L 192,256 z M 192,64l 320,0 l0-64 L 192,0 L 192,64 zM0,416A64,64 1980 1 0 128,416A64,64 1980 1 0 0,416zM0,224A64,64 1980 1 0 128,224A64,64 1980 1 0 0,224zM0,32A64,64 1980 1 0 128,32A64,64 1980 1 0 0,32z" />
+<glyph unicode="&#xe009;" d="M 32,480L 224,480L 224,448L 32,448zM 288,480L 480,480L 480,448L 288,448zM 476,320l-28,0 L 448,448 L 320,448 l0-128 L 192,320 L 192,448 L 64,448 l0-128 L 36,320 c-19.8,0-36-16.2-36-36l0-280 c0-19.8, 16.2-36, 36-36l 152,0 c 19.8,0, 36,16.2, 36,36L 224,192 l 64,0
+ l0-188 c0-19.8, 16.2-36, 36-36l 152,0 c 19.8,0, 36,16.2, 36,36L 512,284 C 512,303.8, 495.8,320, 476,320z M 174,0L 50,0 c-9.9,0-18,7.2-18,16
+ s 8.1,16, 18,16l 124,0 c 9.9,0, 18-7.2, 18-16S 183.9,0, 174,0z M 272,224l-32,0 c-8.8,0-16,7.2-16,16s 7.2,16, 16,16l 32,0 c 8.8,0, 16-7.2, 16-16
+ S 280.8,224, 272,224z M 462,0L 338,0 c-9.9,0-18,7.2-18,16s 8.1,16, 18,16l 124,0 c 9.9,0, 18-7.2, 18-16S 471.9,0, 462,0z" />
+<glyph unicode="&#xe008;" d="M 416,320L 416,400 c0,8.8-7.2,16-16,16L 288,416 L 288,448 c0,17.6-14.4,32-32,32l-64,0 c-17.602,0-32-14.4-32-32l0-32 L 48,416 c-8.801,0-16-7.2-16-16l0-320
+ c0-8.8, 7.199-16, 16-16l 144,0 l0-96 l 224,0 l 96,96L 512,320 L 416,320 z M 192,447.943c 0.017,0.019, 0.036,0.039, 0.057,0.057l 63.884,0
+ c 0.021-0.018, 0.041-0.038, 0.059-0.057L 256,416 l-64,0 L 192,447.943 z M 96,352L 96,384 l 256,0 l0-32 L 96,352 z M 416,13.255L 416,64 l 50.745,0 L 416,13.255z M 480,96l-96,0 l0-96
+ L 224,0 L 224,288 l 256,0 L 480,96 z" />
+<glyph unicode="&#xe007;" d="M 445.387,125.423c-22.827,22.778-51.864,34.536-78.973,34.536l-14.556,0 l-31.952,32.004l 127.81,128.019
+ c 31.952,32.005, 31.952,96.014,0,128.019L 256.001,255.973L 64.285,448c-31.952-32.004-31.952-96.014,0-128.019l 127.811-128.017
+ l-31.953-32.004l-14.557,0 c-27.11,0-56.146-11.759-78.974-34.538c-40.811-40.721-46.325-101.242-12.315-135.175
+ C 69.282-24.704, 89.441-32, 110.795-32c 27.108,0, 56.145,11.757, 78.973,34.536c 26.792,26.732, 38.371,62, 33.542,92.674l 32.692,32.744
+ l 32.688-32.744c-4.828-30.674, 6.753-65.941, 33.542-92.674C 345.063-20.243, 374.098-32, 401.206-32
+ c 21.354,0, 41.512,7.296, 56.497,22.248C 491.713,24.181, 486.197,84.702, 445.387,125.423z M 176.512,57.231
+ c-3.849-8.941-9.505-17.173-16.813-24.463c-7.318-7.302-15.586-12.959-24.574-16.812c-8.066-3.458-16.48-5.284-24.331-5.284
+ c-7.573,0-18.306,1.701-26.431,9.806c-8.068,8.052-9.76,18.659-9.76,26.144c0,7.771, 1.821,16.105, 5.263,24.106
+ c 3.85,8.942, 9.507,17.173, 16.813,24.463c 7.317,7.303, 15.586,12.957, 24.575,16.812c 8.067,3.457, 16.48,5.284, 24.332,5.284
+ c 7.573,0, 18.306-1.7, 26.429-9.807c 8.067-8.049, 9.761-18.658, 9.761-26.142C 181.777,73.567, 179.957,65.23, 176.512,57.231z
+ M 256.002,146.702c-24.957,0-45.188,20.266-45.188,45.263c0,24.996, 20.231,45.26, 45.188,45.26s 45.186-20.264, 45.186-45.26
+ C 301.188,166.966, 280.958,146.702, 256.002,146.702z M 427.636,20.479c-8.124-8.104-18.856-9.806-26.43-9.806
+ c-7.852,0-16.265,1.826-24.333,5.284c-8.986,3.853-17.254,9.51-24.571,16.812c-7.307,7.29-12.963,15.521-16.813,24.463
+ c-3.443,7.999-5.263,16.336-5.263,24.106c0,7.483, 1.692,18.094, 9.76,26.143c 8.123,8.104, 18.856,9.807, 26.43,9.807
+ c 7.85,0, 16.265-1.827, 24.33-5.284c 8.989-3.854, 17.258-9.509, 24.575-16.812c 7.305-7.29, 12.962-15.521, 16.813-24.463
+ c 3.442-7.999, 5.263-16.335, 5.263-24.106C 437.396,39.138, 435.702,28.53, 427.636,20.479z" />
+<glyph unicode="&#xe006;" d="M0,448L 512,448L 512,384L0,384zM0,352L 512,352L 512,288L0,288zM0,256L 512,256L 512,192L0,192zM0,160L 512,160L 512,96L0,96zM0,64L 512,64L 512,0L0,0z" />
+<glyph unicode="&#xe005;" d="M0,448L 512,448L 512,384L0,384zM 192,352L 512,352L 512,288L 192,288zM 192,160L 512,160L 512,96L 192,96zM0,256L 512,256L 512,192L0,192zM0,64L 512,64L 512,0L0,0z" />
+<glyph unicode="&#xe004;" d="M0,448L 512,448L 512,384L0,384zM 96,352L 416,352L 416,288L 96,288zM 96,160L 416,160L 416,96L 96,96zM0,256L 512,256L 512,192L0,192zM0,64L 512,64L 512,0L0,0z" />
+<glyph unicode="&#xe003;" d="M0,448L 512,448L 512,384L0,384zM0,352L 320,352L 320,288L0,288zM0,160L 320,160L 320,96L0,96zM0,256L 512,256L 512,192L0,192zM0,64L 512,64L 512,0L0,0z" />
+<glyph unicode="&#xe002;" d="M 512,183.771l0,80.458 l-79.572,7.957c-4.093,15.021-10.044,29.274-17.605,42.49l 52.298,63.919L 410.595,435.12l-63.918-52.298
+ c-13.217,7.562-27.471,13.513-42.491,17.604L 296.229,480l-80.458,0 l-7.957-79.573c-15.021-4.093-29.274-10.043-42.49-17.604
+ L 101.405,435.12L 44.88,378.595l 52.298-63.918c-7.562-13.216-13.513-27.47-17.605-42.49L0,264.229l0-80.458 l 79.573-7.957
+ c 4.093-15.021, 10.043-29.274, 17.605-42.491L 44.88,69.405l 56.524-56.524l 63.919,52.298c 13.216-7.562, 27.47-13.514, 42.49-17.605
+ L 215.771-32l 80.458,0 l 7.957,79.572c 15.021,4.093, 29.274,10.044, 42.491,17.605l 63.918-52.298l 56.524,56.524l-52.298,63.918
+ c 7.562,13.217, 13.514,27.471, 17.605,42.49L 512,183.771z M 352,192l-64-64l-64,0 l-64,64l0,64 l 64,64l 64,0 l 64-64L 352,192 z" />
+<glyph unicode="&#xe001;" d="M 451.716,380.285l-71.432,71.431C 364.728,467.272, 334,480, 312,480L 72,480 C 50,480, 32,462, 32,440l0-432 c0-22, 18-40, 40-40l 368,0 c 22,0, 40,18, 40,40
+ L 480,312 C 480,334, 467.272,364.729, 451.716,380.285z M 429.089,357.657c 1.565-1.565, 3.125-3.487, 4.64-5.657L 352,352 L 352,433.728
+ c 2.17-1.515, 4.092-3.075, 5.657-4.64L 429.089,357.657z M 448,8c0-4.336-3.664-8-8-8L 72,0 c-4.336,0-8,3.664-8,8L 64,440 c0,4.336, 3.664,8, 8,8
+ l 240,0 c 2.416,0, 5.127-0.305, 8-0.852L 320,320 l 127.148,0 c 0.547-2.873, 0.852-5.583, 0.852-8L 448,8 z" />
+<glyph unicode="&#xe000;" d="M 448,480L0,480 l0-512 l 512,0 L 512,416 L 448,480z M 256,416l 64,0 l0-128 l-64,0 L 256,416 z M 448,32L 64,32 L 64,416 l 32,0 l0-160 l 288,0 L 384,416 l 37.489,0 L 448,389.491L 448,32 z" />
+<glyph unicode="&#xe033;" d="M 64,208L 208,64L 448,304L 384,368L 208,192L 128,272 z" />
+<glyph unicode="&#xe035;" d="M 256,224L 256,160L 272,160L 288,192L 320,192L 320,64L 296,64L 296,32L 408,32L 408,64L 384,64L 384,192L 416,192L 432,160L 448,160L 448,224 zM 416,320L 416,400 c0,8.8-7.2,16-16,16L 288,416 L 288,448 c0,17.6-14.4,32-32,32l-64,0 c-17.602,0-32-14.4-32-32l0-32 L 48,416 c-8.801,0-16-7.2-16-16l0-320
+ c0-8.8, 7.199-16, 16-16l 144,0 l0-96 l 320,0 L 512,320 L 416,320 z M 192,447.943c 0.017,0.019, 0.036,0.039, 0.057,0.057l 63.884,0
+ c 0.021-0.018, 0.041-0.038, 0.059-0.057L 256,416 l-64,0 L 192,447.943 z M 96,352L 96,384 l 256,0 l0-32 L 96,352 z M 480,0L 224,0 L 224,288 l 256,0 L 480,0 z" />
+<glyph unicode="&#x20;" horiz-adv-x="256" />
+</font></defs></svg> \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.ttf b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.ttf
new file mode 100755
index 0000000..dea6e45
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.ttf
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.woff b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.woff
new file mode 100755
index 0000000..f176579
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/icomoon.woff
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/readme.md b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/readme.md
new file mode 100755
index 0000000..fa5d639
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/fonts/readme.md
@@ -0,0 +1 @@
+Icons are generated and provided by the http://icomoon.io service.
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/anchor.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/anchor.gif
new file mode 100755
index 0000000..606348c
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/anchor.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/loader.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/loader.gif
new file mode 100755
index 0000000..c69e937
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/loader.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/object.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/object.gif
new file mode 100755
index 0000000..cccd7f0
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/object.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/trans.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/trans.gif
new file mode 100755
index 0000000..3884865
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/trans.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/wline.gif b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/wline.gif
new file mode 100755
index 0000000..7d0a4db
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/img/wline.gif
Binary files differ
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/skin.ie7.min.css b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/skin.ie7.min.css
new file mode 100755
index 0000000..0d29f3a
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/skin.ie7.min.css
@@ -0,0 +1 @@
+.mce-container,.mce-container *,.mce-widget,.mce-widget *{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:#000;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;-webkit-tap-highlight-color:transparent;line-height:normal;font-weight:normal;text-align:left}.mce-container *[unselectable]{-moz-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}.mce-container ::-webkit-scrollbar{width:8px;height:8px;-webkit-border-radius:4px}.mce-container ::-webkit-scrollbar-track,.mce-container ::-webkit-scrollbar-track-piece{background-color:transparent}.mce-container ::-webkit-scrollbar-thumb{background-color:rgba(53,57,71,0.3);width:6px;height:6px;-webkit-border-radius:4px}.mce-fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.mce-fade.mce-in{opacity:1}.mce-tinymce{visibility:visible!important;position:relative}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;background:#FFF;height:100%;z-index:100}div.mce-fullscreen{position:fixed;top:0;left:0;width:100%;height:auto}.mce-tinymce{display:block;border-radius:2px}.mce-wordcount{position:absolute;top:0;right:0;padding:8px}.mce-edit-area{background:#FFF;filter:none}.mce-statusbar{position:relative}.mce-statusbar .mce-container-body{position:relative}.mce-fullscreen .mce-resizehandle{display:none}.mce-charmap{border-collapse:collapse}.mce-charmap td{cursor:default;border:1px solid #c5c5c5;width:20px;height:20px;line-height:20px;text-align:center;vertical-align:middle;padding:2px}.mce-charmap td div{text-align:center}.mce-charmap td:hover{background:#d9d9d9}.mce-grid td div{border:1px solid #808080;width:12px;height:12px;margin:2px;cursor:pointer}.mce-grid td div:hover{border-color:black}.mce-grid td div:focus{border-color:#59a5e1;outline:1px solid rgba(82,168,236,0.8);border-color:rgba(82,168,236,0.8)}.mce-grid{border-spacing:2px;border-collapse:separate}.mce-grid a{display:block;border:1px solid transparent}.mce-grid a:hover{border-color:#c5c5c5}.mce-grid-border{margin:0 4px 0 4px}.mce-grid-border a{border-color:#e8e8e8;width:13px;height:13px}.mce-grid-border a:hover,.mce-grid-border a.mce-active{border-color:#c4daff;background:#deeafa}.mce-text-center{text-align:center}div.mce-tinymce-inline{width:100%;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.mce-container,.mce-container-body{display:block}.mce-autoscroll{overflow:hidden}.mce-scrollbar{position:absolute;width:7px;height:100%;top:2px;right:2px;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-scrollbar-h{top:auto;right:auto;left:2px;bottom:2px;width:100%;height:7px}.mce-scrollbar-thumb{position:absolute;background-color:#000;border:1px solid #888;border-color:rgba(85,85,85,0.6);width:5px;height:100%;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}.mce-scrollbar-h .mce-scrollbar-thumb{width:100%;height:5px}.mce-scrollbar:hover,.mce-scrollbar.mce-active{background-color:#AAA;opacity:.6;filter:alpha(opacity=60);zoom:1;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}.mce-scroll{position:relative}.mce-panel{border:0 solid #9e9e9e;background-color:#f0f0f0;background-image:-moz-linear-gradient(top,#fdfdfd,#ddd);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fdfdfd),to(#ddd));background-image:-webkit-linear-gradient(top,#fdfdfd,#ddd);background-image:-o-linear-gradient(top,#fdfdfd,#ddd);background-image:linear-gradient(to bottom,#fdfdfd,#ddd);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffdfdfd',endColorstr='#ffdddddd',GradientType=0);zoom:1}.mce-floatpanel{position:absolute;-webkit-box-shadow:#ccc 5px 5px 5px;-moz-box-shadow:#ccc 5px 5px 5px;box-shadow:#ccc 5px 5px 5px}.mce-floatpanel.mce-fixed{position:fixed}.mce-floatpanel .mce-arrow,.mce-floatpanel .mce-arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.mce-floatpanel .mce-arrow{border-width:11px}.mce-floatpanel .mce-arrow:after{border-width:10px;content:""}.mce-floatpanel.mce-popover{top:0;left:0;background:#fff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2)}.mce-floatpanel.mce-popover.mce-bottom{margin-top:10px}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.mce-floatpanel.mce-popover.mce-bottom.mce-start{margin-left:-22px}.mce-floatpanel.mce-popover.mce-bottom.mce-start>.mce-arrow{left:20px}.mce-floatpanel.mce-popover.mce-bottom.mce-end{margin-left:22px}.mce-floatpanel.mce-popover.mce-bottom.mce-end>.mce-arrow{right:10px;left:auto}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;background:#FFF;height:100%}div.mce-fullscreen{position:fixed;top:0;left:0}#mce-modal-block{opacity:0;filter:alpha(opacity=0);zoom:1;position:fixed;left:0;top:0;width:100%;height:100%;background:#000}#mce-modal-block.mce-in{opacity:.3;filter:alpha(opacity=30);zoom:1}.mce-window-move{cursor:move}.mce-window{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;background:#FFF;position:fixed;top:0;left:0;opacity:0;-webkit-transition:opacity 150ms ease-in;transition:opacity 150ms ease-in}.mce-window.mce-in{opacity:1}.mce-window-head{padding:9px 15px;border-bottom:1px solid #EEE;position:relative}.mce-window-head .mce-close{position:absolute;right:15px;top:9px;font-size:20px;font-weight:bold;line-height:20px;color:#CCC;text-shadow:0 1px 0 white;cursor:pointer;height:20px;overflow:hidden}.mce-close:hover{color:#AAA}.mce-window-head .mce-title{display:inline-block;*display:inline;*zoom:1;line-height:20px;font-size:20px;font-weight:bold;text-rendering:optimizelegibility;padding-right:10px}.mce-window .mce-container-body{display:block}.mce-foot{display:block;background-color:whiteSmoke;border-top:1px solid #DDD;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.mce-window-head .mce-dragh{position:absolute;top:0;left:0;cursor:move;width:90%;height:100%}.mce-window iframe{width:100%;height:100%}.mce-window.mce-fullscreen,.mce-window.mce-fullscreen .mce-foot{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.mce-abs-layout{position:relative}body .mce-abs-layout-item,.mce-abs-end{position:absolute}.mce-abs-end{width:1px;height:1px}.mce-container-body.mce-abs-layout{overflow:hidden}.mce-tooltip{position:absolute;padding:5px;opacity:.8;filter:alpha(opacity=80);zoom:1}.mce-tooltip-inner{font-size:11px;background-color:#000;color:#fff;max-width:200px;padding:5px 8px 4px 8px;text-align:center;white-space:normal}.mce-tooltip-inner{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.mce-tooltip-inner{-webkit-box-shadow:0 0 5px #000;-moz-box-shadow:0 0 5px #000;box-shadow:0 0 5px #000}.mce-tooltip-arrow{position:absolute;width:0;height:0;line-height:0;border:5px dashed #000}.mce-tooltip-arrow-n{border-bottom-color:#000}.mce-tooltip-arrow-s{border-top-color:#000}.mce-tooltip-arrow-e{border-left-color:#000}.mce-tooltip-arrow-w{border-right-color:#000}.mce-tooltip-nw,.mce-tooltip-sw{margin-left:-14px}.mce-tooltip-n .mce-tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-style:solid;border-top:0;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-nw .mce-tooltip-arrow{top:0;left:10px;border-bottom-style:solid;border-top:0;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-ne .mce-tooltip-arrow{top:0;right:10px;border-bottom-style:solid;border-top:0;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-s .mce-tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-style:solid;border-bottom:0;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-sw .mce-tooltip-arrow{bottom:0;left:10px;border-top-style:solid;border-bottom:0;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-se .mce-tooltip-arrow{bottom:0;right:10px;border-top-style:solid;border-bottom:0;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-e .mce-tooltip-arrow{right:0;top:50%;margin-top:-5px;border-left-style:solid;border-right:0;border-top-color:transparent;border-bottom-color:transparent}.mce-tooltip-w .mce-tooltip-arrow{left:0;top:50%;margin-top:-5px;border-right-style:solid;border-left:none;border-top-color:transparent;border-bottom-color:transparent}.mce-btn{border:1px solid #c5c5c5;position:relative;color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f0f0f0;background-image:-moz-linear-gradient(top,#fff,#d9d9d9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#d9d9d9));background-image:-webkit-linear-gradient(top,#fff,#d9d9d9);background-image:-o-linear-gradient(top,#fff,#d9d9d9);background-image:linear-gradient(to bottom,#fff,#d9d9d9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffd9d9d9',GradientType=0);zoom:1;border-color:#d9d9d9 #d9d9d9 #b3b3b3;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);display:inline-block;*display:inline;*zoom:1;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.mce-btn:hover,.mce-btn:focus{text-decoration:none;color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#e3e3e3;background-image:-moz-linear-gradient(top,#f2f2f2,#ccc);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#ccc));background-image:-webkit-linear-gradient(top,#f2f2f2,#ccc);background-image:-o-linear-gradient(top,#f2f2f2,#ccc);background-image:linear-gradient(to bottom,#f2f2f2,#ccc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffcccccc',GradientType=0);zoom:1;border-color:#ccc #ccc #a6a6a6;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25)}.mce-btn.mce-disabled,.mce-btn.mce-disabled:hover{cursor:default;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:.65;filter:alpha(opacity=65);zoom:1}.mce-btn.mce-active,.mce-btn.mce-active:hover{color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#d6d6d6;background-image:-moz-linear-gradient(top,#e6e6e6,#bfbfbf);background-image:-webkit-gradient(linear,0 0,0 100%,from(#e6e6e6),to(#bfbfbf));background-image:-webkit-linear-gradient(top,#e6e6e6,#bfbfbf);background-image:-o-linear-gradient(top,#e6e6e6,#bfbfbf);background-image:linear-gradient(to bottom,#e6e6e6,#bfbfbf);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6',endColorstr='#ffbfbfbf',GradientType=0);zoom:1;border-color:#bfbfbf #bfbfbf #999;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.mce-btn button{padding:4px 10px;font-size:14px;line-height:20px;*line-height:16px;cursor:pointer;color:#333;text-align:center;overflow:visible;-webkit-appearance:none}.mce-btn button::-moz-focus-inner{border:0;padding:0}.mce-btn i{text-shadow:1px 1px #fff}.mce-primary{min-width:50px;color:#fff;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);zoom:1;border-color:#04c #04c #002b80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25)}.mce-primary:hover,.mce-primary:focus{color:#fff;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#005fb3;background-image:-moz-linear-gradient(top,#0077b3,#003cb3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#0077b3),to(#003cb3));background-image:-webkit-linear-gradient(top,#0077b3,#003cb3);background-image:-o-linear-gradient(top,#0077b3,#003cb3);background-image:linear-gradient(to bottom,#0077b3,#003cb3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0077b3',endColorstr='#ff003cb3',GradientType=0);zoom:1;border-color:#003cb3 #003cb3 #026;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25)}.mce-primary button{color:#fff}.mce-btn-large button{padding:9px 14px;font-size:16px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.mce-btn-large i{margin-top:2px}.mce-btn-small button{padding:3px 5px;font-size:12px;line-height:15px}.mce-btn-small i{margin-top:0}.mce-btn .mce-caret{margin-top:8px;*margin-top:6px;margin-left:0}.mce-btn-small .mce-caret{margin-top:6px;*margin-top:4px;margin-left:0}.mce-caret{display:inline-block;*display:inline;*zoom:1;width:0;height:0;vertical-align:top;border-top:4px solid #444;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.mce-disabled .mce-caret{border-top-color:#999}.mce-caret.mce-up{border-bottom:4px solid #444;border-top:0}.mce-btn-group .mce-btn{border-width:1px 0 1px 0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.mce-btn-group .mce-btn:hover,.mce-btn-group .mce-btn:focus{color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#e3e3e3;background-image:-moz-linear-gradient(top,#f2f2f2,#ccc);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#ccc));background-image:-webkit-linear-gradient(top,#f2f2f2,#ccc);background-image:-o-linear-gradient(top,#f2f2f2,#ccc);background-image:linear-gradient(to bottom,#f2f2f2,#ccc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffcccccc',GradientType=0);zoom:1;border-color:#ccc #ccc #a6a6a6;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25)}.mce-btn-group .mce-btn.mce-disabled,.mce-btn-group .mce-btn.mce-disabled:hover{-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f0f0f0;background-image:-moz-linear-gradient(top,#fff,#d9d9d9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#d9d9d9));background-image:-webkit-linear-gradient(top,#fff,#d9d9d9);background-image:-o-linear-gradient(top,#fff,#d9d9d9);background-image:linear-gradient(to bottom,#fff,#d9d9d9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffd9d9d9',GradientType=0);zoom:1;border-color:#d9d9d9 #d9d9d9 #b3b3b3;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25)}.mce-btn-group .mce-btn.mce-active,.mce-btn-group .mce-btn.mce-active:hover,.mce-btn-group .mce-btn:active{color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#d6d6d6;background-image:-moz-linear-gradient(top,#e6e6e6,#bfbfbf);background-image:-webkit-gradient(linear,0 0,0 100%,from(#e6e6e6),to(#bfbfbf));background-image:-webkit-linear-gradient(top,#e6e6e6,#bfbfbf);background-image:-o-linear-gradient(top,#e6e6e6,#bfbfbf);background-image:linear-gradient(to bottom,#e6e6e6,#bfbfbf);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6',endColorstr='#ffbfbfbf',GradientType=0);zoom:1;border-color:#bfbfbf #bfbfbf #999;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.mce-btn-group .mce-btn.mce-disabled button{opacity:.65;filter:alpha(opacity=65);zoom:1}.mce-btn-group .mce-first{border-left:1px solid #c5c5c5;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.mce-btn-group .mce-last{border-right:1px solid #c5c5c5;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.mce-btn-group .mce-first.mce-last{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.mce-btn-group .mce-btn.mce-flow-layout-item{margin:0}.mce-checkbox{cursor:pointer}i.mce-i-checkbox{margin:0 3px 0 0;border:1px solid #c5c5c5;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);background-color:#f0f0f0;background-image:-moz-linear-gradient(top,#fdfdfd,#ddd);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fdfdfd),to(#ddd));background-image:-webkit-linear-gradient(top,#fdfdfd,#ddd);background-image:-o-linear-gradient(top,#fdfdfd,#ddd);background-image:linear-gradient(to bottom,#fdfdfd,#ddd);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffdfdfd',endColorstr='#ffdddddd',GradientType=0);zoom:1;text-indent:-10em;*font-size:0;*line-height:0;*text-indent:0}.mce-checked i.mce-i-checkbox{color:#000;font-size:16px;line-height:16px;text-indent:0}.mce-checkbox:focus i.mce-i-checkbox{border:1px solid #59a5e1;border:1px solid rgba(82,168,236,0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}.mce-colorbutton .mce-ico{position:relative}.mce-colorpicker{background:#FFF}.mce-colorbutton-grid{margin:4px}.mce-colorbutton button{padding-right:4px}.mce-colorbutton .mce-preview{padding-right:3px;display:block;position:absolute;left:50%;top:50%;margin-left:-14px;margin-top:7px;background:gray;width:13px;height:2px;overflow:hidden}.mce-colorbutton.mce-btn-small .mce-preview{margin-left:-17px;padding-right:0;width:16px}.mce-colorbutton .mce-open{padding-left:4px;border-left:1px solid transparent;border-right:1px solid transparent}.mce-colorbutton:hover .mce-open{border-left-color:#c5c5c5;border-right-color:#c5c5c5}.mce-combobox{display:inline-block;*display:inline;*zoom:1;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;width:100px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.mce-combobox input{border:1px solid #c5c5c5;border-right-color:rgba(0,0,0,0.15);height:28px}.mce-combobox.mce-has-open input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.mce-combobox .mce-btn{border-left:0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.mce-combobox button{padding-right:8px;padding-left:8px}.mce-combobox *:focus{border-color:#59a5e1;border-color:rgba(82,168,236,0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}.mce-path{display:inline-block;*display:inline;*zoom:1;padding:8px;white-space:normal}.mce-path .mce-txt{display:inline-block;padding-right:3px}.mce-path .mce-path-body{display:inline-block}.mce-path-item{display:inline-block;*display:inline;*zoom:1;cursor:pointer;color:#000}.mce-path-item:hover{text-decoration:underline}.mce-path-item:focus{background:gray;color:white}.mce-path .mce-divider{display:inline}.mce-fieldset{border:0 solid #9e9e9e;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.mce-fieldset>.mce-container-body{margin-top:-15px}.mce-fieldset-title{margin-left:5px;padding:0 5px 0 5px}.mce-fit-layout{display:inline-block;*display:inline;*zoom:1}.mce-fit-layout-item{position:absolute}.mce-flow-layout-item{display:inline-block;*display:inline;*zoom:1}.mce-flow-layout-item{margin:2px 0 2px 2px}.mce-flow-layout-item.mce-last{margin-right:2px}.mce-flow-layout{white-space:normal}.mce-tinymce-inline .mce-flow-layout{white-space:nowrap}.mce-iframe{border:0 solid #c5c5c5;width:100%;height:100%}.mce-label{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 1px rgba(255,255,255,0.75);border:0 solid #c5c5c5;overflow:hidden}.mce-label.mce-autoscroll{overflow:auto}.mce-label-disabled .mce-text{color:#999}.mce-label.mce-multiline{white-space:pre-wrap}.mce-menubar .mce-menubtn{border-color:transparent;background:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;filter:none}.mce-menubar{border:1px solid #ddd}.mce-menubar .mce-menubtn button{color:#000}.mce-menubar .mce-menubtn:hover,.mce-menubar .mce-menubtn.mce-active,.mce-menubar .mce-menubtn:focus{border-color:transparent;background:#ddd;filter:none}.mce-menubtn.mce-disabled span{color:#999}.mce-menubtn span{margin-right:2px;line-height:20px;*line-height:16px}.mce-menubtn.mce-btn-small span{font-size:12px;line-height:15px;*line-height:16px}.mce-menubtn.mce-fixed-width span{display:inline-block;overflow-x:hidden;text-overflow:ellipsis;width:90px}.mce-menubtn.mce-fixed-width.mce-btn-small span{width:70px}.mce-listbox button{text-align:left;padding-right:20px;position:relative}.mce-listbox .mce-caret{position:absolute;margin-top:-2px;right:8px;top:50%}.mce-menu-item{display:block;padding:6px 15px 6px 12px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap;cursor:pointer;line-height:normal;border-left:4px solid transparent;margin-bottom:1px}.mce-menu-item.mce-disabled .mce-text{color:#999}.mce-menu-item:hover,.mce-menu-item.mce-selected,.mce-menu-item:focus{text-decoration:none;color:#fff;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0);zoom:1}.mce-menu-item:hover .mce-text,.mce-menu-item.mce-selected .mce-text{color:#fff}.mce-menu-item:hover .mce-ico,.mce-menu-item.mce-selected .mce-ico,.mce-menu-item:focus .mce-ico{color:white}.mce-menu-item.mce-disabled:hover{background:#CCC}.mce-menu-shortcut{display:inline-block;color:#999}.mce-menu-shortcut{display:inline-block;*display:inline;*zoom:1;padding:0 15px 0 20px}.mce-menu-item .mce-caret{margin-top:4px;*margin-top:3px;margin-right:6px;border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:4px solid #666}.mce-menu-item.mce-selected .mce-caret,.mce-menu-item:focus .mce-caret{border-left-color:#FFF}.mce-menu-align .mce-menu-shortcut{*margin-top:-2px}.mce-menu-align .mce-menu-shortcut,.mce-menu-align .mce-caret{position:absolute;right:0}.mce-menu-item-sep,.mce-menu-item-sep:hover{padding:0;height:1px;margin:9px 1px;overflow:hidden;background:#e5e5e5;border-bottom:1px solid white;cursor:default;filter:none}.mce-menu-item.mce-active i{visibility:visible}.mce-menu-item.mce-active{background-color:#c8def4;outline:1px solid #c5c5c5}.mce-menu-item-preview.mce-active{border-left:5px solid #aaa;background-color:transparent;outline:0}.mce-menu-item-checkbox.mce-active{background-color:#FFF;outline:0}.mce-menu{filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;z-index:1000;padding:5px 0 5px 0;margin:2px 0 0;min-width:160px;background:#FFF;border:1px solid #CCC;border:1px solid rgba(0,0,0,0.2);z-index:1002;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);max-height:400px;overflow:auto;overflow-x:hidden}.mce-menu i{display:none}.mce-menu-has-icons i{display:inline-block;*display:inline;*zoom:1}.mce-menu-sub-tr-tl{margin:-6px 0 0 -1px}.mce-menu-sub-br-bl{margin:6px 0 0 -1px}.mce-menu-sub-tl-tr{margin:-6px 0 0 1px}.mce-menu-sub-bl-br{margin:6px 0 0 1px}i.mce-radio{padding:1px;margin:0 3px 0 0;background-color:#fafafa;border:1px solid #cacece;-webkit-border-radius:8px;-moz-border-radius:8px;border-radius:8px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);background-color:#f0f0f0;background-image:-moz-linear-gradient(top,#fdfdfd,#ddd);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fdfdfd),to(#ddd));background-image:-webkit-linear-gradient(top,#fdfdfd,#ddd);background-image:-o-linear-gradient(top,#fdfdfd,#ddd);background-image:linear-gradient(to bottom,#fdfdfd,#ddd);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffdfdfd',endColorstr='#ffdddddd',GradientType=0);zoom:1}i.mce-radio:after{font-family:Arial;font-size:12px;color:#000;content:'\25cf'}.mce-container-body .mce-resizehandle{position:absolute;right:0;bottom:0;width:16px;height:16px;visibility:visible;cursor:s-resize;margin:0}.mce-container-body .mce-resizehandle-both{cursor:se-resize}i.mce-i-resize{color:#000}.mce-spacer{visibility:hidden}.mce-splitbtn .mce-open{border-left:1px solid transparent;border-right:1px solid transparent}.mce-splitbtn:hover .mce-open{border-left-color:#c5c5c5;border-right-color:#c5c5c5}.mce-splitbtn button{padding-right:4px}.mce-splitbtn .mce-open{padding-left:4px}.mce-splitbtn .mce-open.mce-active{-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.mce-stack-layout-item{display:block}.mce-tabs{display:block;border-bottom:1px solid #ccc}.mce-tab{display:inline-block;*display:inline;*zoom:1;border:1px solid #ccc;border-width:1px 1px 0 0;background:#e3e3e3;padding:8px;text-shadow:0 1px 1px rgba(255,255,255,0.75);height:13px;cursor:pointer}.mce-tab:hover{background:#fdfdfd}.mce-tab.mce-active{background:#fdfdfd;border-bottom-color:transparent;margin-bottom:-1px;height:14px}.mce-textbox{background:#FFF;border:1px solid #c5c5c5;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);display:inline-block;-webkit-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s;height:28px;resize:none;padding:0 4px 0 4px;white-space:pre-wrap;*white-space:pre;color:#000}.mce-textbox:focus{border-color:rgba(82,168,236,0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}.mce-placeholder .mce-textbox{color:#aaa}.mce-textbox.mce-multiline{padding:4px}.mce-throbber{position:absolute;top:0;left:0;width:100%;height:100%;opacity:.6;filter:alpha(opacity=60);zoom:1;background:#fff url('img/loader.gif') no-repeat center center}@font-face{font-family:'icomoon';src:url('fonts/icomoon.eot');src:url('fonts/icomoon.eot?#iefix') format('embedded-opentype'),url('fonts/icomoon.svg#icomoon') format('svg'),url('fonts/icomoon.woff') format('woff'),url('fonts/icomoon.ttf') format('truetype');font-weight:normal;font-style:normal}@font-face{font-family:'icomoon-small';src:url('fonts/icomoon-small.eot');src:url('fonts/icomoon-small.eot?#iefix') format('embedded-opentype'),url('fonts/icomoon-small.svg#icomoon') format('svg'),url('fonts/icomoon-small.woff') format('woff'),url('fonts/icomoon-small.ttf') format('truetype');font-weight:normal;font-style:normal}.mce-ico{font-family:'icomoon';font-style:normal;font-weight:normal;font-size:16px;line-height:16px;vertical-align:text-top;-webkit-font-smoothing:antialiased;display:inline-block;background:transparent center center;width:16px;height:16px;color:#333;-ie7-icon:' '}.mce-btn-small .mce-ico{font-family:'icomoon-small'}.mce-ico,i.mce-i-checkbox{zoom:expression(this.runtimeStyle['zoom'] = '1',this.innerHTML = this.currentStyle['-ie7-icon'].substr(1,1)+'&nbsp;')}.mce-i-save{-ie7-icon:"\e000"}.mce-i-newdocument{-ie7-icon:"\e001"}.mce-i-fullpage{-ie7-icon:"\e002"}.mce-i-alignleft{-ie7-icon:"\e003"}.mce-i-aligncenter{-ie7-icon:"\e004"}.mce-i-alignright{-ie7-icon:"\e005"}.mce-i-alignjustify{-ie7-icon:"\e006"}.mce-i-cut{-ie7-icon:"\e007"}.mce-i-paste{-ie7-icon:"\e008"}.mce-i-searchreplace{-ie7-icon:"\e009"}.mce-i-bullist{-ie7-icon:"\e00a"}.mce-i-numlist{-ie7-icon:"\e00b"}.mce-i-indent{-ie7-icon:"\e00c"}.mce-i-outdent{-ie7-icon:"\e00d"}.mce-i-blockquote{-ie7-icon:"\e00e"}.mce-i-undo{-ie7-icon:"\e00f"}.mce-i-redo{-ie7-icon:"\e010"}.mce-i-link{-ie7-icon:"\e011"}.mce-i-unlink{-ie7-icon:"\e012"}.mce-i-anchor{-ie7-icon:"\e013"}.mce-i-image{-ie7-icon:"\e014"}.mce-i-media{-ie7-icon:"\e015"}.mce-i-help{-ie7-icon:"\e016"}.mce-i-code{-ie7-icon:"\e017"}.mce-i-inserttime{-ie7-icon:"\e018"}.mce-i-preview{-ie7-icon:"\e019"}.mce-i-forecolor{-ie7-icon:"\e01a"}.mce-i-backcolor{-ie7-icon:"\e01a"}.mce-i-table{-ie7-icon:"\e01b"}.mce-i-hr{-ie7-icon:"\e01c"}.mce-i-removeformat{-ie7-icon:"\e01d"}.mce-i-subscript{-ie7-icon:"\e01e"}.mce-i-superscript{-ie7-icon:"\e01f"}.mce-i-charmap{-ie7-icon:"\e020"}.mce-i-emoticons{-ie7-icon:"\e021"}.mce-i-print{-ie7-icon:"\e022"}.mce-i-fullscreen{-ie7-icon:"\e023"}.mce-i-spellchecker{-ie7-icon:"\e024"}.mce-i-nonbreaking{-ie7-icon:"\e025"}.mce-i-template{-ie7-icon:"\e026"}.mce-i-pagebreak{-ie7-icon:"\e027"}.mce-i-restoredraft{-ie7-icon:"\e028"}.mce-i-untitled{-ie7-icon:"\e029"}.mce-i-bold{-ie7-icon:"\e02a"}.mce-i-italic{-ie7-icon:"\e02b"}.mce-i-underline{-ie7-icon:"\e02c"}.mce-i-strikethrough{-ie7-icon:"\e02d"}.mce-i-visualchars{-ie7-icon:"\e02e"}.mce-i-ltr{-ie7-icon:"\e02f"}.mce-i-rtl{-ie7-icon:"\e030"}.mce-i-copy{-ie7-icon:"\e031"}.mce-i-resize{-ie7-icon:"\e032"}.mce-i-browse{-ie7-icon:"\e034"}.mce-i-checkbox,.mce-i-selected{-ie7-icon:"\e033"}.mce-i-selected{visibility:hidden}.mce-i-backcolor{background:#BBB} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/skin.min.css b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/skin.min.css
new file mode 100755
index 0000000..23a89fd
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/skins/lightgray/skin.min.css
@@ -0,0 +1 @@
+.mce-container,.mce-container *,.mce-widget,.mce-widget *{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:#000;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;-webkit-tap-highlight-color:transparent;line-height:normal;font-weight:normal;text-align:left}.mce-container *[unselectable]{-moz-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}.mce-container ::-webkit-scrollbar{width:8px;height:8px;-webkit-border-radius:4px}.mce-container ::-webkit-scrollbar-track,.mce-container ::-webkit-scrollbar-track-piece{background-color:transparent}.mce-container ::-webkit-scrollbar-thumb{background-color:rgba(53,57,71,0.3);width:6px;height:6px;-webkit-border-radius:4px}.mce-fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.mce-fade.mce-in{opacity:1}.mce-tinymce{visibility:visible!important;position:relative}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;background:#FFF;height:100%;z-index:100}div.mce-fullscreen{position:fixed;top:0;left:0;width:100%;height:auto}.mce-tinymce{display:block;border-radius:2px}.mce-wordcount{position:absolute;top:0;right:0;padding:8px}.mce-edit-area{background:#FFF;filter:none}.mce-statusbar{position:relative}.mce-statusbar .mce-container-body{position:relative}.mce-fullscreen .mce-resizehandle{display:none}.mce-charmap{border-collapse:collapse}.mce-charmap td{cursor:default;border:1px solid #c5c5c5;width:20px;height:20px;line-height:20px;text-align:center;vertical-align:middle;padding:2px}.mce-charmap td div{text-align:center}.mce-charmap td:hover{background:#d9d9d9}.mce-grid td div{border:1px solid #808080;width:12px;height:12px;margin:2px;cursor:pointer}.mce-grid td div:hover{border-color:black}.mce-grid td div:focus{border-color:#59a5e1;outline:1px solid rgba(82,168,236,0.8);border-color:rgba(82,168,236,0.8)}.mce-grid{border-spacing:2px;border-collapse:separate}.mce-grid a{display:block;border:1px solid transparent}.mce-grid a:hover{border-color:#c5c5c5}.mce-grid-border{margin:0 4px 0 4px}.mce-grid-border a{border-color:#e8e8e8;width:13px;height:13px}.mce-grid-border a:hover,.mce-grid-border a.mce-active{border-color:#c4daff;background:#deeafa}.mce-text-center{text-align:center}div.mce-tinymce-inline{width:100%;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.mce-container,.mce-container-body{display:block}.mce-autoscroll{overflow:hidden}.mce-scrollbar{position:absolute;width:7px;height:100%;top:2px;right:2px;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-scrollbar-h{top:auto;right:auto;left:2px;bottom:2px;width:100%;height:7px}.mce-scrollbar-thumb{position:absolute;background-color:#000;border:1px solid #888;border-color:rgba(85,85,85,0.6);width:5px;height:100%;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}.mce-scrollbar-h .mce-scrollbar-thumb{width:100%;height:5px}.mce-scrollbar:hover,.mce-scrollbar.mce-active{background-color:#AAA;opacity:.6;filter:alpha(opacity=60);zoom:1;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}.mce-scroll{position:relative}.mce-panel{border:0 solid #9e9e9e;background-color:#f0f0f0;background-image:-moz-linear-gradient(top,#fdfdfd,#ddd);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fdfdfd),to(#ddd));background-image:-webkit-linear-gradient(top,#fdfdfd,#ddd);background-image:-o-linear-gradient(top,#fdfdfd,#ddd);background-image:linear-gradient(to bottom,#fdfdfd,#ddd);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffdfdfd',endColorstr='#ffdddddd',GradientType=0);zoom:1}.mce-floatpanel{position:absolute;-webkit-box-shadow:#ccc 5px 5px 5px;-moz-box-shadow:#ccc 5px 5px 5px;box-shadow:#ccc 5px 5px 5px}.mce-floatpanel.mce-fixed{position:fixed}.mce-floatpanel .mce-arrow,.mce-floatpanel .mce-arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.mce-floatpanel .mce-arrow{border-width:11px}.mce-floatpanel .mce-arrow:after{border-width:10px;content:""}.mce-floatpanel.mce-popover{top:0;left:0;background:#fff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2)}.mce-floatpanel.mce-popover.mce-bottom{margin-top:10px}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.mce-floatpanel.mce-popover.mce-bottom.mce-start{margin-left:-22px}.mce-floatpanel.mce-popover.mce-bottom.mce-start>.mce-arrow{left:20px}.mce-floatpanel.mce-popover.mce-bottom.mce-end{margin-left:22px}.mce-floatpanel.mce-popover.mce-bottom.mce-end>.mce-arrow{right:10px;left:auto}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;background:#FFF;height:100%}div.mce-fullscreen{position:fixed;top:0;left:0}#mce-modal-block{opacity:0;filter:alpha(opacity=0);zoom:1;position:fixed;left:0;top:0;width:100%;height:100%;background:#000}#mce-modal-block.mce-in{opacity:.3;filter:alpha(opacity=30);zoom:1}.mce-window-move{cursor:move}.mce-window{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;background:#FFF;position:fixed;top:0;left:0;opacity:0;-webkit-transition:opacity 150ms ease-in;transition:opacity 150ms ease-in}.mce-window.mce-in{opacity:1}.mce-window-head{padding:9px 15px;border-bottom:1px solid #EEE;position:relative}.mce-window-head .mce-close{position:absolute;right:15px;top:9px;font-size:20px;font-weight:bold;line-height:20px;color:#CCC;text-shadow:0 1px 0 white;cursor:pointer;height:20px;overflow:hidden}.mce-close:hover{color:#AAA}.mce-window-head .mce-title{display:inline-block;*display:inline;*zoom:1;line-height:20px;font-size:20px;font-weight:bold;text-rendering:optimizelegibility;padding-right:10px}.mce-window .mce-container-body{display:block}.mce-foot{display:block;background-color:whiteSmoke;border-top:1px solid #DDD;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.mce-window-head .mce-dragh{position:absolute;top:0;left:0;cursor:move;width:90%;height:100%}.mce-window iframe{width:100%;height:100%}.mce-window.mce-fullscreen,.mce-window.mce-fullscreen .mce-foot{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.mce-abs-layout{position:relative}body .mce-abs-layout-item,.mce-abs-end{position:absolute}.mce-abs-end{width:1px;height:1px}.mce-container-body.mce-abs-layout{overflow:hidden}.mce-tooltip{position:absolute;padding:5px;opacity:.8;filter:alpha(opacity=80);zoom:1}.mce-tooltip-inner{font-size:11px;background-color:#000;color:#fff;max-width:200px;padding:5px 8px 4px 8px;text-align:center;white-space:normal}.mce-tooltip-inner{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.mce-tooltip-inner{-webkit-box-shadow:0 0 5px #000;-moz-box-shadow:0 0 5px #000;box-shadow:0 0 5px #000}.mce-tooltip-arrow{position:absolute;width:0;height:0;line-height:0;border:5px dashed #000}.mce-tooltip-arrow-n{border-bottom-color:#000}.mce-tooltip-arrow-s{border-top-color:#000}.mce-tooltip-arrow-e{border-left-color:#000}.mce-tooltip-arrow-w{border-right-color:#000}.mce-tooltip-nw,.mce-tooltip-sw{margin-left:-14px}.mce-tooltip-n .mce-tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-style:solid;border-top:0;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-nw .mce-tooltip-arrow{top:0;left:10px;border-bottom-style:solid;border-top:0;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-ne .mce-tooltip-arrow{top:0;right:10px;border-bottom-style:solid;border-top:0;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-s .mce-tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-style:solid;border-bottom:0;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-sw .mce-tooltip-arrow{bottom:0;left:10px;border-top-style:solid;border-bottom:0;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-se .mce-tooltip-arrow{bottom:0;right:10px;border-top-style:solid;border-bottom:0;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-e .mce-tooltip-arrow{right:0;top:50%;margin-top:-5px;border-left-style:solid;border-right:0;border-top-color:transparent;border-bottom-color:transparent}.mce-tooltip-w .mce-tooltip-arrow{left:0;top:50%;margin-top:-5px;border-right-style:solid;border-left:none;border-top-color:transparent;border-bottom-color:transparent}.mce-btn{border:1px solid #c5c5c5;position:relative;color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f0f0f0;background-image:-moz-linear-gradient(top,#fff,#d9d9d9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#d9d9d9));background-image:-webkit-linear-gradient(top,#fff,#d9d9d9);background-image:-o-linear-gradient(top,#fff,#d9d9d9);background-image:linear-gradient(to bottom,#fff,#d9d9d9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffd9d9d9',GradientType=0);zoom:1;border-color:#d9d9d9 #d9d9d9 #b3b3b3;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);display:inline-block;*display:inline;*zoom:1;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.mce-btn:hover,.mce-btn:focus{text-decoration:none;color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#e3e3e3;background-image:-moz-linear-gradient(top,#f2f2f2,#ccc);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#ccc));background-image:-webkit-linear-gradient(top,#f2f2f2,#ccc);background-image:-o-linear-gradient(top,#f2f2f2,#ccc);background-image:linear-gradient(to bottom,#f2f2f2,#ccc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffcccccc',GradientType=0);zoom:1;border-color:#ccc #ccc #a6a6a6;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25)}.mce-btn.mce-disabled,.mce-btn.mce-disabled:hover{cursor:default;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:.65;filter:alpha(opacity=65);zoom:1}.mce-btn.mce-active,.mce-btn.mce-active:hover{color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#d6d6d6;background-image:-moz-linear-gradient(top,#e6e6e6,#bfbfbf);background-image:-webkit-gradient(linear,0 0,0 100%,from(#e6e6e6),to(#bfbfbf));background-image:-webkit-linear-gradient(top,#e6e6e6,#bfbfbf);background-image:-o-linear-gradient(top,#e6e6e6,#bfbfbf);background-image:linear-gradient(to bottom,#e6e6e6,#bfbfbf);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6',endColorstr='#ffbfbfbf',GradientType=0);zoom:1;border-color:#bfbfbf #bfbfbf #999;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.mce-btn button{padding:4px 10px;font-size:14px;line-height:20px;*line-height:16px;cursor:pointer;color:#333;text-align:center;overflow:visible;-webkit-appearance:none}.mce-btn button::-moz-focus-inner{border:0;padding:0}.mce-btn i{text-shadow:1px 1px #fff}.mce-primary{min-width:50px;color:#fff;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);zoom:1;border-color:#04c #04c #002b80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25)}.mce-primary:hover,.mce-primary:focus{color:#fff;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#005fb3;background-image:-moz-linear-gradient(top,#0077b3,#003cb3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#0077b3),to(#003cb3));background-image:-webkit-linear-gradient(top,#0077b3,#003cb3);background-image:-o-linear-gradient(top,#0077b3,#003cb3);background-image:linear-gradient(to bottom,#0077b3,#003cb3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0077b3',endColorstr='#ff003cb3',GradientType=0);zoom:1;border-color:#003cb3 #003cb3 #026;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25)}.mce-primary button{color:#fff}.mce-btn-large button{padding:9px 14px;font-size:16px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.mce-btn-large i{margin-top:2px}.mce-btn-small button{padding:3px 5px;font-size:12px;line-height:15px}.mce-btn-small i{margin-top:0}.mce-btn .mce-caret{margin-top:8px;*margin-top:6px;margin-left:0}.mce-btn-small .mce-caret{margin-top:6px;*margin-top:4px;margin-left:0}.mce-caret{display:inline-block;*display:inline;*zoom:1;width:0;height:0;vertical-align:top;border-top:4px solid #444;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.mce-disabled .mce-caret{border-top-color:#999}.mce-caret.mce-up{border-bottom:4px solid #444;border-top:0}.mce-btn-group .mce-btn{border-width:1px 0 1px 0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.mce-btn-group .mce-btn:hover,.mce-btn-group .mce-btn:focus{color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#e3e3e3;background-image:-moz-linear-gradient(top,#f2f2f2,#ccc);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#ccc));background-image:-webkit-linear-gradient(top,#f2f2f2,#ccc);background-image:-o-linear-gradient(top,#f2f2f2,#ccc);background-image:linear-gradient(to bottom,#f2f2f2,#ccc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffcccccc',GradientType=0);zoom:1;border-color:#ccc #ccc #a6a6a6;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25)}.mce-btn-group .mce-btn.mce-disabled,.mce-btn-group .mce-btn.mce-disabled:hover{-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f0f0f0;background-image:-moz-linear-gradient(top,#fff,#d9d9d9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#d9d9d9));background-image:-webkit-linear-gradient(top,#fff,#d9d9d9);background-image:-o-linear-gradient(top,#fff,#d9d9d9);background-image:linear-gradient(to bottom,#fff,#d9d9d9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffd9d9d9',GradientType=0);zoom:1;border-color:#d9d9d9 #d9d9d9 #b3b3b3;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25)}.mce-btn-group .mce-btn.mce-active,.mce-btn-group .mce-btn.mce-active:hover,.mce-btn-group .mce-btn:active{color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#d6d6d6;background-image:-moz-linear-gradient(top,#e6e6e6,#bfbfbf);background-image:-webkit-gradient(linear,0 0,0 100%,from(#e6e6e6),to(#bfbfbf));background-image:-webkit-linear-gradient(top,#e6e6e6,#bfbfbf);background-image:-o-linear-gradient(top,#e6e6e6,#bfbfbf);background-image:linear-gradient(to bottom,#e6e6e6,#bfbfbf);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6',endColorstr='#ffbfbfbf',GradientType=0);zoom:1;border-color:#bfbfbf #bfbfbf #999;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.mce-btn-group .mce-btn.mce-disabled button{opacity:.65;filter:alpha(opacity=65);zoom:1}.mce-btn-group .mce-first{border-left:1px solid #c5c5c5;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.mce-btn-group .mce-last{border-right:1px solid #c5c5c5;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.mce-btn-group .mce-first.mce-last{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.mce-btn-group .mce-btn.mce-flow-layout-item{margin:0}.mce-checkbox{cursor:pointer}i.mce-i-checkbox{margin:0 3px 0 0;border:1px solid #c5c5c5;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);background-color:#f0f0f0;background-image:-moz-linear-gradient(top,#fdfdfd,#ddd);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fdfdfd),to(#ddd));background-image:-webkit-linear-gradient(top,#fdfdfd,#ddd);background-image:-o-linear-gradient(top,#fdfdfd,#ddd);background-image:linear-gradient(to bottom,#fdfdfd,#ddd);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffdfdfd',endColorstr='#ffdddddd',GradientType=0);zoom:1;text-indent:-10em;*font-size:0;*line-height:0;*text-indent:0}.mce-checked i.mce-i-checkbox{color:#000;font-size:16px;line-height:16px;text-indent:0}.mce-checkbox:focus i.mce-i-checkbox{border:1px solid #59a5e1;border:1px solid rgba(82,168,236,0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}.mce-colorbutton .mce-ico{position:relative}.mce-colorpicker{background:#FFF}.mce-colorbutton-grid{margin:4px}.mce-colorbutton button{padding-right:4px}.mce-colorbutton .mce-preview{padding-right:3px;display:block;position:absolute;left:50%;top:50%;margin-left:-14px;margin-top:7px;background:gray;width:13px;height:2px;overflow:hidden}.mce-colorbutton.mce-btn-small .mce-preview{margin-left:-17px;padding-right:0;width:16px}.mce-colorbutton .mce-open{padding-left:4px;border-left:1px solid transparent;border-right:1px solid transparent}.mce-colorbutton:hover .mce-open{border-left-color:#c5c5c5;border-right-color:#c5c5c5}.mce-combobox{display:inline-block;*display:inline;*zoom:1;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;width:100px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.mce-combobox input{border:1px solid #c5c5c5;border-right-color:rgba(0,0,0,0.15);height:28px}.mce-combobox.mce-has-open input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.mce-combobox .mce-btn{border-left:0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.mce-combobox button{padding-right:8px;padding-left:8px}.mce-combobox *:focus{border-color:#59a5e1;border-color:rgba(82,168,236,0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}.mce-path{display:inline-block;*display:inline;*zoom:1;padding:8px;white-space:normal}.mce-path .mce-txt{display:inline-block;padding-right:3px}.mce-path .mce-path-body{display:inline-block}.mce-path-item{display:inline-block;*display:inline;*zoom:1;cursor:pointer;color:#000}.mce-path-item:hover{text-decoration:underline}.mce-path-item:focus{background:gray;color:white}.mce-path .mce-divider{display:inline}.mce-fieldset{border:0 solid #9e9e9e;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.mce-fieldset>.mce-container-body{margin-top:-15px}.mce-fieldset-title{margin-left:5px;padding:0 5px 0 5px}.mce-fit-layout{display:inline-block;*display:inline;*zoom:1}.mce-fit-layout-item{position:absolute}.mce-flow-layout-item{display:inline-block;*display:inline;*zoom:1}.mce-flow-layout-item{margin:2px 0 2px 2px}.mce-flow-layout-item.mce-last{margin-right:2px}.mce-flow-layout{white-space:normal}.mce-tinymce-inline .mce-flow-layout{white-space:nowrap}.mce-iframe{border:0 solid #c5c5c5;width:100%;height:100%}.mce-label{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 1px rgba(255,255,255,0.75);border:0 solid #c5c5c5;overflow:hidden}.mce-label.mce-autoscroll{overflow:auto}.mce-label-disabled .mce-text{color:#999}.mce-label.mce-multiline{white-space:pre-wrap}.mce-menubar .mce-menubtn{border-color:transparent;background:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;filter:none}.mce-menubar{border:1px solid #ddd}.mce-menubar .mce-menubtn button{color:#000}.mce-menubar .mce-menubtn:hover,.mce-menubar .mce-menubtn.mce-active,.mce-menubar .mce-menubtn:focus{border-color:transparent;background:#ddd;filter:none}.mce-menubtn.mce-disabled span{color:#999}.mce-menubtn span{margin-right:2px;line-height:20px;*line-height:16px}.mce-menubtn.mce-btn-small span{font-size:12px;line-height:15px;*line-height:16px}.mce-menubtn.mce-fixed-width span{display:inline-block;overflow-x:hidden;text-overflow:ellipsis;width:90px}.mce-menubtn.mce-fixed-width.mce-btn-small span{width:70px}.mce-listbox button{text-align:left;padding-right:20px;position:relative}.mce-listbox .mce-caret{position:absolute;margin-top:-2px;right:8px;top:50%}.mce-menu-item{display:block;padding:6px 15px 6px 12px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap;cursor:pointer;line-height:normal;border-left:4px solid transparent;margin-bottom:1px}.mce-menu-item.mce-disabled .mce-text{color:#999}.mce-menu-item:hover,.mce-menu-item.mce-selected,.mce-menu-item:focus{text-decoration:none;color:#fff;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0);zoom:1}.mce-menu-item:hover .mce-text,.mce-menu-item.mce-selected .mce-text{color:#fff}.mce-menu-item:hover .mce-ico,.mce-menu-item.mce-selected .mce-ico,.mce-menu-item:focus .mce-ico{color:white}.mce-menu-item.mce-disabled:hover{background:#CCC}.mce-menu-shortcut{display:inline-block;color:#999}.mce-menu-shortcut{display:inline-block;*display:inline;*zoom:1;padding:0 15px 0 20px}.mce-menu-item .mce-caret{margin-top:4px;*margin-top:3px;margin-right:6px;border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:4px solid #666}.mce-menu-item.mce-selected .mce-caret,.mce-menu-item:focus .mce-caret{border-left-color:#FFF}.mce-menu-align .mce-menu-shortcut{*margin-top:-2px}.mce-menu-align .mce-menu-shortcut,.mce-menu-align .mce-caret{position:absolute;right:0}.mce-menu-item-sep,.mce-menu-item-sep:hover{padding:0;height:1px;margin:9px 1px;overflow:hidden;background:#e5e5e5;border-bottom:1px solid white;cursor:default;filter:none}.mce-menu-item.mce-active i{visibility:visible}.mce-menu-item.mce-active{background-color:#c8def4;outline:1px solid #c5c5c5}.mce-menu-item-preview.mce-active{border-left:5px solid #aaa;background-color:transparent;outline:0}.mce-menu-item-checkbox.mce-active{background-color:#FFF;outline:0}.mce-menu{filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;z-index:1000;padding:5px 0 5px 0;margin:2px 0 0;min-width:160px;background:#FFF;border:1px solid #CCC;border:1px solid rgba(0,0,0,0.2);z-index:1002;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);max-height:400px;overflow:auto;overflow-x:hidden}.mce-menu i{display:none}.mce-menu-has-icons i{display:inline-block;*display:inline;*zoom:1}.mce-menu-sub-tr-tl{margin:-6px 0 0 -1px}.mce-menu-sub-br-bl{margin:6px 0 0 -1px}.mce-menu-sub-tl-tr{margin:-6px 0 0 1px}.mce-menu-sub-bl-br{margin:6px 0 0 1px}i.mce-radio{padding:1px;margin:0 3px 0 0;background-color:#fafafa;border:1px solid #cacece;-webkit-border-radius:8px;-moz-border-radius:8px;border-radius:8px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);background-color:#f0f0f0;background-image:-moz-linear-gradient(top,#fdfdfd,#ddd);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fdfdfd),to(#ddd));background-image:-webkit-linear-gradient(top,#fdfdfd,#ddd);background-image:-o-linear-gradient(top,#fdfdfd,#ddd);background-image:linear-gradient(to bottom,#fdfdfd,#ddd);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffdfdfd',endColorstr='#ffdddddd',GradientType=0);zoom:1}i.mce-radio:after{font-family:Arial;font-size:12px;color:#000;content:'\25cf'}.mce-container-body .mce-resizehandle{position:absolute;right:0;bottom:0;width:16px;height:16px;visibility:visible;cursor:s-resize;margin:0}.mce-container-body .mce-resizehandle-both{cursor:se-resize}i.mce-i-resize{color:#000}.mce-spacer{visibility:hidden}.mce-splitbtn .mce-open{border-left:1px solid transparent;border-right:1px solid transparent}.mce-splitbtn:hover .mce-open{border-left-color:#c5c5c5;border-right-color:#c5c5c5}.mce-splitbtn button{padding-right:4px}.mce-splitbtn .mce-open{padding-left:4px}.mce-splitbtn .mce-open.mce-active{-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.mce-stack-layout-item{display:block}.mce-tabs{display:block;border-bottom:1px solid #ccc}.mce-tab{display:inline-block;*display:inline;*zoom:1;border:1px solid #ccc;border-width:1px 1px 0 0;background:#e3e3e3;padding:8px;text-shadow:0 1px 1px rgba(255,255,255,0.75);height:13px;cursor:pointer}.mce-tab:hover{background:#fdfdfd}.mce-tab.mce-active{background:#fdfdfd;border-bottom-color:transparent;margin-bottom:-1px;height:14px}.mce-textbox{background:#FFF;border:1px solid #c5c5c5;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);display:inline-block;-webkit-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s;height:28px;resize:none;padding:0 4px 0 4px;white-space:pre-wrap;*white-space:pre;color:#000}.mce-textbox:focus{border-color:rgba(82,168,236,0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}.mce-placeholder .mce-textbox{color:#aaa}.mce-textbox.mce-multiline{padding:4px}.mce-throbber{position:absolute;top:0;left:0;width:100%;height:100%;opacity:.6;filter:alpha(opacity=60);zoom:1;background:#fff url('img/loader.gif') no-repeat center center}@font-face{font-family:'tinymce';src:url('fonts/icomoon.eot');src:url('fonts/icomoon.eot?#iefix') format('embedded-opentype'),url('fonts/icomoon.svg#icomoon') format('svg'),url('fonts/icomoon.woff') format('woff'),url('fonts/icomoon.ttf') format('truetype');font-weight:normal;font-style:normal}@font-face{font-family:'tinymce-small';src:url('fonts/icomoon-small.eot');src:url('fonts/icomoon-small.eot?#iefix') format('embedded-opentype'),url('fonts/icomoon-small.svg#icomoon') format('svg'),url('fonts/icomoon-small.woff') format('woff'),url('fonts/icomoon-small.ttf') format('truetype');font-weight:normal;font-style:normal}.mce-ico{font-family:'tinymce',Arial;font-style:normal;font-weight:normal;font-size:16px;line-height:16px;vertical-align:text-top;-webkit-font-smoothing:antialiased;display:inline-block;background:transparent center center;width:16px;height:16px;color:#333}.mce-btn-small .mce-ico{font-family:'tinymce-small',Arial}.mce-i-save:before{content:"\e000"}.mce-i-newdocument:before{content:"\e001"}.mce-i-fullpage:before{content:"\e002"}.mce-i-alignleft:before{content:"\e003"}.mce-i-aligncenter:before{content:"\e004"}.mce-i-alignright:before{content:"\e005"}.mce-i-alignjustify:before{content:"\e006"}.mce-i-cut:before{content:"\e007"}.mce-i-paste:before{content:"\e008"}.mce-i-searchreplace:before{content:"\e009"}.mce-i-bullist:before{content:"\e00a"}.mce-i-numlist:before{content:"\e00b"}.mce-i-indent:before{content:"\e00c"}.mce-i-outdent:before{content:"\e00d"}.mce-i-blockquote:before{content:"\e00e"}.mce-i-undo:before{content:"\e00f"}.mce-i-redo:before{content:"\e010"}.mce-i-link:before{content:"\e011"}.mce-i-unlink:before{content:"\e012"}.mce-i-anchor:before{content:"\e013"}.mce-i-image:before{content:"\e014"}.mce-i-media:before{content:"\e015"}.mce-i-help:before{content:"\e016"}.mce-i-code:before{content:"\e017"}.mce-i-inserttime:before{content:"\e018"}.mce-i-preview:before{content:"\e019"}.mce-i-forecolor:before{content:"\e01a"}.mce-i-backcolor:before{content:"\e01a"}.mce-i-table:before{content:"\e01b"}.mce-i-hr:before{content:"\e01c"}.mce-i-removeformat:before{content:"\e01d"}.mce-i-subscript:before{content:"\e01e"}.mce-i-superscript:before{content:"\e01f"}.mce-i-charmap:before{content:"\e020"}.mce-i-emoticons:before{content:"\e021"}.mce-i-print:before{content:"\e022"}.mce-i-fullscreen:before{content:"\e023"}.mce-i-spellchecker:before{content:"\e024"}.mce-i-nonbreaking:before{content:"\e025"}.mce-i-template:before{content:"\e026"}.mce-i-pagebreak:before{content:"\e027"}.mce-i-restoredraft:before{content:"\e028"}.mce-i-untitled:before{content:"\e029"}.mce-i-bold:before{content:"\e02a"}.mce-i-italic:before{content:"\e02b"}.mce-i-underline:before{content:"\e02c"}.mce-i-strikethrough:before{content:"\e02d"}.mce-i-visualchars:before{content:"\e02e"}.mce-i-visualblocks:before{content:"\e02e"}.mce-i-ltr:before{content:"\e02f"}.mce-i-rtl:before{content:"\e030"}.mce-i-copy:before{content:"\e031"}.mce-i-resize:before{content:"\e032"}.mce-i-browse:before{content:"\e034"}.mce-i-pastetext:before{content:"\e035"}.mce-i-checkbox:before,.mce-i-selected:before{content:"\e033"}.mce-i-selected{visibility:hidden}i.mce-i-backcolor{text-shadow:none;background:#BBB} \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/themes/modern/theme.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/themes/modern/theme.min.js
new file mode 100755
index 0000000..4a63687
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/themes/modern/theme.min.js
@@ -0,0 +1 @@
+tinymce.ThemeManager.add("modern",function(e){function t(){function t(t){var i,r=[];if(t)return m(t.split(/[ ,]/),function(t){function n(){var n=e.selection;"bullist"==a&&n.selectorChanged("ul > li",function(e,n){for(var i,r=n.parents.length;r--&&(i=n.parents[r].nodeName,"OL"!=i&&"UL"!=i););t.active("UL"==i)}),"numlist"==a&&n.selectorChanged("ol > li",function(e,n){for(var i,r=n.parents.length;r--&&(i=n.parents[r].nodeName,"OL"!=i&&"UL"!=i););t.active("OL"==i)}),t.settings.stateSelector&&n.selectorChanged(t.settings.stateSelector,function(e){t.active(e)},!0),t.settings.disabledStateSelector&&n.selectorChanged(t.settings.disabledStateSelector,function(e){t.disabled(e)})}var a;"|"==t?i=null:u.has(t)?(t={type:t},c.toolbar_items_size&&(t.size=c.toolbar_items_size),r.push(t),i=null):(i||(i={type:"buttongroup",items:[]},r.push(i)),e.buttons[t]&&(a=t,t=e.buttons[a],"function"==typeof t&&(t=t()),t.type=t.type||"button",c.toolbar_items_size&&(t.size=c.toolbar_items_size),t=u.create(t),i.items.push(t),e.initialized?n():e.on("init",n)))}),n.push({type:"toolbar",layout:"flow",items:r}),!0}for(var n=[],i=1;10>i&&t(c["toolbar"+i]);i++);return n.length||t(c.toolbar||h),n}function n(){function t(t){var n;return"|"==t?{text:"|"}:n=e.menuItems[t]}function n(n){var i,r,a,o,s;if(s=tinymce.makeMap((c.removed_menuitems||"").split(/[ ,]/)),c.menu?(r=c.menu[n],o=!0):r=f[n],r){i={text:r.title},a=[],m((r.items||"").split(/[ ,]/),function(e){var n=t(e);n&&!s[e]&&a.push(t(e))}),o||m(e.menuItems,function(e){e.context==n&&("before"==e.separator&&a.push({text:"|"}),e.prependToContext?a.unshift(e):a.push(e),"after"==e.separator&&a.push({text:"|"}))});for(var l=0;l<a.length;l++)"|"==a[l].text&&(0===l||l==a.length-1)&&a.splice(l,1);if(i.menu=a,!i.menu.length)return null}return i}var i,r=[],a=[];if(c.menu)for(i in c.menu)a.push(i);else for(i in f)a.push(i);for(var o=c.menubar?c.menubar.split(/[ ,]/):a,s=0;s<o.length;s++){var l=o[s];l=n(l),l&&r.push(l)}return r}function i(t){function n(e){var n=t.find(e)[0];n&&n.focus()}e.shortcuts.add("Alt+F9","",function(){n("menubar")}),e.shortcuts.add("Alt+F10","",function(){n("toolbar")}),e.shortcuts.add("Alt+F11","",function(){n("elementpath")}),t.on("cancel",function(){e.focus()})}function r(t,n){function i(e){return{width:e.clientWidth,height:e.clientHeight}}var r,a,o,s;r=e.getContainer(),a=e.getContentAreaContainer().firstChild,o=i(r),s=i(a),null!==t&&(t=Math.max(c.min_width||100,t),t=Math.min(c.max_width||65535,t),d.css(r,"width",t+(o.width-s.width)),d.css(a,"width",t)),n=Math.max(c.min_height||100,n),n=Math.min(c.max_height||65535,n),d.css(a,"height",n),e.fire("ResizeEditor")}function a(t,n){var i=e.getContentAreaContainer();l.resizeTo(i.clientWidth+t,i.clientHeight+n)}function o(){function r(){m&&m.moveRel&&m.visible()&&!m._fixed&&m.moveRel(e.getBody(),["tl-bl","bl-tl"])}function a(){m&&(m.show(),r(),d.addClass(e.getBody(),"mce-edit-focus"))}function o(){m&&(m.hide(),d.removeClass(e.getBody(),"mce-edit-focus"))}function s(){return m?(m.visible()||a(),void 0):(m=l.panel=u.create({type:f?"panel":"floatpanel",classes:"tinymce tinymce-inline",layout:"flex",direction:"column",autohide:!1,autofix:!0,fixed:!!f,border:1,items:[c.menubar===!1?null:{type:"menubar",border:"0 0 1 0",items:n()},c.toolbar===!1?null:{type:"panel",name:"toolbar",layout:"stack",items:t()}]}),m.renderTo(f||document.body).reflow(),i(m),a(),e.on("nodeChange",r),e.on("activate",a),e.on("deactivate",o),void 0)}var m,f;return c.fixed_toolbar_container&&(f=d.select(c.fixed_toolbar_container)[0]),c.content_editable=!0,e.on("focus",s),e.on("blur",o),e.on("remove",function(){m&&(m.remove(),m=null)}),{}}function s(a){var o,s,m;return o=l.panel=u.create({type:"panel",classes:"tinymce",style:"visibility: hidden",layout:"stack",border:1,items:[c.menubar===!1?null:{type:"menubar",border:"0 0 1 0",items:n()},c.toolbar===!1?null:{type:"panel",layout:"stack",items:t()},{type:"panel",name:"iframe",layout:"stack",classes:"edit-area",html:"",border:"1 0 0 0"}]}),c.resize!==!1&&(s={type:"resizehandle",direction:c.resize,onResizeStart:function(){var t=e.getContentAreaContainer().firstChild;m={width:t.clientWidth,height:t.clientHeight}},onResize:function(e){"both"==c.resize?r(m.width+e.deltaX,m.height+e.deltaY):r(null,m.height+e.deltaY)}}),c.statusbar!==!1&&o.add({type:"panel",name:"statusbar",classes:"statusbar",layout:"flow",border:"1 0 0 0",items:[{type:"elementpath"},s]}),o.renderBefore(a.targetNode).reflow(),c.width&&tinymce.DOM.setStyle(o.getEl(),"width",c.width),e.on("remove",function(){o.remove(),o=null}),i(o),{iframeContainer:o.find("#iframe")[0].getEl(),editorContainer:o.getEl()}}var l=this,c=e.settings,u=tinymce.ui.Factory,m=tinymce.each,d=tinymce.DOM,f={file:{title:"File",items:"newdocument"},edit:{title:"Edit",items:"undo redo | cut copy paste pastetext | selectall"},insert:{title:"Insert",items:"|"},view:{title:"View",items:"visualaid |"},format:{title:"Format",items:"bold italic underline strikethrough superscript subscript | formats | removeformat"},table:{title:"Table"},tools:{title:"Tools"}},h="undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image";l.renderUI=function(t){var n=c.skin!==!1?c.skin||"lightgray":!1;return n&&(tinymce.Env.documentMode<=7?tinymce.DOM.loadCSS(tinymce.baseURL+"/skins/"+n+"/skin.ie7.min.css"):tinymce.DOM.loadCSS(tinymce.baseURL+"/skins/"+n+"/skin.min.css"),e.contentCSS.push(tinymce.baseURL+"/skins/"+n+"/content"+(e.inline?".inline":"")+".min.css")),e.on("ProgressState",function(e){l.throbber=l.throbber||new tinymce.ui.Throbber(l.panel.getEl("body")),e.state?l.throbber.show(e.time):l.throbber.hide()}),c.inline?o(t):s(t)},l.resizeTo=r,l.resizeBy=a}); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Javascripts/source/tinymce-405/tinymce.min.js b/lib/prado/framework/Web/Javascripts/source/tinymce-405/tinymce.min.js
new file mode 100755
index 0000000..13f1823
--- /dev/null
+++ b/lib/prado/framework/Web/Javascripts/source/tinymce-405/tinymce.min.js
@@ -0,0 +1,10 @@
+// 4.0.5 (2013-08-27)
+!function(e,t){"use strict";function n(e,t){for(var n,r=[],i=0;i<e.length;++i){if(n=s[e[i]]||o(e[i]),!n)throw"module definition dependecy not found: "+e[i];r.push(n)}t.apply(null,r)}function r(e,r,i){if("string"!=typeof e)throw"invalid module definition, module id must be defined and be a string";if(r===t)throw"invalid module definition, dependencies must be specified";if(i===t)throw"invalid module definition, definition function must be specified";n(r,function(){s[e]=i.apply(null,arguments)})}function i(e){return!!s[e]}function o(t){for(var n=e,r=t.split(/[.\/]/),i=0;i<r.length;++i){if(!n[r[i]])return;n=n[r[i]]}return n}function a(n){for(var r=0;r<n.length;r++){for(var i=e,o=n[r],a=o.split(/[.\/]/),l=0;l<a.length-1;++l)i[a[l]]===t&&(i[a[l]]={}),i=i[a[l]];i[a[a.length-1]]=s[o]}}var s={},l="tinymce/dom/EventUtils",c="tinymce/dom/Sizzle",u="tinymce/dom/DomQuery",d="tinymce/html/Styles",f="tinymce/dom/TreeWalker",p="tinymce/util/Tools",h="tinymce/dom/Range",m="tinymce/html/Entities",g="tinymce/Env",v="tinymce/dom/DOMUtils",y="tinymce/dom/ScriptLoader",b="tinymce/AddOnManager",C="tinymce/html/Node",x="tinymce/html/Schema",w="tinymce/html/SaxParser",_="tinymce/html/DomParser",N="tinymce/html/Writer",E="tinymce/html/Serializer",k="tinymce/dom/Serializer",S="tinymce/dom/TridentSelection",T="tinymce/util/VK",R="tinymce/dom/ControlSelection",A="tinymce/dom/Selection",B="tinymce/dom/RangeUtils",D="tinymce/Formatter",L="tinymce/UndoManager",M="tinymce/EnterKey",H="tinymce/ForceBlocks",P="tinymce/EditorCommands",O="tinymce/util/URI",I="tinymce/util/Class",F="tinymce/ui/Selector",W="tinymce/ui/Collection",z="tinymce/ui/DomUtils",V="tinymce/ui/Control",U="tinymce/ui/Factory",q="tinymce/ui/Container",j="tinymce/ui/DragHelper",$="tinymce/ui/Scrollable",K="tinymce/ui/Panel",G="tinymce/ui/Movable",Y="tinymce/ui/Resizable",X="tinymce/ui/FloatPanel",J="tinymce/ui/KeyboardNavigation",Q="tinymce/ui/Window",Z="tinymce/ui/MessageBox",et="tinymce/WindowManager",tt="tinymce/util/Quirks",nt="tinymce/util/Observable",rt="tinymce/Shortcuts",it="tinymce/Editor",ot="tinymce/util/I18n",at="tinymce/FocusManager",st="tinymce/EditorManager",lt="tinymce/LegacyInput",ct="tinymce/util/XHR",ut="tinymce/util/JSON",dt="tinymce/util/JSONRequest",ft="tinymce/util/JSONP",pt="tinymce/util/LocalStorage",ht="tinymce/Compat",mt="tinymce/ui/Layout",gt="tinymce/ui/AbsoluteLayout",vt="tinymce/ui/Tooltip",yt="tinymce/ui/Widget",bt="tinymce/ui/Button",Ct="tinymce/ui/ButtonGroup",xt="tinymce/ui/Checkbox",wt="tinymce/ui/PanelButton",_t="tinymce/ui/ColorButton",Nt="tinymce/ui/ComboBox",Et="tinymce/ui/Path",kt="tinymce/ui/ElementPath",St="tinymce/ui/FormItem",Tt="tinymce/ui/Form",Rt="tinymce/ui/FieldSet",At="tinymce/ui/FilePicker",Bt="tinymce/ui/FitLayout",Dt="tinymce/ui/FlexLayout",Lt="tinymce/ui/FlowLayout",Mt="tinymce/ui/FormatControls",Ht="tinymce/ui/GridLayout",Pt="tinymce/ui/Iframe",Ot="tinymce/ui/Label",It="tinymce/ui/Toolbar",Ft="tinymce/ui/MenuBar",Wt="tinymce/ui/MenuButton",zt="tinymce/ui/ListBox",Vt="tinymce/ui/MenuItem",Ut="tinymce/ui/Menu",qt="tinymce/ui/Radio",jt="tinymce/ui/ResizeHandle",$t="tinymce/ui/Spacer",Kt="tinymce/ui/SplitButton",Gt="tinymce/ui/StackLayout",Yt="tinymce/ui/TabPanel",Xt="tinymce/ui/TextBox",Jt="tinymce/ui/Throbber";r(l,[],function(){function e(e,t,n,r){e.addEventListener?e.addEventListener(t,n,r||!1):e.attachEvent&&e.attachEvent("on"+t,n)}function t(e,t,n,r){e.removeEventListener?e.removeEventListener(t,n,r||!1):e.detachEvent&&e.detachEvent("on"+t,n)}function n(e,t){function n(){return!1}function r(){return!0}var i,o=t||{},l;for(i in e)s[i]||(o[i]=e[i]);if(o.target||(o.target=o.srcElement||document),e&&a.test(e.type)&&e.pageX===l&&e.clientX!==l){var c=o.target.ownerDocument||document,u=c.documentElement,d=c.body;o.pageX=e.clientX+(u&&u.scrollLeft||d&&d.scrollLeft||0)-(u&&u.clientLeft||d&&d.clientLeft||0),o.pageY=e.clientY+(u&&u.scrollTop||d&&d.scrollTop||0)-(u&&u.clientTop||d&&d.clientTop||0)}return o.preventDefault=function(){o.isDefaultPrevented=r,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},o.stopPropagation=function(){o.isPropagationStopped=r,e&&(e.stopPropagation?e.stopPropagation():e.cancelBubble=!0)},o.stopImmediatePropagation=function(){o.isImmediatePropagationStopped=r,o.stopPropagation()},o.isDefaultPrevented||(o.isDefaultPrevented=n,o.isPropagationStopped=n,o.isImmediatePropagationStopped=n),o}function r(n,r,i){function o(){i.domLoaded||(i.domLoaded=!0,r(c))}function a(){"complete"===l.readyState&&(t(l,"readystatechange",a),o())}function s(){try{l.documentElement.doScroll("left")}catch(e){return setTimeout(s,0),void 0}o()}var l=n.document,c={type:"ready"};return i.domLoaded?(r(c),void 0):(l.addEventListener?e(n,"DOMContentLoaded",o):(e(l,"readystatechange",a),l.documentElement.doScroll&&n===n.top&&s()),e(n,"load",o),void 0)}function i(){function i(e,t){var n,r,i,o;if(n=s[t][e.type])for(r=0,i=n.length;i>r;r++)if(o=n[r],o&&o.func.call(o.scope,e)===!1&&e.preventDefault(),e.isImmediatePropagationStopped())return}var a=this,s={},l,c,u,d,f;c=o+(+new Date).toString(32),d="onmouseenter"in document.documentElement,u="onfocusin"in document.documentElement,f={mouseenter:"mouseover",mouseleave:"mouseout"},l=1,a.domLoaded=!1,a.events=s,a.bind=function(t,o,p,h){function m(e){i(n(e||_.event),g)}var g,v,y,b,C,x,w,_=window;if(t&&3!==t.nodeType&&8!==t.nodeType){for(t[c]?g=t[c]:(g=l++,t[c]=g,s[g]={}),h=h||t,o=o.split(" "),y=o.length;y--;)b=o[y],x=m,C=w=!1,"DOMContentLoaded"===b&&(b="ready"),a.domLoaded&&"ready"===b&&"complete"==t.readyState?p.call(h,n({type:b})):(d||(C=f[b],C&&(x=function(e){var t,r;if(t=e.currentTarget,r=e.relatedTarget,r&&t.contains)r=t.contains(r);else for(;r&&r!==t;)r=r.parentNode;r||(e=n(e||_.event),e.type="mouseout"===e.type?"mouseleave":"mouseenter",e.target=t,i(e,g))})),u||"focusin"!==b&&"focusout"!==b||(w=!0,C="focusin"===b?"focus":"blur",x=function(e){e=n(e||_.event),e.type="focus"===e.type?"focusin":"focusout",i(e,g)}),v=s[g][b],v?"ready"===b&&a.domLoaded?p({type:b}):v.push({func:p,scope:h}):(s[g][b]=v=[{func:p,scope:h}],v.fakeName=C,v.capture=w,v.nativeHandler=x,"ready"===b?r(t,x,a):e(t,C||b,x,w)));return t=v=0,p}},a.unbind=function(e,n,r){var i,o,l,u,d,f;if(!e||3===e.nodeType||8===e.nodeType)return a;if(i=e[c]){if(f=s[i],n){for(n=n.split(" "),l=n.length;l--;)if(d=n[l],o=f[d]){if(r)for(u=o.length;u--;)o[u].func===r&&o.splice(u,1);r&&0!==o.length||(delete f[d],t(e,o.fakeName||d,o.nativeHandler,o.capture))}}else{for(d in f)o=f[d],t(e,o.fakeName||d,o.nativeHandler,o.capture);f={}}for(d in f)return a;delete s[i];try{delete e[c]}catch(p){e[c]=null}}return a},a.fire=function(e,t,r){var o;if(!e||3===e.nodeType||8===e.nodeType)return a;r=n(null,r),r.type=t,r.target=e;do o=e[c],o&&i(r,o),e=e.parentNode||e.ownerDocument||e.defaultView||e.parentWindow;while(e&&!r.isPropagationStopped());return a},a.clean=function(e){var t,n,r=a.unbind;if(!e||3===e.nodeType||8===e.nodeType)return a;if(e[c]&&r(e),e.getElementsByTagName||(e=e.document),e&&e.getElementsByTagName)for(r(e),n=e.getElementsByTagName("*"),t=n.length;t--;)e=n[t],e[c]&&r(e);return a},a.destroy=function(){s={}},a.cancel=function(e){return e&&(e.preventDefault(),e.stopImmediatePropagation()),!1}}var o="mce-data-",a=/^(?:mouse|contextmenu)|click/,s={keyLocation:1,layerX:1,layerY:1};return i.Event=new i,i.Event.bind(window,"ready",function(){}),i}),r(c,[],function(){function e(e){return gt.test(e+"")}function n(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>N.cacheLength&&delete e[t.shift()],e[n]=r,r}}function i(e){return e[F]=!0,e}function o(e){var t=D.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t=null}}function a(e,t,n,r){var i,o,a,s,l,c,u,p,h,m;if((t?t.ownerDocument||t:W)!==D&&B(t),t=t||D,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(M&&!r){if(i=vt.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&I(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return et.apply(n,t.getElementsByTagName(e)),n;if((a=i[3])&&z.getElementsByClassName&&t.getElementsByClassName)return et.apply(n,t.getElementsByClassName(a)),n}if(z.qsa&&!H.test(e)){if(u=!0,p=F,h=t,m=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){for(c=d(e),(u=t.getAttribute("id"))?p=u.replace(Ct,"\\$&"):t.setAttribute("id",p),p="[id='"+p+"'] ",l=c.length;l--;)c[l]=p+f(c[l]);h=mt.test(e)&&t.parentNode||t,m=c.join(",")}if(m)try{return et.apply(n,h.querySelectorAll(m)),n}catch(g){}finally{u||t.removeAttribute("id")}}}return C(e.replace(ct,"$1"),t,n,r)}function s(e,t){var n=t&&e,r=n&&(~t.sourceIndex||X)-(~e.sourceIndex||X);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function l(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function c(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function u(e){return i(function(t){return t=+t,i(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function d(e,t){var n,r,i,o,s,l,c,u=j[e+" "];if(u)return t?0:u.slice(0);for(s=e,l=[],c=N.preFilter;s;){(!n||(r=ut.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=dt.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(ct," ")}),s=s.slice(n.length));for(o in N.filter)!(r=ht[o].exec(s))||c[o]&&!(r=c[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?a.error(e):j(e,l).slice(0)}function f(e){for(var t=0,n=e.length,r="";n>t;t++)r+=e[t].value;return r}function p(e,t,n){var r=t.dir,i=n&&"parentNode"===r,o=U++;return t.first?function(t,n,o){for(;t=t[r];)if(1===t.nodeType||i)return e(t,n,o)}:function(t,n,a){var s,l,c,u=V+" "+o;if(a){for(;t=t[r];)if((1===t.nodeType||i)&&e(t,n,a))return!0}else for(;t=t[r];)if(1===t.nodeType||i)if(c=t[F]||(t[F]={}),(l=c[r])&&l[0]===u){if((s=l[1])===!0||s===_)return s===!0}else if(l=c[r]=[u],l[1]=e(t,n,a)||_,l[1]===!0)return!0}}function h(e){return e.length>1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function m(e,t,n,r,i){for(var o,a=[],s=0,l=e.length,c=null!=t;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),c&&t.push(s));return a}function g(e,t,n,r,o,a){return r&&!r[F]&&(r=g(r)),o&&!o[F]&&(o=g(o,a)),i(function(i,a,s,l){var c,u,d,f=[],p=[],h=a.length,g=i||b(t||"*",s.nodeType?[s]:s,[]),v=!e||!i&&t?g:m(g,f,e,s,l),y=n?o||(i?e:h||r)?[]:a:v;if(n&&n(v,y,s,l),r)for(c=m(y,p),r(c,[],s,l),u=c.length;u--;)(d=c[u])&&(y[p[u]]=!(v[p[u]]=d));if(i){if(o||e){if(o){for(c=[],u=y.length;u--;)(d=y[u])&&c.push(v[u]=d);o(null,y=[],c,l)}for(u=y.length;u--;)(d=y[u])&&(c=o?nt.call(i,d):f[u])>-1&&(i[c]=!(a[c]=d))}}else y=m(y===a?y.splice(h,y.length):y),o?o(null,a,y,l):et.apply(a,y)})}function v(e){for(var t,n,r,i=e.length,o=N.relative[e[0].type],a=o||N.relative[" "],s=o?1:0,l=p(function(e){return e===t},a,!0),c=p(function(e){return nt.call(t,e)>-1},a,!0),u=[function(e,n,r){return!o&&(r||n!==T)||((t=n).nodeType?l(e,n,r):c(e,n,r))}];i>s;s++)if(n=N.relative[e[s].type])u=[p(h(u),n)];else{if(n=N.filter[e[s].type].apply(null,e[s].matches),n[F]){for(r=++s;i>r&&!N.relative[e[r].type];r++);return g(s>1&&h(u),s>1&&f(e.slice(0,s-1)).replace(ct,"$1"),n,r>s&&v(e.slice(s,r)),i>r&&v(e=e.slice(r)),i>r&&f(e))}u.push(n)}return h(u)}function y(e,t){var n=0,r=t.length>0,o=e.length>0,s=function(i,s,l,c,u){var d,f,p,h=[],g=0,v="0",y=i&&[],b=null!=u,C=T,x=i||o&&N.find.TAG("*",u&&s.parentNode||s),w=V+=null==C?1:Math.random()||.1;for(b&&(T=s!==D&&s,_=n);null!=(d=x[v]);v++){if(o&&d){for(f=0;p=e[f++];)if(p(d,s,l)){c.push(d);break}b&&(V=w,_=++n)}r&&((d=!p&&d)&&g--,i&&y.push(d))}if(g+=v,r&&v!==g){for(f=0;p=t[f++];)p(y,h,s,l);if(i){if(g>0)for(;v--;)y[v]||h[v]||(h[v]=Q.call(c));h=m(h)}et.apply(c,h),b&&!i&&h.length>0&&g+t.length>1&&a.uniqueSort(c)}return b&&(V=w,T=C),y};return r?i(s):s}function b(e,t,n){for(var r=0,i=t.length;i>r;r++)a(e,t[r],n);return n}function C(e,t,n,r){var i,o,a,s,l,c=d(e);if(!r&&1===c.length){if(o=c[0]=c[0].slice(0),o.length>2&&"ID"===(a=o[0]).type&&9===t.nodeType&&M&&N.relative[o[1].type]){if(t=(N.find.ID(a.matches[0].replace(wt,_t),t)||[])[0],!t)return n;e=e.slice(o.shift().value.length)}for(i=ht.needsContext.test(e)?0:o.length;i--&&(a=o[i],!N.relative[s=a.type]);)if((l=N.find[s])&&(r=l(a.matches[0].replace(wt,_t),mt.test(o[0].type)&&t.parentNode||t))){if(o.splice(i,1),e=r.length&&f(o),!e)return et.apply(n,r),n;break}}return S(e,c)(r,t,!M,n,mt.test(e)),n}function x(){}var w,_,N,E,k,S,T,R,A,B,D,L,M,H,P,O,I,F="sizzle"+-new Date,W=window.document,z={},V=0,U=0,q=n(),j=n(),$=n(),K=!1,G=function(){return 0},Y=typeof t,X=1<<31,J=[],Q=J.pop,Z=J.push,et=J.push,tt=J.slice,nt=J.indexOf||function(e){for(var t=0,n=this.length;n>t;t++)if(this[t]===e)return t;return-1},rt="[\\x20\\t\\r\\n\\f]",it="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",ot=it.replace("w","w#"),at="([*^$|!~]?=)",st="\\["+rt+"*("+it+")"+rt+"*(?:"+at+rt+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+ot+")|)|)"+rt+"*\\]",lt=":("+it+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+st.replace(3,8)+")*)|.*)\\)|)",ct=new RegExp("^"+rt+"+|((?:^|[^\\\\])(?:\\\\.)*)"+rt+"+$","g"),ut=new RegExp("^"+rt+"*,"+rt+"*"),dt=new RegExp("^"+rt+"*([\\x20\\t\\r\\n\\f>+~])"+rt+"*"),ft=new RegExp(lt),pt=new RegExp("^"+ot+"$"),ht={ID:new RegExp("^#("+it+")"),CLASS:new RegExp("^\\.("+it+")"),NAME:new RegExp("^\\[name=['\"]?("+it+")['\"]?\\]"),TAG:new RegExp("^("+it.replace("w","w*")+")"),ATTR:new RegExp("^"+st),PSEUDO:new RegExp("^"+lt),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+rt+"*(even|odd|(([+-]|)(\\d*)n|)"+rt+"*(?:([+-]|)"+rt+"*(\\d+)|))"+rt+"*\\)|)","i"),needsContext:new RegExp("^"+rt+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+rt+"*((?:-\\d)?\\d*)"+rt+"*\\)|)(?=[^-]|$)","i")},mt=/[\x20\t\r\n\f]*[+~]/,gt=/^[^{]+\{\s*\[native code/,vt=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,yt=/^(?:input|select|textarea|button)$/i,bt=/^h\d$/i,Ct=/'|\\/g,xt=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,wt=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,_t=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{et.apply(J=tt.call(W.childNodes),W.childNodes),J[W.childNodes.length].nodeType}catch(Nt){et={apply:J.length?function(e,t){Z.apply(e,tt.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}k=a.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},B=a.setDocument=function(n){var r=n?n.ownerDocument||n:W;return r!==D&&9===r.nodeType&&r.documentElement?(D=r,L=r.documentElement,M=!k(r),z.getElementsByTagName=o(function(e){return e.appendChild(r.createComment("")),!e.getElementsByTagName("*").length}),z.attributes=o(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),z.getElementsByClassName=o(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),z.getByName=o(function(e){e.id=F+0,e.appendChild(D.createElement("a")).setAttribute("name",F),e.appendChild(D.createElement("i")).setAttribute("name",F),L.appendChild(e);var t=r.getElementsByName&&r.getElementsByName(F).length===2+r.getElementsByName(F+0).length;return L.removeChild(e),t}),z.sortDetached=o(function(e){return e.compareDocumentPosition&&1&e.compareDocumentPosition(D.createElement("div"))}),N.attrHandle=o(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==Y&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},z.getByName?(N.find.ID=function(e,t){if(typeof t.getElementById!==Y&&M){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},N.filter.ID=function(e){var t=e.replace(wt,_t);return function(e){return e.getAttribute("id")===t}}):(N.find.ID=function(e,n){if(typeof n.getElementById!==Y&&M){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==Y&&r.getAttributeNode("id").value===e?[r]:t:[]}},N.filter.ID=function(e){var t=e.replace(wt,_t);return function(e){var n=typeof e.getAttributeNode!==Y&&e.getAttributeNode("id");return n&&n.value===t}}),N.find.TAG=z.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==Y?t.getElementsByTagName(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},N.find.NAME=z.getByName&&function(e,t){return typeof t.getElementsByName!==Y?t.getElementsByName(name):void 0},N.find.CLASS=z.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==Y&&M?t.getElementsByClassName(e):void 0},P=[],H=[":focus"],(z.qsa=e(r.querySelectorAll))&&(o(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||H.push("\\["+rt+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||H.push(":checked")}),o(function(e){e.innerHTML="<input type='hidden' i=''/>",e.querySelectorAll("[i^='']").length&&H.push("[*^$]="+rt+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||H.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),H.push(",.*:")})),(z.matchesSelector=e(O=L.matchesSelector||L.mozMatchesSelector||L.webkitMatchesSelector||L.oMatchesSelector||L.msMatchesSelector))&&o(function(e){z.disconnectedMatch=O.call(e,"div"),O.call(e,"[s!='']:x"),P.push("!=",lt)}),H=new RegExp(H.join("|")),P=P.length&&new RegExp(P.join("|")),I=e(L.contains)||L.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},G=L.compareDocumentPosition?function(e,t){if(e===t)return K=!0,0;var n=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return n?1&n||R&&t.compareDocumentPosition(e)===n?e===r||I(W,e)?-1:t===r||I(W,t)?1:A?nt.call(A,e)-nt.call(A,t):0:4&n?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var n,i=0,o=e.parentNode,a=t.parentNode,l=[e],c=[t];if(e===t)return K=!0,0;if(!o||!a)return e===r?-1:t===r?1:o?-1:a?1:0;if(o===a)return s(e,t);for(n=e;n=n.parentNode;)l.unshift(n);for(n=t;n=n.parentNode;)c.unshift(n);for(;l[i]===c[i];)i++;return i?s(l[i],c[i]):l[i]===W?-1:c[i]===W?1:0},D):D},a.matches=function(e,t){return a(e,null,null,t)},a.matchesSelector=function(e,t){if((e.ownerDocument||e)!==D&&B(e),t=t.replace(xt,"='$1']"),z.matchesSelector&&M&&(!P||!P.test(t))&&!H.test(t))try{var n=O.call(e,t);if(n||z.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return a(t,D,null,[e]).length>0},a.contains=function(e,t){return(e.ownerDocument||e)!==D&&B(e),I(e,t)},a.attr=function(e,t){var n;return(e.ownerDocument||e)!==D&&B(e),M&&(t=t.toLowerCase()),(n=N.attrHandle[t])?n(e):!M||z.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},a.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},a.uniqueSort=function(e){var t,n=[],r=0,i=0;if(K=!z.detectDuplicates,R=!z.sortDetached,A=!z.sortStable&&e.slice(0),e.sort(G),K){for(;t=e[i++];)t===e[i]&&(r=n.push(i));for(;r--;)e.splice(n[r],1)}return e},E=a.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=E(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=E(t);return n},N=a.selectors={cacheLength:50,createPseudo:i,match:ht,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(wt,_t),e[3]=(e[4]||e[5]||"").replace(wt,_t),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||a.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&a.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return ht.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&ft.test(n)&&(t=d(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(wt,_t).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=q[e+" "];return t||(t=new RegExp("(^|"+rt+")"+e+"("+rt+"|$)"))&&q(e,function(e){return t.test(e.className||typeof e.getAttribute!==Y&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=a.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var c,u,d,f,p,h,m=o!==a?"nextSibling":"previousSibling",g=t.parentNode,v=s&&t.nodeName.toLowerCase(),y=!l&&!s;if(g){if(o){for(;m;){for(d=t;d=d[m];)if(s?d.nodeName.toLowerCase()===v:1===d.nodeType)return!1;h=m="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?g.firstChild:g.lastChild],a&&y){for(u=g[F]||(g[F]={}),c=u[e]||[],p=c[0]===V&&c[1],f=c[0]===V&&c[2],d=p&&g.childNodes[p];d=++p&&d&&d[m]||(f=p=0)||h.pop();)if(1===d.nodeType&&++f&&d===t){u[e]=[V,p,f];break}}else if(y&&(c=(t[F]||(t[F]={}))[e])&&c[0]===V)f=c[1];else for(;(d=++p&&d&&d[m]||(f=p=0)||h.pop())&&((s?d.nodeName.toLowerCase()!==v:1!==d.nodeType)||!++f||(y&&((d[F]||(d[F]={}))[e]=[V,f]),d!==t)););return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=N.pseudos[e]||N.setFilters[e.toLowerCase()]||a.error("unsupported pseudo: "+e);return r[F]?r(t):r.length>1?(n=[e,e,"",t],N.setFilters.hasOwnProperty(e.toLowerCase())?i(function(e,n){for(var i,o=r(e,t),a=o.length;a--;)i=nt.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:i(function(e){var t=[],n=[],r=S(e.replace(ct,"$1"));return r[F]?i(function(e,t,n,i){for(var o,a=r(e,null,i,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:i(function(e){return function(t){return a(e,t).length>0}}),contains:i(function(e){return function(t){return(t.textContent||t.innerText||E(t)).indexOf(e)>-1}}),lang:i(function(e){return pt.test(e||"")||a.error("unsupported lang: "+e),e=e.replace(wt,_t).toLowerCase(),function(t){var n;do if(n=M?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(e){var t=window.location&&window.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===L},focus:function(e){return e===D.activeElement&&(!D.hasFocus||D.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!N.pseudos.empty(e)},header:function(e){return bt.test(e.nodeName)},input:function(e){return yt.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:u(function(){return[0]}),last:u(function(e,t){return[t-1]}),eq:u(function(e,t,n){return[0>n?n+t:n]}),even:u(function(e,t){for(var n=0;t>n;n+=2)e.push(n);return e}),odd:u(function(e,t){for(var n=1;t>n;n+=2)e.push(n);return e}),lt:u(function(e,t,n){for(var r=0>n?n+t:n;--r>=0;)e.push(r);return e}),gt:u(function(e,t,n){for(var r=0>n?n+t:n;++r<t;)e.push(r);return e})}};for(w in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})N.pseudos[w]=l(w);for(w in{submit:!0,reset:!0})N.pseudos[w]=c(w);return S=a.compile=function(e,t){var n,r=[],i=[],o=$[e+" "];if(!o){for(t||(t=d(e)),n=t.length;n--;)o=v(t[n]),o[F]?r.push(o):i.push(o);o=$(e,y(i,r))}return o},N.pseudos.nth=N.pseudos.eq,x.prototype=N.filters=N.pseudos,N.setFilters=new x,z.sortStable=F.split("").sort(G).join("")===F,B(),[0,0].sort(G),z.detectDuplicates=K,"function"==typeof r&&r.amd?r(function(){return a}):window.Sizzle=a,a}),r(u,[l,c],function(e,n){function r(e){return"undefined"!=typeof e}function i(e){return"string"==typeof e}function o(e){var t,n,r;for(r=g.createElement("div"),t=g.createDocumentFragment(),r.innerHTML=e;n=r.firstChild;)t.appendChild(n);return t}function a(e,t,n){var r;if("string"==typeof t)t=o(t);else if(t.length){for(r=0;r<t.length;r++)a(e,t[r],n);return e}for(r=e.length;r--;)n.call(e[r],t.parentNode?t:t);return e}function s(e,t){return e&&t&&-1!==(" "+e.className+" ").indexOf(" "+t+" ")}function l(e,t){var n;for(e=e||[],"string"==typeof e&&(e=e.split(" ")),t=t||{},n=e.length;n--;)t[e[n]]={};return t}function c(e,t){return new c.fn.init(e,t)}function u(e){var t=arguments,n,r,i;for(r=1;r<t.length;r++){n=t[r];for(i in n)e[i]=n[i]}return e}function d(e){var t=[],n,r;for(n=0,r=e.length;r>n;n++)t[n]=e[n];return t}function f(e,t){var n;if(t.indexOf)return t.indexOf(e);for(n=t.length;n--;)if(t[n]===e)return n;return-1}function p(e,t){var n,r,i,o,a;if(e)if(n=e.length,n===o){for(r in e)if(e.hasOwnProperty(r)&&(a=e[r],t.call(a,a,r)===!1))break}else for(i=0;n>i&&(a=e[i],t.call(a,a,r)!==!1);i++);return e}function h(e,n,r){for(var i=[],o=e[n];o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!c(o).is(r));)1===o.nodeType&&i.push(o),o=o[n];return i}function m(e,t,n,r){for(var i=[];e;e=e[n])r&&e.nodeType!==r||e===t||i.push(e);return i}var g=document,v=Array.prototype.push,y=Array.prototype.slice,b=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,C=e.Event,x=l("fillOpacity fontWeight lineHeight opacity orphans widows zIndex zoom"),w=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},_=/^\s*|\s*$/g,N=function(e){return null===e||e===t?"":(""+e).replace(_,"")};return c.fn=c.prototype={constructor:c,selector:"",length:0,init:function(e,t){var n=this,r,a;if(!e)return n;if(e.nodeType)return n.context=n[0]=e,n.length=1,n;if(i(e)){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:b.exec(e),!r)return c(t||document).find(e);if(r[1])for(a=o(e).firstChild;a;)this.add(a),a=a.nextSibling;else{if(a=g.getElementById(r[2]),a.id!==r[2])return n.find(e);n.length=1,n[0]=a}}else this.add(e);return n},toArray:function(){return d(this)},add:function(e){var t=this;return w(e)?v.apply(t,e):e instanceof c?t.add(e.toArray()):v.call(t,e),t},attr:function(e,n){var i=this;if("object"==typeof e)p(e,function(e,t){i.attr(t,e)});else{if(!r(n))return i[0]&&1===i[0].nodeType?i[0].getAttribute(e):t;this.each(function(){1===this.nodeType&&this.setAttribute(e,n)})}return i},css:function(e,n){var i=this;if("object"==typeof e)p(e,function(e,t){i.css(t,e)});else{if(e=e.replace(/-(\D)/g,function(e,t){return t.toUpperCase()}),!r(n))return i[0]?i[0].style[e]:t;"number"!=typeof n||x[e]||(n+="px"),i.each(function(){var t=this.style;"opacity"===e&&this.runtimeStyle&&"undefined"==typeof this.runtimeStyle.opacity&&(t.filter=""===n?"":"alpha(opacity="+100*n+")");try{t[e]=n}catch(r){}})}return i},remove:function(){for(var e=this,t,n=this.length;n--;)t=e[n],C.clean(t),t.parentNode&&t.parentNode.removeChild(t);return this},empty:function(){for(var e=this,t,n=this.length;n--;)for(t=e[n];t.firstChild;)t.removeChild(t.firstChild);return this},html:function(e){var t=this,n;if(r(e)){for(n=t.length;n--;)t[n].innerHTML=e;return t}return t[0]?t[0].innerHTML:""},text:function(e){var t=this,n;if(r(e)){for(n=t.length;n--;)t[n].innerText=t[0].textContent=e;return t}return t[0]?t[0].innerText||t[0].textContent:""},append:function(){return a(this,arguments,function(e){1===this.nodeType&&this.appendChild(e)})},prepend:function(){return a(this,arguments,function(e){1===this.nodeType&&this.insertBefore(e,this.firstChild)})},before:function(){var e=this;return e[0]&&e[0].parentNode?a(e,arguments,function(e){this.parentNode.insertBefore(e,this.nextSibling)}):e},after:function(){var e=this;return e[0]&&e[0].parentNode?a(e,arguments,function(e){this.parentNode.insertBefore(e,this)}):e},appendTo:function(e){return c(e).append(this),this},addClass:function(e){return this.toggleClass(e,!0)},removeClass:function(e){return this.toggleClass(e,!1)},toggleClass:function(e,t){var n=this;return-1!==e.indexOf(" ")?p(e.split(" "),function(){n.toggleClass(this,t)}):n.each(function(){var n=this,r;s(n,e)!==t&&(r=n.className,t?n.className+=r?" "+e:e:n.className=N((" "+r+" ").replace(" "+e+" "," ")))}),n},hasClass:function(e){return s(this[0],e)},each:function(e){return p(this,e)},on:function(e,t){return this.each(function(){C.bind(this,e,t)})},off:function(e,t){return this.each(function(){C.unbind(this,e,t)})},show:function(){return this.css("display","")},hide:function(){return this.css("display","none")},slice:function(){return new c(y.apply(this,arguments))},eq:function(e){return-1===e?this.slice(e):this.slice(e,+e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},replaceWith:function(e){var t=this;return t[0]&&t[0].parentNode.replaceChild(c(e)[0],t[0]),t},wrap:function(e){return e=c(e)[0],this.each(function(){var t=this,n=e.cloneNode(!1);t.parentNode.insertBefore(n,t),n.appendChild(t)})},unwrap:function(){return this.each(function(){for(var e=this,t=e.firstChild,n;t;)n=t,t=t.nextSibling,e.parentNode.insertBefore(n,e)})},clone:function(){var e=[];return this.each(function(){e.push(this.cloneNode(!0))}),c(e)},find:function(e){var t,n,r=[];for(t=0,n=this.length;n>t;t++)c.find(e,this[t],r);return c(r)},push:v,sort:[].sort,splice:[].splice},u(c,{extend:u,toArray:d,inArray:f,isArray:w,each:p,trim:N,makeMap:l,find:n,expr:n.selectors,unique:n.uniqueSort,text:n.getText,isXMLDoc:n.isXML,contains:n.contains,filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?c.find.matchesSelector(t[0],e)?[t[0]]:[]:c.find.matches(e,t)}}),p({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,"parentNode")},parentsUntil:function(e,t){return h(e,"parentNode",t)},next:function(e){return m(e,"nextSibling",1)},prev:function(e){return m(e,"previousSibling",1)},nextNodes:function(e){return m(e,"nextSibling")},prevNodes:function(e){return m(e,"previousSibling")},children:function(e){return m(e.firstChild,"nextSibling",1)},contents:function(e){return d(("iframe"===e.nodeName?e.contentDocument||e.contentWindow.document:e).childNodes)}},function(e,t){c.fn[e]=function(n){var r=this,i;if(r.length>1)throw new Error("DomQuery only supports traverse functions on a single node.");return r[0]&&(i=t(r[0],n)),i=c(i),n&&"parentsUntil"!==e?i.filter(n):i}}),c.fn.filter=function(e){return c.filter(e)},c.fn.is=function(e){return!!e&&this.filter(e).length>0},c.fn.init.prototype=c.fn,c}),r(d,[],function(){return function(e,t){function n(e,t,n,r){function i(e){return e=parseInt(e,10).toString(16),e.length>1?e:"0"+e}return"#"+i(t)+i(n)+i(r)}var r=/rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi,i=/(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi,o=/\s*([^:]+):\s*([^;]+);?/g,a=/\s+$/,s,l,c={},u,d="\ufeff";
+for(e=e||{},u=("\\\" \\' \\; \\: ; : "+d).split(" "),l=0;l<u.length;l++)c[u[l]]=d+l,c[d+l]=u[l];return{toHex:function(e){return e.replace(r,n)},parse:function(t){function s(e,t){var n,r,i,o;n=h[e+"-top"+t],n&&(r=h[e+"-right"+t],n==r&&(i=h[e+"-bottom"+t],r==i&&(o=h[e+"-left"+t],i==o&&(h[e+t]=o,delete h[e+"-top"+t],delete h[e+"-right"+t],delete h[e+"-bottom"+t],delete h[e+"-left"+t]))))}function l(e){var t=h[e],n;if(t&&!(t.indexOf(" ")<0)){for(t=t.split(" "),n=t.length;n--;)if(t[n]!==t[0])return!1;return h[e]=t[0],!0}}function u(e,t,n,r){l(t)&&l(n)&&l(r)&&(h[e]=h[t]+" "+h[n]+" "+h[r],delete h[t],delete h[n],delete h[r])}function d(e){return y=!0,c[e]}function f(e,t){return y&&(e=e.replace(/\uFEFF[0-9]/g,function(e){return c[e]})),t||(e=e.replace(/\\([\'\";:])/g,"$1")),e}function p(e,t,n,r,i,o){return(i=i||o)?(i=f(i),"'"+i.replace(/\'/g,"\\'")+"'"):(t=f(t||n||r),b&&(t=b.call(C,t,"style")),"url('"+t.replace(/\'/g,"\\'")+"')")}var h={},m,g,v,y,b=e.url_converter,C=e.url_converter_scope||this;if(t){for(t=t.replace(/\\[\"\';:\uFEFF]/g,d).replace(/\"[^\"]+\"|\'[^\']+\'/g,function(e){return e.replace(/[;:]/g,d)});m=o.exec(t);)g=m[1].replace(a,"").toLowerCase(),v=m[2].replace(a,""),g&&v.length>0&&("font-weight"===g&&"700"===v?v="bold":("color"===g||"background-color"===g)&&(v=v.toLowerCase()),v=v.replace(r,n),v=v.replace(i,p),h[g]=y?f(v,!0):v),o.lastIndex=m.index+m[0].length;s("border",""),s("border","-width"),s("border","-color"),s("border","-style"),s("padding",""),s("margin",""),u("border","border-width","border-style","border-color"),"medium none"===h.border&&delete h.border}return h},serialize:function(e,n){function r(n){var r,o,a,l;if(r=t.styles[n])for(o=0,a=r.length;a>o;o++)n=r[o],l=e[n],l!==s&&l.length>0&&(i+=(i.length>0?" ":"")+n+": "+l+";")}var i="",o,a;if(n&&t&&t.styles)r("*"),r(n);else for(o in e)a=e[o],a!==s&&a.length>0&&(i+=(i.length>0?" ":"")+o+": "+a+";");return i}}}}),r(f,[],function(){return function(e,t){function n(e,n,r,i){var o,a;if(e){if(!i&&e[n])return e[n];if(e!=t){if(o=e[r])return o;for(a=e.parentNode;a&&a!=t;a=a.parentNode)if(o=a[r])return o}}}var r=e;this.current=function(){return r},this.next=function(e){return r=n(r,"firstChild","nextSibling",e)},this.prev=function(e){return r=n(r,"lastChild","previousSibling",e)}}}),r(p,[],function(){function e(e,n){return n?"array"==n&&g(e)?!0:typeof e==n:e!==t}function n(e){var t=[],n,r;for(n=0,r=e.length;r>n;n++)t[n]=e[n];return t}function r(e,t,n){var r;for(e=e||[],t=t||",","string"==typeof e&&(e=e.split(t)),n=n||{},r=e.length;r--;)n[e[r]]={};return n}function i(e,n,r){var i,o;if(!e)return 0;if(r=r||e,e.length!==t){for(i=0,o=e.length;o>i;i++)if(n.call(r,e[i],i,e)===!1)return 0}else for(i in e)if(e.hasOwnProperty(i)&&n.call(r,e[i],i,e)===!1)return 0;return 1}function o(e,t){var n=[];return i(e,function(e){n.push(t(e))}),n}function a(e,t){var n=[];return i(e,function(e){(!t||t(e))&&n.push(e)}),n}function s(e,t,n){var r=this,i,o,a,s,l,c=0;if(e=/^((static) )?([\w.]+)(:([\w.]+))?/.exec(e),a=e[3].match(/(^|\.)(\w+)$/i)[2],o=r.createNS(e[3].replace(/\.\w+$/,""),n),!o[a]){if("static"==e[2])return o[a]=t,this.onCreate&&this.onCreate(e[2],e[3],o[a]),void 0;t[a]||(t[a]=function(){},c=1),o[a]=t[a],r.extend(o[a].prototype,t),e[5]&&(i=r.resolve(e[5]).prototype,s=e[5].match(/\.(\w+)$/i)[1],l=o[a],o[a]=c?function(){return i[s].apply(this,arguments)}:function(){return this.parent=i[s],l.apply(this,arguments)},o[a].prototype[a]=o[a],r.each(i,function(e,t){o[a].prototype[t]=i[t]}),r.each(t,function(e,t){i[t]?o[a].prototype[t]=function(){return this.parent=i[t],e.apply(this,arguments)}:t!=a&&(o[a].prototype[t]=e)})),r.each(t["static"],function(e,t){o[a][t]=e})}}function l(e,t){var n,r;if(e)for(n=0,r=e.length;r>n;n++)if(e[n]===t)return n;return-1}function c(e,n){var r,i,o,a=arguments,s;for(r=1,i=a.length;i>r;r++){n=a[r];for(o in n)n.hasOwnProperty(o)&&(s=n[o],s!==t&&(e[o]=s))}return e}function u(e,t,n,r){r=r||this,e&&(n&&(e=e[n]),i(e,function(e,i){return t.call(r,e,i,n)===!1?!1:(u(e,t,n,r),void 0)}))}function d(e,t){var n,r;for(t=t||window,e=e.split("."),n=0;n<e.length;n++)r=e[n],t[r]||(t[r]={}),t=t[r];return t}function f(e,t){var n,r;for(t=t||window,e=e.split("."),n=0,r=e.length;r>n&&(t=t[e[n]],t);n++);return t}function p(t,n){return!t||e(t,"array")?t:o(t.split(n||","),m)}var h=/^\s*|\s*$/g,m=function(e){return null===e||e===t?"":(""+e).replace(h,"")},g=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)};return{trim:m,isArray:g,is:e,toArray:n,makeMap:r,each:i,map:o,grep:a,inArray:l,extend:c,create:s,walk:u,createNS:d,resolve:f,explode:p}}),r(h,[p],function(e){function t(n){function r(){return H.createDocumentFragment()}function i(e,t){_(F,e,t)}function o(e,t){_(W,e,t)}function a(e){i(e.parentNode,$(e))}function s(e){i(e.parentNode,$(e)+1)}function l(e){o(e.parentNode,$(e))}function c(e){o(e.parentNode,$(e)+1)}function u(e){e?(M[U]=M[V],M[q]=M[z]):(M[V]=M[U],M[z]=M[q]),M.collapsed=F}function d(e){a(e),c(e)}function f(e){i(e,0),o(e,1===e.nodeType?e.childNodes.length:e.nodeValue.length)}function p(e,t){var n=M[V],r=M[z],i=M[U],o=M[q],a=t.startContainer,s=t.startOffset,l=t.endContainer,c=t.endOffset;return 0===e?w(n,r,a,s):1===e?w(i,o,a,s):2===e?w(i,o,l,c):3===e?w(n,r,l,c):void 0}function h(){N(I)}function m(){return N(P)}function g(){return N(O)}function v(e){var t=this[V],r=this[z],i,o;3!==t.nodeType&&4!==t.nodeType||!t.nodeValue?(t.childNodes.length>0&&(o=t.childNodes[r]),o?t.insertBefore(e,o):t.appendChild(e)):r?r>=t.nodeValue.length?n.insertAfter(e,t):(i=t.splitText(r),t.parentNode.insertBefore(e,i)):t.parentNode.insertBefore(e,t)}function y(e){var t=M.extractContents();M.insertNode(e),e.appendChild(t),M.selectNode(e)}function b(){return j(new t(n),{startContainer:M[V],startOffset:M[z],endContainer:M[U],endOffset:M[q],collapsed:M.collapsed,commonAncestorContainer:M.commonAncestorContainer})}function C(e,t){var n;if(3==e.nodeType)return e;if(0>t)return e;for(n=e.firstChild;n&&t>0;)--t,n=n.nextSibling;return n?n:e}function x(){return M[V]==M[U]&&M[z]==M[q]}function w(e,t,r,i){var o,a,s,l,c,u;if(e==r)return t==i?0:i>t?-1:1;for(o=r;o&&o.parentNode!=e;)o=o.parentNode;if(o){for(a=0,s=e.firstChild;s!=o&&t>a;)a++,s=s.nextSibling;return a>=t?-1:1}for(o=e;o&&o.parentNode!=r;)o=o.parentNode;if(o){for(a=0,s=r.firstChild;s!=o&&i>a;)a++,s=s.nextSibling;return i>a?-1:1}for(l=n.findCommonAncestor(e,r),c=e;c&&c.parentNode!=l;)c=c.parentNode;for(c||(c=l),u=r;u&&u.parentNode!=l;)u=u.parentNode;if(u||(u=l),c==u)return 0;for(s=l.firstChild;s;){if(s==c)return-1;if(s==u)return 1;s=s.nextSibling}}function _(e,t,r){var i,o;for(e?(M[V]=t,M[z]=r):(M[U]=t,M[q]=r),i=M[U];i.parentNode;)i=i.parentNode;for(o=M[V];o.parentNode;)o=o.parentNode;o==i?w(M[V],M[z],M[U],M[q])>0&&M.collapse(e):M.collapse(e),M.collapsed=x(),M.commonAncestorContainer=n.findCommonAncestor(M[V],M[U])}function N(e){var t,n=0,r=0,i,o,a,s,l,c;if(M[V]==M[U])return E(e);for(t=M[U],i=t.parentNode;i;t=i,i=i.parentNode){if(i==M[V])return k(t,e);++n}for(t=M[V],i=t.parentNode;i;t=i,i=i.parentNode){if(i==M[U])return S(t,e);++r}for(o=r-n,a=M[V];o>0;)a=a.parentNode,o--;for(s=M[U];0>o;)s=s.parentNode,o++;for(l=a.parentNode,c=s.parentNode;l!=c;l=l.parentNode,c=c.parentNode)a=l,s=c;return T(a,s,e)}function E(e){var t,n,i,o,a,s,l,c,u;if(e!=I&&(t=r()),M[z]==M[q])return t;if(3==M[V].nodeType){if(n=M[V].nodeValue,i=n.substring(M[z],M[q]),e!=O&&(o=M[V],c=M[z],u=M[q]-M[z],0===c&&u>=o.nodeValue.length-1?o.parentNode.removeChild(o):o.deleteData(c,u),M.collapse(F)),e==I)return;return i.length>0&&t.appendChild(H.createTextNode(i)),t}for(o=C(M[V],M[z]),a=M[q]-M[z];o&&a>0;)s=o.nextSibling,l=D(o,e),t&&t.appendChild(l),--a,o=s;return e!=O&&M.collapse(F),t}function k(e,t){var n,i,o,a,s,l;if(t!=I&&(n=r()),i=R(e,t),n&&n.appendChild(i),o=$(e),a=o-M[z],0>=a)return t!=O&&(M.setEndBefore(e),M.collapse(W)),n;for(i=e.previousSibling;a>0;)s=i.previousSibling,l=D(i,t),n&&n.insertBefore(l,n.firstChild),--a,i=s;return t!=O&&(M.setEndBefore(e),M.collapse(W)),n}function S(e,t){var n,i,o,a,s,l;for(t!=I&&(n=r()),o=A(e,t),n&&n.appendChild(o),i=$(e),++i,a=M[q]-i,o=e.nextSibling;o&&a>0;)s=o.nextSibling,l=D(o,t),n&&n.appendChild(l),--a,o=s;return t!=O&&(M.setStartAfter(e),M.collapse(F)),n}function T(e,t,n){var i,o,a,s,l,c,u,d;for(n!=I&&(o=r()),i=A(e,n),o&&o.appendChild(i),a=e.parentNode,s=$(e),l=$(t),++s,c=l-s,u=e.nextSibling;c>0;)d=u.nextSibling,i=D(u,n),o&&o.appendChild(i),u=d,--c;return i=R(t,n),o&&o.appendChild(i),n!=O&&(M.setStartAfter(e),M.collapse(F)),o}function R(e,t){var n=C(M[U],M[q]-1),r,i,o,a,s,l=n!=M[U];if(n==e)return B(n,l,W,t);for(r=n.parentNode,i=B(r,W,W,t);r;){for(;n;)o=n.previousSibling,a=B(n,l,W,t),t!=I&&i.insertBefore(a,i.firstChild),l=F,n=o;if(r==e)return i;n=r.previousSibling,r=r.parentNode,s=B(r,W,W,t),t!=I&&s.appendChild(i),i=s}}function A(e,t){var n=C(M[V],M[z]),r=n!=M[V],i,o,a,s,l;if(n==e)return B(n,r,F,t);for(i=n.parentNode,o=B(i,W,F,t);i;){for(;n;)a=n.nextSibling,s=B(n,r,F,t),t!=I&&o.appendChild(s),r=F,n=a;if(i==e)return o;n=i.nextSibling,i=i.parentNode,l=B(i,W,F,t),t!=I&&l.appendChild(o),o=l}}function B(e,t,r,i){var o,a,s,l,c;if(t)return D(e,i);if(3==e.nodeType){if(o=e.nodeValue,r?(l=M[z],a=o.substring(l),s=o.substring(0,l)):(l=M[q],a=o.substring(0,l),s=o.substring(l)),i!=O&&(e.nodeValue=s),i==I)return;return c=n.clone(e,W),c.nodeValue=a,c}if(i!=I)return n.clone(e,W)}function D(e,t){return t!=I?t==O?n.clone(e,F):e:(e.parentNode.removeChild(e),void 0)}function L(){return n.create("body",null,g()).outerText}var M=this,H=n.doc,P=0,O=1,I=2,F=!0,W=!1,z="startOffset",V="startContainer",U="endContainer",q="endOffset",j=e.extend,$=n.nodeIndex;return j(M,{startContainer:H,startOffset:0,endContainer:H,endOffset:0,collapsed:F,commonAncestorContainer:H,START_TO_START:0,START_TO_END:1,END_TO_END:2,END_TO_START:3,setStart:i,setEnd:o,setStartBefore:a,setStartAfter:s,setEndBefore:l,setEndAfter:c,collapse:u,selectNode:d,selectNodeContents:f,compareBoundaryPoints:p,deleteContents:h,extractContents:m,cloneContents:g,insertNode:v,surroundContents:y,cloneRange:b,toStringIE:L}),M}return t.prototype.toString=function(){return this.toStringIE()},t}),r(m,[p],function(e){function t(e){var t;return t=document.createElement("div"),t.innerHTML=e,t.textContent||t.innerText||e}function n(e,t){var n,r,i,a={};if(e){for(e=e.split(","),t=t||10,n=0;n<e.length;n+=2)r=String.fromCharCode(parseInt(e[n],t)),o[r]||(i="&"+e[n+1]+";",a[r]=i,a[i]=r);return a}}var r=e.makeMap,i,o,a,s=/[&<>\"\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,l=/[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,c=/[<>&\"\']/g,u=/&(#x|#)?([\w]+);/g,d={128:"\u20ac",130:"\u201a",131:"\u0192",132:"\u201e",133:"\u2026",134:"\u2020",135:"\u2021",136:"\u02c6",137:"\u2030",138:"\u0160",139:"\u2039",140:"\u0152",142:"\u017d",145:"\u2018",146:"\u2019",147:"\u201c",148:"\u201d",149:"\u2022",150:"\u2013",151:"\u2014",152:"\u02dc",153:"\u2122",154:"\u0161",155:"\u203a",156:"\u0153",158:"\u017e",159:"\u0178"};o={'"':"&quot;","'":"&#39;","<":"&lt;",">":"&gt;","&":"&amp;"},a={"&lt;":"<","&gt;":">","&amp;":"&","&quot;":'"',"&apos;":"'"},i=n("50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,t9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro",32);var f={encodeRaw:function(e,t){return e.replace(t?s:l,function(e){return o[e]||e})},encodeAllRaw:function(e){return(""+e).replace(c,function(e){return o[e]||e})},encodeNumeric:function(e,t){return e.replace(t?s:l,function(e){return e.length>1?"&#"+(1024*(e.charCodeAt(0)-55296)+(e.charCodeAt(1)-56320)+65536)+";":o[e]||"&#"+e.charCodeAt(0)+";"})},encodeNamed:function(e,t,n){return n=n||i,e.replace(t?s:l,function(e){return o[e]||n[e]||e})},getEncodeFunc:function(e,t){function a(e,n){return e.replace(n?s:l,function(e){return o[e]||t[e]||"&#"+e.charCodeAt(0)+";"||e})}function c(e,n){return f.encodeNamed(e,n,t)}return t=n(t)||i,e=r(e.replace(/\+/g,",")),e.named&&e.numeric?a:e.named?t?c:f.encodeNamed:e.numeric?f.encodeNumeric:f.encodeRaw},decode:function(e){return e.replace(u,function(e,n,r){return n?(r=parseInt(r,2===n.length?16:10),r>65535?(r-=65536,String.fromCharCode(55296+(r>>10),56320+(1023&r))):d[r]||String.fromCharCode(r)):a[e]||i[e]||t(e)})}};return f}),r(g,[],function(){var e=navigator,t=e.userAgent,n,r,i,o,a,s,l;n=window.opera&&window.opera.buildNumber,r=/WebKit/.test(t),i=!r&&!n&&/MSIE/gi.test(t)&&/Explorer/gi.test(e.appName),i=i&&/MSIE (\w+)\./.exec(t)[1],o=-1!=t.indexOf("Trident")?11:!1,i=i||o,a=!r&&/Gecko/.test(t),s=-1!=t.indexOf("Mac"),l=/(iPad|iPhone)/.test(t);var c=!l||t.match(/AppleWebKit\/(\d*)/)[1]>=534;return{opera:n,webkit:r,ie:i,gecko:a,mac:s,iOS:l,contentEditable:c,transparentSrc:"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",caretAfter:8!=i,range:window.getSelection&&"Range"in window,documentMode:i?document.documentMode||7:10}}),r(v,[c,d,l,f,h,m,g,p],function(e,n,r,i,o,a,s,l){function c(e,t){var i=this,o;i.doc=e,i.win=window,i.files={},i.counter=0,i.stdMode=!g||e.documentMode>=8,i.boxModel=!g||"CSS1Compat"==e.compatMode||i.stdMode,i.hasOuterHTML="outerHTML"in e.createElement("a"),i.settings=t=h({keep_values:!1,hex_colors:1},t),i.schema=t.schema,i.styles=new n({url_converter:t.url_converter,url_converter_scope:t.url_converter_scope},t.schema),i.fixDoc(e),i.events=t.ownEvents?new r(t.proxy):r.Event,o=t.schema?t.schema.getBlockElements():{},i.isBlock=function(e){if(!e)return!1;var t=e.nodeType;return t?!(1!==t||!o[e.nodeName]):!!o[e]}}var u=l.each,d=l.is,f=l.grep,p=l.trim,h=l.extend,m=s.webkit,g=s.ie,v=/^([a-z0-9],?)+$/i,y=/^[ \t\r\n]*$/,b=l.makeMap("fillOpacity fontWeight lineHeight opacity orphans widows zIndex zoom"," ");return c.prototype={root:null,props:{"for":"htmlFor","class":"className",className:"className",checked:"checked",disabled:"disabled",maxlength:"maxLength",readonly:"readOnly",selected:"selected",value:"value",id:"id",name:"name",type:"type"},fixDoc:function(e){var t=this.settings,n;if(g&&t.schema){"abbr article aside audio canvas details figcaption figure footer header hgroup mark menu meter nav output progress section summary time video".replace(/\w+/g,function(t){e.createElement(t)});for(n in t.schema.getCustomElements())e.createElement(n)}},clone:function(e,t){var n=this,r,i;return!g||1!==e.nodeType||t?e.cloneNode(t):(i=n.doc,t?r.firstChild:(r=i.createElement(e.nodeName),u(n.getAttribs(e),function(t){n.setAttrib(r,t.nodeName,n.getAttrib(e,t.nodeName))}),r))},getRoot:function(){var e=this;return e.get(e.settings.root_element)||e.doc.body},getViewPort:function(e){var t,n;return e=e?e:this.win,t=e.document,n=this.boxModel?t.documentElement:t.body,{x:e.pageXOffset||n.scrollLeft,y:e.pageYOffset||n.scrollTop,w:e.innerWidth||n.clientWidth,h:e.innerHeight||n.clientHeight}},getRect:function(e){var t=this,n,r;return e=t.get(e),n=t.getPos(e),r=t.getSize(e),{x:n.x,y:n.y,w:r.w,h:r.h}},getSize:function(e){var t=this,n,r;return e=t.get(e),n=t.getStyle(e,"width"),r=t.getStyle(e,"height"),-1===n.indexOf("px")&&(n=0),-1===r.indexOf("px")&&(r=0),{w:parseInt(n,10)||e.offsetWidth||e.clientWidth,h:parseInt(r,10)||e.offsetHeight||e.clientHeight}},getParent:function(e,t,n){return this.getParents(e,t,n,!1)},getParents:function(e,n,r,i){var o=this,a,s=[];for(e=o.get(e),i=i===t,r=r||("BODY"!=o.getRoot().nodeName?o.getRoot().parentNode:null),d(n,"string")&&(a=n,n="*"===n?function(e){return 1==e.nodeType}:function(e){return o.is(e,a)});e&&e!=r&&e.nodeType&&9!==e.nodeType;){if(!n||n(e)){if(!i)return e;s.push(e)}e=e.parentNode}return i?s:null},get:function(e){var t;return e&&this.doc&&"string"==typeof e&&(t=e,e=this.doc.getElementById(e),e&&e.id!==t)?this.doc.getElementsByName(t)[1]:e},getNext:function(e,t){return this._findSib(e,t,"nextSibling")},getPrev:function(e,t){return this._findSib(e,t,"previousSibling")},select:function(t,n){var r=this;return e(t,r.get(n)||r.get(r.settings.root_element)||r.doc,[])},is:function(n,r){var i;if(n.length===t){if("*"===r)return 1==n.nodeType;if(v.test(r)){for(r=r.toLowerCase().split(/,/),n=n.nodeName.toLowerCase(),i=r.length-1;i>=0;i--)if(r[i]==n)return!0;return!1}}return n.nodeType&&1!=n.nodeType?!1:e.matches(r,n.nodeType?[n]:n).length>0},add:function(e,t,n,r,i){var o=this;return this.run(e,function(e){var a;return a=d(t,"string")?o.doc.createElement(t):t,o.setAttribs(a,n),r&&(r.nodeType?a.appendChild(r):o.setHTML(a,r)),i?a:e.appendChild(a)})},create:function(e,t,n){return this.add(this.doc.createElement(e),e,t,n,1)},createHTML:function(e,t,n){var r="",i;r+="<"+e;for(i in t)t.hasOwnProperty(i)&&null!==t[i]&&(r+=" "+i+'="'+this.encode(t[i])+'"');return"undefined"!=typeof n?r+">"+n+"</"+e+">":r+" />"},createFragment:function(e){var t,n,r=this.doc,i;for(i=r.createElement("div"),t=r.createDocumentFragment(),e&&(i.innerHTML=e);n=i.firstChild;)t.appendChild(n);return t},remove:function(e,t){return this.run(e,function(e){var n,r=e.parentNode;if(!r)return null;if(t)for(;n=e.firstChild;)!g||3!==n.nodeType||n.nodeValue?r.insertBefore(n,e):e.removeChild(n);return r.removeChild(e)})},setStyle:function(e,t,n){return this.run(e,function(e){var r=this,i,o;if(t)if("string"==typeof t){i=e.style,t=t.replace(/-(\D)/g,function(e,t){return t.toUpperCase()}),"number"!=typeof n||b[t]||(n+="px"),"opacity"===t&&e.runtimeStyle&&"undefined"==typeof e.runtimeStyle.opacity&&(i.filter=""===n?"":"alpha(opacity="+100*n+")"),"float"==t&&(t="cssFloat"in e.style?"cssFloat":"styleFloat");try{i[t]=n}catch(a){}r.settings.update_styles&&e.removeAttribute("data-mce-style")}else for(o in t)r.setStyle(e,o,t[o])})},getStyle:function(e,n,r){if(e=this.get(e)){if(this.doc.defaultView&&r){n=n.replace(/[A-Z]/g,function(e){return"-"+e});try{return this.doc.defaultView.getComputedStyle(e,null).getPropertyValue(n)}catch(i){return null}}return n=n.replace(/-(\D)/g,function(e,t){return t.toUpperCase()}),"float"==n&&(n=g?"styleFloat":"cssFloat"),e.currentStyle&&r?e.currentStyle[n]:e.style?e.style[n]:t}},setStyles:function(e,t){this.setStyle(e,t)},css:function(e,t,n){this.setStyle(e,t,n)},removeAllAttribs:function(e){return this.run(e,function(e){var t,n=e.attributes;for(t=n.length-1;t>=0;t--)e.removeAttributeNode(n.item(t))})},setAttrib:function(e,t,n){var r=this;if(e&&t)return this.run(e,function(e){var i=r.settings,o=e.getAttribute(t);if(null!==n)switch(t){case"style":if(!d(n,"string"))return u(n,function(t,n){r.setStyle(e,n,t)}),void 0;i.keep_values&&(n?e.setAttribute("data-mce-style",n,2):e.removeAttribute("data-mce-style",2)),e.style.cssText=n;break;case"class":e.className=n||"";break;case"src":case"href":i.keep_values&&(i.url_converter&&(n=i.url_converter.call(i.url_converter_scope||r,n,t,e)),r.setAttrib(e,"data-mce-"+t,n,2));break;case"shape":e.setAttribute("data-mce-style",n)}d(n)&&null!==n&&0!==n.length?e.setAttribute(t,""+n,2):e.removeAttribute(t,2),o!=n&&i.onSetAttrib&&i.onSetAttrib({attrElm:e,attrName:t,attrValue:n})})},setAttribs:function(e,t){var n=this;return this.run(e,function(e){u(t,function(t,r){n.setAttrib(e,r,t)})})},getAttrib:function(e,t,n){var r,i=this,o;if(e=i.get(e),!e||1!==e.nodeType)return n===o?!1:n;if(d(n)||(n=""),/^(src|href|style|coords|shape)$/.test(t)&&(r=e.getAttribute("data-mce-"+t)))return r;if(g&&i.props[t]&&(r=e[i.props[t]],r=r&&r.nodeValue?r.nodeValue:r),r||(r=e.getAttribute(t,2)),/^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)$/.test(t))return e[i.props[t]]===!0&&""===r?t:r?t:"";if("FORM"===e.nodeName&&e.getAttributeNode(t))return e.getAttributeNode(t).nodeValue;if("style"===t&&(r=r||e.style.cssText,r&&(r=i.serializeStyle(i.parseStyle(r),e.nodeName),i.settings.keep_values&&e.setAttribute("data-mce-style",r))),m&&"class"===t&&r&&(r=r.replace(/(apple|webkit)\-[a-z\-]+/gi,"")),g)switch(t){case"rowspan":case"colspan":1===r&&(r="");break;case"size":("+0"===r||20===r||0===r)&&(r="");break;case"width":case"height":case"vspace":case"checked":case"disabled":case"readonly":0===r&&(r="");break;case"hspace":-1===r&&(r="");break;case"maxlength":case"tabindex":(32768===r||2147483647===r||"32768"===r)&&(r="");break;case"multiple":case"compact":case"noshade":case"nowrap":return 65535===r?t:n;case"shape":r=r.toLowerCase();break;default:0===t.indexOf("on")&&r&&(r=(""+r).replace(/^function\s+\w+\(\)\s+\{\s+(.*)\s+\}$/,"$1"))}return r!==o&&null!==r&&""!==r?""+r:n},getPos:function(e,t){var n=this,r=0,i=0,o,a=n.doc,s;if(e=n.get(e),t=t||a.body,e){if(t===a.body&&e.getBoundingClientRect)return s=e.getBoundingClientRect(),t=n.boxModel?a.documentElement:a.body,r=s.left+(a.documentElement.scrollLeft||a.body.scrollLeft)-t.clientTop,i=s.top+(a.documentElement.scrollTop||a.body.scrollTop)-t.clientLeft,{x:r,y:i};for(o=e;o&&o!=t&&o.nodeType;)r+=o.offsetLeft||0,i+=o.offsetTop||0,o=o.offsetParent;for(o=e.parentNode;o&&o!=t&&o.nodeType;)r-=o.scrollLeft||0,i-=o.scrollTop||0,o=o.parentNode}return{x:r,y:i}},parseStyle:function(e){return this.styles.parse(e)},serializeStyle:function(e,t){return this.styles.serialize(e,t)},addStyle:function(e){var t=this,n=t.doc,r,i;if(t!==c.DOM&&n===document){var o=c.DOM.addedStyles;if(o=o||[],o[e])return;o[e]=!0,c.DOM.addedStyles=o}i=n.getElementById("mceDefaultStyles"),i||(i=n.createElement("style"),i.id="mceDefaultStyles",i.type="text/css",r=n.getElementsByTagName("head")[0],r.firstChild?r.insertBefore(i,r.firstChild):r.appendChild(i)),i.styleSheet?i.styleSheet.cssText+=e:i.appendChild(n.createTextNode(e))},loadCSS:function(e){var t=this,n=t.doc,r;return t!==c.DOM&&n===document?(c.DOM.loadCSS(e),void 0):(e||(e=""),r=n.getElementsByTagName("head")[0],u(e.split(","),function(e){var i;t.files[e]||(t.files[e]=!0,i=t.create("link",{rel:"stylesheet",href:e}),g&&n.documentMode&&n.recalc&&(i.onload=function(){n.recalc&&n.recalc(),i.onload=null}),r.appendChild(i))}),void 0)},addClass:function(e,t){return this.run(e,function(e){var n;return t?this.hasClass(e,t)?e.className:(n=this.removeClass(e,t),e.className=n=(""!==n?n+" ":"")+t,n):0})},removeClass:function(e,t){var n=this,r;return n.run(e,function(e){var i;return n.hasClass(e,t)?(r||(r=new RegExp("(^|\\s+)"+t+"(\\s+|$)","g")),i=e.className.replace(r," "),i=p(" "!=i?i:""),e.className=i,i||(e.removeAttribute("class"),e.removeAttribute("className")),i):e.className})},hasClass:function(e,t){return e=this.get(e),e&&t?-1!==(" "+e.className+" ").indexOf(" "+t+" "):!1},toggleClass:function(e,n,r){r=r===t?!this.hasClass(e,n):r,this.hasClass(e,n)!==r&&(r?this.addClass(e,n):this.removeClass(e,n))},show:function(e){return this.setStyle(e,"display","block")},hide:function(e){return this.setStyle(e,"display","none")},isHidden:function(e){return e=this.get(e),!e||"none"==e.style.display||"none"==this.getStyle(e,"display")},uniqueId:function(e){return(e?e:"mce_")+this.counter++},setHTML:function(e,t){var n=this;return n.run(e,function(e){if(g){for(;e.firstChild;)e.removeChild(e.firstChild);try{e.innerHTML="<br />"+t,e.removeChild(e.firstChild)}catch(r){var i=n.create("div");i.innerHTML="<br />"+t,u(f(i.childNodes),function(t,n){n&&e.canHaveHTML&&e.appendChild(t)})}}else e.innerHTML=t;return t})},getOuterHTML:function(e){var t,n=this;return(e=n.get(e))?1===e.nodeType&&n.hasOuterHTML?e.outerHTML:(t=(e.ownerDocument||n.doc).createElement("body"),t.appendChild(e.cloneNode(!0)),t.innerHTML):null},setOuterHTML:function(e,t,n){var r=this;return r.run(e,function(e){function i(){var i,o;for(o=n.createElement("body"),o.innerHTML=t,i=o.lastChild;i;)r.insertAfter(i.cloneNode(!0),e),i=i.previousSibling;r.remove(e)}if(1==e.nodeType)if(n=n||e.ownerDocument||r.doc,g)try{1==e.nodeType&&r.hasOuterHTML?e.outerHTML=t:i()}catch(o){i()}else i()})},decode:a.decode,encode:a.encodeAllRaw,insertAfter:function(e,t){return t=this.get(t),this.run(e,function(e){var n,r;return n=t.parentNode,r=t.nextSibling,r?n.insertBefore(e,r):n.appendChild(e),e})},replace:function(e,t,n){var r=this;return r.run(t,function(t){return d(t,"array")&&(e=e.cloneNode(!0)),n&&u(f(t.childNodes),function(t){e.appendChild(t)}),t.parentNode.replaceChild(e,t)})},rename:function(e,t){var n=this,r;return e.nodeName!=t.toUpperCase()&&(r=n.create(t),u(n.getAttribs(e),function(t){n.setAttrib(r,t.nodeName,n.getAttrib(e,t.nodeName))}),n.replace(r,e,1)),r||e},findCommonAncestor:function(e,t){for(var n=e,r;n;){for(r=t;r&&n!=r;)r=r.parentNode;if(n==r)break;n=n.parentNode}return!n&&e.ownerDocument?e.ownerDocument.documentElement:n},toHex:function(e){return this.styles.toHex(l.trim(e))},run:function(e,t,n){var r=this,i;return"string"==typeof e&&(e=r.get(e)),e?(n=n||this,e.nodeType||!e.length&&0!==e.length?t.call(n,e):(i=[],u(e,function(e,o){e&&("string"==typeof e&&(e=r.get(e)),i.push(t.call(n,e,o)))}),i)):!1},getAttribs:function(e){var t;if(e=this.get(e),!e)return[];if(g){if(t=[],"OBJECT"==e.nodeName)return e.attributes;"OPTION"===e.nodeName&&this.getAttrib(e,"selected")&&t.push({specified:1,nodeName:"selected"});var n=/<\/?[\w:\-]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=[\w\-]+|>/gi;return e.cloneNode(!1).outerHTML.replace(n,"").replace(/[\w:\-]+/gi,function(e){t.push({specified:1,nodeName:e})}),t}return e.attributes},isEmpty:function(e,t){var n=this,r,o,a,s,l,c=0;if(e=e.firstChild){s=new i(e,e.parentNode),t=t||n.schema?n.schema.getNonEmptyElements():null;do{if(a=e.nodeType,1===a){if(e.getAttribute("data-mce-bogus"))continue;if(l=e.nodeName.toLowerCase(),t&&t[l]){if("br"===l){c++;continue}return!1}for(o=n.getAttribs(e),r=e.attributes.length;r--;)if(l=e.attributes[r].nodeName,"name"===l||"data-mce-bookmark"===l)return!1}if(8==a)return!1;if(3===a&&!y.test(e.nodeValue))return!1}while(e=s.next())}return 1>=c},createRng:function(){var e=this.doc;return e.createRange?e.createRange():new o(this)},nodeIndex:function(e,t){var n=0,r,i,o;if(e)for(r=e.nodeType,e=e.previousSibling,i=e;e;e=e.previousSibling)o=e.nodeType,(!t||3!=o||o!=r&&e.nodeValue.length)&&(n++,r=o);return n},split:function(e,t,n){function r(e){function t(e){var t=e.previousSibling&&"SPAN"==e.previousSibling.nodeName,n=e.nextSibling&&"SPAN"==e.nextSibling.nodeName;return t&&n}var n,o=e.childNodes,a=e.nodeType;if(1!=a||"bookmark"!=e.getAttribute("data-mce-type")){for(n=o.length-1;n>=0;n--)r(o[n]);if(9!=a){if(3==a&&e.nodeValue.length>0){var s=p(e.nodeValue).length;if(!i.isBlock(e.parentNode)||s>0||0===s&&t(e))return}else if(1==a&&(o=e.childNodes,1==o.length&&o[0]&&1==o[0].nodeType&&"bookmark"==o[0].getAttribute("data-mce-type")&&e.parentNode.insertBefore(o[0],e),o.length||/^(br|hr|input|img)$/i.test(e.nodeName)))return;i.remove(e)}return e}}var i=this,o=i.createRng(),a,s,l;return e&&t?(o.setStart(e.parentNode,i.nodeIndex(e)),o.setEnd(t.parentNode,i.nodeIndex(t)),a=o.extractContents(),o=i.createRng(),o.setStart(t.parentNode,i.nodeIndex(t)+1),o.setEnd(e.parentNode,i.nodeIndex(e)+1),s=o.extractContents(),l=e.parentNode,l.insertBefore(r(a),e),n?l.replaceChild(n,t):l.insertBefore(t,e),l.insertBefore(r(s),e),i.remove(e),n||t):void 0},bind:function(e,t,n,r){return this.events.bind(e,t,n,r||this)},unbind:function(e,t,n){return this.events.unbind(e,t,n)},fire:function(e,t,n){return this.events.fire(e,t,n)},getContentEditable:function(e){var t;return 1!=e.nodeType?null:(t=e.getAttribute("data-mce-contenteditable"),t&&"inherit"!==t?t:"inherit"!==e.contentEditable?e.contentEditable:null)},destroy:function(){var e=this;e.win=e.doc=e.root=e.events=e.frag=null},dumpRng:function(e){return"startContainer: "+e.startContainer.nodeName+", startOffset: "+e.startOffset+", endContainer: "+e.endContainer.nodeName+", endOffset: "+e.endOffset},_findSib:function(e,t,n){var r=this,i=t;if(e)for("string"==typeof i&&(i=function(e){return r.is(e,t)}),e=e[n];e;e=e[n])if(i(e))return e;return null}},c.DOM=new c(document),c}),r(y,[v,p],function(e,t){function n(){function e(e,t){function n(){o.remove(s),a&&(a.onreadystatechange=a.onload=a=null),t()}function i(){"undefined"!=typeof console&&console.log&&console.log("Failed to load: "+e)}var o=r,a,s;s=o.uniqueId(),a=document.createElement("script"),a.id=s,a.type="text/javascript",a.src=e,"onreadystatechange"in a?a.onreadystatechange=function(){/loaded|complete/.test(a.readyState)&&n()}:a.onload=n,a.onerror=i,(document.getElementsByTagName("head")[0]||document.body).appendChild(a)}var t=0,n=1,a=2,s={},l=[],c={},u=[],d=0,f;this.isDone=function(e){return s[e]==a},this.markDone=function(e){s[e]=a},this.add=this.load=function(e,n,r){var i=s[e];i==f&&(l.push(e),s[e]=t),n&&(c[e]||(c[e]=[]),c[e].push({func:n,scope:r||this}))},this.loadQueue=function(e,t){this.loadScripts(l,e,t)},this.loadScripts=function(t,r,l){function p(e){i(c[e],function(e){e.func.call(e.scope)}),c[e]=f}var h;u.push({func:r,scope:l||this}),h=function(){var r=o(t);t.length=0,i(r,function(t){return s[t]==a?(p(t),void 0):(s[t]!=n&&(s[t]=n,d++,e(t,function(){s[t]=a,d--,p(t),h()})),void 0)}),d||(i(u,function(e){e.func.call(e.scope)}),u.length=0)},h()}}var r=e.DOM,i=t.each,o=t.grep;return n.ScriptLoader=new n,n}),r(b,[y,p],function(e,n){function r(){var e=this;e.items=[],e.urls={},e.lookup={}}var i=n.each;return r.prototype={get:function(e){return this.lookup[e]?this.lookup[e].instance:t},dependencies:function(e){var t;return this.lookup[e]&&(t=this.lookup[e].dependencies),t||[]},requireLangPack:function(t){var n=r.settings;n&&n.language&&n.language_load!==!1&&e.ScriptLoader.add(this.urls[t]+"/langs/"+n.language+".js")},add:function(e,t,n){return this.items.push(t),this.lookup[e]={instance:t,dependencies:n},t},createUrl:function(e,t){return"object"==typeof t?t:{prefix:e.prefix,resource:t,suffix:e.suffix}},addComponents:function(t,n){var r=this.urls[t];i(n,function(t){e.ScriptLoader.add(r+"/"+t)})},load:function(n,o,a,s){function l(){var r=c.dependencies(n);i(r,function(e){var n=c.createUrl(o,e);c.load(n.resource,n,t,t)}),a&&(s?a.call(s):a.call(e))}var c=this,u=o;c.urls[n]||("object"==typeof o&&(u=o.prefix+o.resource+o.suffix),0!==u.indexOf("/")&&-1==u.indexOf("://")&&(u=r.baseURL+"/"+u),c.urls[n]=u.substring(0,u.lastIndexOf("/")),c.lookup[n]?l():e.ScriptLoader.add(u,l,s))}},r.PluginManager=new r,r.ThemeManager=new r,r}),r(C,[],function(){function e(e,t,n){var r,i,o=n?"lastChild":"firstChild",a=n?"prev":"next";
+if(e[o])return e[o];if(e!==t){if(r=e[a])return r;for(i=e.parent;i&&i!==t;i=i.parent)if(r=i[a])return r}}function t(e,t){this.name=e,this.type=t,1===t&&(this.attributes=[],this.attributes.map={})}var n=/^[ \t\r\n]*$/,r={"#text":3,"#comment":8,"#cdata":4,"#pi":7,"#doctype":10,"#document-fragment":11};return t.prototype={replace:function(e){var t=this;return e.parent&&e.remove(),t.insert(e,t),t.remove(),t},attr:function(e,t){var n=this,r,i,o;if("string"!=typeof e){for(i in e)n.attr(i,e[i]);return n}if(r=n.attributes){if(t!==o){if(null===t){if(e in r.map)for(delete r.map[e],i=r.length;i--;)if(r[i].name===e)return r=r.splice(i,1),n;return n}if(e in r.map){for(i=r.length;i--;)if(r[i].name===e){r[i].value=t;break}}else r.push({name:e,value:t});return r.map[e]=t,n}return r.map[e]}},clone:function(){var e=this,n=new t(e.name,e.type),r,i,o,a,s;if(o=e.attributes){for(s=[],s.map={},r=0,i=o.length;i>r;r++)a=o[r],"id"!==a.name&&(s[s.length]={name:a.name,value:a.value},s.map[a.name]=a.value);n.attributes=s}return n.value=e.value,n.shortEnded=e.shortEnded,n},wrap:function(e){var t=this;return t.parent.insert(e,t),e.append(t),t},unwrap:function(){var e=this,t,n;for(t=e.firstChild;t;)n=t.next,e.insert(t,e,!0),t=n;e.remove()},remove:function(){var e=this,t=e.parent,n=e.next,r=e.prev;return t&&(t.firstChild===e?(t.firstChild=n,n&&(n.prev=null)):r.next=n,t.lastChild===e?(t.lastChild=r,r&&(r.next=null)):n.prev=r,e.parent=e.next=e.prev=null),e},append:function(e){var t=this,n;return e.parent&&e.remove(),n=t.lastChild,n?(n.next=e,e.prev=n,t.lastChild=e):t.lastChild=t.firstChild=e,e.parent=t,e},insert:function(e,t,n){var r;return e.parent&&e.remove(),r=t.parent||this,n?(t===r.firstChild?r.firstChild=e:t.prev.next=e,e.prev=t.prev,e.next=t,t.prev=e):(t===r.lastChild?r.lastChild=e:t.next.prev=e,e.next=t.next,e.prev=t,t.next=e),e.parent=r,e},getAll:function(t){var n=this,r,i=[];for(r=n.firstChild;r;r=e(r,n))r.name===t&&i.push(r);return i},empty:function(){var t=this,n,r,i;if(t.firstChild){for(n=[],i=t.firstChild;i;i=e(i,t))n.push(i);for(r=n.length;r--;)i=n[r],i.parent=i.firstChild=i.lastChild=i.next=i.prev=null}return t.firstChild=t.lastChild=null,t},isEmpty:function(t){var r=this,i=r.firstChild,o,a;if(i)do{if(1===i.type){if(i.attributes.map["data-mce-bogus"])continue;if(t[i.name])return!1;for(o=i.attributes.length;o--;)if(a=i.attributes[o].name,"name"===a||0===a.indexOf("data-mce-"))return!1}if(8===i.type)return!1;if(3===i.type&&!n.test(i.value))return!1}while(i=e(i,r));return!0},walk:function(t){return e(this,null,t)}},t.create=function(e,n){var i,o;if(i=new t(e,r[e]||1),n)for(o in n)i.attr(o,n[o]);return i},t}),r(x,[p],function(e){function t(e,t){return e?e.split(t||" "):[]}function n(e){function n(e,n,r){function i(e){var t={},n,r;for(n=0,r=e.length;r>n;n++)t[e[n]]={};return t}var o,l,c,u=arguments;for(r=r||[],n=n||"","string"==typeof r&&(r=t(r)),l=3;l<u.length;l++)"string"==typeof u[l]&&(u[l]=t(u[l])),r.push.apply(r,u[l]);for(e=t(e),o=e.length;o--;)c=[].concat(s,t(n)),a[e[o]]={attributes:i(c),attributesOrder:c,children:i(r)}}function i(e,n){var r,i,o,s;for(e=t(e),r=e.length,n=t(n);r--;)for(i=a[e[r]],o=0,s=n.length;s>o;o++)i.attributes[n[o]]={},i.attributesOrder.push(n[o])}var a={},s,l,c,u,d,f,p;return r[e]?r[e]:(s=t("id accesskey class dir lang style tabindex title"),l=t("onabort onblur oncancel oncanplay oncanplaythrough onchange onclick onclose oncontextmenu oncuechange ondblclick ondrag ondragend ondragenter ondragleave ondragover ondragstart ondrop ondurationchange onemptied onended onerror onfocus oninput oninvalid onkeydown onkeypress onkeyup onload onloadeddata onloadedmetadata onloadstart onmousedown onmousemove onmouseout onmouseover onmouseup onmousewheel onpause onplay onplaying onprogress onratechange onreset onscroll onseeked onseeking onseeking onselect onshow onstalled onsubmit onsuspend ontimeupdate onvolumechange onwaiting"),c=t("address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul"),u=t("a abbr b bdo br button cite code del dfn em embed i iframe img input ins kbd label map noscript object q s samp script select small span strong sub sup textarea u var #text #comment"),"html4"!=e&&(s.push.apply(s,t("contenteditable contextmenu draggable dropzone hidden spellcheck translate")),c.push.apply(c,t("article aside details dialog figure header footer hgroup section nav")),u.push.apply(u,t("audio canvas command datalist mark meter output progress time wbr video ruby bdi keygen"))),"html5-strict"!=e&&(s.push("xml:lang"),p=t("acronym applet basefont big font strike tt"),u.push.apply(u,p),o(p,function(e){n(e,"",u)}),f=t("center dir isindex noframes"),c.push.apply(c,f),d=[].concat(c,u),o(f,function(e){n(e,"",d)})),d=d||[].concat(c,u),n("html","manifest","head body"),n("head","","base command link meta noscript script style title"),n("title hr noscript br"),n("base","href target"),n("link","href rel media hreflang type sizes hreflang"),n("meta","name http-equiv content charset"),n("style","media type scoped"),n("script","src async defer type charset"),n("body","onafterprint onbeforeprint onbeforeunload onblur onerror onfocus onhashchange onload onmessage onoffline ononline onpagehide onpageshow onpopstate onresize onscroll onstorage onunload",d),n("address dt dd div caption","",d),n("h1 h2 h3 h4 h5 h6 pre p abbr code var samp kbd sub sup i b u bdo span legend em strong small s cite dfn","",u),n("blockquote","cite",d),n("ol","reversed start type","li"),n("ul","","li"),n("li","value",d),n("dl","","dt dd"),n("a","href target rel media hreflang type",u),n("q","cite",u),n("ins del","cite datetime",d),n("img","src alt usemap ismap width height"),n("iframe","src name width height",d),n("embed","src type width height"),n("object","data type typemustmatch name usemap form width height",d,"param"),n("param","name value"),n("map","name",d,"area"),n("area","alt coords shape href target rel media hreflang type"),n("table","border","caption colgroup thead tfoot tbody tr"+("html4"==e?" col":"")),n("colgroup","span","col"),n("col","span"),n("tbody thead tfoot","","tr"),n("tr","","td th"),n("td","colspan rowspan headers",d),n("th","colspan rowspan headers scope abbr",d),n("form","accept-charset action autocomplete enctype method name novalidate target",d),n("fieldset","disabled form name",d,"legend"),n("label","form for",u),n("input","accept alt autocomplete checked dirname disabled form formaction formenctype formmethod formnovalidate formtarget height list max maxlength min multiple name pattern readonly required size src step type value width"),n("button","disabled form formaction formenctype formmethod formnovalidate formtarget name type value","html4"==e?d:u),n("select","disabled form multiple name required size","option optgroup"),n("optgroup","disabled label","option"),n("option","disabled label selected value"),n("textarea","cols dirname disabled form maxlength name readonly required rows wrap"),n("menu","type label",d,"li"),n("noscript","",d),"html4"!=e&&(n("wbr"),n("ruby","",u,"rt rp"),n("figcaption","",d),n("mark rt rp summary bdi","",u),n("canvas","width height",d),n("video","src crossorigin poster preload autoplay mediagroup loop muted controls width height",d,"track source"),n("audio","src crossorigin preload autoplay mediagroup loop muted controls",d,"track source"),n("source","src type media"),n("track","kind src srclang label default"),n("datalist","",u,"option"),n("article section nav aside header footer","",d),n("hgroup","","h1 h2 h3 h4 h5 h6"),n("figure","",d,"figcaption"),n("time","datetime",u),n("dialog","open",d),n("command","type label icon disabled checked radiogroup command"),n("output","for form name",u),n("progress","value max",u),n("meter","value min max low high optimum",u),n("details","open",d,"summary"),n("keygen","autofocus challenge disabled form keytype name")),"html5-strict"!=e&&(i("script","language xml:space"),i("style","xml:space"),i("object","declare classid codebase codetype archive standby align border hspace vspace"),i("param","valuetype type"),i("a","charset name rev shape coords"),i("br","clear"),i("applet","codebase archive code object alt name width height align hspace vspace"),i("img","name longdesc align border hspace vspace"),i("iframe","longdesc frameborder marginwidth marginheight scrolling align"),i("font basefont","size color face"),i("input","usemap align"),i("select","onchange"),i("textarea"),i("h1 h2 h3 h4 h5 h6 div p legend caption","align"),i("ul","type compact"),i("li","type"),i("ol dl menu dir","compact"),i("pre","width xml:space"),i("hr","align noshade size width"),i("isindex","prompt"),i("table","summary width frame rules cellspacing cellpadding align bgcolor"),i("col","width align char charoff valign"),i("colgroup","width align char charoff valign"),i("thead","align char charoff valign"),i("tr","align char charoff valign bgcolor"),i("th","axis align char charoff valign nowrap bgcolor width height"),i("form","accept"),i("td","abbr axis scope align char charoff valign nowrap bgcolor width height"),i("tfoot","align char charoff valign"),i("tbody","align char charoff valign"),i("area","nohref"),i("body","background bgcolor text link vlink alink")),"html4"!=e&&(i("input button select textarea","autofocus"),i("input textarea","placeholder"),i("a","download"),i("link script img","crossorigin"),i("iframe","srcdoc sandbox seamless allowfullscreen")),o(t("a form meter progress dfn"),function(e){a[e]&&delete a[e].children[e]}),delete a.caption.children.table,r[e]=a,a)}var r={},i=e.makeMap,o=e.each,a=e.extend,s=e.explode,l=e.inArray;return function(e){function c(t,n,o){var s=e[t];return s?s=i(s,",",i(s.toUpperCase()," ")):(s=r[t],s||(s=i(n," ",i(n.toUpperCase()," ")),s=a(s,o),r[t]=s)),s}function u(e){return new RegExp("^"+e.replace(/([?+*])/g,".$1")+"$")}function d(e){var n,r,o,a,s,c,d,f,p,h,m,g,y,C,x,w,_,N,E,k=/^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)\])?$/,S=/^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/,T=/[*?+]/;if(e)for(e=t(e,","),v["@"]&&(w=v["@"].attributes,_=v["@"].attributesOrder),n=0,r=e.length;r>n;n++)if(s=k.exec(e[n])){if(C=s[1],p=s[2],x=s[3],f=s[5],g={},y=[],c={attributes:g,attributesOrder:y},"#"===C&&(c.paddEmpty=!0),"-"===C&&(c.removeEmpty=!0),"!"===s[4]&&(c.removeEmptyAttrs=!0),w){for(N in w)g[N]=w[N];y.push.apply(y,_)}if(f)for(f=t(f,"|"),o=0,a=f.length;a>o;o++)if(s=S.exec(f[o])){if(d={},m=s[1],h=s[2].replace(/::/g,":"),C=s[3],E=s[4],"!"===m&&(c.attributesRequired=c.attributesRequired||[],c.attributesRequired.push(h),d.required=!0),"-"===m){delete g[h],y.splice(l(y,h),1);continue}C&&("="===C&&(c.attributesDefault=c.attributesDefault||[],c.attributesDefault.push({name:h,value:E}),d.defaultValue=E),":"===C&&(c.attributesForced=c.attributesForced||[],c.attributesForced.push({name:h,value:E}),d.forcedValue=E),"<"===C&&(d.validValues=i(E,"?"))),T.test(h)?(c.attributePatterns=c.attributePatterns||[],d.pattern=u(h),c.attributePatterns.push(d)):(g[h]||y.push(h),g[h]=d)}w||"@"!=p||(w=g,_=y),x&&(c.outputName=p,v[x]=c),T.test(p)?(c.pattern=u(p),b.push(c)):v[p]=c}}function f(e){v={},b=[],d(e),o(x,function(e,t){y[t]=e.children})}function p(e){var n=/^(~)?(.+)$/;e&&o(t(e,","),function(e){var t=n.exec(e),r="~"===t[1],i=r?"span":"div",s=t[2];if(y[s]=y[i],R[s]=i,r||(k[s.toUpperCase()]={},k[s]={}),!v[s]){var l=v[i];l=a({},l),delete l.removeEmptyAttrs,delete l.removeEmpty,v[s]=l}o(y,function(e){e[i]&&(e[s]=e[i])})})}function h(e){var n=/^([+\-]?)(\w+)\[([^\]]+)\]$/;e&&o(t(e,","),function(e){var r=n.exec(e),i,a;r&&(a=r[1],i=a?y[r[2]]:y[r[2]]={"#comment":{}},i=y[r[2]],o(t(r[3],"|"),function(e){"-"===a?delete i[e]:i[e]={}}))})}function m(e){var t=v[e],n;if(t)return t;for(n=b.length;n--;)if(t=b[n],t.pattern.test(e))return t}var g=this,v={},y={},b=[],C,x,w,_,N,E,k,S,T,R={},A={};e=e||{},x=n(e.schema),e.verify_html===!1&&(e.valid_elements="*[*]"),e.valid_styles&&(C={},o(e.valid_styles,function(e,t){C[t]=s(e)})),w=c("whitespace_elements","pre script noscript style textarea video audio iframe object"),_=c("self_closing_elements","colgroup dd dt li option p td tfoot th thead tr"),N=c("short_ended_elements","area base basefont br col frame hr img input isindex link meta param embed source wbr track"),E=c("boolean_attributes","checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected autoplay loop controls"),S=c("non_empty_elements","td th iframe video audio object",N),T=c("text_block_elements","h1 h2 h3 h4 h5 h6 p div address pre form blockquote center dir fieldset header footer article section hgroup aside nav figure"),k=c("block_elements","hr table tbody thead tfoot th tr td li ol ul caption dl dt dd noscript menu isindex samp option datalist select optgroup",T),o((e.special||"script noscript style textarea").split(" "),function(e){A[e]=new RegExp("</"+e+"[^>]*>","gi")}),e.valid_elements?f(e.valid_elements):(o(x,function(e,t){v[t]={attributes:e.attributes,attributesOrder:e.attributesOrder},y[t]=e.children}),"html5"!=e.schema&&o(t("strong/b em/i"),function(e){e=t(e,"/"),v[e[1]].outputName=e[0]}),v.img.attributesDefault=[{name:"alt",value:""}],o(t("ol ul sub sup blockquote span font a table tbody tr strong em b i"),function(e){v[e]&&(v[e].removeEmpty=!0)}),o(t("p h1 h2 h3 h4 h5 h6 th td pre div address caption"),function(e){v[e].paddEmpty=!0}),o(t("span"),function(e){v[e].removeEmptyAttrs=!0})),p(e.custom_elements),h(e.valid_children),d(e.extended_valid_elements),h("+ol[ul|ol],+ul[ul|ol]"),e.invalid_elements&&o(s(e.invalid_elements),function(e){v[e]&&delete v[e]}),m("span")||d("span[!data-mce-type|*]"),g.children=y,g.styles=C,g.getBoolAttrs=function(){return E},g.getBlockElements=function(){return k},g.getTextBlockElements=function(){return T},g.getShortEndedElements=function(){return N},g.getSelfClosingElements=function(){return _},g.getNonEmptyElements=function(){return S},g.getWhiteSpaceElements=function(){return w},g.getSpecialElements=function(){return A},g.isValidChild=function(e,t){var n=y[e];return!(!n||!n[t])},g.isValid=function(e,t){var n,r,i=m(e);if(i){if(!t)return!0;if(i.attributes[t])return!0;if(n=i.attributePatterns)for(r=n.length;r--;)if(n[r].pattern.test(e))return!0}return!1},g.getElementRule=m,g.getCustomElements=function(){return R},g.addValidElements=d,g.setValidElements=f,g.addCustomElements=p,g.addValidChildren=h,g.elements=v}}),r(w,[x,m,p],function(e,t,n){var r=n.each;return function(n,i){var o=this,a=function(){};n=n||{},o.schema=i=i||new e,n.fix_self_closing!==!1&&(n.fix_self_closing=!0),r("comment cdata text start end pi doctype".split(" "),function(e){e&&(o[e]=n[e]||a)}),o.parse=function(e){function r(e){var t,n;for(t=d.length;t--&&d[t].name!==e;);if(t>=0){for(n=d.length-1;n>=t;n--)e=d[n],e.valid&&a.end(e.name);d.length=t}}function o(e,t,n,r,i){var o,a;if(t=t.toLowerCase(),n=t in b?t:I(n||r||i||""),x&&!g&&0!==t.indexOf("data-")){if(o=k[t],!o&&S){for(a=S.length;a--&&(o=S[a],!o.pattern.test(t)););-1===a&&(o=null)}if(!o)return;if(o.validValues&&!(n in o.validValues))return}f.map[t]=n,f.push({name:t,value:n})}var a=this,s,l=0,c,u,d=[],f,p,h,m,g,v,y,b,C,x,w,_,N,E,k,S,T,R,A,B,D,L,M,H,P,O=0,I=t.decode,F;for(L=new RegExp("<(?:(?:!--([\\w\\W]*?)-->)|(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)|(?:!DOCTYPE([\\w\\W]*?)>)|(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|(?:\\/([^>]+)>)|(?:([A-Za-z0-9\\-\\:\\.]+)((?:\\s+[^\"'>]+(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>]*))*|\\/|\\s+)>))","g"),M=/([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:[^\"])*)\")|(?:\'((?:[^\'])*)\')|([^>\s]+)))?/g,y=i.getShortEndedElements(),D=n.self_closing_elements||i.getSelfClosingElements(),b=i.getBoolAttrs(),x=n.validate,v=n.remove_internals,F=n.fix_self_closing,H=i.getSpecialElements();s=L.exec(e);){if(l<s.index&&a.text(I(e.substr(l,s.index-l))),c=s[6])c=c.toLowerCase(),":"===c.charAt(0)&&(c=c.substr(1)),r(c);else if(c=s[7]){if(c=c.toLowerCase(),":"===c.charAt(0)&&(c=c.substr(1)),C=c in y,F&&D[c]&&d.length>0&&d[d.length-1].name===c&&r(c),!x||(w=i.getElementRule(c))){if(_=!0,x&&(k=w.attributes,S=w.attributePatterns),(E=s[8])?(g=-1!==E.indexOf("data-mce-type"),g&&v&&(_=!1),f=[],f.map={},E.replace(M,o)):(f=[],f.map={}),x&&!g){if(T=w.attributesRequired,R=w.attributesDefault,A=w.attributesForced,B=w.removeEmptyAttrs,B&&!f.length&&(_=!1),A)for(p=A.length;p--;)N=A[p],m=N.name,P=N.value,"{$uid}"===P&&(P="mce_"+O++),f.map[m]=P,f.push({name:m,value:P});if(R)for(p=R.length;p--;)N=R[p],m=N.name,m in f.map||(P=N.value,"{$uid}"===P&&(P="mce_"+O++),f.map[m]=P,f.push({name:m,value:P}));if(T){for(p=T.length;p--&&!(T[p]in f.map););-1===p&&(_=!1)}f.map["data-mce-bogus"]&&(_=!1)}_&&a.start(c,f,C)}else _=!1;if(u=H[c]){u.lastIndex=l=s.index+s[0].length,(s=u.exec(e))?(_&&(h=e.substr(l,s.index-l)),l=s.index+s[0].length):(h=e.substr(l),l=e.length),_&&(h.length>0&&a.text(h,!0),a.end(c)),L.lastIndex=l;continue}C||(E&&E.indexOf("/")==E.length-1?_&&a.end(c):d.push({name:c,valid:_}))}else(c=s[1])?a.comment(c):(c=s[2])?a.cdata(c):(c=s[3])?a.doctype(c):(c=s[4])&&a.pi(c,s[5]);l=s.index+s[0].length}for(l<e.length&&a.text(I(e.substr(l))),p=d.length-1;p>=0;p--)c=d[p],c.valid&&a.end(c.name)}}}),r(_,[C,x,w,p],function(e,t,n,r){var i=r.makeMap,o=r.each,a=r.explode,s=r.extend;return function(r,l){function c(t){var n,r,o,a,s,c,d,f,p,h,m,g,v,y;for(m=i("tr,td,th,tbody,thead,tfoot,table"),h=l.getNonEmptyElements(),g=l.getTextBlockElements(),n=0;n<t.length;n++)if(r=t[n],r.parent&&!r.fixed)if(g[r.name]&&"li"==r.parent.name){for(v=r.next;v&&g[v.name];)v.name="li",v.fixed=!0,r.parent.insert(v,r.parent),v=v.next;r.unwrap(r)}else{for(a=[r],o=r.parent;o&&!l.isValidChild(o.name,r.name)&&!m[o.name];o=o.parent)a.push(o);if(o&&a.length>1){for(a.reverse(),s=c=u.filterNode(a[0].clone()),p=0;p<a.length-1;p++){for(l.isValidChild(c.name,a[p].name)?(d=u.filterNode(a[p].clone()),c.append(d)):d=c,f=a[p].firstChild;f&&f!=a[p+1];)y=f.next,d.append(f),f=y;c=d}s.isEmpty(h)?o.insert(r,a[0],!0):(o.insert(s,a[0],!0),o.insert(r,s)),o=a[0],(o.isEmpty(h)||o.firstChild===o.lastChild&&"br"===o.firstChild.name)&&o.empty().remove()}else if(r.parent){if("li"===r.name){if(v=r.prev,v&&("ul"===v.name||"ul"===v.name)){v.append(r);continue}if(v=r.next,v&&("ul"===v.name||"ul"===v.name)){v.insert(r,v.firstChild,!0);continue}r.wrap(u.filterNode(new e("ul",1)));continue}l.isValidChild(r.parent.name,"div")&&l.isValidChild("div",r.name)?r.wrap(u.filterNode(new e("div",1))):"style"===r.name||"script"===r.name?r.empty().remove():r.unwrap()}}}var u=this,d={},f=[],p={},h={};r=r||{},r.validate="validate"in r?r.validate:!0,r.root_name=r.root_name||"body",u.schema=l=l||new t,u.filterNode=function(e){var t,n,r;n in d&&(r=p[n],r?r.push(e):p[n]=[e]),t=f.length;for(;t--;)n=f[t].name,n in e.attributes.map&&(r=h[n],r?r.push(e):h[n]=[e]);return e},u.addNodeFilter=function(e,t){o(a(e),function(e){var n=d[e];n||(d[e]=n=[]),n.push(t)})},u.addAttributeFilter=function(e,t){o(a(e),function(e){var n;for(n=0;n<f.length;n++)if(f[n].name===e)return f[n].callbacks.push(t),void 0;f.push({name:e,callbacks:[t]})})},u.parse=function(t,o){function a(){function e(e){e&&(t=e.firstChild,t&&3==t.type&&(t.value=t.value.replace(R,"")),t=e.lastChild,t&&3==t.type&&(t.value=t.value.replace(D,"")))}var t=y.firstChild,n,r;if(l.isValidChild(y.name,I.toLowerCase())){for(;t;)n=t.next,3==t.type||1==t.type&&"p"!==t.name&&!T[t.name]&&!t.attr("data-mce-type")?r?r.append(t):(r=u(I,1),y.insert(r,t),r.append(t)):(e(r),r=null),t=n;e(r)}}function u(t,n){var r=new e(t,n),i;return t in d&&(i=p[t],i?i.push(r):p[t]=[r]),r}function m(e){var t,n,r;for(t=e.prev;t&&3===t.type;)n=t.value.replace(D,""),n.length>0?(t.value=n,t=t.prev):(r=t.prev,t.remove(),t=r)}function g(e){var t,n={};for(t in e)"li"!==t&&"p"!=t&&(n[t]=e[t]);return n}var v,y,b,C,x,w,_,N,E,k,S,T,R,A=[],B,D,L,M,H,P,O,I;if(o=o||{},p={},h={},T=s(i("script,style,head,html,body,title,meta,param"),l.getBlockElements()),O=l.getNonEmptyElements(),P=l.children,S=r.validate,I="forced_root_block"in o?o.forced_root_block:r.forced_root_block,H=l.getWhiteSpaceElements(),R=/^[ \t\r\n]+/,D=/[ \t\r\n]+$/,L=/[ \t\r\n]+/g,M=/^[ \t\r\n]+$/,v=new n({validate:S,self_closing_elements:g(l.getSelfClosingElements()),cdata:function(e){b.append(u("#cdata",4)).value=e},text:function(e,t){var n;B||(e=e.replace(L," "),b.lastChild&&T[b.lastChild.name]&&(e=e.replace(R,""))),0!==e.length&&(n=u("#text",3),n.raw=!!t,b.append(n).value=e)},comment:function(e){b.append(u("#comment",8)).value=e},pi:function(e,t){b.append(u(e,7)).value=t,m(b)},doctype:function(e){var t;t=b.append(u("#doctype",10)),t.value=e,m(b)},start:function(e,t,n){var r,i,o,a,s;if(o=S?l.getElementRule(e):{}){for(r=u(o.outputName||e,1),r.attributes=t,r.shortEnded=n,b.append(r),s=P[b.name],s&&P[r.name]&&!s[r.name]&&A.push(r),i=f.length;i--;)a=f[i].name,a in t.map&&(E=h[a],E?E.push(r):h[a]=[r]);T[e]&&m(r),n||(b=r),!B&&H[e]&&(B=!0)}},end:function(t){var n,r,i,o,a;if(r=S?l.getElementRule(t):{}){if(T[t]&&!B){if(n=b.firstChild,n&&3===n.type)if(i=n.value.replace(R,""),i.length>0)n.value=i,n=n.next;else for(o=n.next,n.remove(),n=o;n&&3===n.type;)i=n.value,o=n.next,(0===i.length||M.test(i))&&(n.remove(),n=o),n=o;if(n=b.lastChild,n&&3===n.type)if(i=n.value.replace(D,""),i.length>0)n.value=i,n=n.prev;else for(o=n.prev,n.remove(),n=o;n&&3===n.type;)i=n.value,o=n.prev,(0===i.length||M.test(i))&&(n.remove(),n=o),n=o}if(B&&H[t]&&(B=!1),(r.removeEmpty||r.paddEmpty)&&b.isEmpty(O))if(r.paddEmpty)b.empty().append(new e("#text","3")).value="\xa0";else if(!b.attributes.map.name&&!b.attributes.map.id)return a=b.parent,b.empty().remove(),b=a,void 0;b=b.parent}}},l),y=b=new e(o.context||r.root_name,11),v.parse(t),S&&A.length&&(o.context?o.invalid=!0:c(A)),I&&("body"==y.name||o.isRootContent)&&a(),!o.invalid){for(k in p){for(E=d[k],C=p[k],_=C.length;_--;)C[_].parent||C.splice(_,1);for(x=0,w=E.length;w>x;x++)E[x](C,k,o)}for(x=0,w=f.length;w>x;x++)if(E=f[x],E.name in h){for(C=h[E.name],_=C.length;_--;)C[_].parent||C.splice(_,1);for(_=0,N=E.callbacks.length;N>_;_++)E.callbacks[_](C,E.name,o)}}return y},r.remove_trailing_brs&&u.addNodeFilter("br",function(t){var n,r=t.length,i,o=s({},l.getBlockElements()),a=l.getNonEmptyElements(),c,u,d,f,p,h;for(o.body=1,n=0;r>n;n++)if(i=t[n],c=i.parent,o[i.parent.name]&&i===c.lastChild){for(d=i.prev;d;){if(f=d.name,"span"!==f||"bookmark"!==d.attr("data-mce-type")){if("br"!==f)break;if("br"===f){i=null;break}}d=d.prev}i&&(i.remove(),c.isEmpty(a)&&(p=l.getElementRule(c.name),p&&(p.removeEmpty?c.remove():p.paddEmpty&&(c.empty().append(new e("#text",3)).value="\xa0"))))}else{for(u=i;c&&c.firstChild===u&&c.lastChild===u&&(u=c,!o[c.name]);)c=c.parent;u===c&&(h=new e("#text",3),h.value="\xa0",i.replace(h))}}),r.allow_html_in_named_anchor||u.addAttributeFilter("id,name",function(e){for(var t=e.length,n,r,i,o;t--;)if(o=e[t],"a"===o.name&&o.firstChild&&!o.attr("href")){i=o.parent,n=o.lastChild;do r=n.prev,i.insert(n,o),n=r;while(n)}})}}),r(N,[m,p],function(e,t){var n=t.makeMap;return function(t){var r=[],i,o,a,s,l;return t=t||{},i=t.indent,o=n(t.indent_before||""),a=n(t.indent_after||""),s=e.getEncodeFunc(t.entity_encoding||"raw",t.entities),l="html"==t.element_format,{start:function(e,t,n){var c,u,d,f;if(i&&o[e]&&r.length>0&&(f=r[r.length-1],f.length>0&&"\n"!==f&&r.push("\n")),r.push("<",e),t)for(c=0,u=t.length;u>c;c++)d=t[c],r.push(" ",d.name,'="',s(d.value,!0),'"');r[r.length]=!n||l?">":" />",n&&i&&a[e]&&r.length>0&&(f=r[r.length-1],f.length>0&&"\n"!==f&&r.push("\n"))},end:function(e){var t;r.push("</",e,">"),i&&a[e]&&r.length>0&&(t=r[r.length-1],t.length>0&&"\n"!==t&&r.push("\n"))},text:function(e,t){e.length>0&&(r[r.length]=t?e:s(e))},cdata:function(e){r.push("<![CDATA[",e,"]]>")},comment:function(e){r.push("<!--",e,"-->")},pi:function(e,t){t?r.push("<?",e," ",t,"?>"):r.push("<?",e,"?>"),i&&r.push("\n")},doctype:function(e){r.push("<!DOCTYPE",e,">",i?"\n":"")},reset:function(){r.length=0},getContent:function(){return r.join("").replace(/\n$/,"")}}}}),r(E,[N,x],function(e,t){return function(n,r){var i=this,o=new e(n);n=n||{},n.validate="validate"in n?n.validate:!0,i.schema=r=r||new t,i.writer=o,i.serialize=function(e){function t(e){var n=i[e.type],s,l,c,u,d,f,p,h,m;if(n)n(e);else{if(s=e.name,l=e.shortEnded,c=e.attributes,a&&c&&c.length>1){for(f=[],f.map={},m=r.getElementRule(e.name),p=0,h=m.attributesOrder.length;h>p;p++)u=m.attributesOrder[p],u in c.map&&(d=c.map[u],f.map[u]=d,f.push({name:u,value:d}));for(p=0,h=c.length;h>p;p++)u=c[p].name,u in f.map||(d=c.map[u],f.map[u]=d,f.push({name:u,value:d}));c=f}if(o.start(e.name,c,l),!l){if(e=e.firstChild)do t(e);while(e=e.next);o.end(s)}}}var i,a;return a=n.validate,i={3:function(e){o.text(e.value,e.raw)},8:function(e){o.comment(e.value)},7:function(e){o.pi(e.name,e.value)},10:function(e){o.doctype(e.value)},4:function(e){o.cdata(e.value)},11:function(e){if(e=e.firstChild)do t(e);while(e=e.next)}},o.reset(),1!=e.type||n.inner?i[11](e):t(e),o.getContent()}}}),r(k,[v,_,m,E,C,x,g,p],function(e,t,n,r,i,o,a,s){var l=s.each,c=s.trim,u=e.DOM;return function(e,i){var s,d,f;return i&&(s=i.dom,d=i.schema),s=s||u,d=d||new o(e),e.entity_encoding=e.entity_encoding||"named",e.remove_trailing_brs="remove_trailing_brs"in e?e.remove_trailing_brs:!0,f=new t(e,d),f.addAttributeFilter("src,href,style",function(t,n){for(var r=t.length,i,o,a="data-mce-"+n,l=e.url_converter,c=e.url_converter_scope,u;r--;)i=t[r],o=i.attributes.map[a],o!==u?(i.attr(n,o.length>0?o:null),i.attr(a,null)):(o=i.attributes.map[n],"style"===n?o=s.serializeStyle(s.parseStyle(o),i.name):l&&(o=l.call(c,o,n,i.name)),i.attr(n,o.length>0?o:null))}),f.addAttributeFilter("class",function(e){for(var t=e.length,n,r;t--;)n=e[t],r=n.attr("class").replace(/(?:^|\s)mce-item-\w+(?!\S)/g,""),n.attr("class",r.length>0?r:null)}),f.addAttributeFilter("data-mce-type",function(e,t,n){for(var r=e.length,i;r--;)i=e[r],"bookmark"!==i.attributes.map["data-mce-type"]||n.cleanup||i.remove()}),f.addAttributeFilter("data-mce-expando",function(e,t){for(var n=e.length;n--;)e[n].attr(t,null)}),f.addNodeFilter("noscript",function(e){for(var t=e.length,r;t--;)r=e[t].firstChild,r&&(r.value=n.decode(r.value))}),f.addNodeFilter("script,style",function(e,t){function n(e){return e.replace(/(<!--\[CDATA\[|\]\]-->)/g,"\n").replace(/^[\r\n]*|[\r\n]*$/g,"").replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi,"").replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g,"")}for(var r=e.length,i,o;r--;)if(i=e[r],o=i.firstChild?i.firstChild.value:"","script"===t){var a=(i.attr("type")||"text/javascript").replace(/^mce\-/,"");i.attr("type","text/javascript"===a?null:a),o.length>0&&(i.firstChild.value="// <![CDATA[\n"+n(o)+"\n// ]]>")}else o.length>0&&(i.firstChild.value="<!--\n"+n(o)+"\n-->")}),f.addNodeFilter("#comment",function(e){for(var t=e.length,n;t--;)n=e[t],0===n.value.indexOf("[CDATA[")?(n.name="#cdata",n.type=4,n.value=n.value.replace(/^\[CDATA\[|\]\]$/g,"")):0===n.value.indexOf("mce:protected ")&&(n.name="#text",n.type=3,n.raw=!0,n.value=unescape(n.value).substr(14))}),f.addNodeFilter("xml:namespace,input",function(e,t){for(var n=e.length,r;n--;)r=e[n],7===r.type?r.remove():1===r.type&&("input"!==t||"type"in r.attributes.map||r.attr("type","text"))}),e.fix_list_elements&&f.addNodeFilter("ul,ol",function(e){for(var t=e.length,n,r;t--;)n=e[t],r=n.parent,("ul"===r.name||"ol"===r.name)&&n.prev&&"li"===n.prev.name&&n.prev.append(n)}),f.addAttributeFilter("data-mce-src,data-mce-href,data-mce-style,data-mce-selected",function(e,t){for(var n=e.length;n--;)e[n].attr(t,null)}),{schema:d,addNodeFilter:f.addNodeFilter,addAttributeFilter:f.addAttributeFilter,serialize:function(t,n){var i=this,o,u,p,h,m;return a.ie&&s.select("script,style,select,map").length>0?(m=t.innerHTML,t=t.cloneNode(!1),s.setHTML(t,m)):t=t.cloneNode(!0),o=t.ownerDocument.implementation,o.createHTMLDocument&&(u=o.createHTMLDocument(""),l("BODY"==t.nodeName?t.childNodes:[t],function(e){u.body.appendChild(u.importNode(e,!0))}),t="BODY"!=t.nodeName?u.body.firstChild:u.body,p=s.doc,s.doc=u),n=n||{},n.format=n.format||"html",n.selection&&(n.forced_root_block=""),n.no_events||(n.node=t,i.onPreProcess(n)),h=new r(e,d),n.content=h.serialize(f.parse(c(n.getInner?t.innerHTML:s.getOuterHTML(t)),n)),n.cleanup||(n.content=n.content.replace(/\uFEFF/g,"")),n.no_events||i.onPostProcess(n),p&&(s.doc=p),n.node=null,n.content},addRules:function(e){d.addValidElements(e)},setRules:function(e){d.setValidElements(e)},onPreProcess:function(e){i&&i.fire("PreProcess",e)},onPostProcess:function(e){i&&i.fire("PostProcess",e)}}}}),r(S,[],function(){function e(e){function t(t,n){var r,i=0,o,a,s,l,c,u,d=-1,f;if(r=t.duplicate(),r.collapse(n),f=r.parentElement(),f.ownerDocument===e.dom.doc){for(;"false"===f.contentEditable;)f=f.parentNode;if(!f.hasChildNodes())return{node:f,inside:1};for(s=f.children,o=s.length-1;o>=i;)if(u=Math.floor((i+o)/2),l=s[u],r.moveToElementText(l),d=r.compareEndPoints(n?"StartToStart":"EndToEnd",t),d>0)o=u-1;else{if(!(0>d))return{node:l};i=u+1}if(0>d)for(l?r.collapse(!1):(r.moveToElementText(f),r.collapse(!0),l=f,a=!0),c=0;0!==r.compareEndPoints(n?"StartToStart":"StartToEnd",t)&&0!==r.move("character",1)&&f==r.parentElement();)c++;else for(r.collapse(!0),c=0;0!==r.compareEndPoints(n?"StartToStart":"StartToEnd",t)&&0!==r.move("character",-1)&&f==r.parentElement();)c++;return{node:l,position:d,offset:c,inside:a}}}function n(){function n(e){var n=t(o,e),r,i,s=0,l,c,u;if(r=n.node,i=n.offset,n.inside&&!r.hasChildNodes())return a[e?"setStart":"setEnd"](r,0),void 0;if(i===c)return a[e?"setStartBefore":"setEndAfter"](r),void 0;if(n.position<0){if(l=n.inside?r.firstChild:r.nextSibling,!l)return a[e?"setStartAfter":"setEndAfter"](r),void 0;if(!i)return 3==l.nodeType?a[e?"setStart":"setEnd"](l,0):a[e?"setStartBefore":"setEndBefore"](l),void 0;for(;l;){if(u=l.nodeValue,s+=u.length,s>=i){r=l,s-=i,s=u.length-s;break}l=l.nextSibling}}else{if(l=r.previousSibling,!l)return a[e?"setStartBefore":"setEndBefore"](r);if(!i)return 3==r.nodeType?a[e?"setStart":"setEnd"](l,r.nodeValue.length):a[e?"setStartAfter":"setEndAfter"](l),void 0;for(;l;){if(s+=l.nodeValue.length,s>=i){r=l,s-=i;break}l=l.previousSibling}}a[e?"setStart":"setEnd"](r,s)}var o=e.getRng(),a=i.createRng(),s,l,c,u,d;if(s=o.item?o.item(0):o.parentElement(),s.ownerDocument!=i.doc)return a;if(l=e.isCollapsed(),o.item)return a.setStart(s.parentNode,i.nodeIndex(s)),a.setEnd(a.startContainer,a.startOffset+1),a;try{n(!0),l||n()}catch(f){if(-2147024809!=f.number)throw f;d=r.getBookmark(2),c=o.duplicate(),c.collapse(!0),s=c.parentElement(),l||(c=o.duplicate(),c.collapse(!1),u=c.parentElement(),u.innerHTML=u.innerHTML),s.innerHTML=s.innerHTML,r.moveToBookmark(d),o=e.getRng(),n(!0),l||n()}return a}var r=this,i=e.dom,o=!1;this.getBookmark=function(n){function r(e){var t,n,r,o,a=[];for(t=e.parentNode,n=i.getRoot().parentNode;t!=n&&9!==t.nodeType;){for(r=t.children,o=r.length;o--;)if(e===r[o]){a.push(o);break}e=t,t=t.parentNode}return a}function o(e){var n;return n=t(a,e),n?{position:n.position,offset:n.offset,indexes:r(n.node),inside:n.inside}:void 0}var a=e.getRng(),s={};return 2===n&&(a.item?s.start={ctrl:!0,indexes:r(a.item(0))}:(s.start=o(!0),e.isCollapsed()||(s.end=o()))),s},this.moveToBookmark=function(e){function t(e){var t,n,r,o;for(t=i.getRoot(),n=e.length-1;n>=0;n--)o=t.children,r=e[n],r<=o.length-1&&(t=o[r]);return t}function n(n){var i=e[n?"start":"end"],a,s,l,c;i&&(a=i.position>0,s=o.createTextRange(),s.moveToElementText(t(i.indexes)),c=i.offset,c!==l?(s.collapse(i.inside||a),s.moveStart("character",a?-c:c)):s.collapse(n),r.setEndPoint(n?"StartToStart":"EndToStart",s),n&&r.collapse(!0))}var r,o=i.doc.body;e.start&&(e.start.ctrl?(r=o.createControlRange(),r.addElement(t(e.start.indexes)),r.select()):(r=o.createTextRange(),n(!0),n(),r.select()))},this.addRange=function(t){function n(e){var t,n,a,d,h;a=i.create("a"),t=e?s:c,n=e?l:u,d=r.duplicate(),(t==f||t==f.documentElement)&&(t=p,n=0),3==t.nodeType?(t.parentNode.insertBefore(a,t),d.moveToElementText(a),d.moveStart("character",n),i.remove(a),r.setEndPoint(e?"StartToStart":"EndToEnd",d)):(h=t.childNodes,h.length?(n>=h.length?i.insertAfter(a,h[h.length-1]):t.insertBefore(a,h[n]),d.moveToElementText(a)):t.canHaveHTML&&(t.innerHTML="<span>&#xFEFF;</span>",a=t.firstChild,d.moveToElementText(a),d.collapse(o)),r.setEndPoint(e?"StartToStart":"EndToEnd",d),i.remove(a))
+}var r,a,s,l,c,u,d,f=e.dom.doc,p=f.body,h,m;if(s=t.startContainer,l=t.startOffset,c=t.endContainer,u=t.endOffset,r=p.createTextRange(),s==c&&1==s.nodeType){if(l==u&&!s.hasChildNodes()){if(s.canHaveHTML)return d=s.previousSibling,d&&!d.hasChildNodes()&&i.isBlock(d)?d.innerHTML="&#xFEFF;":d=null,s.innerHTML="<span>&#xFEFF;</span><span>&#xFEFF;</span>",r.moveToElementText(s.lastChild),r.select(),i.doc.selection.clear(),s.innerHTML="",d&&(d.innerHTML=""),void 0;l=i.nodeIndex(s),s=s.parentNode}if(l==u-1)try{if(m=s.childNodes[l],a=p.createControlRange(),a.addElement(m),a.select(),h=e.getRng(),h.item&&m===h.item(0))return}catch(g){}}n(!0),n(),r.select()},this.getRangeAt=n}return e}),r(T,[g],function(e){return{BACKSPACE:8,DELETE:46,DOWN:40,ENTER:13,LEFT:37,RIGHT:39,SPACEBAR:32,TAB:9,UP:38,modifierPressed:function(e){return e.shiftKey||e.ctrlKey||e.altKey},metaKeyPressed:function(t){return(e.mac?t.ctrlKey||t.metaKey:t.ctrlKey)&&!t.altKey}}}),r(R,[T,p,g],function(e,t,n){return function(r,i){function o(e){return i.settings.object_resizing===!1?!1:/TABLE|IMG|DIV/.test(e.nodeName)?"false"===e.getAttribute("data-mce-resize")?!1:!0:!1}function a(t){var n,r;n=t.screenX-k,r=t.screenY-S,M=n*N[2]+A,H=r*N[3]+B,M=5>M?5:M,H=5>H?5:H,(e.modifierPressed(t)||"IMG"==x.nodeName&&0!==N[2]*N[3])&&(M=Math.round(H/D),H=Math.round(M*D)),b.setStyles(w,{width:M,height:H}),N[2]<0&&w.clientWidth<=M&&b.setStyle(w,"left",T+(A-M)),N[3]<0&&w.clientHeight<=H&&b.setStyle(w,"top",R+(B-H)),L||(i.fire("ObjectResizeStart",{target:x,width:A,height:B}),L=!0)}function s(){function e(e,t){t&&(x.style[e]||!i.schema.isValid(x.nodeName.toLowerCase(),e)?b.setStyle(x,e,t):b.setAttrib(x,e,t))}L=!1,e("width",M),e("height",H),b.unbind(P,"mousemove",a),b.unbind(P,"mouseup",s),O!=P&&(b.unbind(O,"mousemove",a),b.unbind(O,"mouseup",s)),b.remove(w),I&&"TABLE"!=x.nodeName||l(x),i.fire("ObjectResized",{target:x,width:M,height:H}),i.nodeChanged()}function l(e,t,n){var r,l,u,d,f,p=i.getBody().offsetParent||i.getBody();r=b.getPos(e,p),T=r.x,R=r.y,f=e.getBoundingClientRect(),l=f.width||f.right-f.left,u=f.height||f.bottom-f.top,x!=e&&(m(),x=e,M=H=0),d=i.fire("ObjectSelected",{target:e}),o(e)&&!d.isDefaultPrevented()?C(_,function(e,r){function o(t){L=!0,k=t.screenX,S=t.screenY,A=x.clientWidth,B=x.clientHeight,D=B/A,N=e,w=x.cloneNode(!0),b.addClass(w,"mce-clonedresizable"),w.contentEditable=!1,w.unSelectabe=!0,b.setStyles(w,{left:T,top:R,margin:0}),w.removeAttribute("data-mce-selected"),i.getBody().appendChild(w),b.bind(P,"mousemove",a),b.bind(P,"mouseup",s),O!=P&&(b.bind(O,"mousemove",a),b.bind(O,"mouseup",s))}var c,d;return t?(r==t&&o(n),void 0):(c=b.get("mceResizeHandle"+r),c?b.show(c):(d=i.getBody(),c=b.add(d,"div",{id:"mceResizeHandle"+r,"data-mce-bogus":!0,"class":"mce-resizehandle",contentEditable:!1,unSelectabe:!0,style:"cursor:"+r+"-resize; margin:0; padding:0"}),b.bind(c,"mousedown",function(e){e.preventDefault(),o(e)})),b.setStyles(c,{left:l*e[0]+T-c.offsetWidth/2,top:u*e[1]+R-c.offsetHeight/2}),void 0)}):c(),x.setAttribute("data-mce-selected","1")}function c(){var e,t;x&&x.removeAttribute("data-mce-selected");for(e in _)t=b.get("mceResizeHandle"+e),t&&(b.unbind(t),b.remove(t))}function u(e){function t(e,t){do if(e===t)return!0;while(e=e.parentNode)}var n;return C(b.select("img[data-mce-selected],hr[data-mce-selected]"),function(e){e.removeAttribute("data-mce-selected")}),n="mousedown"==e.type?e.target:r.getNode(),n=b.getParent(n,I?"table":"table,img,hr"),n&&(g(),t(r.getStart(),n)&&t(r.getEnd(),n)&&(!I||n!=r.getStart()&&"IMG"!==r.getStart().nodeName))?(l(n),void 0):(c(),void 0)}function d(e,t,n){e&&e.attachEvent&&e.attachEvent("on"+t,n)}function f(e,t,n){e&&e.detachEvent&&e.detachEvent("on"+t,n)}function p(e){var t=e.srcElement,n,r,o,a,s,c,u;n=t.getBoundingClientRect(),c=E.clientX-n.left,u=E.clientY-n.top;for(r in _)if(o=_[r],a=t.offsetWidth*o[0],s=t.offsetHeight*o[1],Math.abs(a-c)<8&&Math.abs(s-u)<8){N=o;break}L=!0,i.getDoc().selection.empty(),l(t,r,E)}function h(e){var t=e.srcElement;if(t!=x){if(m(),0===t.id.indexOf("mceResizeHandle"))return e.returnValue=!1,void 0;("IMG"==t.nodeName||"TABLE"==t.nodeName)&&(c(),x=t,d(t,"resizestart",p))}}function m(){f(x,"resizestart",p)}function g(){try{i.getDoc().execCommand("enableObjectResizing",!1,!1)}catch(e){}}function v(e){var t;if(I){t=P.body.createControlRange();try{return t.addElement(e),t.select(),!0}catch(n){}}}function y(){x=w=null,I&&(m(),f(i.getBody(),"controlselect",h))}var b=i.dom,C=t.each,x,w,_,N,E,k,S,T,R,A,B,D,L,M,H,P=i.getDoc(),O=document,I=n.ie&&n.ie<11;_={n:[.5,0,0,-1],e:[1,.5,1,0],s:[.5,1,0,1],w:[0,.5,-1,0],nw:[0,0,-1,-1],ne:[1,0,1,-1],se:[1,1,1,1],sw:[0,1,-1,1]};var F=".mce-content-body";return i.contentStyles.push(F+" div.mce-resizehandle {"+"position: absolute;"+"border: 1px solid black;"+"background: #FFF;"+"width: 5px;"+"height: 5px;"+"z-index: 10000"+"}"+F+" .mce-resizehandle:hover {"+"background: #000"+"}"+F+" img[data-mce-selected], hr[data-mce-selected] {"+"outline: 1px solid black;"+"resize: none"+"}"+F+" .mce-clonedresizable {"+"position: absolute;"+(n.gecko?"":"outline: 1px dashed black;")+"opacity: .5;"+"filter: alpha(opacity=50);"+"z-index: 10000"+"}"),i.on("init",function(){I?(i.on("ObjectResized",function(e){"TABLE"!=e.target.nodeName&&(c(),v(e.target))}),d(i.getBody(),"controlselect",h),i.on("mousedown",function(e){E=e})):(g(),n.ie>=11&&i.on("mouseup mousedown",function(e){("IMG"==e.target.nodeName||"IMG"==i.selection.getNode().nodeName)&&(e.preventDefault(),i.selection.select(e.target))})),i.on("nodechange mousedown ResizeEditor",u),i.on("keydown keyup",function(e){x&&"TABLE"==x.nodeName&&u(e)})}),{controlSelect:v,destroy:y}}}),r(A,[f,S,R,g,p],function(e,n,r,i,o){function a(e,t,i,o){var a=this;a.dom=e,a.win=t,a.serializer=i,a.editor=o,a.controlSelection=new r(a,o),a.win.getSelection||(a.tridentSel=new n(a))}var s=o.each,l=o.grep,c=o.trim,u=i.ie,d=i.opera;return a.prototype={setCursorLocation:function(e,t){var n=this,r=n.dom.createRng();r.setStart(e,t),r.setEnd(e,t),n.setRng(r),n.collapse(!1)},getContent:function(e){var n=this,r=n.getRng(),i=n.dom.create("body"),o=n.getSel(),a,s,l;return e=e||{},a=s="",e.get=!0,e.format=e.format||"html",e.selection=!0,n.editor.fire("BeforeGetContent",e),"text"==e.format?n.isCollapsed()?"":r.text||(o.toString?o.toString():""):(r.cloneContents?(l=r.cloneContents(),l&&i.appendChild(l)):r.item!==t||r.htmlText!==t?(i.innerHTML="<br>"+(r.item?r.item(0).outerHTML:r.htmlText),i.removeChild(i.firstChild)):i.innerHTML=r.toString(),/^\s/.test(i.innerHTML)&&(a=" "),/\s+$/.test(i.innerHTML)&&(s=" "),e.getInner=!0,e.content=n.isCollapsed()?"":a+n.serializer.serialize(i,e)+s,n.editor.fire("GetContent",e),e.content)},setContent:function(e,t){var n=this,r=n.getRng(),i,o=n.win.document,a,s;if(t=t||{format:"html"},t.set=!0,t.selection=!0,e=t.content=e,t.no_events||n.editor.fire("BeforeSetContent",t),e=t.content,r.insertNode){e+='<span id="__caret">_</span>',r.startContainer==o&&r.endContainer==o?o.body.innerHTML=e:(r.deleteContents(),0===o.body.childNodes.length?o.body.innerHTML=e:r.createContextualFragment?r.insertNode(r.createContextualFragment(e)):(a=o.createDocumentFragment(),s=o.createElement("div"),a.appendChild(s),s.outerHTML=e,r.insertNode(a))),i=n.dom.get("__caret"),r=o.createRange(),r.setStartBefore(i),r.setEndBefore(i),n.setRng(r),n.dom.remove("__caret");try{n.setRng(r)}catch(l){}}else r.item&&(o.execCommand("Delete",!1,null),r=n.getRng()),/^\s+/.test(e)?(r.pasteHTML('<span id="__mce_tmp">_</span>'+e),n.dom.remove("__mce_tmp")):r.pasteHTML(e);t.no_events||n.editor.fire("SetContent",t)},getStart:function(){var e=this,t=e.getRng(),n,r,i,o;if(t.duplicate||t.item){if(t.item)return t.item(0);for(i=t.duplicate(),i.collapse(1),n=i.parentElement(),n.ownerDocument!==e.dom.doc&&(n=e.dom.getRoot()),r=o=t.parentElement();o=o.parentNode;)if(o==n){n=r;break}return n}return n=t.startContainer,1==n.nodeType&&n.hasChildNodes()&&(n=n.childNodes[Math.min(n.childNodes.length-1,t.startOffset)]),n&&3==n.nodeType?n.parentNode:n},getEnd:function(){var e=this,t=e.getRng(),n,r;return t.duplicate||t.item?t.item?t.item(0):(t=t.duplicate(),t.collapse(0),n=t.parentElement(),n.ownerDocument!==e.dom.doc&&(n=e.dom.getRoot()),n&&"BODY"==n.nodeName?n.lastChild||n:n):(n=t.endContainer,r=t.endOffset,1==n.nodeType&&n.hasChildNodes()&&(n=n.childNodes[r>0?r-1:r]),n&&3==n.nodeType?n.parentNode:n)},getBookmark:function(e,t){function n(e,t){var n=0;return s(a.select(e),function(e,r){e==t&&(n=r)}),n}function r(e){function t(t){var n,r,i,o=t?"start":"end";n=e[o+"Container"],r=e[o+"Offset"],1==n.nodeType&&"TR"==n.nodeName&&(i=n.childNodes,n=i[Math.min(t?r:r-1,i.length-1)],n&&(r=t?0:n.childNodes.length,e["set"+(t?"Start":"End")](n,r)))}return t(!0),t(),e}function i(){function e(e,n){var i=e[n?"startContainer":"endContainer"],a=e[n?"startOffset":"endOffset"],s=[],l,c,u=0;if(3==i.nodeType){if(t)for(l=i.previousSibling;l&&3==l.nodeType;l=l.previousSibling)a+=l.nodeValue.length;s.push(a)}else c=i.childNodes,a>=c.length&&c.length&&(u=1,a=Math.max(0,c.length-1)),s.push(o.dom.nodeIndex(c[a],t)+u);for(;i&&i!=r;i=i.parentNode)s.push(o.dom.nodeIndex(i,t));return s}var n=o.getRng(!0),r=a.getRoot(),i={};return i.start=e(n,!0),o.isCollapsed()||(i.end=e(n)),i}var o=this,a=o.dom,l,c,u,d,f,p,h="&#xFEFF;",m;if(2==e)return p=o.getNode(),f=p.nodeName,"IMG"==f?{name:f,index:n(f,p)}:o.tridentSel?o.tridentSel.getBookmark(e):i();if(e)return{rng:o.getRng()};if(l=o.getRng(),u=a.uniqueId(),d=o.isCollapsed(),m="overflow:hidden;line-height:0px",l.duplicate||l.item){if(l.item)return p=l.item(0),f=p.nodeName,{name:f,index:n(f,p)};c=l.duplicate();try{l.collapse(),l.pasteHTML('<span data-mce-type="bookmark" id="'+u+'_start" style="'+m+'">'+h+"</span>"),d||(c.collapse(!1),l.moveToElementText(c.parentElement()),0===l.compareEndPoints("StartToEnd",c)&&c.move("character",-1),c.pasteHTML('<span data-mce-type="bookmark" id="'+u+'_end" style="'+m+'">'+h+"</span>"))}catch(g){return null}}else{if(p=o.getNode(),f=p.nodeName,"IMG"==f)return{name:f,index:n(f,p)};c=r(l.cloneRange()),d||(c.collapse(!1),c.insertNode(a.create("span",{"data-mce-type":"bookmark",id:u+"_end",style:m},h))),l=r(l),l.collapse(!0),l.insertNode(a.create("span",{"data-mce-type":"bookmark",id:u+"_start",style:m},h))}return o.moveToBookmark({id:u,keep:1}),{id:u}},moveToBookmark:function(e){function t(t){var n=e[t?"start":"end"],r,i,o,s;if(n){for(o=n[0],i=c,r=n.length-1;r>=1;r--){if(s=i.childNodes,n[r]>s.length-1)return;i=s[n[r]]}3===i.nodeType&&(o=Math.min(n[0],i.nodeValue.length)),1===i.nodeType&&(o=Math.min(n[0],i.childNodes.length)),t?a.setStart(i,o):a.setEnd(i,o)}return!0}function n(t){var n=o.get(e.id+"_"+t),r,i,a,c,u=e.keep;if(n&&(r=n.parentNode,"start"==t?(u?(r=n.firstChild,i=1):i=o.nodeIndex(n),f=p=r,h=m=i):(u?(r=n.firstChild,i=1):i=o.nodeIndex(n),p=r,m=i),!u)){for(c=n.previousSibling,a=n.nextSibling,s(l(n.childNodes),function(e){3==e.nodeType&&(e.nodeValue=e.nodeValue.replace(/\uFEFF/g,""))});n=o.get(e.id+"_"+t);)o.remove(n,1);c&&a&&c.nodeType==a.nodeType&&3==c.nodeType&&!d&&(i=c.nodeValue.length,c.appendData(a.nodeValue),o.remove(a),"start"==t?(f=p=c,h=m=i):(p=c,m=i))}}function r(e){return!o.isBlock(e)||e.innerHTML||u||(e.innerHTML='<br data-mce-bogus="1" />'),e}var i=this,o=i.dom,a,c,f,p,h,m;if(e)if(e.start){if(a=o.createRng(),c=o.getRoot(),i.tridentSel)return i.tridentSel.moveToBookmark(e);t(!0)&&t()&&i.setRng(a)}else e.id?(n("start"),n("end"),f&&(a=o.createRng(),a.setStart(r(f),h),a.setEnd(r(p),m),i.setRng(a))):e.name?i.select(o.select(e.name)[e.index]):e.rng&&i.setRng(e.rng)},select:function(t,n){function r(t,n){var r=new e(t,t);do{if(3==t.nodeType&&0!==c(t.nodeValue).length)return n?a.setStart(t,0):a.setEnd(t,t.nodeValue.length),void 0;if("BR"==t.nodeName)return n?a.setStartBefore(t):a.setEndBefore(t),void 0}while(t=n?r.next():r.prev())}var i=this,o=i.dom,a=o.createRng(),s;if(i.lastFocusBookmark=null,t){if(!n&&i.controlSelection.controlSelect(t))return;s=o.nodeIndex(t),a.setStart(t.parentNode,s),a.setEnd(t.parentNode,s+1),n&&(r(t,1),r(t)),i.setRng(a)}return t},isCollapsed:function(){var e=this,t=e.getRng(),n=e.getSel();return!t||t.item?!1:t.compareEndPoints?0===t.compareEndPoints("StartToEnd",t):!n||t.collapsed},collapse:function(e){var t=this,n=t.getRng(),r;n.item&&(r=n.item(0),n=t.win.document.body.createTextRange(),n.moveToElementText(r)),n.collapse(!!e),t.setRng(n)},getSel:function(){var e=this.win;return e.getSelection?e.getSelection():e.document.selection},getRng:function(e){var t=this,n,r,i,o=t.win.document,a;if(!e&&t.lastFocusBookmark){var s=t.lastFocusBookmark;return s.startContainer?(r=o.createRange(),r.setStart(s.startContainer,s.startOffset),r.setEnd(s.endContainer,s.endOffset)):r=s,r}if(e&&t.tridentSel)return t.tridentSel.getRangeAt(0);try{(n=t.getSel())&&(r=n.rangeCount>0?n.getRangeAt(0):n.createRange?n.createRange():o.createRange())}catch(l){}if(u&&r&&r.setStart){try{a=o.selection.createRange()}catch(l){}a&&a.item&&(i=a.item(0),r=o.createRange(),r.setStartBefore(i),r.setEndAfter(i))}return r||(r=o.createRange?o.createRange():o.body.createTextRange()),r.setStart&&9===r.startContainer.nodeType&&r.collapsed&&(i=t.dom.getRoot(),r.setStart(i,0),r.setEnd(i,0)),t.selectedRange&&t.explicitRange&&(0===r.compareBoundaryPoints(r.START_TO_START,t.selectedRange)&&0===r.compareBoundaryPoints(r.END_TO_END,t.selectedRange)?r=t.explicitRange:(t.selectedRange=null,t.explicitRange=null)),r},setRng:function(e,t){var n=this,r;if(e.select)try{e.select()}catch(i){}else if(n.tridentSel){if(e.cloneRange)try{return n.tridentSel.addRange(e),void 0}catch(i){}}else if(r=n.getSel()){n.explicitRange=e;try{r.removeAllRanges(),r.addRange(e)}catch(i){}t===!1&&r.extend&&(r.collapse(e.endContainer,e.endOffset),r.extend(e.startContainer,e.startOffset)),n.selectedRange=r.rangeCount>0?r.getRangeAt(0):null}},setNode:function(e){var t=this;return t.setContent(t.dom.getOuterHTML(e)),e},getNode:function(){function e(e,t){for(var n=e;e&&3===e.nodeType&&0===e.length;)e=t?e.nextSibling:e.previousSibling;return e||n}var t=this,n=t.getRng(),r,i=n.startContainer,o=n.endContainer,a=n.startOffset,s=n.endOffset;return n?n.setStart?(r=n.commonAncestorContainer,!n.collapsed&&(i==o&&2>s-a&&i.hasChildNodes()&&(r=i.childNodes[a]),3===i.nodeType&&3===o.nodeType&&(i=i.length===a?e(i.nextSibling,!0):i.parentNode,o=0===s?e(o.previousSibling,!1):o.parentNode,i&&i===o))?i:r&&3==r.nodeType?r.parentNode:r):n.item?n.item(0):n.parentElement():t.dom.getRoot()},getSelectedBlocks:function(t,n){var r=this,i=r.dom,o,a,s=[];if(a=i.getRoot(),t=i.getParent(t||r.getStart(),i.isBlock),n=i.getParent(n||r.getEnd(),i.isBlock),t&&t!=a&&s.push(t),t&&n&&t!=n){o=t;for(var l=new e(t,a);(o=l.next())&&o!=n;)i.isBlock(o)&&s.push(o)}return n&&t!=n&&n!=a&&s.push(n),s},isForward:function(){var e=this.dom,t=this.getSel(),n,r;return t&&t.anchorNode&&t.focusNode?(n=e.createRng(),n.setStart(t.anchorNode,t.anchorOffset),n.collapse(!0),r=e.createRng(),r.setStart(t.focusNode,t.focusOffset),r.collapse(!0),n.compareBoundaryPoints(n.START_TO_START,r)<=0):!0},normalize:function(){function t(t){function a(t,n){for(var r=new e(t,f.getParent(t.parentNode,f.isBlock)||p);t=r[n?"prev":"next"]();)if("BR"===t.nodeName)return!0}function s(e,t){return e.previousSibling&&e.previousSibling.nodeName==t}function l(t,n){var r,a;for(n=n||c,r=new e(n,f.getParent(n.parentNode,f.isBlock)||p);h=r[t?"prev":"next"]();){if(3===h.nodeType&&h.nodeValue.length>0)return c=h,u=t?h.nodeValue.length:0,i=!0,void 0;if(f.isBlock(h)||m[h.nodeName.toLowerCase()])return;a=h}o&&a&&(c=a,i=!0,u=0)}var c,u,d,f=n.dom,p=f.getRoot(),h,m,g;if(c=r[(t?"start":"end")+"Container"],u=r[(t?"start":"end")+"Offset"],m=f.schema.getNonEmptyElements(),9===c.nodeType&&(c=f.getRoot(),u=0),c===p){if(t&&(h=c.childNodes[u>0?u-1:0],h&&(g=h.nodeName.toLowerCase(),m[h.nodeName]||"TABLE"==h.nodeName)))return;if(c.hasChildNodes()&&(u=Math.min(!t&&u>0?u-1:u,c.childNodes.length-1),c=c.childNodes[u],u=0,c.hasChildNodes()&&!/TABLE/.test(c.nodeName))){h=c,d=new e(c,p);do{if(3===h.nodeType&&h.nodeValue.length>0){u=t?0:h.nodeValue.length,c=h,i=!0;break}if(m[h.nodeName.toLowerCase()]){u=f.nodeIndex(h),c=h.parentNode,"IMG"!=h.nodeName||t||u++,i=!0;break}}while(h=t?d.next():d.prev())}}o&&(3===c.nodeType&&0===u&&l(!0),1===c.nodeType&&(h=c.childNodes[u],!h||"BR"!==h.nodeName||s(h,"A")||a(h)||a(h,!0)||l(!0,c.childNodes[u]))),t&&!o&&3===c.nodeType&&u===c.nodeValue.length&&l(!1),i&&r["set"+(t?"Start":"End")](c,u)}var n=this,r,i,o;u||(r=n.getRng(),o=r.collapsed,t(!0),o||t(),i&&(o&&r.collapse(!0),n.setRng(r,n.isForward())))},selectorChanged:function(e,t){var n=this,r;return n.selectorChangedData||(n.selectorChangedData={},r={},n.editor.on("NodeChange",function(e){var t=e.element,i=n.dom,o=i.getParents(t,null,i.getRoot()),a={};s(n.selectorChangedData,function(e,t){s(o,function(n){return i.is(n,t)?(r[t]||(s(e,function(e){e(!0,{node:n,selector:t,parents:o})}),r[t]=e),a[t]=e,!1):void 0})}),s(r,function(e,n){a[n]||(delete r[n],s(e,function(e){e(!1,{node:t,selector:n,parents:o})}))})})),n.selectorChangedData[e]||(n.selectorChangedData[e]=[]),n.selectorChangedData[e].push(t),n},scrollIntoView:function(e){var t,n,r=this,i=r.dom;n=i.getViewPort(r.editor.getWin()),t=i.getPos(e).y,(t<n.y||t+25>n.y+n.h)&&r.editor.getWin().scrollTo(0,t<n.y?t:t-n.h+25)},destroy:function(){this.win=null,this.controlSelection.destroy()}},a}),r(B,[p],function(e){function t(e){this.walk=function(t,r){function i(e){var t;return t=e[0],3===t.nodeType&&t===l&&c>=t.nodeValue.length&&e.splice(0,1),t=e[e.length-1],0===d&&e.length>0&&t===u&&3===t.nodeType&&e.splice(e.length-1,1),e}function o(e,t,n){for(var r=[];e&&e!=n;e=e[t])r.push(e);return r}function a(e,t){do{if(e.parentNode==t)return e;e=e.parentNode}while(e)}function s(e,t,n){var a=n?"nextSibling":"previousSibling";for(m=e,g=m.parentNode;m&&m!=t;m=g)g=m.parentNode,v=o(m==e?m:m[a],a),v.length&&(n||v.reverse(),r(i(v)))}var l=t.startContainer,c=t.startOffset,u=t.endContainer,d=t.endOffset,f,p,h,m,g,v,y;if(y=e.select("td.mce-item-selected,th.mce-item-selected"),y.length>0)return n(y,function(e){r([e])}),void 0;if(1==l.nodeType&&l.hasChildNodes()&&(l=l.childNodes[c]),1==u.nodeType&&u.hasChildNodes()&&(u=u.childNodes[Math.min(d-1,u.childNodes.length-1)]),l==u)return r(i([l]));for(f=e.findCommonAncestor(l,u),m=l;m;m=m.parentNode){if(m===u)return s(l,f,!0);if(m===f)break}for(m=u;m;m=m.parentNode){if(m===l)return s(u,f);if(m===f)break}p=a(l,f)||l,h=a(u,f)||u,s(l,p,!0),v=o(p==l?p:p.nextSibling,"nextSibling",h==u?h.nextSibling:h),v.length&&r(i(v)),s(u,h)},this.split=function(e){function t(e,t){return e.splitText(t)}var n=e.startContainer,r=e.startOffset,i=e.endContainer,o=e.endOffset;return n==i&&3==n.nodeType?r>0&&r<n.nodeValue.length&&(i=t(n,r),n=i.previousSibling,o>r?(o-=r,n=i=t(i,o).previousSibling,o=i.nodeValue.length,r=0):o=0):(3==n.nodeType&&r>0&&r<n.nodeValue.length&&(n=t(n,r),r=0),3==i.nodeType&&o>0&&o<i.nodeValue.length&&(i=t(i,o).previousSibling,o=i.nodeValue.length)),{startContainer:n,startOffset:r,endContainer:i,endOffset:o}}}var n=e.each;return t.compareRanges=function(e,t){if(e&&t){if(!e.item&&!e.duplicate)return e.startContainer==t.startContainer&&e.startOffset==t.startOffset;if(e.item&&t.item&&e.item(0)===t.item(0))return!0;if(e.isEqual&&t.isEqual&&t.isEqual(e))return!0}return!1},t}),r(D,[f,B,p],function(e,t,n){return function(r){function i(e){return e.nodeType&&(e=e.nodeName),!!r.schema.getTextBlockElements()[e.toLowerCase()]}function o(e,t){return I.getParents(e,t,I.getRoot())}function a(e){return 1===e.nodeType&&"_mce_caret"===e.id}function s(){u({alignleft:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"left"},defaultBlock:"div"},{selector:"img,table",collapsed:!1,styles:{"float":"left"}}],aligncenter:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"center"},defaultBlock:"div"},{selector:"img",collapsed:!1,styles:{display:"block",marginLeft:"auto",marginRight:"auto"}},{selector:"table",collapsed:!1,styles:{marginLeft:"auto",marginRight:"auto"}}],alignright:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"right"},defaultBlock:"div"},{selector:"img,table",collapsed:!1,styles:{"float":"right"}}],alignjustify:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"justify"},defaultBlock:"div"}],bold:[{inline:"strong",remove:"all"},{inline:"span",styles:{fontWeight:"bold"}},{inline:"b",remove:"all"}],italic:[{inline:"em",remove:"all"},{inline:"span",styles:{fontStyle:"italic"}},{inline:"i",remove:"all"}],underline:[{inline:"span",styles:{textDecoration:"underline"},exact:!0},{inline:"u",remove:"all"}],strikethrough:[{inline:"span",styles:{textDecoration:"line-through"},exact:!0},{inline:"strike",remove:"all"}],forecolor:{inline:"span",styles:{color:"%value"},wrap_links:!1},hilitecolor:{inline:"span",styles:{backgroundColor:"%value"},wrap_links:!1},fontname:{inline:"span",styles:{fontFamily:"%value"}},fontsize:{inline:"span",styles:{fontSize:"%value"}},fontsize_class:{inline:"span",attributes:{"class":"%value"}},blockquote:{block:"blockquote",wrapper:1,remove:"all"},subscript:{inline:"sub"},superscript:{inline:"sup"},code:{inline:"code"},link:{inline:"a",selector:"a",remove:"all",split:!0,deep:!0,onmatch:function(){return!0},onformat:function(e,t,n){et(n,function(t,n){I.setAttrib(e,n,t)})}},removeformat:[{selector:"b,strong,em,i,font,u,strike,sub,sup",remove:"all",split:!0,expand:!1,block_expand:!0,deep:!0},{selector:"span",attributes:["style","class"],remove:"empty",split:!0,expand:!1,deep:!0},{selector:"*",attributes:["style","class"],split:!1,expand:!1,deep:!0}]}),et("p h1 h2 h3 h4 h5 h6 div address pre div dt dd samp".split(/\s/),function(e){u(e,{block:e,remove:"all"})}),u(r.settings.formats)}function l(){r.addShortcut("ctrl+b","bold_desc","Bold"),r.addShortcut("ctrl+i","italic_desc","Italic"),r.addShortcut("ctrl+u","underline_desc","Underline");for(var e=1;6>=e;e++)r.addShortcut("ctrl+"+e,"",["FormatBlock",!1,"h"+e]);r.addShortcut("ctrl+7","",["FormatBlock",!1,"p"]),r.addShortcut("ctrl+8","",["FormatBlock",!1,"div"]),r.addShortcut("ctrl+9","",["FormatBlock",!1,"address"])}function c(e){return e?O[e]:O}function u(e,t){e&&("string"!=typeof e?et(e,function(e,t){u(t,e)}):(t=t.length?t:[t],et(t,function(e){e.deep===X&&(e.deep=!e.selector),e.split===X&&(e.split=!e.selector||e.inline),e.remove===X&&e.selector&&!e.inline&&(e.remove="none"),e.selector&&e.inline&&(e.mixed=!0,e.block_expand=!0),"string"==typeof e.classes&&(e.classes=e.classes.split(/\s+/))}),O[e]=t))}function d(e){var t;return r.dom.getParent(e,function(e){return t=r.dom.getStyle(e,"text-decoration"),t&&"none"!==t}),t}function f(e){var t;1===e.nodeType&&e.parentNode&&1===e.parentNode.nodeType&&(t=d(e.parentNode),r.dom.getStyle(e,"color")&&t?r.dom.setStyle(e,"text-decoration",t):r.dom.getStyle(e,"textdecoration")===t&&r.dom.setStyle(e,"text-decoration",null))}function p(t,n,o){function s(e,t){t=t||m,e&&(t.onformat&&t.onformat(e,t,n,o),et(t.styles,function(t,r){I.setStyle(e,r,E(t,n))}),et(t.attributes,function(t,r){I.setAttrib(e,r,E(t,n))}),et(t.classes,function(t){t=E(t,n),I.hasClass(e,t)||I.addClass(e,t)}))}function l(){function t(t,n){var r=new e(n);for(o=r.current();o;o=r.prev())if(o.childNodes.length>1||o==t||"BR"==o.tagName)return o}var n=r.selection.getRng(),i=n.startContainer,a=n.endContainer;if(i!=a&&0===n.endOffset){var s=t(i,a),l=3==s.nodeType?s.length:s.childNodes.length;n.setEnd(s,l)}return n}function u(e,t,n,r,i){var o=[],a=-1,s,l=-1,c=-1,u;return et(e.childNodes,function(e,t){return"UL"===e.nodeName||"OL"===e.nodeName?(a=t,s=e,!1):void 0}),et(e.childNodes,function(e,n){"SPAN"===e.nodeName&&"bookmark"==I.getAttrib(e,"data-mce-type")&&(e.id==t.id+"_start"?l=n:e.id==t.id+"_end"&&(c=n))}),0>=a||a>l&&c>a?(et(tt(e.childNodes),i),0):(u=I.clone(n,K),et(tt(e.childNodes),function(e,t){(a>l&&a>t||l>a&&t>a)&&(o.push(e),e.parentNode.removeChild(e))}),a>l?e.insertBefore(u,s):l>a&&e.insertBefore(u,s.nextSibling),r.push(u),et(o,function(e){u.appendChild(e)}),u)}function d(e,r,o){var l=[],c,d,f=!0;c=m.inline||m.block,d=I.create(c),s(d),W.walk(e,function(e){function p(e){var y,C,x,_,N;return N=f,y=e.nodeName.toLowerCase(),C=e.parentNode.nodeName.toLowerCase(),1===e.nodeType&&J(e)&&(N=f,f="true"===J(e),_=!0),w(y,"br")?(v=0,m.block&&I.remove(e),void 0):m.wrapper&&g(e,t,n)?(v=0,void 0):f&&!_&&m.block&&!m.wrapper&&i(y)&&z(C,c)?(e=I.rename(e,c),s(e),l.push(e),v=0,void 0):m.selector&&(et(h,function(t){"collapsed"in t&&t.collapsed!==b||I.is(e,t.selector)&&!a(e)&&(s(e,t),x=!0)}),!m.inline||x)?(v=0,void 0):(!f||_||!z(c,y)||!z(C,c)||!o&&3===e.nodeType&&1===e.nodeValue.length&&65279===e.nodeValue.charCodeAt(0)||a(e)||m.inline&&V(e)?"li"==y&&r?v=u(e,r,d,l,p):(v=0,et(tt(e.childNodes),p),_&&(f=N),v=0):(v||(v=I.clone(d,K),e.parentNode.insertBefore(v,e),l.push(v)),v.appendChild(e)),void 0)}var v;et(e,p)}),m.wrap_links===!1&&et(l,function(e){function t(e){var n,r,i;if("A"===e.nodeName){for(r=I.clone(d,K),l.push(r),i=tt(e.childNodes),n=0;n<i.length;n++)r.appendChild(i[n]);e.appendChild(r)}et(tt(e.childNodes),t)}t(e)}),et(l,function(e){function r(e){var t=0;return et(e.childNodes,function(e){k(e)||D(e)||t++}),t}function i(e){var t,n;return et(e.childNodes,function(e){return 1!=e.nodeType||D(e)||a(e)?void 0:(t=e,K)}),t&&x(t,m)&&(n=I.clone(t,K),s(n),I.replace(n,e,G),I.remove(t,1)),n||e}var o;if(o=r(e),(l.length>1||!V(e))&&0===o)return I.remove(e,1),void 0;if(m.inline||m.wrapper){if(m.exact||1!==o||(e=i(e)),et(h,function(t){et(I.select(t.inline,e),function(e){var r;if(t.wrap_links===!1){r=e.parentNode;do if("A"===r.nodeName)return;while(r=r.parentNode)}R(t,n,e,t.exact?e:null)})}),g(e.parentNode,t,n))return I.remove(e,1),e=0,G;m.merge_with_parents&&I.getParent(e.parentNode,function(r){return g(r,t,n)?(I.remove(e,1),e=0,G):void 0}),e&&m.merge_siblings!==!1&&(e=L(B(e),e),e=L(e,B(e,G)))}})}var h=c(t),m=h[0],v,y,b=!o&&F.isCollapsed();if(m)if(o)o.nodeType?(y=I.createRng(),y.setStartBefore(o),y.setEndAfter(o),d(T(y,h),null,!0)):d(o,null,!0);else if(b&&m.inline&&!I.select("td.mce-item-selected,th.mce-item-selected").length)H("apply",t,n);else{var C=r.selection.getNode();U||!h[0].defaultBlock||I.getParent(C,I.isBlock)||p(h[0].defaultBlock),r.selection.setRng(l()),v=F.getBookmark(),d(T(F.getRng(G),h),v),m.styles&&(m.styles.color||m.styles.textDecoration)&&(nt(C,f,"childNodes"),f(C)),F.moveToBookmark(v),P(F.getRng(G)),r.nodeChanged()}}function h(e,t,n){function i(e){var n,r,o,a,s;if(1===e.nodeType&&J(e)&&(a=b,b="true"===J(e),s=!0),n=tt(e.childNodes),b&&!s)for(r=0,o=p.length;o>r&&!R(p[r],t,e,e);r++);if(h.deep&&n.length){for(r=0,o=n.length;o>r;r++)i(n[r]);s&&(b=a)}}function a(n){var r;return et(o(n.parentNode).reverse(),function(n){var i;r||"_start"==n.id||"_end"==n.id||(i=g(n,e,t),i&&i.split!==!1&&(r=n))}),r}function s(e,n,r,i){var o,a,s,l,c,u;if(e){for(u=e.parentNode,o=n.parentNode;o&&o!=u;o=o.parentNode){for(a=I.clone(o,K),c=0;c<p.length;c++)if(R(p[c],t,a,a)){a=0;break}a&&(s&&a.appendChild(s),l||(l=a),s=a)}!i||h.mixed&&V(e)||(n=I.split(e,n)),s&&(r.parentNode.insertBefore(s,r),l.appendChild(r))}return n}function l(e){return s(a(e),e,e,!0)}function u(e){var t=I.get(e?"_start":"_end"),n=t[e?"firstChild":"lastChild"];return D(n)&&(n=n[e?"firstChild":"lastChild"]),I.remove(t,!0),n}function f(e){var t,n;e=T(e,p,G),h.split&&(t=M(e,G),n=M(e),t!=n?(/^(TR|TD)$/.test(t.nodeName)&&t.firstChild&&(t="TD"==t.nodeName?t.firstChild||t:t.firstChild.firstChild||t),t=S(t,"span",{id:"_start","data-mce-type":"bookmark"}),n=S(n,"span",{id:"_end","data-mce-type":"bookmark"}),l(t),l(n),t=u(G),n=u()):t=n=l(t),e.startContainer=t.parentNode,e.startOffset=q(t),e.endContainer=n.parentNode,e.endOffset=q(n)+1),W.walk(e,function(e){et(e,function(e){i(e),1===e.nodeType&&"underline"===r.dom.getStyle(e,"text-decoration")&&e.parentNode&&"underline"===d(e.parentNode)&&R({deep:!1,exact:!0,inline:"span",styles:{textDecoration:"underline"}},null,e)})})}var p=c(e),h=p[0],m,y,b=!0;return n?(n.nodeType?(y=I.createRng(),y.setStartBefore(n),y.setEndAfter(n),f(y)):f(n),void 0):(F.isCollapsed()&&h.inline&&!I.select("td.mce-item-selected,th.mce-item-selected").length?H("remove",e,t):(m=F.getBookmark(),f(F.getRng(G)),F.moveToBookmark(m),h.inline&&v(e,t,F.getStart())&&P(F.getRng(!0)),r.nodeChanged()),void 0)}function m(e,t,n){var r=c(e);!v(e,t,n)||"toggle"in r[0]&&!r[0].toggle?p(e,t,n):h(e,t,n)}function g(e,t,n,r){function i(e,t,i){var o,a,s=t[i],l;if(t.onmatch)return t.onmatch(e,t,i);if(s)if(s.length===X){for(o in s)if(s.hasOwnProperty(o)){if(a="attributes"===i?I.getAttrib(e,o):_(e,o),r&&!a&&!t.exact)return;if((!r||t.exact)&&!w(a,N(E(s[o],n),o)))return}}else for(l=0;l<s.length;l++)if("attributes"===i?I.getAttrib(e,s[l]):_(e,s[l]))return t;return t}var o=c(t),a,s,l;if(o&&e)for(s=0;s<o.length;s++)if(a=o[s],x(e,a)&&i(e,a,"attributes")&&i(e,a,"styles")){if(l=a.classes)for(s=0;s<l.length;s++)if(!I.hasClass(e,l[s]))return;return a}}function v(e,t,n){function r(n){var r=I.getRoot();return n=I.getParent(n,function(n){return n.parentNode===r||!!g(n,e,t,!0)}),g(n,e,t)}var i;return n?r(n):(n=F.getNode(),r(n)?G:(i=F.getStart(),i!=n&&r(i)?G:K))}function y(e,t){var n,r=[],i={};return n=F.getStart(),I.getParent(n,function(n){var o,a;for(o=0;o<e.length;o++)a=e[o],!i[a]&&g(n,a,t)&&(i[a]=!0,r.push(a))},I.getRoot()),r}function b(e){var t=c(e),n,r,i,a,s;if(t)for(n=F.getStart(),r=o(n),a=t.length-1;a>=0;a--){if(s=t[a].selector,!s||t[a].defaultBlock)return G;for(i=r.length-1;i>=0;i--)if(I.is(r[i],s))return G}return K}function C(e,t,n){var i;return Y||(Y={},i={},r.on("NodeChange",function(e){var t=o(e.element),n={};et(Y,function(e,r){et(t,function(o){return g(o,r,{},e.similar)?(i[r]||(et(e,function(e){e(!0,{node:o,format:r,parents:t})}),i[r]=e),n[r]=e,!1):void 0})}),et(i,function(r,o){n[o]||(delete i[o],et(r,function(n){n(!1,{node:e.element,format:o,parents:t})}))})})),et(e.split(","),function(e){Y[e]||(Y[e]=[],Y[e].similar=n),Y[e].push(t)}),this}function x(e,t){return w(e,t.inline)?G:w(e,t.block)?G:t.selector?1==e.nodeType&&I.is(e,t.selector):void 0}function w(e,t){return e=e||"",t=t||"",e=""+(e.nodeName||e),t=""+(t.nodeName||t),e.toLowerCase()==t.toLowerCase()}function _(e,t){return N(I.getStyle(e,t),t)}function N(e,t){return("color"==t||"backgroundColor"==t)&&(e=I.toHex(e)),"fontWeight"==t&&700==e&&(e="bold"),"fontFamily"==t&&(e=e.replace(/[\'\"]/g,"").replace(/,\s+/g,",")),""+e}function E(e,t){return"string"!=typeof e?e=e(t):t&&(e=e.replace(/%(\w+)/g,function(e,n){return t[n]||e})),e}function k(e){return e&&3===e.nodeType&&/^([\t \r\n]+|)$/.test(e.nodeValue)}function S(e,t,n){var r=I.create(t,n);return e.parentNode.insertBefore(r,e),r.appendChild(e),r}function T(t,n,a){function s(e){function t(e){return"BR"==e.nodeName&&e.getAttribute("data-mce-bogus")&&!e.nextSibling}var r,i,o,a,s;if(r=i=e?g:y,a=e?"previousSibling":"nextSibling",s=I.getRoot(),3==r.nodeType&&!k(r)&&(e?v>0:b<r.nodeValue.length))return r;for(;;){if(!n[0].block_expand&&V(i))return i;for(o=i[a];o;o=o[a])if(!D(o)&&!k(o)&&!t(o))return i;if(i.parentNode==s){r=i;break}i=i.parentNode}return r}function l(e,t){for(t===X&&(t=3===e.nodeType?e.length:e.childNodes.length);e&&e.hasChildNodes();)e=e.childNodes[t],e&&(t=3===e.nodeType?e.length:e.childNodes.length);return{node:e,offset:t}}function c(e){for(var t=e;t;){if(1===t.nodeType&&J(t))return"false"===J(t)?t:e;t=t.parentNode}return e}function u(t,n,i){function o(e,t){var n,r,o=e.nodeValue;return"undefined"==typeof t&&(t=i?o.length:0),i?(n=o.lastIndexOf(" ",t),r=o.lastIndexOf("\xa0",t),n=n>r?n:r,-1===n||a||n++):(n=o.indexOf(" ",t),r=o.indexOf("\xa0",t),n=-1!==n&&(-1===r||r>n)?n:r),n}var s,l,c,u;if(3===t.nodeType){if(c=o(t,n),-1!==c)return{container:t,offset:c};u=t}for(s=new e(t,I.getParent(t,V)||r.getBody());l=s[i?"prev":"next"]();)if(3===l.nodeType){if(u=l,c=o(l),-1!==c)return{container:l,offset:c}}else if(V(l))break;return u?(n=i?0:u.length,{container:u,offset:n}):void 0}function d(e,r){var i,a,s,l;for(3==e.nodeType&&0===e.nodeValue.length&&e[r]&&(e=e[r]),i=o(e),a=0;a<i.length;a++)for(s=0;s<n.length;s++)if(l=n[s],!("collapsed"in l&&l.collapsed!==t.collapsed)&&I.is(i[a],l.selector))return i[a];
+return e}function f(e,t){var r,a=I.getRoot();if(n[0].wrapper||(r=I.getParent(e,n[0].block)),r||(r=I.getParent(3==e.nodeType?e.parentNode:e,function(e){return e!=a&&i(e)})),r&&n[0].wrapper&&(r=o(r,"ul,ol").reverse()[0]||r),!r)for(r=e;r[t]&&!V(r[t])&&(r=r[t],!w(r,"br")););return r||e}var p,h,m,g=t.startContainer,v=t.startOffset,y=t.endContainer,b=t.endOffset;if(1==g.nodeType&&g.hasChildNodes()&&(p=g.childNodes.length-1,g=g.childNodes[v>p?p:v],3==g.nodeType&&(v=0)),1==y.nodeType&&y.hasChildNodes()&&(p=y.childNodes.length-1,y=y.childNodes[b>p?p:b-1],3==y.nodeType&&(b=y.nodeValue.length)),g=c(g),y=c(y),(D(g.parentNode)||D(g))&&(g=D(g)?g:g.parentNode,g=g.nextSibling||g,3==g.nodeType&&(v=0)),(D(y.parentNode)||D(y))&&(y=D(y)?y:y.parentNode,y=y.previousSibling||y,3==y.nodeType&&(b=y.length)),n[0].inline&&(t.collapsed&&(m=u(g,v,!0),m&&(g=m.container,v=m.offset),m=u(y,b),m&&(y=m.container,b=m.offset)),h=l(y,b),h.node)){for(;h.node&&0===h.offset&&h.node.previousSibling;)h=l(h.node.previousSibling);h.node&&h.offset>0&&3===h.node.nodeType&&" "===h.node.nodeValue.charAt(h.offset-1)&&h.offset>1&&(y=h.node,y.splitText(h.offset-1))}return(n[0].inline||n[0].block_expand)&&(n[0].inline&&3==g.nodeType&&0!==v||(g=s(!0)),n[0].inline&&3==y.nodeType&&b!==y.nodeValue.length||(y=s())),n[0].selector&&n[0].expand!==K&&!n[0].inline&&(g=d(g,"previousSibling"),y=d(y,"nextSibling")),(n[0].block||n[0].selector)&&(g=f(g,"previousSibling"),y=f(y,"nextSibling"),n[0].block&&(V(g)||(g=s(!0)),V(y)||(y=s()))),1==g.nodeType&&(v=q(g),g=g.parentNode),1==y.nodeType&&(b=q(y)+1,y=y.parentNode),{startContainer:g,startOffset:v,endContainer:y,endOffset:b}}function R(e,t,n,r){var i,o,a;if(!x(n,e))return K;if("all"!=e.remove)for(et(e.styles,function(e,i){e=N(E(e,t),i),"number"==typeof i&&(i=e,r=0),(!r||w(_(r,i),e))&&I.setStyle(n,i,""),a=1}),a&&""===I.getAttrib(n,"style")&&(n.removeAttribute("style"),n.removeAttribute("data-mce-style")),et(e.attributes,function(e,i){var o;if(e=E(e,t),"number"==typeof i&&(i=e,r=0),!r||w(I.getAttrib(r,i),e)){if("class"==i&&(e=I.getAttrib(n,i),e&&(o="",et(e.split(/\s+/),function(e){/mce\w+/.test(e)&&(o+=(o?" ":"")+e)}),o)))return I.setAttrib(n,i,o),void 0;"class"==i&&n.removeAttribute("className"),$.test(i)&&n.removeAttribute("data-mce-"+i),n.removeAttribute(i)}}),et(e.classes,function(e){e=E(e,t),(!r||I.hasClass(r,e))&&I.removeClass(n,e)}),o=I.getAttribs(n),i=0;i<o.length;i++)if(0!==o[i].nodeName.indexOf("_"))return K;return"none"!=e.remove?(A(n,e),G):void 0}function A(e,t){function n(e,t,n){return e=B(e,t,n),!e||"BR"==e.nodeName||V(e)}var r=e.parentNode,i;t.block&&(U?r==I.getRoot()&&(t.list_block&&w(e,t.list_block)||et(tt(e.childNodes),function(e){z(U,e.nodeName.toLowerCase())?i?i.appendChild(e):i=S(e,U):i=0})):V(e)&&!V(r)&&(n(e,K)||n(e.firstChild,G,1)||e.insertBefore(I.create("br"),e.firstChild),n(e,G)||n(e.lastChild,K,1)||e.appendChild(I.create("br")))),t.selector&&t.inline&&!w(t.inline,e)||I.remove(e,1)}function B(e,t,n){if(e)for(t=t?"nextSibling":"previousSibling",e=n?e:e[t];e;e=e[t])if(1==e.nodeType||!k(e))return e}function D(e){return e&&1==e.nodeType&&"bookmark"==e.getAttribute("data-mce-type")}function L(e,t){function n(e,t){function n(e){var t={};return et(I.getAttribs(e),function(n){var r=n.nodeName.toLowerCase();0!==r.indexOf("_")&&"style"!==r&&(t[r]=I.getAttrib(e,r))}),t}function r(e,t){var n,r;for(r in e)if(e.hasOwnProperty(r)){if(n=t[r],n===X)return K;if(e[r]!=n)return K;delete t[r]}for(r in t)if(t.hasOwnProperty(r))return K;return G}return e.nodeName!=t.nodeName?K:r(n(e),n(t))?r(I.parseStyle(I.getAttrib(e,"style")),I.parseStyle(I.getAttrib(t,"style")))?G:K:K}function r(e,t){for(i=e;i;i=i[t]){if(3==i.nodeType&&0!==i.nodeValue.length)return e;if(1==i.nodeType&&!D(i))return i}return e}var i,o;if(e&&t&&(e=r(e,"previousSibling"),t=r(t,"nextSibling"),n(e,t))){for(i=e.nextSibling;i&&i!=t;)o=i,i=i.nextSibling,e.appendChild(o);return I.remove(t),et(tt(t.childNodes),function(t){e.appendChild(t)}),e}return t}function M(t,n){var i,o,a;return i=t[n?"startContainer":"endContainer"],o=t[n?"startOffset":"endOffset"],1==i.nodeType&&(a=i.childNodes.length-1,!n&&o&&o--,i=i.childNodes[o>a?a:o]),3===i.nodeType&&n&&o>=i.nodeValue.length&&(i=new e(i,r.getBody()).next()||i),3!==i.nodeType||n||0!==o||(i=new e(i,r.getBody()).prev()||i),i}function H(t,n,o){function a(e){var t=I.create("span",{id:y,"data-mce-bogus":!0,style:b?"color:red":""});return e&&t.appendChild(r.getDoc().createTextNode(j)),t}function s(e,t){for(;e;){if(3===e.nodeType&&e.nodeValue!==j||e.childNodes.length>1)return!1;t&&1===e.nodeType&&t.push(e),e=e.firstChild}return!0}function l(e){for(;e;){if(e.id===y)return e;e=e.parentNode}}function u(t){var n;if(t)for(n=new e(t,t),t=n.current();t;t=n.next())if(3===t.nodeType)return t}function d(e,t){var n,r;if(e)r=F.getRng(!0),s(e)?(t!==!1&&(r.setStartBefore(e),r.setEndBefore(e)),I.remove(e)):(n=u(e),n.nodeValue.charAt(0)===j&&(n=n.deleteData(0,1)),I.remove(e,1)),F.setRng(r);else if(e=l(F.getStart()),!e)for(;e=I.get(y);)d(e,!1)}function f(){var e,t,r,i,s,d,f;e=F.getRng(!0),i=e.startOffset,d=e.startContainer,f=d.nodeValue,t=l(F.getStart()),t&&(r=u(t)),f&&i>0&&i<f.length&&/\w/.test(f.charAt(i))&&/\w/.test(f.charAt(i-1))?(s=F.getBookmark(),e.collapse(!0),e=T(e,c(n)),e=W.split(e),p(n,o,e),F.moveToBookmark(s)):(t&&r.nodeValue===j?p(n,o,t):(t=a(!0),r=t.firstChild,e.insertNode(t),i=1,p(n,o,t)),F.setCursorLocation(r,i))}function m(){var e=F.getRng(!0),t,r,s,l,u,d,f=[],p,m;for(t=e.startContainer,r=e.startOffset,u=t,3==t.nodeType&&((r!=t.nodeValue.length||t.nodeValue===j)&&(l=!0),u=u.parentNode);u;){if(g(u,n,o)){d=u;break}u.nextSibling&&(l=!0),f.push(u),u=u.parentNode}if(d)if(l)s=F.getBookmark(),e.collapse(!0),e=T(e,c(n),!0),e=W.split(e),h(n,o,e),F.moveToBookmark(s);else{for(m=a(),u=m,p=f.length-1;p>=0;p--)u.appendChild(I.clone(f[p],!1)),u=u.firstChild;u.appendChild(I.doc.createTextNode(j)),u=u.firstChild;var v=I.getParent(d,i);v&&I.isEmpty(v)?d.parentNode.replaceChild(m,d):I.insertAfter(m,d),F.setCursorLocation(u,1),I.isEmpty(d)&&I.remove(d)}}function v(){var e;e=l(F.getStart()),e&&!I.isEmpty(e)&&nt(e,function(e){1!=e.nodeType||e.id===y||I.isEmpty(e)||I.setAttrib(e,"data-mce-bogus",null)},"childNodes")}var y="_mce_caret",b=r.settings.caret_debug;r._hasCaretEvents||(Z=function(){var e=[],t;if(s(l(F.getStart()),e))for(t=e.length;t--;)I.setAttrib(e[t],"data-mce-bogus","1")},Q=function(e){var t=e.keyCode;d(),(8==t||37==t||39==t)&&d(l(F.getStart())),v()},r.on("SetContent",function(e){e.selection&&v()}),r._hasCaretEvents=!0),"apply"==t?f():m()}function P(t){var n=t.startContainer,r=t.startOffset,i,o,a,s,l;if(3==n.nodeType&&r>=n.nodeValue.length&&(r=q(n),n=n.parentNode,i=!0),1==n.nodeType)for(s=n.childNodes,n=s[Math.min(r,s.length-1)],o=new e(n,I.getParent(n,I.isBlock)),(r>s.length-1||i)&&o.next(),a=o.current();a;a=o.next())if(3==a.nodeType&&!k(a))return l=I.create("a",null,j),a.parentNode.insertBefore(l,a),t.setStart(a,0),F.setRng(t),I.remove(l),void 0}var O={},I=r.dom,F=r.selection,W=new t(I),z=r.schema.isValidChild,V=I.isBlock,U=r.settings.forced_root_block,q=I.nodeIndex,j="\ufeff",$=/^(src|href|style)$/,K=!1,G=!0,Y,X,J=I.getContentEditable,Q,Z,et=n.each,tt=n.grep,nt=n.walk,rt=n.extend;rt(this,{get:c,register:u,apply:p,remove:h,toggle:m,match:v,matchAll:y,matchNode:g,canApply:b,formatChanged:C}),s(),l(),r.on("BeforeGetContent",function(){Z&&Z()}),r.on("mouseup keydown",function(e){Q&&Q(e)})}}),r(L,[g,p],function(e,t){var n=t.trim,r;return r=new RegExp(["<span[^>]+data-mce-bogus[^>]+>[\u200b\ufeff]+<\\/span>","<div[^>]+data-mce-bogus[^>]+><\\/div>",'\\s?data-mce-selected="[^"]+"'].join("|"),"gi"),function(t){function i(){return n(t.getContent({format:"raw",no_events:1}).replace(r,""))}function o(){a.typing=!1,a.add()}var a,s=0,l=[],c,u,d;return t.on("init",function(){a.add()}),t.on("BeforeExecCommand",function(e){var t=e.command;"Undo"!=t&&"Redo"!=t&&"mceRepaint"!=t&&a.beforeChange()}),t.on("ExecCommand",function(e){var t=e.command;"Undo"!=t&&"Redo"!=t&&"mceRepaint"!=t&&a.add()}),t.on("ObjectResizeStart",function(){a.beforeChange()}),t.on("SaveContent ObjectResized",o),t.dom.bind(t.dom.getRoot(),"dragend",o),t.dom.bind(t.getBody(),"focusout",function(){!t.removed&&a.typing&&o()}),t.on("KeyUp",function(n){var r=n.keyCode;(r>=33&&36>=r||r>=37&&40>=r||45==r||13==r||n.ctrlKey)&&(o(),t.nodeChanged()),(46==r||8==r||e.mac&&(91==r||93==r))&&t.nodeChanged(),u&&a.typing&&(t.isDirty()||(t.isNotDirty=!l[0]||i()==l[0].content,t.isNotDirty||t.fire("change",{level:l[0],lastLevel:null})),t.fire("TypingUndo"),u=!1,t.nodeChanged())}),t.on("KeyDown",function(e){var t=e.keyCode;return t>=33&&36>=t||t>=37&&40>=t||45==t?(a.typing&&o(),void 0):((16>t||t>20)&&224!=t&&91!=t&&!a.typing&&(a.beforeChange(),a.typing=!0,a.add(),u=!0),void 0)}),t.on("MouseDown",function(){a.typing&&o()}),t.addShortcut("ctrl+z","","Undo"),t.addShortcut("ctrl+y,ctrl+shift+z","","Redo"),t.on("AddUndo Undo Redo ClearUndos MouseUp",function(e){e.isDefaultPrevented()||t.nodeChanged()}),a={data:l,typing:!1,beforeChange:function(){d||(c=t.selection.getBookmark(2,!0))},add:function(e){var n,r=t.settings,o;if(e=e||{},e.content=i(),d||t.fire("BeforeAddUndo",{level:e}).isDefaultPrevented())return null;if(o=l[s],o&&o.content==e.content)return null;if(l[s]&&(l[s].beforeBookmark=c),r.custom_undo_redo_levels&&l.length>r.custom_undo_redo_levels){for(n=0;n<l.length-1;n++)l[n]=l[n+1];l.length--,s=l.length}e.bookmark=t.selection.getBookmark(2,!0),s<l.length-1&&(l.length=s+1),l.push(e),s=l.length-1;var a={level:e,lastLevel:o};return t.fire("AddUndo",a),s>0&&(t.fire("change",a),t.isNotDirty=!1),e},undo:function(){var e;return a.typing&&(a.add(),a.typing=!1),s>0&&(e=l[--s],t.setContent(e.content,{format:"raw"}),t.selection.moveToBookmark(e.beforeBookmark),t.fire("undo",{level:e})),e},redo:function(){var e;return s<l.length-1&&(e=l[++s],t.setContent(e.content,{format:"raw"}),t.selection.moveToBookmark(e.bookmark),t.fire("redo",{level:e})),e},clear:function(){l=[],s=0,a.typing=!1,t.fire("ClearUndos")},hasUndo:function(){return s>0||a.typing&&l[0]&&i()!=l[0].content},hasRedo:function(){return s<l.length-1&&!this.typing},transact:function(e){a.beforeChange(),d=!0,e(),d=!1,a.add()}}}}),r(M,[f,g],function(e,t){var n=t.ie&&t.ie<11;return function(t){function r(r){function u(e){return e&&i.isBlock(e)&&!/^(TD|TH|CAPTION|FORM)$/.test(e.nodeName)&&!/^(fixed|absolute)/i.test(e.style.position)&&"true"!==i.getContentEditable(e)}function d(e){var t;i.isBlock(e)&&(t=o.getRng(),e.appendChild(i.create("span",null,"\xa0")),o.select(e),e.lastChild.outerHTML="",o.setRng(t))}function f(e){for(var t=e,n=[],r;t=t.firstChild;){if(i.isBlock(t))return;1!=t.nodeType||c[t.nodeName.toLowerCase()]||n.push(t)}for(r=n.length;r--;)t=n[r],!t.hasChildNodes()||t.firstChild==t.lastChild&&""===t.firstChild.nodeValue?i.remove(t):"A"==t.nodeName&&" "===(t.innerText||t.textContent)&&i.remove(t)}function p(t){var n,r,a,s=t,l;if(a=i.createRng(),t.hasChildNodes()){for(n=new e(t,t);r=n.current();){if(3==r.nodeType){a.setStart(r,0),a.setEnd(r,0);break}if(c[r.nodeName.toLowerCase()]){a.setStartBefore(r),a.setEndBefore(r);break}s=r,r=n.next()}r||(a.setStart(s,0),a.setEnd(s,0))}else"BR"==t.nodeName?t.nextSibling&&i.isBlock(t.nextSibling)?((!R||9>R)&&(l=i.create("br"),t.parentNode.insertBefore(l,t)),a.setStartBefore(t),a.setEndBefore(t)):(a.setStartAfter(t),a.setEndAfter(t)):(a.setStart(t,0),a.setEnd(t,0));o.setRng(a),i.remove(l),o.scrollIntoView(t)}function h(e){var t=k,r,o,s;if(r=e||"TABLE"==M?i.create(e||P):T.cloneNode(!1),s=r,a.keep_styles!==!1)do if(/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(t.nodeName)){if("_mce_caret"==t.id)continue;o=t.cloneNode(!1),i.setAttrib(o,"id",""),r.hasChildNodes()?(o.appendChild(r.firstChild),r.appendChild(o)):(s=o,r.appendChild(o))}while(t=t.parentNode);return n||(s.innerHTML='<br data-mce-bogus="1">'),r}function m(t){var n,r,i;if(3==k.nodeType&&(t?S>0:S<k.nodeValue.length))return!1;if(k.parentNode==T&&O&&!t)return!0;if(t&&1==k.nodeType&&k==T.firstChild)return!0;if("TABLE"===k.nodeName||k.previousSibling&&"TABLE"==k.previousSibling.nodeName)return O&&!t||!O&&t;for(n=new e(k,T),3==k.nodeType&&(t&&0===S?n.prev():t||S!=k.nodeValue.length||n.next());r=n.current();){if(1===r.nodeType){if(!r.getAttribute("data-mce-bogus")&&(i=r.nodeName.toLowerCase(),c[i]&&"br"!==i))return!1}else if(3===r.nodeType&&!/^[ \t\r\n]*$/.test(r.nodeValue))return!1;t?n.prev():n.next()}return!0}function g(e,n){var r,o,a,s,c,d,f=P||"P";if(o=i.getParent(e,i.isBlock),d=t.getBody().nodeName.toLowerCase(),!o||!u(o)){if(o=o||E,!o.hasChildNodes())return r=i.create(f),o.appendChild(r),_.setStart(r,0),_.setEnd(r,0),r;for(s=e;s.parentNode!=o;)s=s.parentNode;for(;s&&!i.isBlock(s);)a=s,s=s.previousSibling;if(a&&l.isValidChild(d,f.toLowerCase())){for(r=i.create(f),a.parentNode.insertBefore(r,a),s=a;s&&!i.isBlock(s);)c=s.nextSibling,r.appendChild(s),s=c;_.setStart(e,n),_.setEnd(e,n)}}return e}function v(){function e(e){for(var t=L[e?"firstChild":"lastChild"];t&&1!=t.nodeType;)t=t[e?"nextSibling":"previousSibling"];return t===T}function t(){var e=L.parentNode;return"LI"==e.nodeName?e:L}var n=L.parentNode.nodeName;/^(OL|UL|LI)$/.test(n)&&(P="LI"),B=P?h(P):i.create("BR"),e(!0)&&e()?"LI"==n?i.insertAfter(B,t()):i.replace(B,L):e(!0)?"LI"==n?(i.insertAfter(B,t()),B.appendChild(i.doc.createTextNode(" ")),B.appendChild(L)):L.parentNode.insertBefore(B,L):e()?(i.insertAfter(B,t()),d(B)):(L=t(),N=_.cloneRange(),N.setStartAfter(T),N.setEndAfter(L),D=N.extractContents(),i.insertAfter(D,L),i.insertAfter(B,L)),i.remove(T),p(B),s.add()}function y(){for(var t=new e(k,T),n;n=t.next();)if(c[n.nodeName.toLowerCase()]||n.length>0)return!0}function b(){var e,t,r;k&&3==k.nodeType&&S>=k.nodeValue.length&&(n||y()||(e=i.create("br"),_.insertNode(e),_.setStartAfter(e),_.setEndAfter(e),t=!0)),e=i.create("br"),_.insertNode(e),n&&"PRE"==M&&(!R||8>R)&&e.parentNode.insertBefore(i.doc.createTextNode("\r"),e),r=i.create("span",{},"&nbsp;"),e.parentNode.insertBefore(r,e),o.scrollIntoView(r),i.remove(r),t?(_.setStartBefore(e),_.setEndBefore(e)):(_.setStartAfter(e),_.setEndAfter(e)),o.setRng(_),s.add()}function C(e){do 3===e.nodeType&&(e.nodeValue=e.nodeValue.replace(/^[\r\n]+/,"")),e=e.firstChild;while(e)}function x(e){var t=i.getRoot(),n,r;for(n=e;n!==t&&"false"!==i.getContentEditable(n);)"true"===i.getContentEditable(n)&&(r=n),n=n.parentNode;return n!==t?r:t}function w(e){var t;n||(e.normalize(),t=e.lastChild,(!t||/^(left|right)$/gi.test(i.getStyle(t,"float",!0)))&&i.add(e,"br"))}var _=o.getRng(!0),N,E,k,S,T,R,A,B,D,L,M,H,P,O;if(!_.collapsed)return t.execCommand("Delete"),void 0;if(!r.isDefaultPrevented()&&(k=_.startContainer,S=_.startOffset,P=(a.force_p_newlines?"p":"")||a.forced_root_block,P=P?P.toUpperCase():"",R=i.doc.documentMode,A=r.shiftKey,1==k.nodeType&&k.hasChildNodes()&&(O=S>k.childNodes.length-1,k=k.childNodes[Math.min(S,k.childNodes.length-1)]||k,S=O&&3==k.nodeType?k.nodeValue.length:0),E=x(k))){if(s.beforeChange(),!i.isBlock(E)&&E!=i.getRoot())return(!P||A)&&b(),void 0;if((P&&!A||!P&&A)&&(k=g(k,S)),T=i.getParent(k,i.isBlock),L=T?i.getParent(T.parentNode,i.isBlock):null,M=T?T.nodeName.toUpperCase():"",H=L?L.nodeName.toUpperCase():"","LI"!=H||r.ctrlKey||(T=L,M=H),"LI"==M){if(!P&&A)return b(),void 0;if(i.isEmpty(T))return v(),void 0}if("PRE"==M&&a.br_in_pre!==!1){if(!A)return b(),void 0}else if(!P&&!A&&"LI"!=M||P&&A)return b(),void 0;P&&T===t.getBody()||(P=P||"P",m()?(B=/^(H[1-6]|PRE|FIGURE)$/.test(M)&&"HGROUP"!=H?h(P):h(),a.end_container_on_empty_block&&u(L)&&i.isEmpty(T)?B=i.split(L,T):i.insertAfter(B,T),p(B)):m(!0)?(B=T.parentNode.insertBefore(h(),T),d(B)):(N=_.cloneRange(),N.setEndAfter(T),D=N.extractContents(),C(D),B=D.firstChild,i.insertAfter(D,T),f(B),w(T),p(B)),i.setAttrib(B,"id",""),s.add())}}var i=t.dom,o=t.selection,a=t.settings,s=t.undoManager,l=t.schema,c=l.getNonEmptyElements();t.on("keydown",function(e){13==e.keyCode&&r(e)!==!1&&e.preventDefault()})}}),r(H,[],function(){return function(e){function t(){var t=i.getStart(),s=e.getBody(),l,c,u,d,f,p,h,m=-16777215,g,v,y,b,C;if(C=n.forced_root_block,t&&1===t.nodeType&&C){for(;t&&t!=s;){if(a[t.nodeName])return;t=t.parentNode}if(l=i.getRng(),l.setStart){c=l.startContainer,u=l.startOffset,d=l.endContainer,f=l.endOffset;try{v=e.getDoc().activeElement===s}catch(x){}}else l.item&&(t=l.item(0),l=e.getDoc().body.createTextRange(),l.moveToElementText(t)),v=l.parentElement().ownerDocument===e.getDoc(),y=l.duplicate(),y.collapse(!0),u=-1*y.move("character",m),y.collapsed||(y=l.duplicate(),y.collapse(!1),f=-1*y.move("character",m)-u);for(t=s.firstChild,b=s.nodeName.toLowerCase();t;)if((3===t.nodeType||1==t.nodeType&&!a[t.nodeName])&&o.isValidChild(b,C.toLowerCase())){if(3===t.nodeType&&0===t.nodeValue.length){h=t,t=t.nextSibling,r.remove(h);continue}p||(p=r.create(C),t.parentNode.insertBefore(p,t),g=!0),h=t,t=t.nextSibling,p.appendChild(h)}else p=null,t=t.nextSibling;if(g&&v){if(l.setStart)l.setStart(c,u),l.setEnd(d,f),i.setRng(l);else try{l=e.getDoc().body.createTextRange(),l.moveToElementText(s),l.collapse(!0),l.moveStart("character",u),f>0&&l.moveEnd("character",f),l.select()}catch(x){}e.nodeChanged()}}}var n=e.settings,r=e.dom,i=e.selection,o=e.schema,a=o.getBlockElements();n.forced_root_block&&e.on("NodeChange",t)}}),r(P,[E,g,p],function(e,n,r){var i=r.each,o=r.extend,a=r.map,s=r.inArray,l=r.explode,c=n.gecko,u=n.ie,d=!0,f=!1;return function(n){function r(e,t,n){var r;return e=e.toLowerCase(),(r=_.exec[e])?(r(e,t,n),d):f}function p(e){var t;return e=e.toLowerCase(),(t=_.state[e])?t(e):-1}function h(e){var t;return e=e.toLowerCase(),(t=_.value[e])?t(e):f}function m(e,t){t=t||"exec",i(e,function(e,n){i(n.toLowerCase().split(","),function(n){_[t][n]=e})})}function g(e,r,i){return r===t&&(r=f),i===t&&(i=null),n.getDoc().execCommand(e,r,i)}function v(e){return E.match(e)}function y(e,r){E.toggle(e,r?{value:r}:t),n.nodeChanged()}function b(e){k=w.getBookmark(e)}function C(){w.moveToBookmark(k)}var x=n.dom,w=n.selection,_={state:{},exec:{},value:{}},N=n.settings,E=n.formatter,k;o(this,{execCommand:r,queryCommandState:p,queryCommandValue:h,addCommands:m}),m({"mceResetDesignMode,mceBeginUndoLevel":function(){},"mceEndUndoLevel,mceAddUndoLevel":function(){n.undoManager.add()},"Cut,Copy,Paste":function(e){var t=n.getDoc(),r;try{g(e)}catch(i){r=d}(r||!t.queryCommandSupported(e))&&n.windowManager.alert("Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.")},unlink:function(e){w.isCollapsed()&&w.select(w.getNode()),g(e),w.collapse(f)},"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(e){var t=e.substring(7);"full"==t&&(t="justify"),i("left,center,right,justify".split(","),function(e){t!=e&&E.remove("align"+e)}),y("align"+t),r("mceRepaint")},"InsertUnorderedList,InsertOrderedList":function(e){var t,n;g(e),t=x.getParent(w.getNode(),"ol,ul"),t&&(n=t.parentNode,/^(H[1-6]|P|ADDRESS|PRE)$/.test(n.nodeName)&&(b(),x.split(n,t),C()))},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(e){y(e)},"ForeColor,HiliteColor,FontName":function(e,t,n){y(e,n)},FontSize:function(e,t,n){var r,i;n>=1&&7>=n&&(i=l(N.font_size_style_values),r=l(N.font_size_classes),n=r?r[n-1]||n:i[n-1]||n),y(e,n)},RemoveFormat:function(e){E.remove(e)},mceBlockQuote:function(){y("blockquote")},FormatBlock:function(e,t,n){return y(n||"p")},mceCleanup:function(){var e=w.getBookmark();n.setContent(n.getContent({cleanup:d}),{cleanup:d}),w.moveToBookmark(e)},mceRemoveNode:function(e,t,r){var i=r||w.getNode();i!=n.getBody()&&(b(),n.dom.remove(i,d),C())},mceSelectNodeDepth:function(e,t,r){var i=0;x.getParent(w.getNode(),function(e){return 1==e.nodeType&&i++==r?(w.select(e),f):void 0},n.getBody())},mceSelectNode:function(e,t,n){w.select(n)},mceInsertContent:function(t,r,i){function o(e){function t(e){return r[e]&&3==r[e].nodeType}var n,r,i;return n=w.getRng(!0),r=n.startContainer,i=n.startOffset,3==r.nodeType&&(i>0?e=e.replace(/^&nbsp;/," "):t("previousSibling")||(e=e.replace(/^ /,"&nbsp;")),i<r.length?e=e.replace(/&nbsp;(<br>|)$/," "):t("nextSibling")||(e=e.replace(/(&nbsp;| )(<br>|)$/,"&nbsp;"))),e}var a,s,l,c,d,f,p,h,m,g,v,y,b,C;if(/^ | $/.test(i)&&(i=o(i)),a=n.parser,s=new e({},n.schema),b='<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;</span>',f={content:i,format:"html",selection:!0},n.fire("BeforeSetContent",f),i=f.content,-1==i.indexOf("{$caret}")&&(i+="{$caret}"),i=i.replace(/\{\$caret\}/,b),w.isCollapsed()||n.getDoc().execCommand("Delete",!1,null),l=w.getNode(),f={context:l.nodeName.toLowerCase()},d=a.parse(i,f),v=d.lastChild,"mce_marker"==v.attr("id"))for(p=v,v=v.prev;v;v=v.walk(!0))if(3==v.type||!x.isBlock(v.name)){v.parent.insert(p,v,"br"===v.name);break}if(f.invalid){for(w.setContent(b),l=w.getNode(),c=n.getBody(),9==l.nodeType?l=v=c:v=l;v!==c;)l=v,v=v.parentNode;i=l==c?c.innerHTML:x.getOuterHTML(l),i=s.serialize(a.parse(i.replace(/<span (id="mce_marker"|id=mce_marker).+?<\/span>/i,function(){return s.serialize(d)}))),l==c?x.setHTML(c,i):x.setOuterHTML(l,i)}else i=s.serialize(d),v=l.firstChild,y=l.lastChild,!v||v===y&&"BR"===v.nodeName?x.setHTML(l,i):w.setContent(i);p=x.get("mce_marker"),h=x.getRect(p),m=x.getViewPort(n.getWin()),(h.y+h.h>m.y+m.h||h.y<m.y||h.x>m.x+m.w||h.x<m.x)&&(C=u?n.getDoc().documentElement:n.getBody(),C.scrollLeft=h.x,C.scrollTop=h.y-m.h+25),g=x.createRng(),v=p.previousSibling,v&&3==v.nodeType?(g.setStart(v,v.nodeValue.length),u||(y=p.nextSibling,y&&3==y.nodeType&&(v.appendData(y.data),y.parentNode.removeChild(y)))):(g.setStartBefore(p),g.setEndBefore(p)),x.remove(p),w.setRng(g),n.fire("SetContent",f),n.addVisual()},mceInsertRawHTML:function(e,t,r){w.setContent("tiny_mce_marker"),n.setContent(n.getContent().replace(/tiny_mce_marker/g,function(){return r}))},mceToggleFormat:function(e,t,n){y(n)},mceSetContent:function(e,t,r){n.setContent(r)},"Indent,Outdent":function(e){var t,n,r;t=N.indentation,n=/[a-z%]+$/i.exec(t),t=parseInt(t,10),p("InsertUnorderedList")||p("InsertOrderedList")?g(e):(N.forced_root_block||x.getParent(w.getNode(),x.isBlock)||E.apply("div"),i(w.getSelectedBlocks(),function(i){var o;"LI"!=i.nodeName&&(o="rtl"==x.getStyle(i,"direction",!0)?"paddingRight":"paddingLeft","outdent"==e?(r=Math.max(0,parseInt(i.style[o]||0,10)-t),x.setStyle(i,o,r?r+n:"")):(r=parseInt(i.style[o]||0,10)+t+n,x.setStyle(i,o,r)))}))},mceRepaint:function(){if(c)try{b(d),w.getSel()&&w.getSel().selectAllChildren(n.getBody()),w.collapse(d),C()}catch(e){}},InsertHorizontalRule:function(){n.execCommand("mceInsertContent",!1,"<hr />")},mceToggleVisualAid:function(){n.hasVisual=!n.hasVisual,n.addVisual()},mceReplaceContent:function(e,t,r){n.execCommand("mceInsertContent",!1,r.replace(/\{\$selection\}/g,w.getContent({format:"text"})))},mceInsertLink:function(e,t,n){var r;"string"==typeof n&&(n={href:n}),r=x.getParent(w.getNode(),"a"),n.href=n.href.replace(" ","%20"),r&&n.href||E.remove("link"),n.href&&E.apply("link",n,r)},selectAll:function(){var e=x.getRoot(),t=x.createRng();w.getRng().setStart?(t.setStart(e,0),t.setEnd(e,e.childNodes.length),w.setRng(t)):g("SelectAll")},mceNewDocument:function(){n.setContent("")}}),m({"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(e){var t="align"+e.substring(7),n=w.isCollapsed()?[x.getParent(w.getNode(),x.isBlock)]:w.getSelectedBlocks(),r=a(n,function(e){return!!E.matchNode(e,t)});return-1!==s(r,d)},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(e){return v(e)},mceBlockQuote:function(){return v("blockquote")},Outdent:function(){var e;if(N.inline_styles){if((e=x.getParent(w.getStart(),x.isBlock))&&parseInt(e.style.paddingLeft,10)>0)return d;if((e=x.getParent(w.getEnd(),x.isBlock))&&parseInt(e.style.paddingLeft,10)>0)return d}return p("InsertUnorderedList")||p("InsertOrderedList")||!N.inline_styles&&!!x.getParent(w.getNode(),"BLOCKQUOTE")},"InsertUnorderedList,InsertOrderedList":function(e){var t=x.getParent(w.getNode(),"ul,ol");return t&&("insertunorderedlist"===e&&"UL"===t.tagName||"insertorderedlist"===e&&"OL"===t.tagName)}},"state"),m({"FontSize,FontName":function(e){var t=0,n;return(n=x.getParent(w.getNode(),"span"))&&(t="fontsize"==e?n.style.fontSize:n.style.fontFamily.replace(/, /g,",").replace(/[\'\"]/g,"").toLowerCase()),t}},"value"),m({Undo:function(){n.undoManager.undo()},Redo:function(){n.undoManager.redo()}})}}),r(O,[p],function(e){function t(e,i){var o=this,a,s;return e=r(e),i=o.settings=i||{},/^([\w\-]+):([^\/]{2})/i.test(e)||/^\s*#/.test(e)?(o.source=e,void 0):(0===e.indexOf("/")&&0!==e.indexOf("//")&&(e=(i.base_uri?i.base_uri.protocol||"http":"http")+"://mce_host"+e),/^[\w\-]*:?\/\//.test(e)||(s=i.base_uri?i.base_uri.path:new t(location.href).directory,e=(i.base_uri&&i.base_uri.protocol||"http")+"://mce_host"+o.toAbsPath(s,e)),e=e.replace(/@@/g,"(mce_at)"),e=/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(e),n(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],function(t,n){var r=e[n];r&&(r=r.replace(/\(mce_at\)/g,"@@")),o[t]=r}),a=i.base_uri,a&&(o.protocol||(o.protocol=a.protocol),o.userInfo||(o.userInfo=a.userInfo),o.port||"mce_host"!==o.host||(o.port=a.port),o.host&&"mce_host"!==o.host||(o.host=a.host),o.source=""),void 0)}var n=e.each,r=e.trim;return t.prototype={setPath:function(e){var t=this;e=/^(.*?)\/?(\w+)?$/.exec(e),t.path=e[0],t.directory=e[1],t.file=e[2],t.source="",t.getURI()},toRelative:function(e){var n=this,r;if("./"===e)return e;if(e=new t(e,{base_uri:n}),"mce_host"!=e.host&&n.host!=e.host&&e.host||n.port!=e.port||n.protocol!=e.protocol)return e.getURI();var i=n.getURI(),o=e.getURI();return i==o||"/"==i.charAt(i.length-1)&&i.substr(0,i.length-1)==o?i:(r=n.toRelPath(n.path,e.path),e.query&&(r+="?"+e.query),e.anchor&&(r+="#"+e.anchor),r)},toAbsolute:function(e,n){return e=new t(e,{base_uri:this}),e.getURI(this.host==e.host&&this.protocol==e.protocol?n:0)},toRelPath:function(e,t){var n,r=0,i="",o,a;if(e=e.substring(0,e.lastIndexOf("/")),e=e.split("/"),n=t.split("/"),e.length>=n.length)for(o=0,a=e.length;a>o;o++)if(o>=n.length||e[o]!=n[o]){r=o+1;break}if(e.length<n.length)for(o=0,a=n.length;a>o;o++)if(o>=e.length||e[o]!=n[o]){r=o+1;break}if(1===r)return t;for(o=0,a=e.length-(r-1);a>o;o++)i+="../";for(o=r-1,a=n.length;a>o;o++)i+=o!=r-1?"/"+n[o]:n[o];return i},toAbsPath:function(e,t){var r,i=0,o=[],a,s;for(a=/\/$/.test(t)?"/":"",e=e.split("/"),t=t.split("/"),n(e,function(e){e&&o.push(e)}),e=o,r=t.length-1,o=[];r>=0;r--)0!==t[r].length&&"."!==t[r]&&(".."!==t[r]?i>0?i--:o.push(t[r]):i++);return r=e.length-i,s=0>=r?o.reverse().join("/"):e.slice(0,r).join("/")+"/"+o.reverse().join("/"),0!==s.indexOf("/")&&(s="/"+s),a&&s.lastIndexOf("/")!==s.length-1&&(s+=a),s},getURI:function(e){var t,n=this;return(!n.source||e)&&(t="",e||(n.protocol&&(t+=n.protocol+"://"),n.userInfo&&(t+=n.userInfo+"@"),n.host&&(t+=n.host),n.port&&(t+=":"+n.port)),n.path&&(t+=n.path),n.query&&(t+="?"+n.query),n.anchor&&(t+="#"+n.anchor),n.source=t),n.source}},t}),r(I,[p],function(e){function t(){}var n=e.each,r=e.extend,i,o;return t.extend=i=function(e){function t(){var e,t,n,r;if(!o&&(r=this,r.init&&r.init.apply(r,arguments),t=r.Mixins))for(e=t.length;e--;)n=t[e],n.init&&n.init.apply(r,arguments)}function a(){return this}function s(e,t){return function(){var n=this,r=n._super,i;return n._super=c[e],i=t.apply(n,arguments),n._super=r,i}}var l=this,c=l.prototype,u,d,f;o=!0,u=new l,o=!1,e.Mixins&&(n(e.Mixins,function(t){t=t;for(var n in t)"init"!==n&&(e[n]=t[n])}),c.Mixins&&(e.Mixins=c.Mixins.concat(e.Mixins))),e.Methods&&n(e.Methods.split(","),function(t){e[t]=a}),e.Properties&&n(e.Properties.split(","),function(t){var n="_"+t;e[t]=function(e){var t=this,r;return e!==r?(t[n]=e,t):t[n]}}),e.Statics&&n(e.Statics,function(e,n){t[n]=e}),e.Defaults&&c.Defaults&&(e.Defaults=r({},c.Defaults,e.Defaults));for(d in e)f=e[d],u[d]="function"==typeof f&&c[d]?s(d,f):f;return t.prototype=u,t.constructor=t,t.extend=i,t},t}),r(F,[I,p],function(e,t){function n(e){for(var t=[],n=e.length,r;n--;)r=e[n],r.__checked||(t.push(r),r.__checked=1);for(n=t.length;n--;)delete t[n].__checked;return t}var r=/^([\w\\*]+)?(?:#([\w\\]+))?(?:\.([\w\\\.]+))?(?:\[\@?([\w\\]+)([\^\$\*!~]?=)([\w\\]+)\])?(?:\:(.+))?/i,i=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,o=/^\s*|\s*$/g,a,s=e.extend({init:function(e){function t(e){return e?(e=e.toLowerCase(),function(t){return"*"===e||t.type===e}):void 0}function n(e){return e?function(t){return t._name===e}:void 0}function a(e){return e?(e=e.split("."),function(t){for(var n=e.length;n--;)if(!t.hasClass(e[n]))return!1;return!0}):void 0}function s(e,t,n){return e?function(r){var i=r[e]?r[e]():"";return t?"="===t?i===n:"*="===t?i.indexOf(n)>=0:"~="===t?(" "+i+" ").indexOf(" "+n+" ")>=0:"!="===t?i!=n:"^="===t?0===i.indexOf(n):"$="===t?i.substr(i.length-n.length)===n:!1:!!n}:void 0}function l(e){var t;return e?(e=/(?:not\((.+)\))|(.+)/i.exec(e),e[1]?(t=u(e[1],[]),function(e){return!d(e,t)}):(e=e[2],function(t,n,r){return"first"===e?0===n:"last"===e?n===r-1:"even"===e?0===n%2:"odd"===e?1===n%2:t[e]?t[e]():!1})):void 0}function c(e,i,c){function u(e){e&&i.push(e)}var d;return d=r.exec(e.replace(o,"")),u(t(d[1])),u(n(d[2])),u(a(d[3])),u(s(d[4],d[5],d[6])),u(l(d[7])),i.psuedo=!!d[7],i.direct=c,i}function u(e,t){var n=[],r,o,a;do if(i.exec(""),o=i.exec(e),o&&(e=o[3],n.push(o[1]),o[2])){r=o[3];break}while(o);for(r&&u(r,t),e=[],a=0;a<n.length;a++)">"!=n[a]&&e.push(c(n[a],[],">"===n[a-1]));return t.push(e),t}var d=this.match;this._selectors=u(e,[])},match:function(e,n){var r,i,o,a,s,l,c,u,d,f,p,h,m;for(n=n||this._selectors,r=0,i=n.length;i>r;r++){for(s=n[r],a=s.length,m=e,h=0,o=a-1;o>=0;o--)for(u=s[o];m;){for(u.psuedo&&(p=m.parent().items(),d=t.inArray(m,p),f=p.length),l=0,c=u.length;c>l;l++)if(!u[l](m,d,f)){l=c+1;break}if(l===c){h++;break}if(o===a-1)break;m=m.parent()}if(h===a)return!0}return!1},find:function(e){function t(e,n,i){var o,a,s,l,c,u=n[i];for(o=0,a=e.length;a>o;o++){for(c=e[o],s=0,l=u.length;l>s;s++)if(!u[s](c,o,a)){s=l+1;break}if(s===l)i==n.length-1?r.push(c):c.items&&t(c.items(),n,i+1);else if(u.direct)return;c.items&&t(c.items(),n,i)}}var r=[],i,o,l=this._selectors;if(e.items){for(i=0,o=l.length;o>i;i++)t(e.items(),l[i],0);o>1&&(r=n(r))}return a||(a=s.Collection),new a(r)}});return s}),r(W,[p,F,I],function(e,t,n){var r,i,o=Array.prototype.push,a=Array.prototype.slice;return i={length:0,init:function(e){e&&this.add(e)},add:function(t){var n=this;return e.isArray(t)?o.apply(n,t):t instanceof r?n.add(t.toArray()):o.call(n,t),n},set:function(e){var t=this,n=t.length,r;for(t.length=0,t.add(e),r=t.length;n>r;r++)delete t[r];return t},filter:function(e){var n=this,i,o,a=[],s,l;for("string"==typeof e?(e=new t(e),l=function(t){return e.match(t)}):l=e,i=0,o=n.length;o>i;i++)s=n[i],l(s)&&a.push(s);return new r(a)},slice:function(){return new r(a.apply(this,arguments))},eq:function(e){return-1===e?this.slice(e):this.slice(e,+e+1)},each:function(t){return e.each(this,t),this},toArray:function(){return e.toArray(this)},indexOf:function(e){for(var t=this,n=t.length;n--&&t[n]!==e;);return n},reverse:function(){return new r(e.toArray(this).reverse())},hasClass:function(e){return this[0]?this[0].hasClass(e):!1},prop:function(e,t){var n=this,r,i;return t!==r?(n.each(function(n){n[e]&&n[e](t)}),n):(i=n[0],i&&i[e]?i[e]():void 0)},exec:function(t){var n=this,r=e.toArray(arguments).slice(1);return n.each(function(e){e[t]&&e[t].apply(e,r)}),n},remove:function(){for(var e=this.length;e--;)this[e].remove();return this}},e.each("fire on off show hide addClass removeClass append prepend before after reflow".split(" "),function(t){i[t]=function(){var n=e.toArray(arguments);return this.each(function(e){t in e&&e[t].apply(e,n)}),this}}),e.each("text name disabled active selected checked visible parent value data".split(" "),function(e){i[e]=function(t){return this.prop(e,t)
+}}),r=n.extend(i),t.Collection=r,r}),r(z,[p,v],function(e,t){return{id:function(){return t.DOM.uniqueId()},createFragment:function(e){return t.DOM.createFragment(e)},getWindowSize:function(){return t.DOM.getViewPort()},getSize:function(e){return t.DOM.getSize(e)},getPos:function(e,n){return t.DOM.getPos(e,n)},getViewPort:function(e){return t.DOM.getViewPort(e)},get:function(e){return document.getElementById(e)},addClass:function(e,n){return t.DOM.addClass(e,n)},removeClass:function(e,n){return t.DOM.removeClass(e,n)},hasClass:function(e,n){return t.DOM.hasClass(e,n)},toggleClass:function(e,n,r){return t.DOM.toggleClass(e,n,r)},css:function(e,n,r){return t.DOM.setStyle(e,n,r)},on:function(e,n,r,i){return t.DOM.bind(e,n,r,i)},off:function(e,n,r){return t.DOM.unbind(e,n,r)},fire:function(e,n,r){return t.DOM.fire(e,n,r)},innerHtml:function(e,n){t.DOM.setHTML(e,n)}}}),r(V,[I,p,W,z],function(e,t,n,r){var i=t.makeMap("focusin focusout scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave wheel keydown keypress keyup contextmenu"," "),o={},a="onmousewheel"in document,s=!1,l=e.extend({Statics:{controlIdLookup:{}},classPrefix:"mce-",init:function(e){var n=this,i,o;if(n.settings=e=t.extend({},n.Defaults,e),n._id=r.id(),n._text=n._name="",n._width=n._height=0,n._aria={role:e.role},i=e.classes)for(i=i.split(" "),i.map={},o=i.length;o--;)i.map[i[o]]=!0;n._classes=i||[],n.visible(!0),t.each("title text width height name classes visible disabled active value".split(" "),function(t){var r=e[t],i;r!==i?n[t](r):n["_"+t]===i&&(n["_"+t]=!1)}),n.on("click",function(){return n.disabled()?!1:void 0}),e.classes&&t.each(e.classes.split(" "),function(e){n.addClass(e)}),n.settings=e,n._borderBox=n.parseBox(e.border),n._paddingBox=n.parseBox(e.padding),n._marginBox=n.parseBox(e.margin),e.hidden&&n.hide()},Properties:"parent,title,text,width,height,disabled,active,name,value",Methods:"renderHtml",getContainerElm:function(){return document.body},getParentCtrl:function(e){for(var t;e&&!(t=l.controlIdLookup[e.id]);)e=e.parentNode;return t},parseBox:function(e){var t,n=10;if(e)return"number"==typeof e?(e=e||0,{top:e,left:e,bottom:e,right:e}):(e=e.split(" "),t=e.length,1===t?e[1]=e[2]=e[3]=e[0]:2===t?(e[2]=e[0],e[3]=e[1]):3===t&&(e[3]=e[1]),{top:parseInt(e[0],n)||0,right:parseInt(e[1],n)||0,bottom:parseInt(e[2],n)||0,left:parseInt(e[3],n)||0})},borderBox:function(){return this._borderBox},paddingBox:function(){return this._paddingBox},marginBox:function(){return this._marginBox},measureBox:function(e,t){function n(t){var n=document.defaultView;return n?(t=t.replace(/[A-Z]/g,function(e){return"-"+e}),n.getComputedStyle(e,null).getPropertyValue(t)):e.currentStyle[t]}function r(e){var t=parseInt(n(e),10);return isNaN(t)?0:t}return{top:r(t+"TopWidth"),right:r(t+"RightWidth"),bottom:r(t+"BottomWidth"),left:r(t+"LeftWidth")}},initLayoutRect:function(){var e=this,t=e.settings,n,r,i=e.getEl(),o,a,s,l,c,u,d;n=e._borderBox=e._borderBox||e.measureBox(i,"border"),e._paddingBox=e._paddingBox||e.measureBox(i,"padding"),e._marginBox=e._marginBox||e.measureBox(i,"margin"),u=t.minWidth,d=t.minHeight,s=u||i.offsetWidth,l=d||i.offsetHeight,o=t.width,a=t.height,c=t.autoResize,c="undefined"!=typeof c?c:!o&&!a,o=o||s,a=a||l;var f=n.left+n.right,p=n.top+n.bottom,h=t.maxWidth||65535,m=t.maxHeight||65535;return e._layoutRect=r={x:t.x||0,y:t.y||0,w:o,h:a,deltaW:f,deltaH:p,contentW:o-f,contentH:a-p,innerW:o-f,innerH:a-p,startMinWidth:u||0,startMinHeight:d||0,minW:Math.min(s,h),minH:Math.min(l,m),maxW:h,maxH:m,autoResize:c,scrollW:0},e._lastLayoutRect={},r},layoutRect:function(e){var t=this,n=t._layoutRect,r,i,o,a,s,c;return n||(n=t.initLayoutRect()),e?(o=n.deltaW,a=n.deltaH,e.x!==s&&(n.x=e.x),e.y!==s&&(n.y=e.y),e.minW!==s&&(n.minW=e.minW),e.minH!==s&&(n.minH=e.minH),i=e.w,i!==s&&(i=i<n.minW?n.minW:i,i=i>n.maxW?n.maxW:i,n.w=i,n.innerW=i-o),i=e.h,i!==s&&(i=i<n.minH?n.minH:i,i=i>n.maxH?n.maxH:i,n.h=i,n.innerH=i-a),i=e.innerW,i!==s&&(i=i<n.minW-o?n.minW-o:i,i=i>n.maxW-o?n.maxW-o:i,n.innerW=i,n.w=i+o),i=e.innerH,i!==s&&(i=i<n.minH-a?n.minH-a:i,i=i>n.maxH-a?n.maxH-a:i,n.innerH=i,n.h=i+a),e.contentW!==s&&(n.contentW=e.contentW),e.contentH!==s&&(n.contentH=e.contentH),r=t._lastLayoutRect,(r.x!==n.x||r.y!==n.y||r.w!==n.w||r.h!==n.h)&&(c=l.repaintControls,c&&c.map&&!c.map[t._id]&&(c.push(t),c.map[t._id]=!0),r.x=n.x,r.y=n.y,r.w=n.w,r.h=n.h),t):n},repaint:function(){var e=this,t,n,r,i,o=0,a=0,s;t=e.getEl().style,r=e._layoutRect,s=e._lastRepaintRect||{},i=e._borderBox,o=i.left+i.right,a=i.top+i.bottom,r.x!==s.x&&(t.left=r.x+"px",s.x=r.x),r.y!==s.y&&(t.top=r.y+"px",s.y=r.y),r.w!==s.w&&(t.width=r.w-o+"px",s.w=r.w),r.h!==s.h&&(t.height=r.h-a+"px",s.h=r.h),e._hasBody&&r.innerW!==s.innerW&&(n=e.getEl("body").style,n.width=r.innerW+"px",s.innerW=r.innerW),e._hasBody&&r.innerH!==s.innerH&&(n=n||e.getEl("body").style,n.height=r.innerH+"px",s.innerH=r.innerH),e._lastRepaintRect=s,e.fire("repaint",{},!1)},on:function(e,t){function n(e){var t,n;return function(i){return t||r.parents().each(function(r){var i=r.settings.callbacks;return i&&(t=i[e])?(n=r,!1):void 0}),t.call(n,i)}}var r=this,o,a,s,l;if(t)for("string"==typeof t&&(t=n(t)),s=e.toLowerCase().split(" "),l=s.length;l--;)e=s[l],o=r._bindings,o||(o=r._bindings={}),a=o[e],a||(a=o[e]=[]),a.push(t),i[e]&&(r._nativeEvents?r._nativeEvents[e]=!0:r._nativeEvents={name:!0},r._rendered&&r.bindPendingEvents());return r},off:function(e,t){var n=this,r,i=n._bindings,o,a,s,l;if(i)if(e)for(s=e.toLowerCase().split(" "),r=s.length;r--;){if(e=s[r],o=i[e],!e){for(a in i)i[a].length=0;return n}if(o)if(t)for(l=o.length;l--;)o[l]===t&&o.splice(l,1);else o.length=0}else n._bindings=[];return n},fire:function(e,t,n){function r(){return!1}function i(){return!0}var o=this,a,s,l,c;if(e=e.toLowerCase(),t=t||{},t.type||(t.type=e),t.control||(t.control=o),t.preventDefault||(t.preventDefault=function(){t.isDefaultPrevented=i},t.stopPropagation=function(){t.isPropagationStopped=i},t.stopImmediatePropagation=function(){t.isImmediatePropagationStopped=i},t.isDefaultPrevented=r,t.isPropagationStopped=r,t.isImmediatePropagationStopped=r),o._bindings&&(l=o._bindings[e]))for(a=0,s=l.length;s>a&&(t.isImmediatePropagationStopped()||l[a].call(o,t)!==!1);a++);if(n!==!1)for(c=o.parent();c&&!t.isPropagationStopped();)c.fire(e,t,!1),c=c.parent();return t},parents:function(e){var t=this,r=new n;for(t=t.parent();t;t=t.parent())r.add(t);return e&&(r=r.filter(e)),r},next:function(){var e=this.parent().items();return e[e.indexOf(this)+1]},prev:function(){var e=this.parent().items();return e[e.indexOf(this)-1]},findCommonAncestor:function(e,t){for(var n;e;){for(n=t;n&&e!=n;)n=n.parent();if(e==n)break;e=e.parent()}return e},hasClass:function(e,t){var n=this._classes[t||"control"];return e=this.classPrefix+e,n&&!!n.map[e]},addClass:function(e,t){var n=this,r,i;return e=this.classPrefix+e,r=n._classes[t||"control"],r||(r=[],r.map={},n._classes[t||"control"]=r),r.map[e]||(r.map[e]=e,r.push(e),n._rendered&&(i=n.getEl(t),i&&(i.className=r.join(" ")))),n},removeClass:function(e,t){var n=this,r,i,o;if(e=this.classPrefix+e,r=n._classes[t||"control"],r&&r.map[e])for(delete r.map[e],i=r.length;i--;)r[i]===e&&r.splice(i,1);return n._rendered&&(o=n.getEl(t),o&&(o.className=r.join(" "))),n},toggleClass:function(e,t,n){var r=this;return t?r.addClass(e,n):r.removeClass(e,n),r},classes:function(e){var t=this._classes[e||"control"];return t?t.join(" "):""},innerHtml:function(e){return r.innerHtml(this.getEl(),e),this},getEl:function(e,t){var n,i=e?this._id+"-"+e:this._id;return n=o[i]=(t===!0?null:o[i])||r.get(i)},visible:function(e){var t=this,n;return"undefined"!=typeof e?(t._visible!==e&&(t._rendered&&(t.getEl().style.display=e?"":"none"),t._visible=e,n=t.parent(),n&&(n._lastRect=null),t.fire(e?"show":"hide")),t):t._visible},show:function(){return this.visible(!0)},hide:function(){return this.visible(!1)},focus:function(){try{this.getEl().focus()}catch(e){}return this},blur:function(){return this.getEl().blur(),this},aria:function(e,t){var n=this,r=n.getEl();return"undefined"==typeof t?n._aria[e]:(n._aria[e]=t,n._rendered&&("label"==e&&r.setAttribute("aria-labeledby",n._id),r.setAttribute("role"==e?e:"aria-"+e,t)),n)},encode:function(e,t){return t!==!1&&l.translate&&(e=l.translate(e)),(e||"").replace(/[&<>"]/g,function(e){return"&#"+e.charCodeAt(0)+";"})},before:function(e){var t=this,n=t.parent();return n&&n.insert(e,n.items().indexOf(t),!0),t},after:function(e){var t=this,n=t.parent();return n&&n.insert(e,n.items().indexOf(t)),t},remove:function(){var e=this,t=e.getEl(),n=e.parent(),i;if(e.items)for(var o=e.items().toArray(),a=o.length;a--;)o[a].remove();return n&&n.items&&(i=[],n.items().each(function(t){t!==e&&i.push(t)}),n.items().set(i),n._lastRect=null),e._eventsRoot&&e._eventsRoot==e&&r.off(t),delete l.controlIdLookup[e._id],t.parentNode&&t.parentNode.removeChild(t),e},renderBefore:function(e){var t=this;return e.parentNode.insertBefore(r.createFragment(t.renderHtml()),e),t.postRender(),t},renderTo:function(e){var t=this;return e=e||t.getContainerElm(),e.appendChild(r.createFragment(t.renderHtml())),t.postRender(),t},postRender:function(){var e=this,t=e.settings,n,i,o,a,s;for(a in t)0===a.indexOf("on")&&e.on(a.substr(2),t[a]);if(e._eventsRoot){for(o=e.parent();!s&&o;o=o.parent())s=o._eventsRoot;if(s)for(a in s._nativeEvents)e._nativeEvents[a]=!0}e.bindPendingEvents(),t.style&&(n=e.getEl(),n&&(n.setAttribute("style",t.style),n.style.cssText=t.style)),e._visible||r.css(e.getEl(),"display","none"),e.settings.border&&(i=e.borderBox(),r.css(e.getEl(),{"border-top-width":i.top,"border-right-width":i.right,"border-bottom-width":i.bottom,"border-left-width":i.left})),l.controlIdLookup[e._id]=e;for(var c in e._aria)e.aria(c,e._aria[c]);e.fire("postrender",{},!1)},scrollIntoView:function(e){function t(e,t){var n,r,i=e;for(n=r=0;i&&i!=t&&i.nodeType;)n+=i.offsetLeft||0,r+=i.offsetTop||0,i=i.offsetParent;return{x:n,y:r}}var n=this.getEl(),r=n.parentNode,i,o,a,s,l,c,u=t(n,r);return i=u.x,o=u.y,a=n.offsetWidth,s=n.offsetHeight,l=r.clientWidth,c=r.clientHeight,"end"==e?(i-=l-a,o-=c-s):"center"==e&&(i-=l/2-a/2,o-=c/2-s/2),r.scrollLeft=i,r.scrollTop=o,this},bindPendingEvents:function(){function e(e){var t=o.getParentCtrl(e.target);t&&t.fire(e.type,e)}function t(){var e=d._lastHoverCtrl;e&&(e.fire("mouseleave",{target:e.getEl()}),e.parents().each(function(e){e.fire("mouseleave",{target:e.getEl()})}),d._lastHoverCtrl=null)}function n(e){var t=o.getParentCtrl(e.target),n=d._lastHoverCtrl,r=0,i,a,s;if(t!==n){if(d._lastHoverCtrl=t,a=t.parents().toArray().reverse(),a.push(t),n){for(s=n.parents().toArray().reverse(),s.push(n),r=0;r<s.length&&a[r]===s[r];r++);for(i=s.length-1;i>=r;i--)n=s[i],n.fire("mouseleave",{target:n.getEl()})}for(i=r;i<a.length;i++)t=a[i],t.fire("mouseenter",{target:t.getEl()})}}function i(e){e.preventDefault(),"mousewheel"==e.type?(e.deltaY=-1/40*e.wheelDelta,e.wheelDeltaX&&(e.deltaX=-1/40*e.wheelDeltaX)):(e.deltaX=0,e.deltaY=e.detail),e=o.fire("wheel",e)}var o=this,l,c,u,d,f,p;if(o._rendered=!0,f=o._nativeEvents){for(u=o.parents().toArray(),u.unshift(o),l=0,c=u.length;!d&&c>l;l++)d=u[l]._eventsRoot;for(d||(d=u[u.length-1]||o),o._eventsRoot=d,c=l,l=0;c>l;l++)u[l]._eventsRoot=d;for(p in f){if(!f)return!1;"wheel"!==p||s?("mouseenter"===p||"mouseleave"===p?d._hasMouseEnter||(r.on(d.getEl(),"mouseleave",t),r.on(d.getEl(),"mouseover",n),d._hasMouseEnter=1):d[p]||(r.on(d.getEl(),p,e),d[p]=!0),f[p]=!1):a?r.on(o.getEl(),"mousewheel",i):r.on(o.getEl(),"DOMMouseScroll",i)}}},reflow:function(){return this.repaint(),this}});return l}),r(U,[],function(){var e={},t;return{add:function(t,n){e[t.toLowerCase()]=n},has:function(t){return!!e[t.toLowerCase()]},create:function(n,r){var i,o,a;if(!t){a=tinymce.ui;for(o in a)e[o.toLowerCase()]=a[o];t=!0}if("string"==typeof n?(r=r||{},r.type=n):(r=n,n=r.type),n=n.toLowerCase(),i=e[n],!i)throw new Error("Could not find control by type: "+n);return i=new i(r),i.type=n,i}}}),r(q,[V,W,F,U,p,z],function(e,t,n,r,i,o){var a={};return e.extend({layout:"",innerClass:"container-inner",init:function(e){var n=this;n._super(e),e=n.settings,n._fixed=e.fixed,n._items=new t,n.addClass("container"),n.addClass("container-body","body"),e.containerCls&&n.addClass(e.containerCls),n._layout=r.create((e.layout||n.layout)+"layout"),n.settings.items&&n.add(n.settings.items),n._hasBody=!0},items:function(){return this._items},find:function(e){return e=a[e]=a[e]||new n(e),e.find(this)},add:function(e){var t=this;return t.items().add(t.create(e)).parent(t),t},focus:function(){var e=this;return e.keyNav?e.keyNav.focusFirst():e._super(),e},replace:function(e,t){for(var n,r=this.items(),i=r.length;i--;)if(r[i]===e){r[i]=t;break}i>=0&&(n=t.getEl(),n&&n.parentNode.removeChild(n),n=e.getEl(),n&&n.parentNode.removeChild(n)),t.parent(this)},create:function(t){var n=this,o,a=[];return i.isArray(t)||(t=[t]),i.each(t,function(t){t&&(t instanceof e||("string"==typeof t&&(t={type:t}),o=i.extend({},n.settings.defaults,t),t.type=o.type=o.type||t.type||n.settings.defaultType||(o.defaults?o.defaults.type:null),t=r.create(o)),a.push(t))}),a},renderNew:function(){var e=this;return e.items().each(function(t,n){var r,i;t.parent(e),t._rendered||(r=e.getEl("body"),i=o.createFragment(t.renderHtml()),r.hasChildNodes()&&n<=r.childNodes.length-1?r.insertBefore(i,r.childNodes[n]):r.appendChild(i),t.postRender())}),e._layout.applyClasses(e),e._lastRect=null,e},append:function(e){return this.add(e).renderNew()},prepend:function(e){var t=this;return t.items().set(t.create(e).concat(t.items().toArray())),t.renderNew()},insert:function(e,t,n){var r=this,i,o,a;return e=r.create(e),i=r.items(),!n&&t<i.length-1&&(t+=1),t>=0&&t<i.length&&(o=i.slice(0,t).toArray(),a=i.slice(t).toArray(),i.set(o.concat(e,a))),r.renderNew()},fromJSON:function(e){var t=this;for(var n in e)t.find("#"+n).value(e[n]);return t},toJSON:function(){var e=this,t={};return e.find("*").each(function(e){var n=e.name(),r=e.value();n&&"undefined"!=typeof r&&(t[n]=r)}),t},preRender:function(){},renderHtml:function(){var e=this,t=e._layout;return e.preRender(),t.preRender(e),'<div id="'+e._id+'" class="'+e.classes()+'" role="'+this.settings.role+'">'+'<div id="'+e._id+'-body" class="'+e.classes("body")+'">'+(e.settings.html||"")+t.renderHtml(e)+"</div>"+"</div>"},postRender:function(){var e=this,t;return e.items().exec("postRender"),e._super(),e._layout.postRender(e),e._rendered=!0,e.settings.style&&o.css(e.getEl(),e.settings.style),e.settings.border&&(t=e.borderBox(),o.css(e.getEl(),{"border-top-width":t.top,"border-right-width":t.right,"border-bottom-width":t.bottom,"border-left-width":t.left})),e},initLayoutRect:function(){var e=this,t=e._super();return e._layout.recalc(e),t},recalc:function(){var e=this,t=e._layoutRect,n=e._lastRect;return n&&n.w==t.w&&n.h==t.h?void 0:(e._layout.recalc(e),t=e.layoutRect(),e._lastRect={x:t.x,y:t.y,w:t.w,h:t.h},!0)},reflow:function(){var t,n;if(this.visible()){for(e.repaintControls=[],e.repaintControls.map={},n=this.recalc(),t=e.repaintControls.length;t--;)e.repaintControls[t].repaint();"flow"!==this.settings.layout&&"stack"!==this.settings.layout&&this.repaint(),e.repaintControls=[]}return this}})}),r(j,[z],function(e){function t(){var e=document,t,n,r,i,o,a,s,l,c=Math.max;return t=e.documentElement,n=e.body,r=c(t.scrollWidth,n.scrollWidth),i=c(t.clientWidth,n.clientWidth),o=c(t.offsetWidth,n.offsetWidth),a=c(t.scrollHeight,n.scrollHeight),s=c(t.clientHeight,n.clientHeight),l=c(t.offsetHeight,n.offsetHeight),{width:o>r?i:r,height:l>a?s:a}}return function(n,r){function i(){return a.getElementById(r.handle||n)}var o,a=document,s,l,c,u,d,f;r=r||{},l=function(n){var l=t(),p,h;n.preventDefault(),s=n.button,p=i(),d=n.screenX,f=n.screenY,h=window.getComputedStyle?window.getComputedStyle(p,null).getPropertyValue("cursor"):p.runtimeStyle.cursor,o=a.createElement("div"),e.css(o,{position:"absolute",top:0,left:0,width:l.width,height:l.height,zIndex:2147483647,opacity:1e-4,background:"red",cursor:h}),a.body.appendChild(o),e.on(a,"mousemove",u),e.on(a,"mouseup",c),r.start(n)},u=function(e){return e.button!==s?c(e):(e.deltaX=e.screenX-d,e.deltaY=e.screenY-f,e.preventDefault(),r.drag(e),void 0)},c=function(t){e.off(a,"mousemove",u),e.off(a,"mouseup",c),o.parentNode.removeChild(o),r.stop&&r.stop(t)},this.destroy=function(){e.off(i())},e.on(i(),"mousedown",l)}}),r($,[z,j],function(e,t){return{init:function(){var e=this;e.on("repaint",e.renderScroll)},renderScroll:function(){function n(){function t(t,a,s,l,c,u){var d,f,p,h,m,g,v,y,b;if(f=i.getEl("scroll"+t)){if(y=a.toLowerCase(),b=s.toLowerCase(),i.getEl("absend")&&e.css(i.getEl("absend"),y,i.layoutRect()[l]-1),!c)return e.css(f,"display","none"),void 0;e.css(f,"display","block"),d=i.getEl("body"),p=i.getEl("scroll"+t+"t"),h=d["client"+s]-2*o,h-=n&&r?f["client"+u]:0,m=d["scroll"+s],g=h/m,v={},v[y]=d["offset"+a]+o,v[b]=h,e.css(f,v),v={},v[y]=d["scroll"+a]*g,v[b]=h*g,e.css(p,v)}}var n,r,a;a=i.getEl("body"),n=a.scrollWidth>a.clientWidth,r=a.scrollHeight>a.clientHeight,t("h","Left","Width","contentW",n,"Height"),t("v","Top","Height","contentH",r,"Width")}function r(){function n(n,r,a,s,l){var c,u=i._id+"-scroll"+n,d=i.classPrefix;i.getEl().appendChild(e.createFragment('<div id="'+u+'" class="'+d+"scrollbar "+d+"scrollbar-"+n+'">'+'<div id="'+u+'t" class="'+d+'scrollbar-thumb"></div>'+"</div>")),i.draghelper=new t(u+"t",{start:function(){c=i.getEl("body")["scroll"+r],e.addClass(e.get(u),d+"active")},drag:function(e){var t,u,d,f,p=i.layoutRect();u=p.contentW>p.innerW,d=p.contentH>p.innerH,f=i.getEl("body")["client"+a]-2*o,f-=u&&d?i.getEl("scroll"+n)["client"+l]:0,t=f/i.getEl("body")["scroll"+a],i.getEl("body")["scroll"+r]=c+e["delta"+s]/t},stop:function(){e.removeClass(e.get(u),d+"active")}})}i.addClass("scroll"),n("v","Top","Height","Y","Width"),n("h","Left","Width","X","Height")}var i=this,o=2;i.settings.autoScroll&&(i._hasScroll||(i._hasScroll=!0,r(),i.on("wheel",function(e){var t=i.getEl("body");t.scrollLeft+=10*(e.deltaX||0),t.scrollTop+=10*e.deltaY,n()}),e.on(i.getEl("body"),"scroll",n)),n())}}}),r(K,[q,$],function(e,t){return e.extend({Defaults:{layout:"fit",containerCls:"panel"},Mixins:[t],renderHtml:function(){var e=this,t=e._layout,n=e.settings.html;return e.preRender(),t.preRender(e),"undefined"==typeof n?n='<div id="'+e._id+'-body" class="'+e.classes("body")+'">'+t.renderHtml(e)+"</div>":("function"==typeof n&&(n=n.call(e)),e._hasBody=!1),'<div id="'+e._id+'" class="'+e.classes()+'" hideFocus="1" tabIndex="-1">'+(e._preBodyHtml||"")+n+"</div>"}})}),r(G,[z],function(e){function t(t,n,r){var i,o,a,s,l,c,u,d,f;return f=e.getViewPort(),o=e.getPos(n),a=o.x,s=o.y,t._fixed&&(a-=f.x,s-=f.y),i=t.getEl(),l=i.offsetWidth,c=i.offsetHeight,u=n.offsetWidth,d=n.offsetHeight,r=(r||"").split(""),"b"===r[0]&&(s+=d),"r"===r[1]&&(a+=u),"c"===r[0]&&(s+=Math.round(d/2)),"c"===r[1]&&(a+=Math.round(u/2)),"b"===r[3]&&(s-=c),"r"===r[4]&&(a-=l),"c"===r[3]&&(s-=Math.round(c/2)),"c"===r[4]&&(a-=Math.round(l/2)),{x:a,y:s,w:l,h:c}}return{testMoveRel:function(n,r){for(var i=e.getViewPort(),o=0;o<r.length;o++){var a=t(this,n,r[o]);if(this._fixed){if(a.x>0&&a.x+a.w<i.w&&a.y>0&&a.y+a.h<i.h)return r[o]}else if(a.x>i.x&&a.x+a.w<i.w+i.x&&a.y>i.y&&a.y+a.h<i.h+i.y)return r[o]}return r[0]},moveRel:function(e,n){"string"!=typeof n&&(n=this.testMoveRel(e,n));var r=t(this,e,n);return this.moveTo(r.x,r.y)},moveBy:function(e,t){var n=this,r=n.layoutRect();return n.moveTo(r.x+e,r.y+t),n},moveTo:function(t,n){function r(e,t,n){return 0>e?0:e+n>t?(e=t-n,0>e?0:e):e}var i=this;if(i.settings.constrainToViewport){var o=e.getViewPort(window),a=i.layoutRect();t=r(t,o.w+o.x,a.w),n=r(n,o.h+o.y,a.h)}return i._rendered?i.layoutRect({x:t,y:n}).repaint():(i.settings.x=t,i.settings.y=n),i.fire("move",{x:t,y:n}),i}}}),r(Y,[z],function(e){return{resizeToContent:function(){this._layoutRect.autoResize=!0,this._lastRect=null,this.reflow()},resizeTo:function(t,n){if(1>=t||1>=n){var r=e.getWindowSize();t=1>=t?t*r.w:t,n=1>=n?n*r.h:n}return this._layoutRect.autoResize=!1,this.layoutRect({minW:t,minH:n,w:t,h:n}).reflow()},resizeBy:function(e,t){var n=this,r=n.layoutRect();return n.resizeTo(r.w+e,r.h+t)}}}),r(X,[K,G,Y,z],function(e,t,n,r){function i(e){var t;for(t=s.length;t--;)s[t]===e&&s.splice(t,1)}var o,a,s=[],l=[],c,u=e.extend({Mixins:[t,n],init:function(e){function t(){var e,t=u.zIndex||65535,n;if(l.length)for(e=0;e<l.length;e++)l[e].modal&&(t++,n=l[e]),l[e].getEl().style.zIndex=t,l[e].zIndex=t,t++;var i=document.getElementById(d.classPrefix+"modal-block");n?r.css(i,"z-index",n.zIndex-1):i&&(i.parentNode.removeChild(i),c=!1),u.currentZIndex=t}function n(e,t){for(;e;){if(e==t)return!0;e=e.parent()}}function i(e){function t(t,n){for(var r,i=0;i<s.length;i++)if(s[i]!=e)for(r=s[i].parent();r&&(r=r.parent());)r==e&&s[i].fixed(t).moveBy(0,n).repaint()}var n=r.getViewPort().y;e.settings.autofix&&(e._fixed?e._autoFixY>n&&(e.fixed(!1).layoutRect({y:e._autoFixY}).repaint(),t(!1,e._autoFixY-n)):(e._autoFixY=e.layoutRect().y,e._autoFixY<n&&(e.fixed(!0).layoutRect({y:0}).repaint(),t(!0,n-e._autoFixY))))}var d=this;d._super(e),d._eventsRoot=d,d.addClass("floatpanel"),e.autohide&&(o||(o=function(e){var t,r=d.getParentCtrl(e.target);for(t=s.length;t--;){var i=s[t];if(i.settings.autohide){if(r&&(n(r,i)||i.parent()===r))continue;e=i.fire("autohide",{target:e.target}),e.isDefaultPrevented()||i.hide()}}},r.on(document,"click",o)),s.push(d)),e.autofix&&(a||(a=function(){var e;for(e=s.length;e--;)i(s[e])},r.on(window,"scroll",a)),d.on("move",function(){i(this)})),d.on("postrender show",function(e){if(e.control==d){var n,i=d.classPrefix;d.modal&&!c&&(n=r.createFragment('<div id="'+i+'modal-block" class="'+i+"reset "+i+'fade"></div>'),n=n.firstChild,d.getContainerElm().appendChild(n),setTimeout(function(){r.addClass(n,i+"in"),r.addClass(d.getEl(),i+"in")},0),c=!0),l.push(d),t()}}),d.on("close hide",function(e){if(e.control==d){for(var n=l.length;n--;)l[n]===d&&l.splice(n,1);t()}}),d.on("show",function(){d.parents().each(function(e){return e._fixed?(d.fixed(!0),!1):void 0})}),e.popover&&(d._preBodyHtml='<div class="'+d.classPrefix+'arrow"></div>',d.addClass("popover").addClass("bottom").addClass("start"))},fixed:function(e){var t=this;if(t._fixed!=e){if(t._rendered){var n=r.getViewPort();e?t.layoutRect().y-=n.y:t.layoutRect().y+=n.y}t.toggleClass("fixed",e),t._fixed=e}return t},show:function(){var e=this,t,n=e._super();for(t=s.length;t--&&s[t]!==e;);return-1===t&&s.push(e),n},hide:function(){return i(this),this._super()},hideAll:function(){u.hideAll()},close:function(){var e=this;return e.fire("close"),e.remove()},remove:function(){i(this),this._super()}});return u.hideAll=function(){for(var e=s.length;e--;){var t=s[e];t.settings.autohide&&(t.fire("cancel",{},!1),t.hide(),s.splice(e,1))}},u}),r(J,[z],function(e){return function(t){function n(){if(!h)if(h=[],d.find)d.find("*").each(function(e){e.canFocus&&h.push(e.getEl())});else for(var e=d.getEl().getElementsByTagName("*"),t=0;t<e.length;t++)e[t].id&&e[t]&&h.push(e[t])}function r(){return document.getElementById(m)}function i(e){return e=e||r(),e&&e.getAttribute("role")}function o(e){for(var t,n=e||r();n=n.parentNode;)if(t=i(n))return t}function a(e){var t=document.getElementById(m);return t?t.getAttribute("aria-"+e):void 0}function s(){var n=r();if(!n||"TEXTAREA"!=n.nodeName&&"text"!=n.type)return t.onAction?t.onAction(m):e.fire(r(),"click",{keyboard:!0}),!0}function l(){var e;t.onCancel?((e=r())&&e.blur(),t.onCancel()):t.root.fire("cancel")}function c(e){function r(e){for(var t=d?d.getEl():document.body;e&&e!=t;){if("none"==e.style.display)return!1;e=e.parentNode}return!0}var i=-1,o,a,l=[];for(n(),a=l.length,a=0;a<h.length;a++)r(h[a])&&l.push(h[a]);for(a=l.length;a--;)if(l[a].id===m){i=a;break}i+=e,0>i?i=l.length-1:i>=l.length&&(i=0),o=l[i],o.focus(),m=o.id,t.actOnFocus&&s()}function u(){var e,r;for(r=i(t.root.getEl()),n(),e=h.length;e--;)if("toolbar"==r&&h[e].id===m)return h[e].focus(),void 0;h[0].focus()}var d=t.root,f=t.enableUpDown!==!1,p=t.enableLeftRight!==!1,h=t.items,m;return d.on("keydown",function(e){var n=37,r=39,u=38,d=40,h=27,m=14,g=13,v=32,y=9,b;switch(e.keyCode){case n:p&&(t.leftAction?t.leftAction():c(-1),b=!0);break;case r:p&&("menuitem"==i()&&"menu"==o()?a("haspopup")&&s():c(1),b=!0);break;case u:f&&(c(-1),b=!0);break;case d:f&&("menuitem"==i()&&"menubar"==o()?s():"button"==i()&&a("haspopup")?s():c(1),b=!0);break;case y:b=!0,e.shiftKey?c(-1):c(1);break;case h:b=!0,l();break;case m:case g:case v:b=s()}b&&(e.stopPropagation(),e.preventDefault())}),d.on("focusin",function(e){n(),m=e.target.id}),{moveFocus:c,focusFirst:u,cancel:l}}}),r(Q,[X,K,z,J,j],function(e,t,n,r,i){var o=e.extend({modal:!0,Defaults:{border:1,layout:"flex",containerCls:"panel",role:"dialog",callbacks:{submit:function(){this.fire("submit",{data:this.toJSON()})},close:function(){this.close()}}},init:function(e){var n=this;n._super(e),n.addClass("window"),n._fixed=!0,e.buttons&&(n.statusbar=new t({layout:"flex",border:"1 0 0 0",spacing:3,padding:10,align:"center",pack:"end",defaults:{type:"button"},items:e.buttons}),n.statusbar.addClass("foot"),n.statusbar.parent(n)),n.on("click",function(e){-1!=e.target.className.indexOf(n.classPrefix+"close")&&n.close()}),n.aria("label",e.title),n._fullscreen=!1},recalc:function(){var e=this,t=e.statusbar,r,i,o;e._fullscreen&&(e.layoutRect(n.getWindowSize()),e.layoutRect().contentH=e.layoutRect().innerH),e._super(),r=e.layoutRect(),e.settings.title&&!e._fullscreen&&(i=r.headerW,i>r.w&&(e.layoutRect({w:i}),o=!0)),t&&(t.layoutRect({w:e.layoutRect().innerW}).recalc(),i=t.layoutRect().minW+r.deltaW,i>r.w&&(e.layoutRect({w:i}),o=!0)),o&&e.recalc()},initLayoutRect:function(){var e=this,t=e._super(),r=0,i;e.settings.title&&!e._fullscreen&&(i=e.getEl("head"),t.headerW=i.offsetWidth,t.headerH=i.offsetHeight,r+=t.headerH),e.statusbar&&(r+=e.statusbar.layoutRect().h),t.deltaH+=r,t.minH+=r,t.h+=r;var o=n.getWindowSize();return t.x=Math.max(0,o.w/2-t.w/2),t.y=Math.max(0,o.h/2-t.h/2),t},renderHtml:function(){var e=this,t=e._layout,n=e._id,r=e.classPrefix,i=e.settings,o="",a="",s=i.html;return e.preRender(),t.preRender(e),i.title&&(o='<div id="'+n+'-head" class="'+r+'window-head">'+'<div class="'+r+'title">'+e.encode(i.title)+"</div>"+'<button type="button" class="'+r+'close" aria-hidden="true">&times;</button>'+'<div id="'+n+'-dragh" class="'+r+'dragh"></div>'+"</div>"),i.url&&(s='<iframe src="'+i.url+'" tabindex="-1"></iframe>'),"undefined"==typeof s&&(s=t.renderHtml(e)),e.statusbar&&(a=e.statusbar.renderHtml()),'<div id="'+n+'" class="'+e.classes()+'" hideFocus="1" tabIndex="-1">'+o+'<div id="'+n+'-body" class="'+e.classes("body")+'">'+s+"</div>"+a+"</div>"},fullscreen:function(e){var t=this,r=document.documentElement,i,o=t.classPrefix,a;if(e!=t._fullscreen)if(n.on(window,"resize",function(){var e;if(t._fullscreen)if(i)t._timer||(t._timer=setTimeout(function(){var e=n.getWindowSize();t.moveTo(0,0).resizeTo(e.w,e.h),t._timer=0},50));else{e=(new Date).getTime();var r=n.getWindowSize();t.moveTo(0,0).resizeTo(r.w,r.h),(new Date).getTime()-e>50&&(i=!0)}}),a=t.layoutRect(),t._fullscreen=e,e){t._initial={x:a.x,y:a.y,w:a.w,h:a.h},t._borderBox=t.parseBox("0"),t.getEl("head").style.display="none",a.deltaH-=a.headerH+2,n.addClass(r,o+"fullscreen"),n.addClass(document.body,o+"fullscreen"),t.addClass("fullscreen");var s=n.getWindowSize();t.moveTo(0,0).resizeTo(s.w,s.h)}else t._borderBox=t.parseBox(t.settings.border),t.getEl("head").style.display="",a.deltaH+=a.headerH,n.removeClass(r,o+"fullscreen"),n.removeClass(document.body,o+"fullscreen"),t.removeClass("fullscreen"),t.moveTo(t._initial.x,t._initial.y).resizeTo(t._initial.w,t._initial.h);return t.reflow()},postRender:function(){var e=this,t=[],n,o,a;setTimeout(function(){e.addClass("in")},0),e.keyboardNavigation=new r({root:e,enableLeftRight:!1,enableUpDown:!1,items:t,onCancel:function(){e.close()}}),e.find("*").each(function(e){e.canFocus&&(o=o||e.settings.autofocus,n=n||e,"filepicker"==e.type?(t.push(e.getEl("inp")),e.getEl("open")&&t.push(e.getEl("open").firstChild)):t.push(e.getEl()))}),e.statusbar&&e.statusbar.find("*").each(function(e){e.canFocus&&(o=o||e.settings.autofocus,n=n||e,t.push(e.getEl()))}),e._super(),e.statusbar&&e.statusbar.postRender(),!o&&n&&n.focus(),this.dragHelper=new i(e._id+"-dragh",{start:function(){a={x:e.layoutRect().x,y:e.layoutRect().y}},drag:function(t){e.moveTo(a.x+t.deltaX,a.y+t.deltaY)}}),e.on("submit",function(t){t.isDefaultPrevented()||e.close()})},submit:function(){var e=this.getParentCtrl(document.activeElement);return e&&e.blur(),this.fire("submit",{data:this.toJSON()})},remove:function(){var e=this;e._super(),e.dragHelper.destroy(),e.statusbar&&this.statusbar.remove()}});return o}),r(Z,[Q],function(e){var t=e.extend({init:function(e){e={border:1,padding:20,layout:"flex",pack:"center",align:"center",containerCls:"panel",autoScroll:!0,buttons:{type:"button",text:"Ok",action:"ok"},items:{type:"label",multiline:!0,maxWidth:500,maxHeight:200}},this._super(e)},Statics:{OK:1,OK_CANCEL:2,YES_NO:3,YES_NO_CANCEL:4,msgBox:function(n){var r,i=n.callback||function(){};switch(n.buttons){case t.OK_CANCEL:r=[{type:"button",text:"Ok",subtype:"primary",onClick:function(e){e.control.parents()[1].close(),i(!0)}},{type:"button",text:"Cancel",onClick:function(e){e.control.parents()[1].close(),i(!1)}}];break;case t.YES_NO:r=[{type:"button",text:"Ok",subtype:"primary",onClick:function(e){e.control.parents()[1].close(),i(!0)}}];break;case t.YES_NO_CANCEL:r=[{type:"button",text:"Ok",subtype:"primary",onClick:function(e){e.control.parents()[1].close()}}];break;default:r=[{type:"button",text:"Ok",subtype:"primary",onClick:function(e){e.control.parents()[1].close()}}]}return new e({padding:20,x:n.x,y:n.y,minWidth:300,minHeight:100,layout:"flex",pack:"center",align:"center",buttons:r,title:n.title,items:{type:"label",multiline:!0,maxWidth:500,maxHeight:200,text:n.text},onClose:n.onClose}).renderTo(document.body).reflow()},alert:function(e,n){return"string"==typeof e&&(e={text:e}),e.callback=n,t.msgBox(e)},confirm:function(e,n){return"string"==typeof e&&(e={text:e}),e.callback=n,e.buttons=t.OK_CANCEL,t.msgBox(e)}}});return t}),r(et,[Q,Z],function(e,t){return function(n){var r=this,i=[];r.windows=i,r.open=function(t,r){var o;return t.url=t.url||t.file,t.url&&(t.width=parseInt(t.width||320,10),t.height=parseInt(t.height||240,10)),t.body&&(t.items={defaults:t.defaults,type:t.bodyType||"form",items:t.body}),t.url||t.buttons||(t.buttons=[{text:"Ok",subtype:"primary",onclick:function(){o.find("form")[0].submit(),o.close()}},{text:"Cancel",onclick:function(){o.close()}}]),o=new e(t),i.push(o),o.on("close",function(){for(var e=i.length;e--;)i[e]===o&&i.splice(e,1);n.focus()}),t.data&&o.on("postRender",function(){this.find("*").each(function(e){var n=e.name();n in t.data&&e.value(t.data[n])})}),o.params=r||{},n.nodeChanged(),o.renderTo(document.body).reflow()},r.alert=function(e,n,r){t.alert(e,function(){n.call(r||this)})},r.confirm=function(e,n,r){t.confirm(e,function(e){n.call(r||this,e)})},r.close=function(){i.length&&i[i.length-1].close()},r.getParams=function(){return i.length?i[i.length-1].params:null},r.setParams=function(e){i.length&&(i[i.length-1].params=e)}}}),r(tt,[T,B,C,m,g,p],function(e,t,n,r,i,o){return function(a){function s(e,t){try{a.getDoc().execCommand(e,!1,t)}catch(n){}}function l(){var e=a.getDoc().documentMode;return e?e:6}function c(e){return e.isDefaultPrevented()}function u(){function t(e){function t(){if(3==l.nodeType){if(e&&c==l.length)return!0;if(!e&&0===c)return!0}}var n,r,i,s,l,c,u;n=W.getRng();var d=[n.startContainer,n.startOffset,n.endContainer,n.endOffset];if(n.collapsed||(e=!0),l=n[(e?"start":"end")+"Container"],c=n[(e?"start":"end")+"Offset"],3==l.nodeType&&(r=F.getParent(n.startContainer,F.isBlock),e&&(r=F.getNext(r,F.isBlock)),!r||!t()&&n.collapsed||(i=F.create("em",{id:"__mceDel"}),P(o.grep(r.childNodes),function(e){i.appendChild(e)}),r.appendChild(i))),n=F.createRng(),n.setStart(d[0],d[1]),n.setEnd(d[2],d[3]),W.setRng(n),a.getDoc().execCommand(e?"ForwardDelete":"Delete",!1,null),i){for(s=W.getBookmark();u=F.get("__mceDel");)F.remove(u,!0);
+W.moveToBookmark(s)}}a.on("keydown",function(n){var r;r=n.keyCode==I,c(n)||!r&&n.keyCode!=O||e.modifierPressed(n)||(n.preventDefault(),t(r))}),a.addCommand("Delete",function(){t()})}function d(){function e(e){var t=F.create("body"),n=e.cloneContents();return t.appendChild(n),W.serializer.serialize(t,{format:"html"})}function t(t){var n=e(t),r=F.createRng();r.selectNode(a.getBody());var i=e(r);return n===i}a.on("keydown",function(e){var n=e.keyCode,r;if(!c(e)&&(n==I||n==O)){if(r=a.selection.isCollapsed(),r&&!F.isEmpty(a.getBody()))return;if(j&&!r)return;if(!r&&!t(a.selection.getRng()))return;e.preventDefault(),a.setContent(""),a.selection.setCursorLocation(a.getBody(),0),a.nodeChanged()}})}function f(){a.on("keydown",function(t){!c(t)&&65==t.keyCode&&e.metaKeyPressed(t)&&(t.preventDefault(),a.execCommand("SelectAll"))})}function p(){a.settings.content_editable||(F.bind(a.getDoc(),"focusin",function(){W.setRng(W.getRng())}),F.bind(a.getDoc(),"mousedown",function(e){e.target==a.getDoc().documentElement&&(a.getWin().focus(),W.setRng(W.getRng()))}))}function h(){a.on("keydown",function(e){if(!c(e)&&e.keyCode===O&&W.isCollapsed()&&0===W.getRng(!0).startOffset){var t=W.getNode(),n=t.previousSibling;n&&n.nodeName&&"hr"===n.nodeName.toLowerCase()&&(F.remove(n),e.preventDefault())}})}function m(){window.Range.prototype.getClientRects||a.on("mousedown",function(e){if(!c(e)&&"HTML"===e.target.nodeName){var t=a.getBody();t.blur(),setTimeout(function(){t.focus()},0)}})}function g(){a.on("click",function(e){e=e.target,/^(IMG|HR)$/.test(e.nodeName)&&W.getSel().setBaseAndExtent(e,0,e,1),"A"==e.nodeName&&F.hasClass(e,"mce-item-anchor")&&W.select(e),a.nodeChanged()})}function v(){function e(){var e=F.getAttribs(W.getStart().cloneNode(!1));return function(){var t=W.getStart();t!==a.getBody()&&(F.setAttrib(t,"style",null),P(e,function(e){t.setAttributeNode(e.cloneNode(!0))}))}}function t(){return!W.isCollapsed()&&F.getParent(W.getStart(),F.isBlock)!=F.getParent(W.getEnd(),F.isBlock)}a.on("keypress",function(n){var r;return c(n)||8!=n.keyCode&&46!=n.keyCode||!t()?void 0:(r=e(),a.getDoc().execCommand("delete",!1,null),r(),n.preventDefault(),!1)}),F.bind(a.getDoc(),"cut",function(n){var r;!c(n)&&t()&&(r=e(),setTimeout(function(){r()},0))})}function y(){var e,n;a.on("selectionchange",function(){n&&(clearTimeout(n),n=0),n=window.setTimeout(function(){var n=W.getRng();e&&t.compareRanges(n,e)||(a.nodeChanged(),e=n)},50)})}function b(){document.body.setAttribute("role","application")}function C(){a.on("keydown",function(e){if(!c(e)&&e.keyCode===O&&W.isCollapsed()&&0===W.getRng(!0).startOffset){var t=W.getNode().previousSibling;if(t&&t.nodeName&&"table"===t.nodeName.toLowerCase())return e.preventDefault(),!1}})}function x(){l()>7||(s("RespectVisibilityInDesign",!0),a.contentStyles.push(".mceHideBrInPre pre br {display: none}"),F.addClass(a.getBody(),"mceHideBrInPre"),V.addNodeFilter("pre",function(e){for(var t=e.length,r,i,o,a;t--;)for(r=e[t].getAll("br"),i=r.length;i--;)o=r[i],a=o.prev,a&&3===a.type&&"\n"!=a.value.charAt(a.value-1)?a.value+="\n":o.parent.insert(new n("#text",3),o,!0).value="\n"}),U.addNodeFilter("pre",function(e){for(var t=e.length,n,r,i,o;t--;)for(n=e[t].getAll("br"),r=n.length;r--;)i=n[r],o=i.prev,o&&3==o.type&&(o.value=o.value.replace(/\r?\n$/,""))}))}function w(){F.bind(a.getBody(),"mouseup",function(){var e,t=W.getNode();"IMG"==t.nodeName&&((e=F.getStyle(t,"width"))&&(F.setAttrib(t,"width",e.replace(/[^0-9%]+/g,"")),F.setStyle(t,"width","")),(e=F.getStyle(t,"height"))&&(F.setAttrib(t,"height",e.replace(/[^0-9%]+/g,"")),F.setStyle(t,"height","")))})}function _(){a.on("keydown",function(t){var n,r,i,o,s,l,u,d;if(n=t.keyCode==I,!c(t)&&(n||t.keyCode==O)&&!e.modifierPressed(t)&&(r=W.getRng(),i=r.startContainer,o=r.startOffset,u=r.collapsed,3==i.nodeType&&i.nodeValue.length>0&&(0===o&&!u||u&&o===(n?0:1)))){if(l=i.previousSibling,l&&"IMG"==l.nodeName)return;d=a.schema.getNonEmptyElements(),t.preventDefault(),s=F.create("br",{id:"__tmp"}),i.parentNode.insertBefore(s,i),a.getDoc().execCommand(n?"ForwardDelete":"Delete",!1,null),i=W.getRng().startContainer,l=i.previousSibling,l&&1==l.nodeType&&!F.isBlock(l)&&F.isEmpty(l)&&!d[l.nodeName.toLowerCase()]&&F.remove(l),F.remove("__tmp")}})}function N(){a.on("keydown",function(t){var n,r,i,o,s;if(!c(t)&&t.keyCode==e.BACKSPACE&&(n=W.getRng(),r=n.startContainer,i=n.startOffset,o=F.getRoot(),s=r,n.collapsed&&0===i)){for(;s&&s.parentNode&&s.parentNode.firstChild==s&&s.parentNode!=o;)s=s.parentNode;"BLOCKQUOTE"===s.tagName&&(a.formatter.toggle("blockquote",null,s),n=F.createRng(),n.setStart(r,0),n.setEnd(r,0),W.setRng(n))}})}function E(){function e(){a._refreshContentEditable(),s("StyleWithCSS",!1),s("enableInlineTableEditing",!1),z.object_resizing||s("enableObjectResizing",!1)}z.readonly||a.on("BeforeExecCommand MouseDown",e)}function k(){function e(){P(F.select("a"),function(e){var t=e.parentNode,n=F.getRoot();if(t.lastChild===e){for(;t&&!F.isBlock(t);){if(t.parentNode.lastChild!==t||t===n)return;t=t.parentNode}F.add(t,"br",{"data-mce-bogus":1})}})}a.on("SetContent ExecCommand",function(t){("setcontent"==t.type||"mceInsertLink"===t.command)&&e()})}function S(){z.forced_root_block&&a.on("init",function(){s("DefaultParagraphSeparator",z.forced_root_block)})}function T(){a.on("Undo Redo SetContent",function(e){e.initial||a.execCommand("mceRepaint")})}function R(){a.on("keydown",function(e){var t;c(e)||e.keyCode!=O||(t=a.getDoc().selection.createRange(),t&&t.item&&(e.preventDefault(),a.undoManager.beforeChange(),F.remove(t.item(0)),a.undoManager.add()))})}function A(){var e;l()>=10&&(e="",P("p div h1 h2 h3 h4 h5 h6".split(" "),function(t,n){e+=(n>0?",":"")+t+":empty"}),a.contentStyles.push(e+"{padding-right: 1px !important}"))}function B(){l()<9&&(V.addNodeFilter("noscript",function(e){for(var t=e.length,n,r;t--;)n=e[t],r=n.firstChild,r&&n.attr("data-mce-innertext",r.value)}),U.addNodeFilter("noscript",function(e){for(var t=e.length,i,o,a;t--;)i=e[t],o=e[t].firstChild,o?o.value=r.decode(o.value):(a=i.attributes.map["data-mce-innertext"],a&&(i.attr("data-mce-innertext",null),o=new n("#text",3),o.value=a,o.raw=!0,i.append(o)))}))}function D(){function e(e,t){var n=i.createTextRange();try{n.moveToPoint(e,t)}catch(r){n=null}return n}function t(t){var r;t.button?(r=e(t.x,t.y),r&&(r.compareEndPoints("StartToStart",a)>0?r.setEndPoint("StartToStart",a):r.setEndPoint("EndToEnd",a),r.select())):n()}function n(){var e=r.selection.createRange();a&&!e.item&&0===e.compareEndPoints("StartToEnd",e)&&a.select(),F.unbind(r,"mouseup",n),F.unbind(r,"mousemove",t),a=o=0}var r=F.doc,i=r.body,o,a,s;r.documentElement.unselectable=!0,F.bind(r,"mousedown contextmenu",function(i){if("HTML"===i.target.nodeName){if(o&&n(),s=r.documentElement,s.scrollHeight>s.clientHeight)return;o=1,a=e(i.x,i.y),a&&(F.bind(r,"mouseup",n),F.bind(r,"mousemove",t),F.win.focus(),a.select())}})}function L(){a.on("keyup focusin",function(t){65==t.keyCode&&e.metaKeyPressed(t)||W.normalize()})}function M(){a.contentStyles.push("img:-moz-broken {-moz-force-broken-image-icon:1;min-width:24px;min-height:24px}")}function H(){a.inline||a.on("keydown",function(){document.activeElement==document.body&&a.getWin().focus()})}var P=o.each,O=e.BACKSPACE,I=e.DELETE,F=a.dom,W=a.selection,z=a.settings,V=a.parser,U=a.serializer,q=i.gecko,j=i.ie,$=i.webkit;C(),N(),d(),L(),$&&(_(),u(),p(),g(),S(),i.iOS?(y(),H()):f()),j&&i.ie<11&&(h(),b(),x(),w(),R(),A(),B(),D()),q&&(h(),m(),v(),E(),k(),T(),M())}}),r(nt,[p],function(e){function t(){return!1}function n(){return!0}var r="__bindings",i=e.makeMap("focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange mouseout mouseenter mouseleave keydown keypress keyup contextmenu dragend dragover draggesture dragdrop drop drag"," ");return{fire:function(e,i,o){var a=this,s,l,c,u,d;if(e=e.toLowerCase(),i=i||{},i.type=e,i.target||(i.target=a),i.preventDefault||(i.preventDefault=function(){i.isDefaultPrevented=n},i.stopPropagation=function(){i.isPropagationStopped=n},i.stopImmediatePropagation=function(){i.isImmediatePropagationStopped=n},i.isDefaultPrevented=t,i.isPropagationStopped=t,i.isImmediatePropagationStopped=t),a[r]&&(s=a[r][e]))for(l=0,c=s.length;c>l&&(s[l]=u=s[l],!i.isImmediatePropagationStopped());l++)if(u.call(a,i)===!1)return i.preventDefault(),i;if(o!==!1&&a.parent)for(d=a.parent();d&&!i.isPropagationStopped();)d.fire(e,i,!1),d=d.parent();return i},on:function(e,t){var n=this,o,a,s,l;if(t===!1&&(t=function(){return!1}),t)for(s=e.toLowerCase().split(" "),l=s.length;l--;)e=s[l],o=n[r],o||(o=n[r]={}),a=o[e],a||(a=o[e]=[],n.bindNative&&i[e]&&n.bindNative(e)),a.push(t);return n},off:function(e,t){var n=this,o,a=n[r],s,l,c,u;if(a)if(e)for(c=e.toLowerCase().split(" "),o=c.length;o--;){if(e=c[o],s=a[e],!e){for(l in a)a[e].length=0;return n}if(s){if(t)for(u=s.length;u--;)s[u]===t&&s.splice(u,1);else s.length=0;!s.length&&n.unbindNative&&i[e]&&(n.unbindNative(e),delete a[e])}}else{if(n.unbindNative)for(e in a)n.unbindNative(e);n[r]=[]}return n}}}),r(rt,[p,g],function(e,t){var n=e.each,r=e.explode,i={f9:120,f10:121,f11:122};return function(o){var a=this,s={};o.on("keyup keypress keydown",function(e){(e.altKey||e.ctrlKey||e.metaKey)&&n(s,function(n){var r=t.mac?e.ctrlKey||e.metaKey:e.ctrlKey;if(n.ctrl==r&&n.alt==e.altKey&&n.shift==e.shiftKey)return e.keyCode==n.keyCode||e.charCode&&e.charCode==n.charCode?(e.preventDefault(),"keydown"==e.type&&n.func.call(n.scope),!0):void 0})}),a.add=function(t,a,l,c){var u;return u=l,"string"==typeof l?l=function(){o.execCommand(u,!1,null)}:e.isArray(u)&&(l=function(){o.execCommand(u[0],u[1],u[2])}),n(r(t.toLowerCase()),function(e){var t={func:l,scope:c||o,desc:o.translate(a),alt:!1,ctrl:!1,shift:!1};n(r(e,"+"),function(e){switch(e){case"alt":case"ctrl":case"shift":t[e]=!0;break;default:t.charCode=e.charCodeAt(0),t.keyCode=i[e]||e.toUpperCase().charCodeAt(0)}}),s[(t.ctrl?"ctrl":"")+","+(t.alt?"alt":"")+","+(t.shift?"shift":"")+","+t.keyCode]=t}),!0}}}),r(it,[v,b,C,k,E,A,D,L,M,H,P,O,y,l,et,x,_,tt,g,p,nt,rt],function(e,n,r,i,o,a,s,l,c,u,d,f,p,h,m,g,v,y,b,C,x,w){function _(e,t){return"selectionchange"==t||"drop"==t?e.getDoc():!e.inline&&/^mouse|click|contextmenu/.test(t)?e.getDoc():e.getBody()}function N(e,t,r){var i=this,o,a;o=i.documentBaseUrl=r.documentBaseURL,a=r.baseURI,i.settings=t=T({id:e,theme:"modern",delta_width:0,delta_height:0,popup_css:"",plugins:"",document_base_url:o,add_form_submit_trigger:!0,submit_patch:!0,add_unload_trigger:!0,convert_urls:!0,relative_urls:!0,remove_script_host:!0,object_resizing:!0,doctype:"<!DOCTYPE html>",visual:!0,font_size_style_values:"xx-small,x-small,small,medium,large,x-large,xx-large",font_size_legacy_values:"xx-small,small,medium,large,x-large,xx-large,300%",forced_root_block:"p",hidden_input:!0,padd_empty_editor:!0,render_ui:!0,indentation:"30px",inline_styles:!0,convert_fonts_to_spans:!0,indent:"simple",indent_before:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist",indent_after:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist",validate:!0,entity_encoding:"named",url_converter:i.convertURL,url_converter_scope:i,ie7_compat:!0},t),n.settings=t,n.baseURL=r.baseURL,i.id=t.id=e,i.isNotDirty=!0,i.plugins={},i.documentBaseURI=new f(t.document_base_url||o,{base_uri:a}),i.baseURI=a,i.contentCSS=[],i.contentStyles=[],i.shortcuts=new w(i),i.execCommands={},i.queryStateCommands={},i.queryValueCommands={},i.loadedCSS={},i.suffix=r.suffix,i.editorManager=r,i.inline=t.inline,i.execCallback("setup",i)}var E=e.DOM,k=n.ThemeManager,S=n.PluginManager,T=C.extend,R=C.each,A=C.explode,B=C.inArray,D=C.trim,L=C.resolve,M=h.Event,H=b.gecko,P=b.ie,O=b.opera;return N.prototype={render:function(){function e(){var e=p.ScriptLoader;n.language&&"en"!=n.language&&(n.language_url=t.editorManager.baseURL+"/langs/"+n.language+".js"),n.language_url&&e.add(n.language_url),n.theme&&"function"!=typeof n.theme&&"-"!=n.theme.charAt(0)&&!k.urls[n.theme]&&k.load(n.theme,"themes/"+n.theme+"/theme"+i+".js"),C.isArray(n.plugins)&&(n.plugins=n.plugins.join(" ")),R(n.external_plugins,function(e,t){S.load(t,e),n.plugins+=" "+t}),R(n.plugins.split(/[ ,]/),function(e){if(e=D(e),e&&!S.urls[e])if("-"==e.charAt(0)){e=e.substr(1,e.length);var t=S.dependencies(e);R(t,function(e){var t={prefix:"plugins/",resource:e,suffix:"/plugin"+i+".js"};e=S.createUrl(t,e),S.load(e.resource,e)})}else S.load(e,{prefix:"plugins/",resource:e,suffix:"/plugin"+i+".js"})}),e.loadQueue(function(){t.removed||t.init()})}var t=this,n=t.settings,r=t.id,i=t.suffix;if(!M.domLoaded)return E.bind(window,"ready",function(){t.render()}),void 0;if(t.editorManager.settings=n,t.getElement()&&b.contentEditable){n.inline?t.inline=!0:(t.orgVisibility=t.getElement().style.visibility,t.getElement().style.visibility="hidden");var o=t.getElement().form||E.getParent(r,"form");o&&(t.formElement=o,n.hidden_input&&!/TEXTAREA|INPUT/i.test(t.getElement().nodeName)&&E.insertAfter(E.create("input",{type:"hidden",name:r}),r),t.formEventDelegate=function(e){t.fire(e.type,e)},E.bind(o,"submit reset",t.formEventDelegate),t.on("reset",function(){t.setContent(t.startContent,{format:"raw"})}),!n.submit_patch||o.submit.nodeType||o.submit.length||o._mceOldSubmit||(o._mceOldSubmit=o.submit,o.submit=function(){return t.editorManager.triggerSave(),t.isNotDirty=!0,o._mceOldSubmit(o)})),t.windowManager=new m(t),"xml"==n.encoding&&t.on("GetContent",function(e){e.save&&(e.content=E.encode(e.content))}),n.add_form_submit_trigger&&t.on("submit",function(){t.initialized&&t.save()}),n.add_unload_trigger&&(t._beforeUnload=function(){!t.initialized||t.destroyed||t.isHidden()||t.save({format:"raw",no_events:!0,set_dirty:!1})},t.editorManager.on("BeforeUnload",t._beforeUnload)),e()}},init:function(){function e(n){var r=S.get(n),i,o;i=S.urls[n]||t.documentBaseUrl.replace(/\/$/,""),n=D(n),r&&-1===B(h,n)&&(R(S.dependencies(n),function(t){e(t)}),o=new r(t,i),t.plugins[n]=o,o.init&&(o.init(t,i),h.push(n)))}var t=this,n=t.settings,r=t.getElement(),i,o,a,s,l,c,u,d,f,p,h=[];if(t.editorManager.add(t),n.aria_label=n.aria_label||E.getAttrib(r,"aria-label",t.getLang("aria.rich_text_area")),n.theme&&("function"!=typeof n.theme?(n.theme=n.theme.replace(/-/,""),l=k.get(n.theme),t.theme=new l(t,k.urls[n.theme]),t.theme.init&&t.theme.init(t,k.urls[n.theme]||t.documentBaseUrl.replace(/\/$/,""))):t.theme=n.theme),R(n.plugins.replace(/\-/g,"").split(/[ ,]/),e),t.fire("BeforeRenderUI"),n.render_ui&&t.theme&&(t.orgDisplay=r.style.display,"function"!=typeof n.theme?(i=n.width||r.style.width||r.offsetWidth,o=n.height||r.style.height||r.offsetHeight,a=n.min_height||100,f=/^[0-9\.]+(|px)$/i,f.test(""+i)&&(i=Math.max(parseInt(i,10)+(l.deltaWidth||0),100)),f.test(""+o)&&(o=Math.max(parseInt(o,10)+(l.deltaHeight||0),a)),l=t.theme.renderUI({targetNode:r,width:i,height:o,deltaWidth:n.delta_width,deltaHeight:n.delta_height}),n.content_editable||(E.setStyles(l.sizeContainer||l.editorContainer,{wi2dth:i,h2eight:o}),o=(l.iframeHeight||o)+("number"==typeof o?l.deltaHeight||0:""),a>o&&(o=a))):(l=n.theme(t,r),l.editorContainer.nodeType&&(l.editorContainer=l.editorContainer.id=l.editorContainer.id||t.id+"_parent"),l.iframeContainer.nodeType&&(l.iframeContainer=l.iframeContainer.id=l.iframeContainer.id||t.id+"_iframecontainer"),o=l.iframeHeight||r.offsetHeight),t.editorContainer=l.editorContainer),n.content_css&&R(A(n.content_css),function(e){t.contentCSS.push(t.documentBaseURI.toAbsolute(e))}),n.content_style&&t.contentStyles.push(n.content_style),n.content_editable)return r=s=l=null,t.initContentBody();for(document.domain&&location.hostname!=document.domain&&(t.editorManager.relaxedDomain=document.domain),t.iframeHTML=n.doctype+"<html><head>",n.document_base_url!=t.documentBaseUrl&&(t.iframeHTML+='<base href="'+t.documentBaseURI.getURI()+'" />'),!b.caretAfter&&n.ie7_compat&&(t.iframeHTML+='<meta http-equiv="X-UA-Compatible" content="IE=7" />'),t.iframeHTML+='<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />',p=0;p<t.contentCSS.length;p++){var m=t.contentCSS[p];t.iframeHTML+='<link type="text/css" rel="stylesheet" href="'+m+'" />',t.loadedCSS[m]=!0}u=n.body_id||"tinymce",-1!=u.indexOf("=")&&(u=t.getParam("body_id","","hash"),u=u[t.id]||u),d=n.body_class||"",-1!=d.indexOf("=")&&(d=t.getParam("body_class","","hash"),d=d[t.id]||""),t.iframeHTML+='</head><body id="'+u+'" class="mce-content-body '+d+'" '+"onload=\"window.parent.tinymce.get('"+t.id+"').fire('load');\"><br></body></html>",t.editorManager.relaxedDomain&&(P||O&&parseFloat(window.opera.version())<11)&&(c='javascript:(function(){document.open();document.domain="'+document.domain+'";'+'var ed = window.parent.tinymce.get("'+t.id+'");document.write(ed.iframeHTML);'+"document.close();ed.initContentBody();})()"),s=E.add(l.iframeContainer,"iframe",{id:t.id+"_ifr",src:c||'javascript:""',frameBorder:"0",allowTransparency:"true",title:t.editorManager.translate("Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help"),style:{width:"100%",height:o,display:"block"}}),t.contentAreaContainer=l.iframeContainer,l.editorContainer&&(E.get(l.editorContainer).style.display=t.orgDisplay),E.get(t.id).style.display="none",E.setAttrib(t.id,"aria-hidden",!0),t.editorManager.relaxedDomain&&c||t.initContentBody(),r=s=l=null},initContentBody:function(){var t=this,n=t.settings,o=E.get(t.id),f=t.getDoc(),p,h;n.inline||(t.getElement().style.visibility=t.orgVisibility),P&&t.editorManager.relaxedDomain||n.content_editable||(f.open(),f.write(t.iframeHTML),f.close(),t.editorManager.relaxedDomain&&(f.domain=t.editorManager.relaxedDomain)),n.content_editable&&(t.on("remove",function(){var e=this.getBody();E.removeClass(e,"mce-content-body"),E.removeClass(e,"mce-edit-focus"),E.setAttrib(e,"tabIndex",null),E.setAttrib(e,"contentEditable",null)}),E.addClass(o,"mce-content-body"),o.tabIndex=-1,t.contentDocument=f=n.content_document||document,t.contentWindow=n.content_window||window,t.bodyElement=o,n.content_document=n.content_window=null,n.root_name=o.nodeName.toLowerCase()),p=t.getBody(),p.disabled=!0,n.readonly||(p.contentEditable=t.getParam("content_editable_state",!0)),p.disabled=!1,t.schema=new g(n),t.dom=new e(f,{keep_values:!0,url_converter:t.convertURL,url_converter_scope:t,hex_colors:n.force_hex_style_colors,class_filter:n.class_filter,update_styles:!0,root_element:n.content_editable?t.id:null,schema:t.schema,onSetAttrib:function(e){t.fire("SetAttrib",e)}}),t.parser=new v(n,t.schema),t.parser.addAttributeFilter("src,href,style",function(e,n){for(var r=e.length,i,o=t.dom,a,s;r--;)i=e[r],a=i.attr(n),s="data-mce-"+n,i.attributes.map[s]||("style"===n?i.attr(s,o.serializeStyle(o.parseStyle(a),i.name)):i.attr(s,t.convertURL(a,n,i.name)))}),t.parser.addNodeFilter("script",function(e){for(var t=e.length,n;t--;)n=e[t],n.attr("type","mce-"+(n.attr("type")||"text/javascript"))}),t.parser.addNodeFilter("#cdata",function(e){for(var t=e.length,n;t--;)n=e[t],n.type=8,n.name="#comment",n.value="[CDATA["+n.value+"]]"}),t.parser.addNodeFilter("p,h1,h2,h3,h4,h5,h6,div",function(e){for(var n=e.length,i,o=t.schema.getNonEmptyElements();n--;)i=e[n],i.isEmpty(o)&&(i.empty().append(new r("br",1)).shortEnded=!0)}),t.serializer=new i(n,t),t.selection=new a(t.dom,t.getWin(),t.serializer,t),t.formatter=new s(t),t.undoManager=new l(t),t.forceBlocks=new u(t),t.enterKey=new c(t),t.editorCommands=new d(t),t.fire("PreInit"),n.browser_spellcheck||n.gecko_spellcheck||(f.body.spellcheck=!1,E.setAttrib(p,"spellcheck","false")),t.fire("PostRender"),t.quirks=y(t),n.directionality&&(p.dir=n.directionality),n.nowrap&&(p.style.whiteSpace="nowrap"),n.protect&&t.on("BeforeSetContent",function(e){R(n.protect,function(t){e.content=e.content.replace(t,function(e){return"<!--mce:protected "+escape(e)+"-->"})})}),t.on("SetContent",function(){t.addVisual(t.getBody())}),n.padd_empty_editor&&t.on("PostProcess",function(e){e.content=e.content.replace(/^(<p[^>]*>(&nbsp;|&#160;|\s|\u00a0|)<\/p>[\r\n]*|<br \/>[\r\n]*)$/,"")}),t.load({initial:!0,format:"html"}),t.startContent=t.getContent({format:"raw"}),t.initialized=!0,R(t._pendingNativeEvents,function(e){t.dom.bind(_(t,e),e,function(e){t.fire(e.type,e)})}),t.fire("init"),t.focus(!0),t.nodeChanged({initial:!0}),t.execCallback("init_instance_callback",t),t.contentStyles.length>0&&(h="",R(t.contentStyles,function(e){h+=e+"\r\n"}),t.dom.addStyle(h)),R(t.contentCSS,function(e){t.loadedCSS[e]||(t.dom.loadCSS(e),t.loadedCSS[e]=!0)}),n.auto_focus&&setTimeout(function(){var e=t.editorManager.get(n.auto_focus);e.selection.select(e.getBody(),1),e.selection.collapse(1),e.getBody().focus(),e.getWin().focus()},100),o=f=p=null},focus:function(e){var t,n=this,r=n.selection,i=n.settings.content_editable,o,a,s=n.getDoc(),l;e||(o=r.getRng(),o.item&&(a=o.item(0)),n._refreshContentEditable(),i||(b.opera||n.getBody().focus(),n.getWin().focus()),(H||i)&&(l=n.getBody(),l.setActive?l.setActive():l.focus(),i&&r.normalize()),a&&a.ownerDocument==s&&(o=s.body.createControlRange(),o.addElement(a),o.select())),n.editorManager.activeEditor!=n&&((t=n.editorManager.activeEditor)&&t.fire("deactivate",{relatedTarget:n}),n.fire("activate",{relatedTarget:t})),n.editorManager.activeEditor=n},execCallback:function(e){var t=this,n=t.settings[e],r;if(n)return t.callbackLookup&&(r=t.callbackLookup[e])&&(n=r.func,r=r.scope),"string"==typeof n&&(r=n.replace(/\.\w+$/,""),r=r?L(r):0,n=L(n),t.callbackLookup=t.callbackLookup||{},t.callbackLookup[e]={func:n,scope:r}),n.apply(r||t,Array.prototype.slice.call(arguments,1))},translate:function(e){var t=this.settings.language||"en",n=this.editorManager.i18n;return e?n[t+"."+e]||e.replace(/\{\#([^\}]+)\}/g,function(e,r){return n[t+"."+r]||"{#"+r+"}"}):""},getLang:function(e,n){return this.editorManager.i18n[(this.settings.language||"en")+"."+e]||(n!==t?n:"{#"+e+"}")},getParam:function(e,t,n){var r=e in this.settings?this.settings[e]:t,i;return"hash"===n?(i={},"string"==typeof r?R(r.indexOf("=")>0?r.split(/[;,](?![^=;,]*(?:[;,]|$))/):r.split(","),function(e){e=e.split("="),i[D(e[0])]=e.length>1?D(e[1]):D(e)}):i=r,i):r},nodeChanged:function(){var e=this,t=e.selection,n,r,i;e.initialized&&!e.settings.disable_nodechange&&(i=e.getBody(),n=t.getStart()||i,n=P&&n.ownerDocument!=e.getDoc()?e.getBody():n,"IMG"==n.nodeName&&t.isCollapsed()&&(n=n.parentNode),r=[],e.dom.getParent(n,function(e){return e===i?!0:(r.push(e),void 0)}),e.fire("NodeChange",{element:n,parents:r}))},addButton:function(e,t){var n=this;t.cmd&&(t.onclick=function(){n.execCommand(t.cmd)}),t.text||t.icon||(t.icon=e),n.buttons=n.buttons||{},t.tooltip=t.tooltip||t.title,n.buttons[e]=t},addMenuItem:function(e,t){var n=this;t.cmd&&(t.onclick=function(){n.execCommand(t.cmd)}),n.menuItems=n.menuItems||{},n.menuItems[e]=t},addCommand:function(e,t,n){this.execCommands[e]={func:t,scope:n||this}},addQueryStateHandler:function(e,t,n){this.queryStateCommands[e]={func:t,scope:n||this}},addQueryValueHandler:function(e,t,n){this.queryValueCommands[e]={func:t,scope:n||this}},addShortcut:function(e,t,n,r){this.shortcuts.add(e,t,n,r)},execCommand:function(e,t,n,r){var i=this,o=0,a;return/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint)$/.test(e)||r&&r.skip_focus||i.focus(),r=T({},r),r=i.fire("BeforeExecCommand",{command:e,ui:t,value:n}),r.isDefaultPrevented()?!1:(a=i.execCommands[e])&&a.func.call(a.scope,t,n)!==!0?(i.fire("ExecCommand",{command:e,ui:t,value:n}),!0):(R(i.plugins,function(r){return r.execCommand&&r.execCommand(e,t,n)?(i.fire("ExecCommand",{command:e,ui:t,value:n}),o=!0,!1):void 0}),o?o:i.theme&&i.theme.execCommand&&i.theme.execCommand(e,t,n)?(i.fire("ExecCommand",{command:e,ui:t,value:n}),!0):i.editorCommands.execCommand(e,t,n)?(i.fire("ExecCommand",{command:e,ui:t,value:n}),!0):(i.getDoc().execCommand(e,t,n),i.fire("ExecCommand",{command:e,ui:t,value:n}),void 0))},queryCommandState:function(e){var t=this,n,r;if(!t._isHidden()){if((n=t.queryStateCommands[e])&&(r=n.func.call(n.scope),r!==!0))return r;if(r=t.editorCommands.queryCommandState(e),-1!==r)return r;try{return t.getDoc().queryCommandState(e)}catch(i){}}},queryCommandValue:function(e){var n=this,r,i;if(!n._isHidden()){if((r=n.queryValueCommands[e])&&(i=r.func.call(r.scope),i!==!0))return i;if(i=n.editorCommands.queryCommandValue(e),i!==t)return i;try{return n.getDoc().queryCommandValue(e)}catch(o){}}},show:function(){var e=this;E.show(e.getContainer()),E.hide(e.id),e.load(),e.fire("show")},hide:function(){var e=this,t=e.getDoc();P&&t&&t.execCommand("SelectAll"),e.save(),E.hide(e.getContainer()),E.setStyle(e.id,"display",e.orgDisplay),e.fire("hide")},isHidden:function(){return!E.isHidden(this.id)},setProgressState:function(e,t){this.fire("ProgressState",{state:e,time:t})},load:function(e){var n=this,r=n.getElement(),i;return r?(e=e||{},e.load=!0,i=n.setContent(r.value!==t?r.value:r.innerHTML,e),e.element=r,e.no_events||n.fire("LoadContent",e),e.element=r=null,i):void 0},save:function(e){var t=this,n=t.getElement(),r,i;if(n&&t.initialized)return e=e||{},e.save=!0,e.element=n,r=e.content=t.getContent(e),e.no_events||t.fire("SaveContent",e),r=e.content,/TEXTAREA|INPUT/i.test(n.nodeName)?n.value=r:(n.innerHTML=r,(i=E.getParent(t.id,"form"))&&R(i.elements,function(e){return e.name==t.id?(e.value=r,!1):void 0})),e.element=n=null,e.set_dirty!==!1&&(t.isNotDirty=!0),r},setContent:function(e,t){var n=this,r=n.getBody(),i;return t=t||{},t.format=t.format||"html",t.set=!0,t.content=e,t.no_events||n.fire("BeforeSetContent",t),e=t.content,0===e.length||/^\s+$/.test(e)?(i=n.settings.forced_root_block,i&&n.schema.isValidChild(r.nodeName.toLowerCase(),i.toLowerCase())?e=P&&11>P?"<"+i+"></"+i+">":"<"+i+'><br data-mce-bogus="1"></'+i+">":P||(e='<br data-mce-bogus="1">'),r.innerHTML=e,n.fire("SetContent",t)):("raw"!==t.format&&(e=new o({},n.schema).serialize(n.parser.parse(e,{isRootContent:!0}))),t.content=D(e),n.dom.setHTML(r,t.content),t.no_events||n.fire("SetContent",t)),t.initial||(n.selection.select(r,!0),n.selection.collapse(!0)),t.content},getContent:function(e){var t=this,n,r=t.getBody();return e=e||{},e.format=e.format||"html",e.get=!0,e.getInner=!0,e.no_events||t.fire("BeforeGetContent",e),n="raw"==e.format?r.innerHTML:"text"==e.format?r.innerText||r.textContent:t.serializer.serialize(r,e),e.content="text"!=e.format?D(n):n,e.no_events||t.fire("GetContent",e),e.content},insertContent:function(e){this.execCommand("mceInsertContent",!1,e)},isDirty:function(){return!this.isNotDirty},getContainer:function(){var e=this;return e.container||(e.container=E.get(e.editorContainer||e.id+"_parent")),e.container},getContentAreaContainer:function(){return this.contentAreaContainer},getElement:function(){return E.get(this.settings.content_element||this.id)},getWin:function(){var e=this,t;return e.contentWindow||(t=E.get(e.id+"_ifr"),t&&(e.contentWindow=t.contentWindow)),e.contentWindow},getDoc:function(){var e=this,t;return e.contentDocument||(t=e.getWin(),t&&(e.contentDocument=t.document)),e.contentDocument},getBody:function(){return this.bodyElement||this.getDoc().body},convertURL:function(e,t,n){var r=this,i=r.settings;return i.urlconverter_callback?r.execCallback("urlconverter_callback",e,n,!0,t):!i.convert_urls||n&&"LINK"==n.nodeName||0===e.indexOf("file:")||0===e.length?e:i.relative_urls?r.documentBaseURI.toRelative(e):e=r.documentBaseURI.toAbsolute(e,i.remove_script_host)},addVisual:function(e){var n=this,r=n.settings,i=n.dom,o;e=e||n.getBody(),n.hasVisual===t&&(n.hasVisual=r.visual),R(i.select("table,a",e),function(e){var t;switch(e.nodeName){case"TABLE":return o=r.visual_table_class||"mce-item-table",t=i.getAttrib(e,"border"),t&&"0"!=t||(n.hasVisual?i.addClass(e,o):i.removeClass(e,o)),void 0;case"A":return i.getAttrib(e,"href",!1)||(t=i.getAttrib(e,"name")||e.id,o="mce-item-anchor",t&&(n.hasVisual?i.addClass(e,o):i.removeClass(e,o))),void 0}}),n.fire("VisualAid",{element:e,hasVisual:n.hasVisual})},remove:function(){var e=this,t=e.getContainer(),n=e.getDoc();e.removed||(e.removed=1,P&&n&&n.execCommand("SelectAll"),e.save(),E.setStyle(e.id,"display",e.orgDisplay),e.settings.content_editable||(M.unbind(e.getWin()),M.unbind(e.getDoc())),M.unbind(e.getBody()),M.unbind(t),e.fire("remove"),e.editorManager.remove(e),E.remove(t))},bindNative:function(e){var t=this;t.initialized?t.dom.bind(_(t,e),e,function(n){t.fire(e,n)}):t._pendingNativeEvents?t._pendingNativeEvents.push(e):t._pendingNativeEvents=[e]},unbindNative:function(e){var t=this;t.initialized&&t.dom.unbind(e)},destroy:function(e){var t=this,n;t.destroyed||(H&&(M.unbind(t.getDoc()),M.unbind(t.getWin()),M.unbind(t.getBody())),e||(t.editorManager.off("beforeunload",t._beforeUnload),t.theme&&t.theme.destroy&&t.theme.destroy(),t.selection.destroy(),t.dom.destroy()),n=t.formElement,n&&(n.submit=n._mceOldSubmit,n._mceOldSubmit=null,E.unbind(n,"submit reset",t.formEventDelegate)),t.contentAreaContainer=t.formElement=t.container=null,t.settings.content_element=t.bodyElement=t.contentDocument=t.contentWindow=null,t.selection&&(t.selection=t.selection.win=t.selection.dom=t.selection.dom.doc=null),t.destroyed=1)},_refreshContentEditable:function(){var e=this,t,n;e._isHidden()&&(t=e.getBody(),n=t.parentNode,n.removeChild(t),n.appendChild(t),t.focus())},_isHidden:function(){var e;return H?(e=this.selection.getSel(),!e||!e.rangeCount||0===e.rangeCount):0}},T(N.prototype,x),N}),r(ot,[],function(){var e={};return{add:function(t,n){for(var r in n)e[r]=n[r]},translate:function(t){if("undefined"==typeof t)return t;if("string"!=typeof t&&t.raw)return t.raw;if(t.push){var n=t.slice(1);t=(e[t[0]]||t[0]).replace(/\{([^\}]+)\}/g,function(e,t){return n[t]})}return e[t]||t},data:e}}),r(at,[v,g],function(e,t){function n(r){function i(){try{return document.activeElement}catch(e){return document.body}}function o(e){return e&&e.startContainer?{startContainer:e.startContainer,startOffset:e.startOffset,endContainer:e.endContainer,endOffset:e.endOffset}:e}function a(e,t){var n;return t.startContainer?(n=e.getDoc().createRange(),n.setStart(t.startContainer,t.startOffset),n.setEnd(t.endContainer,t.endOffset)):n=t,n}function s(s){function l(t){return!!e.DOM.getParent(t,n.isEditorUIElement)}var c=s.editor,u,d;c.on("init",function(){"onbeforedeactivate"in document&&t.ie<11?c.dom.bind(c.getBody(),"beforedeactivate",function(){var e=c.getDoc().selection;try{u=e&&e.createRange?e.createRange():c.selection.getRng()}catch(t){}}):(c.inline||t.ie>10)&&(c.on("nodechange keyup",function(){var e,t=document.activeElement;for(t&&t.id==c.id+"_ifr"&&(t=c.getBody());t;){if(t==c.getBody()){e=!0;break}t=t.parentNode}e&&(u=c.selection.getRng())}),t.webkit&&(d=function(){var e=c.selection.getRng();e.collapsed||(u=e)},e.DOM.bind(document,"selectionchange",d),c.on("remove",function(){e.DOM.unbind(document,"selectionchange",d)})))}),c.on("focusin",function(){var e=r.focusedEditor;c.selection.lastFocusBookmark&&(c.selection.setRng(a(c,c.selection.lastFocusBookmark)),c.selection.lastFocusBookmark=null),e!=c&&(e&&e.fire("blur",{focusedEditor:c}),r.activeEditor=c,c.fire("focus",{blurredEditor:e}),c.focus(!1),r.focusedEditor=c)}),c.on("focusout",function(){c.selection.lastFocusBookmark=o(u),window.setTimeout(function(){var e=r.focusedEditor;e!=c&&(c.selection.lastFocusBookmark=null),l(i())||e!=c||(c.fire("blur",{focusedEditor:null}),r.focusedEditor=null,c.selection.lastFocusBookmark=null)},0)})}r.on("AddEditor",s)}return n.isEditorUIElement=function(e){return-1!==e.className.indexOf("mce-")},n}),r(st,[it,v,O,g,p,nt,ot,at],function(e,n,r,i,o,a,s,l){var c=n.DOM,u=o.explode,d=o.each,f=o.extend,p=0,h,m={majorVersion:"4",minorVersion:"0.5",releaseDate:"2013-08-27",editors:[],i18n:s,activeEditor:null,setup:function(){var e=this,t,n,i="",o;if(n=document.location.href.replace(/[\?#].*$/,"").replace(/[\/\\][^\/]+$/,""),/[\/\\]$/.test(n)||(n+="/"),o=window.tinymce||window.tinyMCEPreInit)t=o.base||o.baseURL,i=o.suffix;
+else for(var a=document.getElementsByTagName("script"),s=0;s<a.length;s++){var c=a[s].src;if(/tinymce(\.jquery|)(\.min|\.dev|)\.js/.test(c)){-1!=c.indexOf(".min")&&(i=".min"),t=c.substring(0,c.lastIndexOf("/"));break}}e.baseURL=new r(n).toAbsolute(t),e.documentBaseURL=n,e.baseURI=new r(e.baseURL),e.suffix=i,e.focusManager=new l(e)},init:function(t){function n(e){var t=e.id;return t||(t=e.name,t=t&&!c.get(t)?e.name:c.uniqueId(),e.setAttribute("id",t)),t}function r(e,t,n){var r=e[t];if(r)return r.apply(n||this,Array.prototype.slice.call(arguments,2))}function i(e,t){return t.constructor===RegExp?t.test(e.className):c.hasClass(e,t)}var o=this,a=[],s;o.settings=t,c.bind(window,"ready",function(){var l,h;if(r(t,"onpageload"),t.types)return d(t.types,function(r){d(c.select(r.selector),function(i){var s=new e(n(i),f({},t,r),o);a.push(s),s.render(1)})}),void 0;if(t.selector)return d(c.select(t.selector),function(r){var i=new e(n(r),t,o);a.push(i),i.render(1)}),void 0;switch(t.mode){case"exact":l=t.elements||"",l.length>0&&d(u(l),function(n){c.get(n)?(s=new e(n,t,o),a.push(s),s.render(!0)):d(document.forms,function(r){d(r.elements,function(r){r.name===n&&(n="mce_editor_"+p++,c.setAttrib(r,"id",n),s=new e(n,t,o),a.push(s),s.render(1))})})});break;case"textareas":case"specific_textareas":d(c.select("textarea"),function(r){t.editor_deselector&&i(r,t.editor_deselector)||(!t.editor_selector||i(r,t.editor_selector))&&(s=new e(n(r),t,o),a.push(s),s.render(!0))})}t.oninit&&(l=h=0,d(a,function(e){h++,e.initialized?l++:e.on("init",function(){l++,l==h&&r(t,"oninit")}),l==h&&r(t,"oninit")}))})},get:function(e){return e===t?this.editors:this.editors[e]},add:function(e){var t=this,n=t.editors;return n[e.id]=e,n.push(e),t.activeEditor=e,t.fire("AddEditor",{editor:e}),h||(h=function(){t.fire("BeforeUnload")},c.bind(window,"beforeunload",h)),e},createEditor:function(t,n){return this.add(new e(t,n,this))},remove:function(e){var t=this,n,r=t.editors,i;if(e){if("string"==typeof e)return e=e.selector||e,d(c.select(e),function(e){t.remove(r[e.id])}),void 0;if(i=e,!r[i.id])return null;for(delete r[i.id],n=0;n<r.length;n++)if(r[n]==i){r.splice(n,1);break}if(t.activeEditor==i&&(t.activeEditor=r[0]),i&&!i.removed)return i.remove(),i.destroy(),t.fire("RemoveEditor",{editor:i}),r.length||c.unbind(window,"beforeunload",h),i}else for(n=r.length-1;n>=0;n--)t.remove(r[n])},execCommand:function(t,n,r){var i=this,o=i.get(r);switch(t){case"mceAddEditor":return i.get(r)||new e(r,i.settings,i).render(),!0;case"mceRemoveEditor":return o&&o.remove(),!0;case"mceToggleEditor":return o?(o.isHidden()?o.show():o.hide(),!0):(i.execCommand("mceAddEditor",0,r),!0)}return i.activeEditor?i.activeEditor.execCommand(t,n,r):!1},triggerSave:function(){d(this.editors,function(e){e.save()})},addI18n:function(e,t){s.add(e,t)},translate:function(e){return s.translate(e)}};return f(m,a),m.setup(),window.tinymce=window.tinyMCE=m,m}),r(lt,[st,p],function(e,t){var n=t.each,r=t.explode;e.on("AddEditor",function(e){var t=e.editor;t.on("preInit",function(){function e(e,t){n(t,function(t,n){t&&s.setStyle(e,n,t)}),s.rename(e,"span")}function i(e){s=t.dom,l.convert_fonts_to_spans&&n(s.select("font,u,strike",e.node),function(e){o[e.nodeName.toLowerCase()](s,e)})}var o,a,s,l=t.settings;l.inline_styles&&(a=r(l.font_size_legacy_values),o={font:function(t,n){e(n,{backgroundColor:n.style.backgroundColor,color:n.color,fontFamily:n.face,fontSize:a[parseInt(n.size,10)-1]})},u:function(t,n){e(n,{textDecoration:"underline"})},strike:function(t,n){e(n,{textDecoration:"line-through"})}},t.on("PreProcess SetContent",i))})})}),r(ct,[],function(){return{send:function(e){function t(){!e.async||4==n.readyState||r++>1e4?(e.success&&1e4>r&&200==n.status?e.success.call(e.success_scope,""+n.responseText,n,e):e.error&&e.error.call(e.error_scope,r>1e4?"TIMED_OUT":"GENERAL",n,e),n=null):setTimeout(t,10)}var n,r=0;if(e.scope=e.scope||this,e.success_scope=e.success_scope||e.scope,e.error_scope=e.error_scope||e.scope,e.async=e.async===!1?!1:!0,e.data=e.data||"",n=new XMLHttpRequest){if(n.overrideMimeType&&n.overrideMimeType(e.content_type),n.open(e.type||(e.data?"POST":"GET"),e.url,e.async),e.content_type&&n.setRequestHeader("Content-Type",e.content_type),n.setRequestHeader("X-Requested-With","XMLHttpRequest"),n.send(e.data),!e.async)return t();setTimeout(t,10)}}}}),r(ut,[],function(){function e(t,n){var r,i,o,a;if(n=n||'"',null===t)return"null";if(o=typeof t,"string"==o)return i="\bb t\nn\ff\rr\"\"''\\\\",n+t.replace(/([\u0080-\uFFFF\x00-\x1f\"\'\\])/g,function(e,t){return'"'===n&&"'"===e?e:(r=i.indexOf(t),r+1?"\\"+i.charAt(r+1):(e=t.charCodeAt().toString(16),"\\u"+"0000".substring(e.length)+e))})+n;if("object"==o){if(t.hasOwnProperty&&"[object Array]"===Object.prototype.toString.call(t)){for(r=0,i="[";r<t.length;r++)i+=(r>0?",":"")+e(t[r],n);return i+"]"}i="{";for(a in t)t.hasOwnProperty(a)&&(i+="function"!=typeof t[a]?(i.length>1?","+n:n)+a+n+":"+e(t[a],n):"");return i+"}"}return""+t}return{serialize:e,parse:function(e){try{return window[String.fromCharCode(101)+"val"]("("+e+")")}catch(t){}}}}),r(dt,[ut,ct,p],function(e,t,n){function r(e){this.settings=i({},e),this.count=0}var i=n.extend;return r.sendRPC=function(e){return(new r).send(e)},r.prototype={send:function(n){var r=n.error,o=n.success;n=i(this.settings,n),n.success=function(t,i){t=e.parse(t),"undefined"==typeof t&&(t={error:"JSON Parse error."}),t.error?r.call(n.error_scope||n.scope,t.error,i):o.call(n.success_scope||n.scope,t.result)},n.error=function(e,t){r&&r.call(n.error_scope||n.scope,e,t)},n.data=e.serialize({id:n.id||"c"+this.count++,method:n.method,params:n.params}),n.content_type="application/json",t.send(n)}},r}),r(ft,[v],function(e){return{callbacks:{},count:0,send:function(n){var r=this,i=e.DOM,o=n.count!==t?n.count:r.count,a="tinymce_jsonp_"+o;r.callbacks[o]=function(e){i.remove(a),delete r.callbacks[o],n.callback(e)},i.add(i.doc.body,"script",{id:a,src:n.url,type:"text/javascript"}),r.count++}}}),r(pt,[],function(){function e(){s=[];for(var e in a)s.push(e);i.length=s.length}function n(){function n(e){var n,r;return r=e!==t?u+e:i.indexOf(",",u),-1===r||r>i.length?null:(n=i.substring(u,r),u=r+1,n)}var r,i,s,u=0;if(a={},c){o.load(l),i=o.getAttribute(l)||"";do r=n(parseInt(n(),32)||0),null!==r&&(s=n(parseInt(n(),32)||0),a[r]=s);while(null!==r);e()}}function r(){var t,n="";if(c){for(var r in a)t=a[r],n+=(n?",":"")+r.length.toString(32)+","+r+","+t.length.toString(32)+","+t;o.setAttribute(l,n),o.save(l),e()}}var i,o,a,s,l,c;return window.localStorage?localStorage:(l="tinymce",o=document.documentElement,c=!!o.addBehavior,c&&o.addBehavior("#default#userData"),i={key:function(e){return s[e]},getItem:function(e){return e in a?a[e]:null},setItem:function(e,t){a[e]=""+t,r()},removeItem:function(e){delete a[e],r()},clear:function(){a={},r()}},n(),i)}),r(ht,[v,l,y,b,p,g],function(e,t,n,r,i,o){var a=window.tinymce;return a.DOM=e.DOM,a.ScriptLoader=n.ScriptLoader,a.PluginManager=r.PluginManager,a.ThemeManager=r.ThemeManager,a.dom=a.dom||{},a.dom.Event=t.Event,i.each(i,function(e,t){a[t]=e}),i.each("isOpera isWebKit isIE isGecko isMac".split(" "),function(e){a[e]=o[e.substr(2).toLowerCase()]}),{}}),r(mt,[I,p],function(e,t){return e.extend({Defaults:{firstControlClass:"first",lastControlClass:"last"},init:function(e){this.settings=t.extend({},this.Defaults,e)},preRender:function(e){e.addClass(this.settings.containerClass,"body")},applyClasses:function(e){var t=this,n=t.settings,r,i,o;r=e.items().filter(":visible"),i=n.firstControlClass,o=n.lastControlClass,r.each(function(e){e.removeClass(i).removeClass(o),n.controlClass&&e.addClass(n.controlClass)}),r.eq(0).addClass(i),r.eq(-1).addClass(o)},renderHtml:function(e){var t=this,n=t.settings,r,i="";return r=e.items(),r.eq(0).addClass(n.firstControlClass),r.eq(-1).addClass(n.lastControlClass),r.each(function(e){n.controlClass&&e.addClass(n.controlClass),i+=e.renderHtml()}),i},recalc:function(){},postRender:function(){}})}),r(gt,[mt],function(e){return e.extend({Defaults:{containerClass:"abs-layout",controlClass:"abs-layout-item"},recalc:function(e){e.items().filter(":visible").each(function(e){var t=e.settings;e.layoutRect({x:t.x,y:t.y,w:t.w,h:t.h}),e.recalc&&e.recalc()})},renderHtml:function(e){return'<div id="'+e._id+'-absend" class="'+e.classPrefix+'abs-end"></div>'+this._super(e)}})}),r(vt,[V,G],function(e,t){return e.extend({Mixins:[t],Defaults:{classes:"widget tooltip tooltip-n"},text:function(e){var t=this;return"undefined"!=typeof e?(t._value=e,t._rendered&&(t.getEl().lastChild.innerHTML=t.encode(e)),t):t._value},renderHtml:function(){var e=this,t=e.classPrefix;return'<div id="'+e._id+'" class="'+e.classes()+'" role="presentation">'+'<div class="'+t+'tooltip-arrow"></div>'+'<div class="'+t+'tooltip-inner">'+e.encode(e._text)+"</div>"+"</div>"},repaint:function(){var e=this,t,n;t=e.getEl().style,n=e._layoutRect,t.left=n.x+"px",t.top=n.y+"px",t.zIndex=131070}})}),r(yt,[V,vt],function(e,t){var n,r=e.extend({init:function(e){var t=this;t._super(e),t.canFocus=!0,e.tooltip&&r.tooltips!==!1&&t.on("mouseenter mouseleave",function(n){var r=t.tooltip().moveTo(-65535);if(n.control==t&&"mouseenter"==n.type){var i=r.text(e.tooltip).show().testMoveRel(t.getEl(),["bc-tc","bc-tl","bc-tr"]);r.toggleClass("tooltip-n","bc-tc"==i),r.toggleClass("tooltip-nw","bc-tl"==i),r.toggleClass("tooltip-ne","bc-tr"==i),r.moveRel(t.getEl(),i)}else r.hide()}),t.aria("label",e.tooltip)},tooltip:function(){var e=this;return n||(n=new t({type:"tooltip"}),n.renderTo(e.getContainerElm())),n},active:function(e){var t=this,n;return e!==n&&(t.aria("pressed",e),t.toggleClass("active",e)),t._super(e)},disabled:function(e){var t=this,n;return e!==n&&(t.aria("disabled",e),t.toggleClass("disabled",e)),t._super(e)},postRender:function(){var e=this,t=e.settings;e._rendered=!0,e._super(),e.parent()||!t.width&&!t.height||(e.initLayoutRect(),e.repaint()),t.autofocus&&setTimeout(function(){e.focus()},0)},remove:function(){this._super(),n&&(n.remove(),n=null)}});return r}),r(bt,[yt],function(e){return e.extend({Defaults:{classes:"widget btn",role:"button"},init:function(e){var t=this,n;t.on("click mousedown",function(e){e.preventDefault()}),t._super(e),n=e.size,e.subtype&&t.addClass(e.subtype),n&&t.addClass("btn-"+n)},repaint:function(){var e=this.getEl().firstChild.style;e.width=e.height="100%",this._super()},renderHtml:function(){var e=this,t=e._id,n=e.classPrefix,r=e.settings.icon,i="";return e.settings.image&&(r="none",i=" style=\"background-image: url('"+e.settings.image+"')\""),r=e.settings.icon?n+"ico "+n+"i-"+r:"",'<div id="'+t+'" class="'+e.classes()+'" tabindex="-1">'+'<button role="presentation" type="button" tabindex="-1">'+(r?'<i class="'+r+'"'+i+"></i>":"")+(e._text?(r?" ":"")+e.encode(e._text):"")+"</button>"+"</div>"}})}),r(Ct,[q],function(e){return e.extend({Defaults:{defaultType:"button",role:"toolbar"},renderHtml:function(){var e=this,t=e._layout;return e.addClass("btn-group"),e.preRender(),t.preRender(e),'<div id="'+e._id+'" class="'+e.classes()+'">'+'<div id="'+e._id+'-body">'+(e.settings.html||"")+t.renderHtml(e)+"</div>"+"</div>"}})}),r(xt,[yt],function(e){return e.extend({Defaults:{classes:"checkbox",role:"checkbox",checked:!1},init:function(e){var t=this;t._super(e),t.on("click mousedown",function(e){e.preventDefault()}),t.on("click",function(e){e.preventDefault(),t.disabled()||t.checked(!t.checked())}),t.checked(t.settings.checked)},checked:function(e){var t=this;return"undefined"!=typeof e?(e?t.addClass("checked"):t.removeClass("checked"),t._checked=e,t.aria("checked",e),t):t._checked},value:function(e){return this.checked(e)},renderHtml:function(){var e=this,t=e._id,n=e.classPrefix;return'<div id="'+t+'" class="'+e.classes()+'" unselectable="on" aria-labeledby="'+t+'-al" tabindex="-1">'+'<i class="'+n+"ico "+n+'i-checkbox"></i>'+'<span id="'+t+'-al" class="'+n+'label">'+e.encode(e._text)+"</span>"+"</div>"}})}),r(wt,[bt,X],function(e,t){return e.extend({showPanel:function(){var e=this,n=e.settings;n.panel.popover=!0,n.panel.autohide=!0,e.active(!0),e.panel?e.panel.show():(e.panel=new t(n.panel).on("hide",function(){e.active(!1)}).parent(e).renderTo(e.getContainerElm()),e.panel.fire("show"),e.panel.reflow()),e.panel.moveRel(e.getEl(),n.popoverAlign||"bc-tc")},hidePanel:function(){var e=this;e.panel&&e.panel.hide()},postRender:function(){var e=this;return e.on("click",function(t){t.control===e&&(e.panel&&e.panel.visible()?e.hidePanel():e.showPanel())}),e._super()}})}),r(_t,[wt,v],function(e,t){var n=t.DOM;return e.extend({init:function(e){this._super(e),this.addClass("colorbutton")},color:function(e){return e?(this._color=e,this.getEl("preview").style.backgroundColor=e,this):this._color},renderHtml:function(){var e=this,t=e._id,n=e.classPrefix,r=e.settings.icon?n+"ico "+n+"i-"+e.settings.icon:"",i=e.settings.image?" style=\"background-image: url('"+e.settings.image+"')\"":"";return'<div id="'+t+'" class="'+e.classes()+'">'+'<button role="presentation" hidefocus type="button" tabindex="-1">'+(r?'<i class="'+r+'"'+i+"></i>":"")+'<span id="'+t+'-preview" class="'+n+'preview"></span>'+(e._text?(r?" ":"")+e._text:"")+"</button>"+'<button type="button" class="'+n+'open" hidefocus tabindex="-1">'+' <i class="'+n+'caret"></i>'+"</button>"+"</div>"},postRender:function(){var e=this,t=e.settings.onclick;return e.on("click",function(r){r.control!=e||n.getParent(r.target,"."+e.classPrefix+"open")||(r.stopImmediatePropagation(),t.call(e,r))}),delete e.settings.onclick,e._super()}})}),r(Nt,[yt,z],function(e,t){return e.extend({init:function(e){var n=this;n._super(e),n.addClass("combobox"),n.on("click",function(e){for(var t=e.target;t;)t.id&&-1!=t.id.indexOf("-open")&&n.fire("action"),t=t.parentNode}),n.on("keydown",function(e){"INPUT"==e.target.nodeName&&13==e.keyCode&&n.parents().reverse().each(function(t){return e.preventDefault(),n.fire("change"),t.submit?(t.submit(),!1):void 0})}),e.placeholder&&(n.addClass("placeholder"),n.on("focusin",function(){n._hasOnChange||(t.on(n.getEl("inp"),"change",function(){n.fire("change")}),n._hasOnChange=!0),n.hasClass("placeholder")&&(n.getEl("inp").value="",n.removeClass("placeholder"))}),n.on("focusout",function(){0===n.value().length&&(n.getEl("inp").value=e.placeholder,n.addClass("placeholder"))}))},value:function(e){var t=this;return"undefined"!=typeof e?(t._value=e,t.removeClass("placeholder"),t._rendered&&(t.getEl("inp").value=e),t):t._rendered?(e=t.getEl("inp").value,e!=t.settings.placeholder?e:""):t._value},disabled:function(e){var t=this;t._super(e),t._rendered&&(t.getEl("inp").disabled=e)},focus:function(){this.getEl("inp").focus()},repaint:function(){var e=this,n=e.getEl(),r=e.getEl("open"),i=e.layoutRect(),o,a;o=r?i.w-r.offsetWidth-10:i.w-10;var s=document;return s.all&&(!s.documentMode||s.documentMode<=8)&&(a=e.layoutRect().h-2+"px"),t.css(n.firstChild,{width:o,lineHeight:a}),e._super(),e},postRender:function(){var e=this;return t.on(this.getEl("inp"),"change",function(){e.fire("change")}),e._super()},renderHtml:function(){var e=this,t=e._id,n=e.settings,r=e.classPrefix,i=n.value||n.placeholder||"",o,a,s="";return o=n.icon?r+"ico "+r+"i-"+n.icon:"",a=e._text,(o||a)&&(s='<div id="'+t+'-open" class="'+r+"btn "+r+'open" tabIndex="-1">'+'<button id="'+t+'-action" type="button" hidefocus tabindex="-1">'+(o?'<i class="'+o+'"></i>':'<i class="'+r+'caret"></i>')+(a?(o?" ":"")+a:"")+"</button>"+"</div>",e.addClass("has-open")),'<div id="'+t+'" class="'+e.classes()+'">'+'<input id="'+t+'-inp" class="'+r+"textbox "+r+'placeholder" value="'+i+'" hidefocus="true">'+s+"</div>"}})}),r(Et,[V,J],function(e,t){return e.extend({Defaults:{delimiter:"\xbb"},init:function(e){var t=this;t._super(e),t.addClass("path"),t.canFocus=!0,t.on("click",function(e){var n,r=e.target;(n=r.getAttribute("data-index"))&&t.fire("select",{value:t.data()[n],index:n})})},focus:function(){var e=this;return e.keyNav=new t({root:e,enableLeftRight:!0}),e.keyNav.focusFirst(),e},data:function(e){var t=this;return"undefined"!=typeof e?(t._data=e,t.update(),t):t._data},update:function(){this.innerHtml(this._getPathHtml())},postRender:function(){var e=this;e._super(),e.data(e.settings.data)},renderHtml:function(){var e=this;return'<div id="'+e._id+'" class="'+e.classPrefix+'path">'+e._getPathHtml()+"</div>"},_getPathHtml:function(){var e=this,t=e._data||[],n,r,i="",o=e.classPrefix;for(n=0,r=t.length;r>n;n++)i+=(n>0?'<div class="'+o+'divider" aria-hidden="true"> '+e.settings.delimiter+" </div>":"")+'<div role="button" class="'+o+"path-item"+(n==r-1?" "+o+"last":"")+'" data-index="'+n+'" tabindex="-1" id="'+e._id+"-"+n+'">'+t[n].name+"</div>";return i||(i='<div class="'+o+'path-item">&nbsp;</div>'),i}})}),r(kt,[Et,st],function(e,t){return e.extend({postRender:function(){function e(e){return 1===e.nodeType&&("BR"==e.nodeName||!!e.getAttribute("data-mce-bogus"))}var n=this,r=t.activeEditor;return n.on("select",function(t){var n=[],i,o=r.getBody();for(r.focus(),i=r.selection.getStart();i&&i!=o;)e(i)||n.push(i),i=i.parentNode;r.selection.select(n[n.length-1-t.index]),r.nodeChanged()}),r.on("nodeChange",function(t){for(var i=[],o=t.parents,a=o.length;a--;)if(1==o[a].nodeType&&!e(o[a])){var s=r.fire("ResolveName",{name:o[a].nodeName.toLowerCase(),target:o[a]});i.push({name:s.name})}n.data(i)}),n._super()}})}),r(St,[q],function(e){return e.extend({Defaults:{layout:"flex",align:"center",defaults:{flex:1}},renderHtml:function(){var e=this,t=e._layout,n=e.classPrefix;return e.addClass("formitem"),t.preRender(e),'<div id="'+e._id+'" class="'+e.classes()+'" hideFocus="1" tabIndex="-1">'+(e.settings.title?'<div id="'+e._id+'-title" class="'+n+'title">'+e.settings.title+"</div>":"")+'<div id="'+e._id+'-body" class="'+e.classes("body")+'">'+(e.settings.html||"")+t.renderHtml(e)+"</div>"+"</div>"}})}),r(Tt,[q,St],function(e,t){return e.extend({Defaults:{containerCls:"form",layout:"flex",direction:"column",align:"stretch",flex:1,padding:20,labelGap:30,spacing:10},preRender:function(){var e=this,n=e.items();n.each(function(n){var r,i=n.settings.label;i&&(r=new t({layout:"flex",autoResize:"overflow",defaults:{flex:1},items:[{type:"label",text:i,flex:0,forId:n._id}]}),r.type="formitem","undefined"==typeof n.settings.flex&&(n.settings.flex=1),e.replace(n,r),r.add(n))})},recalcLabels:function(){var e=this,t=0,n=[],r,i;if(e.settings.labelGapCalc!==!1)for(e.items().filter("formitem").each(function(e){var r=e.items()[0],i=r.getEl().clientWidth;t=i>t?i:t,n.push(r)}),i=e.settings.labelGap||0,r=n.length;r--;)n[r].settings.minWidth=t+i},visible:function(e){var t=this._super(e);return e===!0&&this._rendered&&this.recalcLabels(),t},submit:function(){var e=this.getParentCtrl(document.activeElement);return e&&e.blur(),this.fire("submit",{data:this.toJSON()})},postRender:function(){var e=this;e._super(),e.recalcLabels(),e.fromJSON(e.settings.data)}})}),r(Rt,[Tt],function(e){return e.extend({Defaults:{containerCls:"fieldset",layout:"flex",direction:"column",align:"stretch",flex:1,padding:"25 15 5 15",labelGap:30,spacing:10,border:1},renderHtml:function(){var e=this,t=e._layout,n=e.classPrefix;return e.preRender(),t.preRender(e),'<fieldset id="'+e._id+'" class="'+e.classes()+'" hideFocus="1" tabIndex="-1">'+(e.settings.title?'<legend id="'+e._id+'-title" class="'+n+'fieldset-title">'+e.settings.title+"</legend>":"")+'<div id="'+e._id+'-body" class="'+e.classes("body")+'">'+(e.settings.html||"")+t.renderHtml(e)+"</div>"+"</fieldset>"}})}),r(At,[Nt],function(e){return e.extend({init:function(e){var t=this,n=tinymce.activeEditor,r;e.spellcheck=!1,r=n.settings.file_browser_callback,r&&(e.icon="browse",e.onaction=function(){r(t.getEl("inp").id,t.getEl("inp").value,e.filetype,window)}),t._super(e)}})}),r(Bt,[gt],function(e){return e.extend({recalc:function(e){var t=e.layoutRect(),n=e.paddingBox();e.items().filter(":visible").each(function(e){e.layoutRect({x:n.left,y:n.top,w:t.innerW-n.right-n.left,h:t.innerH-n.top-n.bottom}),e.recalc&&e.recalc()})}})}),r(Dt,[gt],function(e){return e.extend({recalc:function(e){var t,n,r,i,o,a,s,l,c,u,d,f,p,h,m,g,v=[],y,b,C,x,w,_,N,E,k,S,T,R,A,B,D,L,M,H,P,O,I,F,W,z,V=Math.max,U=Math.min;for(r=e.items().filter(":visible"),i=e.layoutRect(),o=e._paddingBox,a=e.settings,f=a.direction,s=a.align,l=a.pack,c=a.spacing||0,("row-reversed"==f||"column-reverse"==f)&&(r=r.set(r.toArray().reverse()),f=f.split("-")[0]),"column"==f?(k="y",N="h",E="minH",S="maxH",R="innerH",T="top",A="bottom",B="deltaH",D="contentH",I="left",H="w",L="x",M="innerW",P="minW",O="maxW",F="right",W="deltaW",z="contentW"):(k="x",N="w",E="minW",S="maxW",R="innerW",T="left",A="right",B="deltaW",D="contentW",I="top",H="h",L="y",M="innerH",P="minH",O="maxH",F="bottom",W="deltaH",z="contentH"),d=i[R]-o[T]-o[T],_=u=0,t=0,n=r.length;n>t;t++)p=r[t],h=p.layoutRect(),m=p.settings,g=m.flex,d-=n-1>t?c:0,g>0&&(u+=g,h[S]&&v.push(p),h.flex=g),d-=h[E],y=o[I]+h[P]+o[F],y>_&&(_=y);if(x={},x[E]=0>d?i[E]-d+i[B]:i[R]-d+i[B],x[P]=_+i[W],x[D]=i[R]-d,x[z]=_,x.minW=U(x.minW,i.maxW),x.minH=U(x.minH,i.maxH),x.minW=V(x.minW,i.startMinWidth),x.minH=V(x.minH,i.startMinHeight),!i.autoResize||x.minW==i.minW&&x.minH==i.minH){for(C=d/u,t=0,n=v.length;n>t;t++)p=v[t],h=p.layoutRect(),b=h[S],y=h[E]+Math.ceil(h.flex*C),y>b?(d-=h[S]-h[E],u-=h.flex,h.flex=0,h.maxFlexSize=b):h.maxFlexSize=0;for(C=d/u,w=o[T],x={},0===u&&("end"==l?w=d+o[T]:"center"==l?(w=Math.round(i[R]/2-(i[R]-d)/2)+o[T],0>w&&(w=o[T])):"justify"==l&&(w=o[T],c=Math.floor(d/(r.length-1)))),x[L]=o[I],t=0,n=r.length;n>t;t++)p=r[t],h=p.layoutRect(),y=h.maxFlexSize||h[E],"center"===s?x[L]=Math.round(i[M]/2-h[H]/2):"stretch"===s?(x[H]=V(h[P]||0,i[M]-o[I]-o[F]),x[L]=o[I]):"end"===s&&(x[L]=i[M]-h[H]-o.top),h.flex>0&&(y+=Math.ceil(h.flex*C)),x[N]=y,x[k]=w,p.layoutRect(x),p.recalc&&p.recalc(),w+=y+c}else if(x.w=x.minW,x.h=x.minH,e.layoutRect(x),this.recalc(e),null===e._lastRect){var q=e.parent();q&&(q._lastRect=null,q.recalc())}}})}),r(Lt,[mt],function(e){return e.extend({Defaults:{containerClass:"flow-layout",controlClass:"flow-layout-item",endClass:"break"},recalc:function(e){e.items().filter(":visible").each(function(e){e.recalc&&e.recalc()})}})}),r(Mt,[V,yt,X,p,st,g],function(e,t,n,r,i,o){function a(e){function t(t){function n(e){return e.replace(/%(\w+)/g,"")}var r,i,o=e.dom,a="",l,c;return c=e.settings.preview_styles,c===!1?"":(c||(c="font-family font-size font-weight text-decoration text-transform color background-color border border-radius"),(t=e.formatter.get(t))?(t=t[0],r=t.block||t.inline||"span",i=o.create(r),s(t.styles,function(e,t){e=n(e),e&&o.setStyle(i,t,e)}),s(t.attributes,function(e,t){e=n(e),e&&o.setAttrib(i,t,e)}),s(t.classes,function(e){e=n(e),o.hasClass(i,e)||o.addClass(i,e)}),e.fire("PreviewFormats"),o.setStyles(i,{position:"absolute",left:-65535}),e.getBody().appendChild(i),l=o.getStyle(e.getBody(),"fontSize",!0),l=/px$/.test(l)?parseInt(l,10):0,s(c.split(" "),function(t){var n=o.getStyle(i,t,!0);if(!("background-color"==t&&/transparent|rgba\s*\([^)]+,\s*0\)/.test(n)&&(n=o.getStyle(e.getBody(),t,!0),"#ffffff"==o.toHex(n).toLowerCase())||"color"==t&&"#000000"==o.toHex(n).toLowerCase())){if("font-size"==t&&/em|%$/.test(n)){if(0===l)return;n=parseFloat(n,10)/(/%$/.test(n)?100:1),n=n*l+"px"}"border"==t&&n&&(a+="padding:0 2px;"),a+=t+":"+n+";"}}),e.fire("AfterPreviewFormats"),o.remove(i),a):void 0)}function r(t,n){return function(){var r=this;e.on("nodeChange",function(i){var o=e.formatter,a=null;s(i.parents,function(e){return s(t,function(t){return n?o.matchNode(e,n,{value:t.value})&&(a=t.value):o.matchNode(e,t.value)&&(a=t.value),a?!1:void 0}),a?!1:void 0}),r.value(a)})}}function i(e){e=e.split(";");for(var t=e.length;t--;)e[t]=e[t].split("=");return e}function o(){function n(e){var t=[];if(e)return s(e,function(e){var o={text:e.title,icon:e.icon};if(e.items)o.menu=n(e.items);else{var a=e.format||"custom"+r++;e.format||(e.name=a,i.push(e)),o.format=a}t.push(o)}),t}var r=0,i=[],o=[{title:"Headers",items:[{title:"Header 1",format:"h1"},{title:"Header 2",format:"h2"},{title:"Header 3",format:"h3"},{title:"Header 4",format:"h4"},{title:"Header 5",format:"h5"},{title:"Header 6",format:"h6"}]},{title:"Inline",items:[{title:"Bold",icon:"bold",format:"bold"},{title:"Italic",icon:"italic",format:"italic"},{title:"Underline",icon:"underline",format:"underline"},{title:"Strikethrough",icon:"strikethrough",format:"strikethrough"},{title:"Superscript",icon:"superscript",format:"superscript"},{title:"Subscript",icon:"subscript",format:"subscript"},{title:"Code",icon:"code",format:"code"}]},{title:"Blocks",items:[{title:"Paragraph",format:"p"},{title:"Blockquote",format:"blockquote"},{title:"Div",format:"div"},{title:"Pre",format:"pre"}]},{title:"Alignment",items:[{title:"Left",icon:"alignleft",format:"alignleft"},{title:"Center",icon:"aligncenter",format:"aligncenter"},{title:"Right",icon:"alignright",format:"alignright"},{title:"Justify",icon:"alignjustify",format:"alignjustify"}]}];e.on("init",function(){s(i,function(t){e.formatter.register(t.name,t)})});var a=n(e.settings.style_formats||o);return a={type:"menu",items:a,onPostRender:function(t){e.fire("renderFormatsMenu",{control:t.control})},itemDefaults:{preview:!0,textStyle:function(){return this.settings.format?t(this.settings.format):void 0},onPostRender:function(){var t=this,n=this.settings.format;n&&t.parent().on("show",function(){t.disabled(!e.formatter.canApply(n)),t.active(e.formatter.match(n))})},onclick:function(){this.settings.format&&f(this.settings.format)}}}}function a(){return e.undoManager?e.undoManager.hasUndo():!1}function l(){return e.undoManager?e.undoManager.hasRedo():!1}function c(){var t=this;t.disabled(!a()),e.on("Undo Redo AddUndo TypingUndo",function(){t.disabled(!a())})}function u(){var t=this;t.disabled(!l()),e.on("Undo Redo AddUndo TypingUndo",function(){t.disabled(!l())})}function d(){var t=this;e.on("VisualAid",function(e){t.active(e.hasVisual)}),t.active(e.hasVisual)}function f(t){t.control&&(t=t.control.value()),t&&e.execCommand("mceToggleFormat",!1,t)}var p;p=o(),s({bold:"Bold",italic:"Italic",underline:"Underline",strikethrough:"Strikethrough",subscript:"Subscript",superscript:"Superscript"},function(t,n){e.addButton(n,{tooltip:t,onPostRender:function(){var t=this;e.formatter?e.formatter.formatChanged(n,function(e){t.active(e)}):e.on("init",function(){e.formatter.formatChanged(n,function(e){t.active(e)})})},onclick:function(){f(n)}})}),s({outdent:["Decrease indent","Outdent"],indent:["Increase indent","Indent"],cut:["Cut","Cut"],copy:["Copy","Copy"],paste:["Paste","Paste"],help:["Help","mceHelp"],selectall:["Select all","SelectAll"],hr:["Insert horizontal rule","InsertHorizontalRule"],removeformat:["Clear formatting","RemoveFormat"],visualaid:["Visual aids","mceToggleVisualAid"],newdocument:["New document","mceNewDocument"]},function(t,n){e.addButton(n,{tooltip:t[0],cmd:t[1]})}),s({blockquote:["Toggle blockquote","mceBlockQuote"],numlist:["Numbered list","InsertOrderedList"],bullist:["Bullet list","InsertUnorderedList"],subscript:["Subscript","Subscript"],superscript:["Superscript","Superscript"],alignleft:["Align left","JustifyLeft"],aligncenter:["Align center","JustifyCenter"],alignright:["Align right","JustifyRight"],alignjustify:["Justify","JustifyFull"]},function(t,n){e.addButton(n,{tooltip:t[0],cmd:t[1],onPostRender:function(){var t=this;e.formatter?e.formatter.formatChanged(n,function(e){t.active(e)}):e.on("init",function(){e.formatter.formatChanged(n,function(e){t.active(e)})})}})}),e.addButton("undo",{tooltip:"Undo",onPostRender:c,cmd:"undo"}),e.addButton("redo",{tooltip:"Redo",onPostRender:u,cmd:"redo"}),e.addMenuItem("newdocument",{text:"New document",shortcut:"Ctrl+N",icon:"newdocument",cmd:"mceNewDocument"}),e.addMenuItem("undo",{text:"Undo",icon:"undo",shortcut:"Ctrl+Z",onPostRender:c,cmd:"undo"}),e.addMenuItem("redo",{text:"Redo",icon:"redo",shortcut:"Ctrl+Y",onPostRender:u,cmd:"redo"}),e.addMenuItem("visualaid",{text:"Visual aids",selectable:!0,onPostRender:d,cmd:"mceToggleVisualAid"}),s({cut:["Cut","Cut","Ctrl+X"],copy:["Copy","Copy","Ctrl+C"],paste:["Paste","Paste","Ctrl+V"],selectall:["Select all","SelectAll","Ctrl+A"],bold:["Bold","Bold","Ctrl+B"],italic:["Italic","Italic","Ctrl+I"],underline:["Underline","Underline"],strikethrough:["Strikethrough","Strikethrough"],subscript:["Subscript","Subscript"],superscript:["Superscript","Superscript"],removeformat:["Clear formatting","RemoveFormat"]},function(t,n){e.addMenuItem(n,{text:t[0],icon:n,shortcut:t[2],cmd:t[1]})}),e.on("mousedown",function(){n.hideAll()}),e.addButton("styleselect",{type:"menubutton",text:"Formats",menu:p}),e.addButton("formatselect",function(){var n=[],o=i(e.settings.block_formats||"Paragraph=p;Address=address;Pre=pre;Header 1=h1;Header 2=h2;Header 3=h3;Header 4=h4;Header 5=h5;Header 6=h6");return s(o,function(e){n.push({text:e[0],value:e[1],textStyle:function(){return t(e[1])}})}),{type:"listbox",text:{raw:o[0][0]},values:n,fixedWidth:!0,onselect:f,onPostRender:r(n)}}),e.addButton("fontselect",function(){var t="Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats",n=[],o=i(e.settings.font_formats||t);return s(o,function(e){n.push({text:{raw:e[0]},value:e[1],textStyle:-1==e[1].indexOf("dings")?"font-family:"+e[1]:""})}),{type:"listbox",text:"Font Family",tooltip:"Font Family",values:n,fixedWidth:!0,onPostRender:r(n,"fontname"),onselect:function(t){t.control.settings.value&&e.execCommand("FontName",!1,t.control.settings.value)}}}),e.addButton("fontsizeselect",function(){var t=[],n="8pt 10pt 12pt 14pt 18pt 24pt 36pt",i=e.settings.fontsize_formats||n;return s(i.split(" "),function(e){t.push({text:e,value:e})}),{type:"listbox",text:"Font Sizes",tooltip:"Font Sizes",values:t,fixedWidth:!0,onPostRender:r(t,"fontsize"),onclick:function(t){t.control.settings.value&&e.execCommand("FontSize",!1,t.control.settings.value)}}}),e.addMenuItem("formats",{text:"Formats",menu:p})}var s=r.each;i.on("AddEditor",function(e){a(e.editor)}),e.translate=function(e){return i.translate(e)},t.tooltips=!o.iOS}),r(Ht,[gt],function(e){return e.extend({recalc:function(e){var t=e.settings,n,r,i,o,a,s,l,c,u,d,f,p,h,m,g,v,y,b,C,x,w,_,N=[],E=[],k,S,T,R,A,B;for(t=e.settings,i=e.items().filter(":visible"),o=e.layoutRect(),r=t.columns||Math.ceil(Math.sqrt(i.length)),n=Math.ceil(i.length/r),y=t.spacingH||t.spacing||0,b=t.spacingV||t.spacing||0,C=t.alignH||t.align,x=t.alignV||t.align,g=e._paddingBox,C&&"string"==typeof C&&(C=[C]),x&&"string"==typeof x&&(x=[x]),d=0;r>d;d++)N.push(0);for(f=0;n>f;f++)E.push(0);for(f=0;n>f;f++)for(d=0;r>d&&(u=i[f*r+d],u);d++)c=u.layoutRect(),k=c.minW,S=c.minH,N[d]=k>N[d]?k:N[d],E[f]=S>E[f]?S:E[f];for(A=o.innerW-g.left-g.right,w=0,d=0;r>d;d++)w+=N[d]+(d>0?y:0),A-=(d>0?y:0)+N[d];for(B=o.innerH-g.top-g.bottom,_=0,f=0;n>f;f++)_+=E[f]+(f>0?b:0),B-=(f>0?b:0)+E[f];if(w+=g.left+g.right,_+=g.top+g.bottom,l={},l.minW=w+(o.w-o.innerW),l.minH=_+(o.h-o.innerH),l.contentW=l.minW-o.deltaW,l.contentH=l.minH-o.deltaH,l.minW=Math.min(l.minW,o.maxW),l.minH=Math.min(l.minH,o.maxH),l.minW=Math.max(l.minW,o.startMinWidth),l.minH=Math.max(l.minH,o.startMinHeight),!o.autoResize||l.minW==o.minW&&l.minH==o.minH){o.autoResize&&(l=e.layoutRect(l),l.contentW=l.minW-o.deltaW,l.contentH=l.minH-o.deltaH);var D;D="start"==t.packV?0:B>0?Math.floor(B/n):0;var L=0,M=t.flexWidths;if(M)for(d=0;d<M.length;d++)L+=M[d];else L=r;var H=A/L;for(d=0;r>d;d++)N[d]+=M?Math.ceil(M[d]*H):H;for(h=g.top,f=0;n>f;f++){for(p=g.left,s=E[f]+D,d=0;r>d&&(u=i[f*r+d],u);d++)m=u.settings,c=u.layoutRect(),a=N[d],T=R=0,c.x=p,c.y=h,v=m.alignH||(C?C[d]||C[0]:null),"center"==v?c.x=p+a/2-c.w/2:"right"==v?c.x=p+a-c.w:"stretch"==v&&(c.w=a),v=m.alignV||(x?x[d]||x[0]:null),"center"==v?c.y=h+s/2-c.h/2:"bottom"==v?c.y=h+s-c.h:"stretch"==v&&(c.h=s),u.layoutRect(c),p+=a+y,u.recalc&&u.recalc();
+h+=s+b}}else if(l.w=l.minW,l.h=l.minH,e.layoutRect(l),this.recalc(e),null===e._lastRect){var P=e.parent();P&&(P._lastRect=null,P.recalc())}}})}),r(Pt,[yt],function(e){return e.extend({renderHtml:function(){var e=this;return e.addClass("iframe"),e.canFocus=!1,'<iframe id="'+e._id+'" class="'+e.classes()+'" tabindex="-1" src="'+(e.settings.url||"javascript:''")+'" frameborder="0"></iframe>'},src:function(e){this.getEl().src=e},html:function(e,t){var n=this,r=this.getEl().contentWindow.document.body;return r?(r.innerHTML=e,t&&t()):setTimeout(function(){n.html(e)},0),this}})}),r(Ot,[yt],function(e){return e.extend({init:function(e){var t=this;t._super(e),t.addClass("widget"),t.addClass("label"),t.canFocus=!1,e.multiline&&t.addClass("autoscroll"),e.strong&&t.addClass("strong")},initLayoutRect:function(){var e=this,t=e._super();return e.settings.multiline&&(e.getEl().offsetWidth>t.maxW&&(t.minW=t.maxW,e.addClass("multiline")),e.getEl().style.width=t.minW+"px",t.startMinH=t.h=t.minH=Math.min(t.maxH,e.getEl().offsetHeight)),t},disabled:function(e){var t=this,n;return e!==n&&(t.toggleClass("label-disabled",e),t._rendered&&(t.getEl()[0].className=t.classes())),t._super(e)},repaint:function(){var e=this;return e.settings.multiline||(e.getEl().style.lineHeight=e.layoutRect().h+"px"),e._super()},text:function(e){var t=this;return t._rendered&&e&&this.innerHtml(t.encode(e)),t._super(e)},renderHtml:function(){var e=this,t=e.settings.forId;return'<label id="'+e._id+'" class="'+e.classes()+'"'+(t?' for="'+t:"")+'">'+e.encode(e._text)+"</label>"}})}),r(It,[q,J],function(e,t){return e.extend({Defaults:{role:"toolbar",layout:"flow"},init:function(e){var t=this;t._super(e),t.addClass("toolbar")},postRender:function(){var e=this;return e.items().addClass("toolbar-item"),e.keyNav=new t({root:e,enableLeftRight:!0}),e._super()}})}),r(Ft,[It],function(e){return e.extend({Defaults:{role:"menubar",containerCls:"menubar",defaults:{type:"menubutton"}}})}),r(Wt,[bt,U,Ft],function(e,t,n){function r(e,t){for(;e;){if(t===e)return!0;e=e.parentNode}return!1}var i=e.extend({init:function(e){var t=this;t._renderOpen=!0,t._super(e),t.addClass("menubtn"),e.fixedWidth&&t.addClass("fixed-width"),t.aria("haspopup",!0),t.hasPopup=!0},showMenu:function(){var e=this,n=e.settings,r;return e.menu&&e.menu.visible()?e.hideMenu():(e.menu||(r=n.menu||[],r.length?r={type:"menu",items:r}:r.type=r.type||"menu",e.menu=t.create(r).parent(e).renderTo(e.getContainerElm()),e.fire("createmenu"),e.menu.reflow(),e.menu.on("cancel",function(t){t.control===e.menu&&e.focus()}),e.menu.on("show hide",function(t){t.control==e.menu&&e.activeMenu("show"==t.type)}).fire("show"),e.aria("expanded",!0)),e.menu.show(),e.menu.layoutRect({w:e.layoutRect().w}),e.menu.moveRel(e.getEl(),["bl-tl","tl-bl"]),void 0)},hideMenu:function(){var e=this;e.menu&&(e.menu.items().each(function(e){e.hideMenu&&e.hideMenu()}),e.menu.hide(),e.aria("expanded",!1))},activeMenu:function(e){this.toggleClass("active",e)},renderHtml:function(){var e=this,t=e._id,r=e.classPrefix,i=e.settings.icon?r+"ico "+r+"i-"+e.settings.icon:"";return e.aria("role",e.parent()instanceof n?"menuitem":"button"),'<div id="'+t+'" class="'+e.classes()+'" tabindex="-1">'+'<button id="'+t+'-open" role="presentation" type="button" tabindex="-1">'+(i?'<i class="'+i+'"></i>':"")+"<span>"+(e._text?(i?" ":"")+e.encode(e._text):"")+"</span>"+' <i class="'+r+'caret"></i>'+"</button>"+"</div>"},postRender:function(){var e=this;return e.on("click",function(t){t.control===e&&r(t.target,e.getEl())&&(e.showMenu(),t.keyboard&&e.menu.items()[0].focus())}),e.on("mouseenter",function(t){var n=t.control,r=e.parent(),o;n&&r&&n instanceof i&&n.parent()==r&&(r.items().filter("MenuButton").each(function(e){e.hideMenu&&e!=n&&(e.menu&&e.menu.visible()&&(o=!0),e.hideMenu())}),o&&(n.focus(),n.showMenu()))}),e._super()},text:function(e){var t=this,n,r;if(t._rendered)for(r=t.getEl("open").getElementsByTagName("span"),n=0;n<r.length;n++)r[n].innerHTML=t.encode(e);return this._super(e)},remove:function(){this._super(),this.menu&&this.menu.remove()}});return i}),r(zt,[Wt],function(e){return e.extend({init:function(e){var t=this,n,r,i,o,a;if(t._values=n=e.values,n){for(r=0;r<n.length;r++)i=n[r].selected||e.value===n[r].value,i&&(o=o||n[r].text,t._value=n[r].value);e.menu=n}e.text=e.text||o||n[0].text,t._super(e),t.addClass("listbox"),t.on("select",function(n){var r=n.control;a&&(n.lastControl=a),e.multiple?r.active(!r.active()):t.value(n.control.settings.value),a=r})},value:function(e){function t(e,n){e.items().each(function(e){r=e.value()===n,r&&(i=i||e.text()),e.active(r),e.menu&&t(e.menu,n)})}var n=this,r,i,o,a;if("undefined"!=typeof e){if(n.menu)t(n.menu,e);else for(o=n.settings.menu,a=0;a<o.length;a++)r=o[a].value==e,r&&(i=i||o[a].text),o[a].active=r;n.text(i||this.settings.text)}return n._super(e)}})}),r(Vt,[yt,U],function(e,t){return e.extend({Defaults:{border:0,role:"menuitem"},init:function(e){var t=this;t.hasPopup=!0,t._super(e),e=t.settings,t.addClass("menu-item"),e.menu&&t.addClass("menu-item-expand"),e.preview&&t.addClass("menu-item-preview"),("-"===t._text||"|"===t._text)&&(t.addClass("menu-item-sep"),t.aria("role","separator"),t.canFocus=!1,t._text="-"),e.selectable&&(t.aria("role","menuitemcheckbox"),t.aria("checked",!0),t.addClass("menu-item-checkbox"),e.icon="selected"),t.on("mousedown",function(e){e.preventDefault()}),t.on("mouseenter click",function(n){n.control===t&&(e.menu||"click"!==n.type?(t.showMenu(),n.keyboard&&setTimeout(function(){t.menu.items()[0].focus()},0)):(t.parent().hideAll(),t.fire("cancel"),t.fire("select")))}),e.menu&&t.aria("haspopup",!0)},hasMenus:function(){return!!this.settings.menu},showMenu:function(){var e=this,n=e.settings,r,i=e.parent();if(i.items().each(function(t){t!==e&&t.hideMenu()}),n.menu){r=e.menu,r?r.show():(r=n.menu,r.length?r={type:"menu",items:r}:r.type=r.type||"menu",i.settings.itemDefaults&&(r.itemDefaults=i.settings.itemDefaults),r=e.menu=t.create(r).parent(e).renderTo(e.getContainerElm()),r.reflow(),r.fire("show"),r.on("cancel",function(){e.focus()}),r.on("hide",function(t){t.control===r&&e.removeClass("selected")})),r._parentMenu=i,r.addClass("menu-sub");var o=r.testMoveRel(e.getEl(),["tr-tl","br-bl","tl-tr","bl-br"]);r.moveRel(e.getEl(),o),o="menu-sub-"+o,r.removeClass(r._lastRel),r.addClass(o),r._lastRel=o,e.addClass("selected"),e.aria("expanded",!0)}},hideMenu:function(){var e=this;return e.menu&&(e.menu.items().each(function(e){e.hideMenu&&e.hideMenu()}),e.menu.hide(),e.aria("expanded",!1)),e},renderHtml:function(){var e=this,t=e._id,n=e.settings,r=e.classPrefix,i=e.encode(e._text),o=e.settings.icon;return o&&e.parent().addClass("menu-has-icons"),o=r+"ico "+r+"i-"+(e.settings.icon||"none"),'<div id="'+t+'" class="'+e.classes()+'" tabindex="-1">'+("-"!==i?'<i class="'+o+'"></i>&nbsp;':"")+("-"!==i?'<span id="'+t+'-text" class="'+r+'text">'+i+"</span>":"")+(n.shortcut?'<div id="'+t+'-shortcut" class="'+r+'menu-shortcut">'+n.shortcut+"</div>":"")+(n.menu?'<div class="'+r+'caret"></div>':"")+"</div>"},postRender:function(){var e=this,t=e.settings,n=t.textStyle;if("function"==typeof n&&(n=n.call(this)),n){var r=e.getEl("text");r&&r.setAttribute("style",n)}return e._super()},remove:function(){this._super(),this.menu&&this.menu.remove()}})}),r(Ut,[X,J,Vt,p],function(e,t,n,r){var i=e.extend({Defaults:{defaultType:"menuitem",border:1,layout:"stack",role:"menu"},init:function(e){var i=this;if(e.autohide=!0,e.constrainToViewport=!0,e.itemDefaults)for(var o=e.items,a=o.length;a--;)o[a]=r.extend({},e.itemDefaults,o[a]);i._super(e),i.addClass("menu"),i.keyNav=new t({root:i,enableUpDown:!0,enableLeftRight:!0,leftAction:function(){i.parent()instanceof n&&i.keyNav.cancel()},onCancel:function(){i.fire("cancel",{},!1),i.hide()}})},repaint:function(){return this.toggleClass("menu-align",!0),this._super(),this.getEl().style.height="",this.getEl("body").style.height="",this},cancel:function(){var e=this;e.hideAll(),e.fire("cancel"),e.fire("select")},hideAll:function(){var e=this;return this.find("menuitem").exec("hideMenu"),e._super()},preRender:function(){var e=this;return e.items().each(function(t){var n=t.settings;return n.icon||n.selectable?(e._hasIcons=!0,!1):void 0}),e._super()}});return i}),r(qt,[xt],function(e){return e.extend({Defaults:{classes:"radio",role:"radio"}})}),r(jt,[yt,j],function(e,t){return e.extend({renderHtml:function(){var e=this,t=e.classPrefix;return e.addClass("resizehandle"),"both"==e.settings.direction&&e.addClass("resizehandle-both"),e.canFocus=!1,'<div id="'+e._id+'" class="'+e.classes()+'">'+'<i class="'+t+"ico "+t+'i-resize"></i>'+"</div>"},postRender:function(){var e=this;e._super(),e.resizeDragHelper=new t(this._id,{start:function(){e.fire("ResizeStart")},drag:function(t){"both"!=e.settings.direction&&(t.deltaX=0),e.fire("Resize",t)},end:function(){e.fire("ResizeEnd")}})}})}),r($t,[yt],function(e){return e.extend({renderHtml:function(){var e=this;return e.addClass("spacer"),e.canFocus=!1,'<div id="'+e._id+'" class="'+e.classes()+'"></div>'}})}),r(Kt,[Wt,v],function(e,t){var n=t.DOM;return e.extend({Defaults:{classes:"widget btn splitbtn",role:"splitbutton"},repaint:function(){var e=this,t=e.getEl(),r=e.layoutRect(),i,o,a;return e._super(),i=t.firstChild,o=t.lastChild,n.css(i,{width:r.w-o.offsetWidth,height:r.h-2}),n.css(o,{height:r.h-2}),a=i.firstChild.style,a.width=a.height="100%",a=o.firstChild.style,a.width=a.height="100%",e},activeMenu:function(e){var t=this;n.toggleClass(t.getEl().lastChild,t.classPrefix+"active",e)},renderHtml:function(){var e=this,t=e._id,n=e.classPrefix,r=e.settings.icon?n+"ico "+n+"i-"+e.settings.icon:"";return'<div id="'+t+'" class="'+e.classes()+'">'+'<button type="button" hidefocus tabindex="-1">'+(r?'<i class="'+r+'"></i>':"")+(e._text?(r?" ":"")+e._text:"")+"</button>"+'<button type="button" class="'+n+'open" hidefocus tabindex="-1">'+(e._menuBtnText?(r?" ":"")+e._menuBtnText:"")+' <i class="'+n+'caret"></i>'+"</button>"+"</div>"},postRender:function(){var e=this,t=e.settings.onclick;return e.on("click",function(e){e.control!=this||n.getParent(e.target,"."+this.classPrefix+"open")||(e.stopImmediatePropagation(),t.call(this,e))}),delete e.settings.onclick,e._super()}})}),r(Gt,[Lt],function(e){return e.extend({Defaults:{containerClass:"stack-layout",controlClass:"stack-layout-item",endClass:"break"}})}),r(Yt,[K,z],function(e,t){"use stict";return e.extend({lastIdx:0,Defaults:{layout:"absolute",defaults:{type:"panel"}},activateTab:function(e){this.activeTabId&&t.removeClass(this.getEl(this.activeTabId),this.classPrefix+"active"),this.activeTabId="t"+e,t.addClass(this.getEl("t"+e),this.classPrefix+"active"),e!=this.lastIdx&&(this.items()[this.lastIdx].hide(),this.lastIdx=e),this.items()[e].show().fire("showtab"),this.reflow()},renderHtml:function(){var e=this,t=e._layout,n="",r=e.classPrefix;return e.preRender(),t.preRender(e),e.items().each(function(t,i){n+='<div id="'+e._id+"-t"+i+'" class="'+r+'tab" unselectable="on">'+e.encode(t.settings.title)+"</div>"}),'<div id="'+e._id+'" class="'+e.classes()+'" hideFocus="1" tabIndex="-1">'+'<div id="'+e._id+'-head" class="'+r+'tabs">'+n+"</div>"+'<div id="'+e._id+'-body" class="'+e.classes("body")+'">'+t.renderHtml(e)+"</div>"+"</div>"},postRender:function(){var e=this;e._super(),e.settings.activeTab=e.settings.activeTab||0,e.activateTab(e.settings.activeTab),this.on("click",function(t){var n=t.target.parentNode;if(t.target.parentNode.id==e._id+"-head")for(var r=n.childNodes.length;r--;)n.childNodes[r]==t.target&&e.activateTab(r)})},initLayoutRect:function(){var e=this,t,n,r;n=r=0,e.items().each(function(t,i){n=Math.max(n,t.layoutRect().minW),r=Math.max(r,t.layoutRect().minH),e.settings.activeTab!=i&&t.hide()}),e.items().each(function(e){e.settings.x=0,e.settings.y=0,e.settings.w=n,e.settings.h=r,e.layoutRect({x:0,y:0,w:n,h:r})});var i=e.getEl("head").offsetHeight;return e.settings.minWidth=n,e.settings.minHeight=r+i,t=e._super(),t.deltaH+=e.getEl("head").offsetHeight,t.innerH=t.h-t.deltaH,t}})}),r(Xt,[yt,z],function(e,t){return e.extend({init:function(e){var t=this;t._super(e),t._value=e.value||"",t.addClass("textbox"),e.multiline?t.addClass("multiline"):t.on("keydown",function(e){13==e.keyCode&&t.parents().reverse().each(function(t){return e.preventDefault(),t.submit?(t.submit(),!1):void 0})})},value:function(e){var t=this;return"undefined"!=typeof e?(t._value=e,t._rendered&&(t.getEl().value=e),t):t._rendered?t.getEl().value:t._value},repaint:function(){var e=this,t,n,r,i=0,o=0,a;t=e.getEl().style,n=e._layoutRect,a=e._lastRepaintRect||{};var s=document;return!e.settings.multiline&&s.all&&(!s.documentMode||s.documentMode<=8)&&(t.lineHeight=n.h-o+"px"),r=e._borderBox,i=r.left+r.right+8,o=r.top+r.bottom+(e.settings.multiline?8:0),n.x!==a.x&&(t.left=n.x+"px",a.x=n.x),n.y!==a.y&&(t.top=n.y+"px",a.y=n.y),n.w!==a.w&&(t.width=n.w-i+"px",a.w=n.w),n.h!==a.h&&(t.height=n.h-o+"px",a.h=n.h),e._lastRepaintRect=a,e.fire("repaint",{},!1),e},renderHtml:function(){var e=this,t=e._id,n=e.settings,r=e.encode(e._value,!1),i="";return"spellcheck"in n&&(i+=' spellcheck="'+n.spellcheck+'"'),n.maxLength&&(i+=' maxlength="'+n.maxLength+'"'),n.size&&(i+=' size="'+n.size+'"'),n.subtype&&(i+=' type="'+n.subtype+'"'),n.multiline?'<textarea id="'+t+'" class="'+e.classes()+'" '+(n.rows?' rows="'+n.rows+'"':"")+' hidefocus="true"'+i+">"+r+"</textarea>":'<input id="'+t+'" class="'+e.classes()+'" value="'+r+'" hidefocus="true"'+i+">"},postRender:function(){var e=this;return t.on(e.getEl(),"change",function(t){e.fire("change",t)}),e._super()}})}),r(Jt,[z],function(e){return function(t){var n=this,r;n.show=function(i){return n.hide(),r=!0,window.setTimeout(function(){r&&t.appendChild(e.createFragment('<div class="mce-throbber"></div>'))},i||0),n},n.hide=function(){var e=t.lastChild;return e&&-1!=e.className.indexOf("throbber")&&e.parentNode.removeChild(e),r=!1,n}}}),a([l,c,u,d,f,p,h,m,g,v,y,b,C,x,w,_,N,E,k,S,T,R,A,B,D,L,M,H,P,O,I,F,W,z,V,U,q,j,$,K,G,Y,X,J,Q,Z,et,tt,nt,rt,it,ot,at,st,lt,ct,ut,dt,ft,pt,ht,mt,gt,vt,yt,bt,Ct,xt,wt,_t,Nt,Et,kt,St,Tt,Rt,At,Bt,Dt,Lt,Mt,Ht,Pt,Ot,It,Ft,Wt,zt,Vt,Ut,qt,jt,$t,Kt,Gt,Yt,Xt,Jt])}(this); \ No newline at end of file
diff --git a/lib/prado/framework/Web/Services/TFeedService.php b/lib/prado/framework/Web/Services/TFeedService.php
new file mode 100644
index 0000000..dc9c064
--- /dev/null
+++ b/lib/prado/framework/Web/Services/TFeedService.php
@@ -0,0 +1,187 @@
+<?php
+/**
+ * TFeedService and TFeed class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @author Knut Urdalen <knut.urdalen@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @version $Id$
+ * @package System.Web.Services
+ */
+
+/**
+ * TFeedService class
+ *
+ * TFeedService provides to end-users feed content.
+ *
+ * TFeedService manages a set of feeds. The service parameter, referring
+ * to the ID of the feed, specifies which feed content to be provided to end-users.
+ *
+ * To use TFeedService, configure it in application configuration as follows,
+ * <code>
+ * <service id="feed" class="System.Web.Services.TFeedService">
+ * <feed id="ch1" class="Path.To.FeedClass1" .../>
+ * <feed id="ch2" class="Path.To.FeedClass2" .../>
+ * <feed id="ch3" class="Path.To.FeedClass3" .../>
+ * </service>
+ * </code>
+ * where each &lt;feed&gt; element specifies a feed identified by its "id" value (case-sensitive).
+ *
+ * PHP configuration style:
+ * <code>
+ * array(
+ * 'feed' => array(
+ * 'ch1' => array(
+ * 'class' => 'Path.To.FeedClass1',
+ * 'properties' => array(
+ * ...
+ * ),
+ * ),
+ * )
+ * </code>
+ *
+ * The class attribute indicates which PHP class will provide the actual feed
+ * content. Note, the class must implement {@link IFeedContentProvider} interface.
+ * Other initial properties for the feed class may also be specified in the
+ * corresponding &lt;feed&gt; element.
+ *
+ * To retrieve the feed content identified by "ch2", use the URL
+ * <code>/path/to/index.php?feed=ch2</code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @author Knut Urdalen <knut.urdalen@gmail.com>
+ * @author Carl G. Mathisen <carlgmathisen@gmail.com>
+ * @package System.Web.Services
+ * @since 3.1
+ */
+class TFeedService extends TService
+{
+ private $_feeds=array();
+
+ /**
+ * Initializes this module.
+ * This method is required by the IModule interface.
+ * @param mixed configuration for this module, can be null
+ */
+ public function init($config)
+ {
+ if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ {
+ if(is_array($config))
+ {
+ foreach($config as $id => $feed)
+ $this->_feeds[$id] = $feed;
+ }
+ }
+ else
+ {
+ foreach($config->getElementsByTagName('feed') as $feed)
+ {
+ if(($id=$feed->getAttributes()->remove('id'))!==null)
+ $this->_feeds[$id]=$feed;
+ else
+ throw new TConfigurationException('feedservice_id_required');
+ }
+ }
+ }
+
+ /**
+ * @return string the requested feed path
+ */
+ protected function determineRequestedFeedPath()
+ {
+ return $this->getRequest()->getServiceParameter();
+ }
+
+ /**
+ * Runs the service.
+ * This method is invoked by application automatically.
+ */
+ public function run()
+ {
+ $id=$this->getRequest()->getServiceParameter();
+ if(isset($this->_feeds[$id]))
+ {
+ $feedConfig=$this->_feeds[$id];
+ $properties = array();
+ $feed = null;
+ if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ {
+ if(isset($feedConfig['class']))
+ {
+ $feed=Prado::createComponent($feedConfig['class']);
+ if($service instanceof IFeedContentProvider)
+ $properties=isset($feedConfig['properties'])?$feedConfig['properties']:array();
+ else
+ throw new TConfigurationException('jsonservice_response_type_invalid',$id);
+ }
+ else
+ throw new TConfigurationException('jsonservice_class_required',$id);
+ }
+ else
+ {
+ $properties=$feedConfig->getAttributes();
+ if(($class=$properties->remove('class'))!==null)
+ {
+ $feed=Prado::createComponent($class);
+ if(!($feed instanceof IFeedContentProvider))
+ throw new TConfigurationException('feedservice_feedtype_invalid',$id);
+ }
+ else
+ throw new TConfigurationException('feedservice_class_required',$id);
+ }
+
+ // init feed properties
+ foreach($properties as $name=>$value)
+ $feed->setSubproperty($name,$value);
+ $feed->init($feedConfig);
+
+ $content=$feed->getFeedContent();
+ //$this->getResponse()->setContentType('application/rss+xml');
+ $this->getResponse()->setContentType($feed->getContentType());
+ $this->getResponse()->write($content);
+ }
+ else
+ throw new THttpException(404,'feedservice_feed_unknown',$id);
+ }
+}
+
+/**
+ * IFeedContentProvider interface.
+ *
+ * IFeedContentProvider interface must be implemented by a feed class who
+ * provides feed content.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @author Knut Urdalen <knut.urdalen@gmail.com>
+ * @package System.Web.Services
+ * @since 3.1
+ */
+interface IFeedContentProvider
+{
+ /**
+ * Initializes the feed content provider.
+ * This method is invoked (before {@link getFeedContent})
+ * when the feed provider is requested by a user.
+ * @param TXmlElement configurations specified within the &lt;feed&gt; element
+ * corresponding to this feed provider when configuring {@link TFeedService}.
+ */
+ public function init($config);
+ /**
+ * @return string feed content in proper XML format
+ */
+ public function getFeedContent();
+ /**
+ * Sets the content type of the feed content to be sent.
+ * Some examples are:
+ * RSS 1.0 feed: application/rdf+xml
+ * RSS 2.0 feed: application/rss+xml or application/xml or text/xml
+ * ATOM feed: application/atom+xml
+ * @return string the content type for the feed content.
+ * @since 3.1.1
+ */
+ public function getContentType();
+}
+
diff --git a/lib/prado/framework/Web/Services/TJsonService.php b/lib/prado/framework/Web/Services/TJsonService.php
new file mode 100644
index 0000000..d17b330
--- /dev/null
+++ b/lib/prado/framework/Web/Services/TJsonService.php
@@ -0,0 +1,209 @@
+<?php
+/**
+ * TJsonService and TJsonResponse class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.Services
+ */
+
+/**
+ * TJsonService class provides to end-users javascript content response in
+ * JSON format.
+ *
+ * TJsonService manages a set of {@link TJsonResponse}, each
+ * representing specific response with javascript content.
+ * The service parameter, referring to the ID of the service, specifies
+ * which javascript content to be provided to end-users.
+ *
+ * To use TJsonService, configure it in application configuration as follows,
+ * <code>
+ * <service id="json" class="System.Web.Services.TJsonService">
+ * <json id="get_article" class="Path.To.JsonResponseClass1" .../>
+ * <json id="register_rating" class="Path.To.JsonResponseClass2" .../>
+ * </service>
+ * </code>
+ * where each JSON response is specified via a &lt;json&gt; element.
+ * Initial property values can be configured in a &lt;json&gt; element.
+ *
+ *
+ * PHP configuration style:
+ * <code>
+ * 'services' => array(
+ * 'get_article' => array(
+ * 'class' => 'Path.To.JsonResponseClass1',
+ * 'properties' => array(
+ * ...
+ * )
+ * )
+ * )
+ * </code>
+ *
+ * To retrieve the JSON content provided by "get_article", use the URL
+ * <code>index.php?json=get_article</code>
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @author Carl G. Mathisen <carlgmathisen@gmail.com>
+ * @package System.Web.Services
+ * @since 3.1
+ */
+class TJsonService extends TService
+{
+ /**
+ * @var array registered services
+ */
+ private $_services=array();
+
+ /**
+ * Initializes this module.
+ * This method is required by the IModule interface.
+ * @param mixed configuration for this module, can be null
+ */
+ public function init($xml)
+ {
+ $this->loadJsonServices($xml);
+ }
+
+ /**
+ * Load the service definitions.
+ * @param mixed configuration for this module, can be null
+ */
+ protected function loadJsonServices($config)
+ {
+ if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ {
+ if(is_array($config))
+ {
+ foreach($config['json'] as $id => $json)
+ $this->_services[$id] = $json;
+ }
+ }
+ else
+ {
+ foreach($config->getElementsByTagName('json') as $json)
+ {
+ if(($id=$json->getAttribute('id'))!==null)
+ $this->_services[$id]=$json;
+ else
+ throw new TConfigurationException('jsonservice_id_required');
+ }
+ }
+ }
+
+ /**
+ * Runs the service.
+ * This method is invoked by application automatically.
+ */
+ public function run()
+ {
+ $id=$this->getRequest()->getServiceParameter();
+ if(isset($this->_services[$id]))
+ {
+ $serviceConfig=$this->_services[$id];
+ if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ {
+ if(isset($serviceConfig['class']))
+ {
+ $service=Prado::createComponent($serviceConfig['class']);
+ if($service instanceof TJsonResponse)
+ {
+ $properties = isset($serviceConfig['properties'])?$serviceConfig['properties']:array();
+ $this->createJsonResponse($service,$properties,$serviceConfig);
+ }
+ else
+ throw new TConfigurationException('jsonservice_response_type_invalid',$id);
+ }
+ else
+ throw new TConfigurationException('jsonservice_class_required',$id);
+ }
+ else
+ {
+ $properties=$serviceConfig->getAttributes();
+ if(($class=$properties->remove('class'))!==null)
+ {
+ $service=Prado::createComponent($class);
+ if($service instanceof TJsonResponse)
+ $this->createJsonResponse($service,$properties,$serviceConfig);
+ else
+ throw new TConfigurationException('jsonservice_response_type_invalid',$id);
+ }
+ else
+ throw new TConfigurationException('jsonservice_class_required',$id);
+ }
+ }
+ else
+ throw new THttpException(404,'jsonservice_provider_unknown',$id);
+ }
+
+ /**
+ * Renders content provided by TJsonResponse::getJsonContent() as
+ * javascript in JSON format.
+ */
+ protected function createJsonResponse($service,$properties,$config)
+ {
+ // init service properties
+ foreach($properties as $name=>$value)
+ $service->setSubproperty($name,$value);
+ $service->init($config);
+
+ //send content if not null
+ if(($content=$service->getJsonContent())!==null)
+ {
+ $response = $this->getResponse();
+ $response->setContentType('application/json');
+ $response->setCharset('UTF-8');
+ //send content
+ $response->write(TJavaScript::jsonEncode($content));
+ }
+ }
+}
+
+/**
+ * TJsonResponse Class
+ *
+ * TJsonResponse is the base class for all JSON response provider classes.
+ *
+ * Derived classes must implement {@link getJsonContent()} to return
+ * an object or literals to be converted to JSON format. The response
+ * will be empty if the returned content is null.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.Services
+ * @since 3.1
+ */
+abstract class TJsonResponse extends TApplicationComponent
+{
+ private $_id='';
+
+ /**
+ * Initializes the feed.
+ * @param TXmlElement configurations specified in {@link TJsonService}.
+ */
+ public function init($config)
+ {
+ }
+
+ /**
+ * @return string ID of this response
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * @param string ID of this response
+ */
+ public function setID($value)
+ {
+ $this->_id=$value;
+ }
+
+ /**
+ * @return object json response content, null to suppress output.
+ */
+ abstract public function getJsonContent();
+}
+
diff --git a/lib/prado/framework/Web/Services/TPageService.php b/lib/prado/framework/Web/Services/TPageService.php
new file mode 100644
index 0000000..4a422c4
--- /dev/null
+++ b/lib/prado/framework/Web/Services/TPageService.php
@@ -0,0 +1,890 @@
+<?php
+/**
+ * TPageService class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.Services
+ */
+
+/**
+ * Include classes to be used by page service
+ */
+Prado::using('System.Web.UI.TPage');
+Prado::using('System.Web.UI.TTemplateManager');
+Prado::using('System.Web.UI.TThemeManager');
+
+/**
+ * TPageService class.
+ *
+ * TPageService implements the service for serving user page requests.
+ *
+ * Pages that are available to client users are stored under a directory specified by
+ * {@link setBasePath BasePath}. The directory may contain subdirectories.
+ * Pages serving for a similar goal are usually placed under the same directory.
+ * A directory may contain a configuration file <b>config.xml</b> whose content
+ * is similar to that of application configuration file.
+ *
+ * A page is requested via page path, which is a dot-connected directory names
+ * appended by the page name. Assume '<BasePath>/Users/Admin' is the directory
+ * containing the page 'Update'. Then the page can be requested via 'Users.Admin.Update'.
+ * By default, the {@link setBasePath BasePath} of the page service is the "pages"
+ * directory under the application base path. You may change this default
+ * by setting {@link setBasePath BasePath} with a different path you prefer.
+ *
+ * Page name refers to the file name (without extension) of the page template.
+ * In order to differentiate from the common control template files, the extension
+ * name of the page template files must be '.page'. If there is a PHP file with
+ * the same page name under the same directory as the template file, that file
+ * will be considered as the page class file and the file name is the page class name.
+ * If such a file is not found, the page class is assumed as {@link TPage}.
+ *
+ * Modules can be configured and loaded in page directory configurations.
+ * Configuration of a module in a subdirectory will overwrite its parent
+ * directory's configuration, if both configurations refer to the same module.
+ *
+ * By default, TPageService will automatically load two modules:
+ * - {@link TTemplateManager} : manages page and control templates
+ * - {@link TThemeManager} : manages themes used in a Prado application
+ *
+ * In page directory configurations, static authorization rules can also be specified,
+ * which governs who and which roles can access particular pages.
+ * Refer to {@link TAuthorizationRule} for more details about authorization rules.
+ * Page authorization rules can be configured within an <authorization> tag in
+ * each page directory configuration as follows,
+ * <authorization>
+ * <deny pages="Update" users="?" />
+ * <allow pages="Admin" roles="administrator" />
+ * <deny pages="Admin" users="*" />
+ * </authorization>
+ * where the 'pages' attribute may be filled with a sequence of comma-separated
+ * page IDs. If 'pages' attribute does not appear in a rule, the rule will be
+ * applied to all pages in this directory and all subdirectories (recursively).
+ * Application of authorization rules are in a bottom-up fashion, starting from
+ * the directory containing the requested page up to all parent directories.
+ * The first matching rule will be used. The last rule always allows all users
+ * accessing to any resources.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @author Carl G. Mathisen <carlgmathisen@gmail.com>
+ * @package System.Web.Services
+ * @since 3.0
+ */
+class TPageService extends TService
+{
+ /**
+ * Configuration file name
+ */
+ const CONFIG_FILE_XML='config.xml';
+ /**
+ * Configuration file name
+ */
+ const CONFIG_FILE_PHP='config.php';
+ /**
+ * Default base path
+ */
+ const DEFAULT_BASEPATH='Pages';
+ /**
+ * Fallback base path - used to be the default up to Prado < 3.2
+ */
+ const FALLBACK_BASEPATH='pages';
+ /**
+ * Prefix of ID used for storing parsed configuration in cache
+ */
+ const CONFIG_CACHE_PREFIX='prado:pageservice:';
+ /**
+ * Page template file extension
+ */
+ const PAGE_FILE_EXT='.page';
+ /**
+ * @var string root path of pages
+ */
+ private $_basePath=null;
+ /**
+ * @var string base path class in namespace format
+ */
+ private $_basePageClass='TPage';
+ /**
+ * @var string clientscript manager class in namespace format
+ * @since 3.1.7
+ */
+ private $_clientScriptManagerClass='System.Web.UI.TClientScriptManager';
+ /**
+ * @var string default page
+ */
+ private $_defaultPage='Home';
+ /**
+ * @var string requested page (path)
+ */
+ private $_pagePath=null;
+ /**
+ * @var TPage the requested page
+ */
+ private $_page=null;
+ /**
+ * @var array list of initial page property values
+ */
+ private $_properties=array();
+ /**
+ * @var boolean whether service is initialized
+ */
+ private $_initialized=false;
+ /**
+ * @var TThemeManager theme manager
+ */
+ private $_themeManager=null;
+ /**
+ * @var TTemplateManager template manager
+ */
+ private $_templateManager=null;
+
+ /**
+ * Initializes the service.
+ * This method is required by IService interface and is invoked by application.
+ * @param TXmlElement service configuration
+ */
+ public function init($config)
+ {
+ Prado::trace("Initializing TPageService",'System.Web.Services.TPageService');
+
+ $pageConfig=$this->loadPageConfig($config);
+
+ $this->initPageContext($pageConfig);
+
+ $this->_initialized=true;
+ }
+
+ /**
+ * Initializes page context.
+ * Page context includes path alias settings, namespace usages,
+ * parameter initialization, module loadings, page initial properties
+ * and authorization rules.
+ * @param TPageConfiguration
+ */
+ protected function initPageContext($pageConfig)
+ {
+ $application=$this->getApplication();
+ foreach($pageConfig->getApplicationConfigurations() as $appConfig)
+ $application->applyConfiguration($appConfig);
+
+ $this->applyConfiguration($pageConfig);
+ }
+
+ /**
+ * Applies a page configuration.
+ * @param TPageConfiguration the configuration
+ */
+ protected function applyConfiguration($config)
+ {
+ // initial page properties (to be set when page runs)
+ $this->_properties=array_merge($this->_properties, $config->getProperties());
+ $this->getApplication()->getAuthorizationRules()->mergeWith($config->getRules());
+ $pagePath=$this->getRequestedPagePath();
+ // external configurations
+ foreach($config->getExternalConfigurations() as $filePath=>$params)
+ {
+ list($configPagePath,$condition)=$params;
+ if($condition!==true)
+ $condition=$this->evaluateExpression($condition);
+ if($condition)
+ {
+ if(($path=Prado::getPathOfNamespace($filePath,Prado::getApplication()->getConfigurationFileExt()))===null || !is_file($path))
+ throw new TConfigurationException('pageservice_includefile_invalid',$filePath);
+ $c=new TPageConfiguration($pagePath);
+ $c->loadFromFile($path,$configPagePath);
+ $this->applyConfiguration($c);
+ }
+ }
+
+ }
+
+ /**
+ * Determines the requested page path.
+ * @return string page path requested
+ */
+ protected function determineRequestedPagePath()
+ {
+ $pagePath=$this->getRequest()->getServiceParameter();
+ if(empty($pagePath))
+ $pagePath=$this->getDefaultPage();
+ return $pagePath;
+ }
+
+ /**
+ * Collects configuration for a page.
+ * @param TXmlElement additional configuration specified in the application configuration
+ * @return TPageConfiguration
+ */
+ protected function loadPageConfig($config)
+ {
+ $application=$this->getApplication();
+ $pagePath=$this->getRequestedPagePath();
+ if(($cache=$application->getCache())===null)
+ {
+ $pageConfig=new TPageConfiguration($pagePath);
+ if($config!==null)
+ {
+ if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ $pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
+ else
+ $pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
+ }
+ $pageConfig->loadFromFiles($this->getBasePath());
+ }
+ else
+ {
+ $configCached=true;
+ $currentTimestamp=array();
+ $arr=$cache->get(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath);
+ if(is_array($arr))
+ {
+ list($pageConfig,$timestamps)=$arr;
+ if($application->getMode()!==TApplicationMode::Performance)
+ {
+ foreach($timestamps as $fileName=>$timestamp)
+ {
+ if($fileName===0) // application config file
+ {
+ $appConfigFile=$application->getConfigurationFile();
+ $currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
+ if($currentTimestamp[0]>$timestamp || ($timestamp>0 && !$currentTimestamp[0]))
+ $configCached=false;
+ }
+ else
+ {
+ $currentTimestamp[$fileName]=@filemtime($fileName);
+ if($currentTimestamp[$fileName]>$timestamp || ($timestamp>0 && !$currentTimestamp[$fileName]))
+ $configCached=false;
+ }
+ }
+ }
+ }
+ else
+ {
+ $configCached=false;
+ $paths=explode('.',$pagePath);
+ $configPath=$this->getBasePath();
+ $fileName = $this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
+ ? self::CONFIG_FILE_PHP
+ : self::CONFIG_FILE_XML;
+ foreach($paths as $path)
+ {
+ $configFile=$configPath.DIRECTORY_SEPARATOR.$fileName;
+ $currentTimestamp[$configFile]=@filemtime($configFile);
+ $configPath.=DIRECTORY_SEPARATOR.$path;
+ }
+ $appConfigFile=$application->getConfigurationFile();
+ $currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
+ }
+ if(!$configCached)
+ {
+ $pageConfig=new TPageConfiguration($pagePath);
+ if($config!==null)
+ {
+ if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ $pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
+ else
+ $pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
+ }
+ $pageConfig->loadFromFiles($this->getBasePath());
+ $cache->set(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath,array($pageConfig,$currentTimestamp));
+ }
+ }
+ return $pageConfig;
+ }
+
+ /**
+ * @return TTemplateManager template manager
+ */
+ public function getTemplateManager()
+ {
+ if(!$this->_templateManager)
+ {
+ $this->_templateManager=new TTemplateManager;
+ $this->_templateManager->init(null);
+ }
+ return $this->_templateManager;
+ }
+
+ /**
+ * @param TTemplateManager template manager
+ */
+ public function setTemplateManager(TTemplateManager $value)
+ {
+ $this->_templateManager=$value;
+ }
+
+ /**
+ * @return TThemeManager theme manager
+ */
+ public function getThemeManager()
+ {
+ if(!$this->_themeManager)
+ {
+ $this->_themeManager=new TThemeManager;
+ $this->_themeManager->init(null);
+ }
+ return $this->_themeManager;
+ }
+
+ /**
+ * @param TThemeManager theme manager
+ */
+ public function setThemeManager(TThemeManager $value)
+ {
+ $this->_themeManager=$value;
+ }
+
+ /**
+ * @return string the requested page path
+ */
+ public function getRequestedPagePath()
+ {
+ if($this->_pagePath===null)
+ {
+ $this->_pagePath=strtr($this->determineRequestedPagePath(),'/\\','..');
+ if(empty($this->_pagePath))
+ throw new THttpException(404,'pageservice_page_required');
+ }
+ return $this->_pagePath;
+ }
+
+ /**
+ * @return TPage the requested page
+ */
+ public function getRequestedPage()
+ {
+ return $this->_page;
+ }
+
+ /**
+ * @return string default page path to be served if no explicit page is request. Defaults to 'Home'.
+ */
+ public function getDefaultPage()
+ {
+ return $this->_defaultPage;
+ }
+
+ /**
+ * @param string default page path to be served if no explicit page is request
+ * @throws TInvalidOperationException if the page service is initialized
+ */
+ public function setDefaultPage($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('pageservice_defaultpage_unchangeable');
+ else
+ $this->_defaultPage=$value;
+ }
+
+ /**
+ * @return string the URL for the default page
+ */
+ public function getDefaultPageUrl()
+ {
+ return $this->constructUrl($this->getDefaultPage());
+ }
+
+ /**
+ * @return string the root directory for storing pages. Defaults to the 'pages' directory under the application base path.
+ */
+ public function getBasePath()
+ {
+ if($this->_basePath===null)
+ {
+ $basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
+ if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
+ {
+ $basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::FALLBACK_BASEPATH;
+ if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
+ throw new TConfigurationException('pageservice_basepath_invalid',$basePath);
+ }
+ }
+ return $this->_basePath;
+ }
+
+ /**
+ * @param string root directory (in namespace form) storing pages
+ * @throws TInvalidOperationException if the service is initialized already or basepath is invalid
+ */
+ public function setBasePath($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('pageservice_basepath_unchangeable');
+ else if(($path=Prado::getPathOfNamespace($value))===null || !is_dir($path))
+ throw new TConfigurationException('pageservice_basepath_invalid',$value);
+ $this->_basePath=realpath($path);
+ }
+
+ /**
+ * Sets the base page class name (in namespace format).
+ * If a page only has a template file without page class file,
+ * this base page class will be instantiated.
+ * @param string class name
+ */
+ public function setBasePageClass($value)
+ {
+ $this->_basePageClass=$value;
+ }
+
+ /**
+ * @return string base page class name in namespace format. Defaults to 'TPage'.
+ */
+ public function getBasePageClass()
+ {
+ return $this->_basePageClass;
+ }
+
+ /**
+ * Sets the clientscript manager class (in namespace format).
+ * @param string class name
+ * @since 3.1.7
+ */
+ public function setClientScriptManagerClass($value)
+ {
+ $this->_clientScriptManagerClass=$value;
+ }
+
+ /**
+ * @return string clientscript manager class in namespace format. Defaults to 'System.Web.UI.TClientScriptManager'.
+ * @since 3.1.7
+ */
+ public function getClientScriptManagerClass()
+ {
+ return $this->_clientScriptManagerClass;
+ }
+
+ /**
+ * Runs the service.
+ * This will create the requested page, initializes it with the property values
+ * specified in the configuration, and executes the page.
+ */
+ public function run()
+ {
+ Prado::trace("Running page service",'System.Web.Services.TPageService');
+ $this->_page=$this->createPage($this->getRequestedPagePath());
+ $this->runPage($this->_page,$this->_properties);
+ }
+
+ /**
+ * Creates a page instance based on requested page path.
+ * @param string requested page path
+ * @return TPage the requested page instance
+ * @throws THttpException if requested page path is invalid
+ * @throws TConfigurationException if the page class cannot be found
+ */
+ protected function createPage($pagePath)
+ {
+ $path=$this->getBasePath().DIRECTORY_SEPARATOR.strtr($pagePath,'.',DIRECTORY_SEPARATOR);
+ $hasTemplateFile=is_file($path.self::PAGE_FILE_EXT);
+ $hasClassFile=is_file($path.Prado::CLASS_FILE_EXT);
+
+ if(!$hasTemplateFile && !$hasClassFile)
+ throw new THttpException(404,'pageservice_page_unknown',$pagePath);
+
+ if($hasClassFile)
+ {
+ $className=basename($path);
+ if(!class_exists($className,false))
+ include_once($path.Prado::CLASS_FILE_EXT);
+ }
+ else
+ {
+ $className=$this->getBasePageClass();
+ Prado::using($className);
+ if(($pos=strrpos($className,'.'))!==false)
+ $className=substr($className,$pos+1);
+ }
+
+ if(!class_exists($className,false) || ($className!=='TPage' && !is_subclass_of($className,'TPage')))
+ throw new THttpException(404,'pageservice_page_unknown',$pagePath);
+
+ $page=Prado::createComponent($className);
+ $page->setPagePath($pagePath);
+
+ if($hasTemplateFile)
+ $page->setTemplate($this->getTemplateManager()->getTemplateByFileName($path.self::PAGE_FILE_EXT));
+
+ return $page;
+ }
+
+ /**
+ * Executes a page.
+ * @param TPage the page instance to be run
+ * @param array list of initial page properties
+ */
+ protected function runPage($page,$properties)
+ {
+ foreach($properties as $name=>$value)
+ $page->setSubProperty($name,$value);
+ $page->run($this->getResponse()->createHtmlWriter());
+ }
+
+ /**
+ * Constructs a URL with specified page path and GET parameters.
+ * @param string page path
+ * @param array list of GET parameters, null if no GET parameters required
+ * @param boolean whether to encode the ampersand in URL, defaults to true.
+ * @param boolean whether to encode the GET parameters (their names and values), defaults to true.
+ * @return string URL for the page and GET parameters
+ */
+ public function constructUrl($pagePath,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true)
+ {
+ return $this->getRequest()->constructUrl($this->getID(),$pagePath,$getParams,$encodeAmpersand,$encodeGetItems);
+ }
+}
+
+
+/**
+ * TPageConfiguration class
+ *
+ * TPageConfiguration represents the configuration for a page.
+ * The page is specified by a dot-connected path.
+ * Configurations along this path are merged together to be provided for the page.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.Services
+ * @since 3.0
+ */
+class TPageConfiguration extends TComponent
+{
+ /**
+ * @var array list of application configurations
+ */
+ private $_appConfigs=array();
+ /**
+ * @var array list of page initial property values
+ */
+ private $_properties=array();
+ /**
+ * @var TAuthorizationRuleCollection list of authorization rules
+ */
+ private $_rules=array();
+ /**
+ * @var array list of included configurations
+ */
+ private $_includes=array();
+ /**
+ * @var string the currently request page in the format of Path.To.PageName
+ */
+ private $_pagePath='';
+
+ /**
+ * Constructor.
+ * @param string the currently request page in the format of Path.To.PageName
+ */
+ public function __construct($pagePath)
+ {
+ $this->_pagePath=$pagePath;
+ }
+
+ /**
+ * @return array list of external configuration files. Each element is like $filePath=>$condition
+ */
+ public function getExternalConfigurations()
+ {
+ return $this->_includes;
+ }
+
+ /**
+ * Returns list of page initial property values.
+ * Each array element represents a single property with the key
+ * being the property name and the value the initial property value.
+ * @return array list of page initial property values
+ */
+ public function getProperties()
+ {
+ return $this->_properties;
+ }
+
+ /**
+ * Returns list of authorization rules.
+ * The authorization rules are aggregated (bottom-up) from configuration files
+ * along the path to the specified page.
+ * @return TAuthorizationRuleCollection collection of authorization rules
+ */
+ public function getRules()
+ {
+ return $this->_rules;
+ }
+
+ /**
+ * @return array list of application configurations specified along page path
+ */
+ public function getApplicationConfigurations()
+ {
+ return $this->_appConfigs;
+ }
+
+ /**
+ * Loads configuration for a page specified in a path format.
+ * @param string root path for pages
+ */
+ public function loadFromFiles($basePath)
+ {
+ $paths=explode('.',$this->_pagePath);
+ $page=array_pop($paths);
+ $path=$basePath;
+ $configPagePath='';
+ $fileName = Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
+ ? TPageService::CONFIG_FILE_PHP
+ : TPageService::CONFIG_FILE_XML;
+ foreach($paths as $p)
+ {
+ $this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
+ $path.=DIRECTORY_SEPARATOR.$p;
+ if($configPagePath==='')
+ $configPagePath=$p;
+ else
+ $configPagePath.='.'.$p;
+ }
+ $this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
+ $this->_rules=new TAuthorizationRuleCollection($this->_rules);
+ }
+
+ /**
+ * Loads a specific config file.
+ * @param string config file name
+ * @param string the page path that the config file is associated with. The page path doesn't include the page name.
+ */
+ public function loadFromFile($fname,$configPagePath)
+ {
+ Prado::trace("Loading page configuration file $fname",'System.Web.Services.TPageService');
+ if(empty($fname) || !is_file($fname))
+ return;
+
+ if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ {
+ $fcontent = include $fname;
+ $this->loadFromPhp($fcontent,dirname($fname),$configPagePath);
+ }
+ else
+ {
+ $dom=new TXmlDocument;
+ if($dom->loadFromFile($fname))
+ $this->loadFromXml($dom,dirname($fname),$configPagePath);
+ else
+ throw new TConfigurationException('pageserviceconf_file_invalid',$fname);
+ }
+ }
+
+ public function loadFromPhp($config,$configPath,$configPagePath)
+ {
+ $this->loadApplicationConfigurationFromPhp($config,$configPath);
+ $this->loadPageConfigurationFromPhp($config,$configPath,$configPagePath);
+ }
+
+ /**
+ * Loads a page configuration.
+ * The configuration includes information for both application
+ * and page service.
+ * @param TXmlElement config xml element
+ * @param string the directory containing this configuration
+ * @param string the page path that the config XML is associated with. The page path doesn't include the page name.
+ */
+ public function loadFromXml($dom,$configPath,$configPagePath)
+ {
+ $this->loadApplicationConfigurationFromXml($dom,$configPath);
+ $this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath);
+ }
+
+ public function loadApplicationConfigurationFromPhp($config,$configPath)
+ {
+ $appConfig=new TApplicationConfiguration;
+ $appConfig->loadFromPhp($config,$configPath);
+ $this->_appConfigs[]=$appConfig;
+ }
+
+ /**
+ * Loads the configuration specific for application part
+ * @param TXmlElement config xml element
+ * @param string base path corresponding to this xml element
+ */
+ public function loadApplicationConfigurationFromXml($dom,$configPath)
+ {
+ $appConfig=new TApplicationConfiguration;
+ $appConfig->loadFromXml($dom,$configPath);
+ $this->_appConfigs[]=$appConfig;
+ }
+
+ public function loadPageConfigurationFromPhp($config, $configPath, $configPagePath)
+ {
+ // authorization
+ if(isset($config['authorization']) && is_array($config['authorization']))
+ {
+ $rules = array();
+ foreach($config['authorization'] as $authorization)
+ {
+ $patterns=isset($authorization['pages'])?$authorization['pages']:'';
+ $ruleApplies=false;
+ if(empty($patterns) || trim($patterns)==='*') // null or empty string
+ $ruleApplies=true;
+ else
+ {
+ foreach(explode(',',$patterns) as $pattern)
+ {
+ if(($pattern=trim($pattern))!=='')
+ {
+ // we know $configPagePath and $this->_pagePath
+ if($configPagePath!=='') // prepend the pattern with ConfigPagePath
+ $pattern=$configPagePath.'.'.$pattern;
+ if(strcasecmp($pattern,$this->_pagePath)===0)
+ {
+ $ruleApplies=true;
+ break;
+ }
+ if($pattern[strlen($pattern)-1]==='*') // try wildcard matching
+ {
+ if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
+ {
+ $ruleApplies=true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if($ruleApplies)
+ {
+ $action = isset($authorization['action'])?$authorization['action']:'';
+ $users = isset($authorization['users'])?$authorization['users']:'';
+ $roles = isset($authorization['roles'])?$authorization['roles']:'';
+ $verb = isset($authorization['verb'])?$authorization['verb']:'';
+ $ips = isset($authorization['ips'])?$authorization['ips']:'';
+ $rules[]=new TAuthorizationRule($action,$users,$roles,$verb,$ips);
+ }
+ }
+ $this->_rules=array_merge($rules,$this->_rules);
+ }
+ // pages
+ if(isset($config['pages']) && is_array($config['pages']))
+ {
+ if(isset($config['pages']['properties']))
+ {
+ $this->_properties = array_merge($this->_properties, $config['pages']['properties']);
+ unset($config['pages']['properties']);
+ }
+ foreach($config['pages'] as $id => $page)
+ {
+ $properties = array();
+ if(isset($page['properties']))
+ {
+ $properties=$page['properties'];
+ unset($page['properties']);
+ }
+ $matching=false;
+ $id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
+ if(strcasecmp($id,$this->_pagePath)===0)
+ $matching=true;
+ else if($id[strlen($id)-1]==='*') // try wildcard matching
+ $matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
+ if($matching)
+ $this->_properties=array_merge($this->_properties,$properties);
+ }
+ }
+
+ // external configurations
+ if(isset($config['includes']) && is_array($config['includes']))
+ {
+ foreach($config['includes'] as $include)
+ {
+ $when = isset($include['when'])?true:false;
+ if(!isset($include['file']))
+ throw new TConfigurationException('pageserviceconf_includefile_required');
+ $filePath = $include['file'];
+ if(isset($this->_includes[$filePath]))
+ $this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
+ else
+ $this->_includes[$filePath]=array($configPagePath,$when);
+ }
+ }
+ }
+
+ /**
+ * Loads the configuration specific for page service.
+ * @param TXmlElement config xml element
+ * @param string base path corresponding to this xml element
+ * @param string the page path that the config XML is associated with. The page path doesn't include the page name.
+ */
+ public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath)
+ {
+ // authorization
+ if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null)
+ {
+ $rules=array();
+ foreach($authorizationNode->getElements() as $node)
+ {
+ $patterns=$node->getAttribute('pages');
+ $ruleApplies=false;
+ if(empty($patterns) || trim($patterns)==='*') // null or empty string
+ $ruleApplies=true;
+ else
+ {
+ foreach(explode(',',$patterns) as $pattern)
+ {
+ if(($pattern=trim($pattern))!=='')
+ {
+ // we know $configPagePath and $this->_pagePath
+ if($configPagePath!=='') // prepend the pattern with ConfigPagePath
+ $pattern=$configPagePath.'.'.$pattern;
+ if(strcasecmp($pattern,$this->_pagePath)===0)
+ {
+ $ruleApplies=true;
+ break;
+ }
+ if($pattern[strlen($pattern)-1]==='*') // try wildcard matching
+ {
+ if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
+ {
+ $ruleApplies=true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if($ruleApplies)
+ $rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips'));
+ }
+ $this->_rules=array_merge($rules,$this->_rules);
+ }
+
+ // pages
+ if(($pagesNode=$dom->getElementByTagName('pages'))!==null)
+ {
+ $this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray());
+ // at the page folder
+ foreach($pagesNode->getElementsByTagName('page') as $node)
+ {
+ $properties=$node->getAttributes();
+ $id=$properties->remove('id');
+ if(empty($id))
+ throw new TConfigurationException('pageserviceconf_page_invalid',$configPath);
+ $matching=false;
+ $id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
+ if(strcasecmp($id,$this->_pagePath)===0)
+ $matching=true;
+ else if($id[strlen($id)-1]==='*') // try wildcard matching
+ $matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
+ if($matching)
+ $this->_properties=array_merge($this->_properties,$properties->toArray());
+ }
+ }
+
+ // external configurations
+ foreach($dom->getElementsByTagName('include') as $node)
+ {
+ if(($when=$node->getAttribute('when'))===null)
+ $when=true;
+ if(($filePath=$node->getAttribute('file'))===null)
+ throw new TConfigurationException('pageserviceconf_includefile_required');
+ if(isset($this->_includes[$filePath]))
+ $this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
+ else
+ $this->_includes[$filePath]=array($configPagePath,$when);
+ }
+ }
+}
+
diff --git a/lib/prado/framework/Web/Services/TRpcService.php b/lib/prado/framework/Web/Services/TRpcService.php
new file mode 100644
index 0000000..cf57944
--- /dev/null
+++ b/lib/prado/framework/Web/Services/TRpcService.php
@@ -0,0 +1,722 @@
+<?php
+
+/**
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @link https://github.com/pradosoft/prado
+ * @copyright 2010 Bigpoint GmbH
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @version $Id$
+ * @since 3.2
+ * @package System.Web.Services
+ */
+
+/**
+ * TRpcService class
+ *
+ * The TRpcService class is a generic class that can be extended and used to implement
+ * rpc services using different servers and protocols.
+ *
+ * A server is a {@link TModule} that must subclass {@link TRpcServer}: its role is
+ * to be an intermediate, moving data between the service and the provider. The base
+ * {@link TRpcServer} class should suit the most common needs, but can be sublassed for
+ * logging and debugging purposes, or to filter and modify the request/response on the fly.
+ *
+ * A protocol is a {@link TModule} that must subclass {@link TRpcProtocol}: its role is
+ * to implement the protocol that exposes the rpc api. Prado already implements two
+ * protocols: {@link TXmlRpcProtocol} for Xml-Rpc request and {@link TJsonRpcProtocol} for
+ * JSON-Rpc requests.
+ *
+ * A provider is a {@link TModule} that must subclass {@link TRpcApiProvider}: its role is
+ * to implement the methods that are available through the api. Each defined api must be
+ * a sublass of the abstract class {@link TRpcApiProvider} and implement its methods.
+ *
+ * The flow of requests and reponses is the following:
+ * Request <-> TRpcService <-> TRpcServer <-> TRpcProtocol <-> TRpcApiProvider <-> Response
+ *
+ * To define an rpc service, add the proper application configuration:
+ *
+ * <code>
+ * <service id="rpc" class="System.Web.Services.TRpcService">
+ * <rpcapi id="customers" class="Application.Api.CustomersApi" />
+ * <modules>
+ * <!-- register any module needed by the service here -->
+ * </modules>
+ * </service>
+ * </code>
+ *
+ * An api can be registered adding a proper <rpcapi ..> definition inside the service
+ * configuration. Each api definition must contain an id property and a class name
+ * expressed in namespace format. When the service receives a request for that api,
+ * the specified class will be instanciated in order to satisfy the request.
+ *
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @version $Id$
+ * @package System.Web.Services
+ * @since 3.2
+ **/
+class TRpcService extends TService
+{
+ /**
+ * const string base api provider class which every API must extend
+ */
+ const BASE_API_PROVIDER = 'TRpcApiProvider';
+
+ /**
+ * const string base RPC server implementation
+ */
+ const BASE_RPC_SERVER = 'TRpcServer';
+
+ /**
+ * @var array containing mimetype to protocol handler mappings
+ */
+ protected $protocolHandlers = array(
+ 'application/json' => 'TJsonRpcProtocol',
+ 'text/xml' => 'TXmlRpcProtocol'
+ );
+
+ /**
+ * @var array containing API provider and their configured properties
+ */
+ protected $apiProviders = array();
+
+ // methods
+
+ /**
+ * Creates the API provider instance for the current request
+ * @param TRpcProtocol $protocolHandler instance
+ * @param string $providerId
+ */
+ public function createApiProvider(TRpcProtocol $protocolHandler, $providerId)
+ {
+ $_properties = $this->apiProviders[$providerId];
+
+ if(($_providerClass = $_properties->remove('class')) === null)
+ throw new TConfigurationException('rpcservice_apiprovider_required');
+
+ Prado::using($_providerClass);
+
+ $_providerClassName = ($_pos = strrpos($_providerClass, '.')) !== false ? substr($_providerClass, $_pos + 1) : $_providerClass;
+ if(!is_subclass_of($_providerClassName, self::BASE_API_PROVIDER))
+ throw new TConfigurationException('rpcservice_apiprovider_invalid');
+
+ if(($_rpcServerClass = $_properties->remove('server')) === null)
+ $_rpcServerClass = self::BASE_RPC_SERVER;
+
+ Prado::using($_rpcServerClass);
+
+ $_rpcServerClassName = ($_pos = strrpos($_rpcServerClass, '.')) !== false ? substr($_rpcServerClass, $_pos + 1) : $_rpcServerClass;
+ if($_rpcServerClassName!==self::BASE_RPC_SERVER && !is_subclass_of($_rpcServerClassName, self::BASE_RPC_SERVER))
+ throw new TConfigurationException('rpcservice_rpcserver_invalid');
+
+ $_apiProvider = new $_providerClassName(new $_rpcServerClassName($protocolHandler));
+ $_apiProvider->setId($providerId);
+
+ foreach($_properties as $_key => $_value)
+ $_apiProvider->setSubProperty($_key, $_value);
+
+ return $_apiProvider;
+ }
+
+ /**
+ * Initializes the service
+ * @param TXmlElement $config containing the module configuration
+ */
+ public function init($config)
+ {
+ $this->loadConfig($config);
+ }
+
+ /**
+ * Loads the service configuration
+ * @param TXmlElement $xml configuration
+ */
+ public function loadConfig(TXmlElement $xml)
+ {
+ foreach($xml->getElementsByTagName('rpcapi') as $_apiProviderXml)
+ {
+ $_properties = $_apiProviderXml->getAttributes();
+
+ if(($_id = $_properties->remove('id')) === null || $_id == "")
+ throw new TConfigurationException('rpcservice_apiproviderid_required');
+
+ if(isset($this->apiProviders[$_id]))
+ throw new TConfigurationException('rpcservice_apiproviderid_duplicated');
+
+ $this->apiProviders[$_id] = $_properties;
+ }
+ }
+
+ /**
+ * Runs the service
+ */
+ public function run()
+ {
+ $_request = $this->getRequest();
+
+ if(($_providerId = $_request->getServiceParameter()) == "")
+ throw new THttpException(400, 'RPC API-Provider id required');
+
+ if(($_method = $_request->getRequestType()) != 'POST')
+ throw new THttpException(405, 'Invalid request method "'.$_method.'"!'); // TODO Exception muss "Allow POST" Header setzen
+
+ if(($_mimeType = $_request->getContentType()) === null)
+ throw new THttpException(406, 'Content-Type is missing!'); // TODO Exception muss gültige Content-Type werte zurück geben
+
+ if(!in_array($_mimeType, array_keys($this->protocolHandlers)))
+ throw new THttpException(406, 'Unsupported Content-Type!'); // TODO see previous
+
+ $_protocolHandlerClass = $this->protocolHandlers[$_mimeType];
+ $_protocolHandler = new $_protocolHandlerClass;
+
+ if(($_result = $this->createApiProvider($_protocolHandler, $_providerId)->processRequest()) !== null)
+ {
+ $_response = $this->getResponse();
+ $_protocolHandler->createResponseHeaders($_response);
+ $_response->write($_result);
+ }
+ }
+}
+
+/**
+ * TRpcServer class
+ *
+ * TRpcServer is a class
+ *
+ * TRpcServer is the base class used to creare a server to be used in conjunction with
+ * {@link TRpcService}.
+ * The role of TRpcServer is to be an intermediate, moving data between the service and
+ * the provider. This base class should suit the most common needs, but can be sublassed for
+ * logging and debugging purposes, or to filter and modify the request/response on the fly.
+ *
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @version $Id$
+ * @package System.Web.Services
+ * @since 3.2
+ **/
+class TRpcServer extends TModule
+{
+ /**
+ * @var TRpcProtocol instance
+ */
+ protected $handler;
+
+ /**
+ * Constructor
+ * @param TRpcProtocol $protocolHandler instance
+ */
+ public function __construct(TRpcProtocol $protocolHandler)
+ {
+ $this->handler = $protocolHandler;
+ }
+
+ /**
+ * Registers the method in the protocol handler
+ * @param string $methodName
+ * @param array $methodDetails
+ */
+ public function addRpcMethod($methodName, $methodDetails)
+ {
+ $this->handler->addMethod($methodName, $methodDetails);
+ }
+
+ /**
+ * Retrieves the request payload
+ * @return string request payload
+ */
+ public function getPayload()
+ {
+ return file_get_contents('php://input');
+ }
+
+ /**
+ * Passes the request payload to the protocol handler and returns the result
+ * @return string rpc response
+ */
+ public function processRequest()
+ {
+ try
+ {
+ return $this->handler->callMethod($this->getPayload());
+ }
+ catch(TRpcException $e)
+ {
+ return $this->handler->createErrorResponse($e);
+ }
+ }
+}
+
+/**
+ * TRpcException class
+ *
+ * A TRpcException represents a RPC fault i.e. an error that is caused by the input data
+ * sent from the client.
+ *
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @version $Id$
+ * @package System.Web.Services
+ * @since 3.2
+ */
+class TRpcException extends TException
+{
+ public function __construct($message, $errorCode = -1)
+ {
+ $this->setErrorCode($errorCode);
+
+ parent::__construct($message);
+ }
+}
+
+/**
+ * TRpcApiProvider class
+ *
+ * TRpcApiProvider is an abstract class the can be subclasses in order to implement an
+ * api for a {@link TRpcService}. A subclass of TRpcApiProvider must implement the
+ * {@link registerMethods} method in order to declare the available methods, their
+ * names and the associated callback.
+ *
+ * <code>
+ * public function registerMethods()
+ * {
+ * return array(
+ * 'apiMethodName1' => array('method' => array($this, 'objectMethodName1')),
+ * 'apiMethodName2' => array('method' => array('ClassName', 'staticMethodName')),
+ * );
+ * }
+ * </code>
+ *
+ * In this example, two api method have been defined. The first refers to an object
+ * method that must be implemented in the same class, the second to a static method
+ * implemented in a 'ClassName' class.
+ * In both cases, the method implementation will receive the request parameters as its
+ * method parameters. Since the number of received parameters depends on
+ * external-supplied data, it's adviced to use php's func_get_args() funtion to
+ * validate them.
+ *
+ * Providers must be registered in the service configuration in order to be available,
+ * as explained in {@link TRpcService}'s documentation.
+ *
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @version $Id$
+ * @package System.Web.Services
+ * @since 3.2
+ */
+abstract class TRpcApiProvider extends TModule
+{
+ /**
+ * @var TRpcServer instance
+ */
+ protected $rpcServer;
+
+ /**
+ * Must return an array of the available methods
+ * @abstract
+ */
+ abstract public function registerMethods();
+
+ /**
+ * Constructor: informs the rpc server of the registered methods
+ */
+ public function __construct(TRpcServer $rpcServer)
+ {
+ $this->rpcServer = $rpcServer;
+
+ foreach($this->registerMethods() as $_methodName => $_methodDetails)
+ $this->rpcServer->addRpcMethod($_methodName, $_methodDetails);
+ }
+
+ /**
+ * Processes the request using the server
+ * @return processed request
+ */
+ public function processRequest()
+ {
+ return $this->rpcServer->processRequest();
+ }
+
+ /**
+ * @return rpc server instance
+ */
+ public function getRpcServer()
+ {
+ return $this->rpcServer;
+ }
+}
+
+/**
+ * TRpcProtocol class
+ *
+ * TRpcProtocol is the base class used to implement a protocol in a {@link TRpcService}.
+ * Prado already implements two protocols: {@link TXmlRpcProtocol} for Xml-Rpc request
+ * and {@link TJsonRpcProtocol} for JSON-Rpc requests.
+ *
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @version $Id$
+ * @package System.Web.Services
+ * @since 3.2
+ **/
+abstract class TRpcProtocol
+{
+ /**
+ * @var array containing the mapping from RPC method names to the actual handlers
+ */
+ protected $rpcMethods = array();
+
+ // abstracts
+
+ /**
+ * @param string request payload
+ * Processed the request ans returns the response, if any
+ * @return processed response
+ * @abstract
+ */
+ abstract public function callMethod($requestPayload);
+ /**
+ * @param TRpcException the exception with error details
+ * Creates a proper response for an error condition
+ * @return a response representing the error
+ * @abstract
+ */
+ abstract public function createErrorResponse(TRpcException $exception);
+ /**
+ * @param response
+ * Sets the needed headers for the response (eg: content-type, charset)
+ * @abstract
+ */
+ abstract public function createResponseHeaders($response);
+ /**
+ * Encodes the response
+ * @param mixed reponse data
+ * @return string encoded response
+ * @abstract
+ */
+ abstract public function encode($data);
+ /**
+ * Decodes the request payload
+ * @param string request payload
+ * @return mixed decoded request
+ * @abstract
+ */
+ abstract public function decode($data);
+
+ // methods
+
+ /**
+ * Registers a new RPC method and handler details
+ * @param string $methodName
+ * @param array $handlerDetails containing the callback handler
+ */
+ public function addMethod($methodName, $handlerDetails)
+ {
+ $this->rpcMethods[$methodName] = $handlerDetails;
+ }
+
+ /**
+ * Calls the callback handler for the given method
+ * @param string $methodName of the RPC
+ * @param array $parameters for the callback handler as provided by the client
+ * @return mixed whatever the callback handler returns
+ */
+ public function callApiMethod($methodName, $parameters)
+ {
+ if(!isset($this->rpcMethods[$methodName]))
+ throw new TRpcException('Method "'.$methodName.'" not found');
+
+ if($parameters === null)
+ $parameters = array();
+
+ if(!is_array($parameters))
+ $parameters = array($parameters);
+ return call_user_func_array($this->rpcMethods[$methodName]['method'], $parameters);
+ }
+}
+
+/**
+ * TJsonRpcProtocol class
+ *
+ * TJsonRpcProtocol is a class that implements JSON-Rpc protocol in {@link TRpcService}.
+ * Both version 1.0 and 2.0 of the specification are implemented, and the server will try
+ * to answer using the same version of the protocol used by the requesting client.
+ *
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @author Fabio Bas <ctrlaltca@gmail.com>
+ * @version $Id$
+ * @package System.Web.Services
+ * @since 3.2
+ */
+class TJsonRpcProtocol extends TRpcProtocol
+{
+ protected $_id=null;
+ protected $_specificationVersion=1.0;
+
+ /**
+ * Handles the RPC request
+ * @param string $requestPayload
+ * @return string JSON RPC response
+ */
+ public function callMethod($requestPayload)
+ {
+ try
+ {
+ $_request = $this->decode($requestPayload);
+
+ if(isset($_request['jsonrpc']))
+ {
+ $this->_specificationVersion=$_request['jsonrpc'];
+ if($this->_specificationVersion > 2.0)
+ throw new TRpcException('Unsupported specification version', '-32600');
+ }
+
+ if(isset($_request['id']))
+ $this->_id=$_request['id'];
+
+ if(!isset($_request['method']))
+ throw new TRpcException('Missing request method', '-32600');
+
+ if(!isset($_request['params']))
+ $parameters = array();
+ else
+ $parameters = $_request['params'];
+
+ if(!is_array($parameters))
+ $parameters = array($parameters);
+
+ // a request without an id is a notification that doesn't need a response
+ if($this->_id !== null)
+ {
+ if($this->_specificationVersion==2.0)
+ {
+ return $this->encode(array(
+ 'jsonrpc' => '2.0',
+ 'id' => $this->_id,
+ 'result' => $this->callApiMethod($_request['method'], $parameters),
+ ));
+ } else {
+ return $this->encode(array(
+ 'id' => $this->_id,
+ 'result' => $this->callApiMethod($_request['method'], $_request['params']),
+ 'error' => null
+ ));
+ }
+ }
+ }
+ catch(TRpcException $e)
+ {
+ return $this->createErrorResponse($e);
+ }
+ catch(THttpException $e)
+ {
+ throw $e;
+ }
+ catch(Exception $e)
+ {
+ return $this->createErrorResponse(new TRpcException('An internal error occured', '-32603'));
+ }
+ }
+
+ /**
+ * Turns the given exception into an JSON RPC fault
+ * @param TRpcException $exception
+ * @return string JSON RPC fault
+ */
+ public function createErrorResponse(TRpcException $exception)
+ {
+ if($this->_specificationVersion==2.0)
+ {
+ return $this->encode(array(
+ 'id' => $this->_id,
+ 'result' => null,
+ 'error'=> array(
+ 'code' => $exception->getCode(),
+ 'message'=> $exception->getMessage(),
+ 'data' => null,
+ )
+ ));
+ } else {
+ return $this->encode(array(
+ 'id' => $this->_id,
+ 'error'=> array(
+ 'code' => $exception->getCode(),
+ 'message'=> $exception->getMessage(),
+ 'data' => null,
+ )
+ ));
+ }
+ }
+
+ /**
+ * Sets the correct response headers
+ * @param THttpResponse $response
+ */
+ public function createResponseHeaders($response)
+ {
+ $response->setContentType('application/json');
+ $response->setCharset('UTF-8');
+ }
+
+ /**
+ * Decodes JSON encoded data into PHP data
+ * @param string $data in JSON format
+ * @return array PHP data
+ */
+ public function decode($data)
+ {
+ $s = json_decode($data, true);
+ self::checkJsonError();
+ return $s;
+ }
+
+ /**
+ * Encodes PHP data into JSON data
+ * @param mixed PHP data
+ * @return string JSON encoded PHP data
+ */
+ public function encode($data)
+ {
+ $s = json_encode($data);
+ self::checkJsonError();
+ return $s;
+ }
+
+ private static function checkJsonError()
+ {
+ $errnum = json_last_error();
+ if($errnum != JSON_ERROR_NONE)
+ throw new Exception("JSON error: $msg", $err);
+ }
+
+ /**
+ * Calls the callback handler for the given method
+ * Overrides parent implementation to correctly handle error codes
+ * @param string $methodName of the RPC
+ * @param array $parameters for the callback handler as provided by the client
+ * @return mixed whatever the callback handler returns
+ */
+ public function callApiMethod($methodName, $parameters)
+ {
+ if(!isset($this->rpcMethods[$methodName]))
+ throw new TRpcException('Method "'.$methodName.'" not found', '-32601');
+
+ return call_user_func_array($this->rpcMethods[$methodName]['method'], $parameters);
+ }
+}
+
+/**
+ * TXmlRpcProtocol class
+ *
+ * TXmlRpcProtocol is a class that implements XML-Rpc protocol in {@link TRpcService}.
+ * It's basically a wrapper to the xmlrpc_server_* family of php methods.
+ *
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @version $Id$
+ * @package System.Web.Services
+ * @since 3.2
+ */
+class TXmlRpcProtocol extends TRpcProtocol
+{
+ /**
+ * @var XML RPC server resource
+ */
+ private $_xmlrpcServer;
+
+ // magics
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->_xmlrpcServer = xmlrpc_server_create();
+ }
+
+ /**
+ * Destructor
+ */
+ public function __destruct()
+ {
+ xmlrpc_server_destroy($this->_xmlrpcServer);
+ }
+
+ // methods
+
+ /**
+ * Registers a new RPC method and handler details
+ * @param string $methodName
+ * @param array $handlerDetails containing the callback handler
+ */
+ public function addMethod($methodName, $methodDetails)
+ {
+ parent::addMethod($methodName, $methodDetails);
+
+ xmlrpc_server_register_method($this->_xmlrpcServer, $methodName, array($this, 'callApiMethod'));
+ }
+
+ // methods
+
+ /**
+ * Handles the RPC request
+ * @param string $requestPayload
+ * @return string XML RPC response
+ */
+ public function callMethod($requestPayload)
+ {
+ try
+ {
+ return xmlrpc_server_call_method($this->_xmlrpcServer, $requestPayload, null);
+ }
+ catch(TRpcException $e)
+ {
+ return $this->createErrorResponse($e);
+ }
+ catch(THttpException $e)
+ {
+ throw $e;
+ }
+ catch(Exception $e)
+ {
+ return $this->createErrorResponse(new TRpcException('An internal error occured'));
+ }
+ }
+
+ /**
+ * Turns the given exception into an XML RPC fault
+ * @param TRpcException $exception
+ * @return string XML RPC fault
+ */
+ public function createErrorResponse(TRpcException $exception)
+ {
+ return $this->encode(array(
+ 'faultCode' => $exception->getCode(),
+ 'faultString' => $exception->getMessage()
+ ));
+ }
+
+ /**
+ * Sets the correct response headers
+ * @param THttpResponse $response
+ */
+ public function createResponseHeaders($response)
+ {
+ $response->setContentType('text/xml');
+ $response->setCharset('UTF-8');
+ }
+
+ /**
+ * Decodes XML encoded data into PHP data
+ * @param string $data in XML format
+ * @return array PHP data
+ */
+ public function decode($data)
+ {
+ return xmlrpc_decode($data);
+ }
+
+ /**
+ * Encodes PHP data into XML data
+ * @param mixed PHP data
+ * @return string XML encoded PHP data
+ */
+ public function encode($data)
+ {
+ return xmlrpc_encode($data);
+ }
+}
diff --git a/lib/prado/framework/Web/Services/TSoapService.php b/lib/prado/framework/Web/Services/TSoapService.php
new file mode 100644
index 0000000..9554af2
--- /dev/null
+++ b/lib/prado/framework/Web/Services/TSoapService.php
@@ -0,0 +1,622 @@
+<?php
+/**
+ * TSoapService and TSoapServer class file
+ *
+ * @author Knut Urdalen <knut.urdalen@gmail.com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.Services
+ */
+
+/**
+ * TSoapService class
+ *
+ * TSoapService processes SOAP requests for a PRADO application.
+ * TSoapService requires PHP SOAP extension to be loaded.
+ *
+ * TSoapService manages a set of SOAP providers. Each SOAP provider
+ * is a class that implements a set of SOAP methods which are exposed
+ * to SOAP clients for remote invocation. TSoapService generates WSDL
+ * automatically for the SOAP providers by default.
+ *
+ * To use TSoapService, configure it in the application specification like following:
+ * <code>
+ * <services>
+ * <service id="soap" class="System.Web.Services.TSoapService">
+ * <soap id="stockquote" provider="MyStockQuote" />
+ * </service>
+ * </services>
+ * </code>
+ * PHP configuration style:
+ * <code>
+ * 'services' => array(
+ * 'soap' => array(
+ * 'class' => 'System.Web.Services.TSoapService'
+ * 'properties' => array(
+ * 'provider' => 'MyStockQuote'
+ * )
+ * )
+ * )
+ * </code>
+ *
+ * The WSDL for the provider class "MyStockQuote" is generated based on special
+ * comment tags in the class. In particular, if a class method's comment
+ * contains the keyword "@soapmethod", it is considered to be a SOAP method
+ * and will be exposed to SOAP clients. For example,
+ * <code>
+ * class MyStockQuote {
+ * / **
+ * * @param string $symbol the stock symbol
+ * * @return float the stock price
+ * * @soapmethod
+ * * /
+ * public function getQuote($symbol) {...}
+ * }
+ * </code>
+ *
+ * With the above SOAP provider, a typical SOAP client may call the method "getQuote"
+ * remotely like the following:
+ * <code>
+ * $client=new SoapClient("http://hostname/path/to/index.php?soap=stockquote.wsdl");
+ * echo $client->getQuote("ibm");
+ * </code>
+ *
+ * Each <soap> element in the application specification actually configures
+ * the properties of a SOAP server which defaults to {@link TSoapServer}.
+ * Therefore, any writable property of {@link TSoapServer} may appear as an attribute
+ * in the <soap> element. For example, the "provider" attribute refers to
+ * the {@link TSoapServer::setProvider Provider} property of {@link TSoapServer}.
+ * The following configuration specifies that the SOAP server is persistent within
+ * the user session (that means a MyStockQuote object will be stored in session)
+ * <code>
+ * <services>
+ * <service id="soap" class="System.Web.Services.TSoapService">
+ * <soap id="stockquote" provider="MyStockQuote" SessionPersistent="true" />
+ * </service>
+ * </services>
+ * </code>
+ *
+ * You may also use your own SOAP server class by specifying the "class" attribute of <soap>.
+ *
+ * @author Knut Urdalen <knut.urdalen@gmail.com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @author Carl G. Mathisen <carlgmathisen@gmail.com>
+ * @package System.Web.Services
+ * @since 3.1
+ */
+class TSoapService extends TService
+{
+ const DEFAULT_SOAP_SERVER='TSoapServer';
+ private $_servers=array();
+ private $_configFile=null;
+ private $_wsdlRequest=false;
+ private $_serverID=null;
+
+ /**
+ * Constructor.
+ * Sets default service ID to 'soap'.
+ */
+ public function __construct()
+ {
+ $this->setID('soap');
+ }
+
+ /**
+ * Initializes this module.
+ * This method is required by the IModule interface.
+ * @param TXmlElement configuration for this module, can be null
+ * @throws TConfigurationException if {@link getConfigFile ConfigFile} is invalid.
+ */
+ public function init($config)
+ {
+ if($this->_configFile!==null)
+ {
+ if(is_file($this->_configFile))
+ {
+ $dom=new TXmlDocument;
+ $dom->loadFromFile($this->_configFile);
+ $this->loadConfig($dom);
+ }
+ else
+ throw new TConfigurationException('soapservice_configfile_invalid',$this->_configFile);
+ }
+ $this->loadConfig($config);
+
+ $this->resolveRequest();
+ }
+
+ /**
+ * Resolves the request parameter.
+ * It identifies the server ID and whether the request is for WSDL.
+ * @throws THttpException if the server ID cannot be found
+ * @see getServerID
+ * @see getIsWsdlRequest
+ */
+ protected function resolveRequest()
+ {
+ $serverID=$this->getRequest()->getServiceParameter();
+ if(($pos=strrpos($serverID,'.wsdl'))===strlen($serverID)-5)
+ {
+ $serverID=substr($serverID,0,$pos);
+ $this->_wsdlRequest=true;
+ }
+ else
+ $this->_wsdlRequest=false;
+ $this->_serverID=$serverID;
+ if(!isset($this->_servers[$serverID]))
+ throw new THttpException(400,'soapservice_request_invalid',$serverID);
+ }
+
+ /**
+ * Loads configuration from an XML element
+ * @param mixed configuration node
+ * @throws TConfigurationException if soap server id is not specified or duplicated
+ */
+ private function loadConfig($config)
+ {
+ if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ {
+ if(is_array($config))
+ {
+ foreach($config['soap'] as $id => $server)
+ {
+ $properties = isset($server['properties'])?$server['properties']:array();
+ if(isset($this->_servers[$id]))
+ throw new TConfigurationException('soapservice_serverid_duplicated',$id);
+ $this->_servers[$id]=$properties;
+ }
+ }
+ }
+ else
+ {
+ foreach($config->getElementsByTagName('soap') as $serverXML)
+ {
+ $properties=$serverXML->getAttributes();
+ if(($id=$properties->remove('id'))===null)
+ throw new TConfigurationException('soapservice_serverid_required');
+ if(isset($this->_servers[$id]))
+ throw new TConfigurationException('soapservice_serverid_duplicated',$id);
+ $this->_servers[$id]=$properties;
+ }
+ }
+ }
+
+ /**
+ * @return string external configuration file. Defaults to null.
+ */
+ public function getConfigFile()
+ {
+ return $this->_configFile;
+ }
+
+ /**
+ * @param string external configuration file in namespace format. The file
+ * must be suffixed with '.xml'.
+ * @throws TInvalidDataValueException if the file is invalid.
+ */
+ public function setConfigFile($value)
+ {
+ if(($this->_configFile=Prado::getPathOfNamespace($value,Prado::getApplication()->getConfigurationFileExt()))===null)
+ throw new TConfigurationException('soapservice_configfile_invalid',$value);
+ }
+
+ /**
+ * Constructs a URL with specified page path and GET parameters.
+ * @param string soap server ID
+ * @param array list of GET parameters, null if no GET parameters required
+ * @param boolean whether to encode the ampersand in URL, defaults to true.
+ * @param boolean whether to encode the GET parameters (their names and values), defaults to true.
+ * @return string URL for the page and GET parameters
+ */
+ public function constructUrl($serverID,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true)
+ {
+ return $this->getRequest()->constructUrl($this->getID(),$serverID,$getParams,$encodeAmpersand,$encodeGetItems);
+ }
+
+ /**
+ * @return boolean whether this is a request for WSDL
+ */
+ public function getIsWsdlRequest()
+ {
+ return $this->_wsdlRequest;
+ }
+
+ /**
+ * @return string the SOAP server ID
+ */
+ public function getServerID()
+ {
+ return $this->_serverID;
+ }
+
+ /**
+ * Creates the requested SOAP server.
+ * The SOAP server is initialized with the property values specified
+ * in the configuration.
+ * @return TSoapServer the SOAP server instance
+ */
+ protected function createServer()
+ {
+ $properties=$this->_servers[$this->_serverID];
+ $serverClass=null;
+ if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP && isset($config['class']))
+ $serverClass=$config['class'];
+ else if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_XML)
+ $serverClass=$properties->remove('class');
+ if($serverClass===null)
+ $serverClass=self::DEFAULT_SOAP_SERVER;
+ Prado::using($serverClass);
+ $className=($pos=strrpos($serverClass,'.'))!==false?substr($serverClass,$pos+1):$serverClass;
+ if($className!==self::DEFAULT_SOAP_SERVER && !is_subclass_of($className,self::DEFAULT_SOAP_SERVER))
+ throw new TConfigurationException('soapservice_server_invalid',$serverClass);
+ $server=new $className;
+ $server->setID($this->_serverID);
+ foreach($properties as $name=>$value)
+ $server->setSubproperty($name,$value);
+ return $server;
+ }
+
+ /**
+ * Runs the service.
+ * If the service parameter ends with '.wsdl', it will serve a WSDL file for
+ * the specified soap server.
+ * Otherwise, it will handle the soap request using the specified server.
+ */
+ public function run()
+ {
+ Prado::trace("Running SOAP service",'System.Web.Services.TSoapService');
+ $server=$this->createServer();
+ $this->getResponse()->setContentType('text/xml');
+ $this->getResponse()->setCharset($server->getEncoding());
+ if($this->getIsWsdlRequest())
+ {
+ // server WSDL file
+ Prado::trace("Generating WSDL",'System.Web.Services.TSoapService');
+ $this->getResponse()->clear();
+ $this->getResponse()->write($server->getWsdl());
+ }
+ else
+ {
+ // provide SOAP service
+ Prado::trace("Handling SOAP request",'System.Web.Services.TSoapService');
+ $server->run();
+ }
+ }
+}
+
+
+/**
+ * TSoapServer class.
+ *
+ * TSoapServer is a wrapper of the PHP SoapServer class.
+ * It associates a SOAP provider class to the SoapServer object.
+ * It also manages the URI for the SOAP service and WSDL.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.Services
+ * @since 3.1
+ */
+class TSoapServer extends TApplicationComponent
+{
+ const WSDL_CACHE_PREFIX='wsdl.';
+
+ private $_id;
+ private $_provider;
+
+ private $_version='';
+ private $_actor='';
+ private $_encoding='';
+ private $_uri='';
+ private $_classMap;
+ private $_persistent=false;
+ private $_wsdlUri='';
+
+ private $_requestedMethod;
+
+ private $_server;
+
+ /**
+ * @return string the ID of the SOAP server
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * @param string the ID of the SOAP server
+ * @throws TInvalidDataValueException if the ID ends with '.wsdl'.
+ */
+ public function setID($id)
+ {
+ if(strrpos($this->_id,'.wsdl')===strlen($this->_id)-5)
+ throw new TInvalidDataValueException('soapserver_id_invalid',$id);
+ $this->_id=$id;
+ }
+
+ /**
+ * Handles the SOAP request.
+ */
+ public function run()
+ {
+ if(($provider=$this->getProvider())!==null)
+ {
+ Prado::using($provider);
+ $providerClass=($pos=strrpos($provider,'.'))!==false?substr($provider,$pos+1):$provider;
+ $this->guessMethodCallRequested($providerClass);
+ $server=$this->createServer();
+ $server->setClass($providerClass, $this);
+ if($this->_persistent)
+ $server->setPersistence(SOAP_PERSISTENCE_SESSION);
+ }
+ else
+ $server=$this->createServer();
+ try
+ {
+ $server->handle();
+ }
+ catch (Exception $e)
+ {
+ if($this->getApplication()->getMode()===TApplicationMode::Debug)
+ $this->fault($e->getMessage(), $e->__toString());
+ else
+ $this->fault($e->getMessage());
+ }
+ }
+
+ /**
+ * Generate a SOAP fault message.
+ * @param string message title
+ * @param mixed message details
+ * @param string message code, defalt is 'SERVER'.
+ * @param string actors
+ * @param string message name
+ */
+ public function fault($title, $details='', $code='SERVER', $actor='', $name='')
+ {
+ Prado::trace('SOAP-Fault '.$code. ' '.$title.' : '.$details, 'System.Web.Services.TSoapService');
+ $this->_server->fault($code, $title, $actor, $details, $name);
+ }
+
+ /**
+ * Guess the SOAP method request from the actual SOAP message
+ *
+ * @param string $class current handler class.
+ */
+ protected function guessMethodCallRequested($class)
+ {
+ $namespace = $class.'wsdl';
+ $message = file_get_contents("php://input");
+ $matches= array();
+ if(preg_match('/xmlns:([^=]+)="urn:'.$namespace.'"/', $message, $matches))
+ {
+ if(preg_match('/<'.$matches[1].':([a-zA-Z_]+[a-zA-Z0-9_]+)/', $message, $method))
+ {
+ $this->_requestedMethod = $method[1];
+ }
+ }
+ }
+
+ /**
+ * Soap method guessed from the SOAP message received.
+ * @return string soap method request, null if not found.
+ */
+ public function getRequestedMethod()
+ {
+ return $this->_requestedMethod;
+ }
+
+ /**
+ * Creates the SoapServer instance.
+ * @return SoapServer
+ */
+ protected function createServer()
+ {
+ if($this->_server===null)
+ {
+ if($this->getApplication()->getMode()===TApplicationMode::Debug)
+ ini_set("soap.wsdl_cache_enabled",0);
+ $this->_server = new SoapServer($this->getWsdlUri(),$this->getOptions());
+ }
+ return $this->_server;
+ }
+
+ /**
+ * @return array options for creating SoapServer instance
+ */
+ protected function getOptions()
+ {
+ $options=array();
+ if($this->_version==='1.1')
+ $options['soap_version']=SOAP_1_1;
+ else if($this->_version==='1.2')
+ $options['soap_version']=SOAP_1_2;
+ if(!empty($this->_actor))
+ $options['actor']=$this->_actor;
+ if(!empty($this->_encoding))
+ $options['encoding']=$this->_encoding;
+ if(!empty($this->_uri))
+ $options['uri']=$this->_uri;
+ if(is_string($this->_classMap))
+ {
+ foreach(preg_split('/\s*,\s*/', $this->_classMap) as $className)
+ $options['classmap'][$className]=$className; //complex type uses the class name in the wsdl
+ }
+ return $options;
+ }
+
+ /**
+ * Returns the WSDL content of the SOAP server.
+ * If {@link getWsdlUri WsdlUri} is set, its content will be returned.
+ * If not, the {@link setProvider Provider} class will be investigated
+ * and the WSDL will be automatically genearted.
+ * @return string the WSDL content of the SOAP server
+ */
+ public function getWsdl()
+ {
+ if($this->_wsdlUri==='')
+ {
+ $provider=$this->getProvider();
+ $providerClass=($pos=strrpos($provider,'.'))!==false?substr($provider,$pos+1):$provider;
+ Prado::using($provider);
+ if($this->getApplication()->getMode()===TApplicationMode::Performance && ($cache=$this->getApplication()->getCache())!==null)
+ {
+ $wsdl=$cache->get(self::WSDL_CACHE_PREFIX.$providerClass);
+ if(is_string($wsdl))
+ return $wsdl;
+ Prado::using('System.3rdParty.WsdlGen.WsdlGenerator');
+ $wsdl=WsdlGenerator::generate($providerClass, $this->getUri(), $this->getEncoding());
+ $cache->set(self::WSDL_CACHE_PREFIX.$providerClass,$wsdl);
+ return $wsdl;
+ }
+ else
+ {
+ Prado::using('System.3rdParty.WsdlGen.WsdlGenerator');
+ return WsdlGenerator::generate($providerClass, $this->getUri(), $this->getEncoding());
+ }
+ }
+ else
+ return file_get_contents($this->_wsdlUri);
+ }
+
+ /**
+ * @return string the URI for WSDL
+ */
+ public function getWsdlUri()
+ {
+ if($this->_wsdlUri==='')
+ return $this->getRequest()->getBaseUrl().$this->getService()->constructUrl($this->getID().'.wsdl',false);
+ else
+ return $this->_wsdlUri;
+ }
+
+ /**
+ * @param string the URI for WSDL
+ */
+ public function setWsdlUri($value)
+ {
+ $this->_wsdlUri=$value;
+ }
+
+ /**
+ * @return string the URI for the SOAP service
+ */
+ public function getUri()
+ {
+ if($this->_uri==='')
+ return $this->getRequest()->getBaseUrl().$this->getService()->constructUrl($this->getID(),false);
+ else
+ return $this->_uri;
+ }
+
+ /**
+ * @param string the URI for the SOAP service
+ */
+ public function setUri($uri)
+ {
+ $this->_uri=$uri;
+ }
+
+ /**
+ * @return string the SOAP provider class (in namespace format)
+ */
+ public function getProvider()
+ {
+ return $this->_provider;
+ }
+
+ /**
+ * @param string the SOAP provider class (in namespace format)
+ */
+ public function setProvider($provider)
+ {
+ $this->_provider=$provider;
+ }
+
+ /**
+ * @return string SOAP version, defaults to empty (meaning not set).
+ */
+ public function getVersion()
+ {
+ return $this->_version;
+ }
+
+ /**
+ * @param string SOAP version, either '1.1' or '1.2'
+ * @throws TInvalidDataValueException if neither '1.1' nor '1.2'
+ */
+ public function setVersion($value)
+ {
+ if($value==='1.1' || $value==='1.2' || $value==='')
+ $this->_version=$value;
+ else
+ throw new TInvalidDataValueException('soapserver_version_invalid',$value);
+ }
+
+ /**
+ * @return string actor of the SOAP service
+ */
+ public function getActor()
+ {
+ return $this->_actor;
+ }
+
+ /**
+ * @param string actor of the SOAP service
+ */
+ public function setActor($value)
+ {
+ $this->_actor=$value;
+ }
+
+ /**
+ * @return string encoding of the SOAP service
+ */
+ public function getEncoding()
+ {
+ return $this->_encoding;
+ }
+
+ /**
+ * @param string encoding of the SOAP service
+ */
+ public function setEncoding($value)
+ {
+ $this->_encoding=$value;
+ }
+
+ /**
+ * @return boolean whether the SOAP service is persistent within session. Defaults to false.
+ */
+ public function getSessionPersistent()
+ {
+ return $this->_persistent;
+ }
+
+ /**
+ * @param boolean whether the SOAP service is persistent within session.
+ */
+ public function setSessionPersistent($value)
+ {
+ $this->_persistent=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return string comma delimit list of complex type classes.
+ */
+ public function getClassMaps()
+ {
+ return $this->_classMap;
+ }
+
+ /**
+ * @return string comma delimit list of class names
+ */
+ public function setClassMaps($classes)
+ {
+ $this->_classMap = $classes;
+ }
+}
+
diff --git a/lib/prado/framework/Web/TAssetManager.php b/lib/prado/framework/Web/TAssetManager.php
new file mode 100644
index 0000000..d84ca56
--- /dev/null
+++ b/lib/prado/framework/Web/TAssetManager.php
@@ -0,0 +1,354 @@
+<?php
+/**
+ * TAssetManager class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web
+ */
+
+/**
+ * TAssetManager class
+ *
+ * TAssetManager provides a scheme to allow web clients visiting
+ * private files that are normally web-inaccessible.
+ *
+ * TAssetManager will copy the file to be published into a web-accessible
+ * directory. The default base directory for storing the file is "assets", which
+ * should be under the application directory. This can be changed by setting
+ * the {@link setBasePath BasePath} property together with the
+ * {@link setBaseUrl BaseUrl} property that refers to the URL for accessing the base path.
+ *
+ * By default, TAssetManager will not publish a file or directory if it already
+ * exists in the publishing directory and has an older modification time.
+ * If the application mode is set as 'Performance', the modification time check
+ * will be skipped. You can explicitly require a modification time check
+ * with the function {@link publishFilePath}. This is usually
+ * very useful during development.
+ *
+ * TAssetManager may be configured in application configuration file as follows,
+ * <code>
+ * <module id="asset" BasePath="Application.assets" BaseUrl="/assets" />
+ * </code>
+ * where {@link getBasePath BasePath} and {@link getBaseUrl BaseUrl} are
+ * configurable properties of TAssetManager. Make sure that BasePath is a namespace
+ * pointing to a valid directory writable by the Web server process.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web
+ * @since 3.0
+ */
+class TAssetManager extends TModule
+{
+ /**
+ * Default web accessible base path for storing private files
+ */
+ const DEFAULT_BASEPATH='assets';
+ /**
+ * @var string base web accessible path for storing private files
+ */
+ private $_basePath=null;
+ /**
+ * @var string base URL for accessing the publishing directory.
+ */
+ private $_baseUrl=null;
+ /**
+ * @var boolean whether to use timestamp checking to ensure files are published with up-to-date versions.
+ */
+ private $_checkTimestamp=false;
+ /**
+ * @var TApplication application instance
+ */
+ private $_application;
+ /**
+ * @var array published assets
+ */
+ private $_published=array();
+ /**
+ * @var boolean whether the module is initialized
+ */
+ private $_initialized=false;
+
+ /**
+ * Initializes the module.
+ * This method is required by IModule and is invoked by application.
+ * @param TXmlElement module configuration
+ */
+ public function init($config)
+ {
+ $application=$this->getApplication();
+ if($this->_basePath===null)
+ $this->_basePath=dirname($application->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
+ if(!is_writable($this->_basePath) || !is_dir($this->_basePath))
+ throw new TConfigurationException('assetmanager_basepath_invalid',$this->_basePath);
+ if($this->_baseUrl===null)
+ $this->_baseUrl=rtrim(dirname($application->getRequest()->getApplicationUrl()),'/\\').'/'.self::DEFAULT_BASEPATH;
+ $application->setAssetManager($this);
+ $this->_initialized=true;
+ }
+
+ /**
+ * @return string the root directory storing published asset files
+ */
+ public function getBasePath()
+ {
+ return $this->_basePath;
+ }
+
+ /**
+ * Sets the root directory storing published asset files.
+ * The directory must be in namespace format.
+ * @param string the root directory storing published asset files
+ * @throws TInvalidOperationException if the module is initialized already
+ */
+ public function setBasePath($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('assetmanager_basepath_unchangeable');
+ else
+ {
+ $this->_basePath=Prado::getPathOfNamespace($value);
+ if($this->_basePath===null || !is_dir($this->_basePath) || !is_writable($this->_basePath))
+ throw new TInvalidDataValueException('assetmanager_basepath_invalid',$value);
+ }
+ }
+
+ /**
+ * @return string the base url that the published asset files can be accessed
+ */
+ public function getBaseUrl()
+ {
+ return $this->_baseUrl;
+ }
+
+ /**
+ * @param string the base url that the published asset files can be accessed
+ * @throws TInvalidOperationException if the module is initialized already
+ */
+ public function setBaseUrl($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('assetmanager_baseurl_unchangeable');
+ else
+ $this->_baseUrl=rtrim($value,'/');
+ }
+
+ /**
+ * Publishes a file or a directory (recursively).
+ * This method will copy the content in a directory (recursively) to
+ * a web accessible directory and returns the URL for the directory.
+ * If the application is not in performance mode, the file modification
+ * time will be used to make sure the published file is latest or not.
+ * If not, a file copy will be performed.
+ * @param string the path to be published
+ * @param boolean If true, file modification time will be checked even if the application
+ * is in performance mode.
+ * @return string an absolute URL to the published directory
+ * @throws TInvalidDataValueException if the file path to be published is
+ * invalid
+ */
+ public function publishFilePath($path,$checkTimestamp=false)
+ {
+ if(isset($this->_published[$path]))
+ return $this->_published[$path];
+ else if(empty($path) || ($fullpath=realpath($path))===false)
+ throw new TInvalidDataValueException('assetmanager_filepath_invalid',$path);
+ else if(is_file($fullpath))
+ {
+ $dir=$this->hash(dirname($fullpath));
+ $fileName=basename($fullpath);
+ $dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
+ if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
+ $this->copyFile($fullpath,$dst);
+ return $this->_published[$path]=$this->_baseUrl.'/'.$dir.'/'.$fileName;
+ }
+ else
+ {
+ $dir=$this->hash($fullpath);
+ if(!is_dir($this->_basePath.DIRECTORY_SEPARATOR.$dir) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
+ {
+ Prado::trace("Publishing directory $fullpath",'System.Web.UI.TAssetManager');
+ $this->copyDirectory($fullpath,$this->_basePath.DIRECTORY_SEPARATOR.$dir);
+ }
+ return $this->_published[$path]=$this->_baseUrl.'/'.$dir;
+ }
+ }
+
+ /**
+ * @return array List of published assets
+ * @since 3.1.6
+ */
+ public function getPublished()
+ {
+ return $this->_published;
+ }
+
+ /**
+ * @param $values List of published assets
+ * @since 3.1.6
+ */
+ protected function setPublished($values=array())
+ {
+ $this->_published = $values;
+ }
+
+ /**
+ * Returns the published path of a file path.
+ * This method does not perform any publishing. It merely tells you
+ * if the file path is published, where it will go.
+ * @param string directory or file path being published
+ * @return string the published file path
+ */
+ public function getPublishedPath($path)
+ {
+ $path=realpath($path);
+ if(is_file($path))
+ return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash(dirname($path)).DIRECTORY_SEPARATOR.basename($path);
+ else
+ return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash($path);
+ }
+
+ /**
+ * Returns the URL of a published file path.
+ * This method does not perform any publishing. It merely tells you
+ * if the file path is published, what the URL will be to access it.
+ * @param string directory or file path being published
+ * @return string the published URL for the file path
+ */
+ public function getPublishedUrl($path)
+ {
+ $path=realpath($path);
+ if(is_file($path))
+ return $this->_baseUrl.'/'.$this->hash(dirname($path)).'/'.basename($path);
+ else
+ return $this->_baseUrl.'/'.$this->hash($path);
+ }
+
+ /**
+ * Generate a CRC32 hash for the directory path. Collisions are higher
+ * than MD5 but generates a much smaller hash string.
+ * @param string string to be hashed.
+ * @return string hashed string.
+ */
+ protected function hash($dir)
+ {
+ return sprintf('%x',crc32($dir.Prado::getVersion()));
+ }
+
+ /**
+ * Copies a file to a directory.
+ * Copying is done only when the destination file does not exist
+ * or has an older file modification time.
+ * @param string source file path
+ * @param string destination directory (if not exists, it will be created)
+ */
+ protected function copyFile($src,$dst)
+ {
+ if(!is_dir($dst))
+ {
+ @mkdir($dst);
+ @chmod($dst, PRADO_CHMOD);
+ }
+ $dstFile=$dst.DIRECTORY_SEPARATOR.basename($src);
+ if(@filemtime($dstFile)<@filemtime($src))
+ {
+ Prado::trace("Publishing file $src to $dstFile",'System.Web.TAssetManager');
+ @copy($src,$dstFile);
+ }
+ }
+
+ /**
+ * Copies a directory recursively as another.
+ * If the destination directory does not exist, it will be created.
+ * File modification time is used to ensure the copied files are latest.
+ * @param string the source directory
+ * @param string the destination directory
+ * @todo a generic solution to ignore certain directories and files
+ */
+ public function copyDirectory($src,$dst)
+ {
+ if(!is_dir($dst))
+ {
+ @mkdir($dst);
+ @chmod($dst, PRADO_CHMOD);
+ }
+ if($folder=@opendir($src))
+ {
+ while($file=@readdir($folder))
+ {
+ if($file==='.' || $file==='..' || $file==='.svn')
+ continue;
+ else if(is_file($src.DIRECTORY_SEPARATOR.$file))
+ {
+ if(@filemtime($dst.DIRECTORY_SEPARATOR.$file)<@filemtime($src.DIRECTORY_SEPARATOR.$file))
+ {
+ @copy($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
+ @chmod($dst.DIRECTORY_SEPARATOR.$file, PRADO_CHMOD);
+ }
+ }
+ else
+ $this->copyDirectory($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
+ }
+ closedir($folder);
+ } else {
+ throw new TInvalidDataValueException('assetmanager_source_directory_invalid', $src);
+ }
+ }
+
+ /**
+ * Publish a tar file by extracting its contents to the assets directory.
+ * Each tar file must be accomplished with its own MD5 check sum file.
+ * The MD5 file is published when the tar contents are successfully
+ * extracted to the assets directory. The presence of the MD5 file
+ * as published asset assumes that the tar file has already been extracted.
+ * @param string tar filename
+ * @param string MD5 checksum for the corresponding tar file.
+ * @param boolean Wether or not to check the time stamp of the file for publishing. Defaults to false.
+ * @return string URL path to the directory where the tar file was extracted.
+ */
+ public function publishTarFile($tarfile, $md5sum, $checkTimestamp=false)
+ {
+ if(isset($this->_published[$md5sum]))
+ return $this->_published[$md5sum];
+ else if(($fullpath=realpath($md5sum))===false || !is_file($fullpath))
+ throw new TInvalidDataValueException('assetmanager_tarchecksum_invalid',$md5sum);
+ else
+ {
+ $dir=$this->hash(dirname($fullpath));
+ $fileName=basename($fullpath);
+ $dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
+ if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
+ {
+ if(@filemtime($dst.DIRECTORY_SEPARATOR.$fileName)<@filemtime($fullpath))
+ {
+ $this->copyFile($fullpath,$dst);
+ $this->deployTarFile($tarfile,$dst);
+ }
+ }
+ return $this->_published[$md5sum]=$this->_baseUrl.'/'.$dir;
+ }
+ }
+
+ /**
+ * Extracts the tar file to the destination directory.
+ * N.B Tar file must not be compressed.
+ * @param string tar file
+ * @param string path where the contents of tar file are to be extracted
+ * @return boolean true if extract successful, false otherwise.
+ */
+ protected function deployTarFile($path,$destination)
+ {
+ if(($fullpath=realpath($path))===false || !is_file($fullpath))
+ throw new TIOException('assetmanager_tarfile_invalid',$path);
+ else
+ {
+ Prado::using('System.IO.TTarFileExtractor');
+ $tar = new TTarFileExtractor($fullpath);
+ return $tar->extract($destination);
+ }
+ }
+
+}
+
diff --git a/lib/prado/framework/Web/TCacheHttpSession.php b/lib/prado/framework/Web/TCacheHttpSession.php
new file mode 100644
index 0000000..604eef4
--- /dev/null
+++ b/lib/prado/framework/Web/TCacheHttpSession.php
@@ -0,0 +1,148 @@
+<?php
+/**
+ * TCacheHttpSession class
+ *
+ * @author Carl G. Mathisen <carlgmathisen@gmail.com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web
+ * @since 3.1.1
+ */
+
+/**
+ * TCacheHttpSession class
+ *
+ * TCacheHttpSession provides access for storing session data using a cache module (e.g. TMemCache, TDbCache).
+ * To specify the cache module for data storage, set the {@link setCacheModuleID CacheModuleID} property
+ * which should refer to a valid cache module configured in the application configuration.
+ *
+ * The following example shows how we configure TCacheHttpSession:
+ * <code>
+ * <modules>
+ * <module id="cache" class="System.Caching.TMemCache" Host="localhost" Port="11211" />
+ * <module id="session" class="System.Web.TCacheHttpSession"
+ * CacheModuleID="cache" SessionName="SSID"
+ * CookieMode="Allow" AutoStart="true" GCProbability="1"
+ * UseTransparentSessionID="true" TimeOut="3600" />
+ * </modules>
+ * </code>
+ *
+ * Beware, by definition cache storage are volatile, which means the data stored on them
+ * may be swapped out and get lost. This may not be the case for certain cache storage,
+ * such as database. So make sure you manage your cache properly to avoid loss of session data.
+ *
+ * @author Carl G. Mathisen <carlgmathisen@gmail.com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web
+ * @since 3.1.1
+ */
+class TCacheHttpSession extends THttpSession
+{
+ private $_prefix='session';
+ private $_cacheModuleID='';
+ private $_cache;
+
+ /**
+ * Initializes the module.
+ * This method is required by IModule.
+ * It reads the CacheModule property.
+ * @param TXmlElement module configuration
+ */
+ public function init($config)
+ {
+ if($this->_cacheModuleID==='')
+ throw new TConfigurationException('cachesession_cachemoduleid_required');
+ else if(($cache=$this->getApplication()->getModule($this->_cacheModuleID))===null)
+ throw new TConfigurationException('cachesession_cachemodule_inexistent',$this->_cacheModuleID);
+ else if($cache instanceof ICache)
+ $this->_cache=$cache;
+ else
+ throw new TConfigurationException('cachesession_cachemodule_invalid',$this->_cacheModuleID);
+ $this->setUseCustomStorage(true);
+ parent::init($config);
+ }
+
+ /**
+ * @return string the ID of the cache module.
+ */
+ public function getCacheModuleID()
+ {
+ return $this->_cacheModuleID;
+ }
+
+ /**
+ * @param string the ID of the cache module.
+ */
+ public function setCacheModuleID($value)
+ {
+ $this->_cacheModuleID=$value;
+ }
+
+ /**
+ * @return ICache the cache module being used for data storage
+ */
+ public function getCache()
+ {
+ return $this->_cache;
+ }
+
+ /**
+ * Session read handler.
+ * @param string session ID
+ * @return string the session data
+ */
+ public function _read($id)
+ {
+ return $this->_cache->get($this->calculateKey($id));
+ }
+
+ /**
+ * Session write handler.
+ * @param string session ID
+ * @param string session data
+ * @return boolean whether session write is successful
+ */
+ public function _write($id,$data)
+ {
+ return $this->_cache->set($this->calculateKey($id),$data,$this->getTimeout());
+ }
+
+ /**
+ * Session destroy handler.
+ * This method should be overriden if {@link setUseCustomStorage UseCustomStorage} is set true.
+ * @param string session ID
+ * @return boolean whether session is destroyed successfully
+ */
+ public function _destroy($id)
+ {
+ return $this->_cache->delete($this->calculateKey($id));
+ }
+
+ /**
+ * @return string prefix of session variable name to avoid conflict with other cache data. Defaults to 'session'.
+ */
+ public function getKeyPrefix()
+ {
+ return $this->_prefix;
+ }
+
+ /**
+ * @param string prefix of session variable name to avoid conflict with other cache data
+ */
+ public function setKeyPrefix($value)
+ {
+ $this->_prefix=$value;
+ }
+
+ /**
+ * @param string session variable name
+ * @return string a safe cache key associated with the session variable name
+ */
+ protected function calculateKey($id)
+ {
+ return $this->_prefix.':'.$id;
+ }
+}
+
diff --git a/lib/prado/framework/Web/THttpRequest.php b/lib/prado/framework/Web/THttpRequest.php
new file mode 100644
index 0000000..f89c354
--- /dev/null
+++ b/lib/prado/framework/Web/THttpRequest.php
@@ -0,0 +1,1406 @@
+<?php
+/**
+ * THttpRequest, THttpCookie, THttpCookieCollection, TUri class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web
+ */
+
+Prado::using('System.Web.TUrlManager');
+
+/**
+ * THttpRequest class
+ *
+ * THttpRequest provides storage and access scheme for user request sent via HTTP.
+ * It also encapsulates a uniform way to parse and construct URLs.
+ *
+ * User post data can be retrieved from THttpRequest by using it like an associative array.
+ * For example, to test if a user supplies a variable named 'param1', you can use,
+ * <code>
+ * if(isset($request['param1'])) ...
+ * // equivalent to:
+ * // if($request->contains('param1')) ...
+ * </code>
+ * To get the value of 'param1', use,
+ * <code>
+ * $value=$request['param1'];
+ * // equivalent to:
+ * // $value=$request->itemAt('param1');
+ * </code>
+ * To traverse the user post data, use
+ * <code>
+ * foreach($request as $name=>$value) ...
+ * </code>
+ * Note, POST and GET variables are merged together in THttpRequest.
+ * If a variable name appears in both POST and GET data, then POST data
+ * takes precedence.
+ *
+ * To construct a URL that can be recognized by Prado, use {@link constructUrl()}.
+ * The format of the recognizable URLs is determined according to
+ * {@link setUrlManager UrlManager}. By default, the following two formats
+ * are recognized:
+ * <code>
+ * /index.php?ServiceID=ServiceParameter&Name1=Value1&Name2=Value2
+ * /index.php/ServiceID,ServiceParameter/Name1,Value1/Name2,Value2
+ * </code>
+ * The first format is called 'Get' while the second 'Path', which is specified
+ * via {@link setUrlFormat UrlFormat}. For advanced users who want to use
+ * their own URL formats, they can write customized URL management modules
+ * and install the managers as application modules and set {@link setUrlManager UrlManager}.
+ *
+ * The ServiceID in the above URLs is as defined in the application configuration
+ * (e.g. the default page service's service ID is 'page').
+ * As a consequence, your GET variable names should not conflict with the service
+ * IDs that your application supports.
+ *
+ * THttpRequest also provides the cookies sent by the user, user information such
+ * as his browser capabilities, accepted languages, etc.
+ *
+ * By default, THttpRequest is registered with {@link TApplication} as the
+ * request module. It can be accessed via {@link TApplication::getRequest()}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web
+ * @since 3.0
+ */
+class THttpRequest extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
+{
+ const CGIFIX__PATH_INFO = 1;
+ const CGIFIX__SCRIPT_NAME = 2;
+ /**
+ * @var TUrlManager the URL manager module
+ */
+ private $_urlManager=null;
+ /**
+ * @var string the ID of the URL manager module
+ */
+ private $_urlManagerID='';
+ /**
+ * @var string Separator used to separate GET variable name and value when URL format is Path.
+ */
+ private $_separator=',';
+ /**
+ * @var string requested service ID
+ */
+ private $_serviceID=null;
+ /**
+ * @var string requested service parameter
+ */
+ private $_serviceParam=null;
+ /**
+ * @var THttpCookieCollection cookies sent from user
+ */
+ private $_cookies=null;
+ /**
+ * @var string requested URI (URL w/o host info)
+ */
+ private $_requestUri;
+ /**
+ * @var string path info of URL
+ */
+ private $_pathInfo;
+ /**
+ * @var boolean whether the session ID should be kept in cookie only
+ */
+ private $_cookieOnly=null;
+ private $_urlFormat=THttpRequestUrlFormat::Get;
+ private $_services;
+ private $_requestResolved=false;
+ private $_enableCookieValidation=false;
+ private $_cgiFix=0;
+ /**
+ * @var boolean whether to cache the TUrlManager class (useful with a lot of TUrlMappings)
+ */
+ private $_enableCache=false;
+ /**
+ * @var string request URL
+ */
+ private $_url=null;
+
+ /**
+ * @var string module id
+ */
+ private $_id;
+
+ /**
+ * @var array contains all request variables
+ */
+ private $_items=array();
+
+ /**
+ * @return string id of this module
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * @param string id of this module
+ */
+ public function setID($value)
+ {
+ $this->_id=$value;
+ }
+
+ /**
+ * Initializes the module.
+ * This method is required by IModule and is invoked by application.
+ * @param TXmlElement module configuration
+ */
+ public function init($config)
+ {
+ // Fill in default request info when the script is run in command line
+ if(php_sapi_name()==='cli')
+ {
+ $_SERVER['REMOTE_ADDR']='127.0.0.1';
+ $_SERVER['REQUEST_METHOD']='GET';
+ $_SERVER['SERVER_NAME']='localhost';
+ $_SERVER['SERVER_PORT']=80;
+ $_SERVER['HTTP_USER_AGENT']='';
+ }
+
+ // Info about server variables:
+ // PHP_SELF contains real URI (w/ path info, w/o query string)
+ // SCRIPT_NAME is the real URI for the requested script (w/o path info and query string)
+ // QUERY_STRING is the string following the '?' in the ur (eg the a=x part in http://foo/bar?a=x)
+ // REQUEST_URI contains the URI part entered in the browser address bar
+ // SCRIPT_FILENAME is the file path to the executing script
+ if(isset($_SERVER['REQUEST_URI']))
+ $this->_requestUri=$_SERVER['REQUEST_URI'];
+ else // TBD: in this case, SCRIPT_NAME need to be escaped
+ $this->_requestUri=$_SERVER['SCRIPT_NAME'].(empty($_SERVER['QUERY_STRING'])?'':'?'.$_SERVER['QUERY_STRING']);
+
+ if($this->_cgiFix&self::CGIFIX__PATH_INFO && isset($_SERVER['ORIG_PATH_INFO']))
+ $this->_pathInfo=substr($_SERVER['ORIG_PATH_INFO'], strlen($_SERVER['SCRIPT_NAME']));
+ elseif(isset($_SERVER['PATH_INFO']))
+ $this->_pathInfo=$_SERVER['PATH_INFO'];
+ else if(strpos($_SERVER['PHP_SELF'],$_SERVER['SCRIPT_NAME'])===0 && $_SERVER['PHP_SELF']!==$_SERVER['SCRIPT_NAME'])
+ $this->_pathInfo=substr($_SERVER['PHP_SELF'],strlen($_SERVER['SCRIPT_NAME']));
+ else
+ $this->_pathInfo='';
+
+ if(get_magic_quotes_gpc())
+ {
+ if(isset($_GET))
+ $_GET=$this->stripSlashes($_GET);
+ if(isset($_POST))
+ $_POST=$this->stripSlashes($_POST);
+ if(isset($_REQUEST))
+ $_REQUEST=$this->stripSlashes($_REQUEST);
+ if(isset($_COOKIE))
+ $_COOKIE=$this->stripSlashes($_COOKIE);
+ }
+
+ $this->getApplication()->setRequest($this);
+ }
+
+ /**
+ * Strips slashes from input data.
+ * This method is applied when magic quotes is enabled.
+ * @param mixed input data to be processed
+ * @return mixed processed data
+ */
+ public function stripSlashes(&$data)
+ {
+ return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data);
+ }
+
+ /**
+ * @return TUri the request URL
+ */
+ public function getUrl()
+ {
+ if($this->_url===null)
+ {
+ $secure=$this->getIsSecureConnection();
+ $url=$secure?'https://':'http://';
+ if(empty($_SERVER['HTTP_HOST']))
+ {
+ $url.=$_SERVER['SERVER_NAME'];
+ $port=$_SERVER['SERVER_PORT'];
+ if(($port!=80 && !$secure) || ($port!=443 && $secure))
+ $url.=':'.$port;
+ }
+ else
+ $url.=$_SERVER['HTTP_HOST'];
+ $url.=$this->getRequestUri();
+ $this->_url=new TUri($url);
+ }
+ return $this->_url;
+ }
+
+ /**
+ * Set true to cache the UrlManager instance. Consider to enable this cache
+ * when the application defines a lot of TUrlMappingPatterns
+ * @param boolean true to cache urlmanager instance.
+ */
+ public function setEnableCache($value)
+ {
+ $this->_enableCache = TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean true if urlmanager instance should be cached, false otherwise.
+ */
+ public function getEnableCache()
+ {
+ return $this->_enableCache;
+ }
+
+ protected function getCacheKey()
+ {
+ return $this->getID();
+ }
+
+ /**
+ * Saves the current UrlManager instance to cache.
+ * @return boolean true if UrlManager instance was cached, false otherwise.
+ */
+ protected function cacheUrlManager($manager)
+ {
+ if($this->getEnableCache())
+ {
+ $cache = $this->getApplication()->getCache();
+ if($cache !== null)
+ {
+ $dependencies = null;
+ if($this->getApplication()->getMode() !== TApplicationMode::Performance)
+ if ($manager instanceof TUrlMapping && $fn = $manager->getConfigFile())
+ {
+ $fn = Prado::getPathOfNamespace($fn,$this->getApplication()->getConfigurationFileExt());
+ $dependencies = new TFileCacheDependency($fn);
+ }
+ return $cache->set($this->getCacheKey(), $manager, 0, $dependencies);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Loads UrlManager instance from cache.
+ * @return TUrlManager intance if load was successful, null otherwise.
+ */
+ protected function loadCachedUrlManager()
+ {
+ if($this->getEnableCache())
+ {
+ $cache = $this->getApplication()->getCache();
+ if($cache !== null)
+ {
+ $manager = $cache->get($this->getCacheKey());
+ if($manager instanceof TUrlManager)
+ return $manager;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @return string the ID of the URL manager module
+ */
+ public function getUrlManager()
+ {
+ return $this->_urlManagerID;
+ }
+
+ /**
+ * Sets the URL manager module.
+ * By default, {@link TUrlManager} is used for managing URLs.
+ * You may specify a different module for URL managing tasks
+ * by loading it as an application module and setting this property
+ * with the module ID.
+ * @param string the ID of the URL manager module
+ */
+ public function setUrlManager($value)
+ {
+ $this->_urlManagerID=$value;
+ }
+
+ /**
+ * @return TUrlManager the URL manager module
+ */
+ public function getUrlManagerModule()
+ {
+ if($this->_urlManager===null)
+ {
+ if(($this->_urlManager = $this->loadCachedUrlManager())===null)
+ {
+ if(empty($this->_urlManagerID))
+ {
+ $this->_urlManager=new TUrlManager;
+ $this->_urlManager->init(null);
+ }
+ else
+ {
+ $this->_urlManager=$this->getApplication()->getModule($this->_urlManagerID);
+ if($this->_urlManager===null)
+ throw new TConfigurationException('httprequest_urlmanager_inexist',$this->_urlManagerID);
+ if(!($this->_urlManager instanceof TUrlManager))
+ throw new TConfigurationException('httprequest_urlmanager_invalid',$this->_urlManagerID);
+ }
+ $this->cacheUrlManager($this->_urlManager);
+ }
+ }
+ return $this->_urlManager;
+ }
+
+ /**
+ * @return THttpRequestUrlFormat the format of URLs. Defaults to THttpRequestUrlFormat::Get.
+ */
+ public function getUrlFormat()
+ {
+ return $this->_urlFormat;
+ }
+
+ /**
+ * Sets the format of URLs constructed and interpretted by the request module.
+ * A Get URL format is like index.php?name1=value1&name2=value2
+ * while a Path URL format is like index.php/name1,value1/name2,value.
+ * Changing the UrlFormat will affect {@link constructUrl} and how GET variables
+ * are parsed.
+ * @param THttpRequestUrlFormat the format of URLs.
+ */
+ public function setUrlFormat($value)
+ {
+ $this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat');
+ }
+
+ /**
+ * @return string separator used to separate GET variable name and value when URL format is Path. Defaults to comma ','.
+ */
+ public function getUrlParamSeparator()
+ {
+ return $this->_separator;
+ }
+
+ /**
+ * @param string separator used to separate GET variable name and value when URL format is Path.
+ * @throws TInvalidDataValueException if the separator is not a single character
+ */
+ public function setUrlParamSeparator($value)
+ {
+ if(strlen($value)===1)
+ $this->_separator=$value;
+ else
+ throw new TInvalidDataValueException('httprequest_separator_invalid');
+ }
+
+ /**
+ * @return string request type, can be GET, POST, HEAD, or PUT
+ */
+ public function getRequestType()
+ {
+ return isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:null;
+ }
+
+ /**
+ * @param boolean $mimetypeOnly whether to return only the mimetype (default: true)
+ * @return string content type (e.g. 'application/json' or 'text/html; encoding=gzip') or null if not specified
+ */
+ public function getContentType($mimetypeOnly = true)
+ {
+ if(!isset($_SERVER['CONTENT_TYPE']))
+ return null;
+
+ if($mimetypeOnly === true && ($_pos = strpos(';', $_SERVER['CONTENT_TYPE'])) !== false)
+ return substr($_SERVER['CONTENT_TYPE'], 0, $_pos);
+
+ return $_SERVER['CONTENT_TYPE'];
+ }
+
+ /**
+ * @return boolean if the request is sent via secure channel (https)
+ */
+ public function getIsSecureConnection()
+ {
+ return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'],'off');
+ }
+
+ /**
+ * @return string part of the request URL after script name and before question mark.
+ */
+ public function getPathInfo()
+ {
+ return $this->_pathInfo;
+ }
+
+ /**
+ * @return string part of that request URL after the question mark
+ */
+ public function getQueryString()
+ {
+ return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:null;
+ }
+
+ /**
+ * @return string the requested http procolol. Blank string if not defined.
+ */
+ public function getHttpProtocolVersion()
+ {
+ return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:null;
+ }
+
+ /**
+ * @param integer|null Either {@link CASE_UPPER} or {@link CASE_LOWER} or as is null (default)
+ * @return array
+ */
+ public function getHeaders($case=null)
+ {
+ static $result;
+
+ if($result === null && function_exists('apache_request_headers')) {
+ $result = apache_request_headers();
+ }
+ elseif($result === null) {
+ $result = array();
+ foreach($_SERVER as $key=>$value) {
+ if(strncasecmp($key, 'HTTP_', 5) !== 0) continue;
+ $key = str_replace(' ','-', ucwords(strtolower(str_replace('_',' ', substr($key, 5)))));
+ $result[$key] = $value;
+ }
+ }
+
+ if($case !== null)
+ return array_change_key_case($result, $case);
+
+ return $result;
+ }
+
+ /**
+ * @return string part of that request URL after the host info (including pathinfo and query string)
+ */
+ public function getRequestUri()
+ {
+ return $this->_requestUri;
+ }
+
+ /**
+ * @param boolean|null whether to use HTTPS instead of HTTP even if the current request is sent via HTTP or vice versa
+ * null - keep current schema
+ * true - force https
+ * false - force http
+ * @return string schema and hostname of the requested URL
+ */
+ public function getBaseUrl($forceSecureConnection=null)
+ {
+ $url=$this->getUrl();
+ $scheme=($forceSecureConnection)?"https": (($forceSecureConnection === null)?$url->getScheme():'http');
+ $host=$url->getHost();
+ if (($port=$url->getPort())) $host.=':'.$port;
+ return $scheme.'://'.$host;
+ }
+
+ /**
+ * @return string entry script URL (w/o host part)
+ */
+ public function getApplicationUrl()
+ {
+ if($this->_cgiFix&self::CGIFIX__SCRIPT_NAME && isset($_SERVER['ORIG_SCRIPT_NAME']))
+ return $_SERVER['ORIG_SCRIPT_NAME'];
+
+ return isset($_SERVER['SCRIPT_NAME'])?$_SERVER['SCRIPT_NAME']:null;
+ }
+
+ /**
+ * @param boolean|null whether to use HTTPS instead of HTTP even if the current request is sent via HTTP or vice versa
+ * null - keep current schema
+ * true - force https
+ * false - force http
+ * @return string entry script URL (w/ host part)
+ */
+ public function getAbsoluteApplicationUrl($forceSecureConnection=null)
+ {
+ return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl();
+ }
+
+ /**
+ * @return string application entry script file path (processed w/ realpath())
+ */
+ public function getApplicationFilePath()
+ {
+ return realpath(isset($_SERVER['SCRIPT_FILENAME'])?$_SERVER['SCRIPT_FILENAME']:null);
+ }
+
+ /**
+ * @return string server name
+ */
+ public function getServerName()
+ {
+ return isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:null;
+ }
+
+ /**
+ * @return integer server port number
+ */
+ public function getServerPort()
+ {
+ return isset($_SERVER['SERVER_PORT'])?$_SERVER['SERVER_PORT']:null;
+ }
+
+ /**
+ * @return string URL referrer, null if not present
+ */
+ public function getUrlReferrer()
+ {
+ return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null;
+ }
+
+ /**
+ * @return array user browser capabilities
+ * @see get_browser
+ */
+ public function getBrowser()
+ {
+ try
+ {
+ return get_browser();
+ }
+ catch(TPhpErrorException $e)
+ {
+ throw new TConfigurationException('httprequest_browscap_required');
+ }
+ }
+
+ /**
+ * @return string user agent
+ */
+ public function getUserAgent()
+ {
+ return isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:null;
+ }
+
+ /**
+ * @return string user IP address
+ */
+ public function getUserHostAddress()
+ {
+ return isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:null;
+ }
+
+ /**
+ * @return string user host name, null if cannot be determined
+ */
+ public function getUserHost()
+ {
+ return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
+ }
+
+ /**
+ * @return string user browser accept types
+ */
+ public function getAcceptTypes()
+ {
+ // TBD: break it into array??
+ return isset($_SERVER['HTTP_ACCEPT'])?$_SERVER['HTTP_ACCEPT']:null;
+ }
+
+ /**
+ * Returns a list of user preferred languages.
+ * The languages are returned as an array. Each array element
+ * represents a single language preference. The languages are ordered
+ * according to user preferences. The first language is the most preferred.
+ * @return array list of user preferred languages.
+ */
+ public function getUserLanguages()
+ {
+ return Prado::getUserLanguages();
+ }
+
+ /**
+ * @return boolean whether cookies should be validated. Defaults to false.
+ */
+ public function getEnableCookieValidation()
+ {
+ return $this->_enableCookieValidation;
+ }
+
+ /**
+ * @param boolean whether cookies should be validated.
+ */
+ public function setEnableCookieValidation($value)
+ {
+ $this->_enableCookieValidation=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return integer whether to use ORIG_PATH_INFO and/or ORIG_SCRIPT_NAME. Defaults to 0.
+ * @see THttpRequest::CGIFIX__PATH_INFO, THttpRequest::CGIFIX__SCRIPT_NAME
+ */
+ public function getCgiFix()
+ {
+ return $this->_cgiFix;
+ }
+
+ /**
+ * Enable this, if you're using PHP via CGI with php.ini setting "cgi.fix_pathinfo=1"
+ * and have trouble with friendly URL feature. Enable this only if you really know what you are doing!
+ * @param integer enable bitwise to use ORIG_PATH_INFO and/or ORIG_SCRIPT_NAME.
+ * @see THttpRequest::CGIFIX__PATH_INFO, THttpRequest::CGIFIX__SCRIPT_NAME
+ */
+ public function setCgiFix($value)
+ {
+ $this->_cgiFix=TPropertyValue::ensureInteger($value);
+ }
+
+ /**
+ * @return THttpCookieCollection list of cookies to be sent
+ */
+ public function getCookies()
+ {
+ if($this->_cookies===null)
+ {
+ $this->_cookies=new THttpCookieCollection;
+ if($this->getEnableCookieValidation())
+ {
+ $sm=$this->getApplication()->getSecurityManager();
+ foreach($_COOKIE as $key=>$value)
+ {
+ if(($value=$sm->validateData($value))!==false)
+ $this->_cookies->add(new THttpCookie($key,$value));
+ }
+ }
+ else
+ {
+ foreach($_COOKIE as $key=>$value)
+ $this->_cookies->add(new THttpCookie($key,$value));
+ }
+ }
+ return $this->_cookies;
+ }
+
+ /**
+ * @return array list of uploaded files.
+ */
+ public function getUploadedFiles()
+ {
+ return $_FILES;
+ }
+
+ /**
+ * @return array list of server variables.
+ */
+ public function getServerVariables()
+ {
+ return $_SERVER;
+ }
+
+ /**
+ * @return array list of environment variables.
+ */
+ public function getEnvironmentVariables()
+ {
+ return $_ENV;
+ }
+
+ /**
+ * Constructs a URL that can be recognized by PRADO.
+ * The actual construction work is done by the URL manager module.
+ * This method may append session information to the generated URL if needed.
+ * You may provide your own URL manager module by setting {@link setUrlManager UrlManager}
+ * to provide your own URL scheme.
+ *
+ * Note, the constructed URL does not contain the protocol and hostname part.
+ * You may obtain an absolute URL by prepending the constructed URL with {@link getBaseUrl BaseUrl}.
+ * @param string service ID
+ * @param string service parameter
+ * @param array GET parameters, null if not needed
+ * @param boolean whether to encode the ampersand in URL, defaults to true.
+ * @param boolean whether to encode the GET parameters (their names and values), defaults to false.
+ * @return string URL
+ * @see TUrlManager::constructUrl
+ */
+ public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true)
+ {
+ if ($this->_cookieOnly===null)
+ $this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies');
+ $url=$this->getUrlManagerModule()->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems);
+ if(defined('SID') && SID != '' && !$this->_cookieOnly)
+ return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&amp;':'&')) . SID;
+ else
+ return $url;
+ }
+
+ /**
+ * Parses the request URL and returns an array of input parameters (excluding GET variables).
+ * You may override this method to support customized URL format.
+ * @return array list of input parameters, indexed by parameter names
+ * @see TUrlManager::parseUrl
+ */
+ protected function parseUrl()
+ {
+ return $this->getUrlManagerModule()->parseUrl();
+ }
+
+ /**
+ * Resolves the requested service.
+ * This method implements a URL-based service resolution.
+ * A URL in the format of /index.php?sp=serviceID.serviceParameter
+ * will be resolved with the serviceID and the serviceParameter.
+ * You may override this method to provide your own way of service resolution.
+ * @param array list of valid service IDs
+ * @return string the currently requested service ID, null if no service ID is found
+ * @see constructUrl
+ */
+ public function resolveRequest($serviceIDs)
+ {
+ Prado::trace("Resolving request from ".$_SERVER['REMOTE_ADDR'],'System.Web.THttpRequest');
+ $getParams=$this->parseUrl();
+ foreach($getParams as $name=>$value)
+ $_GET[$name]=$value;
+ $this->_items=array_merge($_GET,$_POST);
+ $this->_requestResolved=true;
+ foreach($serviceIDs as $serviceID)
+ {
+ if($this->contains($serviceID))
+ {
+ $this->setServiceID($serviceID);
+ $this->setServiceParameter($this->itemAt($serviceID));
+ return $serviceID;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @return boolean true if request is already resolved, false otherwise.
+ */
+ public function getRequestResolved()
+ {
+ return $this->_requestResolved;
+ }
+
+ /**
+ * @return string requested service ID
+ */
+ public function getServiceID()
+ {
+ return $this->_serviceID;
+ }
+
+ /**
+ * Sets the requested service ID.
+ * @param string requested service ID
+ */
+ public function setServiceID($value)
+ {
+ $this->_serviceID=$value;
+ }
+
+ /**
+ * @return string requested service parameter
+ */
+ public function getServiceParameter()
+ {
+ return $this->_serviceParam;
+ }
+
+ /**
+ * Sets the requested service parameter.
+ * @param string requested service parameter
+ */
+ public function setServiceParameter($value)
+ {
+ $this->_serviceParam=$value;
+ }
+
+ //------ The following methods enable THttpRequest to be TMap-like -----
+
+ /**
+ * Returns an iterator for traversing the items in the list.
+ * This method is required by the interface IteratorAggregate.
+ * @return Iterator an iterator for traversing the items in the list.
+ */
+ public function getIterator()
+ {
+ return new TMapIterator($this->_items);
+ }
+
+ /**
+ * @return integer the number of items in the request
+ */
+ public function getCount()
+ {
+ return count($this->_items);
+ }
+
+ /**
+ * Returns the number of items in the request.
+ * This method is required by Countable interface.
+ * @return integer number of items in the request.
+ */
+ public function count()
+ {
+ return $this->getCount();
+ }
+
+ /**
+ * @return array the key list
+ */
+ public function getKeys()
+ {
+ return array_keys($this->_items);
+ }
+
+ /**
+ * Returns the item with the specified key.
+ * This method is exactly the same as {@link offsetGet}.
+ * @param mixed the key
+ * @return mixed the element at the offset, null if no element is found at the offset
+ */
+ public function itemAt($key)
+ {
+ return isset($this->_items[$key]) ? $this->_items[$key] : null;
+ }
+
+ /**
+ * Adds an item into the request.
+ * Note, if the specified key already exists, the old value will be overwritten.
+ * @param mixed key
+ * @param mixed value
+ */
+ public function add($key,$value)
+ {
+ $this->_items[$key]=$value;
+ }
+
+ /**
+ * Removes an item from the request by its key.
+ * @param mixed the key of the item to be removed
+ * @return mixed the removed value, null if no such key exists.
+ * @throws TInvalidOperationException if the item cannot be removed
+ */
+ public function remove($key)
+ {
+ if(isset($this->_items[$key]) || array_key_exists($key,$this->_items))
+ {
+ $value=$this->_items[$key];
+ unset($this->_items[$key]);
+ return $value;
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Removes all items in the request.
+ */
+ public function clear()
+ {
+ foreach(array_keys($this->_items) as $key)
+ $this->remove($key);
+ }
+
+ /**
+ * @param mixed the key
+ * @return boolean whether the request contains an item with the specified key
+ */
+ public function contains($key)
+ {
+ return isset($this->_items[$key]) || array_key_exists($key,$this->_items);
+ }
+
+ /**
+ * @return array the list of items in array
+ */
+ public function toArray()
+ {
+ return $this->_items;
+ }
+
+ /**
+ * Returns whether there is an element at the specified offset.
+ * This method is required by the interface ArrayAccess.
+ * @param mixed the offset to check on
+ * @return boolean
+ */
+ public function offsetExists($offset)
+ {
+ return $this->contains($offset);
+ }
+
+ /**
+ * Returns the element at the specified offset.
+ * This method is required by the interface ArrayAccess.
+ * @param integer the offset to retrieve element.
+ * @return mixed the element at the offset, null if no element is found at the offset
+ */
+ public function offsetGet($offset)
+ {
+ return $this->itemAt($offset);
+ }
+
+ /**
+ * Sets the element at the specified offset.
+ * This method is required by the interface ArrayAccess.
+ * @param integer the offset to set element
+ * @param mixed the element value
+ */
+ public function offsetSet($offset,$item)
+ {
+ $this->add($offset,$item);
+ }
+
+ /**
+ * Unsets the element at the specified offset.
+ * This method is required by the interface ArrayAccess.
+ * @param mixed the offset to unset element
+ */
+ public function offsetUnset($offset)
+ {
+ $this->remove($offset);
+ }
+}
+
+/**
+ * THttpCookieCollection class.
+ *
+ * THttpCookieCollection implements a collection class to store cookies.
+ * Besides using all functionalities from {@link TList}, you can also
+ * retrieve a cookie by its name using either {@link findCookieByName} or
+ * simply:
+ * <code>
+ * $cookie=$collection[$cookieName];
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web
+ * @since 3.0
+ */
+class THttpCookieCollection extends TList
+{
+ /**
+ * @var mixed owner of this collection
+ */
+ private $_o;
+
+ /**
+ * Constructor.
+ * @param mixed owner of this collection.
+ */
+ public function __construct($owner=null)
+ {
+ $this->_o=$owner;
+ }
+
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing additional
+ * operations for each newly added THttpCookie object.
+ * @param integer the specified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a THttpCookie object.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof THttpCookie)
+ {
+ parent::insertAt($index,$item);
+ if($this->_o instanceof THttpResponse)
+ $this->_o->addCookie($item);
+ }
+ else
+ throw new TInvalidDataTypeException('httpcookiecollection_httpcookie_required');
+ }
+
+ /**
+ * Removes an item at the specified position.
+ * This overrides the parent implementation by performing additional
+ * cleanup work when removing a TCookie object.
+ * @param integer the index of the item to be removed.
+ * @return mixed the removed item.
+ */
+ public function removeAt($index)
+ {
+ $item=parent::removeAt($index);
+ if($this->_o instanceof THttpResponse)
+ $this->_o->removeCookie($item);
+ return $item;
+ }
+
+ /**
+ * @param integer|string index of the cookie in the collection or the cookie's name
+ * @return THttpCookie the cookie found
+ */
+ public function itemAt($index)
+ {
+ if(is_integer($index))
+ return parent::itemAt($index);
+ else
+ return $this->findCookieByName($index);
+ }
+
+ /**
+ * Finds the cookie with the specified name.
+ * @param string the name of the cookie to be looked for
+ * @return THttpCookie the cookie, null if not found
+ */
+ public function findCookieByName($name)
+ {
+ foreach($this as $cookie)
+ if($cookie->getName()===$name)
+ return $cookie;
+ return null;
+ }
+}
+
+/**
+ * THttpCookie class.
+ *
+ * A THttpCookie instance stores a single cookie, including the cookie name, value,
+ * domain, path, expire, and secure.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web
+ * @since 3.0
+ */
+class THttpCookie extends TComponent
+{
+ /**
+ * @var string domain of the cookie
+ */
+ private $_domain='';
+ /**
+ * @var string name of the cookie
+ */
+ private $_name;
+ /**
+ * @var string value of the cookie
+ */
+ private $_value='';
+ /**
+ * @var integer expire of the cookie
+ */
+ private $_expire=0;
+ /**
+ * @var string path of the cookie
+ */
+ private $_path='/';
+ /**
+ * @var boolean whether cookie should be sent via secure connection
+ */
+ private $_secure=false;
+ /**
+ * @var boolean if true the cookie value will be unavailable to JavaScript
+ */
+ private $_httpOnly=false;
+
+ /**
+ * Constructor.
+ * @param string name of this cookie
+ * @param string value of this cookie
+ */
+ public function __construct($name,$value)
+ {
+ $this->_name=$name;
+ $this->_value=$value;
+ }
+
+ /**
+ * @return string the domain to associate the cookie with
+ */
+ public function getDomain()
+ {
+ return $this->_domain;
+ }
+
+ /**
+ * @param string the domain to associate the cookie with
+ */
+ public function setDomain($value)
+ {
+ $this->_domain=$value;
+ }
+
+ /**
+ * @return integer the time the cookie expires. This is a Unix timestamp so is in number of seconds since the epoch.
+ */
+ public function getExpire()
+ {
+ return $this->_expire;
+ }
+
+ /**
+ * @param integer the time the cookie expires. This is a Unix timestamp so is in number of seconds since the epoch.
+ */
+ public function setExpire($value)
+ {
+ $this->_expire=TPropertyValue::ensureInteger($value);
+ }
+
+ /**
+ * @return boolean if true the cookie value will be unavailable to JavaScript
+ */
+ public function getHttpOnly()
+ {
+ return $this->_httpOnly;
+ }
+
+ /**
+ * @param boolean $value if true the cookie value will be unavailable to JavaScript
+ */
+ public function setHttpOnly($value)
+ {
+ $this->_httpOnly = TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return string the name of the cookie
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @param string the name of the cookie
+ */
+ public function setName($value)
+ {
+ $this->_name=$value;
+ }
+
+ /**
+ * @return string the value of the cookie
+ */
+ public function getValue()
+ {
+ return $this->_value;
+ }
+
+ /**
+ * @param string the value of the cookie
+ */
+ public function setValue($value)
+ {
+ $this->_value=$value;
+ }
+
+ /**
+ * @return string the path on the server in which the cookie will be available on, default is '/'
+ */
+ public function getPath()
+ {
+ return $this->_path;
+ }
+
+ /**
+ * @param string the path on the server in which the cookie will be available on
+ */
+ public function setPath($value)
+ {
+ $this->_path=$value;
+ }
+
+ /**
+ * @return boolean whether the cookie should only be transmitted over a secure HTTPS connection
+ */
+ public function getSecure()
+ {
+ return $this->_secure;
+ }
+
+ /**
+ * @param boolean ether the cookie should only be transmitted over a secure HTTPS connection
+ */
+ public function setSecure($value)
+ {
+ $this->_secure=TPropertyValue::ensureBoolean($value);
+ }
+}
+
+/**
+ * TUri class
+ *
+ * TUri represents a URI. Given a URI
+ * http://joe:whatever@example.com:8080/path/to/script.php?param=value#anchor
+ * it will be decomposed as follows,
+ * - scheme: http
+ * - host: example.com
+ * - port: 8080
+ * - user: joe
+ * - password: whatever
+ * - path: /path/to/script.php
+ * - query: param=value
+ * - fragment: anchor
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web
+ * @since 3.0
+ */
+class TUri extends TComponent
+{
+ /**
+ * @var array list of default ports for known schemes
+ */
+ private static $_defaultPort=array(
+ 'ftp'=>21,
+ 'gopher'=>70,
+ 'http'=>80,
+ 'https'=>443,
+ 'news'=>119,
+ 'nntp'=>119,
+ 'wais'=>210,
+ 'telnet'=>23
+ );
+ /**
+ * @var string scheme of the URI
+ */
+ private $_scheme;
+ /**
+ * @var string host name of the URI
+ */
+ private $_host;
+ /**
+ * @var integer port of the URI
+ */
+ private $_port;
+ /**
+ * @var string user of the URI
+ */
+ private $_user;
+ /**
+ * @var string password of the URI
+ */
+ private $_pass;
+ /**
+ * @var string path of the URI
+ */
+ private $_path;
+ /**
+ * @var string query string of the URI
+ */
+ private $_query;
+ /**
+ * @var string fragment of the URI
+ */
+ private $_fragment;
+ /**
+ * @var string the URI
+ */
+ private $_uri;
+
+ /**
+ * Constructor.
+ * Decomposes the specified URI into parts.
+ * @param string URI to be represented
+ * @throws TInvalidDataValueException if URI is of bad format
+ */
+ public function __construct($uri)
+ {
+ if(($ret=@parse_url($uri))!==false)
+ {
+ // decoding???
+ $this->_scheme=isset($ret['scheme'])?$ret['scheme']:'';
+ $this->_host=isset($ret['host'])?$ret['host']:'';
+ $this->_port=isset($ret['port'])?$ret['port']:'';
+ $this->_user=isset($ret['user'])?$ret['user']:'';
+ $this->_pass=isset($ret['pass'])?$ret['pass']:'';
+ $this->_path=isset($ret['path'])?$ret['path']:'';
+ $this->_query=isset($ret['query'])?$ret['query']:'';
+ $this->_fragment=isset($ret['fragment'])?$ret['fragment']:'';
+ $this->_uri=$uri;
+ }
+ else
+ {
+ throw new TInvalidDataValueException('uri_format_invalid',$uri);
+ }
+ }
+
+ /**
+ * @return string URI
+ */
+ public function getUri()
+ {
+ return $this->_uri;
+ }
+
+ /**
+ * @return string scheme of the URI, such as 'http', 'https', 'ftp', etc.
+ */
+ public function getScheme()
+ {
+ return $this->_scheme;
+ }
+
+ /**
+ * @return string hostname of the URI
+ */
+ public function getHost()
+ {
+ return $this->_host;
+ }
+
+ /**
+ * @return integer port number of the URI
+ */
+ public function getPort()
+ {
+ return $this->_port;
+ }
+
+ /**
+ * @return string username of the URI
+ */
+ public function getUser()
+ {
+ return $this->_user;
+ }
+
+ /**
+ * @return string password of the URI
+ */
+ public function getPassword()
+ {
+ return $this->_pass;
+ }
+
+ /**
+ * @return string path of the URI
+ */
+ public function getPath()
+ {
+ return $this->_path;
+ }
+
+ /**
+ * @return string query string of the URI
+ */
+ public function getQuery()
+ {
+ return $this->_query;
+ }
+
+ /**
+ * @return string fragment of the URI
+ */
+ public function getFragment()
+ {
+ return $this->_fragment;
+ }
+}
+
+/**
+ * THttpRequestUrlFormat class.
+ * THttpRequestUrlFormat defines the enumerable type for the possible URL formats
+ * that can be recognized by {@link THttpRequest}.
+ *
+ * The following enumerable values are defined:
+ * - Get: the URL format is like /path/to/index.php?name1=value1&name2=value2...
+ * - Path: the URL format is like /path/to/index.php/name1,value1/name2,value2...
+ * - HiddenPath: the URL format is like /path/to/name1,value1/name2,value2...
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web
+ * @since 3.0.4
+ */
+class THttpRequestUrlFormat extends TEnumerable
+{
+ const Get='Get';
+ const Path='Path';
+ const HiddenPath='HiddenPath';
+}
+
diff --git a/lib/prado/framework/Web/THttpResponse.php b/lib/prado/framework/Web/THttpResponse.php
new file mode 100644
index 0000000..21e6410
--- /dev/null
+++ b/lib/prado/framework/Web/THttpResponse.php
@@ -0,0 +1,722 @@
+<?php
+/**
+ * THttpResponse class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web
+ */
+
+/**
+ * Includes the THttpResponse adapter.
+ */
+Prado::using('System.Web.THttpResponseAdapter');
+
+/**
+ * THttpResponse class
+ *
+ * THttpResponse implements the mechanism for sending output to client users.
+ *
+ * To output a string to client, use {@link write()}. By default, the output is
+ * buffered until {@link flush()} is called or the application ends. The output in
+ * the buffer can also be cleaned by {@link clear()}. To disable output buffering,
+ * set BufferOutput property to false.
+ *
+ * To send cookies to client, use {@link getCookies()}.
+ * To redirect client browser to a new URL, use {@link redirect()}.
+ * To send a file to client, use {@link writeFile()}.
+ *
+ * By default, THttpResponse is registered with {@link TApplication} as the
+ * response module. It can be accessed via {@link TApplication::getResponse()}.
+ *
+ * THttpResponse may be configured in application configuration file as follows
+ *
+ * <module id="response" class="System.Web.THttpResponse" CacheExpire="20" CacheControl="nocache" BufferOutput="true" />
+ *
+ * where {@link getCacheExpire CacheExpire}, {@link getCacheControl CacheControl}
+ * and {@link getBufferOutput BufferOutput} are optional properties of THttpResponse.
+ *
+ * THttpResponse sends charset header if either {@link setCharset() Charset}
+ * or {@link TGlobalization::setCharset() TGlobalization.Charset} is set.
+ *
+ * Since 3.1.2, HTTP status code can be set with the {@link setStatusCode StatusCode} property.
+ *
+ * Note: Some HTTP Status codes can require additional header or body information. So, if you use {@link setStatusCode StatusCode}
+ * in your application, be sure to add theses informations.
+ * E.g : to make an http authentication :
+ * <code>
+ * public function clickAuth ($sender, $param)
+ * {
+ * $response=$this->getResponse();
+ * $response->setStatusCode(401);
+ * $response->appendHeader('WWW-Authenticate: Basic realm="Test"');
+ * }
+ * </code>
+ *
+ * This event handler will sent the 401 status code (Unauthorized) to the browser, with the WWW-Authenticate header field. This
+ * will force the browser to ask for a username and a password.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web
+ * @since 3.0
+ */
+class THttpResponse extends TModule implements ITextWriter
+{
+ const DEFAULT_CONTENTTYPE = 'text/html';
+ const DEFAULT_CHARSET = 'UTF-8';
+
+ /**
+ * @var The differents defined status code by RFC 2616 {@link http://www.faqs.org/rfcs/rfc2616}
+ */
+ private static $HTTP_STATUS_CODES = array(
+ 100 => 'Continue', 101 => 'Switching Protocols',
+ 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
+ 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
+ 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed',
+ 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
+ );
+
+ /**
+ * @var boolean whether to buffer output
+ */
+ private $_bufferOutput=true;
+ /**
+ * @var boolean if the application is initialized
+ */
+ private $_initialized=false;
+ /**
+ * @var THttpCookieCollection list of cookies to return
+ */
+ private $_cookies=null;
+ /**
+ * @var integer response status code
+ */
+ private $_status=200;
+ /**
+ * @var string reason correspond to status code
+ */
+ private $_reason='OK';
+ /**
+ * @var string HTML writer type
+ */
+ private $_htmlWriterType='System.Web.UI.THtmlWriter';
+ /**
+ * @var string content type
+ */
+ private $_contentType=null;
+ /**
+ * @var string|boolean character set, e.g. UTF-8 or false if no character set should be send to client
+ */
+ private $_charset='';
+ /**
+ * @var THttpResponseAdapter adapter.
+ */
+ private $_adapter;
+ /**
+ * @var boolean whether http response header has been sent
+ */
+ private $_httpHeaderSent;
+ /**
+ * @var boolean whether content-type header has been sent
+ */
+ private $_contentTypeHeaderSent;
+
+ /**
+ * Destructor.
+ * Flushes any existing content in buffer.
+ */
+ public function __destruct()
+ {
+ //if($this->_bufferOutput)
+ // @ob_end_flush();
+ }
+
+ /**
+ * @param THttpResponseAdapter response adapter
+ */
+ public function setAdapter(THttpResponseAdapter $adapter)
+ {
+ $this->_adapter=$adapter;
+ }
+
+ /**
+ * @return THttpResponseAdapter response adapter, null if not exist.
+ */
+ public function getAdapter()
+ {
+ return $this->_adapter;
+ }
+
+ /**
+ * @return boolean true if adapter exists, false otherwise.
+ */
+ public function getHasAdapter()
+ {
+ return $this->_adapter!==null;
+ }
+
+ /**
+ * Initializes the module.
+ * This method is required by IModule and is invoked by application.
+ * It starts output buffer if it is enabled.
+ * @param TXmlElement module configuration
+ */
+ public function init($config)
+ {
+ if($this->_bufferOutput)
+ ob_start();
+ $this->_initialized=true;
+ $this->getApplication()->setResponse($this);
+ }
+
+ /**
+ * @return integer time-to-live for cached session pages in minutes, this has no effect for nocache limiter. Defaults to 180.
+ */
+ public function getCacheExpire()
+ {
+ return session_cache_expire();
+ }
+
+ /**
+ * @param integer time-to-live for cached session pages in minutes, this has no effect for nocache limiter.
+ */
+ public function setCacheExpire($value)
+ {
+ session_cache_expire(TPropertyValue::ensureInteger($value));
+ }
+
+ /**
+ * @return string cache control method to use for session pages
+ */
+ public function getCacheControl()
+ {
+ return session_cache_limiter();
+ }
+
+ /**
+ * @param string cache control method to use for session pages. Valid values
+ * include none/nocache/private/private_no_expire/public
+ */
+ public function setCacheControl($value)
+ {
+ session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public')));
+ }
+
+ /**
+ * @return string content type, default is text/html
+ */
+ public function setContentType($type)
+ {
+ if ($this->_contentTypeHeaderSent)
+ throw new Exception('Unable to alter content-type as it has been already sent');
+ $this->_contentType = $type;
+ }
+
+ /**
+ * @return string current content type
+ */
+ public function getContentType()
+ {
+ return $this->_contentType;
+ }
+
+ /**
+ * @return string|boolean output charset.
+ */
+ public function getCharset()
+ {
+ return $this->_charset;
+ }
+
+ /**
+ * @param string|boolean output charset.
+ */
+ public function setCharset($charset)
+ {
+ $this->_charset = (strToLower($charset) === 'false') ? false : (string)$charset;
+ }
+
+ /**
+ * @return boolean whether to enable output buffer
+ */
+ public function getBufferOutput()
+ {
+ return $this->_bufferOutput;
+ }
+
+ /**
+ * @param boolean whether to enable output buffer
+ * @throws TInvalidOperationException if session is started already
+ */
+ public function setBufferOutput($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable');
+ else
+ $this->_bufferOutput=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return integer HTTP status code, defaults to 200
+ */
+ public function getStatusCode()
+ {
+ return $this->_status;
+ }
+
+ /**
+ * Set the HTTP status code for the response.
+ * The code and its reason will be sent to client using the currently requested http protocol version (see {@link THttpRequest::getHttpProtocolVersion})
+ * Keep in mind that HTTP/1.0 clients might not understand all status codes from HTTP/1.1
+ *
+ * @param integer HTTP status code
+ * @param string HTTP status reason, defaults to standard HTTP reasons
+ */
+ public function setStatusCode($status, $reason=null)
+ {
+ if ($this->_httpHeaderSent)
+ throw new Exception('Unable to alter response as HTTP header already sent');
+ $status=TPropertyValue::ensureInteger($status);
+ if(isset(self::$HTTP_STATUS_CODES[$status])) {
+ $this->_reason=self::$HTTP_STATUS_CODES[$status];
+ }else{
+ if($reason===null || $reason==='') {
+ throw new TInvalidDataValueException("response_status_reason_missing");
+ }
+ $reason=TPropertyValue::ensureString($reason);
+ if(strpos($reason, "\r")!=false || strpos($reason, "\n")!=false) {
+ throw new TInvalidDataValueException("response_status_reason_barchars");
+ }
+ $this->_reason=$reason;
+ }
+ $this->_status=$status;
+ }
+
+ /**
+ * @param string HTTP status reason
+ */
+ public function getStatusReason() {
+ return $this->_reason;
+ }
+
+ /**
+ * @return THttpCookieCollection list of output cookies
+ */
+ public function getCookies()
+ {
+ if($this->_cookies===null)
+ $this->_cookies=new THttpCookieCollection($this);
+ return $this->_cookies;
+ }
+
+ /**
+ * Outputs a string.
+ * It may not be sent back to user immediately if output buffer is enabled.
+ * @param string string to be output
+ */
+ public function write($str)
+ {
+ // when starting output make sure we send the headers first
+ if (!$this->_bufferOutput and !$this->_httpHeaderSent)
+ $this->ensureHeadersSent();
+ echo $str;
+ }
+
+ /**
+ * Sends a file back to user.
+ * Make sure not to output anything else after calling this method.
+ * @param string file name
+ * @param string content to be set. If null, the content will be read from the server file pointed to by $fileName.
+ * @param string mime type of the content.
+ * @param array list of headers to be sent. Each array element represents a header string (e.g. 'Content-Type: text/plain').
+ * @param boolean force download of file, even if browser able to display inline. Defaults to 'true'.
+ * @param string force a specific file name on client side. Defaults to 'null' means auto-detect.
+ * @param integer size of file or content in bytes if already known. Defaults to 'null' means auto-detect.
+ * @throws TInvalidDataValueException if the file cannot be found
+ */
+ public function writeFile($fileName,$content=null,$mimeType=null,$headers=null,$forceDownload=true,$clientFileName=null,$fileSize=null)
+ {
+ static $defaultMimeTypes=array(
+ 'css'=>'text/css',
+ 'gif'=>'image/gif',
+ 'png'=>'image/png',
+ 'jpg'=>'image/jpeg',
+ 'jpeg'=>'image/jpeg',
+ 'htm'=>'text/html',
+ 'html'=>'text/html',
+ 'js'=>'javascript/js',
+ 'pdf'=>'application/pdf',
+ 'xls'=>'application/vnd.ms-excel',
+ );
+
+ if($mimeType===null)
+ {
+ $mimeType='text/plain';
+ if(function_exists('mime_content_type'))
+ $mimeType=mime_content_type($fileName);
+ else if(($ext=strrchr($fileName,'.'))!==false)
+ {
+ $ext=substr($ext,1);
+ if(isset($defaultMimeTypes[$ext]))
+ $mimeType=$defaultMimeTypes[$ext];
+ }
+ }
+
+ if($clientFileName===null)
+ $clientFileName=basename($fileName);
+ else
+ $clientFileName=basename($clientFileName);
+
+ if($fileSize===null || $fileSize < 0)
+ $fileSize = ($content===null?filesize($fileName):strlen($content));
+
+ $this->sendHttpHeader();
+ if(is_array($headers))
+ {
+ foreach($headers as $h)
+ header($h);
+ }
+ else
+ {
+ header('Pragma: public');
+ header('Expires: 0');
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+ header("Content-Type: $mimeType");
+ $this->_contentTypeHeaderSent = true;
+ }
+
+ header('Content-Length: '.$fileSize);
+ header("Content-Disposition: " . ($forceDownload ? 'attachment' : 'inline') . "; filename=\"$clientFileName\"");
+ header('Content-Transfer-Encoding: binary');
+ if($content===null)
+ readfile($fileName);
+ else
+ echo $content;
+ }
+
+ /**
+ * Redirects the browser to the specified URL.
+ * The current application will be terminated after this method is invoked.
+ * @param string URL to be redirected to. If the URL is a relative one, the base URL of
+ * the current request will be inserted at the beginning.
+ */
+ public function redirect($url)
+ {
+ if($this->getHasAdapter())
+ $this->_adapter->httpRedirect($url);
+ else
+ $this->httpRedirect($url);
+ }
+
+ /**
+ * Redirect the browser to another URL and exists the current application.
+ * This method is used internally. Please use {@link redirect} instead.
+ *
+ * @since 3.1.5
+ * You can set the set {@link setStatusCode StatusCode} to a value between 300 and 399 before
+ * calling this function to change the type of redirection.
+ * If not specified, StatusCode will be 302 (Found) by default
+ *
+ * @param string URL to be redirected to. If the URL is a relative one, the base URL of
+ * the current request will be inserted at the beginning.
+ */
+ public function httpRedirect($url)
+ {
+ $this->ensureHeadersSent();
+
+ if($url[0]==='/')
+ $url=$this->getRequest()->getBaseUrl().$url;
+ if ($this->_status >= 300 && $this->_status < 400)
+ // The status code has been modified to a valid redirection status, send it
+ header('Location: '.str_replace('&amp;','&',$url), true, $this->_status);
+ else
+ header('Location: '.str_replace('&amp;','&',$url));
+
+ if(!$this->getApplication()->getRequestCompleted())
+ $this->getApplication()->onEndRequest();
+
+ exit();
+ }
+
+ /**
+ * Reloads the current page.
+ * The effect of this method call is the same as user pressing the
+ * refresh button on his browser (without post data).
+ **/
+ public function reload()
+ {
+ $this->redirect($this->getRequest()->getRequestUri());
+ }
+
+ /**
+ * Flush the response contents and headers.
+ */
+ public function flush($continueBuffering = true)
+ {
+ if($this->getHasAdapter())
+ $this->_adapter->flushContent($continueBuffering);
+ else
+ $this->flushContent($continueBuffering);
+ }
+
+ /**
+ * Ensures that HTTP response and content-type headers are sent
+ */
+ public function ensureHeadersSent()
+ {
+ $this->ensureHttpHeaderSent();
+ $this->ensureContentTypeHeaderSent();
+ }
+
+ /**
+ * Outputs the buffered content, sends content-type and charset header.
+ * This method is used internally. Please use {@link flush} instead.
+ * @param boolean whether to continue buffering after flush if buffering was active
+ */
+ public function flushContent($continueBuffering = true)
+ {
+ Prado::trace("Flushing output",'System.Web.THttpResponse');
+ $this->ensureHeadersSent();
+ if($this->_bufferOutput)
+ {
+ // avoid forced send of http headers (ob_flush() does that) if there's no output yet
+ if (ob_get_length()>0)
+ {
+ if (!$continueBuffering)
+ {
+ $this->_bufferOutput = false;
+ ob_end_flush();
+ }
+ else
+ ob_flush();
+ flush();
+ }
+ }
+ else
+ flush();
+ }
+
+ /**
+ * Ensures that the HTTP header with the status code and status reason are sent
+ */
+ protected function ensureHttpHeaderSent()
+ {
+ if (!$this->_httpHeaderSent)
+ $this->sendHttpHeader();
+ }
+
+ /**
+ * Send the HTTP header with the status code (defaults to 200) and status reason (defaults to OK)
+ */
+ protected function sendHttpHeader()
+ {
+ $protocol=$this->getRequest()->getHttpProtocolVersion();
+ if($this->getRequest()->getHttpProtocolVersion() === null)
+ $protocol='HTTP/1.1';
+
+ $phpSapiName = substr(php_sapi_name(), 0, 3);
+ $cgi = $phpSapiName == 'cgi' || $phpSapiName == 'fpm';
+
+ header(($cgi ? 'Status:' : $protocol).' '.$this->_status.' '.$this->_reason, true, TPropertyValue::ensureInteger($this->_status));
+
+ $this->_httpHeaderSent = true;
+ }
+
+ /**
+ * Ensures that the HTTP header with the status code and status reason are sent
+ */
+ protected function ensureContentTypeHeaderSent()
+ {
+ if (!$this->_contentTypeHeaderSent)
+ $this->sendContentTypeHeader();
+ }
+
+ /**
+ * Sends content type header with optional charset.
+ */
+ protected function sendContentTypeHeader()
+ {
+ $contentType=$this->_contentType===null?self::DEFAULT_CONTENTTYPE:$this->_contentType;
+ $charset=$this->getCharset();
+ if($charset === false) {
+ $this->appendHeader('Content-Type: '.$contentType);
+ return;
+ }
+
+ if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)
+ $charset=$globalization->getCharset();
+
+ if($charset==='') $charset = self::DEFAULT_CHARSET;
+ $this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
+
+ $this->_contentTypeHeaderSent = true;
+ }
+
+ /**
+ * Returns the content in the output buffer.
+ * The buffer will NOT be cleared after calling this method.
+ * Use {@link clear()} is you want to clear the buffer.
+ * @return string output that is in the buffer.
+ */
+ public function getContents()
+ {
+ Prado::trace("Retrieving output",'System.Web.THttpResponse');
+ return $this->_bufferOutput?ob_get_contents():'';
+ }
+
+ /**
+ * Clears any existing buffered content.
+ */
+ public function clear()
+ {
+ if($this->_bufferOutput)
+ ob_clean();
+ Prado::trace("Clearing output",'System.Web.THttpResponse');
+ }
+
+ /**
+ * @param integer|null Either {@link CASE_UPPER} or {@link CASE_LOWER} or as is null (default)
+ * @return array
+ */
+ public function getHeaders($case=null)
+ {
+ $result = array();
+ $headers = headers_list();
+ foreach($headers as $header) {
+ $tmp = explode(':', $header);
+ $key = trim(array_shift($tmp));
+ $value = trim(implode(':', $tmp));
+ if(isset($result[$key]))
+ $result[$key] .= ', ' . $value;
+ else
+ $result[$key] = $value;
+ }
+
+ if($case !== null)
+ return array_change_key_case($result, $case);
+
+ return $result;
+ }
+
+ /**
+ * Sends a header.
+ * @param string header
+ * @param boolean whether the header should replace a previous similar header, or add a second header of the same type
+ */
+ public function appendHeader($value, $replace=true)
+ {
+ Prado::trace("Sending header '$value'",'System.Web.THttpResponse');
+ header($value, $replace);
+ }
+
+ /**
+ * Writes a log message into error log.
+ * This method is simple wrapper of PHP function error_log.
+ * @param string The error message that should be logged
+ * @param integer where the error should go
+ * @param string The destination. Its meaning depends on the message parameter as described above
+ * @param string The extra headers. It's used when the message parameter is set to 1. This message type uses the same internal function as mail() does.
+ * @see http://us2.php.net/manual/en/function.error-log.php
+ */
+ public function appendLog($message,$messageType=0,$destination='',$extraHeaders='')
+ {
+ error_log($message,$messageType,$destination,$extraHeaders);
+ }
+
+ /**
+ * Sends a cookie.
+ * Do not call this method directly. Operate with the result of {@link getCookies} instead.
+ * @param THttpCookie cook to be sent
+ */
+ public function addCookie($cookie)
+ {
+ $request=$this->getRequest();
+ if($request->getEnableCookieValidation())
+ {
+ $value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue());
+ setcookie(
+ $cookie->getName(),
+ $value,
+ $cookie->getExpire(),
+ $cookie->getPath(),
+ $cookie->getDomain(),
+ $cookie->getSecure(),
+ $cookie->getHttpOnly()
+ );
+ }
+ else {
+ setcookie(
+ $cookie->getName(),
+ $cookie->getValue(),
+ $cookie->getExpire(),
+ $cookie->getPath(),
+ $cookie->getDomain(),
+ $cookie->getSecure(),
+ $cookie->getHttpOnly()
+ );
+ }
+ }
+
+ /**
+ * Deletes a cookie.
+ * Do not call this method directly. Operate with the result of {@link getCookies} instead.
+ * @param THttpCookie cook to be deleted
+ */
+ public function removeCookie($cookie)
+ {
+ setcookie(
+ $cookie->getName(),
+ null,
+ 0,
+ $cookie->getPath(),
+ $cookie->getDomain(),
+ $cookie->getSecure(),
+ $cookie->getHttpOnly()
+ );
+ }
+
+ /**
+ * @return string the type of HTML writer to be used, defaults to THtmlWriter
+ */
+ public function getHtmlWriterType()
+ {
+ return $this->_htmlWriterType;
+ }
+
+ /**
+ * @param string the type of HTML writer to be used, may be the class name or the namespace
+ */
+ public function setHtmlWriterType($value)
+ {
+ $this->_htmlWriterType=$value;
+ }
+
+ /**
+ * Creates a new instance of HTML writer.
+ * If the type of the HTML writer is not supplied, {@link getHtmlWriterType HtmlWriterType} will be assumed.
+ * @param string type of the HTML writer to be created. If null, {@link getHtmlWriterType HtmlWriterType} will be assumed.
+ */
+ public function createHtmlWriter($type=null)
+ {
+ if($type===null)
+ $type=$this->getHtmlWriterType();
+ if($this->getHasAdapter())
+ return $this->_adapter->createNewHtmlWriter($type, $this);
+ else
+ return $this->createNewHtmlWriter($type, $this);
+ }
+
+ /**
+ * Create a new html writer instance.
+ * This method is used internally. Please use {@link createHtmlWriter} instead.
+ * @param string type of HTML writer to be created.
+ * @param ITextWriter text writer holding the contents.
+ */
+ public function createNewHtmlWriter($type, $writer)
+ {
+ return Prado::createComponent($type, $writer);
+ }
+}
+
diff --git a/lib/prado/framework/Web/THttpResponseAdapter.php b/lib/prado/framework/Web/THttpResponseAdapter.php
new file mode 100644
index 0000000..7f87590
--- /dev/null
+++ b/lib/prado/framework/Web/THttpResponseAdapter.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * THttpResponseAdatper class
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @version $Id$
+ * @package System.Web
+ */
+
+/**
+ * THttpResponseAdapter class.
+ *
+ * THttpResponseAdapter allows the base http response class to change behavior
+ * without change the class hierarchy.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web
+ * @since 3.0
+ */
+class THttpResponseAdapter extends TApplicationComponent
+{
+ /**
+ * @var THttpResponse the response object the adapter is attached.
+ */
+ private $_response;
+
+ /**
+ * Constructor. Attach a response to be adapted.
+ * @param THttpResponse the response object the adapter is to attach to.
+ */
+ public function __construct($response)
+ {
+ $this->_response=$response;
+ }
+
+ /**
+ * @return THttpResponse the response object adapted.
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * This method is invoked when the response flushes the content and headers.
+ * Default implementation calls the attached response flushContent method.
+ */
+ public function flushContent()
+ {
+ $this->_response->flushContent();
+ }
+
+ /**
+ * This method is invoked when the response is to redirect to another page.
+ * @param string new url to redirect to.
+ */
+ public function httpRedirect($url)
+ {
+ $this->_response->httpRedirect($url);
+ }
+
+ /**
+ * This method is invoked when a new HtmlWriter needs to be created.
+ * Default implementation calls the attached response createNewHtmlWriter method.
+ * @param string type of the HTML writer to be created.
+ * @param ITextWriter the writer responsible for holding the content.
+ */
+ public function createNewHtmlWriter($type, $writer)
+ {
+ return $this->_response->createNewHtmlWriter($type,$writer);
+ }
+}
+
diff --git a/lib/prado/framework/Web/THttpSession.php b/lib/prado/framework/Web/THttpSession.php
new file mode 100644
index 0000000..50d11b1
--- /dev/null
+++ b/lib/prado/framework/Web/THttpSession.php
@@ -0,0 +1,737 @@
+<?php
+/**
+ * THttpSession class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web
+ */
+
+/**
+ * THttpSession class
+ *
+ * THttpSession provides session-level data management and the related configurations.
+ * To start the session, call {@link open}; to complete and send out session data, call {@link close};
+ * to destroy the session, call {@link destroy}. If AutoStart is true, then the session
+ * will be started once the session module is loaded and initialized.
+ *
+ * To access data stored in session, use THttpSession like an associative array. For example,
+ * <code>
+ * $session=new THttpSession;
+ * $session->open();
+ * $value1=$session['name1']; // get session variable 'name1'
+ * $value2=$session['name2']; // get session variable 'name2'
+ * foreach($session as $name=>$value) // traverse all session variables
+ * $session['name3']=$value3; // set session variable 'name3'
+ * </code>
+ *
+ * The following configurations are available for session:
+ * {@link setAutoStart AutoStart}, {@link setCookieMode CookieMode},
+ * {@link setSavePath SavePath},
+ * {@link setUseCustomStorage UseCustomStorage}, {@link setGCProbability GCProbability},
+ * {@link setTimeout Timeout}.
+ * See the corresponding setter and getter documentation for more information.
+ * Note, these properties must be set before the session is started.
+ *
+ * THttpSession can be inherited with customized session storage method.
+ * Override {@link _open}, {@link _close}, {@link _read}, {@link _write}, {@link _destroy} and {@link _gc}
+ * and set {@link setUseCustomStorage UseCustomStorage} to true.
+ * Then, the session data will be stored using the above methods.
+ *
+ * By default, THttpSession is registered with {@link TApplication} as the
+ * request module. It can be accessed via {@link TApplication::getSession()}.
+ *
+ * THttpSession may be configured in application configuration file as follows,
+ * <code>
+ * <module id="session" class="THttpSession" SessionName="SSID" SavePath="/tmp"
+ * CookieMode="Allow" UseCustomStorage="false" AutoStart="true" GCProbability="1"
+ * UseTransparentSessionID="true" TimeOut="3600" />
+ * </code>
+ * where {@link getSessionName SessionName}, {@link getSavePath SavePath},
+ * {@link getCookieMode CookieMode}, {@link getUseCustomStorage
+ * UseCustomStorage}, {@link getAutoStart AutoStart}, {@link getGCProbability
+ * GCProbability}, {@link getUseTransparentSessionID UseTransparentSessionID}
+ * and {@link getTimeout TimeOut} are configurable properties of THttpSession.
+ *
+ * To avoid the possibility of identity theft through some variants of XSS attacks,
+ * THttpSessionshould always be configured to enforce HttpOnly setting on session cookie.
+ * The HttpOnly setting is disabled by default. To enable it, configure the THttpSession
+ * module as follows,
+ * <code>
+ * <module id="session" class="THttpSession" Cookie.HttpOnly="true" >
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web
+ * @since 3.0
+ */
+class THttpSession extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
+{
+ /**
+ * @var boolean whether this module has been initialized
+ */
+ private $_initialized=false;
+ /**
+ * @var boolean whether the session has started
+ */
+ private $_started=false;
+ /**
+ * @var boolean whether the session should be started when the module is initialized
+ */
+ private $_autoStart=false;
+ /**
+ * @var THttpCookie cookie to be used to store session ID and other data
+ */
+ private $_cookie=null;
+ /**
+ * @var string module id
+ */
+ private $_id;
+ /**
+ * @var boolean
+ */
+ private $_customStorage=false;
+
+ /**
+ * @return string id of this module
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * @param string id of this module
+ */
+ public function setID($value)
+ {
+ $this->_id=$value;
+ }
+
+ /**
+ * Initializes the module.
+ * This method is required by IModule.
+ * If AutoStart is true, the session will be started.
+ * @param TXmlElement module configuration
+ */
+ public function init($config)
+ {
+ if($this->_autoStart)
+ $this->open();
+ $this->_initialized=true;
+ $this->getApplication()->setSession($this);
+ register_shutdown_function(array($this, "close"));
+ }
+
+ /**
+ * Starts the session if it has not started yet.
+ */
+ public function open()
+ {
+ if(!$this->_started)
+ {
+ if($this->_customStorage)
+ session_set_save_handler(array($this,'_open'),array($this,'_close'),array($this,'_read'),array($this,'_write'),array($this,'_destroy'),array($this,'_gc'));
+ if($this->_cookie!==null)
+ session_set_cookie_params($this->_cookie->getExpire(),$this->_cookie->getPath(),$this->_cookie->getDomain(),$this->_cookie->getSecure(),$this->_cookie->getHttpOnly());
+ if(ini_get('session.auto_start')!=='1')
+ session_start();
+ $this->_started=true;
+ }
+ }
+
+ /**
+ * Ends the current session and store session data.
+ */
+ public function close()
+ {
+ if($this->_started)
+ {
+ session_write_close();
+ $this->_started=false;
+ }
+ }
+
+ /**
+ * Destroys all data registered to a session.
+ */
+ public function destroy()
+ {
+ if($this->_started)
+ {
+ session_destroy();
+ $this->_started=false;
+ }
+ }
+
+ /**
+ * Update the current session id with a newly generated one
+ *
+ * @param boolean $deleteOld Whether to delete the old associated session or not.
+ * @return string old session id
+ * @link http://php.net/manual/en/function.session-regenerate-id.php
+ */
+ public function regenerate($deleteOld=false)
+ {
+ $old = $this->getSessionID();
+ session_regenerate_id($deleteOld);
+ return $old;
+ }
+
+ /**
+ * @return boolean whether the session has started
+ */
+ public function getIsStarted()
+ {
+ return $this->_started;
+ }
+
+ /**
+ * @return string the current session ID
+ */
+ public function getSessionID()
+ {
+ return session_id();
+ }
+
+ /**
+ * @param string the session ID for the current session
+ * @throws TInvalidOperationException if session is started already
+ */
+ public function setSessionID($value)
+ {
+ if($this->_started)
+ throw new TInvalidOperationException('httpsession_sessionid_unchangeable');
+ else
+ session_id($value);
+ }
+
+ /**
+ * @return string the current session name
+ */
+ public function getSessionName()
+ {
+ return session_name();
+ }
+
+ /**
+ * @param string the session name for the current session, must be an alphanumeric string, defaults to PHPSESSID
+ * @throws TInvalidOperationException if session is started already
+ */
+ public function setSessionName($value)
+ {
+ if($this->_started)
+ throw new TInvalidOperationException('httpsession_sessionname_unchangeable');
+ else if(ctype_alnum($value))
+ session_name($value);
+ else
+ throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value);
+ }
+
+ /**
+ * @return string the current session save path, defaults to '/tmp'.
+ */
+ public function getSavePath()
+ {
+ return session_save_path();
+ }
+
+ /**
+ * @param string the current session save path
+ * @throws TInvalidOperationException if session is started already
+ */
+ public function setSavePath($value)
+ {
+ if($this->_started)
+ throw new TInvalidOperationException('httpsession_savepath_unchangeable');
+ else if(is_dir($value))
+ session_save_path($value);
+ else
+ throw new TInvalidDataValueException('httpsession_savepath_invalid',$value);
+ }
+
+ /**
+ * @return boolean whether to use user-specified handlers to store session data. Defaults to false.
+ */
+ public function getUseCustomStorage()
+ {
+ return $this->_customStorage;
+ }
+
+ /**
+ * @param boolean whether to use user-specified handlers to store session data.
+ * If true, make sure the methods {@link _open}, {@link _close}, {@link _read},
+ * {@link _write}, {@link _destroy}, and {@link _gc} are overridden in child
+ * class, because they will be used as the callback handlers.
+ */
+ public function setUseCustomStorage($value)
+ {
+ $this->_customStorage=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return THttpCookie cookie that will be used to store session ID
+ */
+ public function getCookie()
+ {
+ if($this->_cookie===null)
+ $this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID());
+ return $this->_cookie;
+ }
+
+ /**
+ * @return THttpSessionCookieMode how to use cookie to store session ID. Defaults to THttpSessionCookieMode::Allow.
+ */
+ public function getCookieMode()
+ {
+ if(ini_get('session.use_cookies')==='0')
+ return THttpSessionCookieMode::None;
+ else if(ini_get('session.use_only_cookies')==='0')
+ return THttpSessionCookieMode::Allow;
+ else
+ return THttpSessionCookieMode::Only;
+ }
+
+ /**
+ * @param THttpSessionCookieMode how to use cookie to store session ID
+ * @throws TInvalidOperationException if session is started already
+ */
+ public function setCookieMode($value)
+ {
+ if($this->_started)
+ throw new TInvalidOperationException('httpsession_cookiemode_unchangeable');
+ else
+ {
+ $value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode');
+ if($value===THttpSessionCookieMode::None)
+ {
+ ini_set('session.use_cookies','0');
+ ini_set('session.use_only_cookies','0');
+ }
+ else if($value===THttpSessionCookieMode::Allow)
+ {
+ ini_set('session.use_cookies','1');
+ ini_set('session.use_only_cookies','0');
+ }
+ else
+ {
+ ini_set('session.use_cookies','1');
+ ini_set('session.use_only_cookies','1');
+ ini_set('session.use_trans_sid', 0);
+ }
+ }
+ }
+
+ /**
+ * @return boolean whether the session should be automatically started when the session module is initialized, defaults to false.
+ */
+ public function getAutoStart()
+ {
+ return $this->_autoStart;
+ }
+
+ /**
+ * @param boolean whether the session should be automatically started when the session module is initialized, defaults to false.
+ * @throws TInvalidOperationException if session is started already
+ */
+ public function setAutoStart($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('httpsession_autostart_unchangeable');
+ else
+ $this->_autoStart=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return integer the probability (percentage) that the gc (garbage collection) process is started on every session initialization, defaults to 1 meaning 1% chance.
+ */
+ public function getGCProbability()
+ {
+ return TPropertyValue::ensureInteger(ini_get('session.gc_probability'));
+ }
+
+ /**
+ * @param integer the probability (percentage) that the gc (garbage collection) process is started on every session initialization.
+ * @throws TInvalidOperationException if session is started already
+ * @throws TInvalidDataValueException if the value is beyond [0,100].
+ */
+ public function setGCProbability($value)
+ {
+ if($this->_started)
+ throw new TInvalidOperationException('httpsession_gcprobability_unchangeable');
+ else
+ {
+ $value=TPropertyValue::ensureInteger($value);
+ if($value>=0 && $value<=100)
+ {
+ ini_set('session.gc_probability',$value);
+ ini_set('session.gc_divisor','100');
+ }
+ else
+ throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value);
+ }
+ }
+
+ /**
+ * @return boolean whether transparent sid support is enabled or not, defaults to false.
+ */
+ public function getUseTransparentSessionID()
+ {
+ return ini_get('session.use_trans_sid')==='1';
+ }
+
+ /**
+ * @param boolean whether transparent sid support is enabled or not.
+ */
+ public function setUseTransparentSessionID($value)
+ {
+ if($this->_started)
+ throw new TInvalidOperationException('httpsession_transid_unchangeable');
+ else
+ {
+ $value=TPropertyValue::ensureBoolean($value);
+ if ($value && $this->getCookieMode()==THttpSessionCookieMode::Only)
+ throw new TInvalidOperationException('httpsession_transid_cookieonly');
+ ini_set('session.use_trans_sid',$value?'1':'0');
+ }
+ }
+
+ /**
+ * @return integer the number of seconds after which data will be seen as 'garbage' and cleaned up, defaults to 1440 seconds.
+ */
+ public function getTimeout()
+ {
+ return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime'));
+ }
+
+ /**
+ * @param integer the number of seconds after which data will be seen as 'garbage' and cleaned up
+ * @throws TInvalidOperationException if session is started already
+ */
+ public function setTimeout($value)
+ {
+ if($this->_started)
+ throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable');
+ else
+ ini_set('session.gc_maxlifetime',$value);
+ }
+
+ /**
+ * Session open handler.
+ * This method should be overridden if {@link setUseCustomStorage UseCustomStorage} is set true.
+ * @param string session save path
+ * @param string session name
+ * @return boolean whether session is opened successfully
+ */
+ public function _open($savePath,$sessionName)
+ {
+ return true;
+ }
+
+ /**
+ * Session close handler.
+ * This method should be overridden if {@link setUseCustomStorage UseCustomStorage} is set true.
+ * @return boolean whether session is closed successfully
+ */
+ public function _close()
+ {
+ return true;
+ }
+
+ /**
+ * Session read handler.
+ * This method should be overridden if {@link setUseCustomStorage UseCustomStorage} is set true.
+ * @param string session ID
+ * @return string the session data
+ */
+ public function _read($id)
+ {
+ return '';
+ }
+
+ /**
+ * Session write handler.
+ * This method should be overridden if {@link setUseCustomStorage UseCustomStorage} is set true.
+ * @param string session ID
+ * @param string session data
+ * @return boolean whether session write is successful
+ */
+ public function _write($id,$data)
+ {
+ return true;
+ }
+
+ /**
+ * Session destroy handler.
+ * This method should be overridden if {@link setUseCustomStorage UseCustomStorage} is set true.
+ * @param string session ID
+ * @return boolean whether session is destroyed successfully
+ */
+ public function _destroy($id)
+ {
+ return true;
+ }
+
+ /**
+ * Session GC (garbage collection) handler.
+ * This method should be overridden if {@link setUseCustomStorage UseCustomStorage} is set true.
+ * @param integer the number of seconds after which data will be seen as 'garbage' and cleaned up.
+ * @return boolean whether session is GCed successfully
+ */
+ public function _gc($maxLifetime)
+ {
+ return true;
+ }
+
+ //------ The following methods enable THttpSession to be TMap-like -----
+
+ /**
+ * Returns an iterator for traversing the session variables.
+ * This method is required by the interface IteratorAggregate.
+ * @return TSessionIterator an iterator for traversing the session variables.
+ */
+ public function getIterator()
+ {
+ return new TSessionIterator;
+ }
+
+ /**
+ * @return integer the number of session variables
+ */
+ public function getCount()
+ {
+ return count($_SESSION);
+ }
+
+ /**
+ * Returns the number of items in the session.
+ * This method is required by Countable interface.
+ * @return integer number of items in the session.
+ */
+ public function count()
+ {
+ return $this->getCount();
+ }
+
+ /**
+ * @return array the list of session variable names
+ */
+ public function getKeys()
+ {
+ return array_keys($_SESSION);
+ }
+
+ /**
+ * Returns the session variable value with the session variable name.
+ * This method is exactly the same as {@link offsetGet}.
+ * @param mixed the session variable name
+ * @return mixed the session variable value, null if no such variable exists
+ */
+ public function itemAt($key)
+ {
+ return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
+ }
+
+ /**
+ * Adds a session variable.
+ * Note, if the specified name already exists, the old value will be removed first.
+ * @param mixed session variable name
+ * @param mixed session variable value
+ */
+ public function add($key,$value)
+ {
+ $_SESSION[$key]=$value;
+ }
+
+ /**
+ * Removes a session variable.
+ * @param mixed the name of the session variable to be removed
+ * @return mixed the removed value, null if no such session variable.
+ */
+ public function remove($key)
+ {
+ if(isset($_SESSION[$key]))
+ {
+ $value=$_SESSION[$key];
+ unset($_SESSION[$key]);
+ return $value;
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Removes all session variables
+ */
+ public function clear()
+ {
+ foreach(array_keys($_SESSION) as $key)
+ unset($_SESSION[$key]);
+ }
+
+ /**
+ * @param mixed session variable name
+ * @return boolean whether there is the named session variable
+ */
+ public function contains($key)
+ {
+ return isset($_SESSION[$key]);
+ }
+
+ /**
+ * @return array the list of all session variables in array
+ */
+ public function toArray()
+ {
+ return $_SESSION;
+ }
+
+ /**
+ * This method is required by the interface ArrayAccess.
+ * @param mixed the offset to check on
+ * @return boolean
+ */
+ public function offsetExists($offset)
+ {
+ return isset($_SESSION[$offset]);
+ }
+
+ /**
+ * This method is required by the interface ArrayAccess.
+ * @param integer the offset to retrieve element.
+ * @return mixed the element at the offset, null if no element is found at the offset
+ */
+ public function offsetGet($offset)
+ {
+ return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
+ }
+
+ /**
+ * This method is required by the interface ArrayAccess.
+ * @param integer the offset to set element
+ * @param mixed the element value
+ */
+ public function offsetSet($offset,$item)
+ {
+ $_SESSION[$offset]=$item;
+ }
+
+ /**
+ * This method is required by the interface ArrayAccess.
+ * @param mixed the offset to unset element
+ */
+ public function offsetUnset($offset)
+ {
+ unset($_SESSION[$offset]);
+ }
+}
+
+/**
+ * TSessionIterator class
+ *
+ * TSessionIterator implements Iterator interface.
+ *
+ * TSessionIterator is used by THttpSession. It allows THttpSession to return a new iterator
+ * for traversing the session variables.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web
+ * @since 3.0
+ */
+class TSessionIterator implements Iterator
+{
+ /**
+ * @var array list of keys in the map
+ */
+ private $_keys;
+ /**
+ * @var mixed current key
+ */
+ private $_key;
+
+ /**
+ * Constructor.
+ * @param array the data to be iterated through
+ */
+ public function __construct()
+ {
+ $this->_keys=array_keys($_SESSION);
+ }
+
+ /**
+ * Rewinds internal array pointer.
+ * This method is required by the interface Iterator.
+ */
+ public function rewind()
+ {
+ $this->_key=reset($this->_keys);
+ }
+
+ /**
+ * Returns the key of the current array element.
+ * This method is required by the interface Iterator.
+ * @return mixed the key of the current array element
+ */
+ public function key()
+ {
+ return $this->_key;
+ }
+
+ /**
+ * Returns the current array element.
+ * This method is required by the interface Iterator.
+ * @return mixed the current array element
+ */
+ public function current()
+ {
+ return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null;
+ }
+
+ /**
+ * Moves the internal pointer to the next array element.
+ * This method is required by the interface Iterator.
+ */
+ public function next()
+ {
+ do
+ {
+ $this->_key=next($this->_keys);
+ }
+ while(!isset($_SESSION[$this->_key]) && $this->_key!==false);
+ }
+
+ /**
+ * Returns whether there is an element at current position.
+ * This method is required by the interface Iterator.
+ * @return boolean
+ */
+ public function valid()
+ {
+ return $this->_key!==false;
+ }
+}
+
+
+/**
+ * THttpSessionCookieMode class.
+ * THttpSessionCookieMode defines the enumerable type for the possible methods of
+ * using cookies to store session ID.
+ *
+ * The following enumerable values are defined:
+ * - None: not using cookie.
+ * - Allow: using cookie.
+ * - Only: using cookie only.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web
+ * @since 3.0.4
+ */
+class THttpSessionCookieMode extends TEnumerable
+{
+ const None='None';
+ const Allow='Allow';
+ const Only='Only';
+}
+
diff --git a/lib/prado/framework/Web/THttpUtility.php b/lib/prado/framework/Web/THttpUtility.php
new file mode 100644
index 0000000..2be5fa4
--- /dev/null
+++ b/lib/prado/framework/Web/THttpUtility.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * THttpUtility class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web
+ */
+
+/**
+ * THttpUtility class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web
+ * @since 3.0
+ */
+class THttpUtility
+{
+ private static $_encodeTable=array('<'=>'&lt;','>'=>'&gt;','"'=>'&quot;');
+ private static $_decodeTable=array('&lt;'=>'<','&gt;'=>'>','&quot;'=>'"');
+ private static $_stripTable=array('&lt;'=>'','&gt;'=>'','&quot;'=>'');
+
+ /**
+ * HTML-encodes a string.
+ * This method translates the following characters to their corresponding
+ * HTML entities: <, >, "
+ * Note, unlike {@link htmlspecialchars}, & is not translated.
+ * @param string string to be encoded
+ * @return string encoded string
+ */
+ public static function htmlEncode($s)
+ {
+ return strtr($s,self::$_encodeTable);
+ }
+
+ /**
+ * HTML-decodes a string.
+ * It is the inverse of {@link htmlEncode}.
+ * @param string string to be decoded
+ * @return string decoded string
+ */
+ public static function htmlDecode($s)
+ {
+ return strtr($s,self::$_decodeTable);
+ }
+
+ /**
+ * This method strips the following characters from a string:
+ * HTML entities: <, >, "
+ * @param string string to be encoded
+ * @return string encoded string
+ */
+ public static function htmlStrip($s)
+ {
+ return strtr($s,self::$_stripTable);
+ }
+}
+
diff --git a/lib/prado/framework/Web/TUrlManager.php b/lib/prado/framework/Web/TUrlManager.php
new file mode 100644
index 0000000..0525a7e
--- /dev/null
+++ b/lib/prado/framework/Web/TUrlManager.php
@@ -0,0 +1,161 @@
+<?php
+/**
+ * TUrlManager class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @version $Id $
+ * @package System.Web
+ */
+
+/**
+ * TUrlManager class
+ *
+ * TUrlManager is the base class for managing URLs that can be
+ * recognized by PRADO applications. It provides the default implementation
+ * for parsing and constructing URLs.
+ *
+ * Derived classes may override {@link constructUrl} and {@link parseUrl}
+ * to provide customized URL schemes.
+ *
+ * By default, {@link THttpRequest} uses TUrlManager as its URL manager.
+ * If you want to use your customized URL manager, load your manager class
+ * as an application module and set {@link THttpRequest::setUrlManager THttpRequest.UrlManager}
+ * with the ID of your URL manager module.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id $
+ * @package System.Web
+ * @since 3.0.6
+ */
+class TUrlManager extends TModule
+{
+ /**
+ * Constructs a URL that can be recognized by PRADO.
+ *
+ * This method provides the actual implementation used by {@link THttpRequest::constructUrl}.
+ * Override this method if you want to provide your own way of URL formatting.
+ * If you do so, you may also need to override {@link parseUrl} so that the URL can be properly parsed.
+ *
+ * The URL is constructed as the following format:
+ * /entryscript.php?serviceID=serviceParameter&get1=value1&...
+ * If {@link THttpRequest::setUrlFormat THttpRequest.UrlFormat} is 'Path',
+ * the following format is used instead:
+ * /entryscript.php/serviceID/serviceParameter/get1,value1/get2,value2...
+ * If {@link THttpRequest::setUrlFormat THttpRequest.UrlFormat} is 'HiddenPath',
+ * then entryscript.php will be hidden and the following format is used instead:
+ * /serviceID/serviceParameter/get1,value1/get2,value2...
+ * In order to use the 'HiddenPath' format you need proper url rewrite configuration;
+ * here's an example for Apache's .htaccess:
+ * <cdde>
+ * Options +FollowSymLinks
+ * RewriteEngine On
+ * RewriteCond %{REQUEST_FILENAME} !-d
+ * RewriteCond %{REQUEST_FILENAME} !-f
+ * RewriteRule ^(.*)$ index.php/$1 [L]
+ * </code>
+ * @param string service ID
+ * @param string service parameter
+ * @param array GET parameters, null if not provided
+ * @param boolean whether to encode the ampersand in URL
+ * @param boolean whether to encode the GET parameters (their names and values)
+ * @return string URL
+ * @see parseUrl
+ */
+ public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems)
+ {
+ $url=$serviceID.'='.urlencode($serviceParam);
+ $amp=$encodeAmpersand?'&amp;':'&';
+ $request=$this->getRequest();
+ if(is_array($getItems) || $getItems instanceof Traversable)
+ {
+ if($encodeGetItems)
+ {
+ foreach($getItems as $name=>$value)
+ {
+ if(is_array($value))
+ {
+ $name=urlencode($name.'[]');
+ foreach($value as $v)
+ $url.=$amp.$name.'='.urlencode($v);
+ }
+ else
+ $url.=$amp.urlencode($name).'='.urlencode($value);
+ }
+ }
+ else
+ {
+ foreach($getItems as $name=>$value)
+ {
+ if(is_array($value))
+ {
+ foreach($value as $v)
+ $url.=$amp.$name.'[]='.$v;
+ }
+ else
+ $url.=$amp.$name.'='.$value;
+ }
+ }
+ }
+
+ switch($request->getUrlFormat())
+ {
+ case THttpRequestUrlFormat::Path:
+ return $request->getApplicationUrl().'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
+ case THttpRequestUrlFormat::HiddenPath:
+ return rtrim(dirname($request->getApplicationUrl()), '/').'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
+ default:
+ return $request->getApplicationUrl().'?'.$url;
+ }
+ }
+
+ /**
+ * Parses the request URL and returns an array of input parameters.
+ * This method is automatically invoked by {@link THttpRequest} when
+ * handling a user request.
+ *
+ * In general, this method should parse the path info part of the requesting URL
+ * and generate an array of name-value pairs according to some scheme.
+ * The current implementation deals with both 'Get' and 'Path' URL formats.
+ *
+ * You may override this method to support customized URL format.
+ * @return array list of input parameters, indexed by parameter names
+ * @see constructUrl
+ */
+ public function parseUrl()
+ {
+ $request=$this->getRequest();
+ $pathInfo=trim($request->getPathInfo(),'/');
+ if(($request->getUrlFormat()===THttpRequestUrlFormat::Path ||
+ $request->getUrlFormat()===THttpRequestUrlFormat::HiddenPath) &&
+ $pathInfo!=='')
+ {
+ $separator=$request->getUrlParamSeparator();
+ $paths=explode('/',$pathInfo);
+ $getVariables=array();
+ foreach($paths as $path)
+ {
+ if(($path=trim($path))!=='')
+ {
+ if(($pos=strpos($path,$separator))!==false)
+ {
+ $name=substr($path,0,$pos);
+ $value=substr($path,$pos+1);
+ if(($pos=strpos($name,'[]'))!==false)
+ $getVariables[substr($name,0,$pos)][]=$value;
+ else
+ $getVariables[$name]=$value;
+ }
+ else
+ $getVariables[$path]='';
+ }
+ }
+ return $getVariables;
+ }
+ else
+ return array();
+ }
+}
+
diff --git a/lib/prado/framework/Web/TUrlMapping.php b/lib/prado/framework/Web/TUrlMapping.php
new file mode 100644
index 0000000..f7fdba6
--- /dev/null
+++ b/lib/prado/framework/Web/TUrlMapping.php
@@ -0,0 +1,1035 @@
+<?php
+/**
+ * TUrlMapping, TUrlMappingPattern and TUrlMappingPatternSecureConnection class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web
+ */
+
+Prado::using('System.Web.TUrlManager');
+Prado::using('System.Collections.TAttributeCollection');
+
+/**
+ * TUrlMapping Class
+ *
+ * The TUrlMapping module allows PRADO to construct and recognize URLs
+ * based on specific patterns.
+ *
+ * TUrlMapping consists of a list of URL patterns which are used to match
+ * against the currently requested URL. The first matching pattern will then
+ * be used to decompose the URL into request parameters (accessible through
+ * <code>$this->Request['paramname']</code>).
+ *
+ * The patterns can also be used to construct customized URLs. In this case,
+ * the parameters in an applied pattern will be replaced with the corresponding
+ * GET variable values.
+ *
+ * Since it is derived from {@link TUrlManager}, it should be configured globally
+ * in the application configuration like the following,
+ * <code>
+ * <module id="request" class="THttpRequest" UrlManager="friendly-url" />
+ * <module id="friendly-url" class="System.Web.TUrlMapping" EnableCustomUrl="true">
+ * <url ServiceParameter="Posts.ViewPost" pattern="post/{id}/" parameters.id="\d+" />
+ * <url ServiceParameter="Posts.ListPost" pattern="archive/{time}/" parameters.time="\d{6}" />
+ * <url ServiceParameter="Posts.ListPost" pattern="category/{cat}/" parameters.cat="\d+" />
+ * </module>
+ * </code>
+ *
+ * In the above, each <tt>&lt;url&gt;</tt> element specifies a URL pattern represented
+ * as a {@link TUrlMappingPattern} internally. You may create your own pattern classes
+ * by extending {@link TUrlMappingPattern} and specifying the <tt>&lt;class&gt;</tt> attribute
+ * in the element.
+ *
+ * The patterns can be also be specified in an external file using the {@link setConfigFile ConfigFile} property.
+ *
+ * The URL mapping are evaluated in order, only the first mapping that matches
+ * the URL will be used. Cascaded mapping can be achieved by placing the URL mappings
+ * in particular order. For example, placing the most specific mappings first.
+ *
+ * Only the PATH_INFO part of the URL is used to match the available patterns. The matching
+ * is strict in the sense that the whole pattern must match the whole PATH_INFO of the URL.
+ *
+ * From PRADO v3.1.1, TUrlMapping also provides support for constructing URLs according to
+ * the specified pattern. You may enable this functionality by setting {@link setEnableCustomUrl EnableCustomUrl} to true.
+ * When you call THttpRequest::constructUrl() (or via TPageService::constructUrl()),
+ * TUrlMapping will examine the available URL mapping patterns using their {@link TUrlMappingPattern::getServiceParameter ServiceParameter}
+ * and {@link TUrlMappingPattern::getPattern Pattern} properties. A pattern is applied if its
+ * {@link TUrlMappingPattern::getServiceParameter ServiceParameter} matches the service parameter passed
+ * to constructUrl() and every parameter in the {@link getPattern Pattern} is found
+ * in the GET variables.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web
+ * @since 3.0.5
+ */
+class TUrlMapping extends TUrlManager
+{
+ /**
+ * @var TUrlMappingPattern[] list of patterns.
+ */
+ protected $_patterns=array();
+ /**
+ * @var TUrlMappingPattern matched pattern.
+ */
+ private $_matched;
+ /**
+ * @var string external configuration file
+ */
+ private $_configFile=null;
+ /**
+ * @var boolean whether to enable custom contructUrl
+ */
+ private $_customUrl=false;
+ /**
+ * @var array rules for constructing URLs
+ */
+ protected $_constructRules=array();
+
+ private $_urlPrefix='';
+
+ private $_defaultMappingClass='TUrlMappingPattern';
+
+ /**
+ * Initializes this module.
+ * This method is required by the IModule interface.
+ * @param mixed configuration for this module, can be null
+ * @throws TConfigurationException if module is configured in the global scope.
+ */
+ public function init($config)
+ {
+ parent::init($config);
+ if($this->getRequest()->getRequestResolved())
+ throw new TConfigurationException('urlmapping_global_required');
+ if($this->_configFile!==null)
+ $this->loadConfigFile();
+ $this->loadUrlMappings($config);
+ if($this->_urlPrefix==='')
+ {
+ $request=$this->getRequest();
+ if($request->getUrlFormat()===THttpRequestUrlFormat::HiddenPath)
+ {
+ $this->_urlPrefix=dirname($request->getApplicationUrl());
+ } else {
+ $this->_urlPrefix=$request->getApplicationUrl();
+ }
+ }
+ $this->_urlPrefix=rtrim($this->_urlPrefix,'/');
+ }
+
+ /**
+ * Initialize the module from configuration file.
+ * @throws TConfigurationException if {@link getConfigFile ConfigFile} is invalid.
+ */
+ protected function loadConfigFile()
+ {
+ if(is_file($this->_configFile))
+ {
+ if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ {
+ $config = include $this->_configFile;
+ $this->loadUrlMappings($dom);
+ }
+ else
+ {
+ $dom=new TXmlDocument;
+ $dom->loadFromFile($this->_configFile);
+ $this->loadUrlMappings($dom);
+ }
+ }
+ else
+ throw new TConfigurationException('urlmapping_configfile_inexistent',$this->_configFile);
+ }
+
+ /**
+ * Returns a value indicating whether to enable custom constructUrl.
+ * If true, constructUrl() will make use of the URL mapping rules to
+ * construct valid URLs.
+ * @return boolean whether to enable custom constructUrl. Defaults to false.
+ * @since 3.1.1
+ */
+ public function getEnableCustomUrl()
+ {
+ return $this->_customUrl;
+ }
+
+ /**
+ * Sets a value indicating whether to enable custom constructUrl.
+ * If true, constructUrl() will make use of the URL mapping rules to
+ * construct valid URLs.
+ * @param boolean whether to enable custom constructUrl.
+ * @since 3.1.1
+ */
+ public function setEnableCustomUrl($value)
+ {
+ $this->_customUrl=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return string the part that will be prefixed to the constructed URLs. Defaults to the requested script path (e.g. /path/to/index.php for a URL http://hostname/path/to/index.php)
+ * @since 3.1.1
+ */
+ public function getUrlPrefix()
+ {
+ return $this->_urlPrefix;
+ }
+
+ /**
+ * @param string the part that will be prefixed to the constructed URLs. This is used by constructUrl() when EnableCustomUrl is set true.
+ * @see getUrlPrefix
+ * @since 3.1.1
+ */
+ public function setUrlPrefix($value)
+ {
+ $this->_urlPrefix=$value;
+ }
+
+ /**
+ * @return string external configuration file. Defaults to null.
+ */
+ public function getConfigFile()
+ {
+ return $this->_configFile;
+ }
+
+ /**
+ * @param string external configuration file in namespace format. The file
+ * must be suffixed with '.xml'.
+ * @throws TInvalidDataValueException if the file is invalid.
+ */
+ public function setConfigFile($value)
+ {
+ if(($this->_configFile=Prado::getPathOfNamespace($value,$this->getApplication()->getConfigurationFileExt()))===null)
+ throw new TConfigurationException('urlmapping_configfile_invalid',$value);
+ }
+
+ /**
+ * @return string the default class of URL mapping patterns. Defaults to TUrlMappingPattern.
+ * @since 3.1.1
+ */
+ public function getDefaultMappingClass()
+ {
+ return $this->_defaultMappingClass;
+ }
+
+ /**
+ * Sets the default class of URL mapping patterns.
+ * When a URL matching pattern does not specify "class" attribute, it will default to the class
+ * specified by this property. You may use either a class name or a namespace format of class (if the class needs to be included first.)
+ * @param string the default class of URL mapping patterns.
+ * @since 3.1.1
+ */
+ public function setDefaultMappingClass($value)
+ {
+ $this->_defaultMappingClass=$value;
+ }
+
+ /**
+ * Load and configure each url mapping pattern.
+ * @param mixed configuration node
+ * @throws TConfigurationException if specific pattern class is invalid
+ */
+ protected function loadUrlMappings($config)
+ {
+ $defaultClass = $this->getDefaultMappingClass();
+
+ if(is_array($config))
+ {
+ if(isset($config['urls']) && is_array($config['urls']))
+ {
+ foreach($config['urls'] as $url)
+ {
+ $class=isset($url['class'])?$url['class']:$defaultClass;
+ $properties = isset($url['properties'])?$url['properties']:array();
+ $this->buildUrlMapping($class,$properties,$url);
+ }
+ }
+ }
+ else
+ {
+ foreach($config->getElementsByTagName('url') as $url)
+ {
+ $properties=$url->getAttributes();
+ if(($class=$properties->remove('class'))===null)
+ $class=$defaultClass;
+ $this->buildUrlMapping($class,$properties,$url);
+ }
+ }
+ }
+
+ private function buildUrlMapping($class, $properties, $url)
+ {
+ $pattern=Prado::createComponent($class,$this);
+ if(!($pattern instanceof TUrlMappingPattern))
+ throw new TConfigurationException('urlmapping_urlmappingpattern_required');
+ foreach($properties as $name=>$value)
+ $pattern->setSubproperty($name,$value);
+
+ if($url instanceof TXmlElement) {
+ $text = $url -> getValue();
+ if($text) {
+ $text = preg_replace('/(\s+)/S', '', $text);
+ if(($regExp = $pattern->getRegularExpression()) !== '')
+ trigger_error(sPrintF('%s.RegularExpression property value "%s" for ServiceID="%s" and ServiceParameter="%s" was replaced by node value "%s"',
+ get_class($pattern),
+ $regExp,
+ $pattern->getServiceID(),
+ $pattern->getServiceParameter(),
+ $text),
+ E_USER_NOTICE);
+ $pattern->setRegularExpression($text);
+ }
+ }
+
+ $this->_patterns[]=$pattern;
+ $pattern->init($url);
+
+ $key=$pattern->getServiceID().':'.$pattern->getServiceParameter();
+ $this->_constructRules[$key][]=$pattern;
+ }
+
+ /**
+ * Parses the request URL and returns an array of input parameters.
+ * This method overrides the parent implementation.
+ * The input parameters do not include GET and POST variables.
+ * This method uses the request URL path to find the first matching pattern. If found
+ * the matched pattern parameters are used to return as the input parameters.
+ * @return array list of input parameters
+ */
+ public function parseUrl()
+ {
+ $request=$this->getRequest();
+ foreach($this->_patterns as $pattern)
+ {
+ $matches=$pattern->getPatternMatches($request);
+ if(count($matches)>0)
+ {
+ $this->_matched=$pattern;
+ $params=array();
+ foreach($matches as $key=>$value)
+ {
+ if(is_string($key))
+ $params[$key]=$value;
+ }
+ if (!$pattern->getIsWildCardPattern())
+ $params[$pattern->getServiceID()]=$pattern->getServiceParameter();
+ return $params;
+ }
+ }
+ return parent::parseUrl();
+ }
+
+ /**
+ * Constructs a URL that can be recognized by PRADO.
+ *
+ * This method provides the actual implementation used by {@link THttpRequest::constructUrl}.
+ * Override this method if you want to provide your own way of URL formatting.
+ * If you do so, you may also need to override {@link parseUrl} so that the URL can be properly parsed.
+ *
+ * The URL is constructed as the following format:
+ * /entryscript.php?serviceID=serviceParameter&get1=value1&...
+ * If {@link THttpRequest::setUrlFormat THttpRequest.UrlFormat} is 'Path',
+ * the following format is used instead:
+ * /entryscript.php/serviceID/serviceParameter/get1,value1/get2,value2...
+ * If {@link THttpRequest::setUrlFormat THttpRequest.UrlFormat} is 'HiddenPath',
+ * the following format is used instead:
+ * /serviceID/serviceParameter/get1,value1/get2,value2...
+ * @param string service ID
+ * @param string service parameter
+ * @param array GET parameters, null if not provided
+ * @param boolean whether to encode the ampersand in URL
+ * @param boolean whether to encode the GET parameters (their names and values)
+ * @return string URL
+ * @see parseUrl
+ * @since 3.1.1
+ */
+ public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems)
+ {
+ if($this->_customUrl)
+ {
+ if(!(is_array($getItems) || ($getItems instanceof Traversable)))
+ $getItems=array();
+ $key=$serviceID.':'.$serviceParam;
+ $wildCardKey = ($pos=strrpos($serviceParam,'.'))!==false ?
+ $serviceID.':'.substr($serviceParam,0,$pos).'.*' : $serviceID.':*';
+ if(isset($this->_constructRules[$key]))
+ {
+ foreach($this->_constructRules[$key] as $rule)
+ {
+ if($rule->supportCustomUrl($getItems))
+ return $rule->constructUrl($getItems,$encodeAmpersand,$encodeGetItems);
+ }
+ }
+ elseif(isset($this->_constructRules[$wildCardKey]))
+ {
+ foreach($this->_constructRules[$wildCardKey] as $rule)
+ {
+ if($rule->supportCustomUrl($getItems))
+ {
+ $getItems['*']= $pos ? substr($serviceParam,$pos+1) : $serviceParam;
+ return $rule->constructUrl($getItems,$encodeAmpersand,$encodeGetItems);
+ }
+ }
+ }
+ }
+ return parent::constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems);
+ }
+
+ /**
+ * @return TUrlMappingPattern the matched pattern, null if not found.
+ */
+ public function getMatchingPattern()
+ {
+ return $this->_matched;
+ }
+}
+
+/**
+ * TUrlMappingPattern class.
+ *
+ * TUrlMappingPattern represents a pattern used to parse and construct URLs.
+ * If the currently requested URL matches the pattern, it will alter
+ * the THttpRequest parameters. If a constructUrl() call matches the pattern
+ * parameters, the pattern will generate a valid URL. In both case, only the PATH_INFO
+ * part of a URL is parsed/constructed using the pattern.
+ *
+ * To specify the pattern, set the {@link setPattern Pattern} property.
+ * {@link setPattern Pattern} takes a string expression with
+ * parameter names enclosed between a left brace '{' and a right brace '}'.
+ * The patterns for each parameter can be set using {@link getParameters Parameters}
+ * attribute collection. For example
+ * <code>
+ * <url ... pattern="articles/{year}/{month}/{day}"
+ * parameters.year="\d{4}" parameters.month="\d{2}" parameters.day="\d+" />
+ * </code>
+ *
+ * In the above example, the pattern contains 3 parameters named "year",
+ * "month" and "day". The pattern for these parameters are, respectively,
+ * "\d{4}" (4 digits), "\d{2}" (2 digits) and "\d+" (1 or more digits).
+ * Essentially, the <tt>Parameters</tt> attribute name and values are used
+ * as substrings in replacing the placeholders in the <tt>Pattern</tt> string
+ * to form a complete regular expression string.
+ *
+ * For more complicated patterns, one may specify the pattern using a regular expression
+ * by {@link setRegularExpression RegularExpression}. For example, the above pattern
+ * is equivalent to the following regular expression-based pattern:
+ * <code>
+ * #^articles/(?P<year>\d{4})/(?P<month>\d{2})\/(?P<day>\d+)$#u
+ * </code>
+ * The above regular expression used the "named group" feature available in PHP.
+ * If you intended to use the <tt>RegularExpression</tt> property or
+ * regular expressions in CDATA sections, notice that you need to escape the slash,
+ * if you are using the slash as regular expressions delimiter.
+ *
+ * Thus, only an url that matches the pattern will be valid. For example,
+ * a URL <tt>http://example.com/index.php/articles/2006/07/21</tt> will match the above pattern,
+ * while <tt>http://example.com/index.php/articles/2006/07/hello</tt> will not
+ * since the "day" parameter pattern is not satisfied.
+ *
+ * The parameter values are available through the <tt>THttpRequest</tt> instance (e.g.
+ * <tt>$this->Request['year']</tt>).
+ *
+ * The {@link setServiceParameter ServiceParameter} and {@link setServiceID ServiceID}
+ * (the default ID is 'page') set the service parameter and service id respectively.
+ *
+ * Since 3.1.4 you can also use simplyfied wildcard patterns to match multiple
+ * ServiceParameters with a single rule. The pattern must contain the placeholder
+ * {*} for the ServiceParameter. For example
+ *
+ * <url ServiceParameter="adminpages.*" pattern="admin/{*}" />
+ *
+ * This rule will match an URL like <tt>http://example.com/index.php/admin/edituser</tt>
+ * and resolve it to the page Application.pages.admin.edituser. The wildcard matching
+ * is non-recursive. That means you have to add a rule for every subdirectory you
+ * want to access pages in:
+ *
+ * <url ServiceParameter="adminpages.users.*" pattern="useradmin/{*}" />
+ *
+ * It is still possible to define an explicit rule for a page in the wildcard path.
+ * This rule has to preceed the wildcard rule.
+ *
+ * You can also use parameters with wildcard patterns. The parameters are then
+ * available with every matching page:
+ *
+ * <url ServiceParameter="adminpages.*" pattern="admin/{*}/{id}" parameters.id="\d+" />
+ *
+ * To enable automatic parameter encoding in a path format from wildcard patterns you can set
+ * {@setUrlFormat UrlFormat} to 'Path':
+ *
+ * <url ServiceParameter="adminpages.*" pattern="admin/{*}" UrlFormat="Path" />
+ *
+ * This will create and parse URLs of the form
+ * <tt>.../index.php/admin/listuser/param1/value1/param2/value2</tt>.
+ *
+ * Use {@setUrlParamSeparator} to define another separator character between parameter
+ * name and value. Parameter/value pairs are always separated by a '/'.
+ *
+ * <url ServiceParameter="adminpages.*" pattern="admin/{*}" UrlFormat="Path" UrlParamSeparator="-" />
+ *
+ * <tt>.../index.php/admin/listuser/param1-value1/param2-value2</tt>.
+ *
+ * Since 3.2.2 you can also add a list of "constants" parameters that can be used just
+ * like the original "parameters" parameters, except that the supplied value will be treated
+ * as a simple string constant instead of a regular expression. For example
+ *
+ * <url ServiceParameter="MyPage" pattern="/mypage/mypath/list/detail/{pageidx}" parameters.pageidx="\d+" constants.listtype="detailed"/>
+ * <url ServiceParameter="MyPage" pattern="/mypage/mypath/list/summary/{pageidx}" parameters.pageidx="\d+" constants.listtype="summarized"/>
+ *
+ * These rules, when matched by the actual request, will make the application see a "lisstype" parameter present
+ * (even through not supplied in the request) and equal to "detailed" or "summarized", depending on the friendly url matched.
+ * The constants is practically a table-based validation and translation of specified, fixed-set parameter values.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web
+ * @since 3.0.5
+ */
+class TUrlMappingPattern extends TComponent
+{
+ /**
+ * @var string service parameter such as Page class name.
+ */
+ private $_serviceParameter;
+ /**
+ * @var string service ID, default is 'page'.
+ */
+ private $_serviceID='page';
+ /**
+ * @var string url pattern to match.
+ */
+ private $_pattern;
+ /**
+ * @var TAttributeCollection parameter regular expressions.
+ */
+ private $_parameters;
+ /**
+ * @var TAttributeCollection of constant parameters.
+ */
+ protected $_constants;
+ /**
+ * @var string regular expression pattern.
+ */
+ private $_regexp='';
+
+ private $_customUrl=true;
+
+ private $_manager;
+
+ private $_caseSensitive=true;
+
+ private $_isWildCardPattern=false;
+
+ private $_urlFormat=THttpRequestUrlFormat::Get;
+
+ private $_separator='/';
+
+ /**
+ * @var TUrlMappingPatternSecureConnection
+ * @since 3.2
+ */
+ private $_secureConnection = TUrlMappingPatternSecureConnection::Automatic;
+
+ /**
+ * Constructor.
+ * @param TUrlManager the URL manager instance
+ */
+ public function __construct(TUrlManager $manager)
+ {
+ $this->_manager=$manager;
+ }
+
+ /**
+ * @return TUrlManager the URL manager instance
+ */
+ public function getManager()
+ {
+ return $this->_manager;
+ }
+
+ /**
+ * Initializes the pattern.
+ * @param TXmlElement configuration for this module.
+ * @throws TConfigurationException if service parameter is not specified
+ */
+ public function init($config)
+ {
+ if($this->_serviceParameter===null)
+ throw new TConfigurationException('urlmappingpattern_serviceparameter_required', $this->getPattern());
+ if(strpos($this->_serviceParameter,'*')!==false)
+ $this->_isWildCardPattern=true;
+ }
+
+ /**
+ * Substitute the parameter key value pairs as named groupings
+ * in the regular expression matching pattern.
+ * @return string regular expression pattern with parameter subsitution
+ */
+ protected function getParameterizedPattern()
+ {
+ $params=array();
+ $values=array();
+ if ($this->_parameters)
+ {
+ foreach($this->_parameters as $key=>$value)
+ {
+ $params[]='{'.$key.'}';
+ $values[]='(?P<'.$key.'>'.$value.')';
+ }
+ }
+ if ($this->getIsWildCardPattern())
+ {
+ $params[]='{*}';
+ // service parameter must not contain '=' and '/'
+ $values[]='(?P<'.$this->getServiceID().'>[^=/]+)';
+ }
+ $params[]='/';
+ $values[]='\\/';
+ $regexp=str_replace($params,$values,trim($this->getPattern(),'/').'/');
+ if ($this->_urlFormat===THttpRequestUrlFormat::Get)
+ $regexp='/^'.$regexp.'$/u';
+ else
+ $regexp='/^'.$regexp.'(?P<urlparams>.*)$/u';
+
+ if(!$this->getCaseSensitive())
+ $regexp.='i';
+ return $regexp;
+ }
+
+ /**
+ * @return string full regular expression mapping pattern
+ */
+ public function getRegularExpression()
+ {
+ return $this->_regexp;
+ }
+
+ /**
+ * @param string full regular expression mapping pattern.
+ */
+ public function setRegularExpression($value)
+ {
+ $this->_regexp=$value;
+ }
+
+ /**
+ * @return boolean whether the {@link getPattern Pattern} should be treated as case sensititve. Defaults to true.
+ */
+ public function getCaseSensitive()
+ {
+ return $this->_caseSensitive;
+ }
+
+ /**
+ * @param boolean whether the {@link getPattern Pattern} should be treated as case sensititve.
+ */
+ public function setCaseSensitive($value)
+ {
+ $this->_caseSensitive=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @param string service parameter, such as page class name.
+ */
+ public function setServiceParameter($value)
+ {
+ $this->_serviceParameter=$value;
+ }
+
+ /**
+ * @return string service parameter, such as page class name.
+ */
+ public function getServiceParameter()
+ {
+ return $this->_serviceParameter;
+ }
+
+ /**
+ * @param string service id to handle.
+ */
+ public function setServiceID($value)
+ {
+ $this->_serviceID=$value;
+ }
+
+ /**
+ * @return string service id.
+ */
+ public function getServiceID()
+ {
+ return $this->_serviceID;
+ }
+
+ /**
+ * @return string url pattern to match. Defaults to ''.
+ */
+ public function getPattern()
+ {
+ return $this->_pattern;
+ }
+
+ /**
+ * @param string url pattern to match.
+ */
+ public function setPattern($value)
+ {
+ $this->_pattern = $value;
+ }
+
+ /**
+ * @return TAttributeCollection parameter key value pairs.
+ */
+ public function getParameters()
+ {
+ if (!$this->_parameters)
+ {
+ $this->_parameters=new TAttributeCollection;
+ $this->_parameters->setCaseSensitive(true);
+ }
+ return $this->_parameters;
+ }
+
+ /**
+ * @param TAttributeCollection new parameter key value pairs.
+ */
+ public function setParameters($value)
+ {
+ $this->_parameters=$value;
+ }
+
+ /**
+ * @return TAttributeCollection constanst parameter key value pairs.
+ * @since 3.2.2
+ */
+ public function getConstants()
+ {
+ if (!$this->_constants)
+ {
+ $this->_constants = new TAttributeCollection;
+ $this->_constants->setCaseSensitive(true);
+ }
+ return $this->_constants;
+ }
+
+ /**
+ * Uses URL pattern (or full regular expression if available) to
+ * match the given url path.
+ * @param THttpRequest the request module
+ * @return array matched parameters, empty if no matches.
+ */
+ public function getPatternMatches($request)
+ {
+ $matches=array();
+ if(($pattern=$this->getRegularExpression())!=='')
+ preg_match($pattern,$request->getPathInfo(),$matches);
+ else
+ preg_match($this->getParameterizedPattern(),trim($request->getPathInfo(),'/').'/',$matches);
+
+ if($this->getIsWildCardPattern() && isset($matches[$this->_serviceID]))
+ $matches[$this->_serviceID]=str_replace('*',$matches[$this->_serviceID],$this->_serviceParameter);
+
+ if (isset($matches['urlparams']))
+ {
+ $params=explode('/',$matches['urlparams']);
+ if ($this->_separator==='/')
+ {
+ while($key=array_shift($params))
+ $matches[$key]=($value=array_shift($params)) ? $value : '';
+ }
+ else
+ {
+ array_pop($params);
+ foreach($params as $param)
+ {
+ list($key,$value)=explode($this->_separator,$param,2);
+ $matches[$key]=$value;
+ }
+ }
+ unset($matches['urlparams']);
+ }
+
+ if(count($matches) > 0 && $this->_constants)
+ {
+ foreach($this->_constants->toArray() as $key=>$value)
+ $matches[$key] = $value;
+ }
+
+ return $matches;
+ }
+
+ /**
+ * Returns a value indicating whether to use this pattern to construct URL.
+ * @return boolean whether to enable custom constructUrl. Defaults to true.
+ * @since 3.1.1
+ */
+ public function getEnableCustomUrl()
+ {
+ return $this->_customUrl;
+ }
+
+ /**
+ * Sets a value indicating whether to enable custom constructUrl using this pattern
+ * @param boolean whether to enable custom constructUrl.
+ */
+ public function setEnableCustomUrl($value)
+ {
+ $this->_customUrl=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether this pattern is a wildcard pattern
+ * @since 3.1.4
+ */
+ public function getIsWildCardPattern() {
+ return $this->_isWildCardPattern;
+ }
+
+ /**
+ * @return THttpRequestUrlFormat the format of URLs. Defaults to THttpRequestUrlFormat::Get.
+ */
+ public function getUrlFormat()
+ {
+ return $this->_urlFormat;
+ }
+
+ /**
+ * Sets the format of URLs constructed and interpreted by this pattern.
+ * A Get URL format is like index.php?name1=value1&name2=value2
+ * while a Path URL format is like index.php/name1/value1/name2/value.
+ * The separating character between name and value can be configured with
+ * {@link setUrlParamSeparator} and defaults to '/'.
+ * Changing the UrlFormat will affect {@link constructUrl} and how GET variables
+ * are parsed.
+ * @param THttpRequestUrlFormat the format of URLs.
+ * @since 3.1.4
+ */
+ public function setUrlFormat($value)
+ {
+ $this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat');
+ }
+
+ /**
+ * @return string separator used to separate GET variable name and value when URL format is Path. Defaults to slash '/'.
+ */
+ public function getUrlParamSeparator()
+ {
+ return $this->_separator;
+ }
+
+ /**
+ * @param string separator used to separate GET variable name and value when URL format is Path.
+ * @throws TInvalidDataValueException if the separator is not a single character
+ */
+ public function setUrlParamSeparator($value)
+ {
+ if(strlen($value)===1)
+ $this->_separator=$value;
+ else
+ throw new TInvalidDataValueException('httprequest_separator_invalid');
+ }
+
+ /**
+ * @return TUrlMappingPatternSecureConnection the SecureConnection behavior. Defaults to {@link TUrlMappingPatternSecureConnection::Automatic Automatic}
+ * @since 3.2
+ */
+ public function getSecureConnection()
+ {
+ return $this->_secureConnection;
+ }
+
+ /**
+ * @param TUrlMappingPatternSecureConnection the SecureConnection behavior.
+ * @since 3.2
+ */
+ public function setSecureConnection($value)
+ {
+ $this->_secureConnection = TPropertyValue::ensureEnum($value, 'TUrlMappingPatternSecureConnection');
+ }
+
+ /**
+ * @param array list of GET items to be put in the constructed URL
+ * @return boolean whether this pattern IS the one for constructing the URL with the specified GET items.
+ * @since 3.1.1
+ */
+ public function supportCustomUrl($getItems)
+ {
+ if(!$this->_customUrl || $this->getPattern()===null)
+ return false;
+ if ($this->_parameters)
+ {
+ foreach($this->_parameters as $key=>$value)
+ {
+ if(!isset($getItems[$key]))
+ return false;
+ }
+ }
+
+ if ($this->_constants)
+ {
+ foreach($this->_constants->toArray() as $key=>$value)
+ {
+ if (!isset($getItems[$key]))
+ return false;
+ if ($getItems[$key]!=$value)
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Constructs a URL using this pattern.
+ * @param array list of GET variables
+ * @param boolean whether the ampersand should be encoded in the constructed URL
+ * @param boolean whether the GET variables should be encoded in the constructed URL
+ * @return string the constructed URL
+ * @since 3.1.1
+ */
+ public function constructUrl($getItems,$encodeAmpersand,$encodeGetItems)
+ {
+ if ($this->_constants)
+ {
+ foreach($this->_constants->toArray() as $key=>$value)
+ {
+ unset($getItems[$key]);
+ }
+ }
+
+ $extra=array();
+ $replace=array();
+ // for the GET variables matching the pattern, put them in the URL path
+ foreach($getItems as $key=>$value)
+ {
+ if(($this->_parameters && $this->_parameters->contains($key)) || ($key==='*' && $this->getIsWildCardPattern()))
+ $replace['{'.$key.'}']=$encodeGetItems ? rawurlencode($value) : $value;
+ else
+ $extra[$key]=$value;
+ }
+
+ $url=$this->_manager->getUrlPrefix().'/'.ltrim(strtr($this->getPattern(),$replace),'/');
+
+ // for the rest of the GET variables, put them in the query string
+ if(count($extra)>0)
+ {
+ if ($this->_urlFormat===THttpRequestUrlFormat::Path && $this->getIsWildCardPattern()) {
+ foreach ($extra as $name=>$value)
+ $url.='/'.$name.$this->_separator.($encodeGetItems?rawurlencode($value):$value);
+ return $url;
+ }
+
+ $url2='';
+ $amp=$encodeAmpersand?'&amp;':'&';
+ if($encodeGetItems)
+ {
+ foreach($extra as $name=>$value)
+ {
+ if(is_array($value))
+ {
+ $name=rawurlencode($name.'[]');
+ foreach($value as $v)
+ $url2.=$amp.$name.'='.rawurlencode($v);
+ }
+ else
+ $url2.=$amp.rawurlencode($name).'='.rawurlencode($value);
+ }
+ }
+ else
+ {
+ foreach($extra as $name=>$value)
+ {
+ if(is_array($value))
+ {
+ foreach($value as $v)
+ $url2.=$amp.$name.'[]='.$v;
+ }
+ else
+ $url2.=$amp.$name.'='.$value;
+ }
+ }
+ $url=$url.'?'.substr($url2,strlen($amp));
+ }
+ return $this -> applySecureConnectionPrefix($url);
+ }
+
+ /**
+ * Apply behavior of {@link SecureConnection} property by conditionaly prefixing
+ * URL with {@link THttpRequest::getBaseUrl()}
+ *
+ * @param string $url
+ * @return string
+ * @since 3.2
+ */
+ protected function applySecureConnectionPrefix($url)
+ {
+ static $request;
+ if($request === null) $request = Prado::getApplication() -> getRequest();
+
+ static $isSecureConnection;
+ if($isSecureConnection === null) $isSecureConnection = $request -> getIsSecureConnection();
+
+ switch($this -> getSecureConnection())
+ {
+ case TUrlMappingPatternSecureConnection::EnableIfNotSecure:
+ if($isSecureConnection) return $url;
+ return $request -> getBaseUrl(true) . $url;
+ break;
+ case TUrlMappingPatternSecureConnection::DisableIfSecure:
+ if(!$isSecureConnection) return $url;
+ return $request -> getBaseUrl(false) . $url;
+ break;
+ case TUrlMappingPatternSecureConnection::Enable:
+ return $request -> getBaseUrl(true) . $url;
+ break;
+ case TUrlMappingPatternSecureConnection::Disable:
+ return $request -> getBaseUrl(false) . $url;
+ break;
+ case TUrlMappingPatternSecureConnection::Automatic:
+ default:
+ return $url;
+ break;
+ }
+ }
+}
+
+/**
+ * TUrlMappingPatternSecureConnection class
+ *
+ * TUrlMappingPatternSecureConnection defines the enumerable type for the possible SecureConnection
+ * URL prefix behavior that can be used by {@link TUrlMappingPattern::constructUrl()}.
+ *
+ * @author Yves Berkholz <godzilla80[at]gmx[dot]net>
+ * @package System.Web
+ * @since 3.2
+ */
+class TUrlMappingPatternSecureConnection extends TEnumerable
+{
+ /**
+ * Keep current SecureConnection status
+ * means no prefixing
+ */
+ const Automatic = 'Automatic';
+
+ /**
+ * Force use secured connection
+ * always prefixing with https://example.com/path/to/app
+ */
+ const Enable = 'Enable';
+
+ /**
+ * Force use unsecured connection
+ * always prefixing with http://example.com/path/to/app
+ */
+ const Disable = 'Disable';
+
+ /**
+ * Force use secured connection, if in unsecured mode
+ * prefixing with https://example.com/path/to/app
+ */
+ const EnableIfNotSecure = 'EnableIfNotSecure';
+
+ /**
+ * Force use unsecured connection, if in secured mode
+ * prefixing with https://example.com/path/to/app
+ */
+ const DisableIfSecure = 'DisableIfSecure';
+}
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveButton.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveButton.php
new file mode 100644
index 0000000..ae5b7f0
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveButton.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ * TActiveButton class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TActiveButton is the active control counter part to TButton.
+ *
+ * When a TActiveButton is clicked, rather than a normal post back request a
+ * callback request is initiated.
+ *
+ * The {@link onCallback OnCallback} event is raised during a callback request
+ * and it is raise <b>after</b> the {@link onClick OnClick} event.
+ *
+ * When the {@link TBaseActiveCallbackControl::setEnableUpdate ActiveControl.EnableUpdate}
+ * property is true, changing the {@link setText Text} property during callback request
+ * will update the button's caption upon callback response completion.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveButton extends TButton implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Raises the callback event. This method is required by
+ * {@link ICallbackEventHandler} interface. If {@link getCausesValidation CausesValidation}
+ * is true, it will invoke the page's {@link TPage::validate validate}
+ * method first. It will raise {@link onClick OnClick} event first
+ * and then the {@link onCallback OnCallback} event.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->raisePostBackEvent($param);
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Updates the button text on the client-side if the
+ * {@link setEnableUpdate EnableUpdate} property is set to true.
+ * @param string caption of the button
+ */
+ public function setText($value)
+ {
+ parent::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'value', $value);
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TActiveButton.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveButton';
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveCheckBox.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveCheckBox.php
new file mode 100644
index 0000000..034666f
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveCheckBox.php
@@ -0,0 +1,179 @@
+<?php
+/**
+ * TActiveCheckBox class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TActiveCheckBox class.
+ *
+ * The active control counter part to checkbox. The {@link setAutoPostBack AutoPostBack}
+ * property is set to true by default. Thus, when the checkbox is clicked a
+ * {@link onCallback OnCallback} event is raise after {@link OnCheckedChanged} event.
+ *
+ * The {@link setText Text} and {@link setChecked Checked} properties can be
+ * changed during a callback.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveCheckBox extends TCheckBox implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ $this->setAutoPostBack(true);
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Updates the button text on the client-side if the
+ * {@link setEnableUpdate EnableUpdate} property is set to true.
+ * @param string caption of the button
+ */
+ public function setText($value)
+ {
+ parent::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->update(
+ $this->getDefaultLabelID(), $value);
+ }
+
+ /**
+ * Sets a value indicating whether the checkbox is to be checked or not.
+ * Updates checkbox checked state on the client-side if the
+ * {@link setEnableUpdate EnableUpdate} property is set to true.
+ * @param boolean whether the checkbox is to be checked or not.
+ */
+ public function setChecked($value)
+ {
+ $value = TPropertyValue::ensureBoolean($value);
+ parent::setChecked($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->check($this, $value);
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ *
+ * Since 3.1.4, the javascript code is not rendered if {@link setAutoPostBack AutoPostBack} is false
+ *
+ * @param THtmlWriter the writer for the rendering purpose
+ * @param string checkbox id
+ * @param string onclick js
+ */
+ protected function renderInputTag($writer,$clientID,$onclick)
+ {
+ parent::renderInputTag($writer,$clientID,$onclick);
+ if ($this->getAutoPostBack())
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TActiveCheckBox.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveCheckBox';
+ }
+
+ /**
+ * Overrides parent implementation to ensure label has ID.
+ * @return TMap list of attributes to be rendered for label beside the checkbox
+ */
+ public function getLabelAttributes()
+ {
+ $attributes = parent::getLabelAttributes();
+ $attributes['id'] = $this->getDefaultLabelID();
+ return $attributes;
+ }
+
+ /**
+ * Renders a label beside the checkbox.
+ * @param THtmlWriter the writer for the rendering purpose
+ * @param string checkbox id
+ * @param string label text
+ */
+ protected function renderLabel($writer,$clientID,$text)
+ {
+ $writer->addAttribute('id', $this->getDefaultLabelID());
+ parent::renderLabel($writer, $clientID, $text);
+ }
+
+ /**
+ * @return string checkbox label ID;
+ */
+ protected function getDefaultLabelID()
+ {
+ if($attributes=$this->getViewState('LabelAttributes',null))
+ return TCheckBox::getLabelAttributes()->itemAt('id');
+ else
+ return $this->getClientID().'_label';
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveCheckBoxList.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveCheckBoxList.php
new file mode 100644
index 0000000..dfcb72c
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveCheckBoxList.php
@@ -0,0 +1,148 @@
+<?php
+/**
+ * TActiveCheckBoxList class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveListControlAdapter');
+
+/**
+ * TActiveCheckBoxList class.
+ *
+ * The active control counter part to checkbox list control.
+ * The {@link setAutoPostBack AutoPostBack} property is set to true by default.
+ * Thus, when a checkbox is clicked a {@link onCallback OnCallback} event is
+ * raised after {@link OnSelectedIndexChanged} event.
+ *
+ * With {@link TBaseActiveControl::setEnableUpdate() ActiveControl.EnableUpdate}
+ * set to true (default is true), changes to the selection will be updated
+ * on the client side.
+ *
+ * List items can not be changed dynamically during a callback request.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveCheckBoxList extends TCheckBoxList implements IActiveControl, ICallbackEventHandler
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveListControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ $this->setAdapter(new TActiveListControlAdapter($this));
+ $this->setAutoPostBack(true);
+ parent::__construct();
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Creates a control used for repetition (used as a template).
+ * @return TControl the control to be repeated
+ */
+ protected function createRepeatedControl()
+ {
+ $control = new TActiveCheckBoxListItem;
+ $control->getAdapter()->setBaseActiveControl($this->getActiveControl());
+ return $control;
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ if($this->getEnableClientScript()
+ && $this->getAutoPostBack()
+ && $this->getPage()->getClientSupportsJavaScript())
+ {
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveCheckBoxList';
+ }
+}
+
+class TActiveCheckBoxListItem extends TActiveCheckBox
+{
+ /**
+ * Override client implementation to avoid emitting the javascript
+ *
+ * @param THtmlWriter the writer for the rendering purpose
+ * @param string checkbox id
+ * @param string onclick js
+ */
+ protected function renderInputTag($writer,$clientID,$onclick)
+ {
+ TCheckBox::renderInputTag($writer,$clientID,$onclick);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveClientScript.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveClientScript.php
new file mode 100755
index 0000000..4093d8f
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveClientScript.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * TActiveClientScript class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TActiveClientScript class
+ *
+ * This is the active counterpart of the {@link TClientScript} class.
+ *
+ * TActiveClientScript has the ability to render itself on ajax
+ * callbacks. This means that every variable or function declared in javascript
+ * code will be available to the page.
+ *
+ * Beware that when rendered on normal (postback) or ajax callbacks, some
+ * javascript code won't behave in the same way.
+ * When rendered as part of a normal/postback response, scripts will execute instantly
+ * where they are in the page and in a synchronous fashion.
+ * Instead, when they are rendered as part of a callback response,
+ * they will be executed when all DOM modifications are complete and any dynamic
+ * script file includes are loaded, out-of-band and practically all blocks at once,
+ * regardless of where they actually occour in the original template/markup code.
+ * This can potentially hurt compatibility and graceful fallback.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.2
+ */
+
+class TActiveClientScript extends TClientScript
+{
+ /**
+ * Renders the custom script file.
+ * @param THtmLWriter the renderer
+ */
+ protected function renderCustomScriptFile($writer)
+ {
+ if(($scriptUrl = $this->getScriptUrl())!=='')
+ {
+ if($this->getPage()->getIsCallback())
+ {
+ $cs = $this->getPage()->getClientScript();
+ $uniqueid=$this->ClientID.'_custom';
+ if(!$cs->isScriptFileRegistered($uniqueid))
+ $cs->registerScriptFile($uniqueid, $scriptUrl);
+ } else {
+ $writer->write("<script type=\"text/javascript\" src=\"$scriptUrl\"></script>\n");
+ }
+ }
+ }
+
+ /**
+ * Registers the body content as javascript.
+ * @param THtmlWriter the renderer
+ */
+ protected function renderCustomScript($writer)
+ {
+ if($this->getHasControls())
+ {
+ if($this->getPage()->getIsCallback())
+ {
+ $extWriter= $this->getPage()->getResponse()->createHtmlWriter();
+ $extWriter->write("/*<![CDATA[*/\n");
+ $this->renderChildren($extWriter);
+ $extWriter->write("\n/*]]>*/");
+ $this->getPage()->getCallbackClient()->appendScriptBlock($extWriter);
+ } else {
+ $writer->write("<script type=\"text/javascript\">\n/*<![CDATA[*/\n");
+ $this->renderChildren($writer);
+ $writer->write("\n/*]]>*/\n</script>\n");
+ }
+ }
+ }
+}
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveControlAdapter.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveControlAdapter.php
new file mode 100644
index 0000000..0cd39c7
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveControlAdapter.php
@@ -0,0 +1,561 @@
+<?php
+/**
+ * TActiveControlAdapter and TCallbackPageStateTracker class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/*
+ * Load common active control options.
+ */
+Prado::using('System.Web.UI.ActiveControls.TBaseActiveControl');
+
+/**
+ * TActiveControlAdapter class.
+ *
+ * Customize the parent TControl class for active control classes.
+ * TActiveControlAdapter instantiates a common base active control class
+ * throught the {@link getBaseActiveControl BaseActiveControl} property.
+ * The type of BaseActiveControl can be provided in the second parameter in the
+ * constructor. Default is TBaseActiveControl or TBaseActiveCallbackControl if
+ * the control adapted implements ICallbackEventHandler.
+ *
+ * TActiveControlAdapter will tracking viewstate changes to update the
+ * corresponding client-side properties.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveControlAdapter extends TControlAdapter
+{
+ /**
+ * @var string base active control class name.
+ */
+ private $_activeControlType;
+ /**
+ * @var TBaseActiveControl base active control instance.
+ */
+ private $_baseActiveControl;
+ /**
+ * @var TCallbackPageStateTracker view state tracker.
+ */
+ private $_stateTracker;
+ /**
+ * @var string view state tracker class.
+ */
+ private $_stateTrackerClass='TCallbackPageStateTracker';
+
+ /**
+ * Constructor.
+ * @param IActiveControl active control to adapt.
+ * @param string Base active control class name.
+ */
+ public function __construct(IActiveControl $control, $baseCallbackClass=null)
+ {
+ parent::__construct($control);
+ $this->setBaseControlClass($baseCallbackClass);
+ }
+
+ /**
+ * @param string base active control instance
+ */
+ protected function setBaseControlClass($type)
+ {
+ if($type===null)
+ {
+ if($this->getControl() instanceof ICallbackEventHandler)
+ $this->_activeControlType = 'TBaseActiveCallbackControl';
+ else
+ $this->_activeControlType = 'TBaseActiveControl';
+ }
+ else
+ $this->_activeControlType = $type;
+ }
+
+ /**
+ * Publish the ajax script
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ }
+
+ /**
+ * Renders the callback client scripts.
+ */
+ public function render($writer)
+ {
+ $this->getPage()->getClientScript()->registerPradoScript('ajax');
+ if($this->_control->getVisible(false))
+ {
+ parent::render($writer);
+ } else {
+ $writer->write("<span id=\"".$this->_control->getClientID()."\" style=\"display:none\"></span>");
+ }
+ }
+
+ /**
+ * @param TBaseActiveControl change base active control
+ */
+ public function setBaseActiveControl($control)
+ {
+ $this->_baseActiveControl=$control;
+ }
+
+ /**
+ * @return TBaseActiveControl Common active control options.
+ */
+ public function getBaseActiveControl()
+ {
+ if($this->_baseActiveControl===null)
+ {
+ $type = $this->_activeControlType;
+ $this->_baseActiveControl = new $type($this->getControl());
+ }
+ return $this->_baseActiveControl;
+ }
+
+ /**
+ * @return boolean true if the viewstate needs to be tracked.
+ */
+ protected function getIsTrackingPageState()
+ {
+ if($this->getPage()->getIsCallback())
+ {
+ $target = $this->getPage()->getCallbackEventTarget();
+ if($target instanceof ICallbackEventHandler)
+ {
+ $client = $target->getActiveControl()->getClientSide();
+ return $client->getEnablePageStateUpdate();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Starts viewstate tracking if necessary after when controls has been loaded
+ */
+ public function onLoad($param)
+ {
+ if($this->getIsTrackingPageState())
+ {
+ $stateTrackerClass = $this->_stateTrackerClass;
+ $this->_stateTracker = new $stateTrackerClass($this->getControl());
+ $this->_stateTracker->trackChanges();
+ }
+ parent::onLoad($param);
+ }
+
+ /**
+ * Saves additional persistent control state. Respond to viewstate changes
+ * if necessary.
+ */
+ public function saveState()
+ {
+ if(($this->_stateTracker!==null)
+ && $this->getControl()->getActiveControl()->canUpdateClientSide(true))
+ {
+ $this->_stateTracker->respondToChanges();
+ }
+ parent::saveState();
+ }
+
+ /**
+ * @return TCallbackPageStateTracker state tracker.
+ */
+ public function getStateTracker()
+ {
+ return $this->_stateTracker;
+ }
+
+ /**
+ * @param string state tracker class.
+ */
+ public function setStateTracker($value)
+ {
+ $this->_stateTrackerClass = TPropertyValue::ensureString($value);
+ }
+}
+
+/**
+ * TCallbackPageStateTracker class.
+ *
+ * Tracking changes to the page state during callback.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackPageStateTracker
+{
+ /**
+ * @var TMap new view state data
+ */
+ private $_states;
+ /**
+ * @var TMap old view state data
+ */
+ private $_existingState;
+ /**
+ * @var TControl the control tracked
+ */
+ protected $_control;
+ /**
+ * @var object null object.
+ */
+ private $_nullObject;
+
+ /**
+ * Constructor. Add a set of default states to track.
+ * @param TControl control to track.
+ */
+ public function __construct($control)
+ {
+ $this->_control = $control;
+ $this->_existingState = new TMap;
+ $this->_nullObject = new stdClass;
+ $this->_states = new TMap;
+ $this->addStatesToTrack();
+ }
+
+ /**
+ * Add a list of view states to track. Each state is added
+ * to the StatesToTrack property with the view state name as key.
+ * The value should be an array with two enteries. The first entery
+ * is the name of the class that will calculate the state differences.
+ * The second entry is a php function/method callback that handles
+ * the changes in the viewstate.
+ */
+ protected function addStatesToTrack()
+ {
+ $states = $this->getStatesToTrack();
+ $states['Visible'] = array('TScalarDiff', array($this, 'updateVisible'));
+ $states['Enabled'] = array('TScalarDiff', array($this, 'updateEnabled'));
+ $states['Attributes'] = array('TMapCollectionDiff', array($this, 'updateAttributes'));
+ $states['Style'] = array('TStyleDiff', array($this, 'updateStyle'));
+ $states['TabIndex'] = array('TScalarDiff', array($this, 'updateTabIndex'));
+ $states['ToolTip'] = array('TScalarDiff', array($this, 'updateToolTip'));
+ $states['AccessKey'] = array('TScalarDiff', array($this, 'updateAccessKey'));
+ }
+
+ /**
+ * @return TMap list of viewstates to track.
+ */
+ protected function getStatesToTrack()
+ {
+ return $this->_states;
+ }
+
+ /**
+ * Start tracking view state changes. The clone function on objects are called
+ * for those viewstate having an object as value.
+ */
+ public function trackChanges()
+ {
+ foreach($this->_states as $name => $value)
+ {
+ $obj = $this->_control->getViewState($name);
+ $this->_existingState[$name] = is_object($obj) ? clone($obj) : $obj;
+ }
+ }
+
+ /**
+ * @return array list of viewstate and the changed data.
+ */
+ protected function getChanges()
+ {
+ $changes = array();
+ foreach($this->_states as $name => $details)
+ {
+ $new = $this->_control->getViewState($name);
+ $old = $this->_existingState[$name];
+ if($new !== $old)
+ {
+ $diff = new $details[0]($new, $old, $this->_nullObject);
+ if(($change = $diff->getDifference()) !== $this->_nullObject)
+ $changes[] = array($details[1],array($change));
+ }
+ }
+ return $changes;
+ }
+
+ /**
+ * For each of the changes call the corresponding change handlers.
+ */
+ public function respondToChanges()
+ {
+ foreach($this->getChanges() as $change)
+ call_user_func_array($change[0], $change[1]);
+ }
+
+ /**
+ * @return TCallbackClientScript callback client scripting
+ */
+ protected function client()
+ {
+ return $this->_control->getPage()->getCallbackClient();
+ }
+
+ /**
+ * Updates the tooltip.
+ * @param string new tooltip
+ */
+ protected function updateToolTip($value)
+ {
+ $this->client()->setAttribute($this->_control, 'title', $value);
+ }
+
+ /**
+ * Updates the tab index.
+ * @param integer tab index
+ */
+ protected function updateTabIndex($value)
+ {
+ $this->client()->setAttribute($this->_control, 'tabindex', $value);
+ }
+
+ /**
+ * Updates the modifier access key
+ * @param string access key
+ */
+ protected function updateAccessKey($value)
+ {
+ $this->client()->setAttribute($this->_control, 'accesskey', $value);
+ }
+
+ /**
+ * Hides or shows the control on the client-side. The control must be
+ * already rendered on the client-side.
+ * @param boolean true to show the control, false to hide.
+ */
+ protected function updateVisible($visible)
+ {
+ if($visible === false)
+ $this->client()->replaceContent($this->_control,"<span id=\"".$this->_control->getClientID()."\" style=\"display:none\" ></span>");
+ else
+ $this->client()->replaceContent($this->_control,$this->_control);
+ }
+
+ /**
+ * Enables or Disables the control on the client-side.
+ * @param boolean true to enable the control, false to disable.
+ */
+ protected function updateEnabled($enable)
+ {
+ $this->client()->setAttribute($this->_control, 'disabled', $enable===false);
+ }
+
+ /**
+ * Updates the CSS style on the control on the client-side.
+ * @param array list of new CSS style declarations.
+ */
+ protected function updateStyle($style)
+ {
+ if($style['CssClass']!==null)
+ $this->client()->setAttribute($this->_control, 'class', $style['CssClass']);
+ if(count($style['Style']) > 0)
+ $this->client()->setStyle($this->_control, $style['Style']);
+ }
+
+ /**
+ * Updates/adds a list of attributes on the control.
+ * @param array list of attribute name-value pairs.
+ */
+ protected function updateAttributes($attributes)
+ {
+ foreach($attributes as $name => $value)
+ $this->client()->setAttribute($this->_control, $name, $value);
+ }
+}
+
+/**
+ * Calculates the viewstate changes during the request.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+abstract class TViewStateDiff
+{
+ /**
+ * @var mixed updated viewstate
+ */
+ protected $_new;
+ /**
+ * @var mixed viewstate value at the begining of the request.
+ */
+ protected $_old;
+ /**
+ * @var object null value.
+ */
+ protected $_null;
+
+ /**
+ * Constructor.
+ * @param mixed updated viewstate value.
+ * @param mixed viewstate value at the begining of the request.
+ * @param object representing the null value.
+ */
+ public function __construct($new, $old, $null)
+ {
+ $this->_new = $new;
+ $this->_old = $old;
+ $this->_null = $null;
+ }
+
+ /**
+ * @return mixed view state changes, nullObject if no difference.
+ */
+ public abstract function getDifference();
+}
+
+/**
+ * TScalarDiff class.
+ *
+ * Calculate the changes to a scalar value.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TScalarDiff extends TViewStateDiff
+{
+ /**
+ * @return mixed update viewstate value.
+ */
+ public function getDifference()
+ {
+ if(gettype($this->_new) === gettype($this->_old)
+ && $this->_new === $this->_old)
+ return $this->_null;
+ else
+ return $this->_new;
+ }
+}
+
+/**
+ * TStyleDiff class.
+ *
+ * Calculates the changes to the Style properties.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TStyleDiff extends TViewStateDiff
+{
+ /**
+ * @param TStyle control style
+ * @return array all the style properties combined.
+ */
+ protected function getCombinedStyle($obj)
+ {
+ if(!($obj instanceof TStyle))
+ return array();
+ $style = $obj->getStyleFields();
+ $style = array_merge($style,$this->getStyleFromString($obj->getCustomStyle()));
+ if($obj->hasFont())
+ $style = array_merge($style, $this->getStyleFromString($obj->getFont()->toString()));
+ return $style;
+ }
+
+ /**
+ * @param string CSS custom style string.
+ * @param array CSS style as name-value array.
+ */
+ protected function getStyleFromString($string)
+ {
+ $style = array();
+ if(!is_string($string)) return $style;
+
+ foreach(explode(';',$string) as $sub)
+ {
+ $arr=explode(':',$sub);
+ if(isset($arr[1]) && trim($arr[0])!=='')
+ $style[trim($arr[0])] = trim($arr[1]);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string changes to the CSS class name.
+ */
+ protected function getCssClassDiff()
+ {
+ if($this->_old===null)
+ {
+ return ($this->_new!==null) && $this->_new->hasCssClass()
+ ? $this->_new->getCssClass() : null;
+ }
+ else
+ {
+ return $this->_old->getCssClass() !== $this->_new->getCssClass() ?
+ $this->_new->getCssClass() : null;
+ }
+ }
+
+ /**
+ * @return array list of changes to the control style.
+ */
+ protected function getStyleDiff()
+ {
+ $diff = array_diff_assoc(
+ $this->getCombinedStyle($this->_new),
+ $this->getCombinedStyle($this->_old));
+ return count($diff) > 0 ? $diff : null;
+ }
+
+ /**
+ * @return array list of changes to the control style and CSS class name.
+ */
+ public function getDifference()
+ {
+ if($this->_new===null)
+ return $this->_null;
+ else
+ {
+ $css = $this->getCssClassDiff();
+ $style = $this->getStyleDiff();
+ if(($css!==null) || ($style!==null))
+ return array('CssClass' => $css, 'Style' => $style);
+ else
+ $this->_null;
+ }
+ }
+}
+
+/**
+ * TAttributesDiff class.
+ *
+ * Calculate the changes to attributes collection.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TMapCollectionDiff extends TViewStateDiff
+{
+ /**
+ * @return array updates to the attributes collection.
+ */
+ public function getDifference()
+ {
+ if($this->_old===null)
+ {
+ return ($this->_new!==null) ? $this->_new->toArray() : $this->_null;
+ }
+ else
+ {
+ $new = $this->_new->toArray();
+ $old = $this->_old->toArray();
+ $diff = array_diff_assoc($new, $old);
+ return count($diff) > 0 ? $diff : $this->_null;
+ }
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveCustomValidator.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveCustomValidator.php
new file mode 100644
index 0000000..18f9f5f
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveCustomValidator.php
@@ -0,0 +1,262 @@
+<?php
+/**
+ * TActiveCustomValidator class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TCallbackClientSide');
+
+/**
+ * TActiveCustomValidator Class
+ *
+ * Performs custom validation using only server-side {@link onServerValidate onServerValidate}
+ * validation event. The client-side uses callbacks to raise
+ * the {@link onServerValidate onServerValidate} event.
+ *
+ * Beware that the {@link onServerValidate onServerValidate} may be
+ * raised when the control to validate on the client side
+ * changes value, that is, the server validation may be called many times.
+ *
+ * After the callback or postback, the {@link onServerValidate onServerValidate}
+ * is raised once more. The {@link getIsCallback IsCallback} property
+ * will be true when validation is made during a callback request.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveCustomValidator extends TCustomValidator
+ implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * @var boolean true if validation is made during a callback request.
+ */
+ private $_isCallback = false;
+
+ /**
+ * @return boolean true if validation is made during a callback request.
+ */
+ public function getIsCallback()
+ {
+ return $this->_isCallback;
+ }
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ $this->getActiveControl()->setClientSide(new TActiveCustomValidatorClientSide);
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Client validation function is NOT supported.
+ */
+ public function setClientValidationFunction($value)
+ {
+ throw new TNotSupportedException('tactivecustomvalidator_clientfunction_unsupported',
+ get_class($this));
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface. The {@link onServerValidate
+ * OnServerValidate} event is raised first and then the
+ * {@link onCallback OnCallback} event.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->_isCallback = true;
+ $result = $this->onServerValidate($param->getCallbackParameter());
+ $param->setResponseData($result);
+ $this->onCallback($param);
+ }
+
+ /**
+ * @param boolean whether the value is valid; this method will trigger a clientside update if needed
+ */
+ public function setIsValid($value)
+ {
+ parent::setIsValid($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $func = 'Prado.Validation.updateActiveCustomValidator';
+ $client->callClientFunction($func, array($this, $value));
+ }
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options=TBaseValidator::getClientScriptOptions();
+ $options['EventTarget'] = $this->getUniqueID();
+ return $options;
+ }
+
+ /**
+ * Sets the text for the error message. Updates client-side erorr message.
+ * @param string the error message
+ */
+ public function setErrorMessage($value)
+ {
+ parent::setErrorMessage($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $func = 'Prado.Validation.setErrorMessage';
+ $client->callClientFunction($func, array($this, $value));
+ }
+ }
+
+
+ /**
+ * It's mandatory for the EnableClientScript to be activated or the TActiveCustomValidator won't work.
+ * @return boolean whether client-side validation is enabled.
+ */
+ public function getEnableClientScript()
+ {
+ return true;
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ TBaseValidator::registerClientScriptValidator();
+ }
+
+ /**
+ * @return string corresponding javascript class name for this this.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveCustomValidator';
+ }
+}
+
+/**
+ * Custom Validator callback client side options class.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveCustomValidatorClientSide extends TCallbackClientSide
+{
+ /**
+ * @return string javascript code for client-side OnValidate event.
+ */
+ public function getOnValidate()
+ {
+ return $this->getOption('OnValidate');
+ }
+
+ /**
+ * Client-side OnValidate validator event is raise before the validators
+ * validation functions are called.
+ * @param string javascript code for client-side OnValidate event.
+ */
+ public function setOnValidate($javascript)
+ {
+ $this->setFunction('OnValidate', $javascript);
+ }
+
+ /**
+ * Client-side OnSuccess event is raise after validation is successfull.
+ * This will override the default client-side validator behaviour.
+ * @param string javascript code for client-side OnSuccess event.
+ */
+ public function setOnValidationSuccess($javascript)
+ {
+ $this->setFunction('OnValidationSuccess', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side OnSuccess event.
+ */
+ public function getOnValidationSuccess()
+ {
+ return $this->getOption('OnValidationSuccess');
+ }
+
+ /**
+ * Client-side OnError event is raised after validation failure.
+ * This will override the default client-side validator behaviour.
+ * @param string javascript code for client-side OnError event.
+ */
+ public function setOnValidationError($javascript)
+ {
+ $this->setFunction('OnValidationError', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side OnError event.
+ */
+ public function getOnValidationError()
+ {
+ return $this->getOption('OnValidationError');
+ }
+
+ /**
+ * @param boolean true to revalidate when the control to validate changes value.
+ */
+ public function setObserveChanges($value)
+ {
+ $this->setOption('ObserveChanges', TPropertyValue::ensureBoolean($value));
+ }
+
+ /**
+ * @return boolean true to observe changes.
+ */
+ public function getObserveChanges()
+ {
+ $changes = $this->getOption('ObserveChanges');
+ return ($changes===null) ? true : $changes;
+ }
+}
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveDataGrid.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveDataGrid.php
new file mode 100644
index 0000000..60a9ae3
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveDataGrid.php
@@ -0,0 +1,851 @@
+<?php
+/**
+ * TActiveDataGrid class file
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @link http://www.landwehr-software.de/
+ * @copyright Copyright &copy; 2009 LANDWEHR Computer und Software GmbH
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Includes the following used classes
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+Prado::using('System.Web.UI.ActiveControls.TActiveLinkButton');
+Prado::using('System.Web.UI.ActiveControls.TActiveImageButton');
+Prado::using('System.Web.UI.ActiveControls.TActiveButton');
+Prado::using('System.Web.UI.ActiveControls.TActiveImage');
+Prado::using('System.Web.UI.ActiveControls.TActiveCheckBox');
+Prado::using('System.Web.UI.ActiveControls.TCallbackOptions');
+Prado::using('System.Web.UI.WebControls.TDataGrid');
+Prado::using('System.Web.UI.WebControls.TBoundColumn');
+Prado::using('System.Web.UI.WebControls.TEditCommandColumn');
+Prado::using('System.Web.UI.WebControls.TButtonColumn');
+Prado::using('System.Web.UI.WebControls.THyperLinkColumn');
+Prado::using('System.Web.UI.WebControls.TCheckBoxColumn');
+
+/**
+ * TActiveDataGrid class
+ *
+ * TActiveDataGrid represents a data bound and updatable grid control which is the
+ * active counterpart to the original {@link TDataGrid} control.
+ *
+ * This component can be used in the same way as the regular datagrid, the only
+ * difference is that the active datagrid uses callbacks instead of postbacks
+ * for interaction.
+ *
+ * There are also active datagrid columns to work with the TActiveDataGrid, which are
+ * - {@link TActiveBoundColumn}, the active counterpart to {@link TBoundColumn}.
+ * - {@link TActiveLiteralColumn}, the active counterpart to {@link TLiteralColumn}.
+ * - {@link TActiveCheckBoxColumn}, the active counterpart to {@link TCheckBoxColumn}.
+ * - {@link TActiveDropDownListColumn}, the active counterpart to {@link TDropDownListColumn}.
+ * - {@link TActiveHyperLinkColumn}, the active counterpart to {@link THyperLinkColumn}.
+ * - {@link TActiveEditCommandColumn}, the active counterpart to {@link TEditCommandColumn}.
+ * - {@link TActiveButtonColumn}, the active counterpart to {@link TButtonColumn}.
+ * - {@link TActiveTemplateColumn}, the active counterpart to {@link TTemplateColumn}.
+ *
+ * Please refer to the original documentation of the regular counterparts for usage.
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.9
+ */
+class TActiveDataGrid extends TDataGrid implements IActiveControl, ISurroundable {
+
+ /**
+ * @var string the tag used to render the surrounding container
+ */
+ protected $_surroundingTag='div';
+
+ /**
+ * @return string Name of the class used in AutoGenerateColumns mode
+ */
+ protected function getAutoGenerateColumnName()
+ {
+ return 'TActiveBoundColumn';
+ }
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter.
+ */
+ public function __construct() {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveControl standard active control options.
+ */
+ public function getActiveControl() {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * Sets the data source object associated with the datagrid control.
+ * In addition, the render method of all connected pagers is called so they
+ * get updated when the data source is changed. Also the datagrid registers
+ * itself for rendering in order to get it's content replaced on client side.
+ * @param Traversable|array|string data source object
+ */
+ public function setDataSource($value) {
+ parent::setDataSource($value);
+ if($this->getActiveControl()->canUpdateClientSide()) {
+ $this->renderPager();
+ $this->getPage()->getAdapter()->registerControlToRender($this,$this->getResponse()->createHtmlWriter());
+ }
+ }
+
+ /**
+ * Gets the tag used to render the surrounding container. Defaults to 'div'.
+ * @return string container tag
+ */
+ public function getSurroundingTag() {
+ return $this->_surroundingTag;
+ }
+
+ /**
+ * Sets the tag used to render the surrounding container.
+ * @param string $value container tag
+ */
+ public function setSurroundingTag($value) {
+ $this->_surroundingTag=TPropertyValue::ensureString($value);
+ }
+
+ /**
+ * Returns the id of the surrounding container.
+ * @return string container id
+ */
+ public function getSurroundingTagID() {
+ return $this->getClientID().'_Container';
+ }
+
+ /**
+ * Creates a pager button.
+ * Depending on the button type, a TActiveLinkButton or a TActiveButton may be created.
+ * If it is enabled (clickable), its command name and parameter will also be set.
+ * It overrides the datagrid's original method to create active controls instead, thus
+ * the pager will do callbacks instead of the regular postbacks.
+ * @param mixed the container pager instance of TActiveDatagridPager
+ * @param string button type, either LinkButton or PushButton
+ * @param boolean whether the button should be enabled
+ * @param string caption of the button
+ * @param string CommandName corresponding to the OnCommand event of the button
+ * @param string CommandParameter corresponding to the OnCommand event of the button
+ * @return mixed the button instance
+ */
+ protected function createPagerButton($pager,$buttonType,$enabled,$text,$commandName,$commandParameter) {
+ if($buttonType===TDataGridPagerButtonType::LinkButton) {
+ if($enabled)
+ $button=new TActiveLinkButton;
+ else {
+ $button=new TLabel;
+ $button->setText($text);
+ return $button;
+ }
+ }
+ else {
+ $button=new TActiveButton;
+ if(!$enabled)
+ $button->setEnabled(false);
+ }
+ $button->setText($text);
+ $button->setCommandName($commandName);
+ $button->setCommandParameter($commandParameter);
+ $button->setCausesValidation(false);
+ $button->getAdapter()->getBaseActiveControl()->setClientSide(
+ $pager->getClientSide()
+ );
+ return $button;
+ }
+
+ protected function createPager()
+ {
+ $pager=new TActiveDataGridPager($this);
+ $this->buildPager($pager);
+ $this->onPagerCreated(new TActiveDataGridPagerEventParameter($pager));
+ $this->getControls()->add($pager);
+ return $pager;
+ }
+
+ /**
+ * Renders the datagrid.
+ * If the datagrid did not pass the prerender phase yet, it will register itself for rendering later.
+ * Else it will call the {@link renderDataGrid()} method which will do the rendering of the datagrid.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer) {
+ if($this->getHasPreRendered()) {
+ $this->renderDataGrid($writer);
+ if($this->getActiveControl()->canUpdateClientSide()) $this->getPage()->getCallbackClient()->replaceContent($this->getSurroundingTagId(),$writer);
+ }
+ else {
+ $this->getPage()->getAdapter()->registerControlToRender($this,$writer);
+ }
+ }
+
+ /**
+ * Loops through all {@link TActivePager} on the page and registers the ones which are set to paginate
+ * the datagrid for rendering. This is to ensure that the connected pagers are also rendered if the
+ * data source changed.
+ */
+ private function renderPager() {
+ $pager=$this->getPage()->findControlsByType('TActivePager', false);
+ foreach($pager as $item) {
+ if($item->ControlToPaginate==$this->ID) {
+ $writer=$this->getResponse()->createHtmlWriter();
+ $this->getPage()->getAdapter()->registerControlToRender($item,$writer);
+ }
+ }
+ }
+
+ /**
+ * Renders the datagrid by writing a {@link getSurroundingTag()} with the container id obtained
+ * from {@link getSurroundingTagId()} which will be called by the replacement method of the client
+ * script to update it's content.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ private function renderDataGrid($writer) {
+ $writer->addAttribute('id',$this->getSurroundingTagID());
+ $writer->renderBeginTag($this->getSurroundingTag());
+ parent::render($writer);
+ $writer->renderEndTag();
+ }
+}
+
+
+/**
+ * TActiveBoundColumn class
+ *
+ * TActiveBoundColumn represents a column that is bound to a field in a data source.
+ * The cells in the column will be displayed using the data indexed by
+ * {@link setDataField DataField}. You can customize the display by
+ * setting {@link setDataFormatString DataFormatString}.
+ *
+ * This is the active counterpart to the {@link TBoundColumn} control. For that purpose,
+ * if sorting is allowed, the header links/buttons are replaced by active controls.
+ *
+ * Please refer to the original documentation of the {@link TBoundColumn} for usage.
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.9
+ */
+class TActiveBoundColumn extends TBoundColumn {
+ protected function initializeHeaderCell($cell,$columnIndex) {
+ $text=$this->getHeaderText();
+
+ if(($classPath=$this->getHeaderRenderer())!=='') {
+ $control=Prado::createComponent($classPath);
+ if($control instanceof IDataRenderer) {
+ if($control instanceof IItemDataRenderer) {
+ $item=$cell->getParent();
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $control->setData($text);
+ }
+ $cell->getControls()->add($control);
+ }
+ else if($this->getAllowSorting()) {
+ $sortExpression=$this->getSortExpression();
+ if(($url=$this->getHeaderImageUrl())!=='') {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveImageButton');
+ $button->setImageUrl($url);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ if($text!=='') {
+ $button->setAlternateText($text);
+ $button->setToolTip($text);
+ }
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else if($text!=='') {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveLinkButton');
+ $button->setText($text);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else
+ $cell->setText('&nbsp;');
+ }
+ else {
+ if(($url=$this->getHeaderImageUrl())!=='') {
+ $image=Prado::createComponent('System.Web.UI.WebControls.TActiveImage');
+ $image->setImageUrl($url);
+ if($text!=='') {
+ $image->setAlternateText($text);
+ $image->setToolTip($text);
+ }
+ $cell->getControls()->add($image);
+ }
+ else if($text!=='')
+ $cell->setText($text);
+ else
+ $cell->setText('&nbsp;');
+ }
+ }
+}
+
+
+/**
+ * TActiveEditCommandColumn class
+ *
+ * TActiveEditCommandColumn contains the Edit command buttons for editing data items in each row.
+ *
+ * TActiveEditCommandColumn will create an edit button if a cell is not in edit mode.
+ * Otherwise an update button and a cancel button will be created within the cell.
+ * The button captions are specified using {@link setEditText EditText},
+ * {@link setUpdateText UpdateText}, and {@link setCancelText CancelText}.
+ *
+ * This is the active counterpart to the {@link TEditCommandColumn} control. The buttons for
+ * interaction are replaced by active buttons.
+ *
+ * Please refer to the original documentation of the {@link TEditCommandColumn} for usage.
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.9
+ */
+class TActiveEditCommandColumn extends TEditCommandColumn {
+ protected function createButton($commandName,$text,$causesValidation,$validationGroup) {
+ if($this->getButtonType()===TButtonColumnType::LinkButton)
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveLinkButton');
+ else if($this->getButtonType()===TButtonColumnType::PushButton)
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveButton');
+ else // image buttons
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveImageButton');
+ $button->setToolTip($text);
+ if(strcasecmp($commandName,'Update')===0)
+ $url=$this->getUpdateImageUrl();
+ else if(strcasecmp($commandName,'Cancel')===0)
+ $url=$this->getCancelImageUrl();
+ else
+ $url=$this->getEditImageUrl();
+ $button->setImageUrl($url);
+ }
+ $button->setText($text);
+ $button->setCommandName($commandName);
+ $button->setCausesValidation($causesValidation);
+ $button->setValidationGroup($validationGroup);
+ return $button;
+ }
+}
+
+
+/**
+ * TActiveButtonColumn class
+ *
+ * TActiveButtonColumn contains a user-defined command button, such as Add or Remove,
+ * that corresponds with each row in the column.
+ *
+ * This is the active counterpart to the {@link TButtonColumn} control where the
+ * button is replaced by the appropriate active button control.
+ *
+ * Please refer to the original documentation of the {@link TButtonColumn} for usage.
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.9
+ */
+class TActiveButtonColumn extends TButtonColumn {
+ public function initializeCell($cell,$columnIndex,$itemType) {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem) {
+ $buttonType=$this->getButtonType();
+ if($buttonType===TButtonColumnType::LinkButton)
+ $button=new TActiveLinkButton;
+ else if($buttonType===TButtonColumnType::PushButton)
+ $button=new TActiveButton;
+ else // image button
+ {
+ $button=new TActiveImageButton;
+ $button->setImageUrl($this->getImageUrl());
+ $button->setToolTip($this->getText());
+ }
+ $button->setText($this->getText());
+ $button->setCommandName($this->getCommandName());
+ $button->setCausesValidation($this->getCausesValidation());
+ $button->setValidationGroup($this->getValidationGroup());
+ if($this->getDataTextField()!=='' || ($buttonType===TButtonColumnType::ImageButton && $this->getDataImageUrlField()!==''))
+ $button->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ $cell->getControls()->add($button);
+ $cell->registerObject('Button',$button);
+ }
+ else
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ }
+}
+
+
+/**
+ * TActiveTemplateColumn class
+ *
+ * TActiveTemplateColumn customizes the layout of controls in the column with templates.
+ * In particular, you can specify {@link setItemTemplate ItemTemplate},
+ * {@link setEditItemTemplate EditItemTemplate}, {@link setHeaderTemplate HeaderTemplate}
+ * and {@link setFooterTemplate FooterTemplate} to customize specific
+ * type of cells in the column.
+ *
+ * This is the active counterpart to the {@link TTemplateColumn} control. For that purpose,
+ * if sorting is allowed, the header links/buttons are replaced by active controls.
+ *
+ * Please refer to the original documentation of the {@link TTemplateColumn} for usage.
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.9
+ */
+class TActiveTemplateColumn extends TTemplateColumn {
+ protected function initializeHeaderCell($cell,$columnIndex) {
+ $text=$this->getHeaderText();
+
+ if(($classPath=$this->getHeaderRenderer())!=='') {
+ $control=Prado::createComponent($classPath);
+ if($control instanceof IDataRenderer) {
+ if($control instanceof IItemDataRenderer) {
+ $item=$cell->getParent();
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $control->setData($text);
+ }
+ $cell->getControls()->add($control);
+ }
+ else if($this->getAllowSorting()) {
+ $sortExpression=$this->getSortExpression();
+ if(($url=$this->getHeaderImageUrl())!=='') {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveImageButton');
+ $button->setImageUrl($url);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ if($text!=='')
+ $button->setAlternateText($text);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else if($text!=='') {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveLinkButton');
+ $button->setText($text);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else
+ $cell->setText('&nbsp;');
+ }
+ else {
+ if(($url=$this->getHeaderImageUrl())!=='') {
+ $image=Prado::createComponent('System.Web.UI.WebControls.TActiveImage');
+ $image->setImageUrl($url);
+ if($text!=='')
+ $image->setAlternateText($text);
+ $cell->getControls()->add($image);
+ }
+ else if($text!=='')
+ $cell->setText($text);
+ else
+ $cell->setText('&nbsp;');
+ }
+ }
+}
+
+/**
+ * TActiveHyperLinkColumn class
+ *
+ * TActiveHyperLinkColumn contains a hyperlink for each item in the column.
+ *
+ * This is the active counterpart to the {@link THyperLinkColumn} control. For that purpose,
+ * if sorting is allowed, the header links/buttons are replaced by active controls.
+ *
+ * Please refer to the original documentation of the {@link THyperLinkColumn} for usage.
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.9
+ */
+class TActiveHyperLinkColumn extends THyperLinkColumn
+{
+
+ protected function initializeHeaderCell($cell,$columnIndex)
+ {
+ $text=$this->getHeaderText();
+
+ if(($classPath=$this->getHeaderRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ if($control instanceof IDataRenderer)
+ {
+ if($control instanceof IItemDataRenderer)
+ {
+ $item=$cell->getParent();
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $control->setData($text);
+ }
+ $cell->getControls()->add($control);
+ }
+ else if($this->getAllowSorting())
+ {
+ $sortExpression=$this->getSortExpression();
+ if(($url=$this->getHeaderImageUrl())!=='')
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveImageButton');
+ $button->setImageUrl($url);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ if($text!=='')
+ $button->setAlternateText($text);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else if($text!=='')
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveLinkButton');
+ $button->setText($text);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else
+ $cell->setText('&nbsp;');
+ }
+ else
+ {
+ if(($url=$this->getHeaderImageUrl())!=='')
+ {
+ $image=Prado::createComponent('System.Web.UI.WebControls.TActiveImage');
+ $image->setImageUrl($url);
+ if($text!=='')
+ $image->setAlternateText($text);
+ $cell->getControls()->add($image);
+ }
+ else if($text!=='')
+ $cell->setText($text);
+ else
+ $cell->setText('&nbsp;');
+ }
+ }
+}
+
+/**
+ * TActiveCheckBoxColumn class
+ *
+ * TActiveCheckBoxColumn represents a checkbox column that is bound to a field in a data source.
+ *
+ * This is the active counterpart to the {@link TCheckBoxColumn} control. For that purpose,
+ * if sorting is allowed, the header links/buttons are replaced by active controls.
+ *
+ * Please refer to the original documentation of the {@link TCheckBoxColumn} for usage.
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.9
+ */
+class TActiveCheckBoxColumn extends TCheckBoxColumn
+{
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates a checkbox inside the cell.
+ * If the column is read-only or if the item is not in edit mode,
+ * the checkbox will be set disabled.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
+ {
+ $checkBox=new TActiveCheckBox;
+ if($this->getReadOnly() || $itemType!==TListItemType::EditItem)
+ $checkBox->setEnabled(false);
+ $cell->setHorizontalAlign('Center');
+ $cell->getControls()->add($checkBox);
+ $cell->registerObject('CheckBox',$checkBox);
+ if($this->getDataField()!=='')
+ $checkBox->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ }
+ else
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ }
+
+ protected function initializeHeaderCell($cell,$columnIndex)
+ {
+ $text=$this->getHeaderText();
+
+ if(($classPath=$this->getHeaderRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ if($control instanceof IDataRenderer)
+ {
+ if($control instanceof IItemDataRenderer)
+ {
+ $item=$cell->getParent();
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $control->setData($text);
+ }
+ $cell->getControls()->add($control);
+ }
+ else if($this->getAllowSorting())
+ {
+ $sortExpression=$this->getSortExpression();
+ if(($url=$this->getHeaderImageUrl())!=='')
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveImageButton');
+ $button->setImageUrl($url);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ if($text!=='')
+ $button->setAlternateText($text);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else if($text!=='')
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveLinkButton');
+ $button->setText($text);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else
+ $cell->setText('&nbsp;');
+ }
+ else
+ {
+ if(($url=$this->getHeaderImageUrl())!=='')
+ {
+ $image=Prado::createComponent('System.Web.UI.WebControls.TActiveImage');
+ $image->setImageUrl($url);
+ if($text!=='')
+ $image->setAlternateText($text);
+ $cell->getControls()->add($image);
+ }
+ else if($text!=='')
+ $cell->setText($text);
+ else
+ $cell->setText('&nbsp;');
+ }
+ }
+}
+
+/**
+ * TActiveDropDownListColumn class
+ *
+ * TActiveDropDownListColumn represents a column that is bound to a field in a data source.
+ *
+ * This is the active counterpart to the {@link TDropDownListColumn} control. For that purpose,
+ * if sorting is allowed, the header links/buttons are replaced by active controls.
+ *
+ * Please refer to the original documentation of the {@link TDropDownListColumn} for usage.
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.9
+ */
+class TActiveDropDownListColumn extends TDropDownListColumn
+{
+ protected function initializeHeaderCell($cell,$columnIndex)
+ {
+ $text=$this->getHeaderText();
+
+ if(($classPath=$this->getHeaderRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ if($control instanceof IDataRenderer)
+ {
+ if($control instanceof IItemDataRenderer)
+ {
+ $item=$cell->getParent();
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $control->setData($text);
+ }
+ $cell->getControls()->add($control);
+ }
+ else if($this->getAllowSorting())
+ {
+ $sortExpression=$this->getSortExpression();
+ if(($url=$this->getHeaderImageUrl())!=='')
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveImageButton');
+ $button->setImageUrl($url);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ if($text!=='')
+ $button->setAlternateText($text);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else if($text!=='')
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveLinkButton');
+ $button->setText($text);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else
+ $cell->setText('&nbsp;');
+ }
+ else
+ {
+ if(($url=$this->getHeaderImageUrl())!=='')
+ {
+ $image=Prado::createComponent('System.Web.UI.WebControls.TActiveImage');
+ $image->setImageUrl($url);
+ if($text!=='')
+ $image->setAlternateText($text);
+ $cell->getControls()->add($image);
+ }
+ else if($text!=='')
+ $cell->setText($text);
+ else
+ $cell->setText('&nbsp;');
+ }
+ }
+
+}
+
+/**
+ * TActiveLiteralColumn class
+ *
+ * TActiveLiteralColumn represents a static text column that is bound to a field in a data source.
+ * The cells in the column will be displayed with static texts using the data indexed by
+ * {@link setDataField DataField}. You can customize the display by
+ * setting {@link setDataFormatString DataFormatString}.
+ *
+ * If {@link setDataField DataField} is not specified, the cells will be filled
+ * with {@link setText Text}.
+ *
+ * If {@link setEncode Encode} is true, the static texts will be HTML-encoded.
+ *
+ * This is the active counterpart to the {@link TLiteralColumn} control. For that purpose,
+ * if sorting is allowed, the header links/buttons are replaced by active controls.
+ *
+ * Please refer to the original documentation of the {@link TLiteralColumn} for usage.
+ *
+ * @author Fabio Bas <ctrlaltca@gmail.com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.9
+ */
+class TActiveLiteralColumn extends TLiteralColumn {
+ protected function initializeHeaderCell($cell,$columnIndex) {
+ $text=$this->getHeaderText();
+
+ if(($classPath=$this->getHeaderRenderer())!=='') {
+ $control=Prado::createComponent($classPath);
+ if($control instanceof IDataRenderer) {
+ if($control instanceof IItemDataRenderer) {
+ $item=$cell->getParent();
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $control->setData($text);
+ }
+ $cell->getControls()->add($control);
+ }
+ else if($this->getAllowSorting()) {
+ $sortExpression=$this->getSortExpression();
+ if(($url=$this->getHeaderImageUrl())!=='') {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveImageButton');
+ $button->setImageUrl($url);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ if($text!=='') {
+ $button->setAlternateText($text);
+ $button->setToolTip($text);
+ }
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else if($text!=='') {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TActiveLinkButton');
+ $button->setText($text);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else
+ $cell->setText('&nbsp;');
+ }
+ else {
+ if(($url=$this->getHeaderImageUrl())!=='') {
+ $image=Prado::createComponent('System.Web.UI.WebControls.TActiveImage');
+ $image->setImageUrl($url);
+ if($text!=='') {
+ $image->setAlternateText($text);
+ $image->setToolTip($text);
+ }
+ $cell->getControls()->add($image);
+ }
+ else if($text!=='')
+ $cell->setText($text);
+ else
+ $cell->setText('&nbsp;');
+ }
+ }
+}
+
+/**
+ * TActiveDataGridPager class.
+ *
+ * TActiveDataGridPager represents a pager in an activedatagrid.
+ *
+ * @author Fabio Bas <ctrlaltca@gmail.com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.2.1
+ */
+class TActiveDataGridPager extends TDataGridPager
+{
+ protected $_callbackoptions;
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ if($this->_callbackoptions === null)
+ $this->_callbackoptions = new TCallbackOptions;
+ return $this->_callbackoptions->getClientSide();
+ }
+}
+
+/**
+ * TActiveDataGridPagerEventParameter class
+ *
+ * TActiveDataGridPagerEventParameter encapsulates the parameter data for
+ * {@link TActiveDataGrid::onPagerCreated OnPagerCreated} event of {@link TActiveDataGrid} controls.
+ * The {@link getPager Pager} property indicates the datagrid pager related with the event.
+ *
+ * @author Fabio Bas <ctrlaltca@gmail.com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.2.1
+ */
+class TActiveDataGridPagerEventParameter extends TDataGridPagerEventParameter
+{
+ /**
+ * Constructor.
+ * @param TActiveDataGridPager datagrid pager related with the corresponding event
+ */
+ public function __construct(TActiveDataGridPager $pager)
+ {
+ $this->_pager=$pager;
+ }
+}
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveDataList.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveDataList.php
new file mode 100644
index 0000000..5bbd898
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveDataList.php
@@ -0,0 +1,116 @@
+<?php
+/**
+ * TActiveDataList class file
+ *
+ * @author Marcos Aurelio Nobre <marconobre@gmail.com>
+ * @copyright Copyright &copy; 2008, PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TActiveDataList class
+ *
+ * TActiveDataList represents a data bound and updatable grid control which is the
+ * active counterpart to the original {@link TDataList} control.
+ *
+ * This component can be used in the same way as the regular datalist, the only
+ * difference is that the active datalist uses callbacks instead of postbacks
+ * for interaction.
+ *
+ * Please refer to the original documentation of the regular counterparts for usage.
+ *
+ * @author Marcos Aurelio Nobre <marconobre@gmail.com>
+ * @package System.Web.UI.ActiveControls
+ */
+class TActiveDataList extends TDataList implements IActiveControl {
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveControl standard active control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * Sets the data source object associated with the repeater control.
+ * In addition, the render method of all connected pagers is called so they
+ * get updated when the data source is changed. Also the repeater registers
+ * itself for rendering in order to get it's content replaced on client side.
+ * @param Traversable|array|string data source object
+ */
+ public function setDataSource($value)
+ {
+ parent::setDataSource($value);
+ if($this->getActiveControl()->canUpdateClientSide()) {
+ $this->renderPager();
+ $this->getPage()->getAdapter()->registerControlToRender($this,$this->getResponse()->createHtmlWriter());
+ }
+ }
+
+ /**
+ * Returns the id of the surrounding container (span).
+ * @return string container id
+ */
+ protected function getContainerID()
+ {
+ return $this->ClientID.'_Container';
+ }
+
+ /**
+ * Renders the repeater.
+ * If the repeater did not pass the prerender phase yet, it will register itself for rendering later.
+ * Else it will call the {@link renderRepeater()} method which will do the rendering of the repeater.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->getHasPreRendered()) {
+ $this->renderDataList($writer);
+ if($this->getActiveControl()->canUpdateClientSide()) $this->getPage()->getCallbackClient()->replaceContent($this->getContainerID(),$writer);
+ }
+ else {
+ $this->getPage()->getAdapter()->registerControlToRender($this,$writer);
+ }
+ }
+
+ /**
+ * Loops through all {@link TActivePager} on the page and registers the ones which are set to paginate
+ * the repeater for rendering. This is to ensure that the connected pagers are also rendered if the
+ * data source changed.
+ */
+ private function renderPager()
+ {
+ $pager=$this->getPage()->findControlsByType('TActivePager', false);
+ foreach($pager as $item)
+ {
+ if($item->ControlToPaginate==$this->ID) {
+ $writer=$this->getResponse()->createHtmlWriter();
+ $this->getPage()->getAdapter()->registerControlToRender($item,$writer);
+ }
+ }
+ }
+
+ /**
+ * Renders the repeater by writing a span tag with the container id obtained from {@link getContainerID()}
+ * which will be called by the replacement method of the client script to update it's content.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ private function renderDataList($writer)
+ {
+ $writer->write('<span id="'.$this->getContainerID().'">');
+ parent::render($writer);
+ $writer->write('</span>');
+ }
+}
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveDatePicker.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveDatePicker.php
new file mode 100755
index 0000000..6328bac
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveDatePicker.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ * TActiveDatePicker class file
+ *
+ * @author Bradley Booms <Bradley.Booms@nsighttel.com>
+ * @author Christophe Boulain <Christophe.Boulain@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TActiveDatePicker class
+ *
+ * The active control counter part to date picker control.
+ * When the date selection is changed, the {@link onCallback OnCallback} event is
+ * raised.
+ *
+ * @author Bradley Booms <Bradley.Booms@nsighttel.com>
+ * @author Christophe Boulain <Christophe.Boulain@gmail.com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.3
+ */
+class TActiveDatePicker extends TDatePicker implements ICallbackEventHandler, IActiveControl
+{
+
+ /**
+ * @return boolean a value indicating whether an automatic postback to the server
+ * will occur whenever the user modifies the text in the TActiveDatePicker control and
+ * then tabs out of the component. Defaults to true.
+ */
+ public function getAutoPostBack()
+ {
+ return $this->getViewState('AutoPostBack',true);
+ }
+
+ /**
+ * Sets the value indicating if postback automatically.
+ * An automatic postback to the server will occur whenever the user
+ * modifies the text in the TActiveDatePicker control and then tabs out of the component.
+ * @param boolean the value indicating if postback automatically
+ */
+ public function setAutoPostBack($value)
+ {
+ $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Get javascript date picker options.
+ * @return array date picker client-side options
+ */
+ protected function getDatePickerOptions()
+ {
+ $options = parent::getDatePickerOptions();
+ $options['CausesValidation']=$this->getCausesValidation();
+ $options['ValidationGroup']=$this->getValidationGroup();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['ShowCalendar'] = $this->getShowCalendar();
+ $options['AutoPostBack'] = $this->getAutoPostBack();
+ return $options;
+ }
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl(){
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * Client-side Text property can only be updated after the OnLoad stage.
+ * @param string text content for the textbox
+ */
+ public function setText($value){
+ parent::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide() && $this->getHasLoadedPostData()){
+ $cb=$this->getPage()->getCallbackClient();
+ $cb->setValue($this, $value);
+ if ($this->getInputMode()==TDatePickerInputMode::DropDownList)
+ {
+ $s = Prado::createComponent('System.Util.TDateTimeStamp');
+ $date = $s->getDate($this->getTimeStampFromText());
+ $id=$this->getClientID();
+ $cb->select($id.TControl::CLIENT_ID_SEPARATOR.'day', 'Value', $date['mday'], 'select');
+ $cb->select($id.TControl::CLIENT_ID_SEPARATOR.'month', 'Value', $date['mon']-1, 'select');
+ $cb->select($id.TControl::CLIENT_ID_SEPARATOR.'year', 'Value', $date['year'], 'select');
+
+ }
+ }
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param){
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param){
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Registers the javascript code to initialize the date picker.
+ */
+
+ protected function registerCalendarClientScriptPre()
+ {
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPradoScript("activedatepicker");
+ }
+
+ protected function renderClientControlScript($writer)
+ {
+ $cs = $this->getPage()->getClientScript();
+ if(!$cs->isEndScriptRegistered('TDatePicker.spacer'))
+ {
+ $spacer = $this->getAssetUrl('spacer.gif');
+ $code = "Prado.WebUI.TDatePicker.spacer = '$spacer';";
+ $cs->registerEndScript('TDatePicker.spacer', $code);
+ }
+
+ $options = TJavaScript::encode($this->getDatePickerOptions());
+ $code = "new Prado.WebUI.TActiveDatePicker($options);";
+ $cs->registerEndScript("prado:".$this->getClientID(), $code);
+ }
+
+ /**
+ * @return TActiveDatePickerClientScript javascript validator event options.
+ */
+ protected function createClientScript()
+ {
+ return new TActiveDatePickerClientScript;
+ }
+}
+
+/**
+ * TActiveDatePickerClientScript class.
+ *
+ * Client-side date picker event {@link setOnDateChanged OnDateChanged}
+ * can be modified through the {@link TActiveDatePicker::getClientSide ClientSide}
+ * property of a date picker.
+ *
+ * The <tt>OnDateChanged</tt> event is raise when the date picker's date
+ * is changed.
+ * The formatted date according to {@link TDatePicker::getDateFormat DateFormat} is sent
+ * as parameter to this event
+ *
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.2.1
+ */
+class TActiveDatePickerClientScript extends TCallbackClientSide
+{
+ /**
+ * Javascript code to execute when the date picker's date is changed.
+ * @param string javascript code
+ */
+ public function setOnDateChanged($javascript)
+ {
+ $this->setFunction('OnDateChanged', $javascript);
+ }
+
+ /**
+ * @return string javascript code to execute when the date picker's date is changed.
+ */
+ public function getOnDateChanged()
+ {
+ return $this->getOption('OnDateChanged');
+ }
+} \ No newline at end of file
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveDropDownList.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveDropDownList.php
new file mode 100644
index 0000000..3245ea6
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveDropDownList.php
@@ -0,0 +1,143 @@
+<?php
+/**
+ * TActiveDropDownList class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active list control adapter
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveListControlAdapter');
+
+/**
+ * TActiveDropDownList class.
+ *
+ * The active control counter part to drop down list control.
+ * The {@link setAutoPostBack AutoPostBack} property is set to true by default.
+ * Thus, when the drop down list selection is changed the {@link onCallback OnCallback} event is
+ * raised after {@link OnSelectedIndexChanged} event.
+ *
+ * With {@link TBaseActiveControl::setEnableUpdate() ActiveControl.EnableUpdate}
+ * set to true (default is true), changes to the selection, <b>after</b> OnLoad event has
+ * been raised, will be updated.
+ * on the client side.
+ *
+ * List items can be changed dynamically during a callback request.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveDropDownList extends TDropDownList implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveListControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveListControlAdapter($this));
+ $this->setAutoPostBack(true);
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * No client class for this control.
+ * This method overrides the parent implementation.
+ * @return null no javascript class name.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveDropDownList';
+ }
+
+ /**
+ * Creates a collection object to hold list items. A specialized
+ * TActiveListItemCollection is created to allow the drop down list options
+ * to be added.
+ * This method may be overriden to create a customized collection.
+ * @return TActiveListItemCollection the collection object
+ */
+ protected function createListItemCollection()
+ {
+ $collection = new TActiveListItemCollection;
+ $collection->setControl($this);
+ return $collection;
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ if ($this->getAutoPostBack())
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Updates the client-side options if the item list has changed after the OnLoad event.
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->getAdapter()->updateListItems();
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveFileUpload.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveFileUpload.php
new file mode 100755
index 0000000..7f11115
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveFileUpload.php
@@ -0,0 +1,461 @@
+<?php
+/**
+ * TActiveFileUpload.php
+ *
+ * @author Bradley Booms <Bradley.Booms@nsighttel.com>
+ * @author Christophe Boulain <Christophe.Boulain@gmail.com>
+ * @author Gabor Berczi <gabor.berczi@devworx.hu> (issue 349 remote vulnerability fix)
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load TActiveControlAdapter and TFileUpload.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+Prado::using('System.Web.UI.WebControls.TFileUpload');
+
+/**
+ * TActiveFileUpload
+ *
+ * TActiveFileUpload displays a file upload field on a page. Upon postback,
+ * the text entered into the field will be treated as the name of the file
+ * that will be uploaded to the server. The property {@link getHasFile HasFile}
+ * indicates whether the file upload is successful. If successful, the file
+ * may be obtained by calling {@link saveAs} to save it at a specified place.
+ * You can use {@link getFileName FileName}, {@link getFileType FileType},
+ * {@link getFileSize FileSize} to get the original client-side file name,
+ * the file mime type, and the file size information. If the upload is not
+ * successful, {@link getErrorCode ErrorCode} contains the error code
+ * describing the cause of failure.
+ *
+ * TActiveFileUpload raises {@link onFileUpload OnFileUpload} event if a file is uploaded
+ * (whether it succeeds or not).
+ *
+ * TActiveFileUpload actually does a postback in a hidden IFrame, and then does a callback.
+ * This callback then raises the {@link onFileUpload OnFileUpload} event. After the postback
+ * a status icon is displayed; either a green checkmark if the upload is successful,
+ * or a red x if there was an error.
+ *
+ * @author Bradley Booms <Bradley.Booms@nsighttel.com>
+ * @author Christophe Boulain <Christophe.Boulain@gmail.com>
+ * @package System.Web.UI.ActiveControls
+ */
+class TActiveFileUpload extends TFileUpload implements IActiveControl, ICallbackEventHandler, INamingContainer
+{
+
+ const SCRIPT_PATH = 'prado/activefileupload';
+
+ /**
+ * @var THiddenField a flag to tell which component is doing the callback.
+ */
+ private $_flag;
+ /**
+ * @var TImage that spins to show that the file is being uploaded.
+ */
+ private $_busy;
+ /**
+ * @var TImage that shows a green check mark for completed upload.
+ */
+ private $_success;
+ /**
+ * @var TImage that shows a red X for incomplete upload.
+ */
+ private $_error;
+ /**
+ * @var TInlineFrame used to submit the data in an "asynchronous" fashion.
+ */
+ private $_target;
+
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct(){
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+
+ /**
+ * @param string asset file in the self::SCRIPT_PATH directory.
+ * @return string asset file url.
+ */
+ protected function getAssetUrl($file='')
+ {
+ $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
+ return $base.'/'.self::SCRIPT_PATH.'/'.$file;
+ }
+
+
+ /**
+ * This method is invoked when a file is uploaded.
+ * If you override this method, be sure to call the parent implementation to ensure
+ * the invocation of the attached event handlers.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onFileUpload($param)
+ {
+ if ($this->_flag->getValue() && $this->getPage()->getIsPostBack() && $param == $this->_target->getUniqueID()){
+ // save the file so that it will persist past the end of this return.
+ $localName = str_replace('\\', '/', tempnam(Prado::getPathOfNamespace($this->getTempPath()),''));
+ parent::saveAs($localName);
+
+ $params = new TActiveFileUploadCallbackParams;
+ $params->localName = $localName;
+ $params->fileName = addslashes($this->getFileName());
+ $params->fileSize = $this->getFileSize();
+ $params->fileType = $this->getFileType();
+ $params->errorCode = $this->getErrorCode();
+
+ // return some javascript to display a completion status.
+ echo <<<EOS
+<script language="Javascript">
+ Options = new Object();
+ Options.clientID = '{$this->getClientID()}';
+ Options.targetID = '{$this->_target->getUniqueID()}';
+ Options.fileName = '{$params->fileName}';
+ Options.fileSize = '{$params->fileSize}';
+ Options.fileType = '{$params->fileType}';
+ Options.errorCode = '{$params->errorCode}';
+ Options.callbackToken = '{$this->pushParamsAndGetToken($params)}';
+ parent.Prado.WebUI.TActiveFileUpload.onFileUpload(Options);
+</script>
+EOS;
+
+ exit();
+ }
+ }
+
+ /**
+ * @return string the path where the uploaded file will be stored temporarily, in namespace format
+ * default "Application.runtime.*"
+ */
+ public function getTempPath(){
+ return $this->getViewState('TempPath', 'Application.runtime.*');
+ }
+
+ /**
+ * @param string the path where the uploaded file will be stored temporarily in namespace format
+ * default "Application.runtime.*"
+ */
+ public function setTempPath($value){
+ $this->setViewState('TempPath',$value,'Application.runtime.*');
+ }
+
+ /**
+ * @return boolean a value indicating whether an automatic callback to the server will occur whenever the user modifies the text in the TTextBox control and then tabs out of the component. Defaults to true.
+ * Note: When set to false, you will need to trigger the callback yourself.
+ */
+ public function getAutoPostBack(){
+ return $this->getViewState('AutoPostBack', true);
+ }
+
+ /**
+ * @param boolean a value indicating whether an automatic callback to the server will occur whenever the user modifies the text in the TTextBox control and then tabs out of the component. Defaults to true.
+ * Note: When set to false, you will need to trigger the callback yourself.
+ */
+ public function setAutoPostBack($value){
+ $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string A chuck of javascript that will need to be called if {{@link getAutoPostBack AutoPostBack} is set to false}
+ */
+ public function getCallbackJavascript(){
+ return "Prado.WebUI.TActiveFileUpload.fileChanged(\"{$this->getClientID()}\")";
+ }
+
+ /**
+ * @throws TInvalidDataValueException if the {@link getTempPath TempPath} is not writable.
+ */
+ public function onInit($sender){
+ parent::onInit($sender);
+
+ if (!Prado::getApplication()->getCache())
+ if (!Prado::getApplication()->getSecurityManager())
+ throw new Exception('TActiveFileUpload needs either an application level cache or a security manager to work securely');
+
+ if (!is_writable(Prado::getPathOfNamespace($this->getTempPath()))){
+ throw new TInvalidDataValueException("activefileupload_temppath_invalid", $this->getTempPath());
+ }
+ }
+
+ /**
+ * Raises <b>OnFileUpload</b> event.
+ *
+ * This method is required by {@link ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param){
+ $cp = $param->getCallbackParameter();
+ if ($key = $cp->targetID == $this->_target->getUniqueID()){
+
+ $params = $this->popParamsByToken($cp->callbackToken);
+
+ $_FILES[$key]['name'] = stripslashes($params->fileName);
+ $_FILES[$key]['size'] = intval($params->fileSize);
+ $_FILES[$key]['type'] = $params->fileType;
+ $_FILES[$key]['error'] = intval($params->errorCode);
+ $_FILES[$key]['tmp_name'] = $params->localName;
+ $this->loadPostData($key, null);
+
+ $this->raiseEvent('OnFileUpload', $this, $param);
+ }
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method calls {@link onFileUpload} method
+ * This method is primarily used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ $this->onFileUpload($this->getPage()->getRequest()->itemAt('TActiveFileUpload_TargetId'));
+ }
+
+ protected function pushParamsAndGetToken(TActiveFileUploadCallbackParams $params)
+ {
+ if ($cache = Prado::getApplication()->getCache())
+ {
+ // this is the most secure method, file info can't be forged from client side, no matter what
+ $token = md5('TActiveFileUpload::Params::'.$this->ClientID.'::'+rand(1000*1000,9999*1000));
+ $cache->set($token, serialize($params), 5*60); // expire in 5 minutes - the callback should arrive back in seconds, actually
+ }
+ else
+ if ($mgr = Prado::getApplication()->getSecurityManager())
+ {
+ // this is a less secure method, file info can be still forged from client side, but only if attacker knows the secret application key
+ $token = urlencode(base64_encode($mgr->encrypt(serialize($params))));
+ }
+ else
+ throw new Exception('TActiveFileUpload needs either an application level cache or a security manager to work securely');
+
+ return $token;
+ }
+
+ protected function popParamsByToken($token)
+ {
+ if ($cache = Prado::getApplication()->getCache())
+ {
+ $v = $cache->get($token);
+ assert($v!='');
+ $cache->delete($token); // remove it from cache so it can't be used again and won't take up space either
+ $params = unserialize($v);
+ }
+ else
+ if ($mgr = Prado::getApplication()->getSecurityManager())
+ {
+ $v = $mgr->decrypt(base64_decode(urldecode($token)));
+ $params = unserialize($v);
+ }
+ else
+ throw new Exception('TActiveFileUpload needs either an application level cache or a security manager to work securely');
+
+ assert($params instanceof TActiveFileUploadCallbackParams);
+
+ return $params;
+ }
+
+ /**
+ * Publish the javascript
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+
+ if(!$this->getPage()->getIsPostBack() && isset($_GET['TActiveFileUpload_InputId']) && isset($_GET['TActiveFileUpload_TargetId']) && $_GET['TActiveFileUpload_InputId'] == $this->getClientID())
+ {
+ // tricky workaround to intercept "uploaded file too big" error: real uploads happens in onFileUpload instead
+ $this->_errorCode = UPLOAD_ERR_FORM_SIZE;
+ $localName = str_replace('\\', '/', tempnam(Prado::getPathOfNamespace($this->getTempPath()),''));
+ $fileName = addslashes($this->getFileName());
+
+ $params = new TActiveFileUploadCallbackParams;
+ $params->localName = $localName;
+ $params->fileName = $fileName;
+ $params->fileSize = $this->getFileSize();
+ $params->fileType = $this->getFileType();
+ $params->errorCode = $this->getErrorCode();
+
+ echo <<<EOS
+<script language="Javascript">
+ Options = new Object();
+ Options.clientID = '{$_GET['TActiveFileUpload_InputId']}';
+ Options.targetID = '{$_GET['TActiveFileUpload_TargetId']}';
+ Options.fileName = '{$params->fileName}';
+ Options.fileSize = '{$params->fileSize}';
+ Options.fileType = '{$params->fileType}';
+ Options.errorCode = '{$params->errorCode}';
+ Options.callbackToken = '{$this->pushParamsAndGetToken($params)}';
+ parent.Prado.WebUI.TActiveFileUpload.onFileUpload(Options);
+</script>
+EOS;
+ }
+ }
+
+ public function createChildControls(){
+ $this->_flag = Prado::createComponent('THiddenField');
+ $this->_flag->setID('Flag');
+ $this->getControls()->add($this->_flag);
+
+ $this->_busy = Prado::createComponent('TImage');
+ $this->_busy->setID('Busy');
+ $this->_busy->setImageUrl($this->getAssetUrl('ActiveFileUploadIndicator.gif'));
+ $this->_busy->setStyle("display:none");
+ $this->getControls()->add($this->_busy);
+
+ $this->_success = Prado::createComponent('TImage');
+ $this->_success->setID('Success');
+ $this->_success->setImageUrl($this->getAssetUrl('ActiveFileUploadComplete.png'));
+ $this->_success->setStyle("display:none");
+ $this->getControls()->add($this->_success);
+
+ $this->_error = Prado::createComponent('TImage');
+ $this->_error->setID('Error');
+ $this->_error->setImageUrl($this->getAssetUrl('ActiveFileUploadError.png'));
+ $this->_error->setStyle("display:none");
+ $this->getControls()->add($this->_error);
+
+ $this->_target = Prado::createComponent('TInlineFrame');
+ $this->_target->setID('Target');
+ $this->_target->setFrameUrl($this->getAssetUrl('ActiveFileUploadBlank.html'));
+ $this->_target->setStyle("width:0px; height:0px;");
+ $this->_target->setShowBorder(false);
+ $this->getControls()->add($this->_target);
+ }
+
+
+ /**
+ * Removes localfile on ending of the callback.
+ */
+ public function onUnload($param){
+ if ($this->getPage()->getIsCallback() &&
+ $this->getHasFile() &&
+ file_exists($this->getLocalName())){
+ unlink($this->getLocalName());
+ }
+ parent::onUnload($param);
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl(){
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Adds ID attribute, and renders the javascript for active component.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function addAttributesToRender($writer){
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+
+ $this->getPage()->getClientScript()->registerPradoScript('activefileupload');
+ $this->getActiveControl()->registerCallbackClientScript($this->getClientClassName(),$this->getClientOptions());
+ }
+
+ /**
+ * @return string corresponding javascript class name for this control.
+ */
+ protected function getClientClassName(){
+ return 'Prado.WebUI.TActiveFileUpload';
+ }
+
+ /**
+ * Gets the client side options for this control.
+ * @return array ( inputID => input client ID,
+ * flagID => flag client ID,
+ * targetName => target unique ID,
+ * formID => form client ID,
+ * indicatorID => upload indicator client ID,
+ * completeID => complete client ID,
+ * errorID => error client ID)
+ */
+ protected function getClientOptions(){
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+
+ $options['inputID'] = $this->getClientID();
+ $options['flagID'] = $this->_flag->getClientID();
+ $options['targetID'] = $this->_target->getUniqueID();
+ $options['formID'] = $this->getPage()->getForm()->getClientID();
+ $options['indicatorID'] = $this->_busy->getClientID();
+ $options['completeID'] = $this->_success->getClientID();
+ $options['errorID'] = $this->_error->getClientID();
+ $options['autoPostBack'] = $this->getAutoPostBack();
+ return $options;
+ }
+
+ /**
+ * Saves the uploaded file.
+ * @param string the file name used to save the uploaded file
+ * @param boolean whether to delete the temporary file after saving.
+ * If true, you will not be able to save the uploaded file again.
+ * @return boolean true if the file saving is successful
+ */
+ public function saveAs($fileName,$deleteTempFile=true){
+ if (($this->getErrorCode()===UPLOAD_ERR_OK) && (file_exists($this->getLocalName()))){
+ if ($deleteTempFile)
+ return rename($this->getLocalName(),$fileName);
+ else
+ return copy($this->getLocalName(),$fileName);
+ } else
+ return false;
+ }
+
+ /**
+ * @return TImage the image displayed when an upload
+ * completes successfully.
+ */
+ public function getSuccessImage(){
+ $this->ensureChildControls();
+ return $this->_success;
+ }
+
+ /**
+ * @return TImage the image displayed when an upload
+ * does not complete successfully.
+ */
+ public function getErrorImage(){
+ $this->ensureChildControls();
+ return $this->_error;
+ }
+
+ /**
+ * @return TImage the image displayed when an upload
+ * is in progress.
+ */
+ public function getBusyImage(){
+ $this->ensureChildControls();
+ return $this->_busy;
+ }
+}
+
+/**
+ * TActiveFileUploadCallbackParams is an internal class used by {@link TActiveFileUpload}.
+ *
+ * @author Bradley Booms <Bradley.Booms@nsighttel.com>
+ * @author Christophe Boulain <Christophe.Boulain@gmail.com>
+ * @package System.Web.UI.ActiveControls
+ */
+class TActiveFileUploadCallbackParams
+{
+ public $localName;
+ public $fileName;
+ public $fileSize;
+ public $fileType;
+ public $errorCode;
+}
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveHiddenField.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveHiddenField.php
new file mode 100644
index 0000000..f87ff07
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveHiddenField.php
@@ -0,0 +1,116 @@
+<?php
+/**
+ * TActiveHiddenField class file.
+ *
+ * @author Carl G. Mathisen <carlgmathisen@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+/**
+ * TActiveHiddenField class
+ *
+ * TActiveHiddenField displays a hidden input field on a Web page.
+ * The value of the input field can be accessed via {@link getValue Value} property.
+ *
+ * @author Carl G. Mathisen <carlgmathisen@gmail.com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveHiddenField extends THiddenField implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Client-side Value property can only be updated after the OnLoad stage.
+ * @param string text content for the hidden field
+ */
+ public function setValue($value)
+ {
+ parent::setValue($value);
+ if($this->getActiveControl()->canUpdateClientSide() && $this->getHasLoadedPostData())
+ $this->getPage()->getCallbackClient()->setValue($this, $value);
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveHiddenField';
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveHyperLink.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveHyperLink.php
new file mode 100644
index 0000000..2ffee7e
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveHyperLink.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * TActiveHyperLink class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TActiveHyperLink class.
+ *
+ * The active control counterpart of THyperLink component. When
+ * {@link TBaseActiveControl::setEnableUpdate ActiveControl.EnableUpdate}
+ * property is true the during a callback request, setting {@link setText Text}
+ * property will also set the text of the label on the client upon callback
+ * completion. Similarly, for other properties such as {@link setImageUrl ImageUrl},
+ * {@link setNavigateUrl NavigateUrl} and {@link setTarget Target}.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveHyperLink extends THyperLink implements IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveControl basic active control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * On callback response, the inner HTMl of the label is updated.
+ * @param string the text value of the label
+ */
+ public function setText($value)
+ {
+ parent::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->update($this, $value);
+ }
+
+ /**
+ * Sets the location of image file of the THyperLink.
+ * @param string the image file location
+ */
+ public function setImageUrl($value)
+ {
+ parent::setImageUrl($value);
+ if($this->getActiveControl()->canUpdateClientSide() && $value !== '')
+ {
+ $textWriter = new TTextWriter;
+ $renderer = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $textWriter);
+ $this->createImage($value)->renderControl($renderer);
+ $this->getPage()->getCallbackClient()->update($this, $textWriter->flush());
+ }
+ }
+
+ /**
+ * Sets the URL to link to when the THyperLink component is clicked.
+ * @param string the URL
+ */
+ public function setNavigateUrl($value)
+ {
+ parent::setNavigateUrl($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ //replace &amp; with & and urldecode the url (setting the href using javascript is literal)
+ $url = urldecode(str_replace('&amp;', '&', $value));
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'href', $url);
+ }
+ }
+
+ /**
+ * Sets the target window or frame to display the Web page content linked to when the THyperLink component is clicked.
+ * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string.
+ */
+ public function setTarget($value)
+ {
+ parent::setTarget($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'target', $value);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveImage.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveImage.php
new file mode 100644
index 0000000..13d5314
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveImage.php
@@ -0,0 +1,90 @@
+<?php
+/**
+ * TActiveImage class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TActiveImage class.
+ *
+ * TActiveImage allows the {@link setAlternateText AlternateText},
+ * {@link setImageAlign ImageAlign}, {@link setImageUrl ImageUrl},
+ * and {@link setDescriptionUrl DescriptionUrl} to be updated during
+ * a callback request.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveImage extends TImage implements IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveControl basic active control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * Sets the alternative text to be displayed in the TImage when the image is unavailable.
+ * @param string the alternative text
+ */
+ public function setAlternateText($value)
+ {
+ parent::setAlternateText($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'alt', $value);
+ }
+
+ /**
+ * Sets the alignment of the image with respective to other elements on the page.
+ * Possible values include: absbottom, absmiddle, baseline, bottom, left,
+ * middle, right, texttop, and top. If an empty string is passed in,
+ * imagealign attribute will not be rendered.
+ * @param string the alignment of the image
+ */
+ public function setImageAlign($value)
+ {
+ parent::setImageAlign($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'align', $value);
+ }
+
+ /**
+ * @param string the URL of the image file
+ */
+ public function setImageUrl($value)
+ {
+ parent::setImageUrl($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'src', $value);
+ }
+
+ /**
+ * @param string the URL to the long description of the image.
+ */
+ public function setDescriptionUrl($value)
+ {
+ parent::setDescriptionUrl($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'longdesc', $value);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveImageButton.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveImageButton.php
new file mode 100644
index 0000000..351a996
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveImageButton.php
@@ -0,0 +1,154 @@
+<?php
+/**
+ * TActiveImageButton class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TActiveImageButton class.
+ *
+ * TActiveImageButton is the active control counter part to TImageButton.
+ * When a TActiveImageButton is clicked, rather than a normal post back request a
+ * callback request is initiated.
+ *
+ * The {@link onCallback OnCallback} event is raised during a callback request
+ * and it is raise <b>after</b> the {@link onClick OnClick} event.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveImageButton extends TImageButton implements IActiveControl, ICallbackEventHandler
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveControl basic active control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Sets the alternative text to be displayed in the TImage when the image is unavailable.
+ * @param string the alternative text
+ */
+ public function setAlternateText($value)
+ {
+ parent::setAlternateText($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'alt', $value);
+ }
+
+ /**
+ * Sets the alignment of the image with respective to other elements on the page.
+ * Possible values include: absbottom, absmiddle, baseline, bottom, left,
+ * middle, right, texttop, and top. If an empty string is passed in,
+ * imagealign attribute will not be rendered.
+ * @param string the alignment of the image
+ */
+ public function setImageAlign($value)
+ {
+ parent::setImageAlign($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'align', $value);
+ }
+
+ /**
+ * @param string the URL of the image file
+ */
+ public function setImageUrl($value)
+ {
+ parent::setImageUrl($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'src', $value);
+ }
+
+ /**
+ * @param string the URL to the long description of the image.
+ */
+ public function setDescriptionUrl($value)
+ {
+ parent::setDescriptionUrl($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'longdesc', $value);
+ }
+
+ /**
+ * Raises the callback event. This method is required by
+ * {@link ICallbackEventHandler ICallbackEventHandler} interface. If
+ * {@link getCausesValidation CausesValidation} is true, it will invoke the page's
+ * {@link TPage::validate} method first. It will raise
+ * {@link onClick OnClick} event first and then the {@link onCallback OnCallback} event.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->raisePostBackEvent($param);
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TActiveLinkButton.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveImageButton';
+ }
+}
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveLabel.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveLabel.php
new file mode 100644
index 0000000..70ff20e
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveLabel.php
@@ -0,0 +1,88 @@
+<?php
+/**
+ * TActiveLabel class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TActiveLabel class
+ *
+ * The active control counterpart of TLabel component. When
+ * {@link TBaseActiveControl::setEnableUpdate ActiveControl.EnableUpdate}
+ * property is true the during a callback request, setting {@link setText Text}
+ * property will also set the text of the label on the client upon callback
+ * completion. Similarly, setting {@link setForControl ForControl} will also set
+ * the client-side "for" attribute on the label.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveLabel extends TLabel implements IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveControl basic active control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * On callback response, the inner HTML of the label is updated.
+ * @param string the text value of the label
+ */
+ public function setText($value)
+ {
+ parent::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->update($this, $value);
+ }
+
+ /**
+ * Sets the ID of the control that the label is associated with.
+ * The control must be locatable via {@link TControl::findControl} using the ID.
+ * On callback response, the For attribute of the label is updated.
+ * @param string the associated control ID
+ */
+ public function setForControl($value)
+ {
+ parent::setForControl($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $id=$this->findControl($value)->getClientID();
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'for', $id);
+ }
+ }
+
+ /**
+ * Adds attribute id to the renderer.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer) {
+ $writer->addAttribute('id',$this->getClientID());
+ parent::addAttributesToRender($writer);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveLinkButton.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveLinkButton.php
new file mode 100644
index 0000000..aaf2d35
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveLinkButton.php
@@ -0,0 +1,159 @@
+<?php
+/**
+ * TActiveLinkButton class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TActiveLinkButton is the active control counter part to TLinkButton.
+ *
+ * When a TActiveLinkButton is clicked, rather than a normal post back request a
+ * callback request is initiated.
+ *
+ * The {@link onCallback OnCallback} event is raised during a callback request
+ * and it is raise <b>after</b> the {@link onClick OnClick} event.
+ *
+ * When the {@link TBaseActiveCallbackControl::setEnableUpdate ActiveControl.EnableUpdate}
+ * property is true, changing the {@link setText Text} property during callback request
+ * will update the link text upon callback response completion.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveLinkButton extends TLinkButton implements IActiveControl, ICallbackEventHandler
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Raises the callback event. This method is required by
+ * {@link ICallbackEventHandlerICallbackEventHandler} interface. If
+ * {@link getCausesValidation CausesValidation} is true, it will
+ * invoke the page's {@link TPage::validate validate} method first. It will raise
+ * {@link onClick OnClick} event first and then the {@link onCallback OnCallback}
+ * event.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->raisePostBackEvent($param);
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Updates the link text on the client-side if the
+ * {@link setEnableUpdate EnableUpdate} property is set to true.
+ * @param string caption of the button
+ */
+ public function setText($value)
+ {
+ parent::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->update($this, $value);
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+
+ if($this->getEnabled(true))
+ {
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+ }
+
+ /**
+ * Ensures that the anchor is rendered correctly when its Enabled property
+ * changes in a callback
+ * @param bool enabled
+ */
+ public function setEnabled($value)
+ {
+ parent::setEnabled($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ if($this->getEnabled(true))
+ {
+ $nop = "javascript:;//".$this->getClientID();
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'href', $nop);
+
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+
+ } else {
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'href', false);
+ }
+ }
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TActiveLinkButton.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveLinkButton';
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveListBox.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveListBox.php
new file mode 100644
index 0000000..e32a8eb
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveListBox.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * TActiveListBox class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active list control adapter
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveListControlAdapter');
+
+/**
+ * TActiveListBox class.
+ *
+ * List items can be added dynamically during a callback request.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveListBox extends TListBox implements IActiveControl, ICallbackEventHandler
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveListControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveListControlAdapter($this));
+ $this->setAutoPostBack(true);
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Creates a collection object to hold list items. A specialized
+ * TActiveListItemCollection is created to allow the drop down list options
+ * to be added.
+ * This method may be overriden to create a customized collection.
+ * @return TActiveListItemCollection the collection object
+ */
+ protected function createListItemCollection()
+ {
+ $collection = new TActiveListItemCollection;
+ $collection->setControl($this);
+ return $collection;
+ }
+
+ /**
+ * Javascript client class for this control.
+ * This method overrides the parent implementation.
+ * @return null no javascript class name.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveListBox';
+ }
+
+ /**
+ * Sets the selection mode of the list control (Single, Multiple)
+ * on the client-side if the {@link setEnableUpdate EnableUpdate}
+ * property is set to true.
+ * @param string the selection mode
+ */
+ public function setSelectionMode($value)
+ {
+ parent::setSelectionMode($value);
+ $multiple = $this->getIsMultiSelect();
+ $id = $this->getUniqueID(); $multi_id = $id.'[]';
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $client->setAttribute($this, 'multiple', $multiple ? 'multiple' : false);
+ $client->setAttribute($this, 'name', $multiple ? $multi_id : $id);
+ }
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Updates the client-side options if the item list has changed after the OnLoad event.
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->getAdapter()->updateListItems();
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ if ($this->getAutoPostBack())
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveListControlAdapter.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveListControlAdapter.php
new file mode 100644
index 0000000..927912b
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveListControlAdapter.php
@@ -0,0 +1,255 @@
+<?php
+/**
+ * TActiveListControlAdapter class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+Prado::using('System.Web.UI.WebControls.TListControl');
+
+/**
+ * TActiveListControlAdapter class.
+ *
+ * Adapte the list controls to allows the selections on the client-side to be altered
+ * during callback response.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveListControlAdapter extends TActiveControlAdapter implements IListControlAdapter
+{
+ /**
+ * @return boolean true if can update client-side attributes.
+ */
+ protected function canUpdateClientSide()
+ {
+ return $this->getControl()->getActiveControl()->canUpdateClientSide();
+ }
+
+ /**
+ * Selects an item based on zero-base index on the client side.
+ * @param integer the index (zero-based) of the item to be selected
+ */
+ public function setSelectedIndex($index)
+ {
+ if($this->canUpdateClientSide())
+ {
+ $this->updateListItems();
+ // if a prompt is set, we mimic the postback behaviour of not counting it
+ // in the index. We assume the prompt is _always_ the first item (Issue #368)
+ $promptValue=$this->getControl()->getPromptValue();
+ if($promptValue==='')
+ $promptValue=$this->getControl()->getPromptText();
+ if($promptValue!=='')
+ $index++;
+
+ if($index >= 0 && $index <= $this->getControl()->getItemCount())
+ $this->getPage()->getCallbackClient()->select(
+ $this->getControl(), 'Index', $index);
+ }
+ }
+
+ /**
+ * Selects a list of item based on zero-base indices on the client side.
+ * @param array list of index of items to be selected
+ */
+ public function setSelectedIndices($indices)
+ {
+ if($this->canUpdateClientSide())
+ {
+ $this->updateListItems();
+ $n = $this->getControl()->getItemCount();
+
+ $promptValue=$this->getControl()->getPromptValue();
+ if($promptValue==='')
+ $promptValue=$this->getControl()->getPromptText();
+
+ $list = array();
+ foreach($indices as $index)
+ {
+ $index = intval($index);
+ if($promptValue!=='')
+ $index++;
+ if($index >= 0 && $index <= $n)
+ $list[] = $index;
+ }
+ if(count($list) > 0)
+ $this->getPage()->getCallbackClient()->select(
+ $this->getControl(), 'Indices', $list);
+ }
+ }
+
+ /**
+ * Sets selection by item value on the client side.
+ * @param string the value of the item to be selected.
+ */
+ public function setSelectedValue($value)
+ {
+ if($this->canUpdateClientSide())
+ {
+ $this->updateListItems();
+ $this->getPage()->getCallbackClient()->select(
+ $this->getControl(), 'Value', $value);
+ }
+ }
+
+ /**
+ * Sets selection by a list of item values on the client side.
+ * @param array list of the selected item values
+ */
+ public function setSelectedValues($values)
+ {
+ if($this->canUpdateClientSide())
+ {
+ $this->updateListItems();
+ $list = array();
+ foreach($values as $value)
+ $list[] = $value;
+ if(count($list) > 0)
+ $this->getPage()->getCallbackClient()->select(
+ $this->getControl(), 'Values', $list);
+ }
+ }
+
+ /**
+ * Clears all existing selections on the client side.
+ */
+ public function clearSelection()
+ {
+ if($this->canUpdateClientSide())
+ {
+ $this->updateListItems();
+ if($this->getControl() instanceof TActiveDropDownList)
+ {
+ // clearing a TActiveDropDownList's selection actually doesn't select the first item;
+ // we mimic the postback behaviour selecting it (Issue #368)
+ $this->getPage()->getCallbackClient()->select($this->getControl(), 'Index', 0);
+ } else {
+ $this->getPage()->getCallbackClient()->select($this->getControl(), 'Clear');
+ }
+ }
+ }
+
+ /**
+ * Update the client-side list options.
+ */
+ public function updateListItems()
+ {
+ if($this->canUpdateClientSide())
+ {
+ $items = $this->getControl()->getItems();
+ if($items instanceof TActiveListItemCollection
+ && $items->getListHasChanged())
+ {
+ $items->updateClientSide();
+ }
+ }
+ }
+}
+
+/**
+ * TActiveListItemCollection class.
+ *
+ * Allows TActiveDropDownList and TActiveListBox to add new options
+ * during callback response. New options can only be added <b>after</b> the
+ * {@link TControl::onLoad OnLoad} event.
+ *
+ * The {@link getListHasChanged ListHasChanged} property is true when the
+ * list items has changed. The control responsible for the list needs to
+ * repopulate the client-side options.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveListItemCollection extends TListItemCollection
+{
+ /**
+ * @var IActiveControl control instance.
+ */
+ private $_control;
+ /**
+ * @var boolean true if list items were changed.
+ */
+ private $_hasChanged=false;
+
+ /**
+ * @return boolean true if active controls can update client-side and
+ * the onLoad event has already been raised.
+ */
+ protected function canUpdateClientSide()
+ {
+ return $this->getControl()->getActiveControl()->canUpdateClientSide()
+ && $this->getControl()->getHasLoaded();
+ }
+
+ /**
+ * @param IActiveControl a active list control.
+ */
+ public function setControl(IActiveControl $control)
+ {
+ $this->_control = $control;
+ }
+
+ /**
+ * @return IActiveControl active control using the collection.
+ */
+ public function getControl()
+ {
+ return $this->_control;
+ }
+
+ /**
+ * @return boolean true if the list has changed after onLoad event.
+ */
+ public function getListHasChanged()
+ {
+ return $this->_hasChanged;
+ }
+
+ /**
+ * Update client-side list items.
+ */
+ public function updateClientSide()
+ {
+ $client = $this->getControl()->getPage()->getCallbackClient();
+ $client->setListItems($this->getControl(), $this);
+ $this->_hasChanged=false;
+ }
+
+ /**
+ * Inserts an item into the collection.
+ * The new option is added on the client-side during callback.
+ * @param integer the location where the item will be inserted.
+ * The current item at the place and the following ones will be moved backward.
+ * @param TListItem the item to be inserted.
+ * @throws TInvalidDataTypeException if the item being inserted is neither a string nor TListItem
+ */
+ public function insertAt($index, $value)
+ {
+ parent::insertAt($index, $value);
+ if($this->canUpdateClientSide())
+ $this->_hasChanged = true;
+ }
+
+ /**
+ * Removes an item from at specified index.
+ * @param int zero based index.
+ */
+ public function removeAt($index)
+ {
+ parent::removeAt($index);
+ if($this->canUpdateClientSide())
+ $this->_hasChanged = true;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveMultiView.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveMultiView.php
new file mode 100644
index 0000000..215706e
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveMultiView.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * TActiveMultiView class file
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @link http://www.landwehr-software.de/
+ * @copyright Copyright &copy; 2009 LANDWEHR Computer und Software GmbH
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Includes the following used classes
+ */
+Prado::using('System.Web.UI.WebControls.TMultiView');
+
+/**
+ * TActiveMultiView class.
+ *
+ * TActiveMultiView is the active counterpart to the original {@link TMultiView} control.
+ * It re-renders on Callback when {@link setActiveView ActiveView} or
+ * {@link setActiveViewIndex ActiveViewIndex} is called.
+ *
+ * Please refer to the original documentation of the regular counterpart for usage.
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.6
+ */
+class TActiveMultiView extends TMultiView implements IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveControl standard active control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * Returns the id of the surrounding container (span).
+ * @return string container id
+ */
+ protected function getContainerID()
+ {
+ return $this->ClientID.'_Container';
+ }
+
+ /**
+ * Renders the TActiveMultiView.
+ * If the MutliView did not pass the prerender phase yet, it will register itself for rendering later.
+ * Else it will call the {@link renderMultiView()} method which will do the rendering of the MultiView.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->getHasPreRendered()) {
+ $this->renderMultiView($writer);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->replaceContent($this->getContainerID(),$writer);
+ }
+ else
+ $this->getPage()->getAdapter()->registerControlToRender($this,$writer);
+ }
+
+ /**
+ * Renders the TActiveMultiView by writing a span tag with the container id obtained from {@link getContainerID()}
+ * which will be called by the replacement method of the client script to update it's content.
+ * @param $writer THtmlWriter writer for the rendering purpose
+ */
+ protected function renderMultiView($writer)
+ {
+ $writer->addAttribute('id', $this->getContainerID());
+ $writer->renderBeginTag('span');
+ parent::render($writer);
+ $writer->renderEndTag();
+ }
+
+ /**
+ * @param integer the zero-based index of the current view in the view collection. -1 if no active view.
+ * @throws TInvalidDataValueException if the view index is invalid
+ */
+ public function setActiveViewIndex($value)
+ {
+ $old=parent::getActiveViewIndex();
+ parent::setActiveViewIndex($value);
+ if($this->getActiveControl()->canUpdateClientSide() && $old!=$value)
+ $this->getPage()->getAdapter()->registerControlToRender($this,$this->getResponse()->createHtmlWriter());
+ }
+
+ /**
+ * @param TView the view to be activated
+ * @throws TInvalidOperationException if the view is not in the view collection
+ */
+ public function setActiveView($value)
+ {
+ $old=parent::getActiveView();
+ parent::setActiveView($value);
+ if($this->getActiveControl()->canUpdateClientSide() && $old!=$value)
+ $this->getPage()->getAdapter()->registerControlToRender($this,$this->getResponse()->createHtmlWriter());
+ }
+}
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActivePageAdapter.php b/lib/prado/framework/Web/UI/ActiveControls/TActivePageAdapter.php
new file mode 100644
index 0000000..1803f44
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActivePageAdapter.php
@@ -0,0 +1,415 @@
+<?php
+/**
+ * TActivePageAdapter, TCallbackErrorHandler and TInvalidCallbackException class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @author Gabor Berczi <gabor.berczi@devworx.hu> (lazyload additions & progressive rendering)
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load callback response adapter class.
+ */
+Prado::using('System.Web.UI.ActiveControls.TCallbackResponseAdapter');
+Prado::using('System.Web.UI.ActiveControls.TCallbackClientScript');
+Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
+
+/**
+ * TActivePageAdapter class.
+ *
+ * Callback request handler.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @author Gabor Berczi <gabor.berczi@devworx.hu> (lazyload additions & progressive rendering)
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActivePageAdapter extends TControlAdapter
+{
+ /**
+ * Callback response data header name.
+ */
+ const CALLBACK_DATA_HEADER = 'X-PRADO-DATA';
+ /**
+ * Callback response client-side action header name.
+ */
+ const CALLBACK_ACTION_HEADER = 'X-PRADO-ACTIONS';
+ /**
+ * Callback error header name.
+ */
+ const CALLBACK_ERROR_HEADER = 'X-PRADO-ERROR';
+ /**
+ * Callback page state header name.
+ */
+ const CALLBACK_PAGESTATE_HEADER = 'X-PRADO-PAGESTATE';
+ /**
+ * Script list header name.
+ */
+ const CALLBACK_SCRIPTLIST_HEADER = 'X-PRADO-SCRIPTLIST';
+ /**
+ * Stylesheet list header name.
+ */
+ const CALLBACK_STYLESHEETLIST_HEADER = 'X-PRADO-STYLESHEETLIST';
+ /**
+ * Stylesheet header name.
+ */
+ const CALLBACK_STYLESHEET_HEADER = 'X-PRADO-STYLESHEET';
+ /**
+ * Hidden field list header name.
+ */
+ const CALLBACK_HIDDENFIELDLIST_HEADER = 'X-PRADO-HIDDENFIELDLIST';
+
+ /**
+ * Callback redirect url header name.
+ */
+ const CALLBACK_REDIRECT = 'X-PRADO-REDIRECT';
+
+ /**
+ * @var ICallbackEventHandler callback event handler.
+ */
+ private $_callbackEventTarget;
+ /**
+ * @var mixed callback event parameter.
+ */
+ private $_callbackEventParameter;
+ /**
+ * @var TCallbackClientScript callback client script handler
+ */
+ private $_callbackClient;
+
+ private $_controlsToRender=array();
+
+ /**
+ * Constructor, trap errors and exception to let the callback response
+ * handle them.
+ */
+ public function __construct(TPage $control)
+ {
+ parent::__construct($control);
+
+ //TODO: can this be done later?
+ $response = $this->getApplication()->getResponse();
+ $response->setAdapter(new TCallbackResponseAdapter($response));
+
+ $this->trapCallbackErrorsExceptions();
+ }
+
+ /**
+ * Process the callback request.
+ * @param THtmlWriter html content writer.
+ */
+ public function processCallbackEvent($writer)
+ {
+ Prado::trace("ActivePage raiseCallbackEvent()",'System.Web.UI.ActiveControls.TActivePageAdapter');
+ $this->raiseCallbackEvent();
+ }
+
+ /**
+ * Register a control for defered render() call.
+ * @param TControl control for defered rendering
+ * @param THtmlWriter the renderer
+ */
+ public function registerControlToRender($control,$writer)
+ {
+ $id = $control->getUniqueID();
+ if(!isset($this->_controlsToRender[$id]))
+ $this->_controlsToRender[$id] = array($control,$writer);
+ }
+
+ /**
+ * Trap errors and exceptions to be handled by TCallbackErrorHandler.
+ */
+ protected function trapCallbackErrorsExceptions()
+ {
+ $this->getApplication()->setErrorHandler(new TCallbackErrorHandler);
+ }
+
+ /**
+ * Render the callback response.
+ * @param THtmlWriter html content writer.
+ */
+ public function renderCallbackResponse($writer)
+ {
+ Prado::trace("ActivePage renderCallbackResponse()",'System.Web.UI.ActiveControls.TActivePageAdapter');
+ if(($url = $this->getResponse()->getAdapter()->getRedirectedUrl())===null)
+ $this->renderResponse($writer);
+ else
+ $this->redirect($url);
+ }
+
+ /**
+ * Redirect url on the client-side using javascript.
+ * @param string new url to load.
+ */
+ protected function redirect($url)
+ {
+ Prado::trace("ActivePage redirect()",'System.Web.UI.ActiveControls.TActivePageAdapter');
+ $this->appendContentPart($this->getResponse(), self::CALLBACK_REDIRECT, $url);
+ }
+
+ /**
+ * Renders the callback response by adding additional callback data and
+ * javascript actions in the header and page state if required.
+ * @param THtmlWriter html content writer.
+ */
+ protected function renderResponse($writer)
+ {
+ Prado::trace("ActivePage renderResponse()",'System.Web.UI.ActiveControls.TActivePageAdapter');
+ //renders all the defered render() calls.
+ foreach($this->_controlsToRender as $rid => $forRender)
+ $forRender[0]->render($forRender[1]);
+
+ $response = $this->getResponse();
+
+ //send response data in header
+ if($response->getHasAdapter())
+ {
+ $responseData = $response->getAdapter()->getResponseData();
+ if($responseData!==null)
+ {
+ $data = TJavaScript::jsonEncode($responseData);
+
+ $this->appendContentPart($response, self::CALLBACK_DATA_HEADER, $data);
+ }
+ }
+
+ //sends page state in header
+ if(($handler = $this->getCallbackEventTarget()) !== null)
+ {
+ if($handler->getActiveControl()->getClientSide()->getEnablePageStateUpdate())
+ {
+ $pagestate = $this->getPage()->getClientState();
+ $this->appendContentPart($response, self::CALLBACK_PAGESTATE_HEADER, $pagestate);
+ }
+ }
+
+ //safari must receive at least 1 byte of data.
+ $writer->write(" ");
+
+ //output the end javascript
+ if($this->getPage()->getClientScript()->hasEndScripts())
+ {
+ $writer = $response->createHtmlWriter();
+ $this->getPage()->getClientScript()->renderEndScriptsCallback($writer);
+ $this->getPage()->getCallbackClient()->evaluateScript($writer);
+ }
+
+ //output the actions
+ $executeJavascript = $this->getCallbackClientHandler()->getClientFunctionsToExecute();
+ $actions = TJavaScript::jsonEncode($executeJavascript);
+ $this->appendContentPart($response, self::CALLBACK_ACTION_HEADER, $actions);
+
+
+ $cs = $this->Page->getClientScript();
+
+ // collect all stylesheet file references
+ $stylesheets = $cs->getStyleSheetUrls();
+ if (count($stylesheets)>0)
+ $this->appendContentPart($response, self::CALLBACK_STYLESHEETLIST_HEADER, TJavaScript::jsonEncode($stylesheets));
+
+ // collect all stylesheet snippets references
+ $stylesheets = $cs->getStyleSheetCodes();
+ if (count($stylesheets)>0)
+ $this->appendContentPart($response, self::CALLBACK_STYLESHEET_HEADER, TJavaScript::jsonEncode($stylesheets));
+
+ // collect all script file references
+ $scripts = $cs->getScriptUrls();
+ if (count($scripts)>0)
+ $this->appendContentPart($response, self::CALLBACK_SCRIPTLIST_HEADER, TJavaScript::jsonEncode($scripts));
+
+ // collect all hidden field references
+ $fields = $cs->getHiddenFields();
+ if (count($fields)>0)
+ $this->appendContentPart($response, self::CALLBACK_HIDDENFIELDLIST_HEADER, TJavaScript::jsonEncode($fields));
+ }
+
+ /**
+ * Appends data or javascript code to the body content surrounded with delimiters
+ */
+ private function appendContentPart($response, $delimiter, $data)
+ {
+ $content = $response->createHtmlWriter();
+ $content->getWriter()->setBoundary($delimiter);
+ $content->write($data);
+ }
+
+ /**
+ * Trys to find the callback event handler and raise its callback event.
+ * @throws TInvalidCallbackException if call back target is not found.
+ * @throws TInvalidCallbackException if the requested target does not
+ * implement ICallbackEventHandler.
+ */
+ private function raiseCallbackEvent()
+ {
+ if(($callbackHandler=$this->getCallbackEventTarget())!==null)
+ {
+ if($callbackHandler instanceof ICallbackEventHandler)
+ {
+ $param = $this->getCallbackEventParameter();
+ $result = new TCallbackEventParameter($this->getResponse(), $param);
+ $callbackHandler->raiseCallbackEvent($result);
+ }
+ else
+ {
+ throw new TInvalidCallbackException(
+ 'callback_invalid_handler', $callbackHandler->getUniqueID());
+ }
+ }
+ else
+ {
+ $target = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_TARGET);
+ throw new TInvalidCallbackException('callback_invalid_target', $target);
+ }
+ }
+
+ /**
+ * @return TControl the control responsible for the current callback event,
+ * null if nonexistent
+ */
+ public function getCallbackEventTarget()
+ {
+ if($this->_callbackEventTarget===null)
+ {
+ $eventTarget=$this->getRequest()->itemAt(TPage::FIELD_CALLBACK_TARGET);
+ if(!empty($eventTarget))
+ $this->_callbackEventTarget=$this->getPage()->findControl($eventTarget);
+ }
+ return $this->_callbackEventTarget;
+ }
+
+ /**
+ * Registers a control to raise callback event in the current request.
+ * @param TControl control registered to raise callback event.
+ */
+ public function setCallbackEventTarget(TControl $control)
+ {
+ $this->_callbackEventTarget=$control;
+ }
+
+ /**
+ * Gets callback parameter.
+ * @return string postback event parameter
+ */
+ public function getCallbackEventParameter()
+ {
+ if($this->_callbackEventParameter===null)
+ {
+ $param = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER);
+ $this->_callbackEventParameter=$param;
+ }
+ return $this->_callbackEventParameter;
+ }
+
+ /**
+ * @param mixed postback event parameter
+ */
+ public function setCallbackEventParameter($value)
+ {
+ $this->_callbackEventParameter=$value;
+ }
+
+ /**
+ * Gets the callback client script handler. It handlers the javascript functions
+ * to be executed during the callback response.
+ * @return TCallbackClientScript callback client handler.
+ */
+ public function getCallbackClientHandler()
+ {
+ if($this->_callbackClient===null)
+ $this->_callbackClient = new TCallbackClientScript;
+ return $this->_callbackClient;
+ }
+}
+
+/**
+ * TCallbackErrorHandler class.
+ *
+ * Captures errors and exceptions and send them back during callback response.
+ * When the application is in debug mode, the error and exception stack trace
+ * are shown. A TJavascriptLogger must be present on the client-side to view
+ * the error stack trace.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackErrorHandler extends TErrorHandler
+{
+ /**
+ * Displays the exceptions to the client-side TJavascriptLogger.
+ * A HTTP 500 status code is sent and the stack trace is sent as JSON encoded.
+ * @param Exception exception details.
+ */
+ protected function displayException($exception)
+ {
+ if($this->getApplication()->getMode()===TApplication::STATE_DEBUG)
+ {
+ $response = $this->getApplication()->getResponse();
+ $trace = $this->getExceptionStackTrace($exception);
+ // avoid error on non-utf8 strings
+ try {
+ $trace = TJavaScript::jsonEncode($trace);
+ } catch (Exception $e) {
+ // strip everythin not 7bit ascii
+ $trace = preg_replace('/[^(\x20-\x7F)]*/','', serialize($trace));
+ }
+
+ // avoid exception loop if headers have already been sent
+ try {
+ $response->setStatusCode(500, 'Internal Server Error');
+ } catch (Exception $e) { }
+
+ $content = $response->createHtmlWriter();
+ $content->getWriter()->setBoundary(TActivePageAdapter::CALLBACK_ERROR_HEADER);
+ $content->write($trace);
+ }
+ else
+ {
+ error_log("Error happened while processing an existing error:\n".$exception->__toString());
+ header('HTTP/1.0 500 Internal Server Error', true, 500);
+ }
+ $this->getApplication()->getResponse()->flush();
+ }
+
+ /**
+ * @param Exception exception details.
+ * @return array exception stack trace details.
+ */
+ private function getExceptionStackTrace($exception)
+ {
+ $data['code']=$exception->getCode() > 0 ? $exception->getCode() : 500;
+ $data['file']=$exception->getFile();
+ $data['line']=$exception->getLine();
+ $data['trace']=$exception->getTrace();
+ if($exception instanceof TPhpErrorException)
+ {
+ // if PHP exception, we want to show the 2nd stack level context
+ // because the 1st stack level is of little use (it's in error handler)
+ if(isset($trace[0]) && isset($trace[0]['file']) && isset($trace[0]['line']))
+ {
+ $data['file']=$trace[0]['file'];
+ $data['line']=$trace[0]['line'];
+ }
+ }
+ $data['type']=get_class($exception);
+ $data['message']=$exception->getMessage();
+ $data['version']=$_SERVER['SERVER_SOFTWARE'].' '.Prado::getVersion();
+ $data['time']=@strftime('%Y-%m-%d %H:%M',time());
+ return $data;
+ }
+}
+
+/**
+ * TInvalidCallbackException class.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TInvalidCallbackException extends TException
+{
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActivePager.php b/lib/prado/framework/Web/UI/ActiveControls/TActivePager.php
new file mode 100644
index 0000000..e99743f
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActivePager.php
@@ -0,0 +1,207 @@
+<?php
+/**
+ * TActivePager class file.
+ *
+ * @author "gevik" (forum contributor) and Christophe Boulain (Christophe.Boulain@gmail.com)
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TActivePager is the active control counter part of TPager.
+ *
+ * When a page change is requested, TActivePager raises a callback instead of the
+ * traditional postback.
+ *
+ * The {@link onCallback OnCallback} event is raised during a callback request
+ * and it is raise <b>after</b> the {@link onPageIndexChanged OnPageIndexChanged} event.
+ *
+ * @author "gevik" (forum contributor) and Christophe Boulain (Christophe.Boulain@gmail.com)
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.2
+ */
+class TActivePager extends TPager implements IActiveControl, ICallbackEventHandler
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveControl standard active control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+
+ public function raiseCallbackEvent($param)
+ {
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Builds a dropdown list pager
+ * Override parent implementation to build Active dropdown lists.
+ */
+ protected function buildListPager()
+ {
+ $list=new TActiveDropDownList;
+
+ $list->getAdapter()->getBaseActiveControl()->setClientSide(
+ $this->getClientSide()
+ );
+
+ $this->getControls()->add($list);
+ $list->setDataSource(range(1,$this->getPageCount()));
+ $list->dataBind();
+ $list->setSelectedIndex($this->getCurrentPageIndex());
+ $list->setAutoPostBack(true);
+ $list->attachEventHandler('OnSelectedIndexChanged',array($this,'listIndexChanged'));
+ $list->attachEventHandler('OnCallback', array($this, 'handleCallback'));
+ }
+
+ /**
+ * Creates a pager button.
+ * Override parent implementation to create, depending on the button type, a TActiveLinkButton,
+ * a TActiveButton or a TActiveImageButton may be created.
+ *
+ * @param string button type, either LinkButton or PushButton
+ * @param boolean whether the button should be enabled
+ * @param string caption of the button
+ * @param string CommandName corresponding to the OnCommand event of the button
+ * @param string CommandParameter corresponding to the OnCommand event of the button
+ * @return mixed the button instance
+ */
+ protected function createPagerButton($buttonType,$enabled,$text,$commandName,$commandParameter)
+ {
+ if($buttonType===TPagerButtonType::LinkButton)
+ {
+ if($enabled)
+ $button=new TActiveLinkButton;
+ else
+ {
+ $button=new TLabel;
+ $button->setText($text);
+ $button->setCssClass($this->getButtonCssClass());
+ return $button;
+ }
+ }
+ else if($buttonType===TPagerButtonType::ImageButton)
+ {
+ $button = new TActiveImageButton;
+ $button->setImageUrl($this->getPageImageUrl($text,$commandName));
+ if($enabled)
+ $button->Visible = true;
+ else
+ $button->Visible = false;
+ }
+ else
+ {
+ $button=new TActiveButton;
+ if(!$enabled)
+ $button->setEnabled(false);
+ }
+
+ if($buttonType===TPagerButtonType::ImageButton)
+ {
+ $button->ImageUrl = $text;
+ }
+
+ $button->setText($text);
+ $button->setCommandName($commandName);
+ $button->setCommandParameter($commandParameter);
+ $button->setCausesValidation(false);
+ $button->setCssClass($this->getButtonCssClass());
+
+ $button->attachEventHandler('OnCallback', array($this, 'handleCallback'));
+ $button->getAdapter()->getBaseActiveControl()->setClientSide(
+ $this->getClientSide()
+ );
+
+ return $button;
+ }
+
+ /**
+ * Event handler to the OnCallback active buttons or active dropdownlist.
+ * This handler will raise the {@link onCallback OnCallback} event
+ *
+ * @param mixed $sender
+ * @param TCallbackEventParameter $param
+ */
+ public function handleCallback ($sender,$param)
+ {
+ // Update all the buttons pagers attached to the same control.
+ // Dropdown pagers doesn't need to be re-rendered.
+ $controlToPaginate=$this->getControlToPaginate();
+ foreach ($this->getNamingContainer()->findControlsByType('TActivePager', false) as $control)
+ {
+ if ($control->getMode() !== TPagerMode::DropDownList && $control->getControlToPaginate()===$controlToPaginate)
+ {
+ $control->render($param->getNewWriter());
+ // FIXME : With some very fast machine, the getNewWriter() consecutive calls are in the same microsecond, resulting
+ // of getting the same boundaries in ajax response. Wait 1 microsecond to avoid this.
+ usleep(1);
+ }
+ }
+ // Raise callback event
+ $this->onCallback($param);
+ }
+
+ public function render ($writer)
+ {
+ if($this->getHasPreRendered())
+ {
+ $this->setDisplay(($this->getPageCount()==1)?TDisplayStyle::None:TDisplayStyle::Dynamic);
+ TWebControl::render($writer);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->replaceContent($this,$writer);
+ }
+ else
+ {
+ $this->getPage()->getAdapter()->registerControlToRender($this,$writer);
+ }
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActivePanel.php b/lib/prado/framework/Web/UI/ActiveControls/TActivePanel.php
new file mode 100644
index 0000000..5192b0d
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActivePanel.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * TActivePanel file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TActivePanel is the TPanel active control counterpart.
+ *
+ * TActivePanel allows the client-side panel contents to be updated during a
+ * callback response using the {@link render} method.
+ *
+ * Example: Assume $param is an instance of TCallbackEventParameter attached to
+ * the OnCallback event of a TCallback with ID "callback1", and
+ * "panel1" is the ID of a TActivePanel.
+ * <code>
+ * function callback1_requested($sender, $param)
+ * {
+ * $this->panel1->render($param->getNewWriter());
+ * }
+ * </code>
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActivePanel extends TPanel implements IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveControl standard active control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * Adds attribute id to the renderer.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer) {
+ $writer->addAttribute('id',$this->getClientID());
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders and replaces the panel's content on the client-side.
+ * When render() is called before the OnPreRender event, such as when render()
+ * is called during a callback event handler, the rendering
+ * is defered until OnPreRender event is raised.
+ * @param THtmlWriter html writer
+ */
+ public function render($writer)
+ {
+ if($this->getHasPreRendered())
+ {
+ parent::render($writer);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->replaceContent($this,$writer);
+ }
+ else
+ {
+ $this->getPage()->getAdapter()->registerControlToRender($this,$writer);
+ if ($this->getHasControls())
+ {
+ // If we update a TActivePanel on callback,
+ // We shouldn't update all childs, because the whole content will be replaced by
+ // the parent
+ foreach ($this->findControlsByType('IActiveControl', false) as $control)
+ {
+ $control->getActiveControl()->setEnableUpdate(false);
+ }
+ }
+ }
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveRadioButton.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveRadioButton.php
new file mode 100644
index 0000000..90190a1
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveRadioButton.php
@@ -0,0 +1,174 @@
+<?php
+/**
+ * TActiveRadioButton class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TActiveRadioButton class.
+ *
+ * The active control counter part to radio button. The {@link setAutoPostBack AutoPostBack}
+ * property is set to true by default. Thus, when the radio button is clicked a
+ * {@link onCallback OnCallback} event is raise after {@link OnCheckedChanged} event.
+ *
+ * The {@link setText Text} and {@link setChecked Checked} properties can be
+ * changed during a callback.
+ *
+ * The {@link setGroupName GroupName} property may <b>NOT</b> be changed
+ * during callback because the client-side <tt>name</tt> attribute is read-only
+ * and can not be changed using javascript.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveRadioButton extends TRadioButton implements IActiveControl, ICallbackEventHandler
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ $this->setAutoPostBack(true);
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Updates the button text on the client-side if the
+ * {@link setEnableUpdate EnableUpdate} property is set to true.
+ * @param string caption of the button
+ */
+ public function setText($value)
+ {
+ parent::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->update(
+ $this->getDefaultLabelID(), $value);
+ }
+
+ /**
+ * Checks the radio button.
+ * Updates radio button checked state on the client-side if the
+ * {@link setEnableUpdate EnableUpdate} property is set to true.
+ * @param boolean whether the radio button is to be checked or not.
+ */
+ public function setChecked($value)
+ {
+ $value = TPropertyValue::ensureBoolean($value);
+ parent::setChecked($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->check($this, $value);
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ * Since 3.1.4, the javascript code is not rendered if {@link setAutoPostBack AutoPostBack} is false
+ *
+ */
+ protected function renderInputTag($writer,$clientID,$onclick)
+ {
+ parent::renderInputTag($writer,$clientID,$onclick);
+ if ($this->getAutoPostBack())
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TActiveRadioButton.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveRadioButton';
+ }
+
+ /**
+ * Overrides parent implementation to ensure label has ID.
+ * @return TMap list of attributes to be rendered for label beside the radio button
+ */
+ public function getLabelAttributes()
+ {
+ $attributes = parent::getLabelAttributes();
+ $attributes['id'] = $this->getDefaultLabelID();
+ return $attributes;
+ }
+
+ /**
+ * Renders a label beside the radio button.
+ * @param THtmlWriter the writer for the rendering purpose
+ * @param string radio button id
+ * @param string label text
+ */
+ protected function renderLabel($writer,$clientID,$text)
+ {
+ $writer->addAttribute('id', $this->getDefaultLabelID());
+ parent::renderLabel($writer, $clientID, $text);
+ }
+
+ /**
+ * @return string radio button label ID;
+ */
+ protected function getDefaultLabelID()
+ {
+ if($attributes=$this->getViewState('LabelAttributes',null))
+ return $this->getLabelAttributes()->itemAt('id');
+ else
+ return $this->getClientID().'_label';
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveRadioButtonList.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveRadioButtonList.php
new file mode 100644
index 0000000..9acb672
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveRadioButtonList.php
@@ -0,0 +1,145 @@
+<?php
+/**
+ * TActiveRadioButtonList class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter and active radio button.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveListControlAdapter');
+Prado::using('System.Web.UI.ActiveControls.TActiveRadioButton');
+
+/**
+ * TActiveRadioButtonList class.
+ *
+ * The active control counter part to radio button list control.
+ * The {@link setAutoPostBack AutoPostBack} property is set to true by default.
+ * Thus, when a radio button is clicked a {@link onCallback OnCallback} event is
+ * raised after {@link OnSelectedIndexChanged} event.
+ *
+ * With {@link TBaseActiveControl::setEnableUpdate() ActiveControl.EnableUpdate}
+ * set to true (default is true), changes to the selection will be updated
+ * on the client side.
+ *
+ * List items can not be changed dynamically during a callback request.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveRadioButtonList extends TRadioButtonList implements IActiveControl, ICallbackEventHandler
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveListControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ $this->setAdapter(new TActiveListControlAdapter($this));
+ $this->setAutoPostBack(true);
+ parent::__construct();
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Creates a control used for repetition (used as a template).
+ * @return TControl the control to be repeated
+ */
+ protected function createRepeatedControl()
+ {
+ $control = new TActiveRadioButtonItem;
+ $control->getAdapter()->setBaseActiveControl($this->getActiveControl());
+ return $control;
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveRadioButtonList';
+ }
+
+}
+
+
+class TActiveRadioButtonItem extends TActiveRadioButton
+{
+ /**
+ * Override client implementation to avoid emitting the javascript
+ *
+ * @param THtmlWriter the writer for the rendering purpose
+ * @param string checkbox id
+ * @param string onclick js
+ */
+ protected function renderInputTag($writer,$clientID,$onclick)
+ {
+ TRadioButton::renderInputTag($writer,$clientID,$onclick);
+ }
+} \ No newline at end of file
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveRatingList.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveRatingList.php
new file mode 100644
index 0000000..a154eb6
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveRatingList.php
@@ -0,0 +1,144 @@
+<?php
+/**
+ * TActiveRatingList class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TActiveRatingList Class
+ *
+ * Displays clickable images that represent a TRadioButtonList
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveRatingList extends TRatingList implements IActiveControl, ICallbackEventHandler
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveListControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ $this->setAdapter(new TActiveListControlAdapter($this));
+ $this->setAutoPostBack(true);
+ parent::__construct();
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * @param boolean whether the items in the column can be edited
+ */
+ public function setReadOnly($value)
+ {
+ parent::setReadOnly($value);
+ $value = $this->getReadOnly();
+ $this->callClientFunction('setReadOnly',$value);
+ }
+
+ /**
+ * @param float rating value, also sets the selected Index
+ */
+ public function setRating($value)
+ {
+ parent::setRating($value);
+ $value = $this->getRating();
+ $this->callClientFunction('setRating',$value);
+ }
+
+ /**
+ * Calls the client-side static method for this control class.
+ * @param string static method name
+ * @param mixed method parmaeter
+ */
+ protected function callClientFunction($func,$value)
+ {
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $code = 'Prado.Registry[\''.$this->ClientID.'\'].'.$func.'('.$value.')';
+ $client->evaluateScript($code,array($value));
+ }
+ }
+
+ /**
+ * @param string caption text
+ */
+ public function setCaption($value)
+ {
+ parent::setCaption($value);
+ // if it's an active control, this should not be needed.
+ $this->callClientFunction('setCaption',$value);
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveRatingList';
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveRepeater.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveRepeater.php
new file mode 100644
index 0000000..ad97d30
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveRepeater.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * TActiveRepeater class file
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.9
+ */
+
+/**
+ * TActiveRepeater class
+ *
+ * TActiveRepeater represents a data bound and updatable grid control which is the
+ * active counterpart to the original {@link TRepeater} control.
+ *
+ * This component can be used in the same way as the regular datagrid, the only
+ * difference is that the active repeater uses callbacks instead of postbacks
+ * for interaction.
+ *
+ * Please refer to the original documentation of the regular counterparts for usage.
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.9
+ */
+class TActiveRepeater extends TRepeater implements IActiveControl, ISurroundable {
+
+ /**
+ * @var string the tag used to render the surrounding container
+ */
+ protected $_surroundingTag='div';
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter.
+ */
+ public function __construct() {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveControl standard active control options.
+ */
+ public function getActiveControl() {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * Sets the data source object associated with the repeater control.
+ * In addition, the render method of all connected pagers is called so they
+ * get updated when the data source is changed. Also the repeater registers
+ * itself for rendering in order to get it's content replaced on client side.
+ * @param Traversable|array|string data source object
+ */
+ public function setDataSource($value) {
+ parent::setDataSource($value);
+ if($this->getActiveControl()->canUpdateClientSide()) {
+ $this->renderPager();
+ $this->getPage()->getAdapter()->registerControlToRender($this,$this->getResponse()->createHtmlWriter());
+ }
+ }
+
+ /**
+ * Gets the tag used to render the surrounding container. Defaults to 'div'.
+ * @return string container tag
+ */
+ public function getSurroundingTag() {
+ return $this->_surroundingTag;
+ }
+
+ /**
+ * Sets the tag used to render the surrounding container.
+ * @param string $value container tag
+ */
+ public function setSurroundingTag($value) {
+ $this->_surroundingTag=TPropertyValue::ensureString($value);
+ }
+
+ /**
+ * Returns the id of the surrounding container.
+ * @return string container id
+ */
+ public function getSurroundingTagID() {
+ return $this->getClientID().'_Container';
+ }
+
+ /**
+ * Renders the repeater.
+ * If the repeater did not pass the prerender phase yet, it will register itself for rendering later.
+ * Else it will call the {@link renderRepeater()} method which will do the rendering of the repeater.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer) {
+ if($this->getHasPreRendered()) {
+ $this->renderRepeater($writer);
+ if($this->getActiveControl()->canUpdateClientSide()) $this->getPage()->getCallbackClient()->replaceContent($this->getSurroundingTagId(),$writer);
+ }
+ else {
+ $this->getPage()->getAdapter()->registerControlToRender($this,$writer);
+ }
+ }
+
+ /**
+ * Loops through all {@link TActivePager} on the page and registers the ones which are set to paginate
+ * the repeater for rendering. This is to ensure that the connected pagers are also rendered if the
+ * data source changed.
+ */
+ private function renderPager() {
+ $pager=$this->getPage()->findControlsByType('TActivePager', false);
+ foreach($pager as $item) {
+ if($item->ControlToPaginate==$this->ID) {
+ $writer=$this->getResponse()->createHtmlWriter();
+ $this->getPage()->getAdapter()->registerControlToRender($item,$writer);
+ }
+ }
+ }
+
+ /**
+ * Renders the repeater by writing a {@link getSurroundingTag()} with the container id obtained
+ * from {@link getSurroundingTagID()} which will be called by the replacement method of the client
+ * script to update it's content.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ private function renderRepeater($writer) {
+ $writer->addAttribute('id',$this->getSurroundingTagID());
+ $writer->renderBeginTag($this->getSurroundingTag());
+ parent::render($writer);
+ $writer->renderEndTag();
+ }
+
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveTableCell.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveTableCell.php
new file mode 100644
index 0000000..a581aa4
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveTableCell.php
@@ -0,0 +1,252 @@
+<?php
+/**
+ * TActiveTableCell class file
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @link http://www.landwehr-software.de/
+ * @copyright Copyright &copy; 2009 LANDWEHR Computer und Software GmbH
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ * @version $Id$
+ */
+
+/**
+ * Includes the following used classes
+ */
+Prado::using('System.Web.UI.WebControls.TTableRow');
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
+
+/**
+ * TActiveTableCell class.
+ *
+ * TActiveTableCell is the active counterpart to the original {@link TTableCell} control
+ * and displays a table cell. The horizontal and vertical alignments of the cell
+ * are specified via {@link setHorizontalAlign HorizontalAlign} and
+ * {@link setVerticalAlign VerticalAlign} properties, respectively.
+ *
+ * TActiveTableCell allows the contents of the table cell to be changed during callback. When
+ * {@link onCellSelected CellSelected} property is set, selecting (clicking on) the cell will
+ * perform a callback request causing {@link onCellSelected OnCellSelected} event to be fired.
+ *
+ * It will also bubble the {@link onCellSelected OnCellSelected} event up to it's parent
+ * {@link TActiveTableRow} control which will fire up the event handlers if implemented.
+ *
+ * TActiveTableCell allows the client-side cell contents to be updated during a
+ * callback response by getting a new writer, invoking the render method and flushing the
+ * output, similar to a {@link TActivePanel} control.
+ * <code>
+ * function callback_request($sender, $param)
+ * {
+ * $this->active_cell->render($param->getNewWriter());
+ * }
+ * </code>
+ *
+ * Please refer to the original documentation of the regular counterpart for usage.
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @version $Id$
+ * @since 3.1.9
+ */
+class TActiveTableCell extends TTableCell implements ICallbackEventHandler, IActiveControl
+{
+
+ /**
+ * @var TTable parent row control containing the cell
+ */
+ private $_row;
+
+ /**
+ * Creates a new callback control, sets the adapter to TActiveControlAdapter.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TActiveTableCell.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveTableCell';
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link ICallbackEventHandler}
+ * interface. It will raise {@link onCellSelected OnCellSelected} event with a
+ * {@link TActiveTableCellEventParameter} containing the zero-based index of the
+ * TActiveTableCell.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $parameter = new TActiveTableCellEventParameter($this->getResponse(), $param->getCallbackParameter(), $this->getCellIndex());
+ $this->onCellSelected($parameter);
+ $this->raiseBubbleEvent($this, $parameter);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCellSelected' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TActiveTableCellEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCellSelected($param)
+ {
+ $this->raiseEvent('OnCellSelected', $this, $param);
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control if the event handler for the
+ * {@link onCellSelected OnCellSelected} event is set.
+ * @param THtmlWriter the writer responsible for rendering
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id', $this->getClientID());
+ if ($this->hasEventHandler('OnCellSelected'))
+ $this->getActiveControl()->registerCallbackClientScript($this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * Renders and replaces the cell's content on the client-side. When render() is
+ * called before the OnPreRender event, such as when render() is called during
+ * a callback event handler, the rendering is defered until OnPreRender event
+ * is raised.
+ * @param THtmlWriter html writer
+ */
+ public function render($writer)
+ {
+ if ($this->getHasPreRendered())
+ {
+ parent::render($writer);
+ if ($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->replaceContent($this, $writer);
+ }
+ else {
+ $this->getPage()->getAdapter()->registerControlToRender($this, $writer);
+ // If we update a TActiveTableCell on callback, we shouldn't update all childs,
+ // because the whole content will be replaced by the parent.
+ if ($this->getHasControls())
+ {
+ foreach ($this->findControlsByType('IActiveControl', false) as $control)
+ $control->getActiveControl()->setEnableUpdate(false);
+ }
+ }
+ }
+
+ /**
+ * Returns postback specifications for the table cell.
+ * This method is used by framework and control developers.
+ * @return array parameters about how the row defines its postback behavior.
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ return $options;
+ }
+
+ /**
+ * Returns the zero-based index of the TActiveTableCell within the {@link TTableCellCollection}
+ * of the parent {@link TTableRow} control. Raises a {@link TConfigurationException} if the cell
+ * is no member of the cell collection.
+ * @return integer the zero-based index of the cell
+ */
+ public function getCellIndex()
+ {
+ foreach ($this->getRow()->getCells() as $key => $row)
+ if ($row == $this) return $key;
+ throw new TConfigurationException('tactivetablecell_control_notincollection', get_class($this), $this->getUniqueID());
+ }
+
+ /**
+ * Returns the parent {@link TTableRow} control by looping through all parents until a {@link TTableRow}
+ * is found. Raises a {@link TConfigurationException} if no row control is found.
+ * @return TTableRow the parent row control
+ */
+ public function getRow()
+ {
+ if ($this->_row === null)
+ {
+ $row = $this->getParent();
+ while (!($row instanceof TTableRow) && $row !== null)
+ {
+ $row = $row->getParent();
+ }
+ if ($row instanceof TTableRow) $this->_row = $row;
+ else throw new TConfigurationException('tactivetablecell_control_outoftable', get_class($this), $this->getUniqueID());
+ }
+ return $this->_row;
+ }
+
+}
+
+/**
+ * TActiveTableCellEventParameter class.
+ *
+ * The TActiveTableCellEventParameter provides the parameter passed during the callback
+ * requestion in the {@link getCallbackParameter CallbackParameter} property. The
+ * callback response content (e.g. new HTML content) must be rendered
+ * using an THtmlWriter obtained from the {@link getNewWriter NewWriter}
+ * property, which returns a <b>NEW</b> instance of TCallbackResponseWriter.
+ *
+ * The {@link getSelectedCellIndex SelectedCellIndex} is a zero-based index of the
+ * TActiveTableCell , -1 if the cell is not part of the cell collection (this shouldn't
+ * happen though since an exception is thrown before).
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.9
+ */
+class TActiveTableCellEventParameter extends TCallbackEventParameter
+{
+
+ /**
+ * @var integer the zero-based index of the cell.
+ */
+ private $_selectedCellIndex = -1;
+
+ /**
+ * Creates a new TActiveTableRowEventParameter.
+ */
+ public function __construct($response, $parameter, $index=-1)
+ {
+ parent::__construct($response, $parameter);
+ $this->_selectedCellIndex = $index;
+ }
+
+ /**
+ * Returns the zero-based index of the {@link TActiveTableCell} within the
+ * {@link TTableCellCollection} of the parent {@link TTableRow} control.
+ * @return integer the zero-based index of the cell.
+ */
+ public function getSelectedCellIndex()
+ {
+ return $this->_selectedCellIndex;
+ }
+
+} \ No newline at end of file
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveTableRow.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveTableRow.php
new file mode 100644
index 0000000..0f8abab
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveTableRow.php
@@ -0,0 +1,270 @@
+<?php
+/**
+ * TActiveTableRow and TActiveTableRowEventParameter class file
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @link http://www.landwehr-software.de/
+ * @copyright Copyright &copy; 2009 LANDWEHR Computer und Software GmbH
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ * @version $Id$
+ */
+
+/**
+ * Includes the following used classes
+ */
+Prado::using('System.Web.UI.WebControls.TTableRow');
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
+
+/**
+ * TActiveTableRow class.
+ *
+ * TActiveTableRow is the active counterpart to the original {@link TTableRow} control
+ * and displays a table row. The table cells in the row can be accessed
+ * via {@link getCells Cells}. The horizontal and vertical alignments of the row
+ * are specified via {@link setHorizontalAlign HorizontalAlign} and
+ * {@link setVerticalAlign VerticalAlign} properties, respectively.
+ *
+ * TActiveTableRow allows the contents of the table row to be changed during callback. When
+ * {@link onRowSelected RowSelected} property is set, selecting (clicking on) the row will
+ * perform a callback request causing {@link onRowSelected OnRowSelected} event to be fired.
+ *
+ * It will also respond to a bubbled {@link onCellSelected OnCellSelected} event of a
+ * {@link TActiveTableCell} child control and fire a {@link onRowSelected OnRowSelected} event.
+ *
+ * TActiveTableRow allows the client-side row contents to be updated during a
+ * callback response by getting a new writer, invoking the render method and flushing the
+ * output, similar to a {@link TActivePanel} control.
+ * <code>
+ * function callback_request($sender, $param)
+ * {
+ * $this->active_row->render($param->getNewWriter());
+ * }
+ * </code>
+ *
+ * Please refer to the original documentation of the regular counterpart for usage.
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @version $Id$
+ * @since 3.1.9
+ */
+class TActiveTableRow extends TTableRow implements ICallbackEventHandler, IActiveControl
+{
+
+ /**
+ * @var TTable parent table control containing the row
+ */
+ private $_table;
+
+ /**
+ * Creates a new callback control, sets the adapter to TActiveControlAdapter.
+ * */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TActiveTableRow.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveTableRow';
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link ICallbackEventHandler}
+ * interface. It will raise {@link onRowSelected OnRowSelected} event with a
+ * {@link TActiveTableRowEventParameter} containing the zero-based index of the
+ * TActiveTableRow.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $parameter = new TActiveTableRowEventParameter($this->getResponse(), $param->getCallbackParameter(), $this->getRowIndex());
+ $this->onRowSelected($parameter);
+ }
+
+ /**
+ * This method overrides parent's implementation and raises the control's
+ * callback event. This will fire the {@link onRowSelected OnRowSelected}
+ * event if an appropriate event handler is implemented.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender, $param)
+ {
+ if ($param instanceof TActiveTableCellEventParameter)
+ {
+ $this->raiseCallbackEvent($param);
+ return true;
+ }
+ else return false;
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnRowSelected' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TActiveTableRowEventParameter event parameter to be passed to the event handlers
+ */
+ public function onRowSelected($param)
+ {
+ $this->raiseEvent('OnRowSelected', $this, $param);
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control if the event handler for the
+ * {@link onRowSelected OnRowSelected} event is set.
+ * @param THtmlWriter the writer responsible for rendering
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id', $this->getClientID());
+ if ($this->hasEventHandler('OnRowSelected'))
+ $this->getActiveControl()->registerCallbackClientScript($this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * Renders and replaces the row's content on the client-side. When render() is
+ * called before the OnPreRender event, such as when render() is called during
+ * a callback event handler, the rendering is defered until OnPreRender event
+ * is raised.
+ * @param THtmlWriter html writer
+ */
+ public function render($writer)
+ {
+ if ($this->getHasPreRendered())
+ {
+ parent::render($writer);
+ if ($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->replaceContent($this, $writer);
+ }
+ else
+ {
+ $this->getPage()->getAdapter()->registerControlToRender($this, $writer);
+ // If we update a TActiveTableRow on callback, we shouldn't update all childs,
+ // because the whole content will be replaced by the parent.
+ if ($this->getHasControls())
+ {
+ foreach ($this->findControlsByType('IActiveControl', false) as $control)
+ $control->getActiveControl()->setEnableUpdate(false);
+ }
+ }
+ }
+
+ /**
+ * Returns postback specifications for the table row.
+ * This method is used by framework and control developers.
+ * @return array parameters about how the row defines its postback behavior.
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ return $options;
+ }
+
+ /**
+ * Returns the zero-based index of the TActiveTableRow within the {@link TTableRowCollection}
+ * of the parent {@link TTable} control. Raises a {@link TConfigurationException} if the row
+ * is no member of the row collection.
+ * @return integer the zero-based index of the row
+ */
+ public function getRowIndex()
+ {
+ foreach ($this->getTable()->getRows() as $key => $row)
+ if ($row == $this) return $key;
+ throw new TConfigurationException('tactivetablerow_control_notincollection', get_class($this), $this->getUniqueID());
+ }
+
+ /**
+ * Returns the parent {@link TTable} control by looping through all parents until a {@link TTable}
+ * is found. Raises a {@link TConfigurationException} if no table control is found.
+ * @return TTable the parent table control
+ */
+ public function getTable()
+ {
+ if ($this->_table === null)
+ {
+ $table = $this->getParent();
+ while (!($table instanceof TTable) && $table !== null)
+ {
+ $table = $table->getParent();
+ }
+ if ($table instanceof TTable) $this->_table = $table;
+ else throw new TConfigurationException('tactivetablerow_control_outoftable', get_class($this), $this->getUniqueID());
+ }
+ return $this->_table;
+ }
+
+}
+
+/**
+ * TActiveTableRowEventParameter class.
+ *
+ * The TActiveTableRowEventParameter provides the parameter passed during the callback
+ * requestion in the {@link getCallbackParameter CallbackParameter} property. The
+ * callback response content (e.g. new HTML content) must be rendered
+ * using an THtmlWriter obtained from the {@link getNewWriter NewWriter}
+ * property, which returns a <b>NEW</b> instance of TCallbackResponseWriter.
+ *
+ * The {@link getSelectedRowIndex SelectedRowIndex} is a zero-based index of the
+ * TActiveTableRow , -1 if the row is not part of the row collection (this shouldn't
+ * happen though since an exception is thrown before).
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1.9
+ */
+class TActiveTableRowEventParameter extends TCallbackEventParameter
+{
+ /**
+ * @var integer the zero-based index of the row.
+ */
+ private $_selectedRowIndex = -1;
+
+ /**
+ * Creates a new TActiveTableRowEventParameter.
+ */
+ public function __construct($response, $parameter, $index=-1)
+ {
+ parent::__construct($response, $parameter);
+ $this->_selectedRowIndex = $index;
+ }
+
+ /**
+ * Returns the zero-based index of the {@link TActiveTableRow} within the
+ * {@link TTableRowCollection} of the parent {@link TTable} control.
+ * @return integer the zero-based index of the row.
+ */
+ public function getSelectedRowIndex()
+ {
+ return $this->_selectedRowIndex;
+ }
+
+} \ No newline at end of file
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveTextBox.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveTextBox.php
new file mode 100644
index 0000000..f80b498
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveTextBox.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ * TActiveTextBox class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TActiveTextBox class.
+ *
+ * TActiveTextBox allows the {@link setText Text} property of the textbox to
+ * be changed during callback. When {@link setAutoPostBack AutoPostBack} property
+ * is true, changes to the textbox contents will perform a callback request causing
+ * {@link onTextChanged OnTextChanged} to be fired first followed by {@link onCallback OnCallback}
+ * event.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveTextBox extends TTextBox implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Client-side Text property can only be updated after the OnLoad stage.
+ * @param string text content for the textbox
+ */
+ public function setText($value)
+ {
+ parent::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide() && $this->getHasLoadedPostData())
+ $this->getPage()->getCallbackClient()->setValue($this, $value);
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveTextBox';
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TAutoComplete.php b/lib/prado/framework/Web/UI/ActiveControls/TAutoComplete.php
new file mode 100644
index 0000000..e396e11
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TAutoComplete.php
@@ -0,0 +1,438 @@
+<?php
+/**
+ * TAutoComplete class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active text box.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
+Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
+
+/**
+ * TAutoComplete class.
+ *
+ * TAutoComplete is a textbox that provides a list of suggestion on
+ * the current partial word typed in the textbox. The suggestions are
+ * requested using callbacks, and raises the {@link onSuggestion OnSuggestion}
+ * event. The events of the TActiveText (from which TAutoComplete is extended from)
+ * and {@link onSuggestion OnSuggestion} are mutually exculsive. That is,
+ * if {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback}
+ * events are raise, then {@link onSuggestion OnSuggestion} will not be raise, and
+ * vice versa.
+ *
+ * The list of suggestions should be set in the {@link onSuggestion OnSuggestion}
+ * event handler. The partial word to match the suggestion is in the
+ * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
+ * property. The datasource of the TAutoComplete must be set using {@link setDataSource}
+ * method. This sets the datasource for the suggestions repeater, available through
+ * the {@link getSuggestions Suggestions} property. Header, footer templates and
+ * other properties of the repeater can be access via the {@link getSuggestions Suggestions}
+ * property and its sub-properties.
+ *
+ * The {@link setTextCssClass TextCssClass} property if set is used to find
+ * the element within the Suggestions.ItemTemplate and Suggestions.AlternatingItemTemplate
+ * that contains the actual text for the suggestion selected. That is,
+ * only text inside elements with CSS class name equal to {@link setTextCssClass TextCssClass}
+ * will be used as suggestions.
+ *
+ * To return the list of suggestions back to the browser, supply a non-empty data source
+ * and call databind. For example,
+ * <code>
+ * function autocomplete_suggestion($sender, $param)
+ * {
+ * $token = $param->getToken(); //the partial word to match
+ * $sender->setDataSource($this->getSuggestionsFor($token)); //set suggestions
+ * $sender->dataBind();
+ * }
+ * </code>
+ *
+ * The suggestion will be rendered when the {@link dataBind()} method is called
+ * <strong>during a callback request</strong>.
+ *
+ * When an suggestion is selected, that is, when the use has clicked, pressed
+ * the "Enter" key, or pressed the "Tab" key, the {@link onSuggestionSelected OnSuggestionSelected}
+ * event is raised. The
+ * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
+ * property contains the index of the selected suggestion.
+ *
+ * TAutoComplete allows multiple suggestions within one textbox with each
+ * word or phrase separated by any characters specified in the
+ * {@link setSeparator Separator} property. The {@link setFrequency Frequency}
+ * and {@link setMinChars MinChars} properties sets the delay and minimum number
+ * of characters typed, respectively, before requesting for sugggestions.
+ *
+ * Use {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback} events
+ * to handle post backs due to {@link setAutoPostBack AutoPostBack}.
+ *
+ * In the {@link getSuggestions Suggestions} TRepater item template, all HTML text elements
+ * are considered as text for the suggestion. Text within HTML elements with CSS class name
+ * "informal" are ignored as text for suggestions.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TAutoComplete extends TActiveTextBox implements INamingContainer
+{
+ /**
+ * @var ITemplate template for repeater items
+ */
+ private $_repeater=null;
+ /**
+ * @var TPanel result panel holding the suggestion items.
+ */
+ private $_resultPanel=null;
+
+ /**
+ * @return string word or token separators (delimiters).
+ */
+ public function getSeparator()
+ {
+ return $this->getViewState('tokens', '');
+ }
+
+ /**
+ * @return string word or token separators (delimiters).
+ */
+ public function setSeparator($value)
+ {
+ $this->setViewState('tokens', TPropertyValue::ensureString($value), '');
+ }
+
+ /**
+ * @return float maximum delay (in seconds) before requesting a suggestion.
+ */
+ public function getFrequency()
+ {
+ return $this->getViewState('frequency', '');
+ }
+
+ /**
+ * @param float maximum delay (in seconds) before requesting a suggestion.
+ * Default is 0.4.
+ */
+ public function setFrequency($value)
+ {
+ $this->setViewState('frequency', TPropertyValue::ensureFloat($value),'');
+ }
+
+ /**
+ * @return integer minimum number of characters before requesting a suggestion.
+ */
+ public function getMinChars()
+ {
+ return $this->getViewState('minChars','');
+ }
+
+ /**
+ * @param integer minimum number of characters before requesting a suggestion.
+ */
+ public function setMinChars($value)
+ {
+ $this->setViewState('minChars', TPropertyValue::ensureInteger($value), '');
+ }
+
+ /**
+ * @param string Css class name of the element to use for suggestion.
+ */
+ public function setTextCssClass($value)
+ {
+ $this->setViewState('TextCssClass', $value);
+ }
+
+ /**
+ * @return string Css class name of the element to use for suggestion.
+ */
+ public function getTextCssClass()
+ {
+ return $this->getViewState('TextCssClass');
+ }
+
+ /**
+ * Raises the callback event. This method is overrides the parent implementation.
+ * If {@link setAutoPostBack AutoPostBack} is enabled it will raise
+ * {@link onTextChanged OnTextChanged} event event and then the
+ * {@link onCallback OnCallback} event. The {@link onSuggest OnSuggest} event is
+ * raise if the request is to find sugggestions, the {@link onTextChanged OnTextChanged}
+ * and {@link onCallback OnCallback} events are <b>NOT</b> raised.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $token = $param->getCallbackParameter();
+ if(is_array($token) && count($token) == 2)
+ {
+ if($token[1] === '__TAutoComplete_onSuggest__')
+ {
+ $parameter = new TAutoCompleteEventParameter($this->getResponse(), $token[0]);
+ $this->onSuggest($parameter);
+ }
+ else if($token[1] === '__TAutoComplete_onSuggestionSelected__')
+ {
+ $parameter = new TAutoCompleteEventParameter($this->getResponse(), null, $token[0]);
+ $this->onSuggestionSelected($parameter);
+ }
+ }
+ else if($this->getAutoPostBack())
+ parent::raiseCallbackEvent($param);
+ }
+
+ /**
+ * This method is invoked when an autocomplete suggestion is requested.
+ * The method raises 'OnSuggest' event. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onSuggest($param)
+ {
+ $this->raiseEvent('OnSuggest', $this, $param);
+ }
+
+ /**
+ * This method is invoked when an autocomplete suggestion is selected.
+ * The method raises 'OnSuggestionSelected' event. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onSuggestionSelected($param)
+ {
+ $this->raiseEvent('OnSuggestionSelected', $this, $param);
+ }
+
+ /**
+ * @param array data source for suggestions.
+ */
+ public function setDataSource($data)
+ {
+ $this->getSuggestions()->setDataSource($data);
+ }
+
+ /**
+ * Overrides parent implementation. Callback {@link renderSuggestions()} when
+ * page's IsCallback property is true.
+ */
+ public function dataBind()
+ {
+ parent::dataBind();
+ if($this->getPage()->getIsCallback())
+ $this->renderSuggestions($this->getResponse()->createHtmlWriter());
+ }
+
+ /**
+ * @return TPanel suggestion results panel.
+ */
+ public function getResultPanel()
+ {
+ if($this->_resultPanel===null)
+ $this->_resultPanel = $this->createResultPanel();
+ return $this->_resultPanel;
+ }
+
+ /**
+ * @return TPanel new instance of result panel. Default uses TPanel.
+ */
+ protected function createResultPanel()
+ {
+ $panel = Prado::createComponent('System.Web.UI.WebControls.TPanel');
+ $this->getControls()->add($panel);
+ $panel->setID('result');
+ return $panel;
+ }
+
+ /**
+ * @return TRepeater suggestion list repeater
+ */
+ public function getSuggestions()
+ {
+ if($this->_repeater===null)
+ $this->_repeater = $this->createRepeater();
+ return $this->_repeater;
+ }
+
+ /**
+ * @return TRepeater new instance of TRepater to render the list of suggestions.
+ */
+ protected function createRepeater()
+ {
+ $repeater = Prado::createComponent('System.Web.UI.WebControls.TRepeater');
+ $repeater->setHeaderTemplate(new TAutoCompleteTemplate('<ul>'));
+ $repeater->setFooterTemplate(new TAutoCompleteTemplate('</ul>'));
+ $repeater->setItemTemplate(new TTemplate('<li><%# $this->DataItem %></li>',null));
+ $repeater->setEmptyTemplate(new TAutoCompleteTemplate('<ul></ul>'));
+ $this->getControls()->add($repeater);
+ return $repeater;
+ }
+
+ /**
+ * Renders the end tag and registers the needed javascript library.
+ */
+ public function renderEndTag($writer)
+ {
+ $cs=$this->getPage()->getClientScript();
+ $cs->registerPradoScript('autocomplete');
+ parent::renderEndTag($writer);
+ $this->renderResultPanel($writer);
+ }
+
+ /**
+ * Renders the result panel.
+ * @param THtmlWriter the renderer.
+ */
+ protected function renderResultPanel($writer)
+ {
+ $this->getResultPanel()->render($writer);
+ }
+
+ /**
+ * Renders the suggestions during a callback respones.
+ * @param THtmlWriter the renderer.
+ */
+ public function renderCallback($writer)
+ {
+ $this->renderSuggestions($writer);
+ }
+
+ /**
+ * Renders the suggestions repeater.
+ * @param THtmlWriter the renderer.
+ */
+ public function renderSuggestions($writer)
+ {
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $this->getSuggestions()->render($writer);
+ $boundary = $writer->getWriter()->getBoundary();
+ $this->getResponse()->getAdapter()->setResponseData($boundary);
+ }
+ }
+
+ /**
+ * @return array list of callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ //disallow page state update ?
+ //$this->getActiveControl()->getClientSide()->setEnablePageStateUpdate(false);
+ $options = array();
+ if(strlen($string = $this->getSeparator()))
+ {
+ $string = strtr($string,array('\t'=>"\t",'\n'=>"\n",'\r'=>"\r"));
+ $token = preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY);
+ $options['tokens'] = $token;
+ }
+ if($this->getAutoPostBack())
+ {
+ $options = array_merge($options,parent::getPostBackOptions());
+ $options['AutoPostBack'] = true;
+ }
+ if(strlen($select = $this->getTextCssClass()))
+ $options['select'] = $select;
+ $options['ResultPanel'] = $this->getResultPanel()->getClientID();
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ if(($minchars=$this->getMinChars())!=='')
+ $options['minChars'] = $minchars;
+ if(($frequency=$this->getFrequency())!=='')
+ $options['frequency'] = $frequency;
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ return $options;
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TActiveButton.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TAutoComplete';
+ }
+}
+
+/**
+ * TAutCompleteEventParameter contains the {@link getToken Token} requested by
+ * the user for a partial match of the suggestions.
+ *
+ * The {@link getSelectedIndex SelectedIndex} is a zero-based index of the
+ * suggestion selected by the user, -1 if not suggestion is selected.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TAutoCompleteEventParameter extends TCallbackEventParameter
+{
+ private $_selectedIndex=-1;
+
+ /**
+ * Creates a new TCallbackEventParameter.
+ */
+ public function __construct($response, $parameter, $index=-1)
+ {
+ parent::__construct($response, $parameter);
+ $this->_selectedIndex=$index;
+ }
+
+ /**
+ * @return int selected suggestion zero-based index, -1 if not selected.
+ */
+ public function getSelectedIndex()
+ {
+ return $this->_selectedIndex;
+ }
+
+ /**
+ * @return string token for matching a list of suggestions.
+ */
+ public function getToken()
+ {
+ return $this->getCallbackParameter();
+ }
+}
+
+/**
+ * TAutoCompleteTemplate class.
+ *
+ * TAutoCompleteTemplate is the default template for TAutoCompleteTemplate
+ * item template.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TAutoCompleteTemplate extends TComponent implements ITemplate
+{
+ private $_template;
+
+ public function __construct($template)
+ {
+ $this->_template = $template;
+ }
+ /**
+ * Instantiates the template.
+ * It creates a {@link TDataList} control.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $parent->getControls()->add($this->_template);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TBaseActiveControl.php b/lib/prado/framework/Web/UI/ActiveControls/TBaseActiveControl.php
new file mode 100644
index 0000000..01583eb
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TBaseActiveControl.php
@@ -0,0 +1,394 @@
+<?php
+/**
+ * TBaseActiveControl and TBaseActiveCallbackControl class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TCallbackClientSide');
+
+/**
+ * TBaseActiveControl class provided additional basic property for every
+ * active control. An instance of TBaseActiveControl or its decendent
+ * TBaseActiveCallbackControl is created by {@link TActiveControlAdapter::getBaseActiveControl()}
+ * method.
+ *
+ * The {@link setEnableUpdate EnableUpdate} property determines wether the active
+ * control is allowed to update the contents of the client-side when the callback
+ * response returns.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TBaseActiveControl extends TComponent
+{
+ /**
+ * @var TMap map of active control options.
+ */
+ private $_options;
+ /**
+ * @var TControl attached control.
+ */
+ private $_control;
+
+ /**
+ * Constructor. Attach a base active control to an active control instance.
+ * @param TControl active control
+ */
+ public function __construct($control)
+ {
+ $this->_control = $control;
+ $this->_options = new TMap;
+ }
+
+ /**
+ * Sets a named options with a value. Options are used to store and retrive
+ * named values for the base active controls.
+ * @param string option name.
+ * @param mixed new value.
+ * @param mixed default value.
+ * @return mixed options value.
+ */
+ protected function setOption($name,$value,$default=null)
+ {
+ $value = ($value===null) ? $default : $value;
+ if($value!==null)
+ $this->_options->add($name,$value);
+ }
+
+ /**
+ * Gets an option named value. Options are used to store and retrive
+ * named values for the base active controls.
+ * @param string option name.
+ * @param mixed default value.
+ * @return mixed options value.
+ */
+ protected function getOption($name,$default=null)
+ {
+ $item = $this->_options->itemAt($name);
+ return ($item===null) ? $default : $item;
+ }
+
+ /**
+ * @return TMap active control options
+ */
+ protected function getOptions()
+ {
+ return $this->_options;
+ }
+
+ /**
+ * @return TPage the page containing the attached control.
+ */
+ protected function getPage()
+ {
+ return $this->_control->getPage();
+ }
+
+ /**
+ * @return TControl the attached control.
+ */
+ protected function getControl()
+ {
+ return $this->_control;
+ }
+
+ /**
+ * @param boolean true to allow fine grain callback updates.
+ */
+ public function setEnableUpdate($value)
+ {
+ $this->setOption('EnableUpdate', TPropertyValue::ensureBoolean($value), true);
+ }
+
+ /**
+ * @return boolean true to allow fine grain callback updates.
+ */
+ public function getEnableUpdate()
+ {
+ return $this->getOption('EnableUpdate', true);
+ }
+
+ /**
+ * Returns true if callback response is allowed to update the browser contents.
+ * Is is true if the control is initilized, and is a callback request and
+ * the {@link setEnableUpdate EnableUpdate} property is true and
+ * the page is not loading post data.
+ * @return boolean true if the callback response is allowed update
+ * client-side contents.
+ */
+ public function canUpdateClientSide($bDontRequireVisibility=false)
+ {
+ return $this->getControl()->getHasChildInitialized()
+ && $this->getPage()->getIsLoadingPostData() == false
+ && $this->getPage()->getIsCallback()
+ && $this->getEnableUpdate()
+ && ($bDontRequireVisibility || $this->getControl()->getVisible());
+ }
+}
+
+/**
+ * TBaseActiveCallbackControl is a common set of options and functionality for
+ * active controls that can perform callback requests.
+ *
+ * The properties of TBaseActiveCallbackControl can be accessed and changed from
+ * each individual active controls' {@link getActiveControl ActiveControl}
+ * property.
+ *
+ * The following example sets the validation group property of a TCallback component.
+ * <code>
+ * <com:TCallback ActiveControl.ValidationGroup="group1" ... />
+ * </code>
+ *
+ * Additional client-side options and events can be set using the
+ * {@link getClientSide ClientSide} property. The following example shows
+ * an alert box when a TCallback component response returns successfully.
+ * <code>
+ * <com:TCallback ActiveControl.ClientSide.OnSuccess="alert('ok!')" ... />
+ * </code>
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TBaseActiveCallbackControl extends TBaseActiveControl
+{
+ /**
+ * Callback client-side options can be set by setting the properties of
+ * the ClientSide property. E.g. <com:TCallback ActiveControl.ClientSide.OnSuccess="..." />
+ * See {@link TCallbackClientSide} for details on the properties of ClientSide.
+ * @return TCallbackClientSide client-side callback options.
+ */
+ public function getClientSide()
+ {
+ if(($client = $this->getOption('ClientSide'))===null)
+ {
+ $client = $this->createClientSide();
+ $this->setOption('ClientSide', $client);
+ }
+ return $client;
+ }
+
+ /**
+ * Sets the client side options. Can only be set when client side is null.
+ * @param TCallbackClientSide client side options.
+ */
+ public function setClientSide($client)
+ {
+ if( $this->getOption('ClientSide')===null)
+ $this->setOption('ClientSide', $client);
+ else
+ throw new TConfigurationException(
+ 'active_controls_client_side_exists', $this->getControl()->getID());
+ }
+
+ /**
+ * @return TCallbackClientSide callback client-side options.
+ */
+ protected function createClientSide()
+ {
+ return new TCallbackClientSide;
+ }
+
+ /**
+ * Sets default callback options. Takes the ID of a TCallbackOptions
+ * component to duplicate the client-side
+ * options for this control. The {@link getClientSide ClientSide}
+ * subproperties takes precedence over the CallbackOptions property.
+ * @param string ID of a TCallbackOptions control from which ClientSide
+ * options are cloned.
+ */
+ public function setCallbackOptions($value)
+ {
+ $this->setOption('CallbackOptions', $value, '');
+ }
+
+ /**
+ * @return string ID of a TCallbackOptions control from which ClientSide
+ * options are duplicated.
+ */
+ public function getCallbackOptions()
+ {
+ return $this->getOption('CallbackOptions', '');
+ }
+
+ /**
+ * Returns an array of default callback client-side options. The default options
+ * are obtained from the client-side options of a TCallbackOptions control with
+ * ID specified by {@link setCallbackOptions CallbackOptions}.
+ * @return array list of default callback client-side options.
+ */
+ protected function getDefaultClientSideOptions()
+ {
+ if(($id=$this->getCallbackOptions())!=='')
+ {
+ if(($pos=strrpos($id,'.'))!==false)
+ {
+ $control=$this->getControl()->getSubProperty(substr($id,0,$pos));
+ $newid=substr($id,$pos+1);
+ if ($control!==null)
+ $control=$control->$newid;
+ }
+ else
+ {
+ // TCheckBoxList overrides findControl() with a fake implementation
+ // but accepts a second parameter to use the standard one
+ $control=$this->getControl()->findControl($id, true);
+ }
+
+ if($control instanceof TCallbackOptions)
+ return $control->getClientSide()->getOptions()->toArray();
+ else
+ throw new TConfigurationException('callback_invalid_callback_options', $this->getControl()->getID(), $id);
+ }
+
+ return array();
+ }
+
+ /**
+ * @return boolean whether callback event trigger by this button will cause
+ * input validation, default is true
+ */
+ public function getCausesValidation()
+ {
+ return $this->getOption('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether callback event trigger by this button will cause
+ * input validation
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setOption('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the group of validators which the button causes validation
+ * upon callback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getOption('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the button causes validation
+ * upon callback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setOption('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return boolean whether to perform validation if the callback is
+ * requested.
+ */
+ public function canCauseValidation()
+ {
+ if($this->getCausesValidation())
+ {
+ $group=$this->getValidationGroup();
+ return $this->getPage()->getValidators($group)->getCount()>0;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * @param mixed callback parameter value.
+ */
+ public function setCallbackParameter($value)
+ {
+ $this->setOption('CallbackParameter', $value, '');
+ }
+
+ /**
+ * @return mixed callback parameter value.
+ */
+ public function getCallbackParameter()
+ {
+ return $this->getOption('CallbackParameter', '');
+ }
+
+
+ /**
+ * @return array list of callback javascript options.
+ */
+ protected function getClientSideOptions()
+ {
+ $default = $this->getDefaultClientSideOptions();
+ $options = array_merge($default,$this->getClientSide()->getOptions()->toArray());
+ $validate = $this->getCausesValidation();
+ $options['CausesValidation']= $validate ? '' : false;
+ $options['ValidationGroup']=$this->getValidationGroup();
+ $options['CallbackParameter'] = $this->getCallbackParameter();
+ // needed for TCallback
+ if(!isset($options['EventTarget']))
+ $options['EventTarget'] = $this->getControl()->getUniqueID();
+ return $options;
+ }
+
+ /**
+ * Registers the callback control javascript code. Client-side options are
+ * merged and passed to the javascript code. This method should be called by
+ * Active component developers wanting to register the javascript to initialize
+ * the active component with additional options offered by the
+ * {@link getClientSide ClientSide} property.
+ * @param string client side javascript class name.
+ * @param array additional callback options.
+ */
+ public function registerCallbackClientScript($class,$options=null)
+ {
+ $cs = $this->getPage()->getClientScript();
+ if(is_array($options))
+ $options = array_merge($this->getClientSideOptions(),$options);
+ else
+ $options = $this->getClientSideOptions();
+
+ //remove true as default to save bytes
+ if($options['CausesValidation']===true)
+ $options['CausesValidation']='';
+ $cs->registerCallbackControl($class, $options);
+ }
+
+ /**
+ * Returns the javascript callback request instance. To invoke a callback
+ * request for this control call the <tt>dispatch()</tt> method on the
+ * request instance. Example code in javascript
+ * <code>
+ * var request = <%= $this->mycallback->ActiveControl->Javascript %>;
+ * request.setParameter('hello');
+ * request.dispatch(); //make the callback request.
+ * </code>
+ *
+ * Alternatively,
+ * <code>
+ * //dispatches immediately
+ * Prado.Callback("<%= $this->mycallback->UniqueID %>",
+ * $this->mycallback->ActiveControl->JsCallbackOptions);
+ * </code>
+ * @return string javascript client-side callback request object (javascript
+ * code)
+ */
+ public function getJavascript()
+ {
+ $client = $this->getPage()->getClientScript();
+ return $client->getCallbackReference($this->getControl(),$this->getClientSideOptions());
+ }
+
+ /**
+ * @param string callback requestion options as javascript code.
+ */
+ public function getJsCallbackOptions()
+ {
+ return TJavaScript::encode($this->getClientSideOptions());
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TCallback.php b/lib/prado/framework/Web/UI/ActiveControls/TCallback.php
new file mode 100644
index 0000000..1aae6ce
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TCallback.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * TCallback class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TCallback component class.
+ *
+ * The TCallback provides a basic callback handler that can be invoked from the
+ * client side by running the javascript code obtained from the
+ * {@link TBaseActiveCallbackControl::getJavascript ActiveControl.Javascript} property.
+ * The event {@link onCallback OnCallback} is raised when a callback is requested made.
+ *
+ * Example usage:
+ * <code>
+ * <com:TCallback ID="callback1" OnCallback="callback1_Requested" />
+ * <script type="text/javascript">
+ * function do_callback1()
+ * {
+ * var request = <%= $this->callback1->ActiveControl->Javascript %>;
+ * request.dispatch();
+ * }
+ * </script>
+ * <div onclick="do_callback1()">Click Me!</div>
+ * </code>
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallback extends TControl implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, call this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Raises the callback event. This method is required by
+ * {@link ICallbackEventHandler ICallbackEventHandler} interface. If
+ * {@link getCausesValidation ActiveControl.CausesValidation} is true,
+ * it will invoke the page's {@link TPage::validate validate} method first.
+ * It will raise {@link onCallback OnCallback} event. This method is mainly
+ * used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ if($this->getActiveControl()->canCauseValidation())
+ $this->getPage()->validate($this->getActiveControl()->getValidationGroup());
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TCallbackClientScript.php b/lib/prado/framework/Web/UI/ActiveControls/TCallbackClientScript.php
new file mode 100644
index 0000000..1f631f2
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TCallbackClientScript.php
@@ -0,0 +1,826 @@
+<?php
+/**
+ * TCallbackClientScript class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TCallbackClientScript class.
+ *
+ * The TCallbackClientScript class provides corresponding methods that can be
+ * executed on the client-side (i.e. the browser client that is viewing
+ * the page) during a callback response.
+ *
+ * The available methods includes setting/clicking input elements, changing Css
+ * styles, hiding/showing elements, and adding visual effects to elements on the
+ * page. The client-side methods can be access through the CallbackClient
+ * property available in TPage.
+ *
+ * For example, to hide "$myTextBox" element during callback response, do
+ * <code>
+ * $this->getPage()->getCallbackClient()->hide($myTextBox);
+ * </code>
+ *
+ * To call a specific jQuery method on an element, use the {@link jQuery} method:
+ * <code>
+ * // simple example: focus a textbox
+ * $this->getCallbackClient()->jQuery($myTextBox, 'focus');
+ *
+ * // complex example: resize a textbox using an animation
+ * $this->getCallbackClient()->jQuery($myTextBox, 'animate', array(
+ * array( 'width' => '+=100',
+ * 'height' => '+=50'
+ * ),
+ * array('duration' => 1000)
+ * ));
+ * </code>
+ *
+ * To call a jQueryUI effect on an element, use the {@link juiEffect} method:
+ * <code>
+ * // simple example: focus a textbox
+ * $this->getCallbackClient()->juiEffect($myTextBox, 'highlight');
+ * </code>
+ *
+ * In order to use the jQueryUI effects, the jqueryui script must be registered:
+ * <code>
+ * $this->getPage()->getClientScript()->registerPradoScript('jqueryui');
+ * </code>
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackClientScript extends TApplicationComponent
+{
+ /**
+ * @var TList list of client functions to execute.
+ */
+ private $_actions;
+
+ /**
+ * Constructor.
+ */
+ public function __construct()
+ {
+ $this->_actions = new TList;
+ }
+
+ /**
+ * @return array list of client function to be executed during callback
+ * response.
+ */
+ public function getClientFunctionsToExecute()
+ {
+ return $this->_actions->toArray();
+ }
+
+ /**
+ * Executes a client-side statement.
+ * @param string javascript function name
+ * @param array list of arguments for the function
+ */
+ public function callClientFunction($function, $params=array())
+ {
+ if(!is_array($params))
+ $params = array($params);
+
+ if(count($params) > 0)
+ {
+ if ($params[0] instanceof ISurroundable)
+ $params[0] = $params[0]->getSurroundingTagID();
+ elseif($params[0] instanceof TControl)
+ $params[0] = $params[0]->getClientID();
+ }
+ $this->_actions->add(array($function => $params));
+ }
+
+ /**
+ * Executes a jQuery client-side method over an element.
+ * @param string control or element id
+ * @param string jQuery method name
+ * @param array list of arguments for the function
+ */
+ public function jQuery($element, $method, $params=array())
+ {
+ if ($element instanceof ISurroundable)
+ $element = $element->getSurroundingTagID();
+ elseif($element instanceof TControl)
+ $element = $element->getClientID();
+
+ if(!is_array($params))
+ $params = array($params);
+
+ $this->_actions->add(array('Prado.Element.j' => array($element, $method, $params)));
+ }
+
+ /**
+ * Client script to set the value of a particular input element.
+ * @param TControl control element to set the new value
+ * @param string new value
+ */
+ public function setValue($input, $text)
+ {
+ $this->jQuery($input, 'val', $text);
+ }
+
+ /**
+ * Client script to select/clear/check a drop down list, check box list,
+ * or radio button list.
+ * The second parameter determines the selection method. Valid methods are
+ * - <b>Value</b>, select or check by value
+ * - <b>Values</b>, select or check by a list of values
+ * - <b>Index</b>, select or check by index (zero based index)
+ * - <b>Indices</b>, select or check by a list of index (zero based index)
+ * - <b>Clear</b>, clears or selections or checks in the list
+ * - <b>All</b>, select all
+ * - <b>Invert</b>, invert the selection.
+ * @param TControl list control
+ * @param string selection method
+ * @param string|int the value or index to select/check.
+ * @param string selection control type, either 'check' or 'select'
+ */
+ public function select($control, $method='Value', $value=null, $type=null)
+ {
+ $method = TPropertyValue::ensureEnum($method,
+ 'Value', 'Index', 'Clear', 'Indices', 'Values', 'All', 'Invert');
+ $type = ($type===null) ? $this->getSelectionControlType($control) : $type;
+ $total = $this->getSelectionControlIsListType($control) ? $control->getItemCount() : 1;
+
+ // pass the ID to avoid getting the surrounding elements (ISurroundable)
+ if($control instanceof TControl)
+ $control = $control->getClientID();
+
+ $this->callClientFunction('Prado.Element.select',
+ array($control, $type.$method, $value, $total));
+ }
+
+ private function getSelectionControlType($control)
+ {
+ if(is_string($control)) return 'check';
+ if($control instanceof TCheckBoxList)
+ return 'check';
+ if($control instanceof TCheckBox)
+ return 'check';
+ return 'select';
+ }
+
+ private function getSelectionControlIsListType($control)
+ {
+ return $control instanceof TListControl;
+ }
+
+ /**
+ * Client script to click on an element. <b>This client-side function is unpredictable.</b>
+ *
+ * @param TControl control element or element id
+ */
+ public function click($control)
+ {
+ $this->jQuery($control, 'trigger', 'click');
+ }
+
+ /**
+ * Client script to check or uncheck a checkbox or radio button.
+ * @param TControl control element or element id
+ * @param boolean check or uncheck the checkbox or radio button.
+ */
+ public function check($checkbox, $checked=true)
+ {
+ $this->select($checkbox, "Value", $checked);
+ }
+
+ /**
+ * Raise the client side event (given by $eventName) on a particular element.
+ * @param TControl control element or element id
+ * @param string Event name, e.g. "click"
+ */
+ public function raiseClientEvent($control, $eventName)
+ {
+ $this->jQuery($control, 'trigger', $eventName);
+ }
+
+ /**
+ * Sets the attribute of a particular control.
+ * @param TControl control element or element id
+ * @param string attribute name
+ * @param string attribute value
+ */
+ public function setAttribute($control, $name, $value)
+ {
+ // Attributes should be applied on Surrounding tag, except for 'disabled' attribute
+ if ($control instanceof ISurroundable && strtolower($name)!=='disabled')
+ $control=$control->getSurroundingTagID();
+ $this->callClientFunction('Prado.Element.setAttribute',array($control, $name, $value));
+ }
+
+ /**
+ * Sets the options of a select input element.
+ * @param TControl control element or element id
+ * @param TCollection a list of new options
+ */
+ public function setListItems($control, $items)
+ {
+ $options = array();
+ if($control instanceof TListControl)
+ {
+ $promptText = $control->getPromptText();
+ $promptValue = $control->getPromptValue();
+
+ if($promptValue==='')
+ $promptValue = $promptText;
+
+ if($promptValue!=='')
+ $options[] = array($promptText, $promptValue);
+ }
+
+ foreach($items as $item)
+ {
+ if($item->getHasAttributes())
+ $options[] = array($item->getText(),$item->getValue(), $item->getAttributes()->itemAt('Group'));
+ else
+ $options[] = array($item->getText(),$item->getValue());
+ }
+ $this->callClientFunction('Prado.Element.setOptions', array($control, $options));
+ }
+
+ /**
+ * Shows an element by changing its CSS display style as empty.
+ * @param TControl control element or element id
+ */
+ public function show($element)
+ {
+ $this->jQuery($element, 'show');
+ }
+
+ /**
+ * Hides an element by changing its CSS display style to "none".
+ * @param TControl control element or element id
+ */
+ public function hide($element)
+ {
+ $this->jQuery($element, 'hide');
+ }
+
+ /**
+ * Toggles the visibility of the element.
+ * @param TControl control element or element id
+ * @param string visual effect, such as, 'fade' or 'slide'.
+ * @param array additional options.
+ */
+ public function toggle($element, $effect=null, $options=array())
+ {
+ switch(strtolower($effect))
+ {
+ case 'fade':
+ $method='fadeToggle';
+ break;
+ case 'slide':
+ $method='slideToggle';
+ break;
+ default:
+ $method='toggle';
+ // avoid fancy effect by default
+ if(!array_key_exists('duration', $options))
+ $options['duration']=0;
+ break;
+ }
+ $this->jQuery($element, $method, $options);
+ }
+
+ /**
+ * Removes an element from the HTML page.
+ * @param TControl control element or element id
+ */
+ public function remove($element)
+ {
+ $this->jQuery($element, 'remove');
+ }
+
+ /**
+ * Update the element's innerHTML with new content.
+ * @param TControl control element or element id
+ * @param TControl new HTML content, if content is of a TControl, the
+ * controls render method is called.
+ */
+ public function update($element, $content)
+ {
+ $this->jQuery($element, 'html', $content);
+ }
+
+ /**
+ * Add a Css class name to the element.
+ * @param TControl control element or element id
+ * @param string CssClass name to add.
+ */
+ public function addCssClass($element, $cssClass)
+ {
+ $this->jQuery($element, 'addClass', $cssClass);
+ }
+
+ /**
+ * Remove a Css class name from the element.
+ * @param TControl control element or element id
+ * @param string CssClass name to remove.
+ */
+ public function removeCssClass($element, $cssClass)
+ {
+ $this->jQuery($element, 'removeClass', $cssClass);
+ }
+
+ /**
+ * Scroll the top of the browser viewing area to the location of the
+ * element.
+ *
+ * @param TControl control element or element id
+ * @param array additional options: 'duration' in ms, 'offset' from the top in pixels
+ */
+ public function scrollTo($element, $options=array())
+ {
+ $this->callClientFunction('Prado.Element.scrollTo', array($element, $options));
+ }
+
+ /**
+ * Focus on a particular element.
+ * @param TControl control element or element id.
+ */
+ public function focus($element)
+ {
+ $this->jQuery($element, 'trigger', 'focus');
+ }
+
+ /**
+ * Sets the style of element. The style must be a key-value array where the
+ * key is the style property and the value is the style value.
+ * @param TControl control element or element id
+ * @param array list of key-value pairs as style property and style value.
+ */
+ public function setStyle($element, $styles)
+ {
+ $this->jQuery($element, 'css', array($styles));
+ }
+
+ /**
+ * Append a HTML fragement to the element.
+ * @param TControl control element or element id
+ * @param string HTML fragement or the control to be rendered
+ */
+ public function appendContent($element, $content)
+ {
+ $this->jQuery($element, 'append', $content);
+ }
+
+ /**
+ * Prepend a HTML fragement to the element.
+ * @param TControl control element or element id
+ * @param string HTML fragement or the control to be rendered
+ */
+ public function prependContent($element, $content)
+ {
+ $this->jQuery($element, 'prepend', $content);
+ }
+
+ /**
+ * Insert a HTML fragement after the element.
+ * @param TControl control element or element id
+ * @param string HTML fragement or the control to be rendered
+ */
+ public function insertContentAfter($element, $content)
+ {
+ $this->jQuery($element, 'after', $content);
+ }
+
+ /**
+ * Insert a HTML fragement in before the element.
+ * @param TControl control element or element id
+ * @param string HTML fragement or the control to be rendered
+ */
+ public function insertContentBefore($element, $content)
+ {
+ $this->jQuery($element, 'before', $content);
+ }
+
+ /**
+ * Replace the content of an element with new content. The new content can
+ * be a string or a TControl component. If the <tt>content</tt> parameter is
+ * a TControl component, its rendered method will be called and its contents
+ * will be used for replacement.
+ * @param TControl control element or HTML element id.
+ * @param string HTML fragement or the control to be rendered.
+ * @param boolean whether to fully replace the element or just its inner content.
+ * @see insertAbout
+ * @see insertBelow
+ * @see insertBefore
+ * @see insertAfter
+ */
+ protected function replace($element, $content, $self)
+ {
+ if($content instanceof TControl)
+ {
+ $boundary = $this->getRenderedContentBoundary($content);
+ $content = null;
+ }
+ else if($content instanceof THtmlWriter)
+ {
+ $boundary = $this->getResponseContentBoundary($content);
+ $content = null;
+ }
+ else
+ $boundary = null;
+
+ $this->callClientFunction('Prado.Element.replace', array($element, $content, $boundary, $self));
+ }
+
+ /**
+ * Replace the content of an element with new content contained in writer.
+ * @param TControl control element or HTML element id.
+ * @param string HTML fragement or the control to be rendered.
+ * @param boolean whether to fully replace the element or just its inner content, defaults to true.
+ */
+ public function replaceContent($element, $content, $self=true)
+ {
+ $this->replace($element, $content, $self);
+ }
+
+
+ /**
+ * Evaluate a block of javascript enclosed in a boundary.
+ * @param THtmlWriter writer for the content.
+ */
+ public function evaluateScript($writer)
+ {
+ if($writer instanceof THtmlWriter)
+ {
+ $boundary = $this->getResponseContentBoundary($writer);
+ $content = null;
+ } else {
+ $boundary = null;
+ $content = $writer;
+ }
+
+ $this->callClientFunction('Prado.Element.evaluateScript', array($content, $boundary));
+ }
+
+ /**
+ * Appends a block of inline javascript enclosed in a boundary.
+ * Similar to to evaluateScript(), but functions declared in the
+ * inline block will be available to page elements.
+ * @param THtmlWriter writer for the content.
+ */
+ public function appendScriptBlock($content)
+ {
+ if($content instanceof TControl)
+ {
+ $boundary = $this->getRenderedContentBoundary($content);
+ }
+ elseif($content instanceof THtmlWriter)
+ {
+ $boundary = $this->getResponseContentBoundary($content);
+ }
+
+ $this->callClientFunction('Prado.Element.appendScriptBlock', array($boundary));
+ }
+
+ /**
+ * Renders the control and return the content boundary from
+ * TCallbackResponseWriter. This method should only be used by framework
+ * component developers. The render() method is defered to be called in the
+ * TActivePageAdapter class.
+ * @param TControl control to be rendered on callback response.
+ * @return string the boundary for which the rendered content is wrapped.
+ */
+ private function getRenderedContentBoundary($control)
+ {
+ $writer = $this->getResponse()->createHtmlWriter();
+ $adapter = $control->getPage()->getAdapter();
+ $adapter->registerControlToRender($control, $writer);
+ return $writer->getWriter()->getBoundary();
+ }
+
+ /**
+ * @param THtmlWriter the writer responsible for rendering html content.
+ * @return string content boundary.
+ */
+ private function getResponseContentBoundary($html)
+ {
+ if($html instanceof THtmlWriter)
+ {
+ if($html->getWriter() instanceof TCallbackResponseWriter)
+ return $html->getWriter()->getBoundary();
+ }
+ return null;
+ }
+
+ /* VISUAL EFFECTS */
+
+ /**
+ * Add a visual effect the element.
+ * @param string visual effect function name.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function visualEffect($type, $element, $options=array())
+ {
+ $this->jQuery($element, $type, $options);
+ }
+
+ /* BASIC EFFECTS (JQUERY CORE) */
+
+ /**
+ * Visual Effect: Gradually make the element appear.
+ * This effect doesn't need jQueryUI.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function fadeIn($element, $options=array())
+ {
+ $this->visualEffect('fadeIn', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Gradually fade the element.
+ * This effect doesn't need jQueryUI.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function fadeOut($element, $options=array())
+ {
+ $this->visualEffect('fadeOut', $element, $options);
+ }
+
+ /**
+ * Set the opacity on a html element or control.
+ * This effect doesn't need jQueryUI.
+ * @param TControl control element or element id
+ * @param float opacity value between 1 and 0
+ */
+ public function fadeTo($element, $value, $duration=500)
+ {
+ $value = TPropertyValue::ensureFloat($value);
+ $this->visualEffect('fadeTo', $element, array($duration, $value));
+ }
+
+ /**
+ * Visual Effect: Slide down.
+ * This effect doesn't need jQueryUI.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function slideDown($element, $options=array())
+ {
+ $this->visualEffect('slideDown', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Slide up.
+ * This effect doesn't need jQueryUI.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function slideUp($element, $options=array())
+ {
+ $this->visualEffect('slideUp', $element, $options);
+ }
+
+ /* OLD METHODS, DEPRECATED, BACKWARDS-COMPATIBILITY */
+
+ /**
+ * Alias of fadeIn()
+ * @deprecated since 3.4
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function appear($element, $options=array())
+ {
+ $this->fadeIn($element, $options);
+ }
+
+ /**
+ * Alias of fadeOut()
+ * @deprecated since 3.4
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function fade($element, $options=array())
+ {
+ $this->fadeOut($element, $options);
+ }
+
+ /**
+ * Alias of fadeTo()
+ * @deprecated since 3.4
+ * @param TControl control element or element id
+ * @param float opacity value between 1 and 0
+ */
+ public function setOpacity($element, $value)
+ {
+ $this->fadeTo($element, $value);
+ }
+
+ /* JQUERY UI EFFECTS */
+
+ /**
+ * Add a jQuery-ui effect the element.
+ * This method needs jQueryUI.
+ * @param string visual effect function name.
+ * @param TControl control element or element id
+ * @param array effect options.
+ */
+ public function juiEffect($element, $effect, $options=array())
+ {
+ $options['effect']=$effect;
+ $this->jQuery($element, 'effect', array($options));
+ }
+
+ /**
+ * Visual Effect: Blind.
+ * This effect needs jQueryUI.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function blind($element, $options=array())
+ {
+ $this->juiEffect($element, 'blind', $options);
+ }
+
+ /**
+ * Visual Effect: Drop out.
+ * This effect needs jQueryUI.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function drop($element, $options=array())
+ {
+ $this->juiEffect($element, 'drop', $options);
+ }
+
+ /**
+ * Visual Effect: Fold.
+ * This effect needs jQueryUI.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function fold($element, $options=array())
+ {
+ $this->juiEffect($element, 'fold', $options);
+ }
+
+ /**
+ * Visual Effect: Gradually make an element grow to a predetermined size.
+ * This effect needs jQueryUI.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function size($element, $options=array())
+ {
+ $this->juiEffect($element, 'size', $options);
+ }
+
+ /**
+ * Visual Effect: Gradually grow and fade the element.
+ * This effect needs jQueryUI.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function puff($element, $options=array())
+ {
+ $this->juiEffect($element, 'puff', $options);
+ }
+
+ /**
+ * Visual Effect: Pulsate.
+ * This effect needs jQueryUI.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function pulsate($element, $options=array())
+ {
+ $this->juiEffect($element, 'pulsate', $options);
+ }
+
+ /**
+ * Visual Effect: Shake the element.
+ * This effect needs jQueryUI.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function shake($element, $options=array())
+ {
+ $this->juiEffect($element, 'shake', $options);
+ }
+
+ /**
+ * Visual Effect: Scale the element.
+ * This effect needs jQueryUI.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function scale($element, $options=array())
+ {
+ $this->juiEffect($element, 'scale', $options);
+ }
+
+ /**
+ * Visual Effect: High light the element for about 2 seconds.
+ * This effect needs jQueryUI.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function highlight($element, $options=array())
+ {
+ $this->juiEffect($element, 'highlight', $options);
+ }
+
+ /* jui - OLD METHODS, DEPRECATED, BACKWARDS-COMPATIBILITY */
+
+ /**
+ * Alias of blind(), presets the direction to 'down'
+ * @deprecated since 3.4
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function blindDown($element, $options=array())
+ {
+ $options['direction']='down';
+ $this->blind($element, $options);
+ }
+
+ /**
+ * Alias of blind(), presets the direction to 'up'
+ * @deprecated since 3.4
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function blindUp($element, $options=array())
+ {
+ $options['direction']='up';
+ $this->blind($element, $options);
+ }
+
+ /**
+ * Alias of drop()
+ * @deprecated since 3.4
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function dropOut($element, $options=array())
+ {
+ $this->drop($element, $options);
+ }
+
+ /**
+ * Alias of size()
+ * @deprecated since 3.4
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function grow($element, $options=array())
+ {
+ $this->size($element, $options);
+ }
+
+ /**
+ * Alias of scale()
+ * @deprecated since 3.4
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function shrink($element, $options=array())
+ {
+ $options['percent']=0;
+ $this->scale($element, $options);
+ }
+
+ /**
+ * Alias of scale()
+ * @deprecated since 3.4
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function squish($element, $options=array())
+ {
+ $options['origin']=array('top', 'left');
+ $options['percent']=0;
+ $this->scale($element, $options);
+ }
+
+ /**
+ * Alias of scale()
+ * @deprecated since 3.4
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function switchOff($element, $options=array())
+ {
+ $options['direction']='vertical';
+ $options['percent']=0;
+ $this->scale($element, $options);
+ }
+
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TCallbackClientSide.php b/lib/prado/framework/Web/UI/ActiveControls/TCallbackClientSide.php
new file mode 100644
index 0000000..874aeb4
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TCallbackClientSide.php
@@ -0,0 +1,320 @@
+<?php
+/**
+ * TCallbackClientSide class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TCallbackClientSide class.
+ *
+ * The following client side events are executing in order if the callback
+ * request and response are send and received successfuly.
+ *
+ * - <b>onPreDispatch</b> executed before a request is dispatched.
+ * - <b>onUninitialized</b> executed when callback request is uninitialized.
+ * - <b>onLoading</b>* executed when callback request is initiated
+ * - <b>onLoaded</b>* executed when callback request begins.
+ * - <b>onInteractive</b> executed when callback request is in progress.
+ * - <b>onComplete</b>executed when callback response returns.
+ * - <b>onSuccess</b> executed when callback request returns and is successful.
+ * - <b>onFailure</b> executed when callback request returns and fails.
+ * - <b>onException</b> raised when callback request fails due to request/response errors.
+ *
+ * * Note that theses 2 events are not fired correctly by Opera. To make
+ * them work in this browser, Prado will fire them just after onPreDispatch.
+ *
+ * In a general way, onUninitialized, onLoading, onLoaded and onInteractive events
+ * are not implemented consistently in all browsers.When cross browser compatibility is
+ * needed, it is best to avoid use them
+ *
+ * The OnSuccess and OnFailure events are raised when the
+ * response is returned. A successful request/response will raise
+ * OnSuccess event otherwise OnFailure will be raised.
+ *
+ * - <b>PostState</b> true to collect the form inputs and post them during callback, default is true.
+ * - <b>RequestTimeOut</b> The request timeout in milliseconds.
+ * - <b>HasPriority</b> true to ensure that the callback request will be sent
+ * immediately and will abort existing prioritized requests. It does not affect
+ * callbacks that are not prioritized.
+ * - <b>EnablePageStateUpdate</b> enable the callback response to enable the
+ * viewstate update. This will automatically set HasPriority to true when enabled.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackClientSide extends TClientSideOptions
+{
+ /**
+ * Returns javascript statement enclosed within a javascript function.
+ * @param string javascript statement
+ * @return string javascript statement wrapped in a javascript function
+ */
+ protected function ensureFunction($javascript)
+ {
+ return "function(sender, parameter){ {$javascript} }";
+ }
+
+ /**
+ * @param string javascript code to be executed before a request is dispatched.
+ */
+ public function setOnPreDispatch($javascript)
+ {
+ $this->setFunction('onPreDispatch', $javascript);
+ }
+
+ /**
+ * @return string javascript code to be executed before a request is dispatched.
+ */
+ public function getOnPreDispatch()
+ {
+ return $this->getOption('onPreDispatch');
+ }
+
+ /**
+ * @return string javascript code for client-side onUninitialized event
+ */
+ public function getOnUninitialized()
+ {
+ return $this->getOption('onUninitialized');
+ }
+
+ /**
+ * @param string javascript code for client-side onUninitialized event.
+ */
+ public function setOnUninitialized($javascript)
+ {
+ $this->setFunction('onUninitialized', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side onLoading event
+ */
+ public function getOnLoading()
+ {
+ return $this->getOption('onLoading');
+ }
+
+ /**
+ * @param string javascript code for client-side onLoading event.
+ */
+ public function setOnLoading($javascript)
+ {
+ $this->setFunction('onLoading', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side onLoaded event
+ */
+ public function getOnLoaded()
+ {
+ return $this->getOption('onLoaded');
+ }
+
+ /**
+ * @param string javascript code for client-side onLoaded event.
+ */
+ public function setOnLoaded($javascript)
+ {
+ $this->setFunction('onLoaded', $javascript);
+ }
+ /**
+ * @return string javascript code for client-side onInteractive event
+ */
+ public function getOnInteractive()
+ {
+ return $this->getOption('onInteractive');
+ }
+
+ /**
+ * @param string javascript code for client-side onInteractive event.
+ */
+ public function setOnInteractive($javascript)
+ {
+ $this->setFunction('onInteractive', $javascript);
+ }
+ /**
+ * @return string javascript code for client-side onComplete event
+ */
+ public function getOnComplete()
+ {
+ return $this->getOption('onComplete');
+ }
+
+ /**
+ * @param string javascript code for client-side onComplete event.
+ */
+ public function setOnComplete($javascript)
+ {
+ $this->setFunction('onComplete', $javascript);
+ }
+ /**
+ * @return string javascript code for client-side onSuccess event
+ */
+ public function getOnSuccess()
+ {
+ return $this->getOption('onSuccess');
+ }
+
+ /**
+ * @param string javascript code for client-side onSuccess event.
+ */
+ public function setOnSuccess($javascript)
+ {
+ $this->setFunction('onSuccess', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side onFailure event
+ */
+ public function getOnFailure()
+ {
+ return $this->getOption('onFailure');
+ }
+
+ /**
+ * @param string javascript code for client-side onFailure event.
+ */
+ public function setOnFailure($javascript)
+ {
+ $this->setFunction('onFailure', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side onException event
+ */
+ public function getOnException()
+ {
+ return $this->getOption('onException');
+ }
+
+ /**
+ * @param string javascript code for client-side onException event.
+ */
+ public function setOnException($javascript)
+ {
+ $this->setFunction('onException', $javascript);
+ }
+
+ /**
+ * @return boolean true to post the inputs of the form on callback, default
+ * is post the inputs on callback.
+ */
+ public function getPostState()
+ {
+ return $this->getOption('PostInputs');
+ }
+
+ /**
+ * @param boolean true to post the inputs of the form with callback
+ * requests. Default is to post the inputs.
+ */
+ public function setPostState($value)
+ {
+ $this->setOption('PostInputs', TPropertyValue::ensureBoolean($value));
+ }
+
+ /**
+ * @return integer callback request timeout.
+ */
+ public function getRequestTimeOut()
+ {
+ return $this->getOption('RequestTimeOut');
+ }
+
+ /**
+ * @param integer callback request timeout
+ */
+ public function setRequestTimeOut($value)
+ {
+ $this->setOption('RequestTimeOut', TPropertyValue::ensureInteger($value));
+ }
+
+ /**
+ * @return boolean true if the callback request has priority and will abort
+ * existing prioritized request in order to send immediately. It does not
+ * affect callbacks that are not prioritized. Default is true.
+ */
+ public function getHasPriority()
+ {
+ $option = $this->getOption('HasPriority');
+ return ($option===null) ? true : $option;
+ }
+
+ /**
+ * @param boolean true to ensure that the callback request will be sent
+ * immediately and will abort existing prioritized requests. It does not
+ * affect callbacks that are not prioritized.
+ */
+ public function setHasPriority($value)
+ {
+ $hasPriority = TPropertyValue::ensureBoolean($value);
+ $this->setOption('HasPriority', $hasPriority);
+ if(!$hasPriority)
+ $this->setEnablePageStateUpdate(false);
+ }
+
+ /**
+ * Set to true to enable the callback response to enable the viewstate
+ * update. This will automatically set HasPrority to true.
+ * @param boolean true enables the callback response to update the
+ * viewstate.
+ */
+ public function setEnablePageStateUpdate($value)
+ {
+ $enabled = TPropertyValue::ensureBoolean($value);
+ $this->setOption('EnablePageStateUpdate', $enabled);
+ if($enabled)
+ $this->setHasPriority(true);
+ }
+
+ /**
+ * @return boolean client-side viewstate will be updated on callback
+ * response if true. Default is true.
+ */
+ public function getEnablePageStateUpdate()
+ {
+ $option = $this->getOption('EnablePageStateUpdate');
+ return ($option===null) ? true : $option;
+ }
+
+ /**
+ * @return string post back target ID
+ */
+ public function getPostBackTarget()
+ {
+ return $this->getOption('EventTarget');
+ }
+
+ /**
+ * @param string post back target ID
+ */
+ public function setPostBackTarget($value)
+ {
+ if($value instanceof TControl)
+ $value = $value->getUniqueID();
+ $this->setOption('EventTarget', $value);
+ }
+
+ /**
+ * @return string post back event parameter.
+ */
+ public function getPostBackParameter()
+ {
+ return $this->getOption('EventParameter');
+ }
+
+ /**
+ * @param string post back event parameter.
+ */
+ public function setPostBackParameter($value)
+ {
+ $this->setOption('EventParameter', $value);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TCallbackEventParameter.php b/lib/prado/framework/Web/UI/ActiveControls/TCallbackEventParameter.php
new file mode 100644
index 0000000..9306aec
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TCallbackEventParameter.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * TCallbackEventParameter class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TCallbackEventParameter class.
+ *
+ * The TCallbackEventParameter provides the parameter passed during the callback
+ * request in the {@link getCallbackParameter CallbackParameter} property. The
+ * callback response content (e.g. new HTML content) must be rendered
+ * using an THtmlWriter obtained from the {@link getNewWriter NewWriter}
+ * property, which returns a <b>NEW</b> instance of TCallbackResponseWriter.
+ *
+ * Each instance TCallbackResponseWriter is associated with a unique
+ * boundary delimited. By default each panel only renders its own content.
+ * To replace the content of ONE panel with that of rendered from multiple panels
+ * use the same writer instance for the panels to be rendered.
+ *
+ * The response data (i.e., passing results back to the client-side
+ * callback handler function) can be set using {@link setResponseData ResponseData} property.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackEventParameter extends TEventParameter
+{
+ /**
+ * @var THttpResponse output content.
+ */
+ private $_response;
+ /**
+ * @var mixed callback request parameter.
+ */
+ private $_parameter;
+
+ /**
+ * Creates a new TCallbackEventParameter.
+ */
+ public function __construct($response, $parameter)
+ {
+ $this->_response = $response;
+ $this->_parameter = $parameter;
+ }
+
+ /**
+ * @return TCallbackResponseWriter holds the response content.
+ */
+ public function getNewWriter()
+ {
+ return $this->_response->createHtmlWriter(null);
+ }
+
+ /**
+ * @return mixed callback request parameter.
+ */
+ public function getCallbackParameter()
+ {
+ return $this->_parameter;
+ }
+
+ /**
+ * @param mixed callback response data.
+ */
+ public function setResponseData($value)
+ {
+ $this->_response->getAdapter()->setResponseData($value);
+ }
+
+ /**
+ * @return mixed callback response data.
+ */
+ public function getResponseData()
+ {
+ return $this->_response->getAdapter()->getResponseData();
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TCallbackOptions.php b/lib/prado/framework/Web/UI/ActiveControls/TCallbackOptions.php
new file mode 100644
index 0000000..e79561d
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TCallbackOptions.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * TCallbackOptions component class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TCallbackOptions class.
+ *
+ * TCallbackOptions allows common set of callback client-side options
+ * to be attached to other active controls.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackOptions extends TControl
+{
+ /**
+ * @var TCallbackClientSide client side callback options.
+ */
+ private $_clientSide;
+
+ /**
+ * Callback client-side options can be set by setting the properties of
+ * the ClientSide property. E.g. <com:TCallbackOptions ClientSide.OnSuccess="..." />
+ * See {@link TCallbackClientSide} for details on the properties of
+ * ClientSide.
+ * @return TCallbackClientSide client-side callback options.
+ */
+ public function getClientSide()
+ {
+ if($this->_clientSide===null)
+ $this->_clientSide = $this->createClientSide();
+ return $this->_clientSide;
+ }
+
+ /**
+ * @return TCallbackClientSide callback client-side options.
+ */
+ protected function createClientSide()
+ {
+ return Prado::createComponent('System.Web.UI.ActiveControls.TCallbackClientSide');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TCallbackResponseAdapter.php b/lib/prado/framework/Web/UI/ActiveControls/TCallbackResponseAdapter.php
new file mode 100755
index 0000000..4a1c41b
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TCallbackResponseAdapter.php
@@ -0,0 +1,159 @@
+<?php
+/**
+ * TCallbackResponseAdapter and TCallbackResponseWriter class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TCallbackResponseAdapter alters the THttpResponse's outputs.
+ *
+ * A TCallbackResponseWriter is used instead of the TTextWrite when
+ * createHtmlWriter is called. Each call to createHtmlWriter will create
+ * a new TCallbackResponseWriter. When flushContent() is called each
+ * instance of TCallbackResponseWriter's content is flushed.
+ *
+ * The callback response data can be set using the {@link setResponseData ResponseData}
+ * property.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackResponseAdapter extends THttpResponseAdapter
+{
+ /**
+ * @var TCallbackResponseWriter[] list of writers.
+ */
+ private $_writers=array();
+ /**
+ * @var mixed callback response data.
+ */
+ private $_data;
+
+ private $_redirectUrl=null;
+
+ /**
+ * Returns a new instance of THtmlWriter.
+ * An instance of TCallbackResponseWriter is created to hold the content.
+ * @param string writer class name.
+ * @param THttpResponse http response handler.
+ */
+ public function createNewHtmlWriter($type,$response)
+ {
+ $writer = new TCallbackResponseWriter();
+ $this->_writers[] = $writer;
+ return parent::createNewHtmlWriter($type,$writer);
+ }
+
+ /**
+ * Flushes the contents in the writers.
+ */
+ public function flushContent()
+ {
+ foreach($this->_writers as $writer)
+ echo $writer->flush();
+ parent::flushContent();
+ }
+
+ /**
+ * @param mixed callback response data.
+ */
+ public function setResponseData($data)
+ {
+ $this->_data = $data;
+ }
+
+ /**
+ * @return mixed callback response data.
+ */
+ public function getResponseData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * Delay the redirect until we process the rest of the page.
+ * @param string new url to redirect to.
+ */
+ public function httpRedirect($url)
+ {
+ if($url[0]==='/')
+ $url=$this->getRequest()->getBaseUrl().$url;
+ $this->_redirectUrl=str_replace('&amp;','&',$url);
+ }
+
+ /**
+ * @return string new url for callback response to redirect to.
+ */
+ public function getRedirectedUrl()
+ {
+ return $this->_redirectUrl;
+ }
+}
+
+/**
+ * TCallbackResponseWriter class.
+ *
+ * TCallbackResponseWriter class enclosed a chunck of content within a
+ * html comment boundary. This allows multiple chuncks of content to return
+ * in the callback response and update multiple HTML elements.
+ *
+ * The {@link setBoundary Boundary} property sets boundary identifier in the
+ * HTML comment that forms the boundary. By default, the boundary identifier
+ * is generated using microtime.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackResponseWriter extends TTextWriter
+{
+ /**
+ * @var string boundary ID
+ */
+ private $_boundary;
+
+ /**
+ * Constructor. Generates unique boundary ID using microtime.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->_boundary = sprintf('%x',crc32(uniqid(null, true)));
+ }
+
+ /**
+ * @return string boundary identifier.
+ */
+ public function getBoundary()
+ {
+ return $this->_boundary;
+ }
+
+ /**
+ * @param string boundary identifier.
+ */
+ public function setBoundary($value)
+ {
+ $this->_boundary = $value;
+ }
+
+ /**
+ * Returns the text content wrapped within a HTML comment with boundary
+ * identifier as its comment content.
+ * @return string text content chunck.
+ */
+ public function flush()
+ {
+ $content = parent::flush();
+ if(empty($content))
+ return "";
+ return '<!--'.$this->getBoundary().'-->'.$content.'<!--//'.$this->getBoundary().'-->';
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TDraggable.php b/lib/prado/framework/Web/UI/ActiveControls/TDraggable.php
new file mode 100755
index 0000000..3f6008b
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TDraggable.php
@@ -0,0 +1,246 @@
+<?php
+/**
+ * TDraggable class file
+ *
+ * @author Christophe BOULAIN (Christophe.Boulain@gmail.com)
+ * @copyright Copyright &copy; 2008, PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TDraggable is a control which can be dragged
+ *
+ * This control will make "draggable" control.
+ * Properties :
+ *
+ * <b>{@link setGhosting Ghosting}</b> : If set to "Ghosting" or "True", the dragged element will be cloned, and the clone will be dragged.
+ * If set to "SuperGhosting", the element will be cloned, and attached to body, so it can be dragged outside of its parent.
+ * If set to "None" of "False" (default), the element itself is dragged
+ * <b>{@link setRevert Revert}</b>: Set to True if you want your dragged element to revert to its initial position if not dropped on a valid area.
+ * <b>{@link setConstraint Constraint}</b>: Set this to Horizontal or Vertical if you want to constraint your move in one direction.
+ * <b>{@link setHandle Handle}</b>:
+ *
+ * @author Christophe BOULAIN (Christophe.Boulain@gmail.com)
+ * @copyright Copyright &copy; 2008, PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+class TDraggable extends TPanel
+{
+ /**
+ * Set the handle id or css class
+ * @param string
+ */
+ public function setHandle ($value)
+ {
+ $this->setViewState('DragHandle', TPropertyValue::ensureString($value), null);
+ }
+
+ /**
+ * Get the handle id or css class
+ * @return string
+ */
+ public function getHandle ()
+ {
+ return $this->getViewState('DragHandle', null);
+ }
+
+ /**
+ * Determine if draggable element should revert to it orginal position
+ * upon release in an non-droppable container.
+ * Since 3.2, Revert property can be set to one of the value of {@link TDraggableRevertOption} enumeration.
+ * o 'True' or 'Revert' : The draggable will revert to it's original position
+ * o 'False' or 'None' : The draggable won't revert to it's original position
+ * o 'Failure' : The draggable will only revert if it's dropped on a non droppable area
+ * @return TDraggableRevertOption true to revert
+ */
+ public function getRevert()
+ {
+ return $this->getViewState('Revert', TDraggableRevertOptions::Revert);
+ }
+
+ /**
+ * Sets whether the draggable element should revert to it orginal position
+ * upon release in an non-droppable container.
+ * Since 3.2, Revert property can be set to one of the value of {@link TDraggableRevertOption} enumeration.
+ * o 'True' or 'Revert' : The draggable will revert to it's original position
+ * o 'False' or 'None' : The draggable won't revert to it's original position
+ * o 'Failure' : The draggable will only revert if it's dropped on a non droppable area
+ * @param boolean true to revert
+ */
+ public function setRevert($value)
+ {
+ if (strcasecmp($value,'true')==0 || $value===true)
+ $value=TDraggableRevertOptions::Revert;
+ elseif (strcasecmp($value,'false')==0 || $value===false)
+ $value=TDraggableRevertOptions::None;
+ $this->setViewState('Revert', TPropertyValue::ensureEnum($value, 'TDraggableRevertOptions'), true);
+ }
+
+ /**
+ * Determine if the element should be cloned when dragged
+ * If true, Clones the element and drags the clone, leaving the original in place until the clone is dropped.
+ * Defaults to false
+ * Since 3.2, Ghosting can be set to one of the value of {@link TDraggableGhostingOptions} enumeration.
+ * o "True" or "Ghosting" means standard pre-3.2 ghosting mechanism
+ * o "SuperGhosting" use the Superghosting patch by Christopher Williams, which allow elements to be dragged from an
+ * scrollable list
+ * o "False" or "None" means no Ghosting options
+ *
+ * @return TDraggableGhostingOption to clone the element
+ */
+ public function getGhosting ()
+ {
+ return $this->getViewState('Ghosting', TDraggableGhostingOptions::None);
+ }
+
+ /**
+ * Sets wether the element should be cloned when dragged
+ * If true, Clones the element and drags the clone, leaving the original in place until the clone is dropped.
+ * Defaults to false
+ *
+ * Since 3.2, Ghosting can be set to one of the value of {@link TDraggableGhostingOptions} enumeration.
+ * o "True" or "Ghosting" means standard pre-3.2 ghosting mechanism
+ * o "SuperGhosting" use the Superghosting patch by Christopher Williams, which allow elements to be dragged from an
+ * scrollable list
+ * o "False" or "None" means no Ghosting options
+ *
+ */
+ public function setGhosting ($value)
+ {
+ if (strcasecmp($value,'true')==0 || $value===true)
+ $value=TDraggableGhostingOptions::Ghosting;
+ elseif (strcasecmp($value,'false')==0 || $value===false)
+ $value=TDraggableGhostingOptions::None;
+ $this->setViewState('Ghosting', TPropertyValue::ensureEnum($value, 'TDraggableGhostingOptions'), TDraggableGhostingOptions::None);
+ }
+
+ /**
+ * Determine if the element should be constrainted in one direction or not
+ * @return CDraggableConstraint
+ */
+ public function getConstraint()
+ {
+ return $this->getViewState('Constraint', TDraggableConstraint::None);
+ }
+
+ /**
+ * Set wether the element should be constrainted in one direction
+ * @param CDraggableConstraint
+ */
+ public function setConstraint($value)
+ {
+ $this->setViewState('Constraint', TPropertyValue::ensureEnum($value, 'TDraggableConstraint'), TDraggableConstraint::None);
+ }
+
+ /**
+ * Registers clientscripts
+ *
+ * This method overrides the parent implementation and is invoked before render.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+
+ $cs=$this->getPage()->getClientScript();
+ if ($this->getGhosting()==TDraggableGhostingOptions::SuperGhosting)
+ $cs->registerPradoScript('dragdropextra');
+ else
+ $cs->registerPradoScript('dragdrop');
+ $writer->addAttribute('id',$this->getClientID());
+ $options=TJavascript::encode($this->getPostBackOptions());
+ $class=$this->getClientClassName();
+ $code="new {$class}('{$this->getClientId()}', {$options}) ";
+ $cs->registerEndScript(sprintf('%08X', crc32($code)), $code);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName ()
+ {
+ return 'Draggable';
+ }
+
+ /**
+ * Gets the post back options for this textbox.
+ * @return array
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+
+ if (($handle=$this->getHandle())!== null) $options['handle']=$handle;
+ if (($revert=$this->getRevert())===TDraggableRevertOptions::None)
+ $options['revert']=false;
+ elseif ($revert==TDraggableRevertOptions::Revert)
+ $options['revert']=true;
+ else
+ $options['revert']=strtolower($revert);
+ if (($constraint=$this->getConstraint())!==TDraggableConstraint::None) $options['constraint']=strtolower($constraint);
+ switch ($this->getGhosting())
+ {
+ case TDraggableGhostingOptions::SuperGhosting:
+ $options['superghosting']=true;
+ break;
+ case TDraggableGhostingOptions::Ghosting:
+ $options['ghosting']=true;
+ break;
+ }
+
+ return $options;
+ }
+
+}
+
+/**
+ * @author Christophe BOULAIN (Christophe.Boulain@gmail.com)
+ * @copyright Copyright &copy; 2008, PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+class TDraggableConstraint extends TEnumerable
+{
+ const None='None';
+ const Horizontal='Horizontal';
+ const Vertical='Vertical';
+}
+
+/**
+ * @author Christophe BOULAIN (Christophe.Boulain@gmail.com)
+ * @copyright Copyright &copy; 2008, PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+class TDraggableGhostingOptions extends TEnumerable
+{
+ const None='None';
+ const Ghosting='Ghosting';
+ const SuperGhosting='SuperGhosting';
+}
+
+/**
+ * @author Christophe BOULAIN (Christophe.Boulain@gmail.com)
+ * @copyright Copyright &copy; 2008, PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+class TDraggableRevertOptions extends TEnumerable
+{
+ const None='None';
+ const Revert='Revert';
+ const Failure='Failure';
+}
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TDropContainer.php b/lib/prado/framework/Web/UI/ActiveControls/TDropContainer.php
new file mode 100755
index 0000000..49eb0db
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TDropContainer.php
@@ -0,0 +1,317 @@
+<?php
+/**
+ * TDropContainer class file
+ *
+ * @author Christophe BOULAIN (Christophe.Boulain@gmail.com)
+ * @copyright Copyright &copy; 2008, PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+/**
+ * Load active panel.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActivePanel');
+
+
+/**
+ * TDropContainer is a panel where TDraggable controls can be dropped.
+ * When a TDraggable component is dropped into a TDropContainer, the {@link OnDrop OnDrop} event is raised.
+ * The {@link TDropContainerEventParameter} param will contain the dropped control.
+ *
+ * Properties :
+ *
+ * <b>{@link setAcceptCssClass AcceptCssClass}</b> : a coma delimited classname of elements that the drop container can accept.
+ * <b>{@link setHoverCssClass HoverCssClass}</b>: CSS classname of the container when a draggable element hovers over the container.
+ *
+ * Events:
+ *
+ * <b>{@link OnDrop OnDrop}</b> : raised when a TDraggable control is dropped. The dropped control id is encapsulated in the event parameter,
+ * as well as mouse coordinates and key modifiers status
+ *
+ *
+ * @author Christophe BOULAIN (Christophe.Boulain@gmail.com)
+ * @copyright Copyright &copy; 2008, PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+class TDropContainer extends TPanel implements IActiveControl, ICallbackEventHandler
+{
+ private $_container=null;
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveControl standard active control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Gets the Css class name that this container can accept.
+ * @return string
+ */
+ public function getAcceptCssClass()
+ {
+ return $this->getViewState('Accepts', '');
+ }
+
+ /**
+ * Sets the Css class name that this container can accept.
+ * @param string comma delimited css class names.
+ */
+ public function setAcceptCssClass($value)
+ {
+ $this->setViewState('Accepts', TPropertyValue::ensureArray($value), '');
+ }
+
+ /**
+ * Sets the Css class name used when a draggble element is hovering
+ * over this container.
+ * @param string css class name during draggable hover.
+ */
+ public function setHoverCssClass($value)
+ {
+ $this->setViewState('HoverClass', $value, '');
+ }
+
+ /**
+ * Gets the Css class name used when a draggble element is hovering
+ * over this container.
+ * @return string css class name during draggable hover.
+ */
+ public function getHoverCssClass()
+ {
+ return $this->getViewState('HoverClass', '');
+ }
+
+
+ /**
+ * Raises callback event. This method is required bu {@link ICallbackEventHandler}
+ * interface.
+ * It raises the {@link onDrop OnDrop} event, then, the {@link onCallback OnCallback} event
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the parameter associated with the callback event
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->onDrop($param->getCallbackParameter());
+ $this->onCallback($param);
+ }
+
+ /**
+ * Raises the onDrop event.
+ * The drop parameters are encapsulated into a {@link TDropContainerEventParameter}
+ *
+ * @param object $dropControlId
+ */
+ public function onDrop ($dropParams)
+ {
+ $this->raiseEvent('OnDrop', $this, new TDropContainerEventParameter ($dropParams));
+
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Gets the post back options for this textbox.
+ * @return array
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+
+ $options['accept'] = $this->getAcceptCssClass();
+ $options['hoverclass'] = $this->getHoverCssClass();
+ return $options;
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.DropContainer';
+ }
+
+ /**
+ * Registers clientscripts
+ *
+ * This method overrides the parent implementation and is invoked before render.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+
+ $this->getPage()->getClientScript()->registerPradoScript('dragdrop');
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * Creates child control
+ * Override parent implementation to create a container which will contain all
+ * child controls. This container will be a TActivePanel, in order to allow user
+ * to update its content on callback.
+ */
+ public function createChildControls ()
+ {
+ if ($this->_container===null)
+ {
+ $this->_container=Prado::CreateComponent('System.Web.UI.ActiveControls.TActivePanel');
+ $this->_container->setId($this->getId(false).'_content');
+ parent::getControls()->add($this->_container);
+ }
+ }
+
+ /**
+ * Override parent implementation to return the container control collection.
+ *
+ * @return TControlCollection
+ */
+ public function getControls()
+ {
+ $this->ensureChildControls();
+ return $this->_container->getControls();
+ }
+
+ /**
+ * Renders and replaces the panel's content on the client-side.
+ * When render() is called before the OnPreRender event, such as when render()
+ * is called during a callback event handler, the rendering
+ * is defered until OnPreRender event is raised.
+ * @param THtmlWriter html writer
+ */
+ public function render ($writer)
+ {
+ if($this->getHasPreRendered())
+ {
+ parent::render($writer);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->replaceContent($this->_container,$writer);
+ }
+ else
+ {
+ $this->getPage()->getAdapter()->registerControlToRender($this->_container,$writer);
+ }
+ }
+
+}
+
+/**
+ * TDropContainerEventParameter class
+ *
+ * TDropContainerEventParameter encapsulate the parameter
+ * data for <b>OnDrop</b> event of TDropContainer components
+ *
+ * @author Christophe BOULAIN (Christophe.Boulain@ceram.fr)
+ * @copyright Copyright &copy; 2008, PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+class TDropContainerEventParameter extends TEventParameter
+{
+ private $_dragElementId;
+ private $_screenX;
+ private $_screenY;
+ private $_offsetX;
+ private $_offsetY;
+ private $_clientX;
+ private $_clientY;
+ private $_shiftKey;
+ private $_ctrlKey;
+ private $_altKey;
+
+ public function __construct($dropParams)
+ {
+ $this->_dragElementId = $dropParams->DragElementID;
+ $this->_screenX = $dropParams->ScreenX;
+ $this->_screenY = $dropParams->ScreenY;
+ $this->_offsetX = isset($dropParams->OffsetX) ? $dropParams->OffsetX : false;
+ $this->_offsetY = isset($dropParams->OffsetY) ? $dropParams->OffsetY : false;
+ $this->_clientX = $dropParams->ClientX;
+ $this->_clientY = $dropParams->ClientY;
+ $this->_shiftKey = TPropertyValue::ensureBoolean($dropParams->ShiftKey);
+ $this->_ctrlKey = TPropertyValue::ensureBoolean($dropParams->CtrlKey);
+ $this->_altKey = TPropertyValue::ensureBoolean($dropParams->AltKey);
+ }
+
+ public function getDragElementId() { return $this->_dragElementId; }
+ public function getScreenX() { return $this->_screenX; }
+ public function getScreenY() { return $this->_screenY; }
+ public function getOffsetX() { return $this->_offsetX; }
+ public function geOffsetY() { return $this->_offsetY; }
+ public function getClientX() { return $this->_clientX; }
+ public function getClientY() { return $this->_clientY; }
+ public function getShiftKey() { return $this->_shiftKey; }
+ public function getCtrlKey() { return $this->_ctrlKey; }
+ public function getAltKey() { return $this->_altKey; }
+
+ /**
+ * GetDroppedControl
+ *
+ * Compatibility method to get the dropped control
+ * @return TControl dropped control, or null if not found
+ */
+ public function getDroppedControl ()
+ {
+ $control=null;
+ $service=prado::getApplication()->getService();
+ if ($service instanceof TPageService)
+ {
+ // Find the control
+ // Warning, this will not work if you have a '_' in your control Id !
+ $dropControlId=str_replace(TControl::CLIENT_ID_SEPARATOR,TControl::ID_SEPARATOR,$this->_dragElementId);
+ $control=$service->getRequestedPage()->findControl($dropControlId);
+ }
+ return $control;
+ }
+}
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php b/lib/prado/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php
new file mode 100644
index 0000000..d990e09
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * TEventTriggeredCallback class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback');
+
+/**
+ * TEventTriggeredCallback Class
+ *
+ * Triggers a new callback request when a particular {@link setEventName EventName}
+ * on a control with ID given by {@link setControlID ControlID} is raised.
+ *
+ * The default action of the event on the client-side can be prevented when
+ * {@link setPreventDefaultAction PreventDefaultAction} is set to true.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TEventTriggeredCallback extends TTriggeredCallback
+{
+ /**
+ * @return string The client-side event name the trigger listens to.
+ */
+ public function getEventName()
+ {
+ return $this->getViewState('EventName', '');
+ }
+
+ /**
+ * Sets the client-side event name that fires the callback request.
+ * @param string The client-side event name the trigger listens to.
+ */
+ public function setEventName($value)
+ {
+ $this->setViewState('EventName', $value, '');
+ }
+
+ /**
+ * @param boolean true to prevent/stop default event action.
+ */
+ public function setPreventDefaultAction($value)
+ {
+ $this->setViewState('StopEvent', TPropertyValue::ensureBoolean($value), false);
+ }
+
+ /**
+ * @return boolean true to prevent/stop default event action.
+ */
+ public function getPreventDefaultAction()
+ {
+ return $this->getViewState('StopEvent', false);
+ }
+
+ /**
+ * @return array list of timer options for client-side.
+ */
+ protected function getTriggerOptions()
+ {
+ $options = parent::getTriggerOptions();
+ $name = preg_replace('/^on/', '', $this->getEventName());
+ $options['EventName'] = strtolower($name);
+ $options['StopEvent'] = $this->getPreventDefaultAction();
+ return $options;
+ }
+
+ /**
+ * Registers the javascript code for initializing the active control.
+ * @param THtmlWriter the renderer.
+ */
+ public function render($writer)
+ {
+ parent::render($writer);
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getTriggerOptions());
+ }
+
+ /**
+ * @return string corresponding javascript class name for TEventTriggeredCallback.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TEventTriggeredCallback';
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TInPlaceTextBox.php b/lib/prado/framework/Web/UI/ActiveControls/TInPlaceTextBox.php
new file mode 100644
index 0000000..d267729
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TInPlaceTextBox.php
@@ -0,0 +1,288 @@
+<?php
+/**
+ * TInPlaceTextBox class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
+
+/**
+ * TInPlaceTextBox Class
+ * *
+ * TInPlaceTextBox is a component rendered as a label and allows its
+ * contents to be edited by changing the label to a textbox when
+ * the label is clicked or when another control or html element with
+ * ID given by {@link setEditTriggerControlID EditTriggerControlID} is clicked.
+ *
+ * If the {@link OnLoadingText} event is handled, a callback request is
+ * made when the label is clicked, while the request is being made the
+ * textbox is disabled from editing. The {@link OnLoadingText} event allows
+ * you to update the content of the textbox before the client is allowed
+ * to edit the content. After the callback request returns successfully,
+ * the textbox is enabled and the contents is then allowed to be edited.
+ *
+ * Once the textbox loses focus, if {@link setAutoPostBack AutoPostBack}
+ * is true and the textbox content has changed, a callback request is made and
+ * the {@link OnTextChanged} event is raised like that of the TActiveTextBox.
+ * During the request, the textbox is disabled.
+ *
+ * After the callback request returns sucessfully, the textbox is enabled.
+ * If the {@link setAutoHideTextBox AutoHideTextBox} property is true, then
+ * the textbox will be hidden and the label is then shown.
+ *
+ * Since 3.1.2, you can set the {@link setReadOnly ReadOnly} property to make
+ * the control not editable. This property can be also changed on callback
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TInPlaceTextBox extends TActiveTextBox
+{
+ /**
+ * Sets the auto post back to true by default.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAutoPostBack(true);
+ }
+
+ /**
+ * @param boolean true to hide the textbox after losing focus.
+ */
+ public function setAutoHideTextBox($value)
+ {
+ $this->setViewState('AutoHide', TPropertyValue::ensureBoolean($value), true);
+ }
+
+ /**
+ * @return boolean true will hide the textbox after losing focus.
+ */
+ public function getAutoHideTextBox()
+ {
+ return $this->getViewState('AutoHide', true);
+ }
+
+ /**
+ * @param boolean true to display the edit textbox
+ */
+ public function setDisplayTextBox($value)
+ {
+ $value = TPropertyValue::ensureBoolean($value);
+ $this->setViewState('DisplayTextBox', $value,false);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->callClientFunction('setDisplayTextBox',$value);
+ }
+
+ /**
+ * @return boolean true to display the edit textbox
+ */
+ public function getDisplayTextBox()
+ {
+ return $this->getViewState('DisplayTextBox', false);
+ }
+
+ /**
+ * Calls the client-side static method for this control class.
+ * @param string static method name
+ * @param mixed method parmaeter
+ */
+ protected function callClientFunction($func,$value)
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $code = $this->getClientClassName().'.'.$func;
+ $client->callClientFunction($code,array($this,$value));
+ }
+
+ /**
+ * @param string ID of the control that can trigger to edit the textbox
+ */
+ public function setEditTriggerControlID($value)
+ {
+ $this->setViewState('EditTriggerControlID', $value);
+ }
+
+ /**
+ * @return string ID of the control that can trigger to edit the textbox
+ */
+ public function getEditTriggerControlID()
+ {
+ return $this->getViewState('EditTriggerControlID');
+ }
+
+ /**
+ * @return string edit trigger control client ID.
+ */
+ protected function getExternalControlID()
+ {
+ $extID = $this->getEditTriggerControlID();
+ if($extID===null) return '';
+ if(($control = $this->findControl($extID))!==null)
+ return $control->getClientID();
+ return $extID;
+ }
+
+ /**
+ * On callback response, the inner HTMl of the label and the
+ * value of the textbox is updated
+ * @param string the text value of the label
+ */
+ public function setText($value)
+ {
+ TTextBox::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $client->update($this->getLabelClientID(), $value);
+ $client->setValue($this, $value);
+ }
+ }
+
+ /**
+ * Update ClientSide Readonly property
+ * @param boolean value
+ * @since 3.1.2
+ */
+ public function setReadOnly ($value)
+ {
+ $value=TPropertyValue::ensureBoolean($value);
+ TTextBox::setReadOnly($value);
+ if ($this->getActiveControl()->canUpdateClientSide())
+ {
+ $this->callClientFunction('setReadOnly', $value);
+ }
+ }
+
+ /**
+ * @return string tag name of the label.
+ */
+ protected function getTagName()
+ {
+ return 'span';
+ }
+
+ /**
+ * Renders the body content of the label.
+ * @param THtmlWriter the writer for rendering
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())==='')
+ parent::renderContents($writer);
+ else
+ $writer->write($text);
+ }
+
+ /**
+ * @return string label client ID
+ */
+ protected function getLabelClientID()
+ {
+ return $this->getClientID().'__label';
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $action = $param->getCallbackParameter();
+ if(is_array($action) && $action[0] === '__InlineEditor_loadExternalText__')
+ {
+ $parameter = new TCallbackEventParameter($this->getResponse(), $action[1]);
+ $this->onLoadingText($parameter);
+ }
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * @return array callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ $options = parent::getPostBackOptions();
+ $options['ID'] = $this->getLabelClientID();
+ $options['TextBoxID'] = $this->getClientID();
+ $options['ExternalControl'] = $this->getExternalControlID();
+ $options['AutoHide'] = $this->getAutoHideTextBox() == false ? '' : true;
+ $options['AutoPostBack'] = $this->getAutoPostBack() == false ? '' : true;
+ $options['Columns'] = $this->getColumns();
+ if($this->getTextMode()==='MultiLine')
+ {
+ $options['Rows'] = $this->getRows();
+ $options['Wrap'] = $this->getWrap()== false ? '' : true;
+ }
+ else
+ {
+ $length = $this->getMaxLength();
+ $options['MaxLength'] = $length > 0 ? $length : '';
+ }
+
+ if($this->hasEventHandler('OnLoadingText'))
+ $options['LoadTextOnEdit'] = true;
+
+ $options['ReadOnly']=$this->getReadOnly();
+ return $options;
+ }
+
+ /**
+ * Raised when editing the content is requsted to be loaded from the
+ * server side.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onLoadingText($param)
+ {
+ $this->raiseEvent('OnLoadingText',$this,$param);
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TInPlaceTextBox
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TInPlaceTextBox';
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ //calls the TWebControl to avoid rendering other attribute normally render for a textbox.
+ TWebControl::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getLabelClientID());
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * Registers CSS and JS.
+ * This method is invoked right before the control rendering, if the control is visible.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->registerClientScript();
+ }
+
+ /**
+ * Registers the relevant JavaScript.
+ */
+ protected function registerClientScript()
+ {
+ $cs=$this->getPage()->getClientScript();
+ $cs->registerPradoScript('inlineeditor');
+ }
+}
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TTimeTriggeredCallback.php b/lib/prado/framework/Web/UI/ActiveControls/TTimeTriggeredCallback.php
new file mode 100644
index 0000000..b643de4
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TTimeTriggeredCallback.php
@@ -0,0 +1,126 @@
+<?php
+/**
+ * TTimeTriggeredCallback class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active callback control.
+ */
+Prado::using('System.Web.UI.ActiveControls.TCallback');
+
+/**
+ * TTimeTriggeredCallback class.
+ *
+ * TTimeTriggeredCallback sends callback request every {@link setInterval Interval} seconds.
+ * Upon each callback request, the {@link onCallback OnCallback} event is raised.
+ *
+ * The timer can be started by calling {@link startTimer()} and stopped using
+ * {@link stopTimer()}. The timer can be automatically started when
+ * {@link setStartTimerOnLoad StartTimerOnLoad} is true.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TTimeTriggeredCallback extends TCallback
+{
+ /**
+ * @return float seconds between callback requests. Default is 1 second.
+ */
+ public function getInterval()
+ {
+ return $this->getViewState('Interval', 1);
+ }
+
+ /**
+ * @param float seconds between callback requests, must be a positive number, default is 1 second.
+ */
+ public function setInterval($value)
+ {
+ $interval = TPropertyValue::ensureFloat($value);
+ if($interval <= 0)
+ throw new TConfigurationException('callback_interval_be_positive', $this->getID());
+ $this->setViewState('Interval', $interval, 1);
+ if ($this->getActiveControl()->canUpdateClientSide()){
+ $client = $this->getPage()->getCallbackClient();
+ $client->callClientFunction('Prado.WebUI.TTimeTriggeredCallback.setTimerInterval', array($this, $interval));
+ }
+ }
+
+ /**
+ * Registers the javascript code to start the timer.
+ */
+ public function startTimer()
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $client->callClientFunction('Prado.WebUI.TTimeTriggeredCallback.start', array($this));
+ }
+
+ /**
+ * Registers the javascript code to stop the timer.
+ */
+ public function stopTimer()
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $client->callClientFunction('Prado.WebUI.TTimeTriggeredCallback.stop', array($this));
+ }
+
+ /**
+ * @param boolean true to start the timer when page loads.
+ */
+ public function setStartTimerOnLoad($value)
+ {
+ $this->setViewState('StartTimerOnLoad',
+ TPropertyValue::ensureBoolean($value), false);
+ }
+
+ /**
+ * @return boolean true to start the timer when page loads.
+ */
+ public function getStartTimerOnLoad()
+ {
+ return $this->getViewState('StartTimerOnLoad', false);
+ }
+
+ /**
+ * @return array list of timer options for client-side.
+ */
+ protected function getTriggerOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget']= $this->getUniqueID();
+ $options['Interval'] = $this->getInterval();
+ return $options;
+ }
+
+ /**
+ * Registers the javascript code for initializing the active control.
+ * @param THtmlWriter the renderer.
+ */
+ public function render($writer)
+ {
+ parent::render($writer);
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getTriggerOptions());
+ if($this->getStartTimerOnLoad()){
+ $id = $this->getClientID();
+ $code = "Prado.WebUI.TTimeTriggeredCallback.start('{$id}');";
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerEndScript("{$id}:start", $code);
+ }
+ }
+
+ /**
+ * @return string corresponding javascript class name for TTimeTriggeredCallback.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TTimeTriggeredCallback';
+ }
+}
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TTriggeredCallback.php b/lib/prado/framework/Web/UI/ActiveControls/TTriggeredCallback.php
new file mode 100644
index 0000000..7675bc8
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TTriggeredCallback.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * TTriggeredCallback class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TCallback');
+/**
+ * TTriggeredCallback abstract Class
+ *
+ * Base class for triggered callback controls. The {@link setControlID ControlID}
+ * property sets the control ID to observe the trigger.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+abstract class TTriggeredCallback extends TCallback
+{
+ /**
+ * @return string The ID of the server control the trigger is bounded to.
+ */
+ public function getControlID()
+ {
+ return $this->getViewState('ControlID', '');
+ }
+
+ /**
+ * @param string The ID of the server control the trigger is bounded to.
+ */
+ public function setControlID($value)
+ {
+ $this->setViewState('ControlID', $value, '');
+ }
+
+ /**
+ * @return string target control client ID or html element ID if
+ * control is not found in hierarchy.
+ */
+ protected function getTargetControl()
+ {
+ $id = $this->getControlID();
+ if(($control=$this->findControl($id)) instanceof TControl)
+ return $control->getClientID();
+ if($id==='')
+ {
+ throw new TConfigurationException(
+ 'ttriggeredcallback_invalid_controlid', get_class($this));
+ }
+ return $id;
+ }
+
+ /**
+ * @return array list of trigger callback options.
+ */
+ protected function getTriggerOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['ControlID'] = $this->getTargetControl();
+ return $options;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php b/lib/prado/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php
new file mode 100644
index 0000000..87a7d60
--- /dev/null
+++ b/lib/prado/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * TValueTriggeredCallback class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback');
+
+/**
+ * TValueTriggeredCallback Class
+ *
+ * Observes the value with {@link setPropertyName PropertyName} of a
+ * control with {@link setControlID ControlID}. Changes to the observed
+ * property value will trigger a new callback request. The property value is checked
+ * for changes every{@link setInterval Interval} seconds.
+ *
+ * A {@link setDecayRate DecayRate} can be set to increase the polling
+ * interval linearly if no changes are observed. Once a change is
+ * observed, the polling interval is reset to the original value.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TValueTriggeredCallback extends TTriggeredCallback
+{
+ /**
+ * @return string The control property name to observe value changes.
+ */
+ public function getPropertyName()
+ {
+ return $this->getViewState('PropertyName', '');
+ }
+
+ /**
+ * Sets the control property name to observe value changes that fires the callback request.
+ * @param string The control property name to observe value changes.
+ */
+ public function setPropertyName($value)
+ {
+ $this->setViewState('PropertyName', $value, '');
+ }
+
+ /**
+ * Sets the polling interval in seconds to observe property changes.
+ * Default is 1 second.
+ * @param float polling interval in seconds.
+ */
+ public function setInterval($value)
+ {
+ $this->setViewState('Interval', TPropertyValue::ensureFloat($value), 1);
+ }
+
+ /**
+ * @return float polling interval, 1 second default.
+ */
+ public function getInterval()
+ {
+ return $this->getViewState('Interval', 1);
+ }
+
+ /**
+ * Gets the decay rate between callbacks. Default is 0;
+ * @return float decay rate between callbacks.
+ */
+ public function getDecayRate()
+ {
+ return $this->getViewState('Decay', 0);
+ }
+
+ /**
+ * Sets the decay rate between callback. Default is 0;
+ * @param float decay rate between callbacks.
+ */
+ public function setDecayRate($value)
+ {
+ $decay = TPropertyValue::ensureFloat($value);
+ if($decay < 0)
+ throw new TConfigurationException('callback_decay_be_not_negative', $this->getID());
+ $this->setViewState('Decay', $decay);
+ }
+
+ /**
+ * @return array list of timer options for client-side.
+ */
+ protected function getTriggerOptions()
+ {
+ $options = parent::getTriggerOptions();
+ $options['PropertyName'] = $this->getPropertyName();
+ $options['Interval'] = $this->getInterval();
+ $options['Decay'] = $this->getDecayRate();
+ return $options;
+ }
+
+ /**
+ * Registers the javascript code for initializing the active control.
+ * @param THtmlWriter the renderer.
+ */
+ public function render($writer)
+ {
+ parent::render($writer);
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getTriggerOptions());
+ }
+
+ /**
+ * @return string corresponding javascript class name for TEventTriggeredCallback.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TValueTriggeredCallback';
+ }
+}
diff --git a/lib/prado/framework/Web/UI/JuiControls/TJuiAutoComplete.php b/lib/prado/framework/Web/UI/JuiControls/TJuiAutoComplete.php
new file mode 100644
index 0000000..be6b1b4
--- /dev/null
+++ b/lib/prado/framework/Web/UI/JuiControls/TJuiAutoComplete.php
@@ -0,0 +1,495 @@
+<?php
+/**
+ * TJuiAutoComplete class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active text box.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
+Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
+Prado::using('System.Web.UI.JuiControls.TJuiControlAdapter');
+/**
+ * TJuiAutoComplete class.
+ *
+ * TJuiAutoComplete is a textbox that provides a list of suggestion on
+ * the current partial word typed in the textbox. The suggestions are
+ * requested using callbacks, and raises the {@link onSuggestion OnSuggestion}
+ * event. The events of the TActiveText (from which TJuiAutoComplete is extended from)
+ * and {@link onSuggestion OnSuggestion} are mutually exculsive. That is,
+ * if {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback}
+ * events are raise, then {@link onSuggestion OnSuggestion} will not be raise, and
+ * vice versa.
+ *
+ * The list of suggestions should be set in the {@link onSuggestion OnSuggestion}
+ * event handler. The partial word to match the suggestion is in the
+ * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
+ * property. The datasource of the TJuiAutoComplete must be set using {@link setDataSource}
+ * method. This sets the datasource for the suggestions repeater, available through
+ * the {@link getSuggestions Suggestions} property. Header, footer templates and
+ * other properties of the repeater can be access via the {@link getSuggestions Suggestions}
+ * property and its sub-properties.
+ *
+ * The {@link setTextCssClass TextCssClass} property if set is used to find
+ * the element within the Suggestions.ItemTemplate and Suggestions.AlternatingItemTemplate
+ * that contains the actual text for the suggestion selected. That is,
+ * only text inside elements with CSS class name equal to {@link setTextCssClass TextCssClass}
+ * will be used as suggestions.
+ *
+ * To return the list of suggestions back to the browser, supply a non-empty data source
+ * and call databind. For example,
+ * <code>
+ * function autocomplete_suggestion($sender, $param)
+ * {
+ * $token = $param->getToken(); //the partial word to match
+ * $sender->setDataSource($this->getSuggestionsFor($token)); //set suggestions
+ * $sender->dataBind();
+ * }
+ * </code>
+ *
+ * The suggestion will be rendered when the {@link dataBind()} method is called
+ * <strong>during a callback request</strong>.
+ *
+ * When an suggestion is selected, that is, when the use has clicked, pressed
+ * the "Enter" key, or pressed the "Tab" key, the {@link onSuggestionSelected OnSuggestionSelected}
+ * event is raised. The
+ * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
+ * property contains the index of the selected suggestion.
+ *
+ * TJuiAutoComplete allows multiple suggestions within one textbox with each
+ * word or phrase separated by any characters specified in the
+ * {@link setSeparator Separator} property. The {@link setFrequency Frequency}
+ * and {@link setMinChars MinChars} properties sets the delay and minimum number
+ * of characters typed, respectively, before requesting for sugggestions.
+ *
+ * Use {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback} events
+ * to handle post backs due to {@link setAutoPostBack AutoPostBack}.
+ *
+ * In the {@link getSuggestions Suggestions} TRepater item template, all HTML text elements
+ * are considered as text for the suggestion. Text within HTML elements with CSS class name
+ * "informal" are ignored as text for suggestions.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TJuiAutoComplete extends TActiveTextBox implements INamingContainer, IJuiOptions
+{
+ /**
+ * @var ITemplate template for repeater items
+ */
+ private $_repeater=null;
+ /**
+ * @var TPanel result panel holding the suggestion items.
+ */
+ private $_resultPanel=null;
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TJuiControlAdapter($this));
+ }
+
+ /**
+ * @return string the name of the jQueryUI widget method
+ */
+ public function getWidget()
+ {
+ return 'autocomplete';
+ }
+
+ /**
+ * @return string the clientid of the jQueryUI widget element
+ */
+ public function getWidgetID()
+ {
+ return $this->getClientID();
+ }
+
+ /**
+ * Object containing defined javascript options
+ * @return TJuiControlOptions
+ */
+ public function getOptions()
+ {
+ if (($options=$this->getViewState('JuiOptions'))===null)
+ {
+ $options=new TJuiControlOptions($this);
+ $this->setViewState('JuiOptions', $options);
+ }
+ return $options;
+ }
+
+ /**
+ * Array containing valid javascript options
+ * @return array()
+ */
+ public function getValidOptions()
+ {
+ return array('appendTo', 'autoFocus', 'delay', 'disabled', 'minLength', 'position', 'source');
+ }
+
+ /**
+ * Array containing valid javascript events
+ * @return array()
+ */
+ public function getValidEvents()
+ {
+ return array();
+ }
+
+ /**
+ * @param string Css class name of the element to use for suggestion.
+ */
+ public function setTextCssClass($value)
+ {
+ $this->setViewState('TextCssClass', $value);
+ }
+
+ /**
+ * @return string Css class name of the element to use for suggestion.
+ */
+ public function getTextCssClass()
+ {
+ return $this->getViewState('TextCssClass');
+ }
+
+
+ /**
+ * @return string word or token separators (delimiters).
+ */
+ public function getSeparator()
+ {
+ return $this->getViewState('separator', '');
+ }
+
+ /**
+ * @param string word or token separators (delimiters).
+ */
+ public function setSeparator($value)
+ {
+ $this->setViewState('separator', TPropertyValue::ensureString($value), '');
+ }
+
+ /**
+ * @return float maximum delay (in seconds) before requesting a suggestion.
+ */
+ public function getFrequency()
+ {
+ return $this->getViewState('frequency', 0.4);
+ }
+
+ /**
+ * @param float maximum delay (in seconds) before requesting a suggestion.
+ * Default is 0.4.
+ */
+ public function setFrequency($value)
+ {
+ $this->setViewState('frequency', TPropertyValue::ensureFloat($value), 0.4);
+ }
+
+ /**
+ * @return integer minimum number of characters before requesting a suggestion.
+ */
+ public function getMinChars()
+ {
+ return $this->getViewState('minChars','');
+ }
+
+ /**
+ * @param integer minimum number of characters before requesting a suggestion.
+ * Default is 1
+ */
+ public function setMinChars($value)
+ {
+ $this->setViewState('minChars', TPropertyValue::ensureInteger($value), 1);
+ }
+
+ /**
+ * Raises the callback event. This method is overrides the parent implementation.
+ * If {@link setAutoPostBack AutoPostBack} is enabled it will raise
+ * {@link onTextChanged OnTextChanged} event event and then the
+ * {@link onCallback OnCallback} event. The {@link onSuggest OnSuggest} event is
+ * raise if the request is to find sugggestions, the {@link onTextChanged OnTextChanged}
+ * and {@link onCallback OnCallback} events are <b>NOT</b> raised.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $token = $param->getCallbackParameter();
+ if(is_array($token) && count($token) == 2)
+ {
+ if($token[1] === '__TJuiAutoComplete_onSuggest__')
+ {
+ $parameter = new TJuiAutoCompleteEventParameter($this->getResponse(), $token[0]);
+ $this->onSuggest($parameter);
+ }
+ else if($token[1] === '__TJuiAutoComplete_onSuggestionSelected__')
+ {
+ $parameter = new TJuiAutoCompleteEventParameter($this->getResponse(), null, $token[0]);
+ $this->onSuggestionSelected($parameter);
+ }
+ }
+ else if($this->getAutoPostBack())
+ parent::raiseCallbackEvent($param);
+ }
+
+ /**
+ * This method is invoked when an autocomplete suggestion is requested.
+ * The method raises 'OnSuggest' event. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onSuggest($param)
+ {
+ $this->raiseEvent('OnSuggest', $this, $param);
+ }
+
+ /**
+ * This method is invoked when an autocomplete suggestion is selected.
+ * The method raises 'OnSuggestionSelected' event. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onSuggestionSelected($param)
+ {
+ $this->raiseEvent('OnSuggestionSelected', $this, $param);
+ }
+
+ /**
+ * @param array data source for suggestions.
+ */
+ public function setDataSource($data)
+ {
+ $this->getSuggestions()->setDataSource($data);
+ }
+
+ /**
+ * Overrides parent implementation. Callback {@link renderSuggestions()} when
+ * page's IsCallback property is true.
+ */
+ public function dataBind()
+ {
+ parent::dataBind();
+ if($this->getPage()->getIsCallback())
+ $this->renderSuggestions($this->getResponse()->createHtmlWriter());
+ }
+
+ /**
+ * @return TPanel suggestion results panel.
+ */
+ public function getResultPanel()
+ {
+ if($this->_resultPanel===null)
+ $this->_resultPanel = $this->createResultPanel();
+ return $this->_resultPanel;
+ }
+
+ /**
+ * @return TPanel new instance of result panel. Default uses TPanel.
+ */
+ protected function createResultPanel()
+ {
+ $panel = Prado::createComponent('System.Web.UI.WebControls.TPanel');
+ $this->getControls()->add($panel);
+ $panel->setID('result');
+ return $panel;
+ }
+
+ /**
+ * @return TRepeater suggestion list repeater
+ */
+ public function getSuggestions()
+ {
+ if($this->_repeater===null)
+ $this->_repeater = $this->createRepeater();
+ return $this->_repeater;
+ }
+
+ /**
+ * @return TRepeater new instance of TRepater to render the list of suggestions.
+ */
+ protected function createRepeater()
+ {
+ $repeater = Prado::createComponent('System.Web.UI.WebControls.TRepeater');
+ $repeater->setItemTemplate(new TTemplate('<%# $this->Data %>',null));
+ $this->getControls()->add($repeater);
+ return $repeater;
+ }
+
+ /**
+ * Renders the end tag and registers javascript effects library.
+ */
+ public function renderEndTag($writer)
+ {
+ parent::renderEndTag($writer);
+ $this->renderResultPanel($writer);
+ }
+
+ /**
+ * Renders the result panel.
+ * @param THtmlWriter the renderer.
+ */
+ protected function renderResultPanel($writer)
+ {
+ $this->getResultPanel()->render($writer);
+ }
+
+ /**
+ * Renders the suggestions during a callback respones.
+ * @param THtmlWriter the renderer.
+ */
+ public function renderCallback($writer)
+ {
+ $this->renderSuggestions($writer);
+ }
+
+ /**
+ * Renders the suggestions repeater.
+ * @param THtmlWriter the renderer.
+ */
+ public function renderSuggestions($writer)
+ {
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $data=array();
+ $items=$this->getSuggestions()->getItems();
+ $writer = new TTextWriter;
+ for($i=0; $i<$items->Count; $i++)
+ {
+ $items->itemAt($i)->render($writer);
+ $item=$writer->flush();
+ $data[]=array( 'id' => $i, 'label' => $item);
+ }
+
+ $this->getResponse()->getAdapter()->setResponseData($data);
+ }
+ }
+
+ /**
+ * @return array list of callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ $options = $this->getOptions()->toArray();
+
+ if(strlen($separator = $this->getSeparator()))
+ $options['Separators'] = $separator;
+
+ if($this->getAutoPostBack())
+ {
+ $options = array_merge($options,parent::getPostBackOptions());
+ $options['AutoPostBack'] = true;
+ }
+ if(strlen($textCssClass = $this->getTextCssClass()))
+ $options['textCssClass'] = $textCssClass;
+ $options['minLength'] = $this->getMinChars();
+ $options['delay'] = $this->getFrequency()*1000.0;
+ $options['appendTo'] = '#'.$this->getResultPanel()->getClientID();
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ return $options;
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TActiveButton.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TJuiAutoComplete';
+ }
+}
+
+/**
+ * TAutCompleteEventParameter contains the {@link getToken Token} requested by
+ * the user for a partial match of the suggestions.
+ *
+ * The {@link getSelectedIndex SelectedIndex} is a zero-based index of the
+ * suggestion selected by the user, -1 if not suggestion is selected.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TJuiAutoCompleteEventParameter extends TCallbackEventParameter
+{
+ private $_selectedIndex=-1;
+
+ /**
+ * Creates a new TCallbackEventParameter.
+ */
+ public function __construct($response, $parameter, $index=-1)
+ {
+ parent::__construct($response, $parameter);
+ $this->_selectedIndex=$index;
+ }
+
+ /**
+ * @return int selected suggestion zero-based index, -1 if not selected.
+ */
+ public function getSelectedIndex()
+ {
+ return $this->_selectedIndex;
+ }
+
+ /**
+ * @return string token for matching a list of suggestions.
+ */
+ public function getToken()
+ {
+ return $this->getCallbackParameter();
+ }
+}
+
+/**
+ * TJuiAutoCompleteTemplate class.
+ *
+ * TJuiAutoCompleteTemplate is the default template for TJuiAutoCompleteTemplate
+ * item template.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TJuiAutoCompleteTemplate extends TComponent implements ITemplate
+{
+ private $_template;
+
+ public function __construct($template)
+ {
+ $this->_template = $template;
+ }
+ /**
+ * Instantiates the template.
+ * It creates a {@link TDataList} control.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $parent->getControls()->add($this->_template);
+ }
+}
diff --git a/lib/prado/framework/Web/UI/JuiControls/TJuiControlAdapter.php b/lib/prado/framework/Web/UI/JuiControls/TJuiControlAdapter.php
new file mode 100644
index 0000000..7feac4f
--- /dev/null
+++ b/lib/prado/framework/Web/UI/JuiControls/TJuiControlAdapter.php
@@ -0,0 +1,203 @@
+<?php
+/**
+ * TJuiControlAdapter class file.
+ *
+ * @author Fabio Bas <ctrlaltca@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2013-2015 PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.JuiControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+Prado::using('System.Web.UI.JuiControls.TJuiControlOptions');
+
+/**
+ * TJuiControlAdapter class
+ *
+ * TJuiControlAdapter is the base adapter class for controls that are
+ * derived from a jQuery-ui widget. It exposes convenience methods to
+ * publish jQuery-UI javascript and css assets.
+ *
+ * @author Fabio Bas <ctrlaltca@gmail.com>
+ * @package System.Web.UI.JuiControls
+ * @since 3.3
+ */
+class TJuiControlAdapter extends TActiveControlAdapter
+{
+ const SCRIPT_PATH = 'jquery';
+ const CSS_PATH = 'css';
+ const BASE_CSS_FILENAME ='jquery-ui.css';
+
+ /**
+ * Replace default StateTracker with {@link TJuiCallbackPageStateTracker} for
+ * options tracking in ViewState.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $this->setStateTracker('TJuiCallbackPageStateTracker');
+ }
+
+ /**
+ * @param string set the jquery-ui style
+ */
+ public function setJuiBaseStyle($value)
+ {
+ $this->getControl()->setViewState('JuiBaseStyle', $value, 'base');
+ }
+
+ /**
+ * @return string current jquery-ui style
+ */
+ public function getJuiBaseStyle()
+ {
+ return $this->getControl()->getViewState('JuiBaseStyle', 'base');
+ }
+
+ /**
+ * Inject jquery script and styles before render
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->getPage()->getClientScript()->registerPradoScript('jqueryui');
+ $this->publishJuiStyle(self::BASE_CSS_FILENAME);
+ }
+
+ /**
+ * @param string jQuery asset file in the self::SCRIPT_PATH directory.
+ * @return string jQuery asset url.
+ */
+ protected function getAssetUrl($file='')
+ {
+ $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
+ return $base.'/'.self::SCRIPT_PATH.'/'.$file;
+ }
+
+ /**
+ * Publish the jQuery-ui style Css asset file.
+ * @param file name
+ * @return string Css file url.
+ */
+ public function publishJuiStyle($file)
+ {
+ $url = $this->getAssetUrl(self::CSS_PATH.'/'.$this->getJuiBaseStyle().'/'.$file);
+ $cs = $this->getPage()->getClientScript();
+ if(!$cs->isStyleSheetFileRegistered($url))
+ $cs->registerStyleSheetFile($url, $url);
+ return $url;
+ }
+
+ /**
+ * Calls the parent implementation first and sets the parent control for the
+ * {@link TJuiControlOptions} again afterwards since it was not serialized in viewstate.
+ */
+ public function loadState() {
+ parent::loadState();
+ $this->getControl()->getOptions()->setControl($this->getControl());
+ }
+
+}
+
+/**
+ * TJuiEventParameter class
+ *
+ * TJuiEventParameter encapsulate the parameters for callback
+ * events of TJui* components.
+ * Any parameter representing a control is identified by its
+ * clientside ID.
+ * TJuiEventParameter contains a {@link getControl} helper method
+ * that retrieves an existing PRADO control on che current page from its
+ * clientside ID as returned by the callback.
+ * For example, if the parameter contains a "draggable" item (as returned in
+ * {@link TJuiDroppable}::OnDrop event), the relative PRADO control can be
+ * retrieved using:
+ * <code>
+ * $draggable = $param->getControl($param->getCallbackParameter()->draggable);
+ * </code>
+ *
+ * A shortcut __get() method is implemented, too:
+ * <code>
+ * $draggable = $param->DraggableControl;
+ * </code>
+ *
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.JuiControls
+ */
+class TJuiEventParameter extends TCallbackEventParameter
+{
+ /**
+ * getControl
+ *
+ * Compatibility method to get a control from its clientside id
+ * @return TControl control, or null if not found
+ */
+ public function getControl($id)
+ {
+ $control=null;
+ $service=prado::getApplication()->getService();
+ if ($service instanceof TPageService)
+ {
+ // Find the control
+ // Warning, this will not work if you have a '_' in your control Id !
+ $controlId=str_replace(TControl::CLIENT_ID_SEPARATOR,TControl::ID_SEPARATOR,$id);
+ $control=$service->getRequestedPage()->findControl($controlId);
+ }
+ return $control;
+ }
+
+ /**
+ * Gets a control instance named after a returned control id.
+ * Example: if a $param->draggable control id is returned from clientside,
+ * calling $param->DraggableControl will return the control instance
+ * @return mixed control or null if not set.
+ */
+ public function __get($name)
+ {
+ $pos=strpos($name, 'Control',1);
+ $name=strtolower(substr($name, 0, $pos));
+
+ $cp=$this->getCallbackParameter();
+ if(!isset($cp->$name) || $cp->$name=='')
+ return null;
+
+ return $this->getControl($cp->$name);
+ }
+}
+
+/**
+ * TJuiCallbackPageStateTracker class.
+ *
+ * Tracking changes to the page state during callback, including {@link TJuiControlOptions}.
+ *
+ * @author LANDWEHR Computer und Software GmbH
+ * @package System.Web.UI.JuiControls
+ * @since 3.3
+ */
+class TJuiCallbackPageStateTracker extends TCallbackPageStateTracker {
+
+ /**
+ * Add the {@link TJuiControlOptions} to the states to track.
+ */
+ protected function addStatesToTrack()
+ {
+ parent::addStatesToTrack();
+ $states = $this->getStatesToTrack();
+ $states['JuiOptions'] = array('TMapCollectionDiff', array($this, 'updateJuiOptions'));
+ }
+
+ /**
+ * Updates the options of the jQueryUI widget.
+ * @param array list of widget options to change.
+ */
+ protected function updateJuiOptions($options)
+ {
+ foreach ($options as $key => $value) $options[$key] = $key . ': ' . (is_string($value) ? "'{$value}'" : TPropertyValue::ensureString($value));
+ $code = "jQuery('#{$this->_control->getWidgetID()}').{$this->_control->getWidget()}('option', { " . implode(', ', $options) . " });";
+ $this->_control->getPage()->getClientScript()->registerEndScript(sprintf('%08X', crc32($code)), $code);
+ }
+
+} \ No newline at end of file
diff --git a/lib/prado/framework/Web/UI/JuiControls/TJuiControlOptions.php b/lib/prado/framework/Web/UI/JuiControls/TJuiControlOptions.php
new file mode 100644
index 0000000..64cf710
--- /dev/null
+++ b/lib/prado/framework/Web/UI/JuiControls/TJuiControlOptions.php
@@ -0,0 +1,181 @@
+<?php
+/**
+ * TJuiControlOptions class file.
+ *
+ * @author Fabio Bas <ctrlaltca@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2013-2015 PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.JuiControls
+ */
+
+/**
+ * IJuiOptions interface
+ *
+ * IJuiOptions is the interface that must be implemented by controls using
+ * {@link TJuiControlOptions}.
+ *
+ * @author Fabio Bas <ctrlaltca@gmail.com>
+ * @package System.Web.UI.JuiControls
+ * @since 3.3
+ */
+interface IJuiOptions
+{
+ public function getWidget();
+ public function getWidgetID();
+ public function getOptions();
+ public function getValidOptions();
+ public function getValidEvents();
+}
+
+/**
+ * TJuiControlOptions interface
+ *
+ * TJuiControlOptions is an helper class that can collect a list of options
+ * for a control. The control must implement {@link IJuiOptions}.
+ * The options are validated againg an array of valid options provided by the control itself.
+ * Since component properties are case insensitive, the array of valid options is used
+ * to ensure the option name has the correct case.
+ * The options array can then get retrieved using {@link toArray} and applied to the jQuery-ui widget.
+ * In addition to the options, this class will render the needed javascript to raise a callback
+ * for any event for which an handler is defined in the control.
+ *
+ * @author Fabio Bas <ctrlaltca@gmail.com>
+ * @package System.Web.UI.JuiControls
+ * @since 3.3
+ */
+class TJuiControlOptions
+{
+ /**
+ * @var TMap map of javascript options.
+ */
+ private $_options;
+ /**
+ * @var TControl parent control.
+ */
+ private $_control;
+
+ /**
+ * Constructor. Set the parent control owning these options.
+ * @param TControl parent control
+ */
+ public function __construct($control)
+ {
+ $this->setControl($control);
+ }
+
+ /**
+ * Sets the parent control.
+ * @param TControl $control
+ * @throws THttpException
+ */
+ public function setControl($control)
+ {
+ if(!$control instanceof IJuiOptions)
+ throw new THttpException(500,'juioptions_control_invalid',$control->ID);
+ $this->_control=$control;
+ }
+
+ /**
+ * Sets a named options with a value. Options are used to store and retrive
+ * named values for the javascript control.
+ * @param string option name.
+ * @param mixed option value.
+ * @throws THttpException
+ */
+ public function __set($name,$value)
+ {
+ if($this->_options===null)
+ $this->_options=array();
+
+ foreach($this->_control->getValidOptions() as $option)
+ {
+ if(0 == strcasecmp($name, $option))
+ {
+ $low = strtolower($value);
+ if($low === 'null')
+ {
+ $this->_options[$option] = null;
+ } elseif($low === 'true') {
+ $this->_options[$option] = true;
+ } elseif($low === 'false') {
+ $this->_options[$option] = false;
+ } elseif(is_numeric($value)) {
+ // trick to get float or integer automatically when needed
+ $this->_options[$option] = $value + 0;
+ } elseif(substr($low,0,8)=='function') {
+ $this->_options[$option] = new TJavaScriptLiteral($value);
+ } else {
+ $this->_options[$option] = $value;
+ }
+ return;
+ }
+ }
+
+ throw new THttpException(500,'juioptions_option_invalid',$this->_control->ID, $name);
+ }
+
+ /**
+ * Gets an option named value. Options are used to store and retrive
+ * named values for the base active controls.
+ * @param string option name.
+ * @return mixed options value or null if not set.
+ */
+ public function __get($name)
+ {
+ if($this->_options===null)
+ $this->_options=array();
+
+ foreach($this->_control->getValidOptions() as $option)
+ {
+ if(0 == strcasecmp($name, $option) && isset($this->_options[$option]))
+ {
+ return $this->_options[$option];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Only serialize the options itself, not the corresponding parent control.
+ * @return mixed array with the names of all variables of that object that should be serialized.
+ */
+ public function __sleep() {
+ return array('_options');
+ }
+
+ /**
+ * @return Array of active control options
+ */
+ public function toArray()
+ {
+ $ret= ($this->_options===null) ? array() : $this->_options;
+
+ foreach($this->_control->getValidEvents() as $event)
+ if($this->_control->hasEventHandler('on'.$event))
+ $ret[$event]=new TJavaScriptLiteral("function( event, ui ) { Prado.JuiCallback(".TJavascript::encode($this->_control->getUniqueID()).", ".TJavascript::encode($event).", event, ui, this); }");
+
+ return $ret;
+ }
+
+ /**
+ * Raise the specific callback event handler of the target control.
+ * @param mixed callback parameters
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $callbackParam=$param->CallbackParameter;
+ if(isset($callbackParam->event))
+ {
+ $eventName = 'On'.ucfirst($callbackParam->event);
+ if($this->_control->hasEventHandler($eventName))
+ {
+ $this->_control->$eventName( new TJuiEventParameter(
+ $this->_control->getResponse(),
+ isset($callbackParam->ui) ? $callbackParam->ui : null)
+ );
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/prado/framework/Web/UI/JuiControls/TJuiDatePicker.php b/lib/prado/framework/Web/UI/JuiControls/TJuiDatePicker.php
new file mode 100644
index 0000000..487714d
--- /dev/null
+++ b/lib/prado/framework/Web/UI/JuiControls/TJuiDatePicker.php
@@ -0,0 +1,287 @@
+<?php
+/**
+ * TJuiDatePicker class file.
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @link http://www.landwehr-software.de/
+ * @copyright Copyright &copy; 2015 LANDWEHR Computer und Software GmbH
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active text box.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
+Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
+Prado::using('System.Web.UI.JuiControls.TJuiControlAdapter');
+/**
+ * TJuiDatePicker class.
+ *
+ * TJuiDatePicker is a textbox that provides a date input. When the text box receives focus,
+ * a calendar will pop up and users can pick up from it a date that will be automatically
+ * entered into the text box. TJuiDatePicker is an extension to {@link TActivePanel} based on
+ * jQuery-UI's {@link http://jqueryui.com/dialog/ Dialog} widget.
+ *
+ * <code>
+ * <com:TJuiDatePicker ID="datepicker1" />
+ * </code>
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.JuiControls
+ * @since 3.3
+ */
+class TJuiDatePicker extends TActiveTextBox implements INamingContainer, IJuiOptions
+{
+
+ /**
+ * The static variable is used to determine if this is the first instance of TJuiDatePicker. If true,
+ * it will register an additional clientscript to set the language specific global default settings.
+ * @var boolean true, if this is the first instance of TJuiDatePicker, false otherwise
+ */
+ private static $_first = true;
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TJuiControlAdapter($this));
+ }
+
+ /**
+ * @return string the name of the jQueryUI widget method
+ */
+ public function getWidget()
+ {
+ return 'datepicker';
+ }
+
+ /**
+ * @return string the clientid of the jQueryUI widget element
+ */
+ public function getWidgetID()
+ {
+ return $this->getClientID();
+ }
+
+ /**
+ * Object containing defined javascript options
+ * @return TJuiControlOptions
+ */
+ public function getOptions()
+ {
+ if (($options=$this->getViewState('JuiOptions'))===null)
+ {
+ $options=new TJuiControlOptions($this);
+ $this->setViewState('JuiOptions', $options);
+ }
+ return $options;
+ }
+
+ /**
+ * Array containing valid javascript options
+ * @return array()
+ */
+ public function getValidOptions()
+ {
+ return array('altField', 'altFormat', 'appendText', 'autoSize', 'buttonImage', 'buttonImageOnly', 'buttonText', 'calculateWeek',
+ 'changeMonth', 'changeYear', 'closeText', 'constrainInput', 'currentText', 'dateFormat', 'dayNames', 'dayNamesMin',
+ 'dayNamesShort', 'defaultDate', 'duration', 'firstDay', 'gotoCurrent', 'hideIfNoPrevNext', 'isRTL', 'maxDate',
+ 'minDate', 'monthNames', 'monthNamesShort', 'navigationAsDateFormat', 'nextText', 'numberOfMonths', 'prevText',
+ 'selectOtherMonths', 'shortYearCutoff', 'showAnim', 'showButtonPanel', 'showCurrentAtPos', 'showMonthAfterYear',
+ 'showOn', 'showOptions', 'showOtherMonths', 'showWeek', 'stepMonths', 'weekHeader', 'yearRange', 'yearSuffix',
+ 'beforeShow', 'beforeShowDay', 'onChangeMonthYear', 'onClose', 'onSelect');
+ }
+
+ /**
+ * Array containing valid javascript events
+ * @return array()
+ */
+ public function getValidEvents()
+ {
+ return array();
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control. Also registers language specific global
+ * settings for the first used date picker.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $cs=$this->getPage()->getClientScript();
+ if(self::$_first)
+ {
+ $code="jQuery(document).ready(function(){jQuery.datepicker.setDefaults(jQuery.datepicker.regional['{$this->getCurrentCulture()}']);});";
+ $cs->registerEndScript(sprintf('%08X', crc32($code)), $code);
+ self::$_first=false;
+ }
+ parent::addAttributesToRender($writer);
+ $options=TJavascript::encode($this->getOptions()->toArray());
+ $code="jQuery('#".$this->getWidgetID()."').".$this->getWidget()."(".$options.");";
+ $cs->registerEndScript(sprintf('%08X', crc32($code)), $code);
+ }
+
+ /**
+ * @return TTextBoxMode the behavior mode of the underlying {@link TTextBox} component.
+ * Fixed to TTextBoxMode::SingleLine for the TJuiDatePicker.
+ */
+ public function getTextMode()
+ {
+ return TTextBoxMode::SingleLine;
+ }
+
+ /**
+ * Setting the behavior mode of the underlying TTextBox component is NOT supported.
+ * @param TTextBoxMode the text mode
+ * @throws TNotSupportedException not supported, fixed to TTextBoxMode::SingleLine.
+ */
+ public function setTextMode($value)
+ {
+ throw new TNotSupportedException('juidatepicker_settextmode_unsupported');
+ }
+
+ /**
+ * Gets the current culture.
+ * @return string current culture, e.g. en_AU.
+ */
+ public function getCulture()
+ {
+ return $this->getViewState('Culture', '');
+ }
+
+ /**
+ * Sets the culture/language for the date picker.
+ * @param string a culture string, e.g. en_AU.
+ */
+ public function setCulture($value)
+ {
+ $this->setViewState('Culture', $value, '');
+ }
+
+ /**
+ * @return string the current culture, falls back to application if culture is not set.
+ */
+ protected function getCurrentCulture()
+ {
+ $app = $this->getApplication()->getGlobalization(false);
+ return $this->getCulture() == '' ?
+ ($app ? $app->getCulture() : 'en') : $this->getCulture();
+ }
+
+ /**
+ * @return string the format of the date string
+ */
+ public function getDateFormat()
+ {
+ return $this->getViewState('DateFormat','dd-MM-yyyy');
+ }
+
+ /**
+ * Sets the format of the date string.
+ * @param string the format of the date string
+ */
+ public function setDateFormat($value)
+ {
+ $this->setViewState('DateFormat',$value,'dd-MM-yyyy');
+ }
+
+ /**
+ * Returns the timestamp selected by the user.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getTimeStamp()}.
+ * @return integer the timestamp of the TDatePicker control.
+ * @see getTimeStamp
+ * @since 3.1.2
+ */
+ public function getData()
+ {
+ return $this->getTimeStamp();
+ }
+
+ /**
+ * Sets the timestamp represented by this control.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setTimeStamp()}.
+ * @param integer the timestamp of the TDatePicker control.
+ * @see setTimeStamp
+ * @since 3.1.2
+ */
+ public function setData($value)
+ {
+ $this->setTimeStamp($value);
+ }
+
+ /**
+ * @return string the date string.
+ */
+ public function getDate()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * @param string date string
+ */
+ public function setDate($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * @return integer current selected date from the date picker as timestamp, NULL if timestamp is not set previously.
+ */
+ public function getTimeStamp()
+ {
+ if(trim($this->getText())==='')
+ return null;
+ else
+ return $this->getTimeStampFromText();
+ }
+
+ /**
+ * Sets the date for the date picker using timestamp.
+ * @param float time stamp for the date picker
+ */
+ public function setTimeStamp($value)
+ {
+ if($value===null || (is_string($value) && trim($value)===''))
+ $this->setText('');
+ else
+ {
+ $date = TPropertyValue::ensureFloat($value);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$this->getDateFormat());
+ $this->setText($formatter->format($date));
+ }
+ }
+
+ /**
+ * Gets the date from the text input using TSimpleDateFormatter
+ * @return integer current selected date timestamp
+ */
+ protected function getTimeStampFromText()
+ {
+ $pattern = $this->getDateFormat();
+ $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$pattern);
+ return $formatter->parse($this->getText());
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return integer the interger timestamp if valid, otherwise the original text.
+ */
+ public function getValidationPropertyValue()
+ {
+ if(($text = $this->getText()) === '')
+ return '';
+ $date = $this->getTimeStamp();
+ return $date == null ? $text : $date;
+ }
+
+} \ No newline at end of file
diff --git a/lib/prado/framework/Web/UI/JuiControls/TJuiDialog.php b/lib/prado/framework/Web/UI/JuiControls/TJuiDialog.php
new file mode 100644
index 0000000..e02157d
--- /dev/null
+++ b/lib/prado/framework/Web/UI/JuiControls/TJuiDialog.php
@@ -0,0 +1,283 @@
+<?php
+/**
+ * TJuiDialog class file.
+ *
+ * @author David Otto <ottodavid[at]gmx[dot]net>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2013-2015 PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.JuiControls
+ */
+
+Prado::using('System.Web.UI.JuiControls.TJuiControlAdapter');
+Prado::using('System.Web.UI.ActiveControls.TActivePanel');
+
+/**
+ * TJuiDialog class.
+ *
+ * TJuiDialog is an extension to {@link TActivePanel} based on jQuery-UI's
+ * {@link http://jqueryui.com/dialog/ Dialog} widget.
+ *
+ *
+ * <code>
+ * <com:TJuiDialog
+ * ID="dlg1"
+ * >
+ * contents
+ * </com:TJuiDialog>
+ * </code>
+ *
+ * @author David Otto <ottodavid[at]gmx[dot]net>
+ * @package System.Web.UI.JuiControls
+ * @since 3.3
+ */
+class TJuiDialog extends TActivePanel implements IJuiOptions, ICallbackEventHandler
+{
+ protected $_options;
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TJuiControlAdapter($this));
+ }
+
+ /**
+ * @return string the name of the jQueryUI widget method
+ */
+ public function getWidget()
+ {
+ return 'dialog';
+ }
+
+ /**
+ * @return string the clientid of the jQueryUI widget element
+ */
+ public function getWidgetID()
+ {
+ return $this->getClientID();
+ }
+
+ /**
+ * Object containing defined javascript options
+ * @return TJuiControlOptions
+ */
+ public function getOptions()
+ {
+ if (($options=$this->getViewState('JuiOptions'))===null)
+ {
+ $options=new TJuiControlOptions($this);
+ $this->setViewState('JuiOptions', $options);
+ }
+ return $options;
+ }
+
+ /**
+ * Array containing valid javascript options
+ * @return array()
+ */
+ public function getValidOptions()
+ {
+ return array('appendTo', 'autoOpen', 'buttons', 'closeOnEscape', 'closeText', 'dialogClass', 'draggable', 'height', 'hide', 'minHeight', 'minWidth', 'maxHeight', 'maxWidth', 'modal', 'position', 'resizeable', 'show', 'title', 'width');
+ }
+
+ /**
+ * Array containing valid javascript events
+ * @return array()
+ */
+ public function getValidEvents()
+ {
+ return array('beforeClose', 'close', 'create', 'drag', 'dragStart', 'dragStop', 'focus', 'open', 'resize', 'resizeStart', 'resizeStop');
+ }
+
+ /**
+ * @return array list of callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ $options = $this->getOptions()->toArray();
+
+ foreach($this->getControls() as $control)
+ if($control instanceof TJuiDialogButton)
+ $options['buttons'][] = $control->getPostBackOptions();
+
+ return $options;
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+
+ $writer->addAttribute('id',$this->getClientID());
+ $options=TJavascript::encode($this->getPostBackOptions());
+ $cs=$this->getPage()->getClientScript();
+ $code="jQuery('#".$this->getWidgetID()."').".$this->getWidget()."(".$options.");";
+ $cs->registerEndScript(sprintf('%08X', crc32($code)), $code);
+ }
+
+ /**
+ * Raises callback event. This method is required by the {@link ICallbackEventHandler}
+ * interface.
+ * @param TCallbackEventParameter the parameter associated with the callback event
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->getOptions()->raiseCallbackEvent($param);
+ }
+
+ /**
+ * Raises the OnCreate event
+ * @param object $params event parameters
+ */
+ public function onOpen ($params)
+ {
+ $this->raiseEvent('OnOpen', $this, $params);
+ }
+
+ /**
+ * Open this dialog
+ */
+ public function open()
+ {
+ $this->triggerClientMethod('open');
+ }
+
+ /**
+ * Close this dialog
+ */
+ public function close()
+ {
+ $this->triggerClientMethod('close');
+ }
+
+ private function triggerClientMethod($method)
+ {
+ $cs = $this->getPage()->getClientScript();
+ $code = "jQuery('#".$this->getClientId()."').dialog('".$method."');";
+ $cs->registerEndScript(sprintf('%08X', crc32($code)), $code);
+ }
+
+ /**
+ * Rendering as a fieldset is not supported for TJuiDialog.
+ * @param string the legend text. If this value is not empty, the panel will be rendered as a fieldset.
+ * @throws TNotSupportedException not supported for TJuiDialog.
+ */
+ public function setGroupingText($value)
+ {
+ throw new TNotSupportedException('Rendering as a fieldset is not supported for {0}.', get_class($this));
+ }
+
+ /**
+ * Overrides parent implementation to just render the inner contents and avoid replacing the element itself when
+ * updating clientside, because replacing/removing will cause jqueryui to fire destroy on the original dialog extension.
+ * @param THtmlWriter html writer
+ */
+ public function render($writer)
+ {
+ if($this->getHasPreRendered() && $this->getActiveControl()->canUpdateClientSide())
+ {
+ parent::renderContents($writer);
+ $this->getPage()->getCallbackClient()->replaceContent($this, $writer, false);
+ }
+ else
+ parent::render($writer);
+ }
+}
+
+/**
+ * TJuiDialogButton class
+ *
+ * This button must be child of a TJuiDialog. It can be used to bind an callback
+ * to the buttons of the dialog.
+ *
+ * <code>
+ * <com:TJuiDialog> * >
+ * Text
+ * <com:TJuiDialogButton Text="Ok" OnClick="Ok" />
+ *
+ * </com:TJuiDialog>
+ * </code>
+ *
+ * @author David Otto <ottodavid[at]gmx[dot]net>
+ * @package System.Web.UI.JuiControls
+ * @since 3.3
+ */
+class TJuiDialogButton extends TControl implements ICallbackEventHandler, IActiveControl
+{
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * Array containing defined javascript options
+ * @return array
+ */
+ public function getPostBackOptions()
+ {
+ return array(
+ 'text' => $this->getText(),
+ 'click' => new TJavaScriptLiteral("function(){new Prado.Callback('".$this->getUniqueID()."', 'onClick');}"
+ )) ;
+ }
+
+ /**
+ * @return string caption of the button
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * @param string caption of the button
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * Raises the OnClick event
+ * @param object $params event parameters
+ */
+ public function onClick ($params)
+ {
+ $this->raiseEvent('OnClick', $this, $params);
+ }
+
+ /**
+ * Raises callback event.
+ * raises the appropriate event(s) (e.g. OnClick)
+ * @param TCallbackEventParameter the parameter associated with the callback event
+ */
+ public function raiseCallbackEvent($param)
+ {
+ if($param->CallbackParameter === 'onClick')
+ $this->onClick($param);
+ }
+
+} \ No newline at end of file
diff --git a/lib/prado/framework/Web/UI/JuiControls/TJuiDraggable.php b/lib/prado/framework/Web/UI/JuiControls/TJuiDraggable.php
new file mode 100644
index 0000000..f32e257
--- /dev/null
+++ b/lib/prado/framework/Web/UI/JuiControls/TJuiDraggable.php
@@ -0,0 +1,169 @@
+<?php
+/**
+ * TJuiDraggable class file.
+ *
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2013-2015 PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.JuiControls
+ */
+
+Prado::using('System.Web.UI.JuiControls.TJuiControlAdapter');
+Prado::using('System.Web.UI.ActiveControls.TActivePanel');
+
+/**
+ * TJuiDraggable class.
+ *
+ * TJuiDraggable is an extension to {@link TActivePanel} based on jQuery-UI's
+ * {@link http://jqueryui.com/draggable/ Draggable} interaction.
+ * The panel can be moved using the mouse, and eventually dropped over a
+ * {@link TJuiDroppable}.
+ *
+ * <code>
+ * <com:TJuiDraggable
+ * ID="drag1"
+ * Style="border: 1px solid red; width:100px;height:100px"
+ * Options.Axis="y"
+ * OnStop="drag1_dragged"
+ * >
+ * drag me
+ * </com:TJuiDraggable>
+ * </code>
+ *
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @package System.Web.UI.JuiControls
+ * @since 3.3
+ */
+class TJuiDraggable extends TActivePanel implements IJuiOptions, ICallbackEventHandler
+{
+ protected $_options;
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TJuiControlAdapter($this));
+ }
+
+ /**
+ * @return string the name of the jQueryUI widget method
+ */
+ public function getWidget()
+ {
+ return 'draggable';
+ }
+
+ /**
+ * @return string the clientid of the jQueryUI widget element
+ */
+ public function getWidgetID()
+ {
+ return $this->getClientID();
+ }
+
+ /**
+ * Object containing defined javascript options
+ * @return TJuiControlOptions
+ */
+ public function getOptions()
+ {
+ if (($options=$this->getViewState('JuiOptions'))===null)
+ {
+ $options=new TJuiControlOptions($this);
+ $this->setViewState('JuiOptions', $options);
+ }
+ return $options;
+ }
+
+ /**
+ * Array containing valid javascript options
+ * @return array()
+ */
+ public function getValidOptions()
+ {
+ return array('addClasses', 'appendTo', 'axis', 'cancel', 'connectToSortable', 'containment', 'cursor', 'cursorAt', 'delay', 'disabled', 'distance', 'grid', 'handle', 'helper', 'iframeFix', 'opacity', 'refreshPositions', 'revert', 'revertDuration', 'scope', 'scroll', 'scrollSensitivity', 'scrollSpeed', 'snap', 'snapMode', 'snapTolerance', 'stack', 'zIndex');
+ }
+
+ /**
+ * Array containing valid javascript events
+ * @return array()
+ */
+ public function getValidEvents()
+ {
+ return array('create', 'drag', 'start', 'stop');
+ }
+
+ /**
+ * @return array list of callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ return $this->getOptions()->toArray();
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+
+ $writer->addAttribute('id',$this->getClientID());
+ $options=TJavascript::encode($this->getPostBackOptions());
+ $cs=$this->getPage()->getClientScript();
+ $code="jQuery('#".$this->getWidgetID()."').".$this->getWidget()."(".$options.");";
+ $cs->registerEndScript(sprintf('%08X', crc32($code)), $code);
+ }
+
+ /**
+ * Raises callback event. This method is required by the {@link ICallbackEventHandler}
+ * interface.
+ * @param TCallbackEventParameter the parameter associated with the callback event
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->getOptions()->raiseCallbackEvent($param);
+ }
+
+ /**
+ * Raises the OnCreate event
+ * @param object $params event parameters
+ */
+ public function onCreate ($params)
+ {
+ $this->raiseEvent('OnCreate', $this, $params);
+ }
+
+ /**
+ * Raises the OnDrag event
+ * @param object $params event parameters
+ */
+ public function onDrag ($params)
+ {
+ $this->raiseEvent('OnDrag', $this, $params);
+ }
+
+ /**
+ * Raises the OnStart event
+ * @param object $params event parameters
+ */
+ public function onStart ($params)
+ {
+ $this->raiseEvent('OnStart', $this, $params);
+ }
+
+ /**
+ * Raises the OnStop event
+ * @param object $params event parameters
+ */
+ public function onStop ($params)
+ {
+ $this->raiseEvent('OnStop', $this, $params);
+ }
+}
diff --git a/lib/prado/framework/Web/UI/JuiControls/TJuiDroppable.php b/lib/prado/framework/Web/UI/JuiControls/TJuiDroppable.php
new file mode 100644
index 0000000..9a61572
--- /dev/null
+++ b/lib/prado/framework/Web/UI/JuiControls/TJuiDroppable.php
@@ -0,0 +1,220 @@
+<?php
+/**
+ * TJuiDroppable class file.
+ *
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2013-2015 PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.JuiControls
+ */
+
+Prado::using('System.Web.UI.JuiControls.TJuiControlAdapter');
+Prado::using('System.Web.UI.ActiveControls.TActivePanel');
+
+/**
+ * TJuiDroppable class.
+ *
+ * TJuiDroppable is an extension to {@link TActivePanel} based on jQuery-UI's
+ * {@link http://jqueryui.com/droppable/ Droppable} interaction.
+ * When a {@link TJuiDraggable} is dropped over a TJuiDroppable panel, the
+ * {@link onDrop OnDrop} event will be triggered. The event hanler will receive
+ * a {@link TJuiEventParameter} object containing a reference to the dropped control
+ * in the <tt>DraggableControl</tt> property.
+ *
+ * <code>
+ * <com:TJuiDraggable
+ * ID="drag1"
+ * Style="border: 1px solid red; width:100px;height:100px;background-color: #fff"
+ * >
+ * drag me
+ * </com:TJuiDraggable>
+ *
+ * <com:TJuiDroppable
+ * ID="drop1"
+ * Style="border: 1px solid blue; width:600px;height:600px; background-color: lime"
+ * OnDrop="drop1_ondrop"
+ * >
+ * drop it over me
+ * </com:TJuiDroppable>
+ * </code>
+ *
+ * <code>
+ * public function drop1_ondrop($sender, $param)
+ * {
+ * $draggable=$param->DraggableControl;
+ * $offset=$param->getCallbackParameter()->offset;
+ * $target=$param->getCallbackParameter()->target->offset;
+ * $top=$offset->top - $target->top;
+ * $left=$offset->left - $target->left;
+ * $this->label1->Text="Dropped ".$draggable->ID." at: <br/>Top=".$top." Left=".$left;
+ * }
+ * </code>
+ *
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @package System.Web.UI.JuiControls
+ * @since 3.3
+ */
+class TJuiDroppable extends TActivePanel implements IJuiOptions, ICallbackEventHandler
+{
+ protected $_options;
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TJuiControlAdapter($this));
+ }
+
+ /**
+ * @return string the name of the jQueryUI widget method
+ */
+ public function getWidget()
+ {
+ return 'droppable';
+ }
+
+ /**
+ * @return string the clientid of the jQueryUI widget element
+ */
+ public function getWidgetID()
+ {
+ return $this->getClientID();
+ }
+
+ /**
+ * Object containing defined javascript options
+ * @return TJuiControlOptions
+ */
+ public function getOptions()
+ {
+ if (($options=$this->getViewState('JuiOptions'))===null)
+ {
+ $options=new TJuiControlOptions($this);
+ $this->setViewState('JuiOptions', $options);
+ }
+ return $options;
+ }
+
+ /**
+ * Array containing valid javascript options
+ * @return array()
+ */
+ public function getValidOptions()
+ {
+ return array('accept', 'activeClass', 'addClasses', 'disabled', 'greedy', 'hoverClass', 'scope', 'tolerance');
+ }
+
+ /**
+ * Array containing valid javascript events
+ * @return array()
+ */
+ public function getValidEvents()
+ {
+ return array('activate', 'create', 'deactivate', 'drop', 'out', 'over');
+ }
+
+ /**
+ * @return array list of callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ return $this->getOptions()->toArray();
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+
+ $writer->addAttribute('id',$this->getClientID());
+ $options=TJavascript::encode($this->getPostBackOptions());
+ $cs=$this->getPage()->getClientScript();
+ $code="jQuery('#".$this->getWidgetID()."').".$this->getWidget()."(".$options.");";
+ $cs->registerEndScript(sprintf('%08X', crc32($code)), $code);
+ }
+
+ /**
+ * Raises callback event. This method is required by the {@link ICallbackEventHandler}
+ * interface.
+ * @param TCallbackEventParameter the parameter associated with the callback event
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->getOptions()->raiseCallbackEvent($param);
+ }
+
+ /**
+ * Raises the OnActivate event
+ * @param object $params event parameters
+ */
+ public function onActivate ($params)
+ {
+ $this->raiseEvent('OnActivate', $this, $params);
+ }
+
+ /**
+ * Raises the OnCreate event
+ * @param object $params event parameters
+ */
+ public function onCreate ($params)
+ {
+ $this->raiseEvent('OnCreate', $this, $params);
+ }
+
+ /**
+ * Raises the OnDeactivate event
+ * @param object $params event parameters
+ */
+ public function onDeactivate ($params)
+ {
+ $this->raiseEvent('OnDeactivate', $this, $params);
+ }
+
+ /**
+ * Raises the OnDrop event
+ * @param object $params event parameters
+ */
+ public function onDrop ($params)
+ {
+ $this->raiseEvent('OnDrop', $this, $params);
+ }
+
+ /**
+ * Raises the OnOut event
+ * @param object $params event parameters
+ */
+ public function OnOut ($params)
+ {
+ $this->raiseEvent('OnOut', $this, $params);
+ }
+
+ /**
+ * Raises the OnOver event
+ * @param object $params event parameters
+ */
+ public function OnOver ($params)
+ {
+ $this->raiseEvent('OnOver', $this, $params);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+}
diff --git a/lib/prado/framework/Web/UI/JuiControls/TJuiProgressbar.php b/lib/prado/framework/Web/UI/JuiControls/TJuiProgressbar.php
new file mode 100644
index 0000000..61e185e
--- /dev/null
+++ b/lib/prado/framework/Web/UI/JuiControls/TJuiProgressbar.php
@@ -0,0 +1,156 @@
+<?php
+/**
+ * TJuiProgressbar class file.
+ *
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2013-2015 PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.JuiControls
+ */
+
+Prado::using('System.Web.UI.JuiControls.TJuiControlAdapter');
+Prado::using('System.Web.UI.ActiveControls.TActivePanel');
+
+/**
+ * TJuiProgressbar class.
+ *
+ * TJuiProgressbar is an extension to {@link TActivePanel} based on jQuery-UI's
+ * {@link http://jqueryui.com/progressbar/ Progressbar} widget.
+ *
+ * <code>
+ * <com:TJuiProgressbar
+ * ID="pbar1"
+ * Options.Max="100"
+ * Options.Value="75"
+ * OnChange="pbar1_changed"
+ * />
+ * </code>
+ *
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @package System.Web.UI.JuiControls
+ * @since 3.3
+ */
+class TJuiProgressbar extends TActivePanel implements IJuiOptions, ICallbackEventHandler
+{
+ protected $_options;
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TJuiControlAdapter($this));
+ }
+
+ /**
+ * @return string the name of the jQueryUI widget method
+ */
+ public function getWidget()
+ {
+ return 'progressbar';
+ }
+
+ /**
+ * @return string the clientid of the jQueryUI widget element
+ */
+ public function getWidgetID()
+ {
+ return $this->getClientID();
+ }
+
+ /**
+ * Object containing defined javascript options
+ * @return TJuiControlOptions
+ */
+ public function getOptions()
+ {
+ if (($options=$this->getViewState('JuiOptions'))===null)
+ {
+ $options=new TJuiControlOptions($this);
+ $this->setViewState('JuiOptions', $options);
+ }
+ return $options;
+ }
+
+ /**
+ * Array containing valid javascript options
+ * @return array()
+ */
+ public function getValidOptions()
+ {
+ return array('disabled', 'max', 'value');
+ }
+
+ /**
+ * Array containing valid javascript events
+ * @return array()
+ */
+ public function getValidEvents()
+ {
+ return array('change', 'complete', 'create');
+ }
+
+ /**
+ * @return array list of callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ return $this->getOptions()->toArray();
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+
+ $writer->addAttribute('id',$this->getClientID());
+ $options=TJavascript::encode($this->getPostBackOptions());
+ $cs=$this->getPage()->getClientScript();
+ $code="jQuery('#".$this->getWidgetID()."').".$this->getWidget()."(".$options.");";
+ $cs->registerEndScript(sprintf('%08X', crc32($code)), $code);
+ }
+
+ /**
+ * Raises callback event. This method is required by the {@link ICallbackEventHandler}
+ * interface.
+ * @param TCallbackEventParameter the parameter associated with the callback event
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->getOptions()->raiseCallbackEvent($param);
+ }
+
+ /**
+ * Raises the OnChange event
+ * @param object $params event parameters
+ */
+ public function onChange($params)
+ {
+ $this->raiseEvent('OnChange', $this, $params);
+ }
+
+ /**
+ * Raises the OnComplete event
+ * @param object $params event parameters
+ */
+ public function onComplete($params)
+ {
+ $this->raiseEvent('OnComplete', $this, $params);
+ }
+
+ /**
+ * Raises the OnCreate event
+ * @param object $params event parameters
+ */
+ public function onCreate($params)
+ {
+ $this->raiseEvent('OnCreate', $this, $params);
+ }
+}
diff --git a/lib/prado/framework/Web/UI/JuiControls/TJuiResizable.php b/lib/prado/framework/Web/UI/JuiControls/TJuiResizable.php
new file mode 100644
index 0000000..c73305f
--- /dev/null
+++ b/lib/prado/framework/Web/UI/JuiControls/TJuiResizable.php
@@ -0,0 +1,172 @@
+<?php
+/**
+ * TJuiResizable class file.
+ *
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2013-2015 PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.JuiControls
+ */
+
+Prado::using('System.Web.UI.JuiControls.TJuiControlAdapter');
+Prado::using('System.Web.UI.ActiveControls.TActivePanel');
+
+/**
+ * TJuiResizable class.
+ *
+ * TJuiResizable is an extension to {@link TActivePanel} based on jQuery-UI's
+ * {@link http://jqueryui.com/resizable/ Resizable} interaction.
+ * A small handle is shown on the bottom right corner of the panel, that permits
+ * the panel to be resized using the mouse.
+ *
+ * <code>
+ * <com:TJuiResizable
+ * ID="resize1"
+ * Style="border: 1px solid green; width:100px;height:100px;background-color: #00dd00"
+ * Options.maxHeight="250"
+ * Options.maxWidth="350"
+ * Options.minHeight="150"
+ * Options.minWidth="200"
+ * >
+ * resize me
+ * </com:TJuiResizable>
+ * </code>
+ *
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @package System.Web.UI.JuiControls
+ * @since 3.3
+ */
+class TJuiResizable extends TActivePanel implements IJuiOptions, ICallbackEventHandler
+{
+ protected $_options;
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TJuiControlAdapter($this));
+ }
+
+ /**
+ * @return string the name of the jQueryUI widget method
+ */
+ public function getWidget()
+ {
+ return 'resizable';
+ }
+
+ /**
+ * @return string the clientid of the jQueryUI widget element
+ */
+ public function getWidgetID()
+ {
+ return $this->getClientID();
+ }
+
+ /**
+ * Object containing defined javascript options
+ * @return TJuiControlOptions
+ */
+ public function getOptions()
+ {
+ if (($options=$this->getViewState('JuiOptions'))===null)
+ {
+ $options=new TJuiControlOptions($this);
+ $this->setViewState('JuiOptions', $options);
+ }
+ return $options;
+ }
+
+ /**
+ * Array containing valid javascript options
+ * @return array()
+ */
+ public function getValidOptions()
+ {
+ return array('alsoResize', 'animate', 'animateDuration', 'animateEasing', 'aspectRatio', 'autoHide', 'cancel', 'containment', 'delay', 'disabled', 'distance', 'ghost', 'grid', 'handles', 'helper', 'maxHeight', 'maxWidth', 'minHeight', 'minWidth');
+ }
+
+ /**
+ * Array containing valid javascript events
+ * @return array()
+ */
+ public function getValidEvents()
+ {
+ return array('create', 'resize', 'start', 'stop');
+ }
+
+ /**
+ * @return array list of callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ $options = $this->getOptions()->toArray();
+ return $options;
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+
+ $writer->addAttribute('id',$this->getClientID());
+ $options=TJavascript::encode($this->getPostBackOptions());
+ $cs=$this->getPage()->getClientScript();
+ $code="jQuery('#".$this->getWidgetID()."').".$this->getWidget()."(".$options.");";
+ $cs->registerEndScript(sprintf('%08X', crc32($code)), $code);
+ }
+
+ /**
+ * Raises callback event. This method is required by the {@link ICallbackEventHandler}
+ * interface.
+ * @param TCallbackEventParameter the parameter associated with the callback event
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->getOptions()->raiseCallbackEvent($param);
+ }
+
+ /**
+ * Raises the OnCreate event
+ * @param object $params event parameters
+ */
+ public function onCreate ($params)
+ {
+ $this->raiseEvent('OnCreate', $this, $params);
+ }
+
+ /**
+ * Raises the OnResize event
+ * @param object $params event parameters
+ */
+ public function onResize ($params)
+ {
+ $this->raiseEvent('OnResize', $this, $params);
+ }
+
+ /**
+ * Raises the OnStart event
+ * @param object $params event parameters
+ */
+ public function onStart ($params)
+ {
+ $this->raiseEvent('OnStart', $this, $params);
+ }
+
+ /**
+ * Raises the OnStop event
+ * @param object $params event parameters
+ */
+ public function onStop ($params)
+ {
+ $this->raiseEvent('OnStop', $this, $params);
+ }
+}
diff --git a/lib/prado/framework/Web/UI/JuiControls/TJuiSelectable.php b/lib/prado/framework/Web/UI/JuiControls/TJuiSelectable.php
new file mode 100644
index 0000000..7fdaaa7
--- /dev/null
+++ b/lib/prado/framework/Web/UI/JuiControls/TJuiSelectable.php
@@ -0,0 +1,280 @@
+<?php
+/**
+ * TJuiSelectable class file.
+ *
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2013-2015 PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.JuiControls
+ */
+
+Prado::using('System.Web.UI.JuiControls.TJuiControlAdapter');
+Prado::using('System.Web.UI.ActiveControls.TActivePanel');
+
+/**
+ * TJuiSelectable class.
+ *
+ * TJuiSelectable is an extension to {@link TActivePanel} based on jQuery-UI's
+ * {@link http://jqueryui.com/selectable/ Selectable} interaction.
+ * TJuiSelectable can be feed a {@link setDataSource DataSource} and will interally
+ * render a {@link TRepeater} that displays items in an unordered list.
+ * Items can be selected by clicking on them, individually or in a group.
+ *
+ * <code>
+ * <style>
+ * .ui-selecting { background: #FECA40; }
+ * .ui-selected { background: #F39814; color: white; }
+ * </style>
+ * <com:TJuiSelectable ID="repeater1" />
+ * </code>
+ *
+ * <code>
+ * $this->repeater1->DataSource=array('home', 'office', 'car', 'boat', 'plane');
+ * $this->repeater1->dataBind();
+ * </code>
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @package System.Web.UI.JuiControls
+ * @since 3.3
+ */
+class TJuiSelectable extends TActivePanel implements IJuiOptions, ICallbackEventHandler
+{
+ protected $_options;
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TJuiControlAdapter($this));
+ }
+
+ /**
+ * @return string the name of the jQueryUI widget method
+ */
+ public function getWidget()
+ {
+ return 'selectable';
+ }
+
+ /**
+ * @return string the clientid of the jQueryUI widget element
+ */
+ public function getWidgetID()
+ {
+ return $this->getClientID() . '_0';
+ }
+
+ /**
+ * Object containing defined javascript options
+ * @return TJuiControlOptions
+ */
+ public function getOptions()
+ {
+ if (($options=$this->getViewState('JuiOptions'))===null)
+ {
+ $options=new TJuiControlOptions($this);
+ $this->setViewState('JuiOptions', $options);
+ }
+ return $options;
+ }
+
+ /**
+ * Array containing valid javascript options
+ * @return array()
+ */
+ public function getValidOptions()
+ {
+ return array('appendTo', 'autoRefresh', 'cancel', 'delay', 'disabled', 'distance', 'filter', 'tolerance');
+ }
+
+ /**
+ * Array containing valid javascript events
+ * @return array()
+ */
+ public function getValidEvents()
+ {
+ return array('create', 'selected', 'selecting', 'start', 'stop', 'unselected', 'unselecting');
+ }
+
+ /**
+ * @return array list of callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ $options = $this->getOptions()->toArray();
+ // overload the "OnStop" event to add information about the current selected items
+ if(isset($options['stop']))
+ {
+ $options['stop']=new TJavaScriptLiteral('function( event, ui ) { ui.index = new Array(); jQuery(\'#'.$this->getClientID().' .ui-selected\').each(function(idx, item){ ui.index.push(item.id) }); Prado.JuiCallback('.TJavascript::encode($this->getUniqueID()).', \'stop\', event, ui, this); }');
+ }
+ return $options;
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ $options=TJavascript::encode($this->getPostBackOptions());
+ $cs=$this->getPage()->getClientScript();
+ $code="jQuery('#".$this->getWidgetID()."').".$this->getWidget()."(".$options.");";
+ $cs->registerEndScript(sprintf('%08X', crc32($code)), $code);
+ }
+
+ /**
+ * Raises callback event. This method is required by the {@link ICallbackEventHandler}
+ * interface.
+ * @param TCallbackEventParameter the parameter associated with the callback event
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->getOptions()->raiseCallbackEvent($param);
+ }
+
+ /**
+ * Raises the OnCreate event
+ * @param object $params event parameters
+ */
+ public function onCreate ($params)
+ {
+ $this->raiseEvent('OnCreate', $this, $params);
+ }
+
+ /**
+ * Raises the OnSelected event
+ * @param object $params event parameters
+ */
+ public function onSelected ($params)
+ {
+ $this->raiseEvent('OnSelected', $this, $params);
+ }
+
+ /**
+ * Raises the OnSelecting event
+ * @param object $params event parameters
+ */
+ public function onSelecting ($params)
+ {
+ $this->raiseEvent('OnSelecting', $this, $params);
+ }
+
+ /**
+ * Raises the OnStart event
+ * @param object $params event parameters
+ */
+ public function onStart ($params)
+ {
+ $this->raiseEvent('OnStart', $this, $params);
+ }
+
+ /**
+ * Raises the OnStop event
+ * @param object $params event parameters
+ */
+ public function onStop ($params)
+ {
+ $this->raiseEvent('OnStop', $this, $params);
+ }
+
+ /**
+ * Raises the OnUnselected event
+ * @param object $params event parameters
+ */
+ public function onUnselected ($params)
+ {
+ $this->raiseEvent('OnUnselected', $this, $params);
+ }
+
+ /**
+ * Raises the OnUnselecting event
+ * @param object $params event parameters
+ */
+ public function onUnselecting ($params)
+ {
+ $this->raiseEvent('OnUnselecting', $this, $params);
+ }
+
+ /**
+ * @var ITemplate template for repeater items
+ */
+ private $_repeater=null;
+
+ /**
+ * @param array data source for Selectables.
+ */
+ public function setDataSource($data)
+ {
+ $this->getSelectables()->setDataSource($data);
+ }
+
+ /**
+ * Overrides parent implementation. Callback {@link renderSelectables()} when
+ * page's IsCallback property is true.
+ */
+ public function dataBind()
+ {
+ parent::dataBind();
+ if($this->getPage()->getIsCallback())
+ $this->renderSelectables($this->getResponse()->createHtmlWriter());
+ }
+
+ /**
+ * @return TRepeater suggestion list repeater
+ */
+ public function getSelectables()
+ {
+ if($this->_repeater===null)
+ $this->_repeater = $this->createRepeater();
+ return $this->_repeater;
+ }
+
+ /**
+ * @return TRepeater new instance of TRepater to render the list of Selectables.
+ */
+ protected function createRepeater()
+ {
+ $repeater = Prado::createComponent('System.Web.UI.WebControls.TRepeater');
+ $repeater->setHeaderTemplate(new TJuiSelectableTemplate('<ul id="'.$this->getWidgetID().'">'));
+ $repeater->setFooterTemplate(new TJuiSelectableTemplate('</ul>'));
+ $repeater->setItemTemplate(new TTemplate('<li id="<%# $this->ItemIndex %>"><%# $this->DataItem %></li>',null));
+ $repeater->setEmptyTemplate(new TJuiSelectableTemplate('<ul></ul>'));
+ $this->getControls()->add($repeater);
+ return $repeater;
+ }
+}
+
+/**
+ * TJuiSelectableTemplate class.
+ *
+ * TJuiSelectableTemplate is the default template for TJuiSelectableTemplate
+ * item template.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TJuiSelectableTemplate extends TComponent implements ITemplate
+{
+ private $_template;
+
+ public function __construct($template)
+ {
+ $this->_template = $template;
+ }
+ /**
+ * Instantiates the template.
+ * It creates a {@link TDataList} control.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $parent->getControls()->add($this->_template);
+ }
+}
diff --git a/lib/prado/framework/Web/UI/JuiControls/TJuiSortable.php b/lib/prado/framework/Web/UI/JuiControls/TJuiSortable.php
new file mode 100644
index 0000000..3fd62f2
--- /dev/null
+++ b/lib/prado/framework/Web/UI/JuiControls/TJuiSortable.php
@@ -0,0 +1,333 @@
+<?php
+/**
+ * TJuiSortable class file.
+ *
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2013-2015 PradoSoft
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.JuiControls
+ */
+
+Prado::using('System.Web.UI.JuiControls.TJuiControlAdapter');
+Prado::using('System.Web.UI.ActiveControls.TActivePanel');
+
+/**
+ * TJuiSortable class.
+ *
+ * TJuiSortable is an extension to {@link TActivePanel} based on jQuery-UI's
+ * {@link http://jqueryui.com/sortable/ Sortable} interaction.
+ * The panel can be feed a {@link setDataSource DataSource} and will interally
+ * render a {@link TRepeater} that displays items in an unordered list.
+ * Items can be sortered dragging and dropping them.
+ *
+ * <code>
+ * <com:TJuiSortable ID="repeater1" />
+ * </code>
+ *
+ * <code>
+ * $this->repeater1->DataSource=array('home', 'office', 'car', 'boat', 'plane');
+ * $this->repeater1->dataBind();
+ * </code>
+ *
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @package System.Web.UI.JuiControls
+ * @since 3.3
+ */
+class TJuiSortable extends TActivePanel implements IJuiOptions, ICallbackEventHandler
+{
+ protected $_options;
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TJuiControlAdapter($this));
+ }
+
+ /**
+ * @return string the name of the jQueryUI widget method
+ */
+ public function getWidget()
+ {
+ return 'sortable';
+ }
+
+ /**
+ * @return string the clientid of the jQueryUI widget element
+ */
+ public function getWidgetID()
+ {
+ return $this->getClientID() . '_0';
+ }
+
+ /**
+ * Object containing defined javascript options
+ * @return TJuiControlOptions
+ */
+ public function getOptions()
+ {
+ if (($options=$this->getViewState('JuiOptions'))===null)
+ {
+ $options=new TJuiControlOptions($this);
+ $this->setViewState('JuiOptions', $options);
+ }
+ return $options;
+ }
+
+ /**
+ * Array containing valid javascript options
+ * @return array()
+ */
+ public function getValidOptions()
+ {
+ return array('appendTo', 'axis', 'cancel', 'connectWith', 'containment', 'cursor', 'cursorAt', 'delay', 'disabled', 'distance', 'dropOnEmpty', 'forceHelperSize', 'forcePlaceholderSize', 'grid', 'handle', 'helper', 'items', 'opacity', 'placeholder', 'revert', 'scroll', 'scrollSensitivity', 'scrollSpeed', 'tolerance', 'zIndex');
+ }
+
+ /**
+ * Array containing valid javascript events
+ * @return array()
+ */
+ public function getValidEvents()
+ {
+ return array('activate', 'beforeStop', 'change', 'create', 'deactivate', 'out', 'over', 'receive', 'remove', 'sort', 'start', 'stop', 'update');
+ }
+
+ /**
+ * @return array list of callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ $options = $this->getOptions()->toArray();
+ // overload some events to add information about the items order
+ foreach($options as $event => $implementation)
+ {
+ if($event=='sort' || $event=='stop')
+ $options[$event]=new TJavaScriptLiteral('function( event, ui ) { ui.index = jQuery(this).sortable(\'toArray\'); Prado.JuiCallback('.TJavascript::encode($this->getUniqueID()).', \''.$event.'\', event, ui, this); }');
+ }
+ return $options;
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ $options=TJavascript::encode($this->getPostBackOptions());
+ $cs=$this->getPage()->getClientScript();
+ $code="jQuery('#".$this->getWidgetID()."').".$this->getWidget()."(".$options.");";
+ $cs->registerEndScript(sprintf('%08X', crc32($code)), $code);
+ }
+
+ /**
+ * Raises callback event. This method is required by the {@link ICallbackEventHandler}
+ * interface.
+ * @param TCallbackEventParameter the parameter associated with the callback event
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->getOptions()->raiseCallbackEvent($param);
+ }
+
+ /**
+ * Raises the OnActivate event
+ * @param object $params event parameters
+ */
+ public function onActivate ($params)
+ {
+ $this->raiseEvent('OnActivate', $this, $params);
+ }
+
+ /**
+ * Raises the OnBeforeStop event
+ * @param object $params event parameters
+ */
+ public function onBeforeStop ($params)
+ {
+ $this->raiseEvent('OnBeforeStop', $this, $params);
+ }
+
+ /**
+ * Raises the OnChange event
+ * @param object $params event parameters
+ */
+ public function onChange ($params)
+ {
+ $this->raiseEvent('OnChange', $this, $params);
+ }
+
+ /**
+ * Raises the OnCreate event
+ * @param object $params event parameters
+ */
+ public function onCreate ($params)
+ {
+ $this->raiseEvent('OnCreate', $this, $params);
+ }
+
+ /**
+ * Raises the OnDeactivate event
+ * @param object $params event parameters
+ */
+ public function onDeactivate ($params)
+ {
+ $this->raiseEvent('OnDeactivate', $this, $params);
+ }
+
+ /**
+ * Raises the OnOut event
+ * @param object $params event parameters
+ */
+ public function onOut ($params)
+ {
+ $this->raiseEvent('OnOut', $this, $params);
+ }
+
+ /**
+ * Raises the OnOver event
+ * @param object $params event parameters
+ */
+ public function onOver ($params)
+ {
+ $this->raiseEvent('OnOver', $this, $params);
+ }
+
+ /**
+ * Raises the OnReceive event
+ * @param object $params event parameters
+ */
+ public function onReceive ($params)
+ {
+ $this->raiseEvent('OnReceive', $this, $params);
+ }
+
+ /**
+ * Raises the OnRemove event
+ * @param object $params event parameters
+ */
+ public function onRemove ($params)
+ {
+ $this->raiseEvent('OnRemove', $this, $params);
+ }
+
+ /**
+ * Raises the OnSort event
+ * @param object $params event parameters
+ */
+ public function onSort ($params)
+ {
+ $this->raiseEvent('OnSort', $this, $params);
+ }
+
+ /**
+ * Raises the OnStart event
+ * @param object $params event parameters
+ */
+ public function onStart ($params)
+ {
+ $this->raiseEvent('OnStart', $this, $params);
+ }
+
+ /**
+ * Raises the OnStop event
+ * @param object $params event parameters
+ */
+ public function OnStop ($params)
+ {
+ $this->raiseEvent('OnStop', $this, $params);
+ }
+
+ /**
+ * Raises the OnUpdate event
+ * @param object $params event parameters
+ */
+ public function onUpdate ($params)
+ {
+ $this->raiseEvent('OnUpdate', $this, $params);
+ }
+
+ /**
+ * @var ITemplate template for repeater items
+ */
+ private $_repeater=null;
+
+ /**
+ * @param array data source for Sortables.
+ */
+ public function setDataSource($data)
+ {
+ $this->getSortables()->setDataSource($data);
+ }
+
+ /**
+ * Overrides parent implementation. Callback {@link renderSortables()} when
+ * page's IsCallback property is true.
+ */
+ public function dataBind()
+ {
+ parent::dataBind();
+ if($this->getPage()->getIsCallback())
+ $this->renderSortables($this->getResponse()->createHtmlWriter());
+ }
+
+ /**
+ * @return TRepeater suggestion list repeater
+ */
+ public function getSortables()
+ {
+ if($this->_repeater===null)
+ $this->_repeater = $this->createRepeater();
+ return $this->_repeater;
+ }
+
+ /**
+ * @return TRepeater new instance of TRepater to render the list of Sortables.
+ */
+ protected function createRepeater()
+ {
+ $repeater = Prado::createComponent('System.Web.UI.WebControls.TRepeater');
+ $repeater->setHeaderTemplate(new TJuiSortableTemplate('<ul id="'.$this->getWidgetID().'">'));
+ $repeater->setFooterTemplate(new TJuiSortableTemplate('</ul>'));
+ $repeater->setItemTemplate(new TTemplate('<li id="<%# $this->ItemIndex %>"><%# $this->Data %></li>',null));
+ $repeater->setEmptyTemplate(new TJuiSortableTemplate('<ul></ul>'));
+ $this->getControls()->add($repeater);
+ return $repeater;
+ }
+}
+
+
+/**
+ * TJuiSortableTemplate class.
+ *
+ * TJuiSortableTemplate is the default template for TJuiSortableTemplate
+ * item template.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TJuiSortableTemplate extends TComponent implements ITemplate
+{
+ private $_template;
+
+ public function __construct($template)
+ {
+ $this->_template = $template;
+ }
+ /**
+ * Instantiates the template.
+ * It creates a {@link TDataList} control.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $parent->getControls()->add($this->_template);
+ }
+}
diff --git a/lib/prado/framework/Web/UI/TCachePageStatePersister.php b/lib/prado/framework/Web/UI/TCachePageStatePersister.php
new file mode 100644
index 0000000..e8419e6
--- /dev/null
+++ b/lib/prado/framework/Web/UI/TCachePageStatePersister.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ * TCachePageStatePersister class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+/**
+ * TCachePageStatePersister class
+ *
+ * TCachePageStatePersister implements a page state persistent method based on cache.
+ * Page state are stored in cache (e.g. memcache, DB cache, etc.), and only a small token
+ * is passed to the client side to identify the state. This greatly reduces the size of
+ * the page state that needs to be transmitted between the server and the client. Of course,
+ * this is at the cost of using server side resource.
+ *
+ * A cache module has to be loaded in order to use TCachePageStatePersister.
+ * By default, TCachePageStatePersister will use the primary cache module.
+ * A non-primary cache module can be used by setting {@link setCacheModuleID CacheModuleID}.
+ * Any cache module, as long as it implements the interface {@link ICache}, may be used.
+ * For example, one can use {@link TDbCache}, {@link TMemCache}, {@link TAPCCache}, etc.
+ *
+ * TCachePageStatePersister uses {@link setCacheTimeout CacheTimeout} to limit the data
+ * that stores in cache.
+ *
+ * Since server resource is often limited, be cautious if you plan to use TCachePageStatePersister
+ * for high-traffic Web pages. You may consider using a small {@link setCacheTimeout CacheTimeout}.
+ *
+ * There are a couple of ways to use TCachePageStatePersister.
+ * One can override the page's {@link TPage::getStatePersister()} method and
+ * create a TCachePageStatePersister instance there.
+ * Or one can configure the pages to use TCachePageStatePersister in page configurations
+ * as follows,
+ * <code>
+ * <pages StatePersisterClass="System.Web.UI.TCachePageStatePersister"
+ * StatePersister.CacheModuleID="mycache"
+ * StatePersister.CacheTimeout="3600" />
+ * </code>
+ * Note in the above, we use StatePersister.CacheModuleID to configure the cache module ID
+ * for the TCachePageStatePersister instance.
+ *
+ * The above configuration will affect the pages under the directory containing
+ * this configuration and all its subdirectories.
+ * To configure individual pages to use TCachePageStatePersister, use
+ * <code>
+ * <pages>
+ * <page id="PageID" StatePersisterClass="System.Web.UI.TCachePageStatePersister" />
+ * </pages>
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.1.1
+ */
+class TCachePageStatePersister extends TComponent implements IPageStatePersister
+{
+ private $_prefix='statepersister';
+ private $_page;
+ private $_cache=null;
+ private $_cacheModuleID='';
+ private $_timeout=1800;
+
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function getPage()
+ {
+ return $this->_page;
+ }
+
+ /**
+ * @param TPage the page that this persister works for.
+ */
+ public function setPage(TPage $page)
+ {
+ $this->_page=$page;
+ }
+
+ /**
+ * @return string the ID of the cache module.
+ */
+ public function getCacheModuleID()
+ {
+ return $this->_cacheModuleID;
+ }
+
+ /**
+ * @param string the ID of the cache module. If not set, the primary cache module will be used.
+ */
+ public function setCacheModuleID($value)
+ {
+ $this->_cacheModuleID=$value;
+ }
+
+ /**
+ * @return ICache the cache module being used for data storage
+ */
+ public function getCache()
+ {
+ if($this->_cache===null)
+ {
+ if($this->_cacheModuleID!=='')
+ $cache=Prado::getApplication()->getModule($this->_cacheModuleID);
+ else
+ $cache=Prado::getApplication()->getCache();
+ if($cache===null || !($cache instanceof ICache))
+ {
+ if($this->_cacheModuleID!=='')
+ throw new TConfigurationException('cachepagestatepersister_cachemoduleid_invalid',$this->_cacheModuleID);
+ else
+ throw new TConfigurationException('cachepagestatepersister_cache_required');
+ }
+ $this->_cache=$cache;
+ }
+ return $this->_cache;
+ }
+
+ /**
+ * @return integer the number of seconds in which the cached state will expire. Defaults to 1800.
+ */
+ public function getCacheTimeout()
+ {
+ return $this->_timeout;
+ }
+
+ /**
+ * @param integer the number of seconds in which the cached state will expire. 0 means never expire.
+ * @throws TInvalidDataValueException if the number is smaller than 0.
+ */
+ public function setCacheTimeout($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))>=0)
+ $this->_timeout=$value;
+ else
+ throw new TInvalidDataValueException('cachepagestatepersister_timeout_invalid');
+ }
+
+ /**
+ * @return string prefix of cache variable name to avoid conflict with other cache data. Defaults to 'statepersister'.
+ */
+ public function getKeyPrefix()
+ {
+ return $this->_prefix;
+ }
+
+ /**
+ * @param string prefix of cache variable name to avoid conflict with other cache data
+ */
+ public function setKeyPrefix($value)
+ {
+ $this->_prefix=$value;
+ }
+
+ /**
+ * @param string micro timestamp when saving state occurs
+ * @return string a key that is unique per user request
+ */
+ protected function calculateKey($timestamp)
+ {
+ return $this->getKeyPrefix().':'
+ . $this->_page->getRequest()->getUserHostAddress()
+ . $this->_page->getPagePath()
+ . $timestamp;
+ }
+
+ /**
+ * Saves state in cache.
+ * @param mixed state to be stored
+ */
+ public function save($data)
+ {
+ $timestamp=(string)microtime(true);
+ $key=$this->calculateKey($timestamp);
+ $this->getCache()->add($key,$data,$this->_timeout);
+ $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp));
+ }
+
+ /**
+ * Loads page state from cache.
+ * @return mixed the restored state
+ * @throws THttpException if page state is corrupted
+ */
+ public function load()
+ {
+ if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
+ {
+ $key=$this->calculateKey($timestamp);
+ if(($data=$this->getCache()->get($key))!==false)
+ return $data;
+ }
+ throw new THttpException(400,'cachepagestatepersister_pagestate_corrupted');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/TClientScriptManager.php b/lib/prado/framework/Web/UI/TClientScriptManager.php
new file mode 100644
index 0000000..e35a1ca
--- /dev/null
+++ b/lib/prado/framework/Web/UI/TClientScriptManager.php
@@ -0,0 +1,849 @@
+<?php
+/**
+ * TClientScriptManager and TClientSideOptions class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @author Gabor Berczi <gabor.berczi@devworx.hu> (lazyload additions & progressive rendering)
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+/**
+ * TClientScriptManager class.
+ *
+ * TClientScriptManager manages javascript and CSS stylesheets for a page.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @author Gabor Berczi <gabor.berczi@devworx.hu> (lazyload additions & progressive rendering)
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TClientScriptManager extends TApplicationComponent
+{
+ /**
+ * directory containing Prado javascript files
+ */
+ const SCRIPT_PATH='Web/Javascripts/source';
+ /**
+ * file containing javascript packages and their cross dependencies
+ */
+ const PACKAGES_FILE='Web/Javascripts/packages.php';
+ /**
+ * @var TPage page who owns this manager
+ */
+ private $_page;
+ /**
+ * @var array registered hidden fields, indexed by hidden field names
+ */
+ private $_hiddenFields=array();
+ /**
+ * @var array javascript blocks to be rendered at the beginning of the form
+ */
+ private $_beginScripts=array();
+ /**
+ * @var array javascript blocks to be rendered at the end of the form
+ */
+ private $_endScripts=array();
+ /**
+ * @var array javascript files to be rendered in the form
+ */
+ private $_scriptFiles=array();
+ /**
+ * @var array javascript files to be rendered in page head section
+ */
+ private $_headScriptFiles=array();
+ /**
+ * @var array javascript blocks to be rendered in page head section
+ */
+ private $_headScripts=array();
+ /**
+ * @var array CSS files
+ */
+ private $_styleSheetFiles=array();
+ /**
+ * @var array CSS declarations
+ */
+ private $_styleSheets=array();
+ /**
+ * @var array registered PRADO script libraries
+ */
+ private $_registeredPradoScripts=array();
+ /**
+ * Client-side javascript library dependencies, loads from PACKAGES_FILE;
+ * @var array
+ */
+ private static $_pradoScripts;
+ /**
+ * Client-side javascript library packages, loads from PACKAGES_FILE;
+ * @var array
+ */
+ private static $_pradoPackages;
+
+ private $_renderedHiddenFields;
+
+ private $_renderedScriptFiles=array();
+
+ private $_expandedPradoScripts;
+
+ /**
+ * Constructor.
+ * @param TPage page that owns this client script manager
+ */
+ public function __construct(TPage $owner)
+ {
+ $this->_page=$owner;
+ }
+
+ /**
+ * @return boolean whether THead is required in order to render CSS and js within head
+ * @since 3.1.1
+ */
+ public function getRequiresHead()
+ {
+ return count($this->_styleSheetFiles) || count($this->_styleSheets)
+ || count($this->_headScriptFiles) || count($this->_headScripts);
+ }
+
+ public static function getPradoPackages()
+ {
+ return self::$_pradoPackages;
+ }
+
+ public static function getPradoScripts()
+ {
+ return self::$_pradoScripts;
+ }
+
+ /**
+ * Registers Prado javascript by library name. See "Web/Javascripts/packages.php"
+ * for library names.
+ * @param string script library name.
+ */
+ public function registerPradoScript($name)
+ {
+ $this->registerPradoScriptInternal($name);
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params);
+ }
+
+ /**
+ * Registers a Prado javascript library to be loaded.
+ */
+ protected function registerPradoScriptInternal($name)
+ {
+ // $this->checkIfNotInRender();
+ if(!isset($this->_registeredPradoScripts[$name]))
+ {
+ if(self::$_pradoScripts === null)
+ {
+ $packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::PACKAGES_FILE;
+ list($packages,$deps)= include($packageFile);
+ self::$_pradoScripts = $deps;
+ self::$_pradoPackages = $packages;
+ }
+
+ if (isset(self::$_pradoScripts[$name]))
+ $this->_registeredPradoScripts[$name]=true;
+ else
+ throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name);
+
+ if(($packages=array_keys($this->_registeredPradoScripts))!==array())
+ {
+ $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
+ list($path,$baseUrl)=$this->getPackagePathUrl($base);
+ $packagesUrl=array();
+ $isDebug=$this->getApplication()->getMode()===TApplicationMode::Debug;
+ foreach ($packages as $p)
+ {
+ foreach (self::$_pradoScripts[$p] as $dep)
+ {
+ foreach (self::$_pradoPackages[$dep] as $script)
+ if (!isset($this->_expandedPradoScripts[$script]))
+ {
+ $this->_expandedPradoScripts[$script] = true;
+ if($isDebug)
+ {
+ if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl))
+ $packagesUrl[]=$url;
+ } else {
+ if (!in_array($url=$baseUrl.'/min/'.$script,$packagesUrl))
+ {
+ if(!is_file($filePath=$path.'/min/'.$script))
+ {
+ $dirPath=dirname($filePath);
+ if(!is_dir($dirPath))
+ mkdir($dirPath, PRADO_CHMOD, true);
+ file_put_contents($filePath, TJavaScript::JSMin(file_get_contents($base.'/'.$script)));
+ chmod($filePath, PRADO_CHMOD);
+ }
+ $packagesUrl[]=$url;
+ }
+ }
+ }
+ }
+ }
+ foreach($packagesUrl as $url)
+ $this->registerScriptFile($url,$url);
+ }
+ }
+ }
+
+ /**
+ * @return string Prado javascript library base asset url.
+ */
+ public function getPradoScriptAssetUrl()
+ {
+ $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
+ $assets = Prado::getApplication()->getAssetManager();
+ return $assets->getPublishedUrl($base);
+ }
+
+ /**
+ * Returns the URLs of all script files referenced on the page
+ * @return array Combined list of all script urls used in the page
+ */
+ public function getScriptUrls()
+ {
+ $scripts = array_values($this->_headScriptFiles);
+ $scripts = array_merge($scripts, array_values($this->_scriptFiles));
+ $scripts = array_unique($scripts);
+
+ return $scripts;
+ }
+
+ /**
+ * @param string javascript package path.
+ * @return array tuple($path,$url).
+ */
+ protected function getPackagePathUrl($base)
+ {
+ $assets = Prado::getApplication()->getAssetManager();
+ if(strpos($base, $assets->getBaseUrl())===false)
+ {
+ if(($dir = Prado::getPathOfNameSpace($base)) !== null) {
+ $base = $dir;
+ }
+ return array($assets->getPublishedPath($base), $assets->publishFilePath($base));
+ }
+ else
+ {
+ return array($assets->getBasePath().str_replace($assets->getBaseUrl(),'',$base), $base);
+ }
+ }
+
+ /**
+ * Returns javascript statement that create a new callback request object.
+ * @param ICallbackEventHandler callback response handler
+ * @param array additional callback options
+ * @return string javascript statement that creates a new callback request.
+ */
+ public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null)
+ {
+ $options = !is_array($options) ? array() : $options;
+ $class = new ReflectionClass($callbackHandler);
+ $clientSide = $callbackHandler->getActiveControl()->getClientSide();
+ $options = array_merge($options, $clientSide->getOptions()->toArray());
+ $optionString = TJavaScript::encode($options);
+ $this->registerPradoScriptInternal('ajax');
+ $id = $callbackHandler->getUniqueID();
+ return "new Prado.CallbackRequest('{$id}',{$optionString})";
+ }
+
+ /**
+ * Registers callback javascript for a control.
+ * @param string javascript class responsible for the control being registered for callback
+ * @param array callback options
+ */
+ public function registerCallbackControl($class, $options)
+ {
+ $optionString=TJavaScript::encode($options);
+ $code="new {$class}({$optionString});";
+ $this->_endScripts[sprintf('%08X', crc32($code))]=$code;
+ $this->registerPradoScriptInternal('ajax');
+
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerCallbackControl',$params);
+ }
+
+ /**
+ * Registers postback javascript for a control. A null class parameter will prevent
+ * the javascript code registration.
+ * @param string javascript class responsible for the control being registered for postback
+ * @param array postback options
+ */
+ public function registerPostBackControl($class,$options)
+ {
+ if($class === null) {
+ return;
+ }
+ if(!isset($options['FormID']) && ($form=$this->_page->getForm())!==null)
+ $options['FormID']=$form->getClientID();
+ $optionString=TJavaScript::encode($options);
+ $code="new {$class}({$optionString});";
+
+ $this->_endScripts[sprintf('%08X', crc32($code))]=$code;
+ $this->registerPradoScriptInternal('prado');
+
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerPostBackControl',$params);
+ }
+
+ /**
+ * Register a default button to panel. When the $panel is in focus and
+ * the 'enter' key is pressed, the $button will be clicked.
+ * @param TControl|string panel (or its unique ID) to register the default button action
+ * @param TControl|string button (or its unique ID) to trigger a postback
+ */
+ public function registerDefaultButton($panel, $button)
+ {
+ $panelID=is_string($panel)?$panel:$panel->getUniqueID();
+
+ if(is_string($button))
+ $buttonID=$button;
+ else
+ {
+ $button->setIsDefaultButton(true);
+ $buttonID=$button->getUniqueID();
+ }
+ $options = TJavaScript::encode($this->getDefaultButtonOptions($panelID, $buttonID));
+ $code = "new Prado.WebUI.DefaultButton($options);";
+
+ $this->_endScripts['prado:'.$panelID]=$code;
+ $this->registerPradoScriptInternal('prado');
+
+ $params=array($panelID,$buttonID);
+ $this->_page->registerCachingAction('Page.ClientScript','registerDefaultButton',$params);
+ }
+
+ /**
+ * @param string the unique ID of the container control
+ * @param string the unique ID of the button control
+ * @return array default button options.
+ */
+ protected function getDefaultButtonOptions($panelID, $buttonID)
+ {
+ $options['ID'] = TControl::convertUniqueIdToClientId($panelID);
+ $options['Panel'] = TControl::convertUniqueIdToClientId($panelID);
+ $options['Target'] = TControl::convertUniqueIdToClientId($buttonID);
+ $options['EventTarget'] = $buttonID;
+ $options['Event'] = 'click';
+ return $options;
+ }
+
+ /**
+ * Registers the control to receive default focus.
+ * @param string the client ID of the control to receive default focus
+ */
+ public function registerFocusControl($target)
+ {
+ $this->registerPradoScriptInternal('jquery');
+ if($target instanceof TControl)
+ $target=$target->getClientID();
+ $this->_endScripts['prado:focus'] = 'jQuery(\'#'.$target.'\').focus();';
+
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerFocusControl',$params);
+ }
+
+ /**
+ * Registers a CSS file to be rendered in the page head
+ *
+ * The CSS files in themes are registered in {@link OnPreRenderComplete onPreRenderComplete} if you want to override
+ * CSS styles in themes you need to register it after this event is completed.
+ *
+ * Example:
+ * <code>
+ * <?php
+ * class BasePage extends TPage {
+ * public function onPreRenderComplete($param) {
+ * parent::onPreRenderComplete($param);
+ * $url = 'path/to/your/stylesheet.css';
+ * $this->Page->ClientScript->registerStyleSheetFile($url, $url);
+ * }
+ * }
+ * </code>
+ *
+ * @param string a unique key identifying the file
+ * @param string URL to the CSS file
+ * @param string media type of the CSS (such as 'print', 'screen', etc.). Defaults to empty, meaning the CSS applies to all media types.
+ */
+ public function registerStyleSheetFile($key,$url,$media='')
+ {
+ if($media==='')
+ $this->_styleSheetFiles[$key]=$url;
+ else
+ $this->_styleSheetFiles[$key]=array($url,$media);
+
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerStyleSheetFile',$params);
+ }
+
+ /**
+ * Registers a CSS block to be rendered in the page head
+ * @param string a unique key identifying the CSS block
+ * @param string CSS block
+ */
+ public function registerStyleSheet($key,$css,$media='')
+ {
+ $this->_styleSheets[$key]=$css;
+
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerStyleSheet',$params);
+ }
+
+ /**
+ * Returns the URLs of all stylesheet files referenced on the page
+ * @return array List of all stylesheet urls used in the page
+ */
+ public function getStyleSheetUrls()
+ {
+ $stylesheets = array_values(
+ array_map(
+ create_function('$e', 'return is_array($e) ? $e[0] : $e;'),
+ $this->_styleSheetFiles)
+ );
+
+ foreach(Prado::getApplication()->getAssetManager()->getPublished() as $path=>$url)
+ if (substr($url,strlen($url)-4)=='.css')
+ $stylesheets[] = $url;
+
+ $stylesheets = array_unique($stylesheets);
+
+ return $stylesheets;
+ }
+
+ /**
+ * Returns all the stylesheet code snippets referenced on the page
+ * @return array List of all stylesheet snippets used in the page
+ */
+ public function getStyleSheetCodes()
+ {
+ return array_unique(array_values($this->_styleSheets));
+ }
+
+ /**
+ * Registers a javascript file in the page head
+ * @param string a unique key identifying the file
+ * @param string URL to the javascript file
+ */
+ public function registerHeadScriptFile($key,$url)
+ {
+ $this->checkIfNotInRender();
+ $this->_headScriptFiles[$key]=$url;
+
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params);
+ }
+
+ /**
+ * Registers a javascript block in the page head.
+ * @param string a unique key identifying the script block
+ * @param string javascript block
+ */
+ public function registerHeadScript($key,$script)
+ {
+ $this->checkIfNotInRender();
+ $this->_headScripts[$key]=$script;
+
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerHeadScript',$params);
+ }
+
+ /**
+ * Registers a javascript file to be rendered within the form
+ * @param string a unique key identifying the file
+ * @param string URL to the javascript file to be rendered
+ */
+ public function registerScriptFile($key, $url)
+ {
+ $this->_scriptFiles[$key]=$url;
+
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params);
+ }
+
+ /**
+ * Registers a javascript script block at the beginning of the form
+ * @param string a unique key identifying the script block
+ * @param string javascript block
+ */
+ public function registerBeginScript($key,$script)
+ {
+ $this->checkIfNotInRender();
+ $this->_beginScripts[$key]=$script;
+
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerBeginScript',$params);
+ }
+
+ /**
+ * Registers a javascript script block at the end of the form
+ * @param string a unique key identifying the script block
+ * @param string javascript block
+ */
+ public function registerEndScript($key,$script)
+ {
+ $this->_endScripts[$key]=$script;
+
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerEndScript',$params);
+ }
+
+ /**
+ * Registers a hidden field to be rendered in the form.
+ * @param string a unique key identifying the hidden field
+ * @param string|array hidden field value, if the value is an array, every element
+ * in the array will be rendered as a hidden field value.
+ */
+ public function registerHiddenField($name,$value)
+ {
+ $this->_hiddenFields[$name]=$value;
+
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','registerHiddenField',$params);
+ }
+
+ /**
+ * @param string a unique key
+ * @return boolean whether there is a CSS file registered with the specified key
+ */
+ public function isStyleSheetFileRegistered($key)
+ {
+ return isset($this->_styleSheetFiles[$key]);
+ }
+
+ /**
+ * @param string a unique key
+ * @return boolean whether there is a CSS block registered with the specified key
+ */
+ public function isStyleSheetRegistered($key)
+ {
+ return isset($this->_styleSheets[$key]);
+ }
+
+ /**
+ * @param string a unique key
+ * @return boolean whether there is a head javascript file registered with the specified key
+ */
+ public function isHeadScriptFileRegistered($key)
+ {
+ return isset($this->_headScriptFiles[$key]);
+ }
+
+ /**
+ * @param string a unique key
+ * @return boolean whether there is a head javascript block registered with the specified key
+ */
+ public function isHeadScriptRegistered($key)
+ {
+ return isset($this->_headScripts[$key]);
+ }
+
+ /**
+ * @param string a unique key
+ * @return boolean whether there is a javascript file registered with the specified key
+ */
+ public function isScriptFileRegistered($key)
+ {
+ return isset($this->_scriptFiles[$key]);
+ }
+
+ /**
+ * @param string a unique key
+ * @return boolean whether there is a beginning javascript block registered with the specified key
+ */
+ public function isBeginScriptRegistered($key)
+ {
+ return isset($this->_beginScripts[$key]);
+ }
+
+ /**
+ * @param string a unique key
+ * @return boolean whether there is an ending javascript block registered with the specified key
+ */
+ public function isEndScriptRegistered($key)
+ {
+ return isset($this->_endScripts[$key]);
+ }
+
+ /**
+ * @return boolean true if any end scripts are registered.
+ */
+ public function hasEndScripts()
+ {
+ return count($this->_endScripts) > 0;
+ }
+
+ /**
+ * @return boolean true if any begin scripts are registered.
+ */
+ public function hasBeginScripts()
+ {
+ return count($this->_beginScripts) > 0;
+ }
+
+ /**
+ * @param string a unique key
+ * @return boolean whether there is a hidden field registered with the specified key
+ */
+ public function isHiddenFieldRegistered($key)
+ {
+ return isset($this->_hiddenFields[$key]);
+ }
+
+ /**
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderStyleSheetFiles($writer)
+ {
+ $str='';
+ foreach($this->_styleSheetFiles as $url)
+ {
+ if(is_array($url))
+ $str.="<link rel=\"stylesheet\" type=\"text/css\" media=\"{$url[1]}\" href=\"".THttpUtility::htmlEncode($url[0])."\" />\n";
+ else
+ $str.="<link rel=\"stylesheet\" type=\"text/css\" href=\"".THttpUtility::htmlEncode($url)."\" />\n";
+ }
+ $writer->write($str);
+ }
+
+ /**
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderStyleSheets($writer)
+ {
+ if(count($this->_styleSheets))
+ $writer->write("<style type=\"text/css\">\n/*<![CDATA[*/\n".implode("\n",$this->_styleSheets)."\n/*]]>*/\n</style>\n");
+ }
+
+ /**
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderHeadScriptFiles($writer)
+ {
+ $this->renderScriptFiles($writer,$this->_headScriptFiles);
+ }
+
+ /**
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderHeadScripts($writer)
+ {
+ $writer->write(TJavaScript::renderScriptBlocks($this->_headScripts));
+ }
+
+ public function renderScriptFilesBegin($writer)
+ {
+ $this->renderAllPendingScriptFiles($writer);
+ }
+
+ public function renderScriptFilesEnd($writer)
+ {
+ $this->renderAllPendingScriptFiles($writer);
+ }
+
+ public function markScriptFileAsRendered($url)
+ {
+ $this->_renderedScriptFiles[$url] = $url;
+ $params=func_get_args();
+ $this->_page->registerCachingAction('Page.ClientScript','markScriptFileAsRendered',$params);
+ }
+
+ protected function renderScriptFiles($writer, Array $scripts)
+ {
+ foreach($scripts as $script)
+ {
+ $writer->write(TJavaScript::renderScriptFile($script));
+ $this->markScriptFileAsRendered($script);
+ }
+ }
+
+ protected function getRenderedScriptFiles()
+ {
+ return $this->_renderedScriptFiles;
+ }
+
+ /**
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderAllPendingScriptFiles($writer)
+ {
+ if(!empty($this->_scriptFiles))
+ {
+ $addedScripts = array_diff($this->_scriptFiles,$this->getRenderedScriptFiles());
+ $this->renderScriptFiles($writer,$addedScripts);
+ }
+ }
+
+ /**
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderBeginScripts($writer)
+ {
+ $writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts));
+ }
+
+ /**
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderEndScripts($writer)
+ {
+ $writer->write(TJavaScript::renderScriptBlocks($this->_endScripts));
+ }
+
+ /**
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderBeginScriptsCallback($writer)
+ {
+ $writer->write(TJavaScript::renderScriptBlocksCallback($this->_beginScripts));
+ }
+
+ /**
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderEndScriptsCallback($writer)
+ {
+ $writer->write(TJavaScript::renderScriptBlocksCallback($this->_endScripts));
+ }
+
+ public function renderHiddenFieldsBegin($writer)
+ {
+ $this->renderHiddenFieldsInt($writer,true);
+ }
+
+ public function renderHiddenFieldsEnd($writer)
+ {
+ $this->renderHiddenFieldsInt($writer,false);
+ }
+
+ /**
+ * Flushes all pending script registrations
+ * @param THtmlWriter writer for the rendering purpose
+ * @param TControl the control forcing the flush (used only in error messages)
+ */
+ public function flushScriptFiles($writer, $control=null)
+ {
+ if(!$this->_page->getIsCallback())
+ {
+ $this->_page->ensureRenderInForm($control);
+ $this->renderAllPendingScriptFiles($writer);
+ }
+ }
+
+ /**
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ protected function renderHiddenFieldsInt($writer, $initial)
+ {
+ if ($initial) $this->_renderedHiddenFields = array();
+ $str='';
+ foreach($this->_hiddenFields as $name=>$value)
+ {
+ if (in_array($name,$this->_renderedHiddenFields)) continue;
+ $id=strtr($name,':','_');
+ if(is_array($value))
+ {
+ foreach($value as $v)
+ $str.='<input type="hidden" name="'.$name.'[]" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
+ }
+ else
+ {
+ $str.='<input type="hidden" name="'.$name.'" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
+ }
+ $this->_renderedHiddenFields[] = $name;
+ }
+ if($str!=='')
+ $writer->write("<div style=\"visibility:hidden;\">\n".$str."</div>\n");
+ }
+
+ public function getHiddenFields()
+ {
+ return $this->_hiddenFields;
+ }
+
+ /**
+ * Checks whether page rendering has not begun yet
+ */
+ protected function checkIfNotInRender()
+ {
+ if ($form = $this->_page->InFormRender)
+ throw new Exception('Operation invalid when page is already rendering');
+ }
+}
+
+/**
+ * TClientSideOptions abstract class.
+ *
+ * TClientSideOptions manages client-side options for components that have
+ * common client-side javascript behaviours and client-side events such as
+ * between ActiveControls and validators.
+ *
+ * @author <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+abstract class TClientSideOptions extends TComponent
+{
+ /**
+ * @var TMap list of client-side options.
+ */
+ private $_options;
+
+ /**
+ * Adds on client-side event handler by wrapping the code within a
+ * javascript function block. If the code begins with "javascript:", the
+ * code is assumed to be a javascript function block rather than arbiturary
+ * javascript statements.
+ * @param string option name
+ * @param string javascript statements.
+ */
+ protected function setFunction($name, $code)
+ {
+ if(!TJavaScript::isJsLiteral($code))
+ $code = TJavaScript::quoteJsLiteral($this->ensureFunction($code));
+ $this->setOption($name, $code);
+ }
+
+ /**
+ * @return string gets a particular option, null if not set.
+ */
+ protected function getOption($name)
+ {
+ if ($this->_options)
+ return $this->_options->itemAt($name);
+ else
+ return null;
+ }
+
+ /**
+ * @param string option name
+ * @param mixed option value.
+ */
+ protected function setOption($name, $value)
+ {
+ $this->getOptions()->add($name, $value);
+ }
+
+ /**
+ * @return TMap gets the list of options as TMap
+ */
+ public function getOptions()
+ {
+ if (!$this->_options)
+ $this->_options = Prado::createComponent('System.Collections.TMap');
+ return $this->_options;
+ }
+
+ /**
+ * Ensure that the javascript statements are wrapped in a javascript
+ * function block as <code>function(sender, parameter){ //code }</code>.
+ */
+ protected function ensureFunction($javascript)
+ {
+ return "function(sender, parameter){ {$javascript} }";
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/TCompositeControl.php b/lib/prado/framework/Web/UI/TCompositeControl.php
new file mode 100644
index 0000000..e830351
--- /dev/null
+++ b/lib/prado/framework/Web/UI/TCompositeControl.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * TCompositeControl class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+/**
+ * TCompositeControl class.
+ * TCompositeControl is the base class for controls that are composed
+ * by other controls.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TCompositeControl extends TControl implements INamingContainer
+{
+ /**
+ * Performs the OnInit step for the control and all its child controls.
+ * This method overrides the parent implementation
+ * by ensuring child controls are created first.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function initRecursive($namingContainer=null)
+ {
+ $this->ensureChildControls();
+ parent::initRecursive($namingContainer);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/TControl.php b/lib/prado/framework/Web/UI/TControl.php
new file mode 100644
index 0000000..055b552
--- /dev/null
+++ b/lib/prado/framework/Web/UI/TControl.php
@@ -0,0 +1,2367 @@
+<?php
+/**
+ * TControl, TControlCollection, TEventParameter and INamingContainer class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+/**
+ * Includes TAttributeCollection and TControlAdapter class
+ */
+Prado::using('System.Collections.TAttributeCollection');
+Prado::using('System.Web.UI.TControlAdapter');
+
+/**
+ * TControl class
+ *
+ * TControl is the base class for all components on a page hierarchy.
+ * It implements the following features for UI-related functionalities:
+ * - databinding feature
+ * - parent and child relationship
+ * - naming container and containee relationship
+ * - viewstate and controlstate features
+ * - rendering scheme
+ * - control lifecycles
+ *
+ * A property can be data-bound with an expression. By calling {@link dataBind},
+ * expressions bound to properties will be evaluated and the results will be
+ * set to the corresponding properties.
+ *
+ * Parent and child relationship determines how the presentation of controls are
+ * enclosed within each other. A parent will determine where to place
+ * the presentation of its child controls. For example, a TPanel will enclose
+ * all its child controls' presentation within a div html tag. A control's parent
+ * can be obtained via {@link getParent Parent} property, and its
+ * {@link getControls Controls} property returns a list of the control's children,
+ * including controls and static texts. The property can be manipulated
+ * like an array for adding or removing a child (see {@link TList} for more details).
+ *
+ * A naming container control implements INamingContainer and ensures that
+ * its containee controls can be differentiated by their ID property values.
+ * Naming container and containee realtionship specifies a protocol to uniquely
+ * identify an arbitrary control on a page hierarchy by an ID path (concatenation
+ * of all naming containers' IDs and the target control's ID).
+ *
+ * Viewstate and controlstate are two approaches to preserve state across
+ * page postback requests. ViewState is mainly related with UI specific state
+ * and can be disabled if not needed. ControlState represents crucial logic state
+ * and cannot be disabled.
+ *
+ * A control is rendered via its {@link render()} method (the method is invoked
+ * by the framework.) Descendant control classes may override this method for
+ * customized rendering. By default, {@link render()} invokes {@link renderChildren()}
+ * which is responsible for rendering of children of the control.
+ * Control's {@link getVisible Visible} property governs whether the control
+ * should be rendered or not.
+ *
+ * Each control on a page will undergo a series of lifecycles, including
+ * control construction, Init, Load, PreRender, Render, and OnUnload.
+ * They work together with page lifecycles to process a page request.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TControl extends TApplicationComponent implements IRenderable, IBindable
+{
+ /**
+ * format of control ID
+ */
+ const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
+ /**
+ * separator char between IDs in a UniqueID
+ */
+ const ID_SEPARATOR='$';
+ /**
+ * separator char between IDs in a ClientID
+ */
+ const CLIENT_ID_SEPARATOR='_';
+ /**
+ * prefix to an ID automatically generated
+ */
+ const AUTOMATIC_ID_PREFIX='ctl';
+
+ /**
+ * the stage of lifecycles that the control is currently at
+ */
+ const CS_CONSTRUCTED=0;
+ const CS_CHILD_INITIALIZED=1;
+ const CS_INITIALIZED=2;
+ const CS_STATE_LOADED=3;
+ const CS_LOADED=4;
+ const CS_PRERENDERED=5;
+
+ /**
+ * State bits.
+ */
+ const IS_ID_SET=0x01;
+ const IS_DISABLE_VIEWSTATE=0x02;
+ const IS_SKIN_APPLIED=0x04;
+ const IS_STYLESHEET_APPLIED=0x08;
+ const IS_DISABLE_THEMING=0x10;
+ const IS_CHILD_CREATED=0x20;
+ const IS_CREATING_CHILD=0x40;
+
+ /**
+ * Indexes for the rare fields.
+ * In order to save memory, rare fields will only be created if they are needed.
+ */
+ const RF_CONTROLS=0; // child controls
+ const RF_CHILD_STATE=1; // child state field
+ const RF_NAMED_CONTROLS=2; // list of controls whose namingcontainer is this control
+ const RF_NAMED_CONTROLS_ID=3; // counter for automatic id
+ const RF_SKIN_ID=4; // skin ID
+ const RF_DATA_BINDINGS=5; // data bindings
+ const RF_EVENTS=6; // event handlers
+ const RF_CONTROLSTATE=7; // controlstate
+ const RF_NAMED_OBJECTS=8; // controls declared with ID on template
+ const RF_ADAPTER=9; // adapter
+ const RF_AUTO_BINDINGS=10; // auto data bindings
+
+ /**
+ * @var string control ID
+ */
+ private $_id='';
+ /**
+ * @var string control unique ID
+ */
+ private $_uid;
+ /**
+ * @var TControl parent of the control
+ */
+ private $_parent;
+ /**
+ * @var TPage page that the control resides in
+ */
+ private $_page;
+ /**
+ * @var TControl naming container of the control
+ */
+ private $_namingContainer;
+ /**
+ * @var TTemplateControl control whose template contains the control
+ */
+ private $_tplControl;
+ /**
+ * @var array viewstate data
+ */
+ private $_viewState=array();
+ /**
+ * @var array temporary state (usually set in template)
+ */
+ private $_tempState=array();
+ /**
+ * @var boolean whether we should keep state in viewstate
+ */
+ private $_trackViewState=true;
+ /**
+ * @var integer the current stage of the control lifecycles
+ */
+ private $_stage=0;
+ /**
+ * @var integer representation of the state bits
+ */
+ private $_flags=0;
+ /**
+ * @var array a collection of rare control data
+ */
+ private $_rf=array();
+
+ /**
+ * Returns a property value by name or a control by ID.
+ * This overrides the parent implementation by allowing accessing
+ * a control via its ID using the following syntax,
+ * <code>
+ * $menuBar=$this->menuBar;
+ * </code>
+ * Note, the control must be configured in the template
+ * with explicit ID. If the name matches both a property and a control ID,
+ * the control ID will take the precedence.
+ *
+ * @param string the property name or control ID
+ * @return mixed the property value or the target control
+ * @throws TInvalidOperationException if the property is not defined.
+ * @see registerObject
+ */
+ public function __get($name)
+ {
+ if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
+ return $this->_rf[self::RF_NAMED_OBJECTS][$name];
+ else
+ return parent::__get($name);
+ }
+
+ /**
+ * @return boolean whether there is an adapter for this control
+ */
+ public function getHasAdapter()
+ {
+ return isset($this->_rf[self::RF_ADAPTER]);
+ }
+
+ /**
+ * @return TControlAdapter control adapter. Null if not exists.
+ */
+ public function getAdapter()
+ {
+ return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
+ }
+
+ /**
+ * @param TControlAdapter control adapter
+ */
+ public function setAdapter(TControlAdapter $adapter)
+ {
+ $this->_rf[self::RF_ADAPTER]=$adapter;
+ }
+
+ /**
+ * @return TControl the parent of this control
+ */
+ public function getParent()
+ {
+ return $this->_parent;
+ }
+
+ /**
+ * @return TControl the naming container of this control
+ */
+ public function getNamingContainer()
+ {
+ if(!$this->_namingContainer && $this->_parent)
+ {
+ if($this->_parent instanceof INamingContainer)
+ $this->_namingContainer=$this->_parent;
+ else
+ $this->_namingContainer=$this->_parent->getNamingContainer();
+ }
+ return $this->_namingContainer;
+ }
+
+ /**
+ * @return TPage the page that contains this control
+ */
+ public function getPage()
+ {
+ if(!$this->_page)
+ {
+ if($this->_parent)
+ $this->_page=$this->_parent->getPage();
+ else if($this->_tplControl)
+ $this->_page=$this->_tplControl->getPage();
+ }
+ return $this->_page;
+ }
+
+ /**
+ * Sets the page for a control.
+ * Only framework developers should use this method.
+ * @param TPage the page that contains this control
+ */
+ public function setPage($page)
+ {
+ $this->_page=$page;
+ }
+
+ /**
+ * Sets the control whose template contains this control.
+ * Only framework developers should use this method.
+ * @param TTemplateControl the control whose template contains this control
+ */
+ public function setTemplateControl($control)
+ {
+ $this->_tplControl=$control;
+ }
+
+ /**
+ * @return TTemplateControl the control whose template contains this control
+ */
+ public function getTemplateControl()
+ {
+ if(!$this->_tplControl && $this->_parent)
+ $this->_tplControl=$this->_parent->getTemplateControl();
+ return $this->_tplControl;
+ }
+
+ /**
+ * @return TTemplateControl the control whose template is loaded from
+ * some external storage, such as file, db, and whose template ultimately
+ * contains this control.
+ */
+ public function getSourceTemplateControl()
+ {
+ $control=$this;
+ while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
+ {
+ if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
+ return $control;
+ }
+ return $this->getPage();
+ }
+
+ /**
+ * Gets the lifecycle step the control is currently at.
+ * This method should only be used by control developers.
+ * @return integer the lifecycle step the control is currently at.
+ * The value can be CS_CONSTRUCTED, CS_CHILD_INITIALIZED, CS_INITIALIZED,
+ * CS_STATE_LOADED, CS_LOADED, CS_PRERENDERED.
+ */
+ protected function getControlStage()
+ {
+ return $this->_stage;
+ }
+
+ /**
+ * Sets the lifecycle step the control is currently at.
+ * This method should only be used by control developers.
+ * @param integer the lifecycle step the control is currently at.
+ * Valid values include CS_CONSTRUCTED, CS_CHILD_INITIALIZED, CS_INITIALIZED,
+ * CS_STATE_LOADED, CS_LOADED, CS_PRERENDERED.
+ */
+ protected function setControlStage($value)
+ {
+ $this->_stage=$value;
+ }
+
+ /**
+ * Returns the id of the control.
+ * Control ID can be either manually set or automatically generated.
+ * If $hideAutoID is true, automatically generated ID will be returned as an empty string.
+ * @param boolean whether to hide automatically generated ID
+ * @return string the ID of the control
+ */
+ public function getID($hideAutoID=true)
+ {
+ if($hideAutoID)
+ return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
+ else
+ return $this->_id;
+ }
+
+ /**
+ * @param string the new control ID. The value must consist of word characters [a-zA-Z0-9_] only
+ * @throws TInvalidDataValueException if ID is in a bad format
+ */
+ public function setID($id)
+ {
+ if(!preg_match(self::ID_FORMAT,$id))
+ throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
+ $this->_id=$id;
+ $this->_flags |= self::IS_ID_SET;
+ $this->clearCachedUniqueID($this instanceof INamingContainer);
+ if($this->_namingContainer)
+ $this->_namingContainer->clearNameTable();
+ }
+
+ /**
+ * Returns a unique ID that identifies the control in the page hierarchy.
+ * A unique ID is the contenation of all naming container controls' IDs and the control ID.
+ * These IDs are separated by '$' character.
+ * Control users should not rely on the specific format of UniqueID, however.
+ * @return string a unique ID that identifies the control in the page hierarchy
+ */
+ public function getUniqueID()
+ {
+ if($this->_uid==='' || $this->_uid===null) // need to build the UniqueID
+ {
+ $this->_uid=''; // set to not-null, so that clearCachedUniqueID() may take action
+ if($namingContainer=$this->getNamingContainer())
+ {
+ if($this->getPage()===$namingContainer)
+ return ($this->_uid=$this->_id);
+ else if(($prefix=$namingContainer->getUniqueID())==='')
+ return $this->_id;
+ else
+ return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
+ }
+ else // no naming container
+ return $this->_id;
+ }
+ else
+ return $this->_uid;
+ }
+
+ /**
+ * Sets input focus to this control.
+ */
+ public function focus()
+ {
+ $this->getPage()->setFocus($this);
+ }
+
+ /**
+ * Returns the client ID of the control.
+ * The client ID can be used to uniquely identify
+ * the control in client-side scripts (such as JavaScript).
+ * Do not rely on the explicit format of the return ID.
+ * @return string the client ID of the control
+ */
+ public function getClientID()
+ {
+ return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
+ }
+
+ /**
+ * Converts a unique ID to a client ID.
+ * @param string the unique ID of a control
+ * @return string the client ID of the control
+ */
+ public static function convertUniqueIdToClientId($uniqueID)
+ {
+ return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
+ }
+
+ /**
+ * @return string the skin ID of this control, '' if not set
+ */
+ public function getSkinID()
+ {
+ return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
+ }
+
+ /**
+ * @param string the skin ID of this control
+ * @throws TInvalidOperationException if the SkinID is set in a stage later than PreInit, or if the skin is applied already.
+ */
+ public function setSkinID($value)
+ {
+ if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
+ throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
+ else
+ $this->_rf[self::RF_SKIN_ID]=$value;
+ }
+
+ /**
+ * @param string the skin ID of this control
+ * @throws TInvalidOperationException if the SkinID is set in a stage later than PreInit, or if the skin is applied already.
+ */
+ public function getIsSkinApplied()
+ {
+ return ($this->_flags & self::IS_SKIN_APPLIED);
+ }
+
+ /**
+ * @return boolean whether theming is enabled for this control.
+ * The theming is enabled if the control and all its parents have it enabled.
+ */
+ public function getEnableTheming()
+ {
+ if($this->_flags & self::IS_DISABLE_THEMING)
+ return false;
+ else
+ return $this->_parent?$this->_parent->getEnableTheming():true;
+ }
+
+ /**
+ * @param boolean whether to enable theming
+ * @throws TInvalidOperationException if this method is invoked after OnPreInit
+ */
+ public function setEnableTheming($value)
+ {
+ if($this->_stage>=self::CS_CHILD_INITIALIZED)
+ throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
+ else if(TPropertyValue::ensureBoolean($value))
+ $this->_flags &= ~self::IS_DISABLE_THEMING;
+ else
+ $this->_flags |= self::IS_DISABLE_THEMING;
+ }
+
+ /**
+ * Returns custom data associated with this control.
+ * A control may be associated with some custom data for various purposes.
+ * For example, a button may be associated with a string to identify itself
+ * in a generic OnClick event handler.
+ * @return mixed custom data associated with this control. Defaults to null.
+ */
+ public function getCustomData()
+ {
+ return $this->getViewState('CustomData',null);
+ }
+
+ /**
+ * Associates custom data with this control.
+ * Note, the custom data must be serializable and unserializable.
+ * @param mixed custom data
+ */
+ public function setCustomData($value)
+ {
+ $this->setViewState('CustomData',$value,null);
+ }
+
+ /**
+ * @return boolean whether the control has child controls
+ */
+ public function getHasControls()
+ {
+ return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
+ }
+
+ /**
+ * @return TControlCollection the child control collection
+ */
+ public function getControls()
+ {
+ if(!isset($this->_rf[self::RF_CONTROLS]))
+ $this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
+ return $this->_rf[self::RF_CONTROLS];
+ }
+
+ /**
+ * Creates a control collection object that is to be used to hold child controls
+ * @return TControlCollection control collection
+ * @see getControls
+ */
+ protected function createControlCollection()
+ {
+ return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
+ }
+
+ /**
+ * Checks if a control is visible.
+ * If parent check is required, then a control is visible only if the control
+ * and all its ancestors are visible.
+ * @param boolean whether the parents should also be checked if visible
+ * @return boolean whether the control is visible (default=true).
+ */
+ public function getVisible($checkParents=true)
+ {
+ if($checkParents)
+ {
+ for($control=$this;$control;$control=$control->_parent)
+ if(!$control->getVisible(false))
+ return false;
+ return true;
+ }
+ else
+ return $this->getViewState('Visible',true);
+ }
+
+ /**
+ * @param boolean whether the control is visible
+ */
+ public function setVisible($value)
+ {
+ $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Returns a value indicating whether the control is enabled.
+ * A control is enabled if it allows client user interaction.
+ * If $checkParents is true, all parent controls will be checked,
+ * and unless they are all enabled, false will be returned.
+ * The property Enabled is mainly used for {@link TWebControl}
+ * derived controls.
+ * @param boolean whether the parents should also be checked enabled
+ * @return boolean whether the control is enabled.
+ */
+ public function getEnabled($checkParents=false)
+ {
+ if($checkParents)
+ {
+ for($control=$this;$control;$control=$control->_parent)
+ if(!$control->getViewState('Enabled',true))
+ return false;
+ return true;
+ }
+ else
+ return $this->getViewState('Enabled',true);
+ }
+
+ /**
+ * @param boolean whether the control is to be enabled.
+ */
+ public function setEnabled($value)
+ {
+ $this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the control has custom attributes
+ */
+ public function getHasAttributes()
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->getCount()>0;
+ else
+ return false;
+ }
+
+ /**
+ * Returns the list of custom attributes.
+ * Custom attributes are name-value pairs that may be rendered
+ * as HTML tags' attributes.
+ * @return TAttributeCollection the list of custom attributes
+ */
+ public function getAttributes()
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes;
+ else
+ {
+ $attributes=new TAttributeCollection;
+ $this->setViewState('Attributes',$attributes,null);
+ return $attributes;
+ }
+ }
+
+ /**
+ * @return boolean whether the named attribute exists
+ */
+ public function hasAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->contains($name);
+ else
+ return false;
+ }
+
+ /**
+ * @return string attribute value, null if attribute does not exist
+ */
+ public function getAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->itemAt($name);
+ else
+ return null;
+ }
+
+ /**
+ * Sets a custom control attribute.
+ * @param string attribute name
+ * @param string value of the attribute
+ */
+ public function setAttribute($name,$value)
+ {
+ $this->getAttributes()->add($name,$value);
+ }
+
+ /**
+ * Removes the named attribute.
+ * @param string the name of the attribute to be removed.
+ * @return string attribute value removed, null if attribute does not exist.
+ */
+ public function removeAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->remove($name);
+ else
+ return null;
+ }
+
+ /**
+ * @return boolean whether viewstate is enabled
+ */
+ public function getEnableViewState($checkParents=false)
+ {
+ if($checkParents)
+ {
+ for($control=$this;$control!==null;$control=$control->getParent())
+ if($control->_flags & self::IS_DISABLE_VIEWSTATE)
+ return false;
+ return true;
+ }
+ else
+ return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
+ }
+
+ /**
+ * @param boolean set whether to enable viewstate
+ */
+ public function setEnableViewState($value)
+ {
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
+ else
+ $this->_flags |= self::IS_DISABLE_VIEWSTATE;
+ }
+
+ /**
+ * Returns a controlstate value.
+ *
+ * This function is mainly used in defining getter functions for control properties
+ * that must be kept in controlstate.
+ * @param string the name of the controlstate value to be returned
+ * @param mixed the default value. If $key is not found in controlstate, $defaultValue will be returned
+ * @return mixed the controlstate value corresponding to $key
+ */
+ protected function getControlState($key,$defaultValue=null)
+ {
+ return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
+ }
+
+ /**
+ * Sets a controlstate value.
+ *
+ * This function is very useful in defining setter functions for control properties
+ * that must be kept in controlstate.
+ * Make sure that the controlstate value must be serializable and unserializable.
+ * @param string the name of the controlstate value
+ * @param mixed the controlstate value to be set
+ * @param mixed default value. If $value===$defaultValue, the item will be cleared from controlstate
+ */
+ protected function setControlState($key,$value,$defaultValue=null)
+ {
+ if($value===$defaultValue)
+ unset($this->_rf[self::RF_CONTROLSTATE][$key]);
+ else
+ $this->_rf[self::RF_CONTROLSTATE][$key]=$value;
+ }
+
+ /**
+ * Clears a controlstate value.
+ * @param string the name of the controlstate value to be cleared
+ */
+ protected function clearControlState($key)
+ {
+ unset($this->_rf[self::RF_CONTROLSTATE][$key]);
+ }
+
+ /**
+ * Sets a value indicating whether we should keep data in viewstate.
+ * When it is false, data saved via setViewState() will not be persisted.
+ * By default, it is true, meaning data will be persisted across postbacks.
+ * @param boolean whether data should be persisted
+ */
+ public function trackViewState($enabled)
+ {
+ $this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
+ }
+
+ /**
+ * Returns a viewstate value.
+ *
+ * This function is very useful in defining getter functions for component properties
+ * that must be kept in viewstate.
+ * @param string the name of the viewstate value to be returned
+ * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
+ * @return mixed the viewstate value corresponding to $key
+ */
+ public function getViewState($key,$defaultValue=null)
+ {
+ if(isset($this->_viewState[$key]))
+ return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
+ else if(isset($this->_tempState[$key]))
+ {
+ if(is_object($this->_tempState[$key]) && $this->_trackViewState)
+ $this->_viewState[$key]=$this->_tempState[$key];
+ return $this->_tempState[$key];
+ }
+ else
+ return $defaultValue;
+ }
+
+ /**
+ * Sets a viewstate value.
+ *
+ * This function is very useful in defining setter functions for control properties
+ * that must be kept in viewstate.
+ * Make sure that the viewstate value must be serializable and unserializable.
+ * @param string the name of the viewstate value
+ * @param mixed the viewstate value to be set
+ * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
+ */
+ public function setViewState($key,$value,$defaultValue=null)
+ {
+ if($this->_trackViewState)
+ {
+ $this->_viewState[$key]=$value;
+ unset($this->_tempState[$key]);
+ }
+ else
+ {
+ unset($this->_viewState[$key]);
+ $this->_tempState[$key]=$value;
+ }
+ }
+
+ /**
+ * Clears a viewstate value.
+ * @param string the name of the viewstate value to be cleared
+ */
+ public function clearViewState($key)
+ {
+ unset($this->_viewState[$key]);
+ unset($this->_tempState[$key]);
+ }
+
+ /**
+ * Sets up the binding between a property (or property path) and an expression.
+ * The context of the expression is the template control (or the control itself if it is a page).
+ * @param string the property name, or property path
+ * @param string the expression
+ */
+ public function bindProperty($name,$expression)
+ {
+ $this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
+ }
+
+ /**
+ * Breaks the binding between a property (or property path) and an expression.
+ * @param string the property name (or property path)
+ */
+ public function unbindProperty($name)
+ {
+ unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
+ }
+
+ /**
+ * Sets up the binding between a property (or property path) and an expression.
+ * Unlike regular databinding, the expression bound by this method
+ * is automatically evaluated during {@link prerenderRecursive()}.
+ * The context of the expression is the template control (or the control itself if it is a page).
+ * @param string the property name, or property path
+ * @param string the expression
+ */
+ public function autoBindProperty($name,$expression)
+ {
+ $this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
+ }
+
+ /**
+ * Performs the databinding for this control.
+ */
+ public function dataBind()
+ {
+ $this->dataBindProperties();
+ $this->onDataBinding(null);
+ $this->dataBindChildren();
+ }
+
+ /**
+ * Databinding properties of the control.
+ */
+ protected function dataBindProperties()
+ {
+ Prado::trace("Data bind properties",'System.Web.UI.TControl');
+ if(isset($this->_rf[self::RF_DATA_BINDINGS]))
+ {
+ if(($context=$this->getTemplateControl())===null)
+ $context=$this;
+ foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
+ $this->setSubProperty($property,$context->evaluateExpression($expression));
+ }
+ }
+
+ /**
+ * Auto databinding properties of the control.
+ */
+ protected function autoDataBindProperties()
+ {
+ if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
+ {
+ if(($context=$this->getTemplateControl())===null)
+ $context=$this;
+ foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
+ $this->setSubProperty($property,$context->evaluateExpression($expression));
+ }
+ }
+
+ /**
+ * Databinding child controls.
+ */
+ protected function dataBindChildren()
+ {
+ Prado::trace("dataBindChildren()",'System.Web.UI.TControl');
+ if(isset($this->_rf[self::RF_CONTROLS]))
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ if($control instanceof IBindable)
+ $control->dataBind();
+ }
+ }
+
+ /**
+ * @return boolean whether child controls have been created
+ */
+ final protected function getChildControlsCreated()
+ {
+ return ($this->_flags & self::IS_CHILD_CREATED)!==0;
+ }
+
+ /**
+ * Sets a value indicating whether child controls are created.
+ * If false, any existing child controls will be cleared up.
+ * @param boolean whether child controls are created
+ */
+ final protected function setChildControlsCreated($value)
+ {
+ if($value)
+ $this->_flags |= self::IS_CHILD_CREATED;
+ else
+ {
+ if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
+ $this->getControls()->clear();
+ $this->_flags &= ~self::IS_CHILD_CREATED;
+ }
+ }
+
+ /**
+ * Ensures child controls are created.
+ * If child controls are not created yet, this method will invoke
+ * {@link createChildControls} to create them.
+ */
+ public function ensureChildControls()
+ {
+ if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
+ {
+ try
+ {
+ $this->_flags |= self::IS_CREATING_CHILD;
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->createChildControls();
+ else
+ $this->createChildControls();
+ $this->_flags &= ~self::IS_CREATING_CHILD;
+ $this->_flags |= self::IS_CHILD_CREATED;
+ }
+ catch(Exception $e)
+ {
+ $this->_flags &= ~self::IS_CREATING_CHILD;
+ $this->_flags |= self::IS_CHILD_CREATED;
+ throw $e;
+ }
+ }
+ }
+
+ /**
+ * Creates child controls.
+ * This method can be overriden for controls who want to have their controls.
+ * Do not call this method directly. Instead, call {@link ensureChildControls}
+ * to ensure child controls are created only once.
+ */
+ public function createChildControls()
+ {
+ }
+
+ /**
+ * Finds a control by ID path within the current naming container.
+ * The current naming container is either the control itself
+ * if it implements {@link INamingContainer} or the control's naming container.
+ * The ID path is an ID sequence separated by {@link TControl::ID_SEPARATOR}.
+ * For example, 'Repeater1.Item1.Button1' looks for a control with ID 'Button1'
+ * whose naming container is 'Item1' whose naming container is 'Repeater1'.
+ * @param string ID of the control to be looked up
+ * @return TControl|null the control found, null if not found
+ * @throws TInvalidDataValueException if a control's ID is found not unique within its naming container.
+ */
+ public function findControl($id)
+ {
+ $id=strtr($id,'.',self::ID_SEPARATOR);
+ $container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
+ if(!$container || !$container->getHasControls())
+ return null;
+ if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
+ {
+ $container->_rf[self::RF_NAMED_CONTROLS]=array();
+ $container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
+ }
+ if(($pos=strpos($id,self::ID_SEPARATOR))===false)
+ return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
+ else
+ {
+ $cid=substr($id,0,$pos);
+ $sid=substr($id,$pos+1);
+ if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
+ return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
+ else
+ return null;
+ }
+ }
+
+ /**
+ * Finds all child and grand-child controls that are of the specified type.
+ * @param string the class name
+ * @param boolean whether the type comparison is strict or not. If false, controls of the parent classes of the specified class will also be returned.
+ * @return array list of controls found
+ */
+ public function findControlsByType($type,$strict=true)
+ {
+ $controls=array();
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
+ $controls[]=$control;
+ if(($control instanceof TControl) && $control->getHasControls())
+ $controls=array_merge($controls,$control->findControlsByType($type,$strict));
+ }
+ }
+ return $controls;
+ }
+
+ /**
+ * Finds all child and grand-child controls with the specified ID.
+ * Note, this method is different from {@link findControl} in that
+ * it searches through all controls that have this control as the ancestor
+ * while {@link findcontrol} only searches through controls that have this
+ * control as the direct naming container.
+ * @param string the ID being looked for
+ * @return array list of controls found
+ */
+ public function findControlsByID($id)
+ {
+ $controls=array();
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ if($control->_id===$id)
+ $controls[]=$control;
+ $controls=array_merge($controls,$control->findControlsByID($id));
+ }
+ }
+ }
+ return $controls;
+ }
+
+ /**
+ * Resets the control as a naming container.
+ * Only framework developers should use this method.
+ */
+ public function clearNamingContainer()
+ {
+ unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
+ $this->clearNameTable();
+ }
+
+ /**
+ * Registers an object by a name.
+ * A registered object can be accessed like a public member variable.
+ * This method should only be used by framework and control developers.
+ * @param string name of the object
+ * @param object object to be declared
+ * @see __get
+ */
+ public function registerObject($name,$object)
+ {
+ if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
+ throw new TInvalidOperationException('control_object_reregistered',$name);
+ $this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
+ }
+
+ /**
+ * Unregisters an object by name.
+ * @param string name of the object
+ * @see registerObject
+ */
+ public function unregisterObject($name)
+ {
+ unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
+ }
+
+ /**
+ * @return boolean whether an object has been registered with the name
+ * @see registerObject
+ */
+ public function isObjectRegistered($name)
+ {
+ return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
+ }
+
+ /**
+ * @return boolean true if the child control has been initialized.
+ */
+ public function getHasChildInitialized()
+ {
+ return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
+ }
+
+ /**
+ * @return boolean true if the onInit event has raised.
+ */
+ public function getHasInitialized()
+ {
+ return $this->getControlStage() >= self::CS_INITIALIZED;
+ }
+
+ /**
+ * @return boolean true if the control has loaded post data.
+ */
+ public function getHasLoadedPostData()
+ {
+ return $this->getControlStage() >= self::CS_STATE_LOADED;
+ }
+
+ /**
+ * @return boolean true if the onLoad event has raised.
+ */
+ public function getHasLoaded()
+ {
+ return $this->getControlStage() >= self::CS_LOADED;
+ }
+
+ /**
+ * @return boolean true if onPreRender event has raised.
+ */
+ public function getHasPreRendered()
+ {
+ return $this->getControlStage() >= self::CS_PRERENDERED;
+ }
+
+ /**
+ * Returns the named registered object.
+ * A component with explicit ID on a template will be registered to
+ * the template owner. This method allows you to obtain this component
+ * with the ID.
+ * @return mixed the named registered object. Null if object is not found.
+ */
+ public function getRegisteredObject($name)
+ {
+ return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
+ }
+
+ /**
+ * @return boolean whether body contents are allowed for this control. Defaults to true.
+ */
+ public function getAllowChildControls()
+ {
+ return true;
+ }
+
+ /**
+ * Adds the object instantiated on a template to the child control collection.
+ * This method overrides the parent implementation.
+ * Only framework developers and control developers should use this method.
+ * @param string|TComponent text string or component parsed and instantiated in template
+ * @see createdOnTemplate
+ */
+ public function addParsedObject($object)
+ {
+ $this->getControls()->add($object);
+ }
+
+ /**
+ * Clears up the child state data.
+ * After a control loads its state, those state that do not belong to
+ * any existing child controls are stored as child state.
+ * This method will remove these state.
+ * Only frameworker developers and control developers should use this method.
+ */
+ final protected function clearChildState()
+ {
+ unset($this->_rf[self::RF_CHILD_STATE]);
+ }
+
+ /**
+ * @param TControl the potential ancestor control
+ * @return boolean if the control is a descendent (parent, parent of parent, etc.)
+ * of the specified control
+ */
+ final protected function isDescendentOf($ancestor)
+ {
+ $control=$this;
+ while($control!==$ancestor && $control->_parent)
+ $control=$control->_parent;
+ return $control===$ancestor;
+ }
+
+ /**
+ * Adds a control into the child collection of the control.
+ * Control lifecycles will be caught up during the addition.
+ * Only framework developers should use this method.
+ * @param TControl the new child control
+ */
+ public function addedControl($control)
+ {
+ if($control->_parent)
+ $control->_parent->getControls()->remove($control);
+ $control->_parent=$this;
+ $control->_page=$this->getPage();
+ $namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
+ if($namingContainer)
+ {
+ $control->_namingContainer=$namingContainer;
+ if($control->_id==='')
+ $control->generateAutomaticID();
+ else
+ $namingContainer->clearNameTable();
+ $control->clearCachedUniqueID($control instanceof INamingContainer);
+ }
+
+ if($this->_stage>=self::CS_CHILD_INITIALIZED)
+ {
+ $control->initRecursive($namingContainer);
+ if($this->_stage>=self::CS_STATE_LOADED)
+ {
+ if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
+ {
+ $state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
+ unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
+ }
+ else
+ $state=null;
+ $control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
+ if($this->_stage>=self::CS_LOADED)
+ {
+ $control->loadRecursive();
+ if($this->_stage>=self::CS_PRERENDERED)
+ $control->preRenderRecursive();
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes a control from the child collection of the control.
+ * Only framework developers should use this method.
+ * @param TControl the child control removed
+ */
+ public function removedControl($control)
+ {
+ if($this->_namingContainer)
+ $this->_namingContainer->clearNameTable();
+ $control->unloadRecursive();
+ $control->_parent=null;
+ $control->_page=null;
+ $control->_namingContainer=null;
+ $control->_tplControl=null;
+ //$control->_stage=self::CS_CONSTRUCTED;
+ if(!($control->_flags & self::IS_ID_SET))
+ $control->_id='';
+ else
+ unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
+ $control->clearCachedUniqueID(true);
+ }
+
+ /**
+ * Performs the Init step for the control and all its child controls.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function initRecursive($namingContainer=null)
+ {
+ $this->ensureChildControls();
+ if($this->getHasControls())
+ {
+ if($this instanceof INamingContainer)
+ $namingContainer=$this;
+ $page=$this->getPage();
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ $control->_namingContainer=$namingContainer;
+ $control->_page=$page;
+ if($control->_id==='' && $namingContainer)
+ $control->generateAutomaticID();
+ $control->initRecursive($namingContainer);
+ }
+ }
+ }
+ if($this->_stage<self::CS_INITIALIZED)
+ {
+ $this->_stage=self::CS_CHILD_INITIALIZED;
+ if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
+ {
+ $page->applyControlSkin($this);
+ $this->_flags |= self::IS_SKIN_APPLIED;
+ }
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onInit(null);
+ else
+ $this->onInit(null);
+ $this->_stage=self::CS_INITIALIZED;
+ }
+ }
+
+ /**
+ * Performs the Load step for the control and all its child controls.
+ * Only framework developers should use this method.
+ */
+ protected function loadRecursive()
+ {
+ if($this->_stage<self::CS_LOADED)
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onLoad(null);
+ else
+ $this->onLoad(null);
+ }
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $control->loadRecursive();
+ }
+ }
+ if($this->_stage<self::CS_LOADED)
+ $this->_stage=self::CS_LOADED;
+ }
+
+ /**
+ * Performs the PreRender step for the control and all its child controls.
+ * Only framework developers should use this method.
+ */
+ protected function preRenderRecursive()
+ {
+ $this->autoDataBindProperties();
+
+ if($this->getVisible(false))
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onPreRender(null);
+ else
+ $this->onPreRender(null);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $control->preRenderRecursive();
+ else if($control instanceof TCompositeLiteral)
+ $control->evaluateDynamicContent();
+ }
+ }
+ }
+ $this->_stage=self::CS_PRERENDERED;
+ }
+
+ /**
+ * Performs the Unload step for the control and all its child controls.
+ * Only framework developers should use this method.
+ */
+ protected function unloadRecursive()
+ {
+ if(!($this->_flags & self::IS_ID_SET))
+ $this->_id='';
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ if($control instanceof TControl)
+ $control->unloadRecursive();
+ }
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onUnload(null);
+ else
+ $this->onUnload(null);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnInit' stage.
+ * The method raises 'OnInit' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onInit($param)
+ {
+ $this->raiseEvent('OnInit',$this,$param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnLoad' stage.
+ * The method raises 'OnLoad' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onLoad($param)
+ {
+ $this->raiseEvent('OnLoad',$this,$param);
+ }
+
+ /**
+ * Raises 'OnDataBinding' event.
+ * This method is invoked when {@link dataBind} is invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onDataBinding($param)
+ {
+ Prado::trace("onDataBinding()",'System.Web.UI.TControl');
+ $this->raiseEvent('OnDataBinding',$this,$param);
+ }
+
+
+ /**
+ * This method is invoked when the control enters 'OnUnload' stage.
+ * The method raises 'OnUnload' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onUnload($param)
+ {
+ $this->raiseEvent('OnUnload',$this,$param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnPreRender' stage.
+ * The method raises 'OnPreRender' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onPreRender($param)
+ {
+ $this->raiseEvent('OnPreRender',$this,$param);
+ }
+
+ /**
+ * Invokes the parent's bubbleEvent method.
+ * A control who wants to bubble an event must call this method in its onEvent method.
+ * @param TControl sender of the event
+ * @param TEventParameter event parameter
+ * @see bubbleEvent
+ */
+ protected function raiseBubbleEvent($sender,$param)
+ {
+ $control=$this;
+ while($control=$control->_parent)
+ {
+ if($control->bubbleEvent($sender,$param))
+ break;
+ }
+ }
+
+ /**
+ * This method responds to a bubbled event.
+ * This method should be overriden to provide customized response to a bubbled event.
+ * Check the type of event parameter to determine what event is bubbled currently.
+ * @param TControl sender of the event
+ * @param TEventParameter event parameters
+ * @return boolean true if the event bubbling is handled and no more bubbling.
+ * @see raiseBubbleEvent
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ return false;
+ }
+
+ /**
+ * Broadcasts an event.
+ * The event will be sent to all controls on the current page hierarchy.
+ * If a control defines the event, the event will be raised for the control.
+ * If a control implements {@link IBroadcastEventReceiver}, its
+ * {@link IBroadcastEventReceiver::broadcastEventReceived broadcastEventReceived()} method will
+ * be invoked which gives the control a chance to respond to the event.
+ * For example, when broadcasting event 'OnClick', all controls having 'OnClick'
+ * event will have this event raised, and all controls implementing
+ * {@link IBroadcastEventReceiver} will also have its
+ * {@link IBroadcastEventReceiver::broadcastEventReceived broadcastEventReceived()}
+ * invoked.
+ * @param string name of the broadcast event
+ * @param TControl sender of this event
+ * @param TEventParameter event parameter
+ */
+ public function broadcastEvent($name,$sender,$param)
+ {
+ $rootControl=(($page=$this->getPage())===null)?$this:$page;
+ $rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
+ }
+
+ /**
+ * Recursively broadcasts an event.
+ * This method should only be used by framework developers.
+ * @param string name of the broadcast event
+ * @param TControl sender of the event
+ * @param TBroadcastEventParameter event parameter
+ */
+ private function broadcastEventInternal($name,$sender,$param)
+ {
+ if($this->hasEvent($name))
+ $this->raiseEvent($name,$sender,$param->getParameter());
+ if($this instanceof IBroadcastEventReceiver)
+ $this->broadcastEventReceived($sender,$param);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $control->broadcastEventInternal($name,$sender,$param);
+ }
+ }
+ }
+
+ /**
+ * Traverse the whole control hierarchy rooted at this control.
+ * Callback function may be invoked for each control being visited.
+ * A pre-callback is invoked before traversing child controls;
+ * A post-callback is invoked after traversing child controls.
+ * Callback functions can be global functions or class methods.
+ * They must be of the following signature:
+ * <code>
+ * function callback_func($control,$param) {...}
+ * </code>
+ * where $control refers to the control being visited and $param
+ * is the parameter that is passed originally when calling this traverse function.
+ *
+ * @param mixed parameter to be passed to callbacks for each control
+ * @param callback callback invoked before traversing child controls. If null, it is ignored.
+ * @param callback callback invoked after traversing child controls. If null, it is ignored.
+ */
+ protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
+ {
+ if($preCallback!==null)
+ call_user_func($preCallback,$this,$param);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ $control->traverseChildControls($param,$preCallback,$postCallback);
+ }
+ }
+ }
+ if($postCallback!==null)
+ call_user_func($postCallback,$this,$param);
+ }
+
+ /**
+ * Renders the control.
+ * Only when the control is visible will the control be rendered.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderControl($writer)
+ {
+ if($this instanceof IActiveControl || $this->getVisible(false))
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->render($writer);
+ else
+ $this->render($writer);
+ }
+ }
+
+ /**
+ * Renders the control.
+ * This method is invoked by {@link renderControl} when the control is visible.
+ * You can override this method to provide customized rendering of the control.
+ * By default, the control simply renders all its child contents.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ $this->renderChildren($writer);
+ }
+
+ /**
+ * Renders the children of the control.
+ * This method iterates through all child controls and static text strings
+ * and renders them in order.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderChildren($writer)
+ {
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if(is_string($control))
+ $writer->write($control);
+ else if($control instanceof TControl)
+ $control->renderControl($writer);
+ else if($control instanceof IRenderable)
+ $control->render($writer);
+ }
+ }
+ }
+
+ /**
+ * This method is invoked when control state is to be saved.
+ * You can override this method to do last step state saving.
+ * Parent implementation must be invoked.
+ */
+ public function saveState()
+ {
+ }
+
+ /**
+ * This method is invoked right after the control has loaded its state.
+ * You can override this method to initialize data from the control state.
+ * Parent implementation must be invoked.
+ */
+ public function loadState()
+ {
+ }
+
+ /**
+ * Loads state (viewstate and controlstate) into a control and its children.
+ * This method should only be used by framework developers.
+ * @param array the collection of the state
+ * @param boolean whether the viewstate should be loaded
+ */
+ protected function loadStateRecursive(&$state,$needViewState=true)
+ {
+ if(is_array($state))
+ {
+ // A null state means the stateful properties all take default values.
+ // So if the state is enabled, we have to assign the null value.
+ $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
+ if(isset($state[1]))
+ {
+ $this->_rf[self::RF_CONTROLSTATE]=&$state[1];
+ unset($state[1]);
+ }
+ else
+ unset($this->_rf[self::RF_CONTROLSTATE]);
+ if($needViewState)
+ {
+ if(isset($state[0]))
+ $this->_viewState=&$state[0];
+ else
+ $this->_viewState=array();
+ }
+ unset($state[0]);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ if(isset($state[$control->_id]))
+ {
+ $control->loadStateRecursive($state[$control->_id],$needViewState);
+ unset($state[$control->_id]);
+ }
+ }
+ }
+ }
+ if(!empty($state))
+ $this->_rf[self::RF_CHILD_STATE]=&$state;
+ }
+ $this->_stage=self::CS_STATE_LOADED;
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->loadState();
+ else
+ $this->loadState();
+ }
+
+ /**
+ * Saves all control state (viewstate and controlstate) as a collection.
+ * This method should only be used by framework developers.
+ * @param boolean whether the viewstate should be saved
+ * @return array the collection of the control state (including its children's state).
+ */
+ protected function &saveStateRecursive($needViewState=true)
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->saveState();
+ else
+ $this->saveState();
+ $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
+ $state=array();
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $state[$control->_id]=&$control->saveStateRecursive($needViewState);
+ }
+ }
+ if($needViewState && !empty($this->_viewState))
+ $state[0]=&$this->_viewState;
+ if(isset($this->_rf[self::RF_CONTROLSTATE]))
+ $state[1]=&$this->_rf[self::RF_CONTROLSTATE];
+ return $state;
+ }
+
+ /**
+ * Applies a stylesheet skin to a control.
+ * @param TPage the page containing the control
+ * @throws TInvalidOperationException if the stylesheet skin is applied already
+ */
+ public function applyStyleSheetSkin($page)
+ {
+ if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
+ {
+ $page->applyControlStyleSheet($this);
+ $this->_flags |= self::IS_STYLESHEET_APPLIED;
+ }
+ else if($this->_flags & self::IS_STYLESHEET_APPLIED)
+ throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
+ }
+
+ /**
+ * Clears the cached UniqueID.
+ * If $recursive=true, all children's cached UniqueID will be cleared as well.
+ * @param boolean whether the clearing is recursive.
+ */
+ private function clearCachedUniqueID($recursive)
+ {
+ if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ if($control instanceof TControl)
+ $control->clearCachedUniqueID($recursive);
+ }
+ $this->_uid=null;
+ }
+
+ /**
+ * Generates an automatic ID for the control.
+ */
+ private function generateAutomaticID()
+ {
+ $this->_flags &= ~self::IS_ID_SET;
+ if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]))
+ $this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0;
+ $id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++;
+ $this->_id=self::AUTOMATIC_ID_PREFIX . $id;
+ $this->_namingContainer->clearNameTable();
+ }
+
+ /**
+ * Clears the list of the controls whose IDs are managed by the specified naming container.
+ */
+ private function clearNameTable()
+ {
+ unset($this->_rf[self::RF_NAMED_CONTROLS]);
+ }
+
+ /**
+ * Updates the list of the controls whose IDs are managed by the specified naming container.
+ * @param TControl the naming container
+ * @param TControlCollection list of controls
+ * @throws TInvalidDataValueException if a control's ID is not unique within its naming container.
+ */
+ private function fillNameTable($container,$controls)
+ {
+ foreach($controls as $control)
+ {
+ if($control instanceof TControl)
+ {
+ if($control->_id!=='')
+ {
+ if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
+ throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
+ else
+ $container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
+ }
+ if(!($control instanceof INamingContainer) && $control->getHasControls())
+ $this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
+ }
+ }
+ }
+}
+
+
+/**
+ * TControlCollection class
+ *
+ * TControlCollection implements a collection that enables
+ * controls to maintain a list of their child controls.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TControlCollection extends TList
+{
+ /**
+ * the control that owns this collection.
+ * @var TControl
+ */
+ private $_o;
+
+ /**
+ * Constructor.
+ * @param TControl the control that owns this collection.
+ * @param boolean whether the list is read-only
+ */
+ public function __construct(TControl $owner,$readOnly=false)
+ {
+ $this->_o=$owner;
+ parent::__construct(null,$readOnly);
+ }
+
+ /**
+ * @return TControl the control that owns this collection.
+ */
+ protected function getOwner()
+ {
+ return $this->_o;
+ }
+
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing additional
+ * operations for each newly added child control.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is neither a string nor a TControl.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TControl)
+ {
+ parent::insertAt($index,$item);
+ $this->_o->addedControl($item);
+ }
+ else if(is_string($item) || ($item instanceof IRenderable))
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('controlcollection_control_required');
+ }
+
+ /**
+ * Removes an item at the specified position.
+ * This overrides the parent implementation by performing additional
+ * cleanup work when removing a child control.
+ * @param integer the index of the item to be removed.
+ * @return mixed the removed item.
+ */
+ public function removeAt($index)
+ {
+ $item=parent::removeAt($index);
+ if($item instanceof TControl)
+ $this->_o->removedControl($item);
+ return $item;
+ }
+
+ /**
+ * Overrides the parent implementation by invoking {@link TControl::clearNamingContainer}
+ */
+ public function clear()
+ {
+ parent::clear();
+ if($this->_o instanceof INamingContainer)
+ $this->_o->clearNamingContainer();
+ }
+}
+
+/**
+ * TEmptyControlCollection class
+ *
+ * TEmptyControlCollection implements an empty control list that prohibits adding
+ * controls to it. This is useful for controls that do not allow child controls.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TEmptyControlCollection extends TControlCollection
+{
+ /**
+ * Constructor.
+ * @param TControl the control that owns this collection.
+ */
+ public function __construct(TControl $owner)
+ {
+ parent::__construct($owner,true);
+ }
+
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by ignoring new addition.
+ * @param integer the speicified position.
+ * @param mixed new item
+ */
+ public function insertAt($index,$item)
+ {
+ if(!is_string($item)) // string is possible if property tag is used. we simply ignore it in this case
+ parent::insertAt($index,$item); // this will generate an exception in parent implementation
+ }
+}
+
+/**
+ * INamingContainer interface.
+ * INamingContainer marks a control as a naming container.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface INamingContainer
+{
+}
+
+/**
+ * IPostBackEventHandler interface
+ *
+ * If a control wants to respond to postback event, it must implement this interface.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IPostBackEventHandler
+{
+ /**
+ * Raises postback event.
+ * The implementation of this function should raise appropriate event(s) (e.g. OnClick, OnCommand)
+ * indicating the component is responsible for the postback event.
+ * @param string the parameter associated with the postback event
+ */
+ public function raisePostBackEvent($param);
+}
+
+/**
+ * IPostBackDataHandler interface
+ *
+ * If a control wants to load post data, it must implement this interface.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IPostBackDataHandler
+{
+ /**
+ * Loads user input data.
+ * The implementation of this function can use $values[$key] to get the user input
+ * data that are meant for the particular control.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values);
+ /**
+ * Raises postdata changed event.
+ * The implementation of this function should raise appropriate event(s) (e.g. OnTextChanged)
+ * indicating the control data is changed.
+ */
+ public function raisePostDataChangedEvent();
+ /**
+ * @return boolean whether postback causes the data change. Defaults to false for non-postback state.
+ */
+ public function getDataChanged();
+}
+
+
+/**
+ * IValidator interface
+ *
+ * If a control wants to validate user input, it must implement this interface.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IValidator
+{
+ /**
+ * Validates certain data.
+ * The implementation of this function should validate certain data
+ * (e.g. data entered into TTextBox control).
+ * @return boolean whether the data passes the validation
+ */
+ public function validate();
+ /**
+ * @return boolean whether the previous {@link validate()} is successful.
+ */
+ public function getIsValid();
+ /**
+ * @param boolean whether the validator validates successfully
+ */
+ public function setIsValid($value);
+ /**
+ * @return string error message during last validate
+ */
+ public function getErrorMessage();
+ /**
+ * @param string error message for the validation
+ */
+ public function setErrorMessage($value);
+}
+
+
+/**
+ * IValidatable interface
+ *
+ * If a control wants to be validated by a validator, it must implement this interface.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IValidatable
+{
+ /**
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue();
+ /**
+ * @return boolean wether this control's validators validated successfully (must default to true)
+ */
+ public function getIsValid();
+ /**
+ * @return boolean wether this control's validators validated successfully
+ */
+ public function setIsValid($value);
+}
+
+/**
+ * IBroadcastEventReceiver interface
+ *
+ * If a control wants to check broadcast event, it must implement this interface.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IBroadcastEventReceiver
+{
+ /**
+ * Handles broadcast event.
+ * This method is invoked automatically when an event is broadcasted.
+ * Within this method, you may check the event name given in
+ * the event parameter to determine whether you should respond to
+ * this event.
+ * @param TControl sender of the event
+ * @param TBroadCastEventParameter event parameter
+ */
+ public function broadcastEventReceived($sender,$param);
+}
+
+/**
+ * ITheme interface.
+ *
+ * This interface must be implemented by theme.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface ITheme
+{
+ /**
+ * Applies this theme to the specified control.
+ * @param TControl the control to be applied with this theme
+ */
+ public function applySkin($control);
+}
+
+/**
+ * ITemplate interface
+ *
+ * ITemplate specifies the interface for classes encapsulating
+ * parsed template structures.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface ITemplate
+{
+ /**
+ * Instantiates the template.
+ * Content in the template will be instantiated as components and text strings
+ * and passed to the specified parent control.
+ * @param TControl the parent control
+ */
+ public function instantiateIn($parent);
+}
+
+/**
+ * IButtonControl interface
+ *
+ * IButtonControl specifies the common properties and events that must
+ * be implemented by a button control, such as {@link TButton}, {@link TLinkButton},
+ * {@link TImageButton}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IButtonControl
+{
+ /**
+ * @return string caption of the button
+ */
+ public function getText();
+
+ /**
+ * @param string caption of the button
+ */
+ public function setText($value);
+
+ /**
+ * @return boolean whether postback event trigger by this button will cause input validation
+ */
+ public function getCausesValidation();
+
+ /**
+ * @param boolean whether postback event trigger by this button will cause input validation
+ */
+ public function setCausesValidation($value);
+
+ /**
+ * @return string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function getCommandName();
+
+ /**
+ * @param string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandName($value);
+
+ /**
+ * @return string the parameter associated with the {@link onCommand OnCommand} event
+ */
+ public function getCommandParameter();
+
+ /**
+ * @param string the parameter associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandParameter($value);
+
+ /**
+ * @return string the group of validators which the button causes validation upon postback
+ */
+ public function getValidationGroup();
+
+ /**
+ * @param string the group of validators which the button causes validation upon postback
+ */
+ public function setValidationGroup($value);
+
+ /**
+ * Raises <b>OnClick</b> event.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onClick($param);
+
+ /**
+ * Raises <b>OnCommand</b> event.
+ * @param TCommandEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCommand($param);
+
+ /**
+ * @param boolean set by a panel to register this button as the default button for the panel.
+ */
+ public function setIsDefaultButton($value);
+
+ /**
+ * @return boolean true if this button is registered as a default button for a panel.
+ */
+ public function getIsDefaultButton();
+}
+
+/**
+ * ISurroundable interface
+ *
+ * Identifies controls that may create an additional surrounding tag. The id of the
+ * tag can be obtained with {@link getSurroundingTagID}, the tag used to render the
+ * surrounding container is obtained by {@link getSurroundingTag}.
+ *
+ * @package System.Web.UI
+ * @since 3.1.2
+ */
+interface ISurroundable
+{
+ /**
+ * @return string the tag used to wrap the control in (if surrounding is needed).
+ */
+ public function getSurroundingTag();
+
+ /**
+ * @return string the id of the embedding tag of the control or the control's clientID if not surrounded.
+ */
+ public function getSurroundingTagID();
+}
+
+/**
+ * TBroadcastEventParameter class
+ *
+ * TBroadcastEventParameter encapsulates the parameter data for
+ * events that are broadcasted. The name of of the event is specified via
+ * {@link setName Name} property while the event parameter is via
+ * {@link setParameter Parameter} property.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TBroadcastEventParameter extends TEventParameter
+{
+ private $_name;
+ private $_param;
+
+ /**
+ * Constructor.
+ * @param string name of the broadcast event
+ * @param mixed parameter of the broadcast event
+ */
+ public function __construct($name='',$parameter=null)
+ {
+ $this->_name=$name;
+ $this->_param=$parameter;
+ }
+
+ /**
+ * @return string name of the broadcast event
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @param string name of the broadcast event
+ */
+ public function setName($value)
+ {
+ $this->_name=$value;
+ }
+
+ /**
+ * @return mixed parameter of the broadcast event
+ */
+ public function getParameter()
+ {
+ return $this->_param;
+ }
+
+ /**
+ * @param mixed parameter of the broadcast event
+ */
+ public function setParameter($value)
+ {
+ $this->_param=$value;
+ }
+}
+
+/**
+ * TCommandEventParameter class
+ *
+ * TCommandEventParameter encapsulates the parameter data for <b>Command</b>
+ * event of button controls. You can access the name of the command via
+ * {@link getCommandName CommandName} property, and the parameter carried
+ * with the command via {@link getCommandParameter CommandParameter} property.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TCommandEventParameter extends TEventParameter
+{
+ private $_name;
+ private $_param;
+
+ /**
+ * Constructor.
+ * @param string name of the command
+ * @param string parameter of the command
+ */
+ public function __construct($name='',$parameter='')
+ {
+ $this->_name=$name;
+ $this->_param=$parameter;
+ }
+
+ /**
+ * @return string name of the command
+ */
+ public function getCommandName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @return string parameter of the command
+ */
+ public function getCommandParameter()
+ {
+ return $this->_param;
+ }
+}
+
+
+/**
+ * TCompositeLiteral class
+ *
+ * TCompositeLiteral is used internally by {@link TTemplate} for representing
+ * consecutive static strings, expressions and statements.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TCompositeLiteral extends TComponent implements IRenderable, IBindable
+{
+ const TYPE_EXPRESSION=0;
+ const TYPE_STATEMENTS=1;
+ const TYPE_DATABINDING=2;
+ private $_container=null;
+ private $_items=array();
+ private $_expressions=array();
+ private $_statements=array();
+ private $_bindings=array();
+
+ /**
+ * Constructor.
+ * @param array list of items to be represented by TCompositeLiteral
+ */
+ public function __construct($items)
+ {
+ $this->_items=array();
+ $this->_expressions=array();
+ $this->_statements=array();
+ foreach($items as $id=>$item)
+ {
+ if(is_array($item))
+ {
+ if($item[0]===self::TYPE_EXPRESSION)
+ $this->_expressions[$id]=$item[1];
+ else if($item[0]===self::TYPE_STATEMENTS)
+ $this->_statements[$id]=$item[1];
+ else if($item[0]===self::TYPE_DATABINDING)
+ $this->_bindings[$id]=$item[1];
+ $this->_items[$id]='';
+ }
+ else
+ $this->_items[$id]=$item;
+ }
+ }
+
+ /**
+ * @return TComponent container of this component. It serves as the evaluation context of expressions and statements.
+ */
+ public function getContainer()
+ {
+ return $this->_container;
+ }
+
+ /**
+ * @param TComponent container of this component. It serves as the evaluation context of expressions and statements.
+ */
+ public function setContainer(TComponent $value)
+ {
+ $this->_container=$value;
+ }
+
+ /**
+ * Evaluates the expressions and/or statements in the component.
+ */
+ public function evaluateDynamicContent()
+ {
+ $context=$this->_container===null?$this:$this->_container;
+ foreach($this->_expressions as $id=>$expression)
+ $this->_items[$id]=$context->evaluateExpression($expression);
+ foreach($this->_statements as $id=>$statement)
+ $this->_items[$id]=$context->evaluateStatements($statement);
+ }
+
+ /**
+ * Performs databindings.
+ * This method is required by {@link IBindable}
+ */
+ public function dataBind()
+ {
+ $context=$this->_container===null?$this:$this->_container;
+ foreach($this->_bindings as $id=>$binding)
+ $this->_items[$id]=$context->evaluateExpression($binding);
+ }
+
+ /**
+ * Renders the content stored in this component.
+ * This method is required by {@link IRenderable}
+ * @param ITextWriter
+ */
+ public function render($writer)
+ {
+ $writer->write(implode('',$this->_items));
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/TControlAdapter.php b/lib/prado/framework/Web/UI/TControlAdapter.php
new file mode 100644
index 0000000..3abc004
--- /dev/null
+++ b/lib/prado/framework/Web/UI/TControlAdapter.php
@@ -0,0 +1,141 @@
+<?php
+/**
+ * TControlAdapter class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+/**
+ * TControlAdapter class
+ *
+ * TControlAdapter is the base class for adapters that customize
+ * various behaviors for the control to which the adapter is attached.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TControlAdapter extends TApplicationComponent
+{
+ /**
+ * @var TControl the control to which the adapter is attached
+ */
+ protected $_control;
+
+ /**
+ * Constructor.
+ * @param TControl the control to which the adapter is attached
+ */
+ public function __construct($control)
+ {
+ $this->_control=$control;
+ }
+
+ /**
+ * @return TControl the control to which this adapter is attached
+ */
+ public function getControl()
+ {
+ return $this->_control;
+ }
+
+ /**
+ * @return TPage the page that contains the attached control
+ */
+ public function getPage()
+ {
+ return $this->_control?$this->_control->getPage():null;
+ }
+
+ /**
+ * Creates child controls for the attached control.
+ * Default implementation calls the attached control's corresponding method.
+ */
+ public function createChildControls()
+ {
+ $this->_control->createChildControls();
+ }
+
+ /**
+ * Loads additional persistent control state.
+ * Default implementation calls the attached control's corresponding method.
+ */
+ public function loadState()
+ {
+ $this->_control->loadState();
+ }
+
+ /**
+ * Saves additional persistent control state.
+ * Default implementation calls the attached control's corresponding method.
+ */
+ public function saveState()
+ {
+ $this->_control->saveState();
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnInit' stage.
+ * Default implementation calls the attached control's corresponding method.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onInit($param)
+ {
+ $this->_control->onInit($param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnLoad' stage.
+ * Default implementation calls the attached control's corresponding method.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onLoad($param)
+ {
+ $this->_control->onLoad($param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnPreRender' stage.
+ * Default implementation calls the attached control's corresponding method.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onPreRender($param)
+ {
+ $this->_control->onPreRender($param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnUnload' stage.
+ * Default implementation calls the attached control's corresponding method.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onUnload($param)
+ {
+ $this->_control->onUnload($param);
+ }
+
+ /**
+ * This method is invoked when the control renders itself.
+ * Default implementation calls the attached control's corresponding method.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+ $this->_control->render($writer);
+ }
+
+ /**
+ * Renders the control's children.
+ * Default implementation calls the attached control's corresponding method.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderChildren($writer)
+ {
+ $this->_control->renderChildren($writer);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/TForm.php b/lib/prado/framework/Web/UI/TForm.php
new file mode 100644
index 0000000..a6fe355
--- /dev/null
+++ b/lib/prado/framework/Web/UI/TForm.php
@@ -0,0 +1,169 @@
+<?php
+/**
+ * TForm class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+/**
+ * TForm class
+ *
+ * TForm displays an HTML form. Besides regular body content,
+ * it displays hidden fields, javascript blocks and files that are registered
+ * through {@link TClientScriptManager}.
+ *
+ * A TForm is required for a page that needs postback.
+ * Each page can contain at most one TForm. If multiple HTML forms are needed,
+ * please use regular HTML form tags for those forms that post to different
+ * URLs.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TForm extends TControl
+{
+ /**
+ * Registers the form with the page.
+ * @param mixed event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $this->getPage()->setForm($this);
+ }
+
+ /**
+ * Adds form specific attributes to renderer.
+ * @param THtmlWriter writer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $writer->addAttribute('method',$this->getMethod());
+ $uri=$this->getRequest()->getRequestURI();
+ $writer->addAttribute('action',str_replace('&','&amp;',str_replace('&amp;','&',$uri)));
+ if(($enctype=$this->getEnctype())!=='')
+ $writer->addAttribute('enctype',$enctype);
+
+ $attributes=$this->getAttributes();
+ $attributes->remove('action');
+ $writer->addAttributes($attributes);
+
+ if(($butt=$this->getDefaultButton())!=='')
+ {
+ if(($button=$this->findControl($butt))!==null)
+ $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
+ else
+ throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
+ }
+ }
+
+ /**
+ * Renders the form.
+ * @param THtmlWriter writer
+ */
+ public function render($writer)
+ {
+ $page=$this->getPage();
+
+ $this->addAttributesToRender($writer);
+ $writer->renderBeginTag('form');
+
+ $cs=$page->getClientScript();
+ if($page->getClientSupportsJavaScript())
+ {
+ $cs->renderHiddenFieldsBegin($writer);
+ $cs->renderScriptFilesBegin($writer);
+ $cs->renderBeginScripts($writer);
+
+ $page->beginFormRender($writer);
+ $this->renderChildren($writer);
+ $cs->renderHiddenFieldsEnd($writer);
+ $page->endFormRender($writer);
+
+ $cs->renderScriptFilesEnd($writer);
+ $cs->renderEndScripts($writer);
+ }
+ else
+ {
+ $cs->renderHiddenFieldsBegin($writer);
+
+ $page->beginFormRender($writer);
+ $this->renderChildren($writer);
+ $page->endFormRender($writer);
+
+ $cs->renderHiddenFieldsEnd($writer);
+ }
+
+ $writer->renderEndTag();
+ }
+
+ /**
+ * @return string id path to the default button control.
+ */
+ public function getDefaultButton()
+ {
+ return $this->getViewState('DefaultButton','');
+ }
+
+ /**
+ * Sets a button to be default one in a form.
+ * A default button will be clicked if a user presses 'Enter' key within
+ * the form.
+ * @param string id path to the default button control.
+ */
+ public function setDefaultButton($value)
+ {
+ $this->setViewState('DefaultButton',$value,'');
+ }
+
+ /**
+ * @return string form submission method. Defaults to 'post'.
+ */
+ public function getMethod()
+ {
+ return $this->getViewState('Method','post');
+ }
+
+ /**
+ * @param string form submission method. Valid values include 'post' and 'get'.
+ */
+ public function setMethod($value)
+ {
+ $this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
+ }
+
+ /**
+ * @return string the encoding type a browser uses to post data back to the server
+ */
+ public function getEnctype()
+ {
+ return $this->getViewState('Enctype','');
+ }
+
+ /**
+ * @param string the encoding type a browser uses to post data back to the server.
+ * Commonly used types include
+ * - application/x-www-form-urlencoded : Form data is encoded as name/value pairs. This is the standard encoding format.
+ * - multipart/form-data : Form data is encoded as a message with a separate part for each control on the page.
+ * - text/plain : Form data is encoded in plain text, without any control or formatting characters.
+ */
+ public function setEnctype($value)
+ {
+ $this->setViewState('Enctype',$value,'');
+ }
+
+ /**
+ * @return string form name, which is equal to {@link getUniqueID UniqueID}.
+ */
+ public function getName()
+ {
+ return $this->getUniqueID();
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/THtmlWriter.php b/lib/prado/framework/Web/UI/THtmlWriter.php
new file mode 100644
index 0000000..9c0c599
--- /dev/null
+++ b/lib/prado/framework/Web/UI/THtmlWriter.php
@@ -0,0 +1,227 @@
+<?php
+/**
+ * THtmlWriter class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+/**
+ * THtmlWriter class
+ *
+ * THtmlWriter is a writer that renders valid XHTML outputs.
+ * It provides functions to render tags, their attributes and stylesheet fields.
+ * Attribute and stylesheet values will be automatically HTML-encoded if
+ * they require so. For example, the 'value' attribute in an input tag
+ * will be encoded.
+ *
+ * A common usage of THtmlWriter is as the following sequence:
+ * <code>
+ * $writer->addAttribute($name1,$value1);
+ * $writer->addAttribute($name2,$value2);
+ * $writer->renderBeginTag($tagName);
+ * // ... render contents enclosed within the tag here
+ * $writer->renderEndTag();
+ * </code>
+ * Make sure each invocation of {@link renderBeginTag} is accompanied with
+ * a {@link renderEndTag} and they are properly nested, like nesting
+ * tags in HTML and XHTML.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class THtmlWriter extends TApplicationComponent implements ITextWriter
+{
+ /**
+ * @var array list of tags are do not need a closing tag
+ */
+ private static $_simpleTags=array(
+ 'area'=>true,
+ 'base'=>true,
+ 'basefont'=>true,
+ 'bgsound'=>true,
+ 'col'=>true,
+ 'embed'=>true,
+ 'frame'=>true,
+ 'hr'=>true,
+ 'img'=>true,
+ 'input'=>true,
+ 'isindex'=>true,
+ 'link'=>true,
+ 'meta'=>true,
+ 'wbr'=>true,
+ );
+ /**
+ * @var array list of attributes to be rendered for a tag
+ */
+ private $_attributes=array();
+ /**
+ * @var array list of openning tags
+ */
+ private $_openTags=array();
+ /**
+ * @var array list of style attributes
+ */
+ private $_styles=array();
+ /**
+ * @var ITextWriter writer
+ */
+ private $_writer=null;
+
+ /**
+ * Constructor.
+ * @param ITextWriter a writer that THtmlWriter will pass its rendering result to
+ */
+ public function __construct($writer)
+ {
+ $this->_writer=$writer;
+ }
+
+ public function getWriter()
+ {
+ return $this->_writer;
+ }
+
+ public function setWriter($writer)
+ {
+ $this->_writer = $writer;
+ }
+ /**
+ * Adds a list of attributes to be rendered.
+ * @param array list of attributes to be rendered
+ */
+ public function addAttributes($attrs)
+ {
+ foreach($attrs as $name=>$value)
+ $this->_attributes[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
+ }
+
+ /**
+ * Adds an attribute to be rendered.
+ * @param string name of the attribute
+ * @param string value of the attribute
+ */
+ public function addAttribute($name,$value)
+ {
+ $this->_attributes[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
+ }
+
+ /**
+ * Removes the named attribute from rendering
+ * @param string name of the attribute to be removed
+ */
+ public function removeAttribute($name)
+ {
+ unset($this->_attributes[THttpUtility::htmlStrip($name)]);
+ }
+
+ /**
+ * Adds a list of stylesheet attributes to be rendered.
+ * @param array list of stylesheet attributes to be rendered
+ */
+ public function addStyleAttributes($attrs)
+ {
+ foreach($attrs as $name=>$value)
+ $this->_styles[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
+ }
+
+ /**
+ * Adds a stylesheet attribute to be rendered
+ * @param string stylesheet attribute name
+ * @param string stylesheet attribute value
+ */
+ public function addStyleAttribute($name,$value)
+ {
+ $this->_styles[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
+ }
+
+ /**
+ * Removes the named stylesheet attribute from rendering
+ * @param string name of the stylesheet attribute to be removed
+ */
+ public function removeStyleAttribute($name)
+ {
+ unset($this->_styles[THttpUtility::htmlStrip($name)]);
+ }
+
+ /**
+ * Flushes the rendering result.
+ * This will invoke the underlying writer's flush method.
+ * @return string the content being flushed
+ */
+ public function flush()
+ {
+ return $this->_writer->flush();
+ }
+
+ /**
+ * Renders a string.
+ * @param string string to be rendered
+ */
+ public function write($str)
+ {
+ $this->_writer->write($str);
+ }
+
+ /**
+ * Renders a string and appends a newline to it.
+ * @param string string to be rendered
+ */
+ public function writeLine($str='')
+ {
+ $this->_writer->write($str."\n");
+ }
+
+ /**
+ * Renders an HTML break.
+ */
+ public function writeBreak()
+ {
+ $this->_writer->write('<br/>');
+ }
+
+ /**
+ * Renders the openning tag.
+ * @param string tag name
+ */
+ public function renderBeginTag($tagName)
+ {
+ $str='<'.$tagName;
+ foreach($this->_attributes as $name=>$value)
+ $str.=' '.$name.'="'.$value.'"';
+ if(!empty($this->_styles))
+ {
+ $str.=' style="';
+ foreach($this->_styles as $name=>$value)
+ $str.=$name.':'.$value.';';
+ $str.='"';
+ }
+ if(isset(self::$_simpleTags[$tagName]))
+ {
+ $str.=' />';
+ $this->_openTags[] = '';
+ }
+ else
+ {
+ $str.='>';
+ $this->_openTags[] = $tagName;
+ }
+ $this->_writer->write($str);
+ $this->_attributes=array();
+ $this->_styles=array();
+ }
+
+ /**
+ * Renders the closing tag.
+ */
+ public function renderEndTag()
+ {
+ if(!empty($this->_openTags) && ($tagName=array_pop($this->_openTags))!=='')
+ $this->_writer->write('</'.$tagName.'>');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/TPage.php b/lib/prado/framework/Web/UI/TPage.php
new file mode 100644
index 0000000..f1ae591
--- /dev/null
+++ b/lib/prado/framework/Web/UI/TPage.php
@@ -0,0 +1,1318 @@
+<?php
+/**
+ * TPage class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+Prado::using('System.Web.UI.WebControls.*');
+Prado::using('System.Web.UI.TControl');
+Prado::using('System.Web.UI.WebControls.TWebControl');
+Prado::using('System.Web.UI.TCompositeControl');
+Prado::using('System.Web.UI.TTemplateControl');
+Prado::using('System.Web.UI.TForm');
+Prado::using('System.Web.UI.TClientScriptManager');
+
+/**
+ * TPage class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TPage extends TTemplateControl
+{
+ /**
+ * system post fields
+ */
+ const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
+ const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
+ const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
+ const FIELD_PAGESTATE='PRADO_PAGESTATE';
+ const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
+ const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
+
+ /**
+ * @var array system post fields
+ */
+ private static $_systemPostFields=array(
+ 'PRADO_POSTBACK_TARGET'=>true,
+ 'PRADO_POSTBACK_PARAMETER'=>true,
+ 'PRADO_LASTFOCUS'=>true,
+ 'PRADO_PAGESTATE'=>true,
+ 'PRADO_CALLBACK_TARGET'=>true,
+ 'PRADO_CALLBACK_PARAMETER'=>true
+ );
+ /**
+ * @var TForm form instance
+ */
+ private $_form;
+ /**
+ * @var THead head instance
+ */
+ private $_head;
+ /**
+ * @var array list of registered validators
+ */
+ private $_validators=array();
+ /**
+ * @var boolean if validation has been performed
+ */
+ private $_validated=false;
+ /**
+ * @var TTheme page theme
+ */
+ private $_theme;
+ /**
+ * @var string page title set when Head is not in page yet
+ */
+ private $_title;
+ /**
+ * @var TTheme page stylesheet theme
+ */
+ private $_styleSheet;
+ /**
+ * @var TClientScriptManager client script manager
+ */
+ private $_clientScript;
+ /**
+ * @var TMap data post back by user
+ */
+ protected $_postData;
+ /**
+ * @var TMap postback data that is not handled during first invocation of LoadPostData.
+ */
+ protected $_restPostData;
+ /**
+ * @var array list of controls whose data have been changed due to the postback
+ */
+ protected $_controlsPostDataChanged=array();
+ /**
+ * @var array list of controls that need to load post data in the current request
+ */
+ protected $_controlsRequiringPostData=array();
+ /**
+ * @var array list of controls that need to load post data in the next postback
+ */
+ protected $_controlsRegisteredForPostData=array();
+ /**
+ * @var TControl control that needs to raise postback event
+ */
+ private $_postBackEventTarget;
+ /**
+ * @var string postback event parameter
+ */
+ private $_postBackEventParameter;
+ /**
+ * @var boolean whether the form has been rendered
+ */
+ protected $_formRendered=false;
+ /**
+ * @var boolean whether the current rendering is within a form
+ */
+ protected $_inFormRender=false;
+ /**
+ * @var TControl|string the control or the ID of the element on the page to be focused when the page is sent back to user
+ */
+ private $_focus;
+ /**
+ * @var string page path to this page
+ */
+ private $_pagePath='';
+ /**
+ * @var boolean whether page state should be HMAC validated
+ */
+ private $_enableStateValidation=true;
+ /**
+ * @var boolean whether page state should be encrypted
+ */
+ private $_enableStateEncryption=false;
+ /**
+ * @var boolean whether page state should be compressed
+ * @since 3.1.6
+ */
+ private $_enableStateCompression=true;
+ /**
+ * @var string page state persister class name
+ */
+ private $_statePersisterClass='System.Web.UI.TPageStatePersister';
+ /**
+ * @var mixed page state persister
+ */
+ private $_statePersister;
+ /**
+ * @var TStack stack used to store currently active caching controls
+ */
+ private $_cachingStack;
+ /**
+ * @var string state string to be stored on the client side
+ */
+ private $_clientState='';
+ /**
+ * @var boolean true if loading post data.
+ */
+ protected $_isLoadingPostData=false;
+ /**
+ * @var boolean whether client supports javascript
+ */
+ private $_enableJavaScript=true;
+ /**
+ * @var THtmlWriter current html render writer
+ */
+ private $_writer;
+
+ /**
+ * Constructor.
+ * Sets the page object to itself.
+ * Derived classes must call parent implementation.
+ */
+ public function __construct()
+ {
+ $this->setPage($this);
+ }
+
+ /**
+ * Runs through the page lifecycles.
+ * @param THtmlTextWriter the HTML writer
+ */
+ public function run($writer)
+ {
+ Prado::trace("Running page life cycles",'System.Web.UI.TPage');
+ $this->_writer = $writer;
+
+ $this->determinePostBackMode();
+
+ if($this->getIsPostBack())
+ {
+ if($this->getIsCallback())
+ $this->processCallbackRequest($writer);
+ else
+ $this->processPostBackRequest($writer);
+ }
+ else
+ $this->processNormalRequest($writer);
+
+ $this->_writer = null;
+ }
+
+ protected function processNormalRequest($writer)
+ {
+ Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
+ $this->onPreInit(null);
+
+ Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
+ $this->initRecursive();
+
+ Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
+ $this->onInitComplete(null);
+
+ Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
+ $this->onPreLoad(null);
+ Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
+ $this->loadRecursive();
+ Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
+ $this->onLoadComplete(null);
+
+ Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
+ $this->preRenderRecursive();
+ Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
+ $this->onPreRenderComplete(null);
+
+ Prado::trace("Page savePageState()",'System.Web.UI.TPage');
+ $this->savePageState();
+ Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
+ $this->onSaveStateComplete(null);
+
+ Prado::trace("Page renderControl()",'System.Web.UI.TPage');
+ $this->renderControl($writer);
+ Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
+ $this->unloadRecursive();
+ }
+
+ protected function processPostBackRequest($writer)
+ {
+ Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
+ $this->onPreInit(null);
+
+ Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
+ $this->initRecursive();
+
+ Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
+ $this->onInitComplete(null);
+
+ $this->_restPostData=new TMap;
+ Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
+ $this->loadPageState();
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_postData,true);
+ Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
+ $this->onPreLoad(null);
+ Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
+ $this->loadRecursive();
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_restPostData,false);
+ Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
+ $this->raiseChangedEvents();
+ Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
+ $this->raisePostBackEvent();
+ Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
+ $this->onLoadComplete(null);
+
+ Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
+ $this->preRenderRecursive();
+ Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
+ $this->onPreRenderComplete(null);
+
+ Prado::trace("Page savePageState()",'System.Web.UI.TPage');
+ $this->savePageState();
+ Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
+ $this->onSaveStateComplete(null);
+
+ Prado::trace("Page renderControl()",'System.Web.UI.TPage');
+ $this->renderControl($writer);
+ Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
+ $this->unloadRecursive();
+ }
+
+ protected static function decodeUTF8($data, $enc)
+ {
+ if(is_array($data))
+ {
+ foreach($data as $k=>$v)
+ $data[$k]=self::decodeUTF8($v, $enc);
+ return $data;
+ } elseif(is_string($data)) {
+ return iconv('UTF-8',$enc.'//IGNORE',$data);
+ } else {
+ return $data;
+ }
+ }
+
+ /**
+ * Sets Adapter to TActivePageAdapter and calls apter to process the
+ * callback request.
+ */
+ protected function processCallbackRequest($writer)
+ {
+ Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
+ Prado::using('System.Web.UI.JuiControls.TJuiControlOptions');
+
+ $this->setAdapter(new TActivePageAdapter($this));
+
+ $callbackEventParameter = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER);
+ if(strlen($callbackEventParameter) > 0)
+ $this->_postData[TPage::FIELD_CALLBACK_PARAMETER]=TJavaScript::jsonDecode((string)$callbackEventParameter);
+
+ // Decode Callback postData from UTF-8 to current Charset
+ if (($g=$this->getApplication()->getGlobalization(false))!==null &&
+ strtoupper($enc=$g->getCharset())!='UTF-8')
+ foreach ($this->_postData as $k=>$v)
+ $this->_postData[$k]=self::decodeUTF8($v, $enc);
+
+ Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
+ $this->onPreInit(null);
+
+ Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
+ $this->initRecursive();
+
+ Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
+ $this->onInitComplete(null);
+
+ $this->_restPostData=new TMap;
+ Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
+ $this->loadPageState();
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_postData,true);
+ Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
+ $this->onPreLoad(null);
+ Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
+ $this->loadRecursive();
+
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_restPostData,false);
+
+ Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
+ $this->raiseChangedEvents();
+
+
+ $this->getAdapter()->processCallbackEvent($writer);
+
+/*
+ Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
+ $this->raisePostBackEvent();
+*/
+ Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
+ $this->onLoadComplete(null);
+
+ Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
+ $this->preRenderRecursive();
+ Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
+ $this->onPreRenderComplete(null);
+
+ Prado::trace("Page savePageState()",'System.Web.UI.TPage');
+ $this->savePageState();
+ Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
+ $this->onSaveStateComplete(null);
+
+/*
+ Prado::trace("Page renderControl()",'System.Web.UI.TPage');
+ $this->renderControl($writer);
+*/
+ $this->getAdapter()->renderCallbackResponse($writer);
+
+ Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
+ $this->unloadRecursive();
+ }
+
+ /**
+ * Gets the callback client script handler that allows javascript functions
+ * to be executed during the callback response.
+ * @return TCallbackClientScript interface to client-side javascript code.
+ */
+ public function getCallbackClient()
+ {
+ if($this->getAdapter() !== null)
+ return $this->getAdapter()->getCallbackClientHandler();
+ else
+ return new TCallbackClientScript();
+ }
+
+ /**
+ * Set a new callback client handler.
+ * @param TCallbackClientScript new callback client script handler.
+ */
+ public function setCallbackClient($client)
+ {
+ $this->getAdapter()->setCallbackClientHandler($client);
+ }
+
+ /**
+ * @return TControl the control responsible for the current callback event,
+ * null if nonexistent
+ */
+ public function getCallbackEventTarget()
+ {
+ return $this->getAdapter()->getCallbackEventTarget();
+ }
+
+ /**
+ * Registers a control to raise callback event in the current request.
+ * @param TControl control registered to raise callback event.
+ */
+ public function setCallbackEventTarget(TControl $control)
+ {
+ $this->getAdapter()->setCallbackEventTarget($control);
+ }
+
+ /**
+ * Callback parameter is decoded assuming JSON encoding.
+ * @return string callback event parameter
+ */
+ public function getCallbackEventParameter()
+ {
+ return $this->getAdapter()->getCallbackEventParameter();
+ }
+
+ /**
+ * @param mixed callback event parameter
+ */
+ public function setCallbackEventParameter($value)
+ {
+ $this->getAdapter()->setCallbackEventParameter($value);
+ }
+
+ /**
+ * @return TForm the form on the page
+ */
+ public function getForm()
+ {
+ return $this->_form;
+ }
+
+ /**
+ * Registers a TForm instance to the page.
+ * Note, a page can contain at most one TForm instance.
+ * @param TForm the form on the page
+ * @throws TInvalidOperationException if this method is invoked twice or more.
+ */
+ public function setForm(TForm $form)
+ {
+ if($this->_form===null)
+ $this->_form=$form;
+ else
+ throw new TInvalidOperationException('page_form_duplicated');
+ }
+
+ /**
+ * Returns a list of registered validators.
+ * If validation group is specified, only the validators in that group will be returned.
+ * @param string validation group
+ * @return TList registered validators in the requested group. If the group is null, all validators will be returned.
+ */
+ public function getValidators($validationGroup=null)
+ {
+ if(!$this->_validators)
+ $this->_validators=new TList;
+ if(empty($validationGroup) === true)
+ return $this->_validators;
+ else
+ {
+ $list=new TList;
+ foreach($this->_validators as $validator)
+ if($validator->getValidationGroup()===$validationGroup)
+ $list->add($validator);
+ return $list;
+ }
+ }
+
+ /**
+ * Performs input validation.
+ * This method will invoke the registered validators to perform the actual validation.
+ * If validation group is specified, only the validators in that group will be invoked.
+ * @param string validation group. If null, all validators will perform validation.
+ */
+ public function validate($validationGroup=null)
+ {
+ Prado::trace("Page validate()",'System.Web.UI.TPage');
+ $this->_validated=true;
+ if($this->_validators && $this->_validators->getCount())
+ {
+ if($validationGroup===null)
+ {
+ foreach($this->_validators as $validator)
+ $validator->validate();
+ }
+ else
+ {
+ foreach($this->_validators as $validator)
+ {
+ if($validator->getValidationGroup()===$validationGroup)
+ $validator->validate();
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns whether user input is valid or not.
+ * This method must be invoked after {@link validate} is called.
+ * @return boolean whether the user input is valid or not.
+ * @throws TInvalidOperationException if {@link validate} is not invoked yet.
+ */
+ public function getIsValid()
+ {
+ if($this->_validated)
+ {
+ if($this->_validators && $this->_validators->getCount())
+ {
+ foreach($this->_validators as $validator)
+ if(!$validator->getIsValid())
+ return false;
+ }
+ return true;
+ }
+ else
+ throw new TInvalidOperationException('page_isvalid_unknown');
+ }
+
+ /**
+ * @return TTheme the theme used for the page. Defaults to null.
+ */
+ public function getTheme()
+ {
+ if(is_string($this->_theme))
+ $this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
+ return $this->_theme;
+ }
+
+ /**
+ * Sets the theme to be used for the page.
+ * @param string|TTheme the theme name or the theme object to be used for the page.
+ */
+ public function setTheme($value)
+ {
+ $this->_theme=empty($value)?null:$value;
+ }
+
+
+ /**
+ * @return TTheme the stylesheet theme used for the page. Defaults to null.
+ */
+ public function getStyleSheetTheme()
+ {
+ if(is_string($this->_styleSheet))
+ $this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
+ return $this->_styleSheet;
+ }
+
+ /**
+ * Sets the stylesheet theme to be used for the page.
+ * @param string|TTheme the stylesheet theme name or the stylesheet theme object to be used for the page.
+ */
+ public function setStyleSheetTheme($value)
+ {
+ $this->_styleSheet=empty($value)?null:$value;
+ }
+
+ /**
+ * Applies a skin in the current theme to a control.
+ * This method should only be used by framework developers.
+ * @param TControl a control to be applied skin with
+ */
+ public function applyControlSkin($control)
+ {
+ if(($theme=$this->getTheme())!==null)
+ $theme->applySkin($control);
+ }
+
+ /**
+ * Applies a stylesheet skin in the current theme to a control.
+ * This method should only be used by framework developers.
+ * @param TControl a control to be applied stylesheet skin with
+ */
+ public function applyControlStyleSheet($control)
+ {
+ if(($theme=$this->getStyleSheetTheme())!==null)
+ $theme->applySkin($control);
+ }
+
+ /**
+ * @return TClientScriptManager client script manager
+ */
+ public function getClientScript()
+ {
+ if(!$this->_clientScript) {
+ $className = $classPath = $this->getService()->getClientScriptManagerClass();
+ Prado::using($className);
+ if(($pos=strrpos($className,'.'))!==false)
+ $className=substr($className,$pos+1);
+
+ if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
+ throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
+
+ $this->_clientScript=new $className($this);
+ }
+ return $this->_clientScript;
+ }
+
+ /**
+ * Raises OnPreInit event.
+ * This method is invoked right before {@link onInit OnInit} stage.
+ * You may override this method to provide additional initialization that
+ * should be done before {@link onInit OnInit} (e.g. setting {@link setTheme Theme} or
+ * {@link setStyleSheetTheme StyleSheetTheme}).
+ * Remember to call the parent implementation to ensure OnPreInit event is raised.
+ * @param mixed event parameter
+ */
+ public function onPreInit($param)
+ {
+ $this->raiseEvent('OnPreInit',$this,$param);
+ }
+
+ /**
+ * Raises OnInitComplete event.
+ * This method is invoked right after {@link onInit OnInit} stage and before {@link onLoad OnLoad} stage.
+ * You may override this method to provide additional initialization that
+ * should be done after {@link onInit OnInit}.
+ * Remember to call the parent implementation to ensure OnInitComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onInitComplete($param)
+ {
+ $this->raiseEvent('OnInitComplete',$this,$param);
+ }
+
+ /**
+ * Raises OnPreLoad event.
+ * This method is invoked right before {@link onLoad OnLoad} stage.
+ * You may override this method to provide additional page loading logic that
+ * should be done before {@link onLoad OnLoad}.
+ * Remember to call the parent implementation to ensure OnPreLoad event is raised.
+ * @param mixed event parameter
+ */
+ public function onPreLoad($param)
+ {
+ $this->raiseEvent('OnPreLoad',$this,$param);
+ }
+
+ /**
+ * Raises OnLoadComplete event.
+ * This method is invoked right after {@link onLoad OnLoad} stage.
+ * You may override this method to provide additional page loading logic that
+ * should be done after {@link onLoad OnLoad}.
+ * Remember to call the parent implementation to ensure OnLoadComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onLoadComplete($param)
+ {
+ $this->raiseEvent('OnLoadComplete',$this,$param);
+ }
+
+ /**
+ * Raises OnPreRenderComplete event.
+ * This method is invoked right after {@link onPreRender OnPreRender} stage.
+ * You may override this method to provide additional preparation for page rendering
+ * that should be done after {@link onPreRender OnPreRender}.
+ * Remember to call the parent implementation to ensure OnPreRenderComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onPreRenderComplete($param)
+ {
+ $this->raiseEvent('OnPreRenderComplete',$this,$param);
+ $cs=$this->getClientScript();
+ $theme=$this->getTheme();
+ if($theme instanceof ITheme)
+ {
+ foreach($theme->getStyleSheetFiles() as $url)
+ $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
+ foreach($theme->getJavaScriptFiles() as $url)
+ $cs->registerHeadScriptFile($url,$url);
+ }
+ $styleSheet=$this->getStyleSheetTheme();
+ if($styleSheet instanceof ITheme)
+ {
+ foreach($styleSheet->getStyleSheetFiles() as $url)
+ $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
+ foreach($styleSheet->getJavaScriptFiles() as $url)
+ $cs->registerHeadScriptFile($url,$url);
+ }
+
+ if($cs->getRequiresHead() && $this->getHead()===null)
+ throw new TConfigurationException('page_head_required');
+ }
+
+ /**
+ * Determines the media type of the CSS file.
+ * The media type is determined according to the following file name pattern:
+ * xxx.media-type.extension
+ * For example, 'mystyle.print.css' means its media type is 'print'.
+ * @param string CSS URL
+ * @return string media type of the CSS file
+ */
+ private function getCssMediaType($url)
+ {
+ $segs=explode('.',basename($url));
+ if(isset($segs[2]))
+ return $segs[count($segs)-2];
+ else
+ return '';
+ }
+
+ /**
+ * Raises OnSaveStateComplete event.
+ * This method is invoked right after {@link onSaveState OnSaveState} stage.
+ * You may override this method to provide additional logic after page state is saved.
+ * Remember to call the parent implementation to ensure OnSaveStateComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onSaveStateComplete($param)
+ {
+ $this->raiseEvent('OnSaveStateComplete',$this,$param);
+ }
+
+ /**
+ * Determines whether the current page request is a postback.
+ * Call {@link getIsPostBack} to get the result.
+ */
+ private function determinePostBackMode()
+ {
+ $postData=$this->getRequest();
+ if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
+ $this->_postData=$postData;
+ }
+
+ /**
+ * @return boolean whether the current page request is a postback
+ */
+ public function getIsPostBack()
+ {
+ return $this->_postData!==null;
+ }
+
+ /**
+ * @return boolean whether this is a callback request
+ */
+ public function getIsCallback()
+ {
+ return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
+ }
+
+ /**
+ * This method is invoked when control state is to be saved.
+ * You can override this method to do last step state saving.
+ * Parent implementation must be invoked.
+ */
+ public function saveState()
+ {
+ parent::saveState();
+ $this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
+ }
+
+ /**
+ * This method is invoked right after the control has loaded its state.
+ * You can override this method to initialize data from the control state.
+ * Parent implementation must be invoked.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ $this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
+ }
+
+ /**
+ * Loads page state from persistent storage.
+ */
+ protected function loadPageState()
+ {
+ Prado::trace("Loading state",'System.Web.UI.TPage');
+ $state=$this->getStatePersister()->load();
+ $this->loadStateRecursive($state,$this->getEnableViewState());
+ }
+
+ /**
+ * Saves page state from persistent storage.
+ */
+ protected function savePageState()
+ {
+ Prado::trace("Saving state",'System.Web.UI.TPage');
+ $state=&$this->saveStateRecursive($this->getEnableViewState());
+ $this->getStatePersister()->save($state);
+ }
+
+ /**
+ * @param string the field name
+ * @return boolean whether the specified field is a system field in postback data
+ */
+ protected function isSystemPostField($field)
+ {
+ return isset(self::$_systemPostFields[$field]);
+ }
+
+ /**
+ * Registers a control for loading post data in the next postback.
+ * This method needs to be invoked if the control to load post data
+ * may not have a post variable in some cases. For example, a checkbox,
+ * if not checked, will not have a post value.
+ * @param TControl control registered for loading post data
+ */
+ public function registerRequiresPostData($control)
+ {
+ $id=is_string($control)?$control:$control->getUniqueID();
+ $this->_controlsRegisteredForPostData[$id]=true;
+ $params=func_get_args();
+ foreach($this->getCachingStack() as $item)
+ $item->registerAction('Page','registerRequiresPostData',array($id));
+ }
+
+ /**
+ * @return TControl the control responsible for the current postback event, null if nonexistent
+ */
+ public function getPostBackEventTarget()
+ {
+ if($this->_postBackEventTarget===null && $this->_postData!==null)
+ {
+ $eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
+ if(!empty($eventTarget))
+ $this->_postBackEventTarget=$this->findControl($eventTarget);
+ }
+ return $this->_postBackEventTarget;
+ }
+
+ /**
+ * Registers a control to raise postback event in the current request.
+ * @param TControl control registered to raise postback event.
+ */
+ public function setPostBackEventTarget(TControl $control)
+ {
+ $this->_postBackEventTarget=$control;
+ }
+
+ /**
+ * @return string postback event parameter
+ */
+ public function getPostBackEventParameter()
+ {
+ if($this->_postBackEventParameter===null && $this->_postData!==null)
+ {
+ if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
+ $this->_postBackEventParameter='';
+ }
+ return $this->_postBackEventParameter;
+ }
+
+ /**
+ * @param string postback event parameter
+ */
+ public function setPostBackEventParameter($value)
+ {
+ $this->_postBackEventParameter=$value;
+ }
+
+ /**
+ * Processes post data.
+ * @param TMap post data to be processed
+ * @param boolean whether this method is invoked before {@link onLoad OnLoad}.
+ */
+ protected function processPostData($postData,$beforeLoad)
+ {
+ $this->_isLoadingPostData=true;
+ if($beforeLoad)
+ $this->_restPostData=new TMap;
+ foreach($postData as $key=>$value)
+ {
+ if($this->isSystemPostField($key))
+ continue;
+ else if($control=$this->findControl($key))
+ {
+ if($control instanceof IPostBackDataHandler)
+ {
+ if($control->loadPostData($key,$postData))
+ $this->_controlsPostDataChanged[]=$control;
+ }
+ else if($control instanceof IPostBackEventHandler &&
+ empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
+ {
+ $this->_postData->add(self::FIELD_POSTBACK_TARGET,$key); // not calling setPostBackEventTarget() because the control may be removed later
+ }
+ unset($this->_controlsRequiringPostData[$key]);
+ }
+ else if($beforeLoad)
+ $this->_restPostData->add($key,$value);
+ }
+
+ foreach($this->_controlsRequiringPostData as $key=>$value)
+ {
+ if($control=$this->findControl($key))
+ {
+ if($control instanceof IPostBackDataHandler)
+ {
+ if($control->loadPostData($key,$this->_postData))
+ $this->_controlsPostDataChanged[]=$control;
+ }
+ else
+ throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
+ unset($this->_controlsRequiringPostData[$key]);
+ }
+ }
+ $this->_isLoadingPostData=false;
+ }
+
+ /**
+ * @return boolean true if loading post data.
+ */
+ public function getIsLoadingPostData()
+ {
+ return $this->_isLoadingPostData;
+ }
+
+ /**
+ * Raises OnPostDataChangedEvent for controls whose data have been changed due to the postback.
+ */
+ protected function raiseChangedEvents()
+ {
+ foreach($this->_controlsPostDataChanged as $control)
+ $control->raisePostDataChangedEvent();
+ }
+
+ /**
+ * Raises PostBack event.
+ */
+ protected function raisePostBackEvent()
+ {
+ if(($postBackHandler=$this->getPostBackEventTarget())===null)
+ $this->validate();
+ else if($postBackHandler instanceof IPostBackEventHandler)
+ $postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
+ }
+
+ /**
+ * @return boolean Whether form rendering is in progress
+ */
+ public function getInFormRender()
+ {
+ return $this->_inFormRender;
+ }
+
+ /**
+ * Ensures the control is rendered within a form.
+ * @param TControl the control to be rendered
+ * @throws TConfigurationException if the control is outside of the form
+ */
+ public function ensureRenderInForm($control)
+ {
+ if(!$this->getIsCallback() && !$this->_inFormRender)
+ throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
+ }
+
+ /**
+ * @internal This method is invoked by TForm at the beginning of its rendering
+ */
+ public function beginFormRender($writer)
+ {
+ if($this->_formRendered)
+ throw new TConfigurationException('page_form_duplicated');
+ $this->_formRendered=true;
+ $this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
+ $this->_inFormRender=true;
+ }
+
+ /**
+ * @internal This method is invoked by TForm at the end of its rendering
+ */
+ public function endFormRender($writer)
+ {
+ if($this->_focus)
+ {
+ if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
+ $focus=$this->_focus->getClientID();
+ else
+ $focus=$this->_focus;
+ $this->getClientScript()->registerFocusControl($focus);
+ }
+ else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
+ $this->getClientScript()->registerFocusControl($lastFocus);
+ $this->_inFormRender=false;
+ }
+
+ /**
+ * Sets input focus on a control after the page is rendered to users.
+ * @param TControl|string control to receive focus, or the ID of the element on the page to receive focus
+ */
+ public function setFocus($value)
+ {
+ $this->_focus=$value;
+ }
+
+ /**
+ * @return boolean whether client supports javascript. Defaults to true.
+ */
+ public function getClientSupportsJavaScript()
+ {
+ return $this->_enableJavaScript;
+ }
+
+ /**
+ * @param boolean whether client supports javascript. If false, javascript will not be generated for controls.
+ */
+ public function setClientSupportsJavaScript($value)
+ {
+ $this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return THead page head, null if not available
+ */
+ public function getHead()
+ {
+ return $this->_head;
+ }
+
+ /**
+ * @param THead page head
+ * @throws TInvalidOperationException if a head already exists
+ */
+ public function setHead(THead $value)
+ {
+ if($this->_head)
+ throw new TInvalidOperationException('page_head_duplicated');
+ $this->_head=$value;
+ if($this->_title!==null)
+ {
+ $this->_head->setTitle($this->_title);
+ $this->_title=null;
+ }
+ }
+
+ /**
+ * @return string page title.
+ */
+ public function getTitle()
+ {
+ if($this->_head)
+ return $this->_head->getTitle();
+ else
+ return $this->_title===null ? '' : $this->_title;
+ }
+
+ /**
+ * Sets the page title.
+ * Note, a {@link THead} control needs to place on the page
+ * in order that this title be rendered.
+ * @param string page title. This will override the title set in {@link getHead Head}.
+ */
+ public function setTitle($value)
+ {
+ if($this->_head)
+ $this->_head->setTitle($value);
+ else
+ $this->_title=$value;
+ }
+
+ /**
+ * Returns the state to be stored on the client side.
+ * This method should only be used by framework and control developers.
+ * @return string the state to be stored on the client side
+ */
+ public function getClientState()
+ {
+ return $this->_clientState;
+ }
+
+ /**
+ * Sets the state to be stored on the client side.
+ * This method should only be used by framework and control developers.
+ * @param string the state to be stored on the client side
+ */
+ public function setClientState($state)
+ {
+ $this->_clientState=$state;
+ }
+
+ /**
+ * @return string the state postback from client side
+ */
+ public function getRequestClientState()
+ {
+ return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
+ }
+
+ /**
+ * @return string class name of the page state persister. Defaults to TPageStatePersister.
+ */
+ public function getStatePersisterClass()
+ {
+ return $this->_statePersisterClass;
+ }
+
+ /**
+ * @param string class name of the page state persister.
+ */
+ public function setStatePersisterClass($value)
+ {
+ $this->_statePersisterClass=$value;
+ }
+
+ /**
+ * @return IPageStatePersister page state persister
+ */
+ public function getStatePersister()
+ {
+ if($this->_statePersister===null)
+ {
+ $this->_statePersister=Prado::createComponent($this->_statePersisterClass);
+ if(!($this->_statePersister instanceof IPageStatePersister))
+ throw new TInvalidDataTypeException('page_statepersister_invalid');
+ $this->_statePersister->setPage($this);
+ }
+ return $this->_statePersister;
+ }
+
+ /**
+ * @return boolean whether page state should be HMAC validated. Defaults to true.
+ */
+ public function getEnableStateValidation()
+ {
+ return $this->_enableStateValidation;
+ }
+
+ /**
+ * @param boolean whether page state should be HMAC validated.
+ */
+ public function setEnableStateValidation($value)
+ {
+ $this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether page state should be encrypted. Defaults to false.
+ */
+ public function getEnableStateEncryption()
+ {
+ return $this->_enableStateEncryption;
+ }
+
+ /**
+ * @param boolean whether page state should be encrypted.
+ */
+ public function setEnableStateEncryption($value)
+ {
+ $this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether page state should be compressed. Defaults to true.
+ * @since 3.1.6
+ */
+ public function getEnableStateCompression()
+ {
+ return $this->_enableStateCompression;
+ }
+
+ /**
+ * @param boolean whether page state should be compressed.
+ * @since 3.1.6
+ */
+ public function setEnableStateCompression($value)
+ {
+ $this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return string the requested page path for this page
+ */
+ public function getPagePath()
+ {
+ return $this->_pagePath;
+ }
+
+ /**
+ * @param string the requested page path for this page
+ */
+ public function setPagePath($value)
+ {
+ $this->_pagePath=$value;
+ }
+
+ /**
+ * Registers an action associated with the content being cached.
+ * The registered action will be replayed if the content stored
+ * in the cache is served to end-users.
+ * @param string context of the action method. This is a property-path
+ * referring to the context object (e.g. Page, Page.ClientScript).
+ * @param string method name of the context object
+ * @param array list of parameters to be passed to the action method
+ */
+ public function registerCachingAction($context,$funcName,$funcParams)
+ {
+ if($this->_cachingStack)
+ {
+ foreach($this->_cachingStack as $cache)
+ $cache->registerAction($context,$funcName,$funcParams);
+ }
+ }
+
+ /**
+ * @return TStack stack of {@link TOutputCache} objects
+ */
+ public function getCachingStack()
+ {
+ if(!$this->_cachingStack)
+ $this->_cachingStack=new TStack;
+ return $this->_cachingStack;
+ }
+
+ /**
+ * Flushes output
+ */
+ public function flushWriter()
+ {
+ if ($this->_writer)
+ $this->Response->write($this->_writer->flush());
+ }
+
+}
+
+/**
+ * IPageStatePersister interface.
+ *
+ * IPageStatePersister interface is required for all page state persister
+ * classes.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.1
+ */
+interface IPageStatePersister
+{
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function getPage();
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function setPage(TPage $page);
+ /**
+ * Saves state to persistent storage.
+ * @param mixed state to be stored
+ */
+ public function save($state);
+ /**
+ * Loads page state from persistent storage
+ * @return mixed the restored state
+ */
+ public function load();
+}
+
+
+/**
+ * TPageStateFormatter class.
+ *
+ * TPageStateFormatter is a utility class to transform the page state
+ * into and from a string that can be properly saved in persistent storage.
+ *
+ * Depending on the {@link TPage::getEnableStateValidation() EnableStateValidation}
+ * and {@link TPage::getEnableStateEncryption() EnableStateEncryption},
+ * TPageStateFormatter may do HMAC validation and encryption to prevent
+ * the state data from being tampered or viewed.
+ * The private keys and hashing/encryption methods are determined by
+ * {@link TApplication::getSecurityManager() SecurityManager}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI
+ * @since 3.1
+ */
+class TPageStateFormatter
+{
+ /**
+ * @param TPage
+ * @param mixed state data
+ * @return string serialized data
+ */
+ public static function serialize($page,$data)
+ {
+ $sm=$page->getApplication()->getSecurityManager();
+ if($page->getEnableStateValidation())
+ $str=$sm->hashData(serialize($data));
+ else
+ $str=serialize($data);
+ if($page->getEnableStateCompression() && extension_loaded('zlib'))
+ $str=gzcompress($str);
+ if($page->getEnableStateEncryption())
+ $str=$sm->encrypt($str);
+ return base64_encode($str);
+ }
+
+ /**
+ * @param TPage
+ * @param string serialized data
+ * @return mixed unserialized state data, null if data is corrupted
+ */
+ public static function unserialize($page,$data)
+ {
+ $str=base64_decode($data);
+ if($str==='')
+ return null;
+ if($str!==false)
+ {
+ $sm=$page->getApplication()->getSecurityManager();
+ if($page->getEnableStateEncryption())
+ $str=$sm->decrypt($str);
+ if($page->getEnableStateCompression() && extension_loaded('zlib'))
+ $str=@gzuncompress($str);
+ if($page->getEnableStateValidation())
+ {
+ if(($str=$sm->validateData($str))!==false)
+ return unserialize($str);
+ }
+ else
+ return unserialize($str);
+ }
+ return null;
+ }
+}
diff --git a/lib/prado/framework/Web/UI/TPageStatePersister.php b/lib/prado/framework/Web/UI/TPageStatePersister.php
new file mode 100644
index 0000000..161316b
--- /dev/null
+++ b/lib/prado/framework/Web/UI/TPageStatePersister.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * TPageStatePersister class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+/**
+ * TPageStatePersister class
+ *
+ * TPageStatePersister implements a page state persistent method based on
+ * form hidden fields.
+ *
+ * Since page state can be very big for complex pages, consider using
+ * alternative persisters, such as {@link TSessionPageStatePersister},
+ * which store page state on the server side and thus reduce the network
+ * traffic for transmitting bulky page state.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TPageStatePersister extends TComponent implements IPageStatePersister
+{
+ private $_page;
+
+ /**
+ * @return TPage the page that this persister works for
+ */
+ public function getPage()
+ {
+ return $this->_page;
+ }
+
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function setPage(TPage $page)
+ {
+ $this->_page=$page;
+ }
+
+ /**
+ * Saves state in hidden fields.
+ * @param mixed state to be stored
+ */
+ public function save($state)
+ {
+ $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$state));
+ }
+
+ /**
+ * Loads page state from hidden fields.
+ * @return mixed the restored state
+ * @throws THttpException if page state is corrupted
+ */
+ public function load()
+ {
+ if(($data=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
+ return $data;
+ else
+ throw new THttpException(400,'pagestatepersister_pagestate_corrupted');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/TSessionPageStatePersister.php b/lib/prado/framework/Web/UI/TSessionPageStatePersister.php
new file mode 100644
index 0000000..a825a7d
--- /dev/null
+++ b/lib/prado/framework/Web/UI/TSessionPageStatePersister.php
@@ -0,0 +1,129 @@
+<?php
+/**
+ * TSessionPageStatePersister class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+/**
+ * TSessionPageStatePersister class
+ *
+ * TSessionPageStatePersister implements a page state persistent method based on
+ * sessions. Page state are stored in user sessions and therefore, this persister
+ * requires session to be started and available.
+ *
+ * TSessionPageStatePersister keeps limited number of history states in session,
+ * mainly to preserve the precious server storage. The number is specified
+ * by {@link setHistorySize HistorySize}, which defaults to 10.
+ *
+ * There are a couple of ways to use TSessionPageStatePersister.
+ * One can override the page's {@link TPage::getStatePersister()} method and
+ * create a TSessionPageStatePersister instance there.
+ * Or one can configure the pages to use TSessionPageStatePersister in page configurations
+ * as follows,
+ * <code>
+ * <pages StatePersisterClass="System.Web.UI.TSessionPageStatePersister" />
+ * </code>
+ * The above configuration will affect the pages under the directory containing
+ * this configuration and all its subdirectories.
+ * To configure individual pages to use TSessionPageStatePersister, use
+ * <code>
+ * <pages>
+ * <page id="PageID" StatePersisterClass="System.Web.UI.TSessionPageStatePersister" />
+ * </pages>
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.1
+ */
+class TSessionPageStatePersister extends TComponent implements IPageStatePersister
+{
+ const STATE_SESSION_KEY='PRADO_SESSION_PAGESTATE';
+ const QUEUE_SESSION_KEY='PRADO_SESSION_STATEQUEUE';
+
+ private $_page;
+ private $_historySize=10;
+
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function getPage()
+ {
+ return $this->_page;
+ }
+
+ /**
+ * @param TPage the page that this persister works for.
+ */
+ public function setPage(TPage $page)
+ {
+ $this->_page=$page;
+ }
+
+ /**
+ * @return integer maximum number of page states that should be kept in session. Defaults to 10.
+ */
+ public function getHistorySize()
+ {
+ return $this->_historySize;
+ }
+
+ /**
+ * @param integer maximum number of page states that should be kept in session
+ * @throws TInvalidDataValueException if the number is smaller than 1.
+ */
+ public function setHistorySize($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))>0)
+ $this->_historySize=$value;
+ else
+ throw new TInvalidDataValueException('sessionpagestatepersister_historysize_invalid');
+ }
+ /**
+ * Saves state in session.
+ * @param mixed state to be stored
+ */
+ public function save($state)
+ {
+ $session=$this->_page->getSession();
+ $session->open();
+ $data=serialize($state);
+ $timestamp=(string)microtime(true);
+ $key=self::STATE_SESSION_KEY.$timestamp;
+ $session->add($key,$data);
+ if(($queue=$session->itemAt(self::QUEUE_SESSION_KEY))===null)
+ $queue=array();
+ $queue[]=$key;
+ if(count($queue)>$this->getHistorySize())
+ {
+ $expiredKey=array_shift($queue);
+ $session->remove($expiredKey);
+ }
+ $session->add(self::QUEUE_SESSION_KEY,$queue);
+ $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp));
+ }
+
+ /**
+ * Loads page state from session.
+ * @return mixed the restored state
+ * @throws THttpException if page state is corrupted
+ */
+ public function load()
+ {
+ if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
+ {
+ $session=$this->_page->getSession();
+ $session->open();
+ $key=self::STATE_SESSION_KEY.$timestamp;
+ if(($data=$session->itemAt($key))!==null)
+ return unserialize($data);
+ }
+ throw new THttpException(400,'sessionpagestatepersister_pagestate_corrupted');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/TTemplateControl.php b/lib/prado/framework/Web/UI/TTemplateControl.php
new file mode 100644
index 0000000..4917d4b
--- /dev/null
+++ b/lib/prado/framework/Web/UI/TTemplateControl.php
@@ -0,0 +1,327 @@
+<?php
+/**
+ * TTemplateControl class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+/**
+ * Includes TCompositeControl class
+ */
+Prado::using('System.Web.UI.TCompositeControl');
+
+/**
+ * TTemplateControl class.
+ * TTemplateControl is the base class for all controls that use templates.
+ * By default, a control template is assumed to be in a file under the same
+ * directory with the control class file. They have the same file name and
+ * different extension name. For template file, the extension name is ".tpl".
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TTemplateControl extends TCompositeControl
+{
+ /**
+ * template file extension.
+ */
+ const EXT_TEMPLATE='.tpl';
+
+ /**
+ * @var ITemplate the parsed template structure shared by the same control class
+ */
+ private static $_template=array();
+ /**
+ * @var ITemplate the parsed template structure specific for this control instance
+ */
+ private $_localTemplate=null;
+ /**
+ * @var TTemplateControl the master control if any
+ */
+ private $_master=null;
+ /**
+ * @var string master control class name
+ */
+ private $_masterClass='';
+ /**
+ * @var array list of TContent controls
+ */
+ private $_contents=array();
+ /**
+ * @var array list of TContentPlaceHolder controls
+ */
+ private $_placeholders=array();
+
+ /**
+ * Returns the template object associated with this control object.
+ * @return ITemplate|null the parsed template, null if none
+ */
+ public function getTemplate()
+ {
+ if($this->_localTemplate===null)
+ {
+ $class=get_class($this);
+ if(!isset(self::$_template[$class]))
+ self::$_template[$class]=$this->loadTemplate();
+ return self::$_template[$class];
+ }
+ else
+ return $this->_localTemplate;
+ }
+
+ /**
+ * Sets the parsed template.
+ * Note, the template will be applied to the whole control class.
+ * This method should only be used by framework and control developers.
+ * @param ITemplate the parsed template
+ */
+ public function setTemplate($value)
+ {
+ $this->_localTemplate=$value;
+ }
+
+ /**
+ * @return boolean whether this control is a source template control.
+ * A source template control loads its template from external storage,
+ * such as file, db, rather than from within another template.
+ */
+ public function getIsSourceTemplateControl()
+ {
+ if(($template=$this->getTemplate())!==null)
+ return $template->getIsSourceTemplate();
+ else
+ return false;
+ }
+
+ /**
+ * @return string the directory containing the template. Empty if no template available.
+ */
+ public function getTemplateDirectory()
+ {
+ if(($template=$this->getTemplate())!==null)
+ return $template->getContextPath();
+ else
+ return '';
+ }
+
+ /**
+ * Loads the template associated with this control class.
+ * @return ITemplate the parsed template structure
+ */
+ protected function loadTemplate()
+ {
+ Prado::trace("Loading template ".get_class($this),'System.Web.UI.TTemplateControl');
+ $template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
+ return $template;
+ }
+
+ /**
+ * Creates child controls.
+ * This method is overridden to load and instantiate control template.
+ * This method should only be used by framework and control developers.
+ */
+ public function createChildControls()
+ {
+ if($tpl=$this->getTemplate())
+ {
+ foreach($tpl->getDirective() as $name=>$value)
+ {
+ if(is_string($value))
+ $this->setSubProperty($name,$value);
+ else
+ throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
+ }
+ $tpl->instantiateIn($this);
+ }
+ }
+
+ /**
+ * Registers a content control.
+ * @param string ID of the content
+ * @param TContent
+ */
+ public function registerContent($id,TContent $object)
+ {
+ if(isset($this->_contents[$id]))
+ throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
+ else
+ $this->_contents[$id]=$object;
+ }
+
+ /**
+ * Registers a content placeholder to this template control.
+ * This method should only be used by framework and control developers.
+ * @param string placeholder ID
+ * @param TContentPlaceHolder placeholder control
+ */
+ public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
+ {
+ if(isset($this->_placeholders[$id]))
+ throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
+ else
+ $this->_placeholders[$id]=$object;
+ }
+
+ /**
+ * @return string master class name (in namespace form)
+ */
+ public function getMasterClass()
+ {
+ return $this->_masterClass;
+ }
+
+ /**
+ * @param string master control class name (in namespace form)
+ */
+ public function setMasterClass($value)
+ {
+ $this->_masterClass=$value;
+ }
+
+ /**
+ * @return TTemplateControl|null master control associated with this control, null if none
+ */
+ public function getMaster()
+ {
+ return $this->_master;
+ }
+
+ /**
+ * Injects all content controls (and their children) to the corresponding content placeholders.
+ * This method should only be used by framework and control developers.
+ * @param string ID of the content control
+ * @param TContent the content to be injected
+ */
+ public function injectContent($id,$content)
+ {
+ if(isset($this->_placeholders[$id]))
+ {
+ $placeholder=$this->_placeholders[$id];
+ $controls=$placeholder->getParent()->getControls();
+ $loc=$controls->remove($placeholder);
+ $controls->insertAt($loc,$content);
+ }
+ else
+ throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
+ }
+
+ /**
+ * Performs the OnInit step for the control and all its child controls.
+ * This method overrides the parent implementation
+ * by ensuring child controls are created first,
+ * and if master class is set, master will be applied.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function initRecursive($namingContainer=null)
+ {
+ $this->ensureChildControls();
+ if($this->_masterClass!=='')
+ {
+ $master=Prado::createComponent($this->_masterClass);
+ if(!($master instanceof TTemplateControl))
+ throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
+ $this->_master=$master;
+ $this->getControls()->clear();
+ $this->getControls()->add($master);
+ $master->ensureChildControls();
+ foreach($this->_contents as $id=>$content)
+ $master->injectContent($id,$content);
+ }
+ else if(!empty($this->_contents))
+ throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
+ parent::initRecursive($namingContainer);
+ }
+
+ /**
+ * Function to update view controls with data in a given AR object.
+ * View controls and AR object need to have the same name in IDs and Attrs respectively.
+ * @param TActiveRecord $arObj
+ * @param Boolean $throwExceptions Wheter or not to throw exceptions
+ * @author Daniel Sampedro <darthdaniel85@gmail.com>
+ */
+ public function tryToUpdateView($arObj, $throwExceptions = false)
+ {
+ $objAttrs = get_class_vars(get_class($arObj));
+ foreach (array_keys($objAttrs) as $key)
+ {
+ try
+ {
+ if ($key != "RELATIONS")
+ {
+ $control = $this->{$key};
+ if ($control instanceof TTextBox)
+ $control->Text = $arObj->{$key};
+ elseif ($control instanceof TCheckBox)
+ $control->Checked = (boolean) $arObj->{$key};
+ elseif ($control instanceof TDatePicker)
+ $control->Date = $arObj->{$key};
+ }
+ else
+ {
+ foreach ($objAttrs["RELATIONS"] as $relKey => $relValues)
+ {
+ $relControl = $this->{$relKey};
+ switch ($relValues[0])
+ {
+ case TActiveRecord::BELONGS_TO:
+ case TActiveRecord::HAS_ONE:
+ $relControl->Text = $arObj->{$relKey};
+ break;
+ case TActiveRecord::HAS_MANY:
+ if ($relControl instanceof TListControl)
+ {
+ $relControl->DataSource = $arObj->{$relKey};
+ $relControl->dataBind();
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ catch (Exception $ex)
+ {
+ if ($throwExceptions)
+ throw $ex;
+ }
+ }
+ }
+
+ /**
+ * Function to try to update an AR object with data in view controls.
+ * @param TActiveRecord $arObj
+ * @param Boolean $throwExceptions Wheter or not to throw exceptions
+ * @author Daniel Sampedro <darthdaniel85@gmail.com>
+ */
+ public function tryToUpdateAR($arObj, $throwExceptions = false)
+ {
+ $objAttrs = get_class_vars(get_class($arObj));
+ foreach (array_keys($objAttrs) as $key)
+ {
+ try
+ {
+ if ($key == "RELATIONS")
+ break;
+ $control = $this->{$key};
+ if ($control instanceof TTextBox)
+ $arObj->{$key} = $control->Text;
+ elseif ($control instanceof TCheckBox)
+ $arObj->{$key} = $control->Checked;
+ elseif ($control instanceof TDatePicker)
+ $arObj->{$key} = $control->Date;
+ }
+ catch (Exception $ex)
+ {
+ if ($throwExceptions)
+ throw $ex;
+ }
+ }
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/TTemplateControlInheritable.php b/lib/prado/framework/Web/UI/TTemplateControlInheritable.php
new file mode 100644
index 0000000..d4dbb87
--- /dev/null
+++ b/lib/prado/framework/Web/UI/TTemplateControlInheritable.php
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * TTemplateControlInheritable class file.
+ *
+ * @author Schlaue-Kids.net <info@schlaue-kids.net>
+ * @link http://www.schlaue-kids.net/
+ * @copyright Copyright &copy; 2010 Schlaue-Kids.net
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+Prado::using('System.Web.UI.TTemplateControl');
+
+/**
+ * TTemplateControlInheritable class.
+ * TTemplateControlInheritable is an extension to the base class for all controls that use templates.
+ * By default, a control template is assumed to be in a file under the same
+ * directory with the control class file. They have the same file name and
+ * different extension name. For template file, the extension name is ".tpl".
+ * If a TTemplateControlInheritable is inherited it uses the base class template unless the
+ * inheriting control defines an own.
+ *
+ * @author Schlaue-Kids.net <info@schlaue-kids.net>
+ * @author Kyle Caine
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.1.8
+ */
+class TTemplateControlInheritable extends TTemplateControl
+{
+ // methods
+
+ /**
+ * Creates child controls.
+ * This method is overridden to load and instantiate control template.
+ * This method should only be used by framework and control developers.
+ * Uses the controls template if available or the base class template otherwise.
+ *
+ * @return void
+ * @throws TConfigurationException if a template control directive is invalid
+ */
+ public function createChildControls()
+ {
+ if(null === ($_template = $this->getTemplate())) {
+ return $this->doCreateChildControlsFor(get_class($this));
+ }
+
+ foreach($_template->getDirective() as $_name => $_value) {
+ if(!is_string($_value)) {
+ throw new TConfigurationException('templatecontrol_directive_invalid', get_class($this), $name);
+ }
+
+ $this->setSubProperty($_name, $_value);
+ }
+
+ $_template->instantiateIn($this);
+ }
+
+ /**
+ * This method creates the cild controls for the given class
+ *
+ * @param string $parentClass The class to generate the child controls for
+ * @return void
+ */
+ public function doCreateChildControlsFor($parentClass)
+ {
+ if(false !== ($_parentClass = get_parent_class($parentClass)) && 'TTemplateControl' != $_parentClass) {
+ $this->doCreateChildControlsFor($_parentClass);
+ }
+
+ $this->doTemplateForClass($parentClass);
+ }
+
+ /**
+ * This method creates the template object for the given class
+ *
+ * @param string $p_class The class to create the template from
+ * @return void
+ * @throws TConfigurationException if a template control directive is invalid
+ */
+ public function doTemplateForClass($parentClass)
+ {
+ if(null !== ($_template = $this->getService()->getTemplateManager()->getTemplateByClassName($parentClass))) {
+ foreach($_template->getDirective() as $_name => $_value) {
+ if(!is_string($_value)) {
+ throw new TConfigurationException('templatecontrol_directive_invalid', get_class(this), $_name);
+ }
+
+ $this->setSubProperty($_name, $_value);
+ }
+
+ $_template->instantiateIn($this);
+ }
+ }
+
+ // getter/setter
+
+ /**
+ * A source template control loads its template from external storage,
+ * such as file, db, rather than from within another template.
+ *
+ * @return boolean whether the current control is a source template control
+ */
+ public function getIsSourceTemplateControl()
+ {
+ if(null !== ($_template = $this->getTemplate())) {
+ return $_template->getIsSourceTemplate();
+ }
+
+ return ($_template = $this->getService()->getTemplateManager()->getTemplateByClassName(get_parent_class($this)))
+ ? $_template->getIsSourceTemplate()
+ : false;
+ }
+} \ No newline at end of file
diff --git a/lib/prado/framework/Web/UI/TTemplateManager.php b/lib/prado/framework/Web/UI/TTemplateManager.php
new file mode 100644
index 0000000..b065eb6
--- /dev/null
+++ b/lib/prado/framework/Web/UI/TTemplateManager.php
@@ -0,0 +1,1096 @@
+<?php
+/**
+ * TTemplateManager and TTemplate class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+/**
+ * Includes TOutputCache class file
+ */
+Prado::using('System.Web.UI.WebControls.TOutputCache');
+
+/**
+ * TTemplateManager class
+ *
+ * TTemplateManager manages the loading and parsing of control templates.
+ *
+ * There are two ways of loading a template, either by the associated template
+ * control class name, or the template file name.
+ * The former is via calling {@link getTemplateByClassName}, which tries to
+ * locate the corresponding template file under the directory containing
+ * the class file. The name of the template file is the class name with
+ * the extension '.tpl'. To load a template from a template file path,
+ * call {@link getTemplateByFileName}.
+ *
+ * By default, TTemplateManager is registered with {@link TPageService} as the
+ * template manager module that can be accessed via {@link TPageService::getTemplateManager()}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TTemplateManager extends TModule
+{
+ /**
+ * Template file extension
+ */
+ const TEMPLATE_FILE_EXT='.tpl';
+ /**
+ * Prefix of the cache variable name for storing parsed templates
+ */
+ const TEMPLATE_CACHE_PREFIX='prado:template:';
+
+ /**
+ * Initializes the module.
+ * This method is required by IModule and is invoked by application.
+ * It starts output buffer if it is enabled.
+ * @param TXmlElement module configuration
+ */
+ public function init($config)
+ {
+ $this->getService()->setTemplateManager($this);
+ }
+
+ /**
+ * Loads the template corresponding to the specified class name.
+ * @return ITemplate template for the class name, null if template doesn't exist.
+ */
+ public function getTemplateByClassName($className)
+ {
+ $class=new ReflectionClass($className);
+ $tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
+ return $this->getTemplateByFileName($tplFile);
+ }
+
+ /**
+ * Loads the template from the specified file.
+ * @return ITemplate template parsed from the specified file, null if the file doesn't exist.
+ */
+ public function getTemplateByFileName($fileName)
+ {
+ if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
+ {
+ Prado::trace("Loading template $fileName",'System.Web.UI.TTemplateManager');
+ if(($cache=$this->getApplication()->getCache())===null)
+ return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
+ else
+ {
+ $array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
+ if(is_array($array))
+ {
+ list($template,$timestamps)=$array;
+ if($this->getApplication()->getMode()===TApplicationMode::Performance)
+ return $template;
+ $cacheValid=true;
+ foreach($timestamps as $tplFile=>$timestamp)
+ {
+ if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
+ {
+ $cacheValid=false;
+ break;
+ }
+ }
+ if($cacheValid)
+ return $template;
+ }
+ $template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
+ $includedFiles=$template->getIncludedFiles();
+ $timestamps=array();
+ $timestamps[$fileName]=filemtime($fileName);
+ foreach($includedFiles as $includedFile)
+ $timestamps[$includedFile]=filemtime($includedFile);
+ $cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
+ return $template;
+ }
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Finds a localized template file.
+ * @param string template file.
+ * @return string|null a localized template file if found, null otherwise.
+ */
+ protected function getLocalizedTemplate($filename)
+ {
+ if(($app=$this->getApplication()->getGlobalization(false))===null)
+ return is_file($filename)?$filename:null;
+ foreach($app->getLocalizedResource($filename) as $file)
+ {
+ if(($file=realpath($file))!==false && is_file($file))
+ return $file;
+ }
+ return null;
+ }
+}
+
+/**
+ * TTemplate implements PRADO template parsing logic.
+ * A TTemplate object represents a parsed PRADO control template.
+ * It can instantiate the template as child controls of a specified control.
+ * The template format is like HTML, with the following special tags introduced,
+ * - component tags: a component tag represents the configuration of a component.
+ * The tag name is in the format of com:ComponentType, where ComponentType is the component
+ * class name. Component tags must be well-formed. Attributes of the component tag
+ * are treated as either property initial values, event handler attachment, or regular
+ * tag attributes.
+ * - property tags: property tags are used to set large block of attribute values.
+ * The property tag name is in the format of <prop:AttributeName> where AttributeName
+ * can be a property name, an event name or a regular tag attribute name.
+ * - group subproperty tags: subproperties of a common property can be configured using
+ * <prop:MainProperty SubProperty1="Value1" SubProperty2="Value2" .../>
+ * - directive: directive specifies the property values for the template owner.
+ * It is in the format of <%@ property name-value pairs %>;
+ * - expressions: They are in the format of <%= PHP expression %> and <%% PHP statements %>
+ * - comments: There are two kinds of comments, regular HTML comments and special template comments.
+ * The former is in the format of <!-- comments -->, which will be treated as text strings.
+ * The latter is in the format of <!-- comments --!>, which will be stripped out.
+ *
+ * Tags other than the above are not required to be well-formed.
+ *
+ * A TTemplate object represents a parsed PRADO template. To instantiate the template
+ * for a particular control, call {@link instantiateIn($control)}, which
+ * will create and intialize all components specified in the template and
+ * set their parent as $control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TTemplate extends TApplicationComponent implements ITemplate
+{
+ /**
+ * '<!--.*?--!>' - template comments
+ * '<!--.*?-->' - HTML comments
+ * '<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>' - component tags
+ * '<\/?prop:([\w\.]+)\s*>' - property tags
+ * '<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>' - directives
+ * '<%[%#~\/\\$=\\[](.*?)%>' - expressions
+ * '<prop:([\w\.]+)((?:\s*[\w\.]+=\'.*?\'|\s*[\w\.]+=".*?"|\s*[\w\.]+=<%.*?%>)*)\s*\/>' - group subproperty tags
+ */
+ const REGEX_RULES='/<!--.*?--!>|<!---.*?--->|<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>|<\/?prop:([\w\.]+)\s*>|<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>|<%[%#~\/\\$=\\[](.*?)%>|<prop:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/>/msS';
+
+ /**
+ * Different configurations of component property/event/attribute
+ */
+ const CONFIG_DATABIND=0;
+ const CONFIG_EXPRESSION=1;
+ const CONFIG_ASSET=2;
+ const CONFIG_PARAMETER=3;
+ const CONFIG_LOCALIZATION=4;
+ const CONFIG_TEMPLATE=5;
+
+ /**
+ * @var array list of component tags and strings
+ */
+ private $_tpl=array();
+ /**
+ * @var array list of directive settings
+ */
+ private $_directive=array();
+ /**
+ * @var string context path
+ */
+ private $_contextPath;
+ /**
+ * @var string template file path (if available)
+ */
+ private $_tplFile=null;
+ /**
+ * @var integer the line number that parsing starts from (internal use)
+ */
+ private $_startingLine=0;
+ /**
+ * @var string template content to be parsed
+ */
+ private $_content;
+ /**
+ * @var boolean whether this template is a source template
+ */
+ private $_sourceTemplate=true;
+ /**
+ * @var string hash code of the template
+ */
+ private $_hashCode='';
+ private $_tplControl=null;
+ private $_includedFiles=array();
+ private $_includeAtLine=array();
+ private $_includeLines=array();
+
+
+ /**
+ * Constructor.
+ * The template will be parsed after construction.
+ * @param string the template string
+ * @param string the template context directory
+ * @param string the template file, null if no file
+ * @param integer the line number that parsing starts from (internal use)
+ * @param boolean whether this template is a source template, i.e., this template is loaded from
+ * some external storage rather than from within another template.
+ */
+ public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
+ {
+ $this->_sourceTemplate=$sourceTemplate;
+ $this->_contextPath=$contextPath;
+ $this->_tplFile=$tplFile;
+ $this->_startingLine=$startingLine;
+ $this->_content=$template;
+ $this->_hashCode=md5($template);
+ $this->parse($template);
+ $this->_content=null; // reset to save memory
+ }
+
+ /**
+ * @return string template file path if available, null otherwise.
+ */
+ public function getTemplateFile()
+ {
+ return $this->_tplFile;
+ }
+
+ /**
+ * @return boolean whether this template is a source template, i.e., this template is loaded from
+ * some external storage rather than from within another template.
+ */
+ public function getIsSourceTemplate()
+ {
+ return $this->_sourceTemplate;
+ }
+
+ /**
+ * @return string context directory path
+ */
+ public function getContextPath()
+ {
+ return $this->_contextPath;
+ }
+
+ /**
+ * @return array name-value pairs declared in the directive
+ */
+ public function getDirective()
+ {
+ return $this->_directive;
+ }
+
+ /**
+ * @return string hash code that can be used to identify the template
+ */
+ public function getHashCode()
+ {
+ return $this->_hashCode;
+ }
+
+ /**
+ * @return array the parsed template
+ */
+ public function &getItems()
+ {
+ return $this->_tpl;
+ }
+
+ /**
+ * Instantiates the template.
+ * Content in the template will be instantiated as components and text strings
+ * and passed to the specified parent control.
+ * @param TControl the control who owns the template
+ * @param TControl the control who will become the root parent of the controls on the template. If null, it uses the template control.
+ */
+ public function instantiateIn($tplControl,$parentControl=null)
+ {
+ $this->_tplControl=$tplControl;
+ if($parentControl===null)
+ $parentControl=$tplControl;
+ if(($page=$tplControl->getPage())===null)
+ $page=$this->getService()->getRequestedPage();
+ $controls=array();
+ $directChildren=array();
+ foreach($this->_tpl as $key=>$object)
+ {
+ if($object[0]===-1)
+ $parent=$parentControl;
+ else if(isset($controls[$object[0]]))
+ $parent=$controls[$object[0]];
+ else
+ continue;
+ if(isset($object[2])) // component
+ {
+ $component=Prado::createComponent($object[1]);
+ $properties=&$object[2];
+ if($component instanceof TControl)
+ {
+ if($component instanceof TOutputCache)
+ $component->setCacheKeyPrefix($this->_hashCode.$key);
+ $component->setTemplateControl($tplControl);
+ if(isset($properties['id']))
+ {
+ if(is_array($properties['id']))
+ $properties['id']=$component->evaluateExpression($properties['id'][1]);
+ $tplControl->registerObject($properties['id'],$component);
+ }
+ if(isset($properties['skinid']))
+ {
+ if(is_array($properties['skinid']))
+ $component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
+ else
+ $component->setSkinID($properties['skinid']);
+ unset($properties['skinid']);
+ }
+
+ $component->trackViewState(false);
+
+ $component->applyStyleSheetSkin($page);
+ foreach($properties as $name=>$value)
+ $this->configureControl($component,$name,$value);
+
+ $component->trackViewState(true);
+
+ if($parent===$parentControl)
+ $directChildren[]=$component;
+ else
+ $component->createdOnTemplate($parent);
+ if($component->getAllowChildControls())
+ $controls[$key]=$component;
+ }
+ else if($component instanceof TComponent)
+ {
+ $controls[$key]=$component;
+ if(isset($properties['id']))
+ {
+ if(is_array($properties['id']))
+ $properties['id']=$component->evaluateExpression($properties['id'][1]);
+ $tplControl->registerObject($properties['id'],$component);
+ if(!$component->hasProperty('id'))
+ unset($properties['id']);
+ }
+ foreach($properties as $name=>$value)
+ $this->configureComponent($component,$name,$value);
+ if($parent===$parentControl)
+ $directChildren[]=$component;
+ else
+ $component->createdOnTemplate($parent);
+ }
+ }
+ else
+ {
+ if($object[1] instanceof TCompositeLiteral)
+ {
+ // need to clone a new object because the one in template is reused
+ $o=clone $object[1];
+ $o->setContainer($tplControl);
+ if($parent===$parentControl)
+ $directChildren[]=$o;
+ else
+ $parent->addParsedObject($o);
+ }
+ else
+ {
+ if($parent===$parentControl)
+ $directChildren[]=$object[1];
+ else
+ $parent->addParsedObject($object[1]);
+ }
+ }
+ }
+ // delay setting parent till now because the parent may cause
+ // the child to do lifecycle catchup which may cause problem
+ // if the child needs its own child controls.
+ foreach($directChildren as $control)
+ {
+ if($control instanceof TComponent)
+ $control->createdOnTemplate($parentControl);
+ else
+ $parentControl->addParsedObject($control);
+ }
+ }
+
+ /**
+ * Configures a property/event of a control.
+ * @param TControl control to be configured
+ * @param string property name
+ * @param mixed property initial value
+ */
+ protected function configureControl($control,$name,$value)
+ {
+ if(strncasecmp($name,'on',2)===0) // is an event
+ $this->configureEvent($control,$name,$value,$control);
+ else if(($pos=strrpos($name,'.'))===false) // is a simple property or custom attribute
+ $this->configureProperty($control,$name,$value);
+ else // is a subproperty
+ $this->configureSubProperty($control,$name,$value);
+ }
+
+ /**
+ * Configures a property of a non-control component.
+ * @param TComponent component to be configured
+ * @param string property name
+ * @param mixed property initial value
+ */
+ protected function configureComponent($component,$name,$value)
+ {
+ if(strpos($name,'.')===false) // is a simple property or custom attribute
+ $this->configureProperty($component,$name,$value);
+ else // is a subproperty
+ $this->configureSubProperty($component,$name,$value);
+ }
+
+ /**
+ * Configures an event for a control.
+ * @param TControl control to be configured
+ * @param string event name
+ * @param string event handler
+ * @param TControl context control
+ */
+ protected function configureEvent($control,$name,$value,$contextControl)
+ {
+ if(strpos($value,'.')===false)
+ $control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
+ else
+ $control->attachEventHandler($name,array($contextControl,$value));
+ }
+
+ /**
+ * Configures a simple property for a component.
+ * @param TComponent component to be configured
+ * @param string property name
+ * @param mixed property initial value
+ */
+ protected function configureProperty($component,$name,$value)
+ {
+ if(is_array($value))
+ {
+ switch($value[0])
+ {
+ case self::CONFIG_DATABIND:
+ $component->bindProperty($name,$value[1]);
+ break;
+ case self::CONFIG_EXPRESSION:
+ if($component instanceof TControl)
+ $component->autoBindProperty($name,$value[1]);
+ else
+ {
+ $setter='set'.$name;
+ $component->$setter($this->_tplControl->evaluateExpression($value[1]));
+ }
+ break;
+ case self::CONFIG_TEMPLATE:
+ $setter='set'.$name;
+ $component->$setter($value[1]);
+ break;
+ case self::CONFIG_ASSET: // asset URL
+ $setter='set'.$name;
+ $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
+ $component->$setter($url);
+ break;
+ case self::CONFIG_PARAMETER: // application parameter
+ $setter='set'.$name;
+ $component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
+ break;
+ case self::CONFIG_LOCALIZATION:
+ $setter='set'.$name;
+ $component->$setter(Prado::localize($value[1]));
+ break;
+ default: // an error if reaching here
+ throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
+ break;
+ }
+ }
+ else
+ {
+ if (substr($name,0,2)=='js')
+ if ($value and !($value instanceof TJavaScriptLiteral))
+ $value = new TJavaScriptLiteral($value);
+ $setter='set'.$name;
+ $component->$setter($value);
+ }
+ }
+
+ /**
+ * Configures a subproperty for a component.
+ * @param TComponent component to be configured
+ * @param string subproperty name
+ * @param mixed subproperty initial value
+ */
+ protected function configureSubProperty($component,$name,$value)
+ {
+ if(is_array($value))
+ {
+ switch($value[0])
+ {
+ case self::CONFIG_DATABIND: // databinding
+ $component->bindProperty($name,$value[1]);
+ break;
+ case self::CONFIG_EXPRESSION: // expression
+ if($component instanceof TControl)
+ $component->autoBindProperty($name,$value[1]);
+ else
+ $component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
+ break;
+ case self::CONFIG_TEMPLATE:
+ $component->setSubProperty($name,$value[1]);
+ break;
+ case self::CONFIG_ASSET: // asset URL
+ $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
+ $component->setSubProperty($name,$url);
+ break;
+ case self::CONFIG_PARAMETER: // application parameter
+ $component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
+ break;
+ case self::CONFIG_LOCALIZATION:
+ $component->setSubProperty($name,Prado::localize($value[1]));
+ break;
+ default: // an error if reaching here
+ throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
+ break;
+ }
+ }
+ else
+ $component->setSubProperty($name,$value);
+ }
+
+ /**
+ * Parses a template string.
+ *
+ * This template parser recognizes five types of data:
+ * regular string, well-formed component tags, well-formed property tags, directives, and expressions.
+ *
+ * The parsing result is returned as an array. Each array element can be of three types:
+ * - a string, 0: container index; 1: string content;
+ * - a component tag, 0: container index; 1: component type; 2: attributes (name=>value pairs)
+ * If a directive is found in the template, it will be parsed and can be
+ * retrieved via {@link getDirective}, which returns an array consisting of
+ * name-value pairs in the directive.
+ *
+ * Note, attribute names are treated as case-insensitive and will be turned into lower cases.
+ * Component and directive types are case-sensitive.
+ * Container index is the index to the array element that stores the container object.
+ * If an object has no container, its container index is -1.
+ *
+ * @param string the template string
+ * @throws TConfigurationException if a parsing error is encountered
+ */
+ protected function parse($input)
+ {
+ $input=$this->preprocess($input);
+ $tpl=&$this->_tpl;
+ $n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
+ $expectPropEnd=false;
+ $textStart=0;
+ $stack=array();
+ $container=-1;
+ $matchEnd=0;
+ $c=0;
+ $this->_directive=null;
+ try
+ {
+ for($i=0;$i<$n;++$i)
+ {
+ $match=&$matches[$i];
+ $str=$match[0][0];
+ $matchStart=$match[0][1];
+ $matchEnd=$matchStart+strlen($str)-1;
+ if(strpos($str,'<com:')===0) // opening component tag
+ {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $type=$match[1][0];
+ $attributes=$this->parseAttributes($match[2][0],$match[2][1]);
+ $this->validateAttributes($type,$attributes);
+ $tpl[$c++]=array($container,$type,$attributes);
+ if($str[strlen($str)-2]!=='/') // open tag
+ {
+ $stack[] = $type;
+ $container=$c-1;
+ }
+ }
+ else if(strpos($str,'</com:')===0) // closing component tag
+ {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $type=$match[1][0];
+
+ if(empty($stack))
+ throw new TConfigurationException('template_closingtag_unexpected',"</com:$type>");
+
+ $name=array_pop($stack);
+ if($name!==$type)
+ {
+ $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
+ throw new TConfigurationException('template_closingtag_expected',$tag);
+ }
+ $container=$tpl[$container][0];
+ }
+ else if(strpos($str,'<%@')===0) // directive
+ {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ if(isset($tpl[0]) || $this->_directive!==null)
+ throw new TConfigurationException('template_directive_nonunique');
+ $this->_directive=$this->parseAttributes($match[4][0],$match[4][1]);
+ }
+ else if(strpos($str,'<%')===0) // expression
+ {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $literal=trim($match[5][0]);
+ if($str[2]==='=') // expression
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
+ else if($str[2]==='%') // statements
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
+ else if($str[2]==='#')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
+ else if($str[2]==='$')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
+ else if($str[2]==='~')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
+ else if($str[2]==='/')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/$literal'"));
+ else if($str[2]==='[')
+ {
+ $literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
+ }
+ }
+ else if(strpos($str,'<prop:')===0) // opening property
+ {
+ if(strrpos($str,'/>')===strlen($str)-2) //subproperties
+ {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $prop=strtolower($match[6][0]);
+ $attrs=$this->parseAttributes($match[7][0],$match[7][1]);
+ $attributes=array();
+ foreach($attrs as $name=>$value)
+ $attributes[$prop.'.'.$name]=$value;
+ $type=$tpl[$container][1];
+ $this->validateAttributes($type,$attributes);
+ foreach($attributes as $name=>$value)
+ {
+ if(isset($tpl[$container][2][$name]))
+ throw new TConfigurationException('template_property_duplicated',$name);
+ $tpl[$container][2][$name]=$value;
+ }
+ }
+ else // regular property
+ {
+ $prop=strtolower($match[3][0]);
+ $stack[] = '@'.$prop;
+ if(!$expectPropEnd)
+ {
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $expectPropEnd=true;
+ }
+ }
+ }
+ else if(strpos($str,'</prop:')===0) // closing property
+ {
+ $prop=strtolower($match[3][0]);
+ if(empty($stack))
+ throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>");
+ $name=array_pop($stack);
+ if($name!=='@'.$prop)
+ {
+ $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
+ throw new TConfigurationException('template_closingtag_expected',$tag);
+ }
+ if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
+ {
+ if($matchStart>$textStart)
+ {
+ $value=substr($input,$textStart,$matchStart-$textStart);
+ if(substr($prop,-8,8)==='template')
+ $value=$this->parseTemplateProperty($value,$textStart);
+ else
+ $value=$this->parseAttribute($value);
+ if($container>=0)
+ {
+ $type=$tpl[$container][1];
+ $this->validateAttributes($type,array($prop=>$value));
+ if(isset($tpl[$container][2][$prop]))
+ throw new TConfigurationException('template_property_duplicated',$prop);
+ $tpl[$container][2][$prop]=$value;
+ }
+ else // a property for the template control
+ $this->_directive[$prop]=$value;
+ $textStart=$matchEnd+1;
+ }
+ $expectPropEnd=false;
+ }
+ }
+ else if(strpos($str,'<!--')===0) // comments
+ {
+ if($expectPropEnd)
+ throw new TConfigurationException('template_comments_forbidden');
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ }
+ else
+ throw new TConfigurationException('template_matching_unexpected',$match);
+ }
+ if(!empty($stack))
+ {
+ $name=array_pop($stack);
+ $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
+ throw new TConfigurationException('template_closingtag_expected',$tag);
+ }
+ if($textStart<strlen($input))
+ $tpl[$c++]=array($container,substr($input,$textStart));
+ }
+ catch(Exception $e)
+ {
+ if(($e instanceof TException) && ($e instanceof TTemplateException))
+ throw $e;
+ if($matchEnd===0)
+ $line=$this->_startingLine+1;
+ else
+ $line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
+ $this->handleException($e,$line,$input);
+ }
+
+ if($this->_directive===null)
+ $this->_directive=array();
+
+ // optimization by merging consecutive strings, expressions, statements and bindings
+ $objects=array();
+ $parent=null;
+ $merged=array();
+ foreach($tpl as $id=>$object)
+ {
+ if(isset($object[2]) || $object[0]!==$parent)
+ {
+ if($parent!==null)
+ {
+ if(count($merged[1])===1 && is_string($merged[1][0]))
+ $objects[$id-1]=array($merged[0],$merged[1][0]);
+ else
+ $objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
+ }
+ if(isset($object[2]))
+ {
+ $parent=null;
+ $objects[$id]=$object;
+ }
+ else
+ {
+ $parent=$object[0];
+ $merged=array($parent,array($object[1]));
+ }
+ }
+ else
+ $merged[1][]=$object[1];
+ }
+ if($parent!==null)
+ {
+ if(count($merged[1])===1 && is_string($merged[1][0]))
+ $objects[$id]=array($merged[0],$merged[1][0]);
+ else
+ $objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
+ }
+ $tpl=$objects;
+ return $objects;
+ }
+
+ /**
+ * Parses the attributes of a tag from a string.
+ * @param string the string to be parsed.
+ * @return array attribute values indexed by names.
+ */
+ protected function parseAttributes($str,$offset)
+ {
+ if($str==='')
+ return array();
+ $pattern='/([\w\.\-]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS';
+ $attributes=array();
+ $n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
+ for($i=0;$i<$n;++$i)
+ {
+ $match=&$matches[$i];
+ $name=strtolower($match[1][0]);
+ if(isset($attributes[$name]))
+ throw new TConfigurationException('template_property_duplicated',$name);
+ $value=$match[2][0];
+ if(substr($name,-8,8)==='template')
+ {
+ if($value[0]==='\'' || $value[0]==='"')
+ $attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1);
+ else
+ $attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]);
+ }
+ else
+ {
+ if($value[0]==='\'' || $value[0]==='"')
+ $attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2));
+ else
+ $attributes[$name]=$this->parseAttribute($value);
+ }
+ }
+ return $attributes;
+ }
+
+ protected function parseTemplateProperty($content,$offset)
+ {
+ $line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1;
+ return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false));
+ }
+
+ /**
+ * Parses a single attribute.
+ * @param string the string to be parsed.
+ * @return array attribute initialization
+ */
+ protected function parseAttribute($value)
+ {
+ if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0)
+ {
+ $isDataBind=false;
+ $textStart=0;
+ $expr='';
+ for($i=0;$i<$n;++$i)
+ {
+ $match=$matches[0][$i];
+ $token=$match[0];
+ $offset=$match[1];
+ $length=strlen($token);
+ if($token[2]==='#')
+ $isDataBind=true;
+ if($offset>$textStart)
+ $expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
+ $expr.='.('.substr($token,3,$length-5).')';
+ $textStart=$offset+$length;
+ }
+ $length=strlen($value);
+ if($length>$textStart)
+ $expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
+ if($isDataBind)
+ return array(self::CONFIG_DATABIND,ltrim($expr,'.'));
+ else
+ return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
+ }
+ else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>|<%\/.*?%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
+ {
+ $value=$matches[1];
+ if($value[2]==='~')
+ return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5)));
+ elseif($value[2]==='[')
+ return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6)));
+ elseif($value[2]==='$')
+ return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5)));
+ elseif($value[2]==='/') {
+ $literal = trim(substr($value,3,strlen($value)-5));
+ return array(self::CONFIG_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/$literal'");
+ }
+ }
+ else
+ return $value;
+ }
+
+ protected function validateAttributes($type,$attributes)
+ {
+ Prado::using($type);
+ if(($pos=strrpos($type,'.'))!==false)
+ $className=substr($type,$pos+1);
+ else
+ $className=$type;
+ $class=new ReflectionClass($className);
+ if(is_subclass_of($className,'TControl') || $className==='TControl')
+ {
+ foreach($attributes as $name=>$att)
+ {
+ if(($pos=strpos($name,'.'))!==false)
+ {
+ // a subproperty, so the first segment must be readable
+ $subname=substr($name,0,$pos);
+ if(!$class->hasMethod('get'.$subname))
+ throw new TConfigurationException('template_property_unknown',$type,$subname);
+ }
+ else if(strncasecmp($name,'on',2)===0)
+ {
+ // an event
+ if(!$class->hasMethod($name))
+ throw new TConfigurationException('template_event_unknown',$type,$name);
+ else if(!is_string($att))
+ throw new TConfigurationException('template_eventhandler_invalid',$type,$name);
+ }
+ else
+ {
+ // a simple property
+ if (! ($class->hasMethod('set'.$name) || $class->hasMethod('setjs'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)) )
+ {
+ if ($class->hasMethod('get'.$name) || $class->hasMethod('getjs'.$name))
+ throw new TConfigurationException('template_property_readonly',$type,$name);
+ else
+ throw new TConfigurationException('template_property_unknown',$type,$name);
+ }
+ else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION)
+ {
+ if(strcasecmp($name,'id')===0)
+ throw new TConfigurationException('template_controlid_invalid',$type);
+ else if(strcasecmp($name,'skinid')===0)
+ throw new TConfigurationException('template_controlskinid_invalid',$type);
+ }
+ }
+ }
+ }
+ else if(is_subclass_of($className,'TComponent') || $className==='TComponent')
+ {
+ foreach($attributes as $name=>$att)
+ {
+ if(is_array($att) && ($att[0]===self::CONFIG_DATABIND))
+ throw new TConfigurationException('template_databind_forbidden',$type,$name);
+ if(($pos=strpos($name,'.'))!==false)
+ {
+ // a subproperty, so the first segment must be readable
+ $subname=substr($name,0,$pos);
+ if(!$class->hasMethod('get'.$subname))
+ throw new TConfigurationException('template_property_unknown',$type,$subname);
+ }
+ else if(strncasecmp($name,'on',2)===0)
+ throw new TConfigurationException('template_event_forbidden',$type,$name);
+ else
+ {
+ // id is still alowed for TComponent, even if id property doesn't exist
+ if(strcasecmp($name,'id')!==0 && !($class->hasMethod('set'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)))
+ {
+ if($class->hasMethod('get'.$name))
+ throw new TConfigurationException('template_property_readonly',$type,$name);
+ else
+ throw new TConfigurationException('template_property_unknown',$type,$name);
+ }
+ }
+ }
+ }
+ else
+ throw new TConfigurationException('template_component_required',$type);
+ }
+
+ /**
+ * @return array list of included external template files
+ */
+ public function getIncludedFiles()
+ {
+ return $this->_includedFiles;
+ }
+
+ /**
+ * Handles template parsing exception.
+ * This method rethrows the exception caught during template parsing.
+ * It adjusts the error location by giving out correct error line number and source file.
+ * @param Exception template exception
+ * @param int line number
+ * @param string template string if no source file is used
+ */
+ protected function handleException($e,$line,$input=null)
+ {
+ $srcFile=$this->_tplFile;
+
+ if(($n=count($this->_includedFiles))>0) // need to adjust error row number and file name
+ {
+ for($i=$n-1;$i>=0;--$i)
+ {
+ if($this->_includeAtLine[$i]<=$line)
+ {
+ if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
+ {
+ $line=$line-$this->_includeAtLine[$i]+1;
+ $srcFile=$this->_includedFiles[$i];
+ break;
+ }
+ else
+ $line=$line-$this->_includeLines[$i]+1;
+ }
+ }
+ }
+ $exception=new TTemplateException('template_format_invalid',$e->getMessage());
+ $exception->setLineNumber($line);
+ if(!empty($srcFile))
+ $exception->setTemplateFile($srcFile);
+ else
+ $exception->setTemplateSource($input);
+ throw $exception;
+ }
+
+ /**
+ * Preprocesses the template string by including external templates
+ * @param string template string
+ * @return string expanded template string
+ */
+ protected function preprocess($input)
+ {
+ if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
+ {
+ for($i=0;$i<$n;++$i)
+ {
+ $filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
+ if($filePath!==null && is_file($filePath))
+ $this->_includedFiles[]=$filePath;
+ else
+ {
+ $errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1)));
+ $this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input);
+ }
+ }
+ $base=0;
+ for($i=0;$i<$n;++$i)
+ {
+ $ext=file_get_contents($this->_includedFiles[$i]);
+ $length=strlen($matches[$i][0][0]);
+ $offset=$base+$matches[$i][0][1];
+ $this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset)));
+ $this->_includeLines[$i]=count(explode("\n",$ext));
+ $input=substr_replace($input,$ext,$offset,$length);
+ $base+=strlen($ext)-$length;
+ }
+ }
+
+ return $input;
+ }
+
+ /**
+ * Checks if the given method belongs to a previously attached class behavior.
+ * @param ReflectionClass $class
+ * @param string $method
+ * @return boolean
+ */
+ protected function isClassBehaviorMethod(ReflectionClass $class,$method)
+ {
+ $component=new ReflectionClass('TComponent');
+ $behaviors=$component->getStaticProperties();
+ if(!isset($behaviors['_um']))
+ return false;
+ foreach($behaviors['_um'] as $name=>$list)
+ {
+ if(strtolower($class->getShortName())!==$name && !$class->isSubclassOf($name)) continue;
+ foreach($list as $param)
+ {
+ if(method_exists($param->getBehavior(),$method))
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/TThemeManager.php b/lib/prado/framework/Web/UI/TThemeManager.php
new file mode 100644
index 0000000..efc7268
--- /dev/null
+++ b/lib/prado/framework/Web/UI/TThemeManager.php
@@ -0,0 +1,513 @@
+<?php
+/**
+ * TThemeManager class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+Prado::using('System.Web.Services.TPageService');
+
+/**
+ * TThemeManager class
+ *
+ * TThemeManager manages the themes used in a Prado application.
+ *
+ * Themes are stored under the directory specified by the
+ * {@link setBasePath BasePath} property. The themes can be accessed
+ * via URL {@link setBaseUrl BaseUrl}. Each theme is represented by a subdirectory
+ * and all the files under that directory. The name of a theme is the name
+ * of the corresponding subdirectory.
+ * By default, the base path of all themes is a directory named "themes"
+ * under the directory containing the application entry script.
+ * To get a theme (normally you do not need to), call {@link getTheme}.
+ *
+ * TThemeManager may be configured within page service tag in application
+ * configuration file as follows,
+ * <module id="themes" class="System.Web.UI.TThemeManager"
+ * BasePath="Application.themes" BaseUrl="/themes" />
+ * where {@link getCacheExpire CacheExpire}, {@link getCacheControl CacheControl}
+ * and {@link getBufferOutput BufferOutput} are configurable properties of THttpResponse.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TThemeManager extends TModule
+{
+ /**
+ * default themes base path
+ */
+ const DEFAULT_BASEPATH='themes';
+
+ /**
+ * default theme class
+ */
+ const DEFAULT_THEMECLASS = 'TTheme';
+
+ /**
+ * @var string
+ */
+ private $_themeClass=self::DEFAULT_THEMECLASS;
+
+ /**
+ * @var boolean whether this module has been initialized
+ */
+ private $_initialized=false;
+ /**
+ * @var string the directory containing all themes
+ */
+ private $_basePath=null;
+ /**
+ * @var string the base URL for all themes
+ */
+ private $_baseUrl=null;
+
+ /**
+ * Initializes the module.
+ * This method is required by IModule and is invoked by application.
+ * @param TXmlElement module configuration
+ */
+ public function init($config)
+ {
+ $this->_initialized=true;
+ $service=$this->getService();
+ if($service instanceof TPageService)
+ $service->setThemeManager($this);
+ else
+ throw new TConfigurationException('thememanager_service_unavailable');
+ }
+
+ /**
+ * @param string name of the theme to be retrieved
+ * @return TTheme the theme retrieved
+ */
+ public function getTheme($name)
+ {
+ $themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name;
+ $themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name;
+ return Prado::createComponent($this->getThemeClass(), $themePath, $themeUrl);
+ }
+
+ /**
+ * @param string|null $class Theme class name in namespace format
+ */
+ public function setThemeClass($class) {
+ $this->_themeClass = $class===null ? self::DEFAULT_THEMECLASS : (string)$class;
+ }
+
+ /**
+ * @return string Theme class name in namespace format. Defaults to {@link TThemeManager::DEFAULT_THEMECLASS DEFAULT_THEMECLASS}.
+ */
+ public function getThemeClass() {
+ return $this->_themeClass;
+ }
+
+ /**
+ * @return array list of available theme names
+ */
+ public function getAvailableThemes()
+ {
+ $themes=array();
+ $basePath=$this->getBasePath();
+ $folder=@opendir($basePath);
+ while($file=@readdir($folder))
+ {
+ if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file))
+ $themes[]=$file;
+ }
+ closedir($folder);
+ return $themes;
+ }
+
+ /**
+ * @return string the base path for all themes. It is returned as an absolute path.
+ * @throws TConfigurationException if base path is not set and "themes" directory does not exist.
+ */
+ public function getBasePath()
+ {
+ if($this->_basePath===null)
+ {
+ $this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
+ if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
+ throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath);
+ $this->_basePath=$basePath;
+ }
+ return $this->_basePath;
+ }
+
+ /**
+ * @param string the base path for all themes. It must be in the format of a namespace.
+ * @throws TInvalidDataValueException if the base path is not a proper namespace.
+ */
+ public function setBasePath($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('thememanager_basepath_unchangeable');
+ else
+ {
+ $this->_basePath=Prado::getPathOfNamespace($value);
+ if($this->_basePath===null || !is_dir($this->_basePath))
+ throw new TInvalidDataValueException('thememanager_basepath_invalid',$value);
+ }
+ }
+
+ /**
+ * @return string the base URL for all themes.
+ * @throws TConfigurationException If base URL is not set and a correct one cannot be determined by Prado.
+ */
+ public function getBaseUrl()
+ {
+ if($this->_baseUrl===null)
+ {
+ $appPath=dirname($this->getRequest()->getApplicationFilePath());
+ $basePath=$this->getBasePath();
+ if(strpos($basePath,$appPath)===false)
+ throw new TConfigurationException('thememanager_baseurl_required');
+ $appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\');
+ $this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/');
+ }
+ return $this->_baseUrl;
+ }
+
+ /**
+ * @param string the base URL for all themes.
+ */
+ public function setBaseUrl($value)
+ {
+ $this->_baseUrl=rtrim($value,'/');
+ }
+}
+
+/**
+ * TTheme class
+ *
+ * TTheme represents a particular theme. It is merely a collection of skins
+ * that are applicable to the corresponding controls.
+ *
+ * Each theme is stored as a directory and files under that directory.
+ * The theme name is the directory name. When TTheme is created, the files
+ * whose name has the extension ".skin" are parsed and saved as controls skins.
+ *
+ * A skin is essentially a list of initial property values that are to be applied
+ * to a control when the skin is applied.
+ * Each type of control can have multiple skins identified by the SkinID.
+ * If a skin does not have SkinID, it is the default skin that will be applied
+ * to controls that do not specify particular SkinID.
+ *
+ * Whenever possible, TTheme will try to make use of available cache to save
+ * the parsing time.
+ *
+ * To apply a theme to a particular control, call {@link applySkin}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TTheme extends TApplicationComponent implements ITheme
+{
+ /**
+ * prefix for cache variable name used to store parsed themes
+ */
+ const THEME_CACHE_PREFIX='prado:theme:';
+ /**
+ * Extension name of skin files
+ */
+ const SKIN_FILE_EXT='.skin';
+ /**
+ * @var string theme path
+ */
+ private $_themePath;
+ /**
+ * @var string theme url
+ */
+ private $_themeUrl;
+ /**
+ * @var array list of skins for the theme
+ */
+ private $_skins=null;
+ /**
+ * @var string theme name
+ */
+ private $_name='';
+ /**
+ * @var array list of css files
+ */
+ private $_cssFiles=array();
+ /**
+ * @var array list of js files
+ */
+ private $_jsFiles=array();
+
+ /**
+ * Constructor.
+ * @param string theme path
+ * @param string theme URL
+ * @throws TConfigurationException if theme path does not exist or any parsing error of the skin files
+ */
+ public function __construct($themePath,$themeUrl)
+ {
+ $this->_themeUrl=$themeUrl;
+ $this->_themePath=realpath($themePath);
+ $this->_name=basename($themePath);
+ $cacheValid=false;
+ // TODO: the following needs to be cleaned up (Qiang)
+ if(($cache=$this->getApplication()->getCache())!==null)
+ {
+ $array=$cache->get(self::THEME_CACHE_PREFIX.$themePath);
+ if(is_array($array))
+ {
+ list($skins,$cssFiles,$jsFiles,$timestamp)=$array;
+ if($this->getApplication()->getMode()!==TApplicationMode::Performance)
+ {
+ if(($dir=opendir($themePath))===false)
+ throw new TIOException('theme_path_inexistent',$themePath);
+ $cacheValid=true;
+ while(($file=readdir($dir))!==false)
+ {
+ if($file==='.' || $file==='..')
+ continue;
+ else if(basename($file,'.css')!==$file)
+ $this->_cssFiles[]=$themeUrl.'/'.$file;
+ else if(basename($file,'.js')!==$file)
+ $this->_jsFiles[]=$themeUrl.'/'.$file;
+ else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp)
+ {
+ $cacheValid=false;
+ break;
+ }
+ }
+ closedir($dir);
+ if($cacheValid)
+ $this->_skins=$skins;
+ }
+ else
+ {
+ $cacheValid=true;
+ $this->_cssFiles=$cssFiles;
+ $this->_jsFiles=$jsFiles;
+ $this->_skins=$skins;
+ }
+ }
+ }
+ if(!$cacheValid)
+ {
+ $this->_cssFiles=array();
+ $this->_jsFiles=array();
+ $this->_skins=array();
+ if(($dir=opendir($themePath))===false)
+ throw new TIOException('theme_path_inexistent',$themePath);
+ while(($file=readdir($dir))!==false)
+ {
+ if($file==='.' || $file==='..')
+ continue;
+ else if(basename($file,'.css')!==$file)
+ $this->_cssFiles[]=$themeUrl.'/'.$file;
+ else if(basename($file,'.js')!==$file)
+ $this->_jsFiles[]=$themeUrl.'/'.$file;
+ else if(basename($file,self::SKIN_FILE_EXT)!==$file)
+ {
+ $template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file);
+ foreach($template->getItems() as $skin)
+ {
+ if(!isset($skin[2])) // a text string, ignored
+ continue;
+ else if($skin[0]!==-1)
+ throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
+ $type=$skin[1];
+ $id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
+ unset($skin[2]['skinid']);
+ if(isset($this->_skins[$type][$id]))
+ throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath));
+ /*
+ foreach($skin[2] as $name=>$value)
+ {
+ if(is_array($value) && ($value[0]===TTemplate::CONFIG_DATABIND || $value[0]===TTemplate::CONFIG_PARAMETER))
+ throw new TConfigurationException('theme_databind_forbidden',dirname($themePath),$type,$id);
+ }
+ */
+ $this->_skins[$type][$id]=$skin[2];
+ }
+ }
+ }
+ closedir($dir);
+ sort($this->_cssFiles);
+ sort($this->_jsFiles);
+ if($cache!==null)
+ $cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time()));
+ }
+ }
+
+ /**
+ * @return string theme name
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @param string theme name
+ */
+ protected function setName($value)
+ {
+ $this->_name = $value;
+ }
+
+ /**
+ * @return string the URL to the theme folder (without ending slash)
+ */
+ public function getBaseUrl()
+ {
+ return $this->_themeUrl;
+ }
+
+ /**
+ * @param string the URL to the theme folder
+ */
+ protected function setBaseUrl($value)
+ {
+ $this->_themeUrl=rtrim($value,'/');
+ }
+
+ /**
+ * @return string the file path to the theme folder
+ */
+ public function getBasePath()
+ {
+ return $this->_themePath;
+ }
+
+ /**
+ * @param string tthe file path to the theme folder
+ */
+ protected function setBasePath($value)
+ {
+ $this->_themePath=$value;
+ }
+
+ /**
+ * @return array list of skins for the theme
+ */
+ public function getSkins()
+ {
+ return $this->_skins;
+ }
+
+ /**
+ * @param array list of skins for the theme
+ */
+ protected function setSkins($value)
+ {
+ $this->_skins = $value;
+ }
+
+ /**
+ * Applies the theme to a particular control.
+ * The control's class name and SkinID value will be used to
+ * identify which skin to be applied. If the control's SkinID is empty,
+ * the default skin will be applied.
+ * @param TControl the control to be applied with a skin
+ * @return boolean if a skin is successfully applied
+ * @throws TConfigurationException if any error happened during the skin application
+ */
+ public function applySkin($control)
+ {
+ $type=get_class($control);
+ if(($id=$control->getSkinID())==='')
+ $id=0;
+ if(isset($this->_skins[$type][$id]))
+ {
+ foreach($this->_skins[$type][$id] as $name=>$value)
+ {
+ Prado::trace("Applying skin $name to $type",'System.Web.UI.TThemeManager');
+ if(is_array($value))
+ {
+ switch($value[0])
+ {
+ case TTemplate::CONFIG_EXPRESSION:
+ $value=$this->evaluateExpression($value[1]);
+ break;
+ case TTemplate::CONFIG_ASSET:
+ $value=$this->_themeUrl.'/'.ltrim($value[1],'/');
+ break;
+ case TTemplate::CONFIG_DATABIND:
+ $control->bindProperty($name,$value[1]);
+ break;
+ case TTemplate::CONFIG_PARAMETER:
+ $control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
+ break;
+ case TTemplate::CONFIG_TEMPLATE:
+ $control->setSubProperty($name,$value[1]);
+ break;
+ case TTemplate::CONFIG_LOCALIZATION:
+ $control->setSubProperty($name,Prado::localize($value[1]));
+ break;
+ default:
+ throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]);
+ break;
+ }
+ }
+ if(!is_array($value))
+ {
+ if(strpos($name,'.')===false) // is simple property or custom attribute
+ {
+ if($control->hasProperty($name))
+ {
+ if($control->canSetProperty($name))
+ {
+ $setter='set'.$name;
+ $control->$setter($value);
+ }
+ else
+ throw new TConfigurationException('theme_property_readonly',$type,$name);
+ }
+ else
+ throw new TConfigurationException('theme_property_undefined',$type,$name);
+ }
+ else // complex property
+ $control->setSubProperty($name,$value);
+ }
+ }
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * @return array list of CSS files (URL) in the theme
+ */
+ public function getStyleSheetFiles()
+ {
+ return $this->_cssFiles;
+ }
+
+ /**
+ * @param array list of CSS files (URL) in the theme
+ */
+ protected function setStyleSheetFiles($value)
+ {
+ $this->_cssFiles=$value;
+ }
+
+ /**
+ * @return array list of Javascript files (URL) in the theme
+ */
+ public function getJavaScriptFiles()
+ {
+ return $this->_jsFiles;
+ }
+
+ /**
+ * @param array list of Javascript files (URL) in the theme
+ */
+ protected function setJavaScriptFiles($value)
+ {
+ $this->_jsFiles=$value;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TAccordion.php b/lib/prado/framework/Web/UI/WebControls/TAccordion.php
new file mode 100644
index 0000000..d193613
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TAccordion.php
@@ -0,0 +1,740 @@
+<?php
+/**
+ * TAccordion class file.
+ *
+ * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+
+/**
+ * Class TAccordion.
+ *
+ * TAccordion displays an accordion control. Users can click on the view headers to switch among
+ * different accordion views. Each accordion view is an independent panel that can contain arbitrary content.
+ *
+ * A TAccordion control consists of one or several {@link TAccordionView} controls representing the possible
+ * accordion views. At any time, only one accordion view is visible (active), which is specified by any of
+ * the following properties:
+ * - {@link setActiveViewIndex ActiveViewIndex} - the zero-based integer index of the view in the view collection.
+ * - {@link setActiveViewID ActiveViewID} - the text ID of the visible view.
+ * - {@link setActiveView ActiveView} - the visible view instance.
+ * If both {@link setActiveViewIndex ActiveViewIndex} and {@link setActiveViewID ActiveViewID}
+ * are set, the latter takes precedence.
+ *
+ * TAccordion uses CSS to specify the appearance of the accordion headers and panel. By default,
+ * an embedded CSS file will be published which contains the default CSS for TTabPanel.
+ * You may also use your own CSS file by specifying the {@link setCssUrl CssUrl} property.
+ * The following properties specify the CSS classes used for elements in a TAccordion:
+ * - {@link setCssClass CssClass} - the CSS class name for the outer-most div element (defaults to 'accordion');
+ * - {@link setHeaderCssClass HeaderCssClass} - the CSS class name for nonactive accordion div elements (defaults to 'accordion-header');
+ * - {@link setActiveHeaderCssClass ActiveHeaderCssClass} - the CSS class name for the active accordion div element (defaults to 'accordion-header-active');
+ * - {@link setViewCssClass ViewCssClass} - the CSS class for the div element enclosing view content (defaults to 'accordion-view');
+ *
+ * When the user clicks on a view header, the switch between the old visible view and the clicked one is animated.
+ * You can use the {@link setAnimationDuration AnimationDuration} property to set the animation length in seconds;
+ * it defaults to 1 second, and when set to 0 it will produce an immediate switch with no animation.
+ *
+ * The TAccordion auto-sizes itself to the largest of all views, so it can encompass all of them without scrolling.
+ * If you want to specify a fixed height (in pixels), use the {@link setViewHeight ViewHeight} property.
+ * When a TAccordion is nested inside another, it's adviced to manually specify a {@link setViewHeight ViewHeight} for the internal TAccordion
+ *
+ * To use TAccordion, write a template like following:
+ * <code>
+ * <com:TAccordion>
+ * <com:TAccordionView Caption="View 1">
+ * content for view 1
+ * </com:TAccordionView>
+ * <com:TAccordionView Caption="View 2">
+ * content for view 2
+ * </com:TAccordionView>
+ * <com:TAccordionView Caption="View 3">
+ * content for view 3
+ * </com:TAccordionView>
+ * </com:TAccordion>
+ * </code>
+ *
+ * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+
+class TAccordion extends TWebControl implements IPostBackDataHandler
+{
+ private $_dataChanged=false;
+
+ /**
+ * @return string tag name for the control
+ */
+ protected function getTagName()
+ {
+ return 'div';
+ }
+
+ /**
+ * Adds object parsed from template to the control.
+ * This method adds only {@link TAccordionView} objects into the {@link getViews Views} collection.
+ * All other objects are ignored.
+ * @param mixed object parsed from template
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TAccordionView)
+ $this->getControls()->add($object);
+ }
+
+ /**
+ * Returns the index of the active accordion view.
+ * Note, this property may not return the correct index.
+ * To ensure the correctness, call {@link getActiveView()} first.
+ * @return integer the zero-based index of the active accordion view. If -1, it means no active accordion view. Default is 0 (the first view is active).
+ */
+ public function getActiveViewIndex()
+ {
+ return $this->getViewState('ActiveViewIndex',0);
+ }
+
+ /**
+ * @param integer the zero-based index of the current view in the view collection. -1 if no active view.
+ * @throws TInvalidDataValueException if the view index is invalid
+ */
+ public function setActiveViewIndex($value)
+ {
+ $this->setViewState('ActiveViewIndex',TPropertyValue::ensureInteger($value),0);
+ $this->setActiveViewID('');
+ }
+
+ /**
+ * Returns the ID of the active accordion view.
+ * Note, this property may not return the correct ID.
+ * To ensure the correctness, call {@link getActiveView()} first.
+ * @return string The ID of the active accordion view. Defaults to '', meaning not set.
+ */
+ public function getActiveViewID()
+ {
+ return $this->getViewState('ActiveViewID','');
+ }
+
+ /**
+ * @param string The ID of the active accordion view.
+ */
+ public function setActiveViewID($value)
+ {
+ $this->setViewState('ActiveViewID',$value,'');
+ }
+
+ /**
+ * Returns the currently active view.
+ * This method will examin the ActiveViewID, ActiveViewIndex and Views collection to
+ * determine which view is currently active. It will update ActiveViewID and ActiveViewIndex accordingly.
+ * @return TAccordionView the currently active view, null if no active view
+ * @throws TInvalidDataValueException if the active view ID or index set previously is invalid
+ */
+ public function getActiveView()
+ {
+ $activeView=null;
+ $views=$this->getViews();
+ if(($id=$this->getActiveViewID())!=='')
+ {
+ if(($index=$views->findIndexByID($id))>=0)
+ $activeView=$views->itemAt($index);
+ else
+ throw new TInvalidDataValueException('accordion_activeviewid_invalid',$id);
+ }
+ else if(($index=$this->getActiveViewIndex())>=0)
+ {
+ if($index<$views->getCount())
+ $activeView=$views->itemAt($index);
+ else
+ throw new TInvalidDataValueException('accordion_activeviewindex_invalid',$index);
+ }
+ else
+ {
+ foreach($views as $index=>$view)
+ {
+ if($view->getActive())
+ {
+ $activeView=$view;
+ break;
+ }
+ }
+ }
+ if($activeView!==null)
+ $this->activateView($activeView);
+ return $activeView;
+ }
+
+ /**
+ * @param TAccordionView the view to be activated
+ * @throws TInvalidOperationException if the view is not in the view collection
+ */
+ public function setActiveView($view)
+ {
+ if($this->getViews()->indexOf($view)>=0)
+ $this->activateView($view);
+ else
+ throw new TInvalidOperationException('accordion_view_inexistent');
+ }
+
+ /**
+ * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to ''.
+ */
+ public function getCssUrl()
+ {
+ return $this->getViewState('CssUrl','default');
+ }
+
+ /**
+ * @param string URL for the CSS file including all relevant CSS class definitions.
+ */
+ public function setCssUrl($value)
+ {
+ $this->setViewState('CssUrl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string CSS class for the whole accordion control div.
+ */
+ public function getCssClass()
+ {
+ $cssClass=parent::getCssClass();
+ return $cssClass===''?'accordion':$cssClass;
+ }
+
+ /**
+ * @return string CSS class for the currently displayed view div. Defaults to 'accordion-view'.
+ */
+ public function getViewCssClass()
+ {
+ return $this->getViewStyle()->getCssClass();
+ }
+
+ /**
+ * @param string CSS class for the currently displayed view div.
+ */
+ public function setViewCssClass($value)
+ {
+ $this->getViewStyle()->setCssClass($value);
+ }
+
+ /**
+ * @return string CSS class for the currently displayed view div. Defaults to 'accordion-view'.
+ */
+ public function getAnimationDuration()
+ {
+ return $this->getViewState('AnimationDuration','1');
+ }
+
+ /**
+ * @param string CSS class for the currently displayed view div.
+ */
+ public function setAnimationDuration($value)
+ {
+ $this->setViewState('AnimationDuration',$value);
+ }
+
+ /**
+ * @return TStyle the style for all the view div
+ */
+ public function getViewStyle()
+ {
+ if(($style=$this->getViewState('ViewStyle',null))===null)
+ {
+ $style=new TStyle;
+ $style->setCssClass('accordion-view');
+ $this->setViewState('ViewStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string CSS class for view headers. Defaults to 'accordion-header'.
+ */
+ public function getHeaderCssClass()
+ {
+ return $this->getHeaderStyle()->getCssClass();
+ }
+
+ /**
+ * @param string CSS class for view headers.
+ */
+ public function setHeaderCssClass($value)
+ {
+ $this->getHeaderStyle()->setCssClass($value);
+ }
+
+ /**
+ * @return TStyle the style for all the inactive header div
+ */
+ public function getHeaderStyle()
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))===null)
+ {
+ $style=new TStyle;
+ $style->setCssClass('accordion-header');
+ $this->setViewState('HeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string Extra CSS class for the active header. Defaults to 'accordion-header-active'.
+ */
+ public function getActiveHeaderCssClass()
+ {
+ return $this->getActiveHeaderStyle()->getCssClass();
+ }
+
+ /**
+ * @param string Extra CSS class for the active header. Will be added to the normal header specified by HeaderCssClass.
+ */
+ public function setActiveHeaderCssClass($value)
+ {
+ $this->getActiveHeaderStyle()->setCssClass($value);
+ }
+
+ /**
+ * @return TStyle the style for the active header div
+ */
+ public function getActiveHeaderStyle()
+ {
+ if(($style=$this->getViewState('ActiveHeaderStyle',null))===null)
+ {
+ $style=new TStyle;
+ $style->setCssClass('accordion-header-active');
+ $this->setViewState('ActiveHeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return integer Maximum height for the accordion views. If non specified, the accordion will auto-sized to the largest of all views, so it can encompass all of them without scrolling
+ */
+ public function getViewHeight()
+ {
+ return TPropertyValue::ensureInteger($this->getViewState('ViewHeight'));
+ }
+
+ /**
+ * @param integer Maximum height for the accordion views. If any of the accordion's views' content is larger, those views will be made scrollable when activated
+ */
+ public function setViewHeight($value)
+ {
+ $this->setViewState('ViewHeight', TPropertyValue::ensureInteger($value));
+ }
+
+ /**
+ * Activates the specified view.
+ * If there is any other view currently active, it will be deactivated.
+ * @param TAccordionView the view to be activated. If null, all views will be deactivated.
+ */
+ protected function activateView($view)
+ {
+ $this->setActiveViewIndex(-1);
+ $this->setActiveViewID('');
+ foreach($this->getViews() as $index=>$v)
+ {
+ if($view===$v)
+ {
+ $this->setActiveViewIndex($index);
+ $this->setActiveViewID($view->getID(false));
+ $view->setActive(true);
+ }
+ else
+ $v->setActive(false);
+ }
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if(($index=$values[$this->getClientID().'_1'])!==null)
+ {
+ $index=(int)$index;
+ $currentIndex=$this->getActiveViewIndex();
+ if($currentIndex!==$index)
+ {
+ $this->setActiveViewID(''); // clear up view ID
+ $this->setActiveViewIndex($index);
+ return $this->_dataChanged=true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method is required by {@link IPostBackDataHandler} interface.
+ * It is invoked by the framework when {@link getActiveViewIndex ActiveViewIndex} property
+ * is changed on postback.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ // do nothing
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $this->setCssClass($this->getCssClass());
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Registers CSS and JS.
+ * This method is invoked right before the control rendering, if the control is visible.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->getActiveView(); // determine the active view
+ $this->registerStyleSheet();
+ }
+
+ /**
+ * Registers the CSS relevant to the TAccordion.
+ * It will register the CSS file specified by {@link getCssUrl CssUrl}.
+ * If that is not set, it will use the default CSS.
+ */
+ protected function registerStyleSheet()
+ {
+ $url = $this->getCssUrl();
+
+ if($url === '') {
+ return;
+ }
+
+ if($url === 'default') {
+ $url = $this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'accordion.css');
+ }
+
+ if($url !== '') {
+ $this->getPage()->getClientScript()->registerStyleSheetFile($url, $url);
+ }
+ }
+
+ /**
+ * Registers the relevant JavaScript.
+ */
+ protected function registerClientScript()
+ {
+ $id=$this->getClientID();
+ $options=TJavaScript::encode($this->getClientOptions());
+ $className=$this->getClientClassName();
+ $page=$this->getPage();
+ $cs=$page->getClientScript();
+ $cs->registerPradoScript('accordion');
+ $code="new $className($options);";
+ $cs->registerEndScript("prado:$id", $code);
+ // ensure an item is always active and visible
+ $index = $this->getActiveViewIndex();
+ if(!$this->getViews()->itemAt($index)->Visible)
+ $index=0;
+ $cs->registerHiddenField($id.'_1', $index);
+ $page->registerRequiresPostData($this);
+ $page->registerRequiresPostData($id."_1");
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TAccordion';
+ }
+
+ /**
+ * @return array the options for JavaScript
+ */
+ protected function getClientOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['ActiveHeaderCssClass'] = $this->getActiveHeaderCssClass();
+ $options['HeaderCssClass'] = $this->getHeaderCssClass();
+ $options['Duration'] = $this->getAnimationDuration();
+
+ if (($viewheight = $this->getViewHeight())>0)
+ $options['maxHeight'] = $viewheight;
+ $views = array();
+ foreach($this->getViews() as $view)
+ $views[$view->getClientID()] = $view->getVisible() ? '1': '0';
+ $options['Views'] = $views;
+
+ return $options;
+ }
+
+ /**
+ * Creates a control collection object that is to be used to hold child controls
+ * @return TAccordionViewCollection control collection
+ */
+ protected function createControlCollection()
+ {
+ return new TAccordionViewCollection($this);
+ }
+
+ /**
+ * @return TAccordionViewCollection list of {@link TAccordionView} controls
+ */
+ public function getViews()
+ {
+ return $this->getControls();
+ }
+
+ public function render($writer)
+ {
+ $this->registerClientScript();
+ parent::render($writer);
+ }
+
+ /**
+ * Renders body contents of the accordion control.
+ * @param THtmlWriter the writer used for the rendering purpose.
+ */
+ public function renderContents($writer)
+ {
+ $views=$this->getViews();
+ if($views->getCount()>0)
+ {
+ $writer->writeLine();
+ foreach($views as $view)
+ {
+ $view->renderHeader($writer);
+ $view->renderControl($writer);
+ $writer->writeLine();
+ }
+ }
+ }
+
+}
+
+/**
+ * Class TAccordionView.
+ *
+ * TAccordionView represents a single view in a {@link TAccordion}.
+ *
+ * TAccordionView is represented inside the {@link TAccordion} with an header label whose text is defined by
+ * the {@link setCaption Caption} property; optionally the label can be an hyperlink: use the
+ * {@link setNavigateUrl NavigateUrl} property to define the destination url.
+ *
+ * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+class TAccordionView extends TWebControl
+{
+ private $_active=false;
+
+ /**
+ * @return the tag name for the view element
+ */
+ protected function getTagName()
+ {
+ return 'div';
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ if(!$this->getActive() && $this->getPage()->getClientSupportsJavaScript())
+ $this->getStyle()->setStyleField('display','none');
+
+ $this->getStyle()->mergeWith($this->getParent()->getViewStyle());
+
+ parent::addAttributesToRender($writer);
+
+ $writer->addAttribute('id',$this->getClientID());
+ }
+
+ /**
+ * @return string the caption displayed on this header. Defaults to ''.
+ */
+ public function getCaption()
+ {
+ return $this->getViewState('Caption','');
+ }
+
+ /**
+ * @param string the caption displayed on this header
+ */
+ public function setCaption($value)
+ {
+ $this->setViewState('Caption',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string the URL of the target page. Defaults to ''.
+ */
+ public function getNavigateUrl()
+ {
+ return $this->getViewState('NavigateUrl','');
+ }
+
+ /**
+ * Sets the URL of the target page.
+ * If not empty, clicking on this header will redirect the browser to the specified URL.
+ * @param string the URL of the target page.
+ */
+ public function setNavigateUrl($value)
+ {
+ $this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string the text content displayed on this view. Defaults to ''.
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text content to be displayed on this view.
+ * If this is not empty, the child content of the view will be ignored.
+ * @param string the text content displayed on this view
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return boolean whether this accordion view is active. Defaults to false.
+ */
+ public function getActive()
+ {
+ return $this->_active;
+ }
+
+ /**
+ * @param boolean whether this accordion view is active.
+ */
+ public function setActive($value)
+ {
+ $this->_active=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * Renders body contents of the accordion view.
+ * @param THtmlWriter the writer used for the rendering purpose.
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())!=='')
+ $writer->write($text);
+ else if($this->getHasControls())
+ parent::renderContents($writer);
+ }
+
+ /**
+ * Renders the header associated with the accordion view.
+ * @param THtmlWriter the writer for rendering purpose.
+ */
+ public function renderHeader($writer)
+ {
+ if($this->getVisible(false) && $this->getPage()->getClientSupportsJavaScript())
+ {
+ $writer->addAttribute('id',$this->getClientID().'_0');
+
+ $style=$this->getActive()?$this->getParent()->getActiveHeaderStyle():$this->getParent()->getHeaderStyle();
+
+ $style->addAttributesToRender($writer);
+
+ $writer->renderBeginTag($this->getTagName());
+
+ $this->renderHeaderContent($writer);
+
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Renders the content in the header.
+ * By default, a hyperlink is displayed.
+ * @param THtmlWriter the HTML writer
+ */
+ protected function renderHeaderContent($writer)
+ {
+ $url = $this->getNavigateUrl();
+ if(($caption=$this->getCaption())==='')
+ $caption='&nbsp;';
+
+ if ($url!='')
+ $writer->write("<a href=\"{$url}\">");
+ $writer->write("{$caption}");
+ if ($url!='')
+ $writer->write("</a>");
+ }
+}
+
+/**
+ * Class TAccordionViewCollection.
+ *
+ * TAccordionViewCollection is a collection of {@link TAccordionView} to be used inside a {@link TAccordion}.
+ *
+ * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+class TAccordionViewCollection extends TControlCollection
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing sanity check on the type of new item.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TAccordionView} object.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TAccordionView)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('tabviewcollection_tabview_required');
+ }
+
+ /**
+ * Finds the index of the accordion view whose ID is the same as the one being looked for.
+ * @param string the explicit ID of the accordion view to be looked for
+ * @return integer the index of the accordion view found, -1 if not found.
+ */
+ public function findIndexByID($id)
+ {
+ foreach($this as $index=>$view)
+ {
+ if($view->getID(false)===$id)
+ return $index;
+ }
+ return -1;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TBaseDataList.php b/lib/prado/framework/Web/UI/WebControls/TBaseDataList.php
new file mode 100644
index 0000000..4501073
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TBaseDataList.php
@@ -0,0 +1,188 @@
+<?php
+/**
+ * TBaseDataList class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TDataBoundControl and TDataFieldAccessor classes
+ */
+Prado::using('System.Web.UI.WebControls.TDataBoundControl');
+Prado::using('System.Util.TDataFieldAccessor');
+
+/**
+ * TBaseDataList class
+ *
+ * TBaseDataList is the base class for data listing controls, including
+ * {@link TDataList} and {@link TDataGrid}.
+ *
+ * The key field in the data source is specified by {@link setKeyField KeyField},
+ * while {@link getKeyValues KeyValues} stores the key values of each record in
+ * a data listing control. You may use the list item index to obtain the corresponding
+ * database key value.
+ *
+ * TBaseDataList also implements a few properties used for presentation based
+ * on tabular layout. The {@link setCaption Caption}, whose alignment is
+ * specified via {@link setCaptionAlign CaptionAlign}, is rendered as the table caption.
+ * The table cellpadding and cellspacing are specified by
+ * {@link setCellPadding CellPadding} and {@link setCellSpacing CellSpacing}
+ * properties, respectively. The {@link setGridLines GridLines} specifies how
+ * the table should display its borders, and the horizontal alignment of the table
+ * content can be specified via {@link setHorizontalAlign HorizontalAlign}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TBaseDataList extends TDataBoundControl
+{
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableStyle} to be used by the data list control.
+ * @return TTableStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableStyle;
+ }
+
+ /**
+ * @return integer the cellspacing for the table layout. Defaults to -1, meaning not set.
+ */
+ public function getCellSpacing()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getCellSpacing();
+ else
+ return -1;
+ }
+
+ /**
+ * @param integer the cellspacing for the table layout.
+ */
+ public function setCellSpacing($value)
+ {
+ $this->getStyle()->setCellSpacing($value);
+ }
+
+ /**
+ * @return integer the cellpadding for the table layout. Defaults to -1, meaning not set.
+ */
+ public function getCellPadding()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getCellPadding();
+ else
+ return -1;
+ }
+
+ /**
+ * @param integer the cellpadding for the table layout
+ */
+ public function setCellPadding($value)
+ {
+ $this->getStyle()->setCellPadding($value);
+ }
+
+ /**
+ * @return THorizontalAlign the horizontal alignment of the table content. Defaults to THorizontalAlign::NotSet.
+ */
+ public function getHorizontalAlign()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getHorizontalAlign();
+ else
+ return THorizontalAlign::NotSet;
+ }
+
+ /**
+ * @param THorizontalAlign the horizontal alignment of the table content.
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->getStyle()->setHorizontalAlign($value);
+ }
+
+ /**
+ * @return TTableGridLines the grid line setting of the table layout. Defaults to TTableGridLines::None.
+ */
+ public function getGridLines()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getGridLines();
+ else
+ return TTableGridLines::None;
+ }
+
+ /**
+ * Sets the grid line style of the table layout.
+ * @param TTableGridLines the grid line setting of the table
+ */
+ public function setGridLines($value)
+ {
+ $this->getStyle()->setGridLines($value);
+ }
+
+
+ /**
+ * @return string the field of the data source that provides the keys of the list items.
+ */
+ public function getDataKeyField()
+ {
+ return $this->getViewState('DataKeyField','');
+ }
+
+ /**
+ * @param string the field of the data source that provides the keys of the list items.
+ */
+ public function setDataKeyField($value)
+ {
+ $this->setViewState('DataKeyField',$value,'');
+ }
+
+ /**
+ * @return TList the keys used in the data listing control.
+ */
+ public function getDataKeys()
+ {
+ if(($dataKeys=$this->getViewState('DataKeys',null))===null)
+ {
+ $dataKeys=new TList;
+ $this->setViewState('DataKeys',$dataKeys,null);
+ }
+ return $dataKeys;
+ }
+
+ /**
+ * Returns the value of the data at the specified field.
+ * If data is an array, TMap or TList, the value will be returned at the index
+ * of the specified field. If the data is a component with a property named
+ * as the field name, the property value will be returned.
+ * Otherwise, an exception will be raised.
+ * @param mixed data item
+ * @param mixed field name
+ * @return mixed data value at the specified field
+ * @throws TInvalidDataValueException if the data is invalid
+ */
+ protected function getDataFieldValue($data,$field)
+ {
+ return TDataFieldAccessor::getDataFieldValue($data,$field);
+ }
+
+ /**
+ * Raises OnSelectedIndexChanged event.
+ * This method is invoked when a different item is selected
+ * in a data listing control between posts to the server.
+ * @param mixed event parameter
+ */
+ public function onSelectedIndexChanged($param)
+ {
+ $this->raiseEvent('OnSelectedIndexChanged',$this,$param);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TBaseValidator.php b/lib/prado/framework/Web/UI/WebControls/TBaseValidator.php
new file mode 100644
index 0000000..a74d4bc
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TBaseValidator.php
@@ -0,0 +1,747 @@
+<?php
+/**
+ * TBaseValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TLabel class
+ */
+Prado::using('System.Web.UI.WebControls.TLabel');
+
+/**
+ * TBaseValidator class
+ *
+ * TBaseValidator serves as the base class for validator controls.
+ *
+ * Validation is performed when a postback control, such as a TButton, a TLinkButton
+ * or a TTextBox (under AutoPostBack mode) is submitting the page and
+ * its <b>CausesValidation</b> property is true.
+ * You can also manually perform validation by calling {@link TPage::validate()}.
+ * The input control to be validated is specified by {@link setControlToValidate ControlToValidate}.
+ *
+ * Validator controls always validate the associated input control on the serve side.
+ * In addition, if {@link getEnableClientScript EnableClientScript} is true,
+ * validation will also be performed on the client-side using javascript.
+ * Client-side validation will validate user input before it is sent to the server.
+ * The form data will not be submitted if any error is detected. This avoids
+ * the round-trip of information necessary for server-side validation.
+ *
+ * You can use multiple validator controls to validate a single input control,
+ * each responsible for validating against a different criteria.
+ * For example, on a user registration form, you may want to make sure the user
+ * enters a value in the username text box, and the input must consist of only word
+ * characters. You can use a {@link TRequiredFieldValidator} to ensure the input
+ * of username and a {@link TRegularExpressionValidator} to ensure the proper input.
+ *
+ * If an input control fails validation, the text specified by the {@link setErrorMessage ErrorMessage}
+ * property is displayed in the validation control. However, if the {@link setText Text}
+ * property is set, it will be displayed instead. If both {@link setErrorMessage ErrorMessage}
+ * and {@link setText Text} are empty, the body content of the validator will
+ * be displayed. Error display is controlled by {@link setDisplay Display} property.
+ *
+ * You can also customized the client-side behaviour by adding javascript
+ * code to the subproperties of the {@link getClientSide ClientSide}
+ * property. See quickstart documentation for further details.
+ *
+ * You can also place a {@link TValidationSummary} control on a page to display error messages
+ * from the validators together. In this case, only the {@link setErrorMessage ErrorMessage}
+ * property of the validators will be displayed in the {@link TValidationSummary} control.
+ *
+ * Validators can be partitioned into validation groups by setting their
+ * {@link setValidationGroup ValidationGroup} property. If the control causing the
+ * validation also sets its ValidationGroup property, only those validators having
+ * the same ValidationGroup value will do input validation.
+ *
+ * Note, the {@link TPage::getIsValid IsValid} property of the current {@link TPage}
+ * instance will be automatically updated by the validation process which occurs
+ * after {@link TPage::onLoad onLoad} of {@link TPage} and before the postback events.
+ * Therefore, if you use the {@link TPage::getIsValid()} property in
+ * the {@link TPage::onLoad()} method, you must first explicitly call
+ * the {@link TPage::validate()} method.
+ *
+ * <b>Notes to Inheritors</b> When you inherit from TBaseValidator, you must
+ * override the method {@link evaluateIsValid}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TBaseValidator extends TLabel implements IValidator
+{
+ /**
+ * @var boolean whether the validation succeeds
+ */
+ private $_isValid=true;
+ /**
+ * @var boolean whether the validator has been registered with the page
+ */
+ private $_registered=false;
+ /**
+ * @var TValidatorClientSide validator client-script options.
+ */
+ private $_clientSide;
+ /**
+ * Controls for which the client-side validation3.js file needs to handle
+ * them specially.
+ * @var array list of control class names
+ */
+ private static $_clientClass = array('THtmlArea', 'THtmlArea4', 'TDatePicker', 'TListBox', 'TCheckBoxList');
+
+ /**
+ * Constructor.
+ * This method sets the foreground color to red.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setForeColor('red');
+ }
+
+ /**
+ * Registers the validator with page.
+ * @param mixed event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $this->getPage()->getValidators()->add($this);
+ $this->_registered=true;
+ }
+
+ /**
+ * Unregisters the validator from page.
+ * @param mixed event parameter
+ */
+ public function onUnload($param)
+ {
+ if($this->_registered && ($page=$this->getPage())!==null)
+ $page->getValidators()->remove($this);
+ $this->_registered=false;
+ parent::onUnload($param);
+ }
+
+ /**
+ * Adds attributes to renderer. Calls parent implementation and renders the
+ * client control scripts.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $display=$this->getDisplay();
+ $visible=$this->getEnabled(true) && !$this->getIsValid();
+ if($display===TValidatorDisplayStyle::None || (!$visible && $display===TValidatorDisplayStyle::Dynamic))
+ $writer->addStyleAttribute('display','none');
+ else if(!$visible)
+ $writer->addStyleAttribute('visibility','hidden');
+ $writer->addAttribute('id',$this->getClientID());
+ parent::addAttributesToRender($writer);
+ $this->renderClientControlScript($writer);
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $control = $this->getValidationTarget();
+ $options['ID'] = $this->getClientID();
+ $options['FormID'] = $this->getPage()->getForm()->getClientID();
+ $options['Display'] = $this->getDisplay();
+ $options['ErrorMessage'] = $this->getErrorMessage();
+ if($this->getFocusOnError())
+ {
+ $options['FocusOnError'] = $this->getFocusOnError();
+ $options['FocusElementID'] = $this->getFocusElementID();
+ }
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ if($control)
+ $options['ControlToValidate'] = $control->getClientID();
+ $options['ControlCssClass'] = $this->getControlCssClass();
+
+ $options['ControlType'] = $this->getClientControlClass($control);
+ $options['Enabled'] = $this->getEnabled(true);
+
+ //get date format from date picker target control
+ if($control instanceof TDatePicker)
+ $options['DateFormat'] = $control->getDateFormat();
+
+ $options = array_merge($options,$this->getClientSide()->getOptions()->toArray());
+
+ return $options;
+ }
+
+ /**
+ * Gets the Control type for client-side validation. If new cases exists in
+ * TBaseValidator::$_clientClass, be sure to update the corresponding
+ * "Javascript/validation3.js" file as well.
+ * @param TControl control to validate.
+ * @return string control type for client-side validation.
+ */
+ private function getClientControlClass($control)
+ {
+ foreach(self::$_clientClass as $type)
+ if($control instanceof $type)
+ return $type;
+ return get_class($control);
+ }
+
+ /**
+ * Gets the TValidatorClientSide that allows modification of the client-
+ * side validator events.
+ *
+ * The client-side validator supports the following events.
+ * # <tt>OnValidate</tt> -- raised before client-side validation is
+ * executed.
+ * # <tt>OnValidationSuccess</tt> -- raised after client-side validation is completed
+ * and is successfull, overrides default validator error messages updates.
+ * # <tt>OnValidationError</tt> -- raised after client-side validation is completed
+ * and failed, overrides default validator error message updates.
+ *
+ * You can attach custom javascript code to each of these events
+ *
+ * @return TValidatorClientSide javascript validator event options.
+ */
+ public function getClientSide()
+ {
+ if($this->_clientSide===null)
+ $this->_clientSide = $this->createClientSide();
+ return $this->_clientSide;
+ }
+
+ /**
+ * @return TValidatorClientSide javascript validator event options.
+ */
+ protected function createClientSide()
+ {
+ return new TValidatorClientSide;
+ }
+
+ /**
+ * Renders the javascript code to the end script.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param THtmlWriter the renderer
+ */
+ public function renderClientControlScript($writer)
+ {
+ $scripts = $this->getPage()->getClientScript();
+ if ($this->getEnableClientScript())
+ $scripts->registerPradoScript('validator');
+ $formID=$this->getPage()->getForm()->getClientID();
+ $scriptKey = "TBaseValidator:$formID";
+ if($this->getEnableClientScript() && !$scripts->isEndScriptRegistered($scriptKey))
+ {
+ $manager['FormID'] = $formID;
+ $options = TJavaScript::encode($manager);
+ $scripts->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});");
+ }
+ if($this->getEnableClientScript())
+ $this->registerClientScriptValidator();
+ }
+
+ /**
+ * Override parent implementation to update the control CSS Class before
+ * the validated control is rendered
+ */
+ public function onPreRender ($param)
+ {
+ parent::onPreRender($param);
+ $this->updateControlCssClass();
+ }
+
+ /**
+ * Update the ControlToValidate component's css class depending
+ * if the ControlCssClass property is set, and whether this is valid.
+ * @return boolean true if change, false otherwise.
+ */
+ protected function updateControlCssClass()
+ {
+ if(($cssClass=$this->getControlCssClass())!=='')
+ {
+ $control=$this->getValidationTarget();
+ if($control instanceof TWebControl)
+ {
+ $class = preg_replace ('/ '.preg_quote($cssClass).'/', '',$control->getCssClass());
+ if(!$this->getIsValid())
+ {
+ $class .= ' '.$cssClass;
+ $control->setCssClass($class);
+ } elseif ($control->getIsValid())
+ $control->setCssClass($class);
+ }
+ }
+ }
+
+ /**
+ * Registers the individual validator client-side javascript code.
+ */
+ protected function registerClientScriptValidator()
+ {
+ $key = 'prado:'.$this->getClientID();
+ if(!$this->getPage()->getClientScript()->isEndScriptRegistered($key))
+ {
+ $options = TJavaScript::encode($this->getClientScriptOptions());
+ $script = 'new '.$this->getClientClassName().'('.$options.');';
+ $this->getPage()->getClientScript()->registerEndScript($key, $script);
+ }
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ abstract protected function getClientClassName();
+
+ /**
+ * This method overrides the parent implementation to forbid setting ForControl.
+ * @param string the associated control ID
+ * @throws TNotSupportedException whenever this method is called
+ */
+ public function setForControl($value)
+ {
+ throw new TNotSupportedException('basevalidator_forcontrol_unsupported',get_class($this));
+ }
+
+ /**
+ * This method overrides parent's implementation by setting {@link setIsValid IsValid} to true if disabled.
+ * @param boolean whether the validator is enabled.
+ */
+ public function setEnabled($value)
+ {
+ $value=TPropertyValue::ensureBoolean($value);
+ parent::setEnabled($value);
+ if(!$value)
+ $this->_isValid=true;
+ }
+
+ /**
+ * @return TValidatorDisplayStyle the style of displaying the error message. Defaults to TValidatorDisplayStyle::Fixed.
+ */
+ public function getDisplay()
+ {
+ return $this->getViewState('Display',TValidatorDisplayStyle::Fixed);
+ }
+
+ /**
+ * @param TValidatorDisplayStyle the style of displaying the error message
+ */
+ public function setDisplay($value)
+ {
+ $this->setViewState('Display',TPropertyValue::ensureEnum($value,'TValidatorDisplayStyle'),TValidatorDisplayStyle::Fixed);
+ }
+
+ /**
+ * @return boolean whether client-side validation is enabled.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether client-side validation is enabled.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the text for the error message.
+ */
+ public function getErrorMessage()
+ {
+ return $this->getViewState('ErrorMessage','');
+ }
+
+ /**
+ * Sets the text for the error message.
+ * @param string the error message
+ */
+ public function setErrorMessage($value)
+ {
+ $this->setViewState('ErrorMessage',$value,'');
+ }
+
+ /**
+ * @return string the ID path of the input control to validate
+ */
+ public function getControlToValidate()
+ {
+ return $this->getViewState('ControlToValidate','');
+ }
+
+ /**
+ * Sets the ID path of the input control to validate.
+ * The ID path is the dot-connected IDs of the controls reaching from
+ * the validator's naming container to the target control.
+ * @param string the ID path
+ */
+ public function setControlToValidate($value)
+ {
+ $this->setViewState('ControlToValidate',$value,'');
+ }
+
+ /**
+ * @return boolean whether to set focus at the validating place if the validation fails. Defaults to false.
+ */
+ public function getFocusOnError()
+ {
+ return $this->getViewState('FocusOnError',false);
+ }
+
+ /**
+ * @param boolean whether to set focus at the validating place if the validation fails
+ */
+ public function setFocusOnError($value)
+ {
+ $this->setViewState('FocusOnError',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Gets the ID of the HTML element that will receive focus if validation fails and {@link getFocusOnError FocusOnError} is true.
+ * Defaults to the client ID of the {@link getControlToValidate ControlToValidate}.
+ * @return string the ID of the HTML element to receive focus
+ */
+ public function getFocusElementID()
+ {
+ if(($id=$this->getViewState('FocusElementID',''))==='')
+ {
+ $target=$this->getValidationTarget();
+ /* Workaround: TCheckBoxList and TRadioButtonList nests the actual
+ * inputs inside a table; we ensure the first input gets focused
+ */
+ if($target instanceof TCheckBoxList && $target->getItemCount()>0)
+ {
+ $id=$target->getClientID().'_c0';
+ } else {
+ $id=$target->getClientID();
+ }
+ }
+ return $id;
+ }
+
+ /**
+ * Sets the ID of the HTML element that will receive focus if validation fails and {@link getFocusOnError FocusOnError} is true.
+ * @param string the ID of the HTML element to receive focus
+ */
+ public function setFocusElementID($value)
+ {
+ $this->setViewState('FocusElementID', $value, '');
+ }
+
+ /**
+ * @return string the group which this validator belongs to
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group which this validator belongs to
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return boolean whether the validation succeeds
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+
+ /**
+ * Sets the value indicating whether the validation succeeds
+ * @param boolean whether the validation succeeds
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return TControl control to be validated. Null if no control is found.
+ * @throws TConfigurationException if {@link getControlToValidate
+ * ControlToValidate} is empty or does not point to a valid control
+ */
+ public function getValidationTarget()
+ {
+ if(($id=$this->getControlToValidate())!=='' && ($control=$this->findControl($id))!==null)
+ return $control;
+ else
+ throw new TConfigurationException('basevalidator_controltovalidate_invalid',get_class($this));
+ }
+
+ /**
+ * Retrieves the property value of the control being validated.
+ * @param TControl control being validated
+ * @return string property value to be validated
+ * @throws TInvalidDataTypeException if the control to be validated does not implement {@link IValidatable}.
+ */
+ protected function getValidationValue($control)
+ {
+ if($control instanceof IValidatable)
+ return $control->getValidationPropertyValue();
+ else
+ throw new TInvalidDataTypeException('basevalidator_validatable_required',get_class($this));
+ }
+
+ /**
+ * Validates the specified control.
+ * Do not override this method. Override {@link evaluateIsValid} instead.
+ * @return boolean whether the validation succeeds
+ */
+ public function validate()
+ {
+ $this->onValidate();
+ if($this->getVisible(true) && $this->getEnabled(true))
+ {
+ $target=$this->getValidationTarget();
+ // if the target is not a disabled web control
+ if($target===null ||
+ ($target!==null &&
+ !($target instanceof TWebControl && !$target->getEnabled(true))))
+ {
+ if($this->evaluateIsValid())
+ {
+ $this->setIsValid(true);
+ $this->onValidationSuccess();
+ }
+ else
+ {
+ if($target)
+ $target->setIsValid(false);
+ $this->setIsValid(false);
+ $this->onValidationError();
+ }
+ }
+ else
+ {
+ $this->evaluateIsValid();
+ $this->setIsValid(true);
+ $this->onValidationSuccess();
+ }
+ } else {
+ $this->setIsValid(true);
+ }
+ return $this->getIsValid();
+ }
+
+ /**
+ * @return string the css class that is applied to the control being validated in case the validation fails
+ */
+ public function getControlCssClass()
+ {
+ return $this->getViewState('ControlCssClass','');
+ }
+
+ /**
+ * @param string the css class that is applied to the control being validated in case the validation fails
+ */
+ public function setControlCssClass($value)
+ {
+ $this->setViewState('ControlCssClass',$value,'');
+ }
+
+ /**
+ * This is the major method for validation.
+ * Derived classes should implement this method to provide customized validation.
+ * @return boolean whether the validation succeeds
+ */
+ abstract protected function evaluateIsValid();
+
+ /**
+ * This event is raised when the validator succeeds in validation.
+ */
+ public function onValidationSuccess()
+ {
+ $this->raiseEvent('OnValidationSuccess',$this,null);
+ }
+
+ /**
+ * This event is raised when the validator fails in validation.
+ */
+ public function onValidationError()
+ {
+ $this->raiseEvent('OnValidationError',$this,null);
+ }
+
+ /**
+ * This event is raised right before the validator starts to perform validation.
+ * You may use this event to change the behavior of validation.
+ * For example, you may disable the validator if certain condition is satisfied.
+ * Note, the event will NOT be raised if the validator is invisible.
+ */
+ public function onValidate()
+ {
+ $this->raiseEvent('OnValidate',$this,null);
+ }
+
+ /**
+ * Renders the validator control.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())!=='')
+ $writer->write($text);
+ else if(($text=$this->getErrorMessage())!=='')
+ $writer->write($text);
+ else
+ parent::renderContents($writer);
+ }
+}
+
+/**
+ * TValidatorClientSide class.
+ *
+ * Client-side validator events can be modified through the {@link
+ * TBaseValidator::getClientSide ClientSide} property of a validator. The
+ * subproperties of ClientSide are those of the TValidatorClientSide
+ * properties. The client-side validator supports the following events.
+ *
+ * The <tt>OnValidate</tt> event is raise before the validator validation
+ * functions are called.
+ *
+ * The <tt>OnValidationSuccess</tt> event is raised after the validator has successfully
+ * validate the control.
+ *
+ * The <tt>OnValidationError</tt> event is raised after the validator fails validation.
+ *
+ * See the quickstart documentation for further details.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TValidatorClientSide extends TClientSideOptions
+{
+ /**
+ * @return string javascript code for client-side OnValidate event.
+ */
+ public function getOnValidate()
+ {
+ return $this->getOption('OnValidate');
+ }
+
+ /**
+ * Client-side OnValidate validator event is raise before the validators
+ * validation functions are called.
+ * @param string javascript code for client-side OnValidate event.
+ */
+ public function setOnValidate($javascript)
+ {
+ $this->setFunction('OnValidate', $javascript);
+ }
+
+ /**
+ * Client-side OnSuccess event is raise after validation is successfull.
+ * This will override the default client-side validator behaviour.
+ * @param string javascript code for client-side OnSuccess event.
+ */
+ public function setOnValidationSuccess($javascript)
+ {
+ $this->setFunction('OnValidationSuccess', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side OnSuccess event.
+ */
+ public function getOnValidationSuccess()
+ {
+ return $this->getOption('OnValidationSuccess');
+ }
+
+ /**
+ * Client-side OnError event is raised after validation failure.
+ * This will override the default client-side validator behaviour.
+ * @param string javascript code for client-side OnError event.
+ */
+ public function setOnValidationError($javascript)
+ {
+ $this->setFunction('OnValidationError', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side OnError event.
+ */
+ public function getOnValidationError()
+ {
+ return $this->getOption('OnValidationError');
+ }
+
+ /**
+ * @param boolean true to revalidate when the control to validate changes value.
+ */
+ public function setObserveChanges($value)
+ {
+ $this->setOption('ObserveChanges', TPropertyValue::ensureBoolean($value));
+ }
+
+ /**
+ * @return boolean true to observe changes.
+ */
+ public function getObserveChanges()
+ {
+ $changes = $this->getOption('ObserveChanges');
+ return ($changes===null) ? true : $changes;
+ }
+}
+
+
+/**
+ * TValidatorDisplayStyle class.
+ * TValidatorDisplayStyle defines the enumerable type for the possible styles
+ * that a validator control can display the error message.
+ *
+ * The following enumerable values are defined:
+ * - None: the error message is not displayed
+ * - Dynamic: the error message dynamically appears when the validator fails validation
+ * - Fixed: Similar to Dynamic except that the error message physically occupies the page layout (even though it may not be visible)
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TValidatorDisplayStyle extends TEnumerable
+{
+ const None='None';
+ const Dynamic='Dynamic';
+ const Fixed='Fixed';
+}
+
+/**
+ * TValidationDataType class.
+ * TValidationDataType defines the enumerable type for the possible data types that
+ * a comparison validator can validate upon.
+ *
+ * The following enumerable values are defined:
+ * - Integer
+ * - Float
+ * - Date
+ * - String
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TValidationDataType extends TEnumerable
+{
+ const Integer='Integer';
+ const Float='Float';
+ const Date='Date';
+ const String='String';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TBoundColumn.php b/lib/prado/framework/Web/UI/WebControls/TBoundColumn.php
new file mode 100644
index 0000000..95697bd
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TBoundColumn.php
@@ -0,0 +1,247 @@
+<?php
+/**
+ * TBoundColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+
+/**
+ * TBoundColumn class
+ *
+ * TBoundColumn represents a column that is bound to a field in a data source.
+ * The cells in the column will be displayed using the data indexed by
+ * {@link setDataField DataField}. You can customize the display by
+ * setting {@link setDataFormatString DataFormatString}.
+ *
+ * If {@link setReadOnly ReadOnly} is false, TBoundColumn will display cells in edit mode
+ * with textboxes. Otherwise, a static text is displayed.
+ *
+ * When a datagrid row is in edit mode, the textbox control in the TBoundColumn
+ * can be accessed by one of the following two methods:
+ * <code>
+ * $datagridItem->BoundColumnID->TextBox
+ * $datagridItem->BoundColumnID->Controls[0]
+ * </code>
+ * The second method is possible because the textbox control created within the
+ * datagrid cell is the first child.
+ *
+ * Since v3.1.0, TBoundColumn has introduced two new properties {@link setItemRenderer ItemRenderer}
+ * and {@link setEditItemRenderer EditItemRenderer} which can be used to specify
+ * the layout of the datagrid cells in browsing and editing mode.
+ * A renderer refers to a control class that is to be instantiated as a control.
+ * For more details, see {@link TRepeater} and {@link TDataList}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TBoundColumn extends TDataGridColumn
+{
+ /**
+ * @return string the class name for the item cell renderer. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getItemRenderer()
+ {
+ return $this->getViewState('ItemRenderer','');
+ }
+
+ /**
+ * Sets the item cell renderer class.
+ *
+ * If not empty, the class will be used to instantiate as a child control in the item cells of the column.
+ *
+ * If the class implements {@link IDataRenderer}, the <b>Data</b> property
+ * will be set as the data associated with the datagrid cell during databinding.
+ * The data can be either the whole data row or a field of the row if
+ * {@link getDataField DataField} is not empty. If {@link getDataFormatString DataFormatString}
+ * is not empty, the data will be formatted first before passing to the renderer.
+ *
+ * @param string the renderer class name in namespace format.
+ * @since 3.1.0
+ */
+ public function setItemRenderer($value)
+ {
+ $this->setViewState('ItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for the edit item cell renderer. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getEditItemRenderer()
+ {
+ return $this->getViewState('EditItemRenderer','');
+ }
+
+ /**
+ * Sets the edit item cell renderer class.
+ *
+ * If not empty, the class will be used to instantiate as a child control in the item cell that is in edit mode.
+ *
+ * If the class implements {@link IDataRenderer}, the <b>Data</b> property
+ * will be set as the data associated with the datagrid cell during databinding.
+ * The data can be either the whole data row or a field of the row if
+ * {@link getDataField DataField} is not empty. If {@link getDataFormatString DataFormatString}
+ * is not empty, the data will be formatted first before passing to the renderer.
+ *
+ * @param string the renderer class name in namespace format.
+ * @since 3.1.0
+ */
+ public function setEditItemRenderer($value)
+ {
+ $this->setViewState('EditItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the field name from the data source to bind to the column
+ */
+ public function getDataField()
+ {
+ return $this->getViewState('DataField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the column
+ */
+ public function setDataField($value)
+ {
+ $this->setViewState('DataField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the bound data will be displayed.
+ */
+ public function getDataFormatString()
+ {
+ return $this->getViewState('DataFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the bound data will be displayed.
+ */
+ public function setDataFormatString($value)
+ {
+ $this->setViewState('DataFormatString',$value,'');
+ }
+
+ /**
+ * @return boolean whether the items in the column can be edited. Defaults to false.
+ */
+ public function getReadOnly()
+ {
+ return $this->getViewState('ReadOnly',false);
+ }
+
+ /**
+ * @param boolean whether the items in the column can be edited
+ */
+ public function setReadOnly($value)
+ {
+ $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates a textbox for item in edit mode and the column is not read-only.
+ * Otherwise it displays a static text.
+ * The caption of the button and the static text are retrieved
+ * from the datasource.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ $item=$cell->getParent();
+ switch($itemType)
+ {
+ case TListItemType::Item:
+ case TListItemType::AlternatingItem:
+ case TListItemType::SelectedItem:
+ if(($classPath=$this->getItemRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ if($control instanceof IItemDataRenderer)
+ {
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $cell->getControls()->add($control);
+ }
+ else
+ $control=$cell;
+ $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ break;
+ case TListItemType::EditItem:
+ if(!$this->getReadOnly())
+ {
+ if(($classPath=$this->getEditItemRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ if($control instanceof IItemDataRenderer)
+ {
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $cell->getControls()->add($control);
+ $cell->registerObject('EditControl',$control);
+ }
+ else
+ {
+ $control=Prado::createComponent('System.Web.UI.WebControls.TTextBox');
+ $cell->getControls()->add($control);
+ $cell->registerObject('TextBox',$control);
+ }
+ }
+ else
+ {
+ if(($classPath=$this->getItemRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ if($control instanceof IItemDataRenderer)
+ {
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $cell->getControls()->add($control);
+ }
+ else
+ $control=$cell;
+ }
+ $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ break;
+ default:
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ break;
+ }
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $data=$item->getData();
+ $formatString=$this->getDataFormatString();
+ if(($field=$this->getDataField())!=='')
+ $value=$this->formatDataValue($formatString,$this->getDataFieldValue($data,$field));
+ else
+ $value=$this->formatDataValue($formatString,$data);
+ $sender->setData($value);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TBulletedList.php b/lib/prado/framework/Web/UI/WebControls/TBulletedList.php
new file mode 100644
index 0000000..5d4167e
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TBulletedList.php
@@ -0,0 +1,487 @@
+<?php
+/**
+ * TBulletedList class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TListControl class
+ */
+Prado::using('System.Web.UI.WebControls.TListControl');
+
+/**
+ * TBulletedList class
+ *
+ * TBulletedList displays items in a bullet format.
+ * The bullet style is specified by {@link setBulletStyle BulletStyle}. When
+ * the style is 'CustomImage', the {@link setBackImageUrl BulletImageUrl}
+ * specifies the image used as bullets.
+ *
+ * TBulletedList displays the item texts in three different modes, specified
+ * via {@link setDisplayMode DisplayMode}. When the mode is Text, the item texts
+ * are displayed as static texts; When the mode is 'HyperLink', each item
+ * is displayed as a hyperlink whose URL is given by the item value, and the
+ * {@link setTarget Target} property can be used to specify the target browser window;
+ * When the mode is 'LinkButton', each item is displayed as a link button which
+ * posts back to the page if a user clicks on that and the event {@link onClick OnClick}
+ * will be raised under such a circumstance.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TBulletedList extends TListControl implements IPostBackEventHandler
+{
+ /**
+ * @var boolean cached property value of Enabled
+ */
+ private $_isEnabled;
+ /**
+ * @var TPostBackOptions postback options
+ */
+ private $_postBackOptions;
+
+ private $_currentRenderItemIndex;
+
+ /**
+ * Raises the postback event.
+ * This method is required by {@link IPostBackEventHandler} interface.
+ * If {@link getCausesValidation CausesValidation} is true, it will
+ * invoke the page's {@link TPage::validate validate} method first.
+ * It will raise {@link onClick OnClick} events.
+ * This method is mainly used by framework and control developers.
+ * @param TEventParameter the event parameter
+ */
+ public function raisePostBackEvent($param)
+ {
+ if($this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onClick(new TBulletedListEventParameter((int)$param));
+ }
+
+ /**
+ * @return string tag name of the bulleted list
+ */
+ protected function getTagName()
+ {
+ switch($this->getBulletStyle())
+ {
+ case TBulletStyle::Numbered:
+ case TBulletStyle::LowerAlpha:
+ case TBulletStyle::UpperAlpha:
+ case TBulletStyle::LowerRoman:
+ case TBulletStyle::UpperRoman:
+ return 'ol';
+ }
+ return 'ul';
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TBulletedList';
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This overrides the parent implementation with additional bulleted list specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $needStart=false;
+ switch($this->getBulletStyle())
+ {
+ case TBulletStyle::None:
+ $writer->addStyleAttribute('list-style-type','none');
+ $needStart=true;
+ break;
+ case TBulletStyle::Numbered:
+ $writer->addStyleAttribute('list-style-type','decimal');
+ $needStart=true;
+ break;
+ case TBulletStyle::LowerAlpha:
+ $writer->addStyleAttribute('list-style-type','lower-alpha');
+ $needStart=true;
+ break;
+ case TBulletStyle::UpperAlpha:
+ $writer->addStyleAttribute('list-style-type','upper-alpha');
+ $needStart=true;
+ break;
+ case TBulletStyle::LowerRoman:
+ $writer->addStyleAttribute('list-style-type','lower-roman');
+ $needStart=true;
+ break;
+ case TBulletStyle::UpperRoman:
+ $writer->addStyleAttribute('list-style-type','upper-roman');
+ $needStart=true;
+ break;
+ case TBulletStyle::Disc:
+ $writer->addStyleAttribute('list-style-type','disc');
+ break;
+ case TBulletStyle::Circle:
+ $writer->addStyleAttribute('list-style-type','circle');
+ break;
+ case TBulletStyle::Square:
+ $writer->addStyleAttribute('list-style-type','square');
+ break;
+ case TBulletStyle::CustomImage:
+ $url=$this->getBulletImageUrl();
+ $writer->addStyleAttribute('list-style-image',"url($url)");
+ break;
+ }
+ if($needStart && ($start=$this->getFirstBulletNumber())!=1)
+ $writer->addAttribute('start',"$start");
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * @return string image URL used for bullets when {@link getBulletStyle BulletStyle} is 'CustomImage'.
+ */
+ public function getBulletImageUrl()
+ {
+ return $this->getViewState('BulletImageUrl','');
+ }
+
+ /**
+ * @param string image URL used for bullets when {@link getBulletStyle BulletStyle} is 'CustomImage'.
+ */
+ public function setBulletImageUrl($value)
+ {
+ $this->setViewState('BulletImageUrl',$value,'');
+ }
+
+ /**
+ * @return TBulletStyle style of bullets. Defaults to TBulletStyle::NotSet.
+ */
+ public function getBulletStyle()
+ {
+ return $this->getViewState('BulletStyle',TBulletStyle::NotSet);
+ }
+
+ /**
+ * @param TBulletStyle style of bullets.
+ */
+ public function setBulletStyle($value)
+ {
+ $this->setViewState('BulletStyle',TPropertyValue::ensureEnum($value,'TBulletStyle'),TBulletStyle::NotSet);
+ }
+
+ /**
+ * @return TBulletedListDisplayMode display mode of the list. Defaults to TBulletedListDisplayMode::Text.
+ */
+ public function getDisplayMode()
+ {
+ return $this->getViewState('DisplayMode',TBulletedListDisplayMode::Text);
+ }
+
+ /**
+ * @return TBulletedListDisplayMode display mode of the list.
+ */
+ public function setDisplayMode($value)
+ {
+ $this->setViewState('DisplayMode',TPropertyValue::ensureEnum($value,'TBulletedListDisplayMode'),TBulletedListDisplayMode::Text);
+ }
+
+ /**
+ * @return integer starting index when {@link getBulletStyle BulletStyle} is one of
+ * the following: 'Numbered', 'LowerAlpha', 'UpperAlpha', 'LowerRoman', 'UpperRoman'.
+ * Defaults to 1.
+ */
+ public function getFirstBulletNumber()
+ {
+ return $this->getViewState('FirstBulletNumber',1);
+ }
+
+ /**
+ * @param integer starting index when {@link getBulletStyle BulletStyle} is one of
+ * the following: 'Numbered', 'LowerAlpha', 'UpperAlpha', 'LowerRoman', 'UpperRoman'.
+ */
+ public function setFirstBulletNumber($value)
+ {
+ $this->setViewState('FirstBulletNumber',TPropertyValue::ensureInteger($value),1);
+ }
+
+ /**
+ * Raises 'OnClick' event.
+ * This method is invoked when the {@link getDisplayMode DisplayMode} is 'LinkButton'
+ * and end-users click on one of the buttons.
+ * @param TBulletedListEventParameter event parameter.
+ */
+ public function onClick($param)
+ {
+ $this->raiseEvent('OnClick',$this,$param);
+ }
+
+ /**
+ * @return string the target window or frame to display the Web page content
+ * linked to when {@link getDisplayMode DisplayMode} is 'HyperLink' and one of
+ * the hyperlinks is clicked.
+ */
+ public function getTarget()
+ {
+ return $this->getViewState('Target','');
+ }
+
+ /**
+ * @param string the target window or frame to display the Web page content
+ * linked to when {@link getDisplayMode DisplayMode} is 'HyperLink' and one of
+ * the hyperlinks is clicked.
+ */
+ public function setTarget($value)
+ {
+ $this->setViewState('Target',$value,'');
+ }
+
+ /**
+ * Renders the control.
+ * @param THtmlWriter the writer for the rendering purpose.
+ */
+ public function render($writer)
+ {
+ if($this->getHasItems())
+ parent::render($writer);
+ }
+
+ /**
+ * Renders the body contents.
+ * @param THtmlWriter the writer for the rendering purpose.
+ */
+ public function renderContents($writer)
+ {
+ $this->_isEnabled=$this->getEnabled(true);
+ $this->_postBackOptions=$this->getPostBackOptions();
+ $writer->writeLine();
+ foreach($this->getItems() as $index=>$item)
+ {
+ if($item->getHasAttributes())
+ $writer->addAttributes($item->getAttributes());
+ $writer->renderBeginTag('li');
+ $this->renderBulletText($writer,$item,$index);
+ $writer->renderEndTag();
+ $writer->writeLine();
+ }
+ }
+
+ /**
+ * Renders each item
+ * @param THtmlWriter writer for the rendering purpose
+ * @param TListItem item to be rendered
+ * @param integer index of the item being rendered
+ */
+ protected function renderBulletText($writer,$item,$index)
+ {
+ switch($this->getDisplayMode())
+ {
+ case TBulletedListDisplayMode::Text:
+ $this->renderTextItem($writer, $item, $index);
+ break;
+ case TBulletedListDisplayMode::HyperLink:
+ $this->renderHyperLinkItem($writer, $item, $index);
+ break;
+ case TBulletedListDisplayMode::LinkButton:
+ $this->renderLinkButtonItem($writer, $item, $index);
+ break;
+ }
+ }
+
+ protected function renderTextItem($writer, $item, $index)
+ {
+ if($item->getEnabled())
+ $writer->write(THttpUtility::htmlEncode($item->getText()));
+ else
+ {
+ $writer->addAttribute('disabled','disabled');
+ $writer->renderBeginTag('span');
+ $writer->write(THttpUtility::htmlEncode($item->getText()));
+ $writer->renderEndTag();
+ }
+ }
+
+ protected function renderHyperLinkItem($writer, $item, $index)
+ {
+ if(!$this->_isEnabled || !$item->getEnabled())
+ $writer->addAttribute('disabled','disabled');
+ else
+ {
+ $writer->addAttribute('href',$item->getValue());
+ if(($target=$this->getTarget())!=='')
+ $writer->addAttribute('target',$target);
+ }
+ if(($accesskey=$this->getAccessKey())!=='')
+ $writer->addAttribute('accesskey',$accesskey);
+ $writer->renderBeginTag('a');
+ $writer->write(THttpUtility::htmlEncode($item->getText()));
+ $writer->renderEndTag();
+ }
+
+ protected function renderLinkButtonItem($writer, $item, $index)
+ {
+ if(!$this->_isEnabled || !$item->getEnabled())
+ $writer->addAttribute('disabled','disabled');
+ else
+ {
+ $this->_currentRenderItemIndex = $index;
+ $writer->addAttribute('id', $this->getClientID().$index);
+ $writer->addAttribute('href', "javascript:;//".$this->getClientID().$index);
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+ if(($accesskey=$this->getAccessKey())!=='')
+ $writer->addAttribute('accesskey',$accesskey);
+ $writer->renderBeginTag('a');
+ $writer->write(THttpUtility::htmlEncode($item->getText()));
+ $writer->renderEndTag();
+ }
+
+ /**
+ * @return array postback options used for linkbuttons.
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['EventParameter'] = $this->_currentRenderItemIndex;
+ $options['ID'] = $this->getClientID().$this->_currentRenderItemIndex;
+ $options['StopEvent'] = true;
+ return $options;
+ }
+
+ protected function canCauseValidation()
+ {
+ $group = $this->getValidationGroup();
+ $hasValidators = $this->getPage()->getValidators($group)->getCount()>0;
+ return $this->getCausesValidation() && $hasValidators;
+ }
+
+ /**
+ * @throws TNotSupportedException if this method is invoked
+ */
+ public function setAutoPostBack($value)
+ {
+ throw new TNotSupportedException('bulletedlist_autopostback_unsupported');
+ }
+
+ /**
+ * @throws TNotSupportedException if this method is invoked
+ */
+ public function setSelectedIndex($index)
+ {
+ throw new TNotSupportedException('bulletedlist_selectedindex_unsupported');
+ }
+
+ /**
+ * @throws TNotSupportedException if this method is invoked
+ */
+ public function setSelectedIndices($indices)
+ {
+ throw new TNotSupportedException('bulletedlist_selectedindices_unsupported');
+ }
+
+ /**
+ * @throws TNotSupportedException if this method is invoked
+ */
+ public function setSelectedValue($value)
+ {
+ throw new TNotSupportedException('bulletedlist_selectedvalue_unsupported');
+ }
+
+ /**
+ * @throws TNotSupportedException if this method is invoked
+ */
+ public function setSelectedValues($values)
+ {
+ throw new TNotSupportedException('bulletedlist_selectedvalue_unsupported');
+ }
+}
+
+/**
+ * TBulletedListEventParameter
+ * Event parameter for {@link TBulletedList::onClick Click} event of the
+ * bulleted list. The {@link getIndex Index} gives the zero-based index
+ * of the item that is currently being clicked.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TBulletedListEventParameter extends TEventParameter
+{
+ /**
+ * @var integer index of the item clicked
+ */
+ private $_index;
+
+ /**
+ * Constructor.
+ * @param integer index of the item clicked
+ */
+ public function __construct($index)
+ {
+ $this->_index=$index;
+ }
+
+ /**
+ * @return integer zero-based index of the item (rendered as a link button) that is clicked
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+}
+
+/**
+ * TBulletStyle class.
+ * TBulletStyle defines the enumerable type for the possible bullet styles that may be used
+ * for a {@link TBulletedList} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TBulletStyle extends TEnumerable
+{
+ const NotSet='NotSet';
+ const None='None';
+ const Numbered='Numbered';
+ const LowerAlpha='LowerAlpha';
+ const UpperAlpha='UpperAlpha';
+ const LowerRoman='LowerRoman';
+ const UpperRoman='UpperRoman';
+ const Disc='Disc';
+ const Circle='Circle';
+ const Square='Square';
+ const CustomImage='CustomImage';
+}
+
+/**
+ * TBulletedListDisplayMode class.
+ * TBulletedListDisplayMode defines the enumerable type for the possible display mode
+ * of a {@link TBulletedList} control.
+ *
+ * The following enumerable values are defined:
+ * - Text: the bulleted list items are displayed as plain texts
+ * - HyperLink: the bulleted list items are displayed as hyperlinks
+ * - LinkButton: the bulleted list items are displayed as link buttons that can cause postbacks
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TBulletedListDisplayMode extends TEnumerable
+{
+ const Text='Text';
+ const HyperLink='HyperLink';
+ const LinkButton='LinkButton';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TButton.php b/lib/prado/framework/Web/UI/WebControls/TButton.php
new file mode 100644
index 0000000..aed518a
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TButton.php
@@ -0,0 +1,404 @@
+<?php
+/**
+ * TButton class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TButton class
+ *
+ * TButton creates a click button on the page. It is mainly used to submit data to a page.
+ *
+ * TButton raises two server-side events, {@link onClick OnClick} and {@link onCommand OnCommand},
+ * when it is clicked on the client-side. The difference between these two events
+ * is that the event {@link onCommand OnCommand} is bubbled up to the button's ancestor controls.
+ * And within the event parameter for {@link onCommand OnCommand} contains the reference
+ * to the {@link setCommandName CommandName} and {@link setCommandParameter CommandParameter}
+ * property values that are set for the button object. This allows you to create multiple TButton
+ * components on a Web page and programmatically determine which one is clicked
+ * with what parameter.
+ *
+ * Clicking on button can also trigger form validation, if
+ * {@link setCausesValidation CausesValidation} is true.
+ * The validation may be restricted within a certain group of validator
+ * controls by setting {@link setValidationGroup ValidationGroup} property.
+ * If validation is successful, the data will be post back to the same page.
+ *
+ * TButton displays the {@link setText Text} property as the button caption.
+ *
+ * TButton can be one of three {@link setButtonType ButtonType}: Submit, Button and Reset.
+ * By default, it is a Submit button and the form submission uses the browser's
+ * default submission capability. If it is Button or Reset, postback may occur
+ * if one of the following conditions is met:
+ * - an event handler is attached to {@link onClick OnClick} event;
+ * - an event handler is attached to {@link onCommand OnCommand} event;
+ * - the button is in a non-empty validation group.
+ * In addition, clicking on a Reset button will clear up all input fields
+ * if the button does not cause a postback.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TButton extends TWebControl implements IPostBackEventHandler, IButtonControl, IDataRenderer
+{
+ /**
+ * @return string tag name of the button
+ */
+ protected function getTagName()
+ {
+ return strtolower($this->getButtonTag());
+ }
+
+ /**
+ * @return TButtonTag the tag name of the button. Defaults to TButtonType::Input.
+ */
+ public function getButtonTag()
+ {
+ return $this->getViewState('ButtonTag',TButtonTag::Input);
+ }
+
+ /**
+ * @param TButtonTag the tag name of the button.
+ */
+ public function setButtonTag($value)
+ {
+ $this->setViewState('ButtonTag',TPropertyValue::ensureEnum($value,'TButtonTag'),TButtonTag::Input);
+ }
+
+ /**
+ * @return boolean whether to render javascript.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether to render javascript.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This overrides the parent implementation with additional button specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $page=$this->getPage();
+ $page->ensureRenderInForm($this);
+ $writer->addAttribute('type',strtolower($this->getButtonType()));
+ if(($uniqueID=$this->getUniqueID())!=='')
+ $writer->addAttribute('name',$uniqueID);
+ if($this->getButtonTag()===TButtonTag::Button)
+ $this->addParsedObject($this->getText());
+ else
+ $writer->addAttribute('value',$this->getText());
+ if($this->getEnabled(true))
+ {
+ if($this->getEnableClientScript() && $this->needPostBackScript())
+ $this->renderClientControlScript($writer);
+ }
+ else if($this->getEnabled()) // in this case, parent will not render 'disabled'
+ $writer->addAttribute('disabled','disabled');
+
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the client-script code.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $this->getPage()->getClientScript()->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TButton';
+ }
+
+ /**
+ * @return boolean whether to perform validation if the button is clicked
+ */
+ protected function canCauseValidation()
+ {
+ if($this->getCausesValidation())
+ {
+ $group=$this->getValidationGroup();
+ return $this->getPage()->getValidators($group)->getCount()>0;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * @param boolean set by a panel to register this button as the default button for the panel.
+ */
+ public function setIsDefaultButton($value)
+ {
+ $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean true if this button is registered as a default button for a panel.
+ */
+ public function getIsDefaultButton()
+ {
+ return $this->getViewState('IsDefaultButton', false);
+ }
+
+ /**
+ * @return boolean whether the button needs javascript to do postback
+ */
+ protected function needPostBackScript()
+ {
+ return $this->canCauseValidation() || ($this->getButtonType()!==TButtonType::Submit &&
+ ($this->hasEventHandler('OnClick') || $this->hasEventHandler('OnCommand')))
+ || $this->getIsDefaultButton();
+ }
+
+ /**
+ * Returns postback specifications for the button.
+ * This method is used by framework and control developers.
+ * @return array parameters about how the button defines its postback behavior.
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID']=$this->getClientID();
+ $options['CausesValidation']=$this->getCausesValidation();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['ValidationGroup']=$this->getValidationGroup();
+
+ return $options;
+ }
+
+ /**
+ * Renders the body content enclosed between the control tag.
+ * This overrides the parent implementation with nothing to be rendered for input tags,
+ * button tags are rendered normally.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ if($this->getButtonTag()===TButtonTag::Button)
+ parent::renderContents($writer);
+ }
+
+ /**
+ * This method is invoked when the button is clicked.
+ * The method raises 'OnClick' event to fire up the event handlers.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handler can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onClick($param)
+ {
+ $this->raiseEvent('OnClick',$this,$param);
+ }
+
+ /**
+ * This method is invoked when the button is clicked.
+ * The method raises 'OnCommand' event to fire up the event handlers.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TCommandEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCommand($param)
+ {
+ $this->raiseEvent('OnCommand',$this,$param);
+ $this->raiseBubbleEvent($this,$param);
+ }
+
+ /**
+ * Raises the postback event.
+ * This method is required by {@link IPostBackEventHandler} interface.
+ * If {@link getCausesValidation CausesValidation} is true, it will
+ * invoke the page's {@link TPage::validate validate} method first.
+ * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events.
+ * This method is mainly used by framework and control developers.
+ * @param TEventParameter the event parameter
+ */
+ public function raisePostBackEvent($param)
+ {
+ if($this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onClick(null);
+ $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter()));
+ }
+
+ /**
+ * @return string caption of the button
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * @param string caption of the button
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * Returns the caption of the button.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string caption of the button.
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the caption of the button.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string caption of the button
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * @return boolean whether postback event trigger by this button will cause input validation, default is true
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by this button will cause input validation
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function getCommandName()
+ {
+ return $this->getViewState('CommandName','');
+ }
+
+ /**
+ * @param string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandName($value)
+ {
+ $this->setViewState('CommandName',$value,'');
+ }
+
+ /**
+ * @return string the parameter associated with the {@link onCommand OnCommand} event
+ */
+ public function getCommandParameter()
+ {
+ return $this->getViewState('CommandParameter','');
+ }
+
+ /**
+ * @param string the parameter associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandParameter($value)
+ {
+ $this->setViewState('CommandParameter',$value,'');
+ }
+
+ /**
+ * @return string the group of validators which the button causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the button causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return TButtonType the type of the button. Defaults to TButtonType::Submit.
+ */
+ public function getButtonType()
+ {
+ return $this->getViewState('ButtonType',TButtonType::Submit);
+ }
+
+ /**
+ * @param TButtonType the type of the button.
+ */
+ public function setButtonType($value)
+ {
+ $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonType'),TButtonType::Submit);
+ }
+}
+
+/**
+ * TButtonType class.
+ * TButtonType defines the enumerable type for the possible types that a {@link TButton} can take.
+ *
+ * The following enumerable values are defined:
+ * - Submit: a normal submit button
+ * - Reset: a reset button
+ * - Button: a client button (normally does not perform form submission)
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TButtonType extends TEnumerable
+{
+ const Submit='Submit';
+ const Reset='Reset';
+ const Button='Button';
+}
+
+/**
+ * TButtonTag class.
+ * TButtonTag defines the enumerable type for the possible tag names that a {@link TButton} can use for rendering.
+ *
+ * The following enumerable values are defined:
+ * - Input: an input tag is rendered
+ * - Button: a button tag is rendered
+ *
+ * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de>
+ * @package System.Web.UI.WebControls
+ */
+class TButtonTag extends TEnumerable
+{
+ const Input='Input';
+ const Button='Button';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TButtonColumn.php b/lib/prado/framework/Web/UI/WebControls/TButtonColumn.php
new file mode 100644
index 0000000..d2d0ec5
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TButtonColumn.php
@@ -0,0 +1,277 @@
+<?php
+/**
+ * TButtonColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+Prado::using('System.Web.UI.WebControls.TButton');
+Prado::using('System.Web.UI.WebControls.TLinkButton');
+Prado::using('System.Web.UI.WebControls.TImageButton');
+
+/**
+ * TButtonColumn class
+ *
+ * TButtonColumn contains a user-defined command button, such as Add or Remove,
+ * that corresponds with each row in the column.
+ *
+ * The caption of the buttons in the column is determined by {@link setText Text}
+ * and {@link setDataTextField DataTextField} properties. If both are present,
+ * the latter takes precedence. The {@link setDataTextField DataTextField} property
+ * refers to the name of the field in datasource whose value will be used as the button caption.
+ * If {@link setDataTextFormatString DataTextFormatString} is not empty,
+ * the value will be formatted before rendering.
+ *
+ * The buttons in the column can be set to display as hyperlinks, push buttons or images
+ * by setting the {@link setButtonType ButtonType} property.
+ * The {@link setCommandName CommandName} will assign its value to
+ * all button's <b>CommandName</b> property. The datagrid will capture
+ * the command event where you can write event handlers based on different command names.
+ * The buttons' <b>CausesValidation</b> and <b>ValidationGroup</b> property values
+ * are determined by the column's corresponding properties.
+ *
+ * The buttons in the column can be accessed by one of the following two methods:
+ * <code>
+ * $datagridItem->ButtonColumnID->Button
+ * $datagridItem->ButtonColumnID->Controls[0]
+ * </code>
+ * The second method is possible because the button control created within the
+ * datagrid cell is the first child.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TButtonColumn extends TDataGridColumn
+{
+ /**
+ * @return string the text caption of the button
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text caption of the button.
+ * @param string the text caption to be set
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * @return string the field name from the data source to bind to the button caption
+ */
+ public function getDataTextField()
+ {
+ return $this->getViewState('DataTextField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the button caption
+ */
+ public function setDataTextField($value)
+ {
+ $this->setViewState('DataTextField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the button caption will be displayed.
+ */
+ public function getDataTextFormatString()
+ {
+ return $this->getViewState('DataTextFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the button caption will be displayed.
+ */
+ public function setDataTextFormatString($value)
+ {
+ $this->setViewState('DataTextFormatString',$value,'');
+ }
+
+ /**
+ * @return string the URL of the image file for image buttons
+ */
+ public function getImageUrl()
+ {
+ return $this->getViewState('ImageUrl','');
+ }
+
+ /**
+ * @param string the URL of the image file for image buttons
+ */
+ public function setImageUrl($value)
+ {
+ $this->setViewState('ImageUrl',$value,'');
+ }
+
+ /**
+ * @return string the field name from the data source to bind to the button image url
+ */
+ public function getDataImageUrlField()
+ {
+ return $this->getViewState('DataImageUrlField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the button image url
+ */
+ public function setDataImageUrlField($value)
+ {
+ $this->setViewState('DataImageUrlField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the button image url will be displayed.
+ */
+ public function getDataImageUrlFormatString()
+ {
+ return $this->getViewState('DataImageUrlFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the button image url will be displayed.
+ */
+ public function setDataImageUrlFormatString($value)
+ {
+ $this->setViewState('DataImageUrlFormatString',$value,'');
+ }
+
+ /**
+ * @return TButtonColumnType the type of command button. Defaults to TButtonColumnType::LinkButton.
+ */
+ public function getButtonType()
+ {
+ return $this->getViewState('ButtonType',TButtonColumnType::LinkButton);
+ }
+
+ /**
+ * @param TButtonColumnType the type of command button
+ */
+ public function setButtonType($value)
+ {
+ $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonColumnType'),TButtonColumnType::LinkButton);
+ }
+
+ /**
+ * @return string the command name associated with the <b>OnCommand</b> event.
+ */
+ public function getCommandName()
+ {
+ return $this->getViewState('CommandName','');
+ }
+
+ /**
+ * Sets the command name associated with the <b>Command</b> event.
+ * @param string the text caption to be set
+ */
+ public function setCommandName($value)
+ {
+ $this->setViewState('CommandName',$value,'');
+ }
+
+ /**
+ * @return boolean whether postback event trigger by this button will cause input validation, default is true
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by this button will cause input validation
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the group of validators which the button causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the button causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates a command button within the cell.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
+ {
+ $buttonType=$this->getButtonType();
+ if($buttonType===TButtonColumnType::LinkButton)
+ $button=new TLinkButton;
+ else if($buttonType===TButtonColumnType::PushButton)
+ $button=new TButton;
+ else // image button
+ {
+ $button=new TImageButton;
+ $button->setImageUrl($this->getImageUrl());
+ $button->setToolTip($this->getText());
+ }
+ $button->setText($this->getText());
+ $button->setCommandName($this->getCommandName());
+ $button->setCausesValidation($this->getCausesValidation());
+ $button->setValidationGroup($this->getValidationGroup());
+ if($this->getDataTextField()!=='' || ($buttonType===TButtonColumnType::ImageButton && $this->getDataImageUrlField()!==''))
+ $button->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ $cell->getControls()->add($button);
+ $cell->registerObject('Button',$button);
+ }
+ else
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ if($sender instanceof IButtonControl)
+ {
+ if(($field=$this->getDataTextField())!=='')
+ {
+ $value=$this->getDataFieldValue($sender->getNamingContainer()->getData(),$field);
+ $text=$this->formatDataValue($this->getDataTextFormatString(),$value);
+ $sender->setText($text);
+ }
+ if(($sender instanceof TImageButton) && ($field=$this->getDataImageUrlField())!=='')
+ {
+ $value=$this->getDataFieldValue($sender->getNamingContainer()->getData(),$field);
+ $url=$this->formatDataValue($this->getDataImageUrlFormatString(),$value);
+ $sender->setImageUrl($url);
+ }
+ }
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TCaptcha.php b/lib/prado/framework/Web/UI/WebControls/TCaptcha.php
new file mode 100644
index 0000000..cf9cc8e
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TCaptcha.php
@@ -0,0 +1,493 @@
+<?php
+/**
+ * TCaptcha class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TImage');
+
+/**
+ * TCaptcha class.
+ *
+ * Notice: while this class is easy to use and implement, it does not provide full security.
+ * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack).
+ * A better alternative is provided by {@link TReCaptcha}.
+ *
+ * TCaptcha displays a CAPTCHA (a token displayed as an image) that can be used
+ * to determine if the input is entered by a real user instead of some program.
+ *
+ * Unlike other CAPTCHA scripts, TCaptcha does not need session or cookie.
+ *
+ * The token (a string consisting of alphanumeric characters) displayed is automatically
+ * generated and can be configured in several ways. To specify the length of characters
+ * in the token, set {@link setMinTokenLength MinTokenLength} and {@link setMaxTokenLength MaxTokenLength}.
+ * To use case-insensitive comparison and generate upper-case-only token, set {@link setCaseSensitive CaseSensitive}
+ * to false. Advanced users can try to set {@link setTokenAlphabet TokenAlphabet}, which
+ * specifies what characters can appear in tokens.
+ *
+ * The validation of the token is related with two properties: {@link setTestLimit TestLimit}
+ * and {@link setTokenExpiry TokenExpiry}. The former specifies how many times a token can
+ * be tested with on the server side, and the latter says when a generated token will expire.
+ *
+ * To specify the appearance of the generated token image, set {@link setTokenImageTheme TokenImageTheme}
+ * to be an integer between 0 and 63. And to adjust the generated image size, set {@link setTokenFontSize TokenFontSize}
+ * (you may also set {@link TWebControl::setWidth Width}, but the scaled image may not look good.)
+ * By setting {@link setChangingTokenBackground ChangingTokenBackground} to true, the image background
+ * of the token will be variating even though the token is the same during postbacks.
+ *
+ * Upon postback, user input can be validated by calling {@link validate()}.
+ * The {@link TCaptchaValidator} control can also be used to do validation, which provides
+ * client-side validation besides the server-side validation. By default, the token will
+ * remain the same during multiple postbacks. A new one can be generated by calling
+ * {@link regenerateToken()} manually.
+ *
+ * The following template shows a typical use of TCaptcha control:
+ * <code>
+ * <com:TCaptcha ID="Captcha" />
+ * <com:TTextBox ID="Input" />
+ * <com:TCaptchaValidator CaptchaControl="Captcha"
+ * ControlToValidate="Input"
+ * ErrorMessage="You are challenged!" />
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TCaptcha extends TImage
+{
+ const MIN_TOKEN_LENGTH=2;
+ const MAX_TOKEN_LENGTH=40;
+ private $_privateKey;
+ private $_validated=false;
+
+ /**
+ * @return integer the theme of the token image. Defaults to 0.
+ */
+ public function getTokenImageTheme()
+ {
+ return $this->getViewState('TokenImageTheme',0);
+ }
+
+ /**
+ * Sets the theme of the token image.
+ * You may test each theme to find out the one you like the most.
+ * Below is the explanation of the theme value:
+ * It is treated as a 5-bit integer. Each bit toggles a specific feature of the image.
+ * Bit 0 (the least significant): whether the image is opaque (1) or transparent (0).
+ * Bit 1: whether we should add white noise to the image (1) or not (0).
+ * Bit 2: whether we should add a grid to the image (1) or not (0).
+ * Bit 3: whether we should add some scribbles to the image (1) or not (0).
+ * Bit 4: whether the image background should be morphed (1) or not (0).
+ * Bit 5: whether the token text should cast a shadow (1) or not (0).
+ * @param integer the theme of the token image. It must be an integer between 0 and 63.
+ */
+ public function setTokenImageTheme($value)
+ {
+ $value=TPropertyValue::ensureInteger($value);
+ if($value>=0 && $value<=63)
+ $this->setViewState('TokenImageTheme',$value,0);
+ else
+ throw new TConfigurationException('captcha_tokenimagetheme_invalid',0,63);
+ }
+
+ /**
+ * @return integer the font size used for displaying the token in an image. Defaults to 30.
+ */
+ public function getTokenFontSize()
+ {
+ return $this->getViewState('TokenFontSize',30);
+ }
+
+ /**
+ * Sets the font size used for displaying the token in an image.
+ * This property affects the generated token image size.
+ * The image width is proportional to this font size.
+ * @param integer the font size used for displaying the token in an image. It must be an integer between 20 and 100.
+ */
+ public function setTokenFontSize($value)
+ {
+ $value=TPropertyValue::ensureInteger($value);
+ if($value>=20 && $value<=100)
+ $this->setViewState('TokenFontSize',$value,30);
+ else
+ throw new TConfigurationException('captcha_tokenfontsize_invalid',20,100);
+ }
+
+ /**
+ * @return integer the minimum length of the token. Defaults to 4.
+ */
+ public function getMinTokenLength()
+ {
+ return $this->getViewState('MinTokenLength',4);
+ }
+
+ /**
+ * @param integer the minimum length of the token. It must be between 2 and 40.
+ */
+ public function setMinTokenLength($value)
+ {
+ $length=TPropertyValue::ensureInteger($value);
+ if($length>=self::MIN_TOKEN_LENGTH && $length<=self::MAX_TOKEN_LENGTH)
+ $this->setViewState('MinTokenLength',$length,4);
+ else
+ throw new TConfigurationException('captcha_mintokenlength_invalid',self::MIN_TOKEN_LENGTH,self::MAX_TOKEN_LENGTH);
+ }
+
+ /**
+ * @return integer the maximum length of the token. Defaults to 6.
+ */
+ public function getMaxTokenLength()
+ {
+ return $this->getViewState('MaxTokenLength',6);
+ }
+
+ /**
+ * @param integer the maximum length of the token. It must be between 2 and 40.
+ */
+ public function setMaxTokenLength($value)
+ {
+ $length=TPropertyValue::ensureInteger($value);
+ if($length>=self::MIN_TOKEN_LENGTH && $length<=self::MAX_TOKEN_LENGTH)
+ $this->setViewState('MaxTokenLength',$length,6);
+ else
+ throw new TConfigurationException('captcha_maxtokenlength_invalid',self::MIN_TOKEN_LENGTH,self::MAX_TOKEN_LENGTH);
+ }
+
+ /**
+ * @return boolean whether the token should be treated as case-sensitive. Defaults to true.
+ */
+ public function getCaseSensitive()
+ {
+ return $this->getViewState('CaseSensitive',true);
+ }
+
+ /**
+ * @param boolean whether the token should be treated as case-sensitive. If false, only upper-case letters will appear in the token.
+ */
+ public function setCaseSensitive($value)
+ {
+ $this->setViewState('CaseSensitive',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the characters that may appear in the token. Defaults to '234578adefhijmnrtABDEFGHJLMNRT'.
+ */
+ public function getTokenAlphabet()
+ {
+ return $this->getViewState('TokenAlphabet','234578adefhijmnrtABDEFGHJLMNRT');
+ }
+
+ /**
+ * @param string the characters that may appear in the token. At least 2 characters must be specified.
+ */
+ public function setTokenAlphabet($value)
+ {
+ if(strlen($value)<2)
+ throw new TConfigurationException('captcha_tokenalphabet_invalid');
+ $this->setViewState('TokenAlphabet',$value,'234578adefhijmnrtABDEFGHJLMNRT');
+ }
+
+ /**
+ * @return integer the number of seconds that a generated token will remain valid. Defaults to 600 seconds (10 minutes).
+ */
+ public function getTokenExpiry()
+ {
+ return $this->getViewState('TokenExpiry',600);
+ }
+
+ /**
+ * @param integer the number of seconds that a generated token will remain valid. A value smaller than 1 means the token will not expire.
+ */
+ public function setTokenExpiry($value)
+ {
+ $this->setViewState('TokenExpiry',TPropertyValue::ensureInteger($value),600);
+ }
+
+ /**
+ * @return boolean whether the background of the token image should be variated during postbacks. Defaults to false.
+ */
+ public function getChangingTokenBackground()
+ {
+ return $this->getViewState('ChangingTokenBackground',false);
+ }
+
+ /**
+ * @param boolean whether the background of the token image should be variated during postbacks.
+ */
+ public function setChangingTokenBackground($value)
+ {
+ $this->setViewState('ChangingTokenBackground',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return integer how many times a generated token can be tested. Defaults to 5.
+ */
+ public function getTestLimit()
+ {
+ return $this->getViewState('TestLimit',5);
+ }
+
+ /**
+ * @param integer how many times a generated token can be tested. For unlimited tests, set it to 0.
+ */
+ public function setTestLimit($value)
+ {
+ $this->setViewState('TestLimit',TPropertyValue::ensureInteger($value),5);
+ }
+
+ /**
+ * @return boolean whether the currently generated token has expired.
+ */
+ public function getIsTokenExpired()
+ {
+ if(($expiry=$this->getTokenExpiry())>0 && ($start=$this->getViewState('TokenGenerated',0))>0)
+ return $expiry+$start<time();
+ else
+ return false;
+ }
+
+ /**
+ * @return string the public key used for generating the token. A random one will be generated and returned if this is not set.
+ */
+ public function getPublicKey()
+ {
+ if(($publicKey=$this->getViewState('PublicKey',''))==='')
+ {
+ $publicKey=$this->generateRandomKey();
+ $this->setPublicKey($publicKey);
+ }
+ return $publicKey;
+ }
+
+ /**
+ * @param string the public key used for generating the token. A random one will be generated if this is not set.
+ */
+ public function setPublicKey($value)
+ {
+ $this->setViewState('PublicKey',$value,'');
+ }
+
+ /**
+ * @return string the token that will be displayed
+ */
+ public function getToken()
+ {
+ return $this->generateToken($this->getPublicKey(),$this->getPrivateKey(),$this->getTokenAlphabet(),$this->getTokenLength(),$this->getCaseSensitive());
+ }
+
+ /**
+ * @return integer the length of the token to be generated.
+ */
+ protected function getTokenLength()
+ {
+ if(($tokenLength=$this->getViewState('TokenLength'))===null)
+ {
+ $minLength=$this->getMinTokenLength();
+ $maxLength=$this->getMaxTokenLength();
+ if($minLength>$maxLength)
+ $tokenLength=rand($maxLength,$minLength);
+ else if($minLength<$maxLength)
+ $tokenLength=rand($minLength,$maxLength);
+ else
+ $tokenLength=$minLength;
+ $this->setViewState('TokenLength',$tokenLength);
+ }
+ return $tokenLength;
+ }
+
+ /**
+ * @return string the private key used for generating the token. This is randomly generated and kept in a file for persistency.
+ */
+ public function getPrivateKey()
+ {
+ if($this->_privateKey===null)
+ {
+ $fileName=$this->generatePrivateKeyFile();
+ $content=file_get_contents($fileName);
+ $matches=array();
+ if(preg_match("/privateKey='(.*?)'/ms",$content,$matches)>0)
+ $this->_privateKey=$matches[1];
+ else
+ throw new TConfigurationException('captcha_privatekey_unknown');
+ }
+ return $this->_privateKey;
+ }
+
+ /**
+ * Validates a user input with the token.
+ * @param string user input
+ * @return boolean if the user input is not the same as the token.
+ */
+ public function validate($input)
+ {
+ $number=$this->getViewState('TestNumber',0);
+ if(!$this->_validated)
+ {
+ $this->setViewState('TestNumber',++$number);
+ $this->_validated=true;
+ }
+ if($this->getIsTokenExpired() || (($limit=$this->getTestLimit())>0 && $number>$limit))
+ {
+ $this->regenerateToken();
+ return false;
+ }
+ return ($this->getToken()===($this->getCaseSensitive()?$input:strtoupper($input)));
+ }
+
+ /**
+ * Regenerates the token to be displayed.
+ * By default, a token, once generated, will remain the same during the following page postbacks.
+ * Calling this method will generate a new token.
+ */
+ public function regenerateToken()
+ {
+ $this->clearViewState('TokenLength');
+ $this->setPublicKey('');
+ $this->clearViewState('TokenGenerated');
+ $this->clearViewState('RandomSeed');
+ $this->clearViewState('TestNumber',0);
+ }
+
+ /**
+ * Configures the image URL that shows the token.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ if(!self::checkRequirements())
+ throw new TConfigurationException('captcha_imagettftext_required');
+ if(!$this->getViewState('TokenGenerated',0))
+ {
+ $manager=$this->getApplication()->getAssetManager();
+ $manager->publishFilePath($this->getFontFile());
+ $url=$manager->publishFilePath($this->getCaptchaScriptFile());
+ $url.='?options='.urlencode($this->getTokenImageOptions());
+ $this->setImageUrl($url);
+
+ $this->setViewState('TokenGenerated',time());
+ }
+ }
+
+ /**
+ * @return string the options to be passed to the token image generator
+ */
+ protected function getTokenImageOptions()
+ {
+ $privateKey=$this->getPrivateKey(); // call this method to ensure private key is generated
+ $token=$this->getToken();
+ $options=array();
+ $options['publicKey']=$this->getPublicKey();
+ $options['tokenLength']=strlen($token);
+ $options['caseSensitive']=$this->getCaseSensitive();
+ $options['alphabet']=$this->getTokenAlphabet();
+ $options['fontSize']=$this->getTokenFontSize();
+ $options['theme']=$this->getTokenImageTheme();
+ if(($randomSeed=$this->getViewState('RandomSeed',0))===0)
+ {
+ $randomSeed=(int)(microtime()*1000000);
+ $this->setViewState('RandomSeed',$randomSeed);
+ }
+ $options['randomSeed']=$this->getChangingTokenBackground()?0:$randomSeed;
+ $str=serialize($options);
+ return base64_encode(md5($privateKey.$str).$str);
+ }
+
+ /**
+ * @return string the file path of the PHP script generating the token image
+ */
+ protected function getCaptchaScriptFile()
+ {
+ return dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'captcha.php';
+ }
+
+ protected function getFontFile()
+ {
+ return dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'verase.ttf';
+ }
+
+ /**
+ * Generates a file with a randomly generated private key.
+ * @return string the path of the file keeping the private key
+ */
+ protected function generatePrivateKeyFile()
+ {
+ $captchaScript=$this->getCaptchaScriptFile();
+ $path=dirname($this->getApplication()->getAssetManager()->getPublishedPath($captchaScript));
+ $fileName=$path.DIRECTORY_SEPARATOR.'captcha_key.php';
+ if(!is_file($fileName))
+ {
+ @mkdir($path);
+ $key=$this->generateRandomKey();
+ $content="<?php
+\$privateKey='$key';
+?>";
+ file_put_contents($fileName,$content);
+ }
+ return $fileName;
+ }
+
+ /**
+ * @return string a randomly generated key
+ */
+ protected function generateRandomKey()
+ {
+ return md5(rand().rand().rand().rand());
+ }
+
+ /**
+ * Generates the token.
+ * @param string public key
+ * @param string private key
+ * @param integer the length of the token
+ * @param boolean whether the token is case sensitive
+ * @return string the token generated.
+ */
+ protected function generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive)
+ {
+ $token=substr($this->hash2string(md5($publicKey.$privateKey),$alphabet).$this->hash2string(md5($privateKey.$publicKey),$alphabet),0,$tokenLength);
+ return $caseSensitive?$token:strtoupper($token);
+ }
+
+ /**
+ * Converts a hash string into a string with characters consisting of alphanumeric characters.
+ * @param string the hexadecimal representation of the hash string
+ * @param string the alphabet used to represent the converted string. If empty, it means '234578adefhijmnrtwyABDEFGHIJLMNQRTWY', which excludes those confusing characters.
+ * @return string the converted string
+ */
+ protected function hash2string($hex,$alphabet='')
+ {
+ if(strlen($alphabet)<2)
+ $alphabet='234578adefhijmnrtABDEFGHJLMNQRT';
+ $hexLength=strlen($hex);
+ $base=strlen($alphabet);
+ $result='';
+ for($i=0;$i<$hexLength;$i+=6)
+ {
+ $number=hexdec(substr($hex,$i,6));
+ while($number)
+ {
+ $result.=$alphabet[$number%$base];
+ $number=floor($number/$base);
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Checks the requirements needed for generating CAPTCHA images.
+ * TCaptach requires GD2 with TrueType font support and PNG image support.
+ * @return boolean whether the requirements are satisfied.
+ */
+ public static function checkRequirements()
+ {
+ return extension_loaded('gd') && function_exists('imagettftext') && function_exists('imagepng');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TCaptchaValidator.php b/lib/prado/framework/Web/UI/WebControls/TCaptchaValidator.php
new file mode 100644
index 0000000..1a08430
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TCaptchaValidator.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * TCaptchaValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+Prado::using('System.Web.UI.WebControls.TCaptcha');
+
+/**
+ * TCaptchaValidator class
+ *
+ * Notice: while this class is easy to use and implement, it does not provide full security.
+ * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack).
+ * A better alternative is provided by {@link TReCaptchaValidator}.
+ *
+ * TCaptchaValidator validates user input against a CAPTCHA represented by
+ * a {@link TCaptcha} control. The input control fails validation if its value
+ * is not the same as the token displayed in CAPTCHA. Note, if the user does
+ * not enter any thing, it is still considered as failing the validation.
+ *
+ * To use TCaptchaValidator, specify the {@link setControlToValidate ControlToValidate}
+ * to be the ID path of the input control (usually a {@link TTextBox} control}.
+ * Also specify the {@link setCaptchaControl CaptchaControl} to be the ID path of
+ * the CAPTCHA control that the user input should be compared with.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TCaptchaValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TCaptchaValidator';
+ }
+
+ /**
+ * @return string the ID path of the CAPTCHA control to validate
+ */
+ public function getCaptchaControl()
+ {
+ return $this->getViewState('CaptchaControl','');
+ }
+
+ /**
+ * Sets the ID path of the CAPTCHA control to validate.
+ * The ID path is the dot-connected IDs of the controls reaching from
+ * the validator's naming container to the target control.
+ * @param string the ID path
+ */
+ public function setCaptchaControl($value)
+ {
+ $this->setViewState('CaptchaControl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input control has the same value
+ * as the one displayed in the corresponding CAPTCHA control.
+ *
+ * @return boolean whether the validation succeeds
+ */
+ protected function evaluateIsValid()
+ {
+ $value=$this->getValidationValue($this->getValidationTarget());
+ $control=$this->findCaptchaControl();
+ return $control->validate(trim($value));
+ }
+
+ /**
+ * @return TCaptchaControl the CAPTCHA control to be validated against
+ * @throws TConfigurationException if the CAPTCHA cannot be found according to {@link setCaptchaControl CaptchaControl}
+ */
+ protected function findCaptchaControl()
+ {
+ if(($id=$this->getCaptchaControl())==='')
+ throw new TConfigurationException('captchavalidator_captchacontrol_required');
+ else if(($control=$this->findControl($id))===null)
+ throw new TConfigurationException('captchavalidator_captchacontrol_inexistent',$id);
+ else if(!($control instanceof TCaptcha))
+ throw new TConfigurationException('captchavalidator_captchacontrol_invalid',$id);
+ else
+ return $control;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options=parent::getClientScriptOptions();
+ $control=$this->findCaptchaControl();
+ if($control->getCaseSensitive())
+ {
+ $options['TokenHash']=$this->generateTokenHash($control->getToken());
+ $options['CaseSensitive']=true;
+ }
+ else
+ {
+ $options['TokenHash']=$this->generateTokenHash(strtoupper($control->getToken()));
+ $options['CaseSensitive']=false;
+ }
+ return $options;
+ }
+
+ private function generateTokenHash($token)
+ {
+ for($h=0,$i=strlen($token)-1;$i>=0;--$i)
+ $h+=ord($token[$i]);
+ return $h;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TCheckBox.php b/lib/prado/framework/Web/UI/WebControls/TCheckBox.php
new file mode 100644
index 0000000..bfbfbf5
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TCheckBox.php
@@ -0,0 +1,536 @@
+<?php
+/**
+ * TCheckBox class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TCheckBox class
+ *
+ * TCheckBox displays a check box on the page.
+ * You can specify the caption to display beside the check box by setting
+ * the {@link setText Text} property. The caption can appear either on the right
+ * or left of the check box, which is determined by the {@link setTextAlign TextAlign}
+ * property.
+ *
+ * To determine whether the TCheckBox component is checked, test the {@link getChecked Checked}
+ * property. The {@link onCheckedChanged OnCheckedChanged} event is raised when
+ * the {@link getChecked Checked} state of the TCheckBox component changes
+ * between posts to the server. You can provide an event handler for
+ * the {@link onCheckedChanged OnCheckedChanged} event to to programmatically
+ * control the actions performed when the state of the TCheckBox component changes
+ * between posts to the server.
+ *
+ * If {@link setAutoPostBack AutoPostBack} is set true, changing the check box state
+ * will cause postback action. And if {@link setCausesValidation CausesValidation}
+ * is true, validation will also be processed, which can be further restricted within
+ * a {@link setValidationGroup ValidationGroup}.
+ *
+ * Note, {@link setText Text} is rendered as is. Make sure it does not contain unwanted characters
+ * that may bring security vulnerabilities.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCheckBox extends TWebControl implements IPostBackDataHandler, IValidatable, IDataRenderer, ISurroundable
+{
+ private $_dataChanged=false;
+ private $_isValid=true;
+
+ /**
+ * @return string tag name of the button
+ */
+ protected function getTagName()
+ {
+ return 'input';
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ $checked=$this->getChecked();
+ if($newChecked=isset($values[$key]))
+ $this->setValue($values[$key]);
+ $this->setChecked($newChecked);
+ return $this->_dataChanged=($newChecked!==$checked);
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method raises {@link onCheckedChanged OnCheckedChanged} event.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ if($this->getAutoPostBack() && $this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onCheckedChanged(null);
+ }
+
+ /**
+ * Raises <b>OnCheckedChanged</b> event when {@link getChecked Checked} changes value during postback.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event delegates can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCheckedChanged($param)
+ {
+ $this->raiseEvent('OnCheckedChanged',$this,$param);
+ }
+
+ /**
+ * Registers the checkbox to receive postback data during postback.
+ * This is necessary because a checkbox if unchecked, when postback,
+ * does not have direct mapping between post data and the checkbox name.
+ *
+ * This method overrides the parent implementation and is invoked before render.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ if($this->getEnabled(true))
+ $this->getPage()->registerRequiresPostData($this);
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Returns the value of the property that needs validation.
+ * @return mixed the property value to be validated
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getChecked();
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return string the text caption of the checkbox
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text caption of the checkbox.
+ * @param string the text caption to be set
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * @return string the value of the checkbox. Defaults to empty.
+ */
+ public function getValue()
+ {
+ return $this->getViewState('Value','');
+ }
+
+ /**
+ * @param string the value of the checkbox
+ */
+ public function setValue($value)
+ {
+ $this->setViewState('Value',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return TTextAlign the alignment (Left or Right) of the text caption, defaults to TTextAlign::Right.
+ */
+ public function getTextAlign()
+ {
+ return $this->getViewState('TextAlign',TTextAlign::Right);
+ }
+
+ /**
+ * @param TTextAlign the alignment of the text caption. Valid values include Left and Right.
+ */
+ public function setTextAlign($value)
+ {
+ $this->setViewState('TextAlign',TPropertyValue::ensureEnum($value,'TTextAlign'),TTextAlign::Right);
+ }
+
+ /**
+ * @return boolean whether the checkbox is checked
+ */
+ public function getChecked()
+ {
+ return $this->getViewState('Checked',false);
+ }
+
+ /**
+ * Sets a value indicating whether the checkbox is to be checked or not.
+ * @param boolean whether the checkbox is to be checked or not.
+ */
+ public function setChecked($value)
+ {
+ $this->setViewState('Checked',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Returns the value indicating whether the checkbox is checked.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getChecked()}.
+ * @return boolean whether the checkbox is checked.
+ * @see getChecked
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getChecked();
+ }
+
+ /**
+ * Sets the value indicating whether the checkbox is to be checked or not.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setChecked()}.
+ * @param boolean whether the checkbox is to be checked
+ * @see setChecked
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setChecked($value);
+ }
+
+ /**
+ * @return boolean whether clicking on the checkbox will post the page.
+ */
+ public function getAutoPostBack()
+ {
+ return $this->getViewState('AutoPostBack',false);
+ }
+
+ /**
+ * Sets a value indicating whether clicking on the checkbox will post the page.
+ * @param boolean whether clicking on the checkbox will post the page.
+ */
+ public function setAutoPostBack($value)
+ {
+ $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether postback event triggered by this checkbox will cause input validation, default is true.
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * Sets the value indicating whether postback event trigger by this checkbox will cause input validation.
+ * @param boolean whether postback event trigger by this checkbox will cause input validation.
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the group of validators which the checkbox causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the checkbox causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return string the tag used to wrap the control in.
+ */
+ public function getSurroundingTag()
+ {
+ return 'span';
+ }
+
+ /**
+ * @return string the id of the surrounding tag or this clientID if no such tag needed.
+ */
+ public function getSurroundingTagID()
+ {
+ return $this->getSpanNeeded() ? $this->getClientID().'_parent' : $this->getClientID();
+ }
+
+ /**
+ * Renders the checkbox control.
+ * This method overrides the parent implementation by rendering a checkbox input element
+ * and a span element if needed.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ $this->getPage()->ensureRenderInForm($this);
+ if($this->getHasStyle())
+ $this->getStyle()->addAttributesToRender($writer);
+ if(($tooltip=$this->getToolTip())!=='')
+ $writer->addAttribute('title',$tooltip);
+ if($this->getHasAttributes())
+ {
+ $attributes=$this->getAttributes();
+ $value=$attributes->remove('value');
+ // onclick js should only be added to input tag
+ if(($onclick=$attributes->remove('onclick'))===null)
+ $onclick='';
+ if($attributes->getCount())
+ $writer->addAttributes($attributes);
+ if($value!==null)
+ $attributes->add('value',$value);
+ }
+ else
+ $onclick='';
+ if($needspan=$this->getSpanNeeded())
+ {
+ $writer->addAttribute('id',$this->getSurroundingTagID());
+ $writer->renderBeginTag($this->getSurroundingTag());
+ }
+ $clientID=$this->getClientID();
+ if(($text=$this->getText())!=='')
+ {
+ if($this->getTextAlign()===TTextAlign::Left)
+ {
+ $this->renderLabel($writer,$clientID,$text);
+ $this->renderInputTag($writer,$clientID,$onclick);
+ }
+ else
+ {
+ $this->renderInputTag($writer,$clientID,$onclick);
+ $this->renderLabel($writer,$clientID,$text);
+ }
+ }
+ else
+ $this->renderInputTag($writer,$clientID,$onclick);
+ if($needspan)
+ $writer->renderEndTag();
+ }
+
+ /**
+ * @return TMap list of attributes to be rendered for label beside the checkbox
+ */
+ public function getLabelAttributes()
+ {
+ if($attributes=$this->getViewState('LabelAttributes',null))
+ return $attributes;
+ else
+ {
+ $attributes=new TAttributeCollection;
+ $this->setViewState('LabelAttributes',$attributes,null);
+ return $attributes;
+ }
+ }
+
+ /**
+ * @return TMap list of attributes to be rendered for the checkbox
+ */
+ public function getInputAttributes()
+ {
+ if($attributes=$this->getViewState('InputAttributes',null))
+ return $attributes;
+ else
+ {
+ $attributes=new TAttributeCollection;
+ $this->setViewState('InputAttributes',$attributes,null);
+ return $attributes;
+ }
+ }
+
+ /**
+ * @return string the value attribute to be rendered
+ */
+ protected function getValueAttribute()
+ {
+ if(($value=$this->getValue())!=='')
+ return $value;
+ else
+ {
+ $attributes=$this->getViewState('InputAttributes',null);
+ if($attributes && $attributes->contains('value'))
+ return $attributes->itemAt('value');
+ else if($this->hasAttribute('value'))
+ return $this->getAttribute('value');
+ else
+ return '';
+ }
+ }
+
+ /**
+ * @return boolean whether to render javascript.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether to render javascript.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Check if we need a span tag to surround this control. The span tag will be created if
+ * the Text property is set for this control.
+ *
+ * @return bool wether this control needs a surrounding span tag
+ */
+ protected function getSpanNeeded() {
+ return $this->getText()!=='';
+ }
+
+ /**
+ * Renders a label beside the checkbox.
+ * @param THtmlWriter the writer for the rendering purpose
+ * @param string checkbox id
+ * @param string label text
+ */
+ protected function renderLabel($writer,$clientID,$text)
+ {
+ $writer->addAttribute('for',$clientID);
+ if($attributes=$this->getViewState('LabelAttributes',null))
+ $writer->addAttributes($attributes);
+ $writer->renderBeginTag('label');
+ $writer->write($text);
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Renders a checkbox input element.
+ * @param THtmlWriter the writer for the rendering purpose
+ * @param string checkbox id
+ * @param string onclick js
+ */
+ protected function renderInputTag($writer,$clientID,$onclick)
+ {
+ if($clientID!=='')
+ $writer->addAttribute('id',$clientID);
+ $writer->addAttribute('type','checkbox');
+ if(($value=$this->getValueAttribute())!=='')
+ $writer->addAttribute('value',$value);
+ if(!empty($onclick))
+ $writer->addAttribute('onclick',$onclick);
+ if(($uniqueID=$this->getUniqueID())!=='')
+ $writer->addAttribute('name',$uniqueID);
+ if($this->getChecked())
+ $writer->addAttribute('checked','checked');
+ if(!$this->getEnabled(true))
+ $writer->addAttribute('disabled','disabled');
+
+ $page=$this->getPage();
+ if($this->getEnabled(true)
+ && $this->getEnableClientScript()
+ && $this->getAutoPostBack()
+ && $page->getClientSupportsJavaScript())
+ {
+ $this->renderClientControlScript($writer);
+ }
+
+ if(($accesskey=$this->getAccessKey())!=='')
+ $writer->addAttribute('accesskey',$accesskey);
+ if(($tabindex=$this->getTabIndex())>0)
+ $writer->addAttribute('tabindex',"$tabindex");
+ if($attributes=$this->getViewState('InputAttributes',null))
+ $writer->addAttributes($attributes);
+ $writer->renderBeginTag('input');
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Renders the client-script code.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TCheckBox';
+ }
+
+ /**
+ * Gets the post back options for this checkbox.
+ * @return array
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['EventTarget'] = $this->getUniqueID();
+ return $options;
+ }
+}
+
+/**
+ * TTextAlign class.
+ * TTextAlign defines the enumerable type for the possible text alignments
+ *
+ * The following enumerable values are defined:
+ * - Left: left aligned
+ * - Right: right aligned
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TTextAlign extends TEnumerable
+{
+ const Left='Left';
+ const Right='Right';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TCheckBoxColumn.php b/lib/prado/framework/Web/UI/WebControls/TCheckBoxColumn.php
new file mode 100644
index 0000000..5cf0265
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TCheckBoxColumn.php
@@ -0,0 +1,121 @@
+<?php
+/**
+ * TCheckBoxColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+/**
+ * TCheckBox class file
+ */
+Prado::using('System.Web.UI.WebControls.TCheckBox');
+
+/**
+ * TCheckBoxColumn class
+ *
+ * TCheckBoxColumn represents a checkbox column that is bound to a field in a data source.
+ * The checked state of the checkboxes are determiend by the bound data at
+ * {@link setDataField DataField}. If {@link setReadOnly ReadOnly} is false,
+ * TCheckBoxColumn will display an enabled checkbox provided the cells are
+ * in edit mode. Otherwise, the checkboxes will be disabled to prevent from editting.
+ *
+ * The checkbox control in the TCheckBoxColumn can be accessed by one of
+ * the following two methods:
+ * <code>
+ * $datagridItem->CheckBoxColumnID->CheckBox
+ * $datagridItem->CheckBoxColumnID->Controls[0]
+ * </code>
+ * The second method is possible because the checkbox control created within the
+ * datagrid cell is the first child.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCheckBoxColumn extends TDataGridColumn
+{
+ /**
+ * @return string the field name from the data source to bind to the column
+ */
+ public function getDataField()
+ {
+ return $this->getViewState('DataField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the column
+ */
+ public function setDataField($value)
+ {
+ $this->setViewState('DataField',$value,'');
+ }
+
+ /**
+ * @return boolean whether the items in the column can be edited. Defaults to false.
+ */
+ public function getReadOnly()
+ {
+ return $this->getViewState('ReadOnly',false);
+ }
+
+ /**
+ * @param boolean whether the items in the column can be edited
+ */
+ public function setReadOnly($value)
+ {
+ $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates a checkbox inside the cell.
+ * If the column is read-only or if the item is not in edit mode,
+ * the checkbox will be set disabled.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
+ {
+ $checkBox=new TCheckBox;
+ if($this->getReadOnly() || $itemType!==TListItemType::EditItem)
+ $checkBox->setEnabled(false);
+ $cell->setHorizontalAlign('Center');
+ $cell->getControls()->add($checkBox);
+ $cell->registerObject('CheckBox',$checkBox);
+ if($this->getDataField()!=='')
+ $checkBox->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ }
+ else
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $data=$item->getData();
+ if(($field=$this->getDataField())!=='')
+ $value=TPropertyValue::ensureBoolean($this->getDataFieldValue($data,$field));
+ else
+ $value=TPropertyValue::ensureBoolean($data);
+ if($sender instanceof TCheckBox)
+ $sender->setChecked($value);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TCheckBoxList.php b/lib/prado/framework/Web/UI/WebControls/TCheckBoxList.php
new file mode 100644
index 0000000..9225e17
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TCheckBoxList.php
@@ -0,0 +1,509 @@
+<?php
+/**
+ * TCheckBoxList class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TListControl class
+ */
+Prado::using('System.Web.UI.WebControls.TListControl');
+/**
+ * Includes TRepeatInfo class
+ */
+Prado::using('System.Web.UI.WebControls.TRepeatInfo');
+/**
+ * Includes TCheckBox class
+ */
+Prado::using('System.Web.UI.WebControls.TCheckBox');
+
+/**
+ * TCheckBoxList class
+ *
+ * TCheckBoxList displays a list of checkboxes on a Web page.
+ *
+ * The layout of the checkbox list is specified via {@link setRepeatLayout RepeatLayout},
+ * which can be either 'Table' (default) or 'Flow'.
+ * A table layout uses HTML table cells to organize the checkboxes while
+ * a flow layout uses line breaks to organize the checkboxes.
+ * When the layout is using 'Table', {@link setCellPadding CellPadding} and
+ * {@link setCellSpacing CellSpacing} can be used to adjust the cellpadding and
+ * cellpadding of the table.
+ *
+ * The number of columns used to display the checkboxes is specified via
+ * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
+ * governs the order of the items being rendered.
+ *
+ * The alignment of the text besides each checkbox can be specified via {@link setTextAlign TextAlign}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingContainer, IPostBackDataHandler, IValidatable
+{
+ private $_repeatedControl;
+ private $_isEnabled;
+ private $_changedEventRaised=false;
+ private $_dataChanged=false;
+ private $_isValid=true;
+
+ /**
+ * Constructor.
+ * Remember to call parent implementation if you override this method
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->_repeatedControl=$this->createRepeatedControl();
+ $this->_repeatedControl->setEnableViewState(false);
+ $this->_repeatedControl->setID('c0');
+ $this->getControls()->add($this->_repeatedControl);
+ }
+
+ /**
+ * Creates a control used for repetition (used as a template).
+ * @return TControl the control to be repeated
+ */
+ protected function createRepeatedControl()
+ {
+ return new TCheckBoxItem;
+ }
+
+ /**
+ * Finds a control by ID.
+ * This method overrides the parent implementation so that it always returns
+ * the checkbox list itself (because the checkbox list does not have child controls.)
+ * @param string control ID
+ * @return TControl control being found
+ */
+ public function findControl($id, $real=false)
+ {
+ if ($real===true)
+ return parent::findControl($id);
+ return $this;
+ }
+
+ /**
+ * @return boolean whether this control supports multiple selection. Always true for checkbox list.
+ */
+ protected function getIsMultiSelect()
+ {
+ return true;
+ }
+
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableStyle} to be used by checkbox list.
+ * @return TStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableStyle;
+ }
+
+ /**
+ * @return TTextAlign the alignment of the text caption, defaults to TTextAlign::Right.
+ */
+ public function getTextAlign()
+ {
+ return $this->getViewState('TextAlign',TTextAlign::Right);
+ }
+
+ /**
+ * @param TTextAlign the text alignment of the checkboxes
+ */
+ public function setTextAlign($value)
+ {
+ $this->setViewState('TextAlign',TPropertyValue::ensureEnum($value,'TTextAlign'),TTextAlign::Right);
+ }
+
+
+ /**
+ * @return TRepeatInfo repeat information (primarily used by control developers)
+ */
+ protected function getRepeatInfo()
+ {
+ if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null)
+ {
+ $repeatInfo=new TRepeatInfo;
+ $this->setViewState('RepeatInfo',$repeatInfo,null);
+ }
+ return $repeatInfo;
+ }
+
+ /**
+ * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set.
+ */
+ public function getRepeatColumns()
+ {
+ return $this->getRepeatInfo()->getRepeatColumns();
+ }
+
+ /**
+ * @param integer the number of columns that the list should be displayed with.
+ */
+ public function setRepeatColumns($value)
+ {
+ $this->getRepeatInfo()->setRepeatColumns($value);
+ }
+
+ /**
+ * @return string the direction of traversing the list, defaults to 'Vertical'
+ */
+ public function getRepeatDirection()
+ {
+ return $this->getRepeatInfo()->getRepeatDirection();
+ }
+
+ /**
+ * @param string the direction (Vertical, Horizontal) of traversing the list
+ */
+ public function setRepeatDirection($value)
+ {
+ $this->getRepeatInfo()->setRepeatDirection($value);
+ }
+
+ /**
+ * @return string how the list should be displayed, using table or using line breaks. Defaults to 'Table'.
+ */
+ public function getRepeatLayout()
+ {
+ return $this->getRepeatInfo()->getRepeatLayout();
+ }
+
+ /**
+ * @param string how the list should be displayed, using table or using line breaks (Table, Flow)
+ */
+ public function setRepeatLayout($value)
+ {
+ $this->getRepeatInfo()->setRepeatLayout($value);
+ }
+
+ /**
+ * @return integer the cellspacing for the table keeping the checkbox list. Defaults to -1, meaning not set.
+ */
+ public function getCellSpacing()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getCellSpacing();
+ else
+ return -1;
+ }
+
+ /**
+ * Sets the cellspacing for the table keeping the checkbox list.
+ * @param integer the cellspacing for the table keeping the checkbox list.
+ */
+ public function setCellSpacing($value)
+ {
+ $this->getStyle()->setCellSpacing($value);
+ }
+
+ /**
+ * @return integer the cellpadding for the table keeping the checkbox list. Defaults to -1, meaning not set.
+ */
+ public function getCellPadding()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getCellPadding();
+ else
+ return -1;
+ }
+
+ /**
+ * Sets the cellpadding for the table keeping the checkbox list.
+ * @param integer the cellpadding for the table keeping the checkbox list.
+ */
+ public function setCellPadding($value)
+ {
+ $this->getStyle()->setCellPadding($value);
+ }
+
+ /**
+ * Returns a value indicating whether this control contains header item.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean always false.
+ */
+ public function getHasHeader()
+ {
+ return false;
+ }
+
+ /**
+ * Returns a value indicating whether this control contains footer item.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean always false.
+ */
+ public function getHasFooter()
+ {
+ return false;
+ }
+
+ /**
+ * Returns a value indicating whether this control contains separator items.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean always false.
+ */
+ public function getHasSeparators()
+ {
+ return false;
+ }
+
+ /**
+ * @param boolean whether the control is to be enabled.
+ */
+ public function setEnabled($value)
+ {
+ parent::setEnabled($value);
+ $value = !TPropertyValue::ensureBoolean($value);
+ // if this is an active control,
+ // and it's a callback,
+ // and we can update clientside,
+ // then update the 'disabled' attribute of the items.
+ if(($this instanceof IActiveControl) &&
+ $this->getPage()->getIsCallBack() &&
+ $this->getActiveControl()->canUpdateClientSide())
+ {
+ $items = $this->getItems();
+ $cs = $this->getPage()->getCallbackClient();
+ $baseClientID = $this->getClientID().'_c';
+ foreach($items as $index=>$item)
+ {
+ $cs->setAttribute($baseClientID.$index, 'disabled', $value);
+ }
+ }
+ }
+
+ /**
+ * Returns a style used for rendering items.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
+ * @param integer index of the item being rendered
+ * @return null
+ */
+ public function generateItemStyle($itemType,$index)
+ {
+ return null;
+ }
+
+ /**
+ * Renders an item in the list.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @param THtmlWriter writer for rendering purpose
+ * @param TRepeatInfo repeat information
+ * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
+ * @param integer zero-based index of the item in the item list
+ */
+ public function renderItem($writer,$repeatInfo,$itemType,$index)
+ {
+ $repeatedControl=$this->_repeatedControl;
+ $item=$this->getItems()->itemAt($index);
+ if($item->getHasAttributes())
+ $repeatedControl->getAttributes()->copyFrom($item->getAttributes());
+ else if($repeatedControl->getHasAttributes())
+ $repeatedControl->getAttributes()->clear();
+ $repeatedControl->setID("c$index");
+ $repeatedControl->setText($item->getText());
+ $repeatedControl->setChecked($item->getSelected());
+ $repeatedControl->setAttribute('value',$item->getValue());
+ $repeatedControl->setEnabled($this->_isEnabled && $item->getEnabled());
+ $repeatedControl->setEnableClientScript(false);
+ $repeatedControl->renderControl($writer);
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if($this->getEnabled(true))
+ {
+ $index=(int)substr($key,strlen($this->getUniqueID())+2);
+ $this->ensureDataBound();
+ if($index>=0 && $index<$this->getItemCount())
+ {
+ $item=$this->getItems()->itemAt($index);
+ if($item->getEnabled())
+ {
+ $checked=isset($values[$key]);
+ if($item->getSelected()!==$checked)
+ {
+ $item->setSelected($checked);
+ if(!$this->_changedEventRaised)
+ {
+ $this->_changedEventRaised=true;
+ return $this->_dataChanged=true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method is required by {@link IPostBackDataHandler} interface.
+ * It is invoked by the framework when {@link getSelectedIndices SelectedIndices} property
+ * is changed on postback.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ if($this->getAutoPostBack() && $this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onSelectedIndexChanged(null);
+ }
+
+ /**
+ * Registers for post data on postback.
+ * This method overrides the parent implementation.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->_repeatedControl->setAutoPostBack($this->getAutoPostBack());
+ $this->_repeatedControl->setCausesValidation($this->getCausesValidation());
+ $this->_repeatedControl->setValidationGroup($this->getValidationGroup());
+ $page=$this->getPage();
+ $n=$this->getItemCount();
+ for($i=0;$i<$n;++$i)
+ {
+ $this->_repeatedControl->setID("c$i");
+ $page->registerRequiresPostData($this->_repeatedControl);
+ }
+ }
+
+ /**
+ * Wether the list should be rendered inside a span or not
+ *
+ *@return boolean true if we need a span
+ */
+ protected function getSpanNeeded ()
+ {
+ return $this->getRepeatLayout()===TRepeatLayout::Raw;
+ }
+
+ /**
+ * Renders the checkbox list control.
+ * This method overrides the parent implementation.
+ * @param THtmlWriter writer for rendering purpose.
+ */
+ public function render($writer)
+ {
+ if($this->getItemCount()>0)
+ {
+ if ($needSpan=$this->getSpanNeeded())
+ {
+ $writer->addAttribute('id', $this->getClientId());
+ $writer->renderBeginTag('span');
+ }
+ $this->_isEnabled=$this->getEnabled(true);
+ $repeatInfo=$this->getRepeatInfo();
+ $accessKey=$this->getAccessKey();
+ $tabIndex=$this->getTabIndex();
+ $this->_repeatedControl->setTextAlign($this->getTextAlign());
+ $this->_repeatedControl->setAccessKey($accessKey);
+ $this->_repeatedControl->setTabIndex($tabIndex);
+ $this->setAccessKey('');
+ $this->setTabIndex(0);
+ $this->addAttributesToRender($writer);
+ $repeatInfo->renderRepeater($writer,$this);
+ $this->setAccessKey($accessKey);
+ $this->setTabIndex($tabIndex);
+ if ($needSpan)
+ $writer->renderEndTag();
+ }
+
+ //checkbox skipped the client control script in addAttributesToRender
+ if($this->getEnabled(true)
+ && $this->getEnableClientScript()
+ && $this->getAutoPostBack()
+ && $this->getPage()->getClientSupportsJavaScript())
+ {
+ $this->renderClientControlScript($writer);
+ }
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getSelectedValue();
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TCheckBoxList';
+ }
+
+ /**
+ * Gets the post back options for this checkbox.
+ * @return array
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ListName'] = $this->getUniqueID();
+ $options['ItemCount'] = $this->getItemCount();
+ return $options;
+ }
+
+}
+
+class TCheckBoxItem extends TCheckBox {
+ /**
+ * Override client implementation to avoid emitting the javascript
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TClientScript.php b/lib/prado/framework/Web/UI/WebControls/TClientScript.php
new file mode 100644
index 0000000..c931bcb
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TClientScript.php
@@ -0,0 +1,155 @@
+<?php
+/**
+ * TClientScript class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TClientScript class
+ *
+ * Allows importing of Prado Client Scripts from template via the
+ * {@link setPradoScripts PradoScripts} property. Multiple Prado
+ * client-scripts can be specified using comma delimited string of the
+ * javascript library to include on the page. For example,
+ *
+ * <code>
+ * <com:TClientScript PradoScripts="effects, rico" />
+ * </code>
+ *
+ * Custom javascript files can be register using the {@link setScriptUrl ScriptUrl}
+ * property.
+ * <code>
+ * <com:TClientScript ScriptUrl=<%~ test.js %> />
+ * </code>
+ *
+ * Contents within TClientScript will be treated as javascript code and will be
+ * rendered in place.
+ *
+ * Since Prado 3.2 the property {@link setFlushScriptFiles FlushScriptFiles} controls
+ * whether Prado will flush the script files defined in the page before rendering the
+ * TClientScript contents.
+ * If you're not using any external functions in your TClientScript block, you should
+ * set the {@link setFlushScriptFiles FlushScriptFiles} property to false, so Prado
+ * can postpone the loading of all the referenced script files further down the page
+ * generation cycle.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TClientScript extends TControl
+{
+ /**
+ * @return string comma delimited list of javascript libraries to included
+ * on the page.
+ */
+ public function getPradoScripts()
+ {
+ return $this->getViewState('PradoScripts', '');
+ }
+
+ /**
+ * Include javascript library to the current page. The current supported
+ * libraries are: "prado", "effects", "ajax", "validator", "logger",
+ * "datepicker", "colorpicker". Library dependencies are automatically resolved.
+ *
+ * @param string comma delimited list of javascript libraries to include.
+ */
+ public function setPradoScripts($value)
+ {
+ $this->setViewState('PradoScripts', $value, '');
+ }
+
+ /**
+ * @return string custom javascript file url.
+ */
+ public function getScriptUrl()
+ {
+ return $this->getViewState('ScriptUrl', '');
+ }
+
+ /**
+ * @param string custom javascript file url.
+ */
+ public function setScriptUrl($value)
+ {
+ $this->setViewState('ScriptUrl', $value, '');
+ }
+
+ /**
+ * @return bool whether to flush script files using TClientScriptManager::flushScriptFiles() before rendering the script block
+ */
+ public function getFlushScriptFiles()
+ {
+ return TPropertyValue::ensureBoolean($this->getViewState('FlushScriptFiles', true));
+ }
+
+ /**
+ * @param bool whether to flush script files using TClientScriptManager::flushScriptFiles() before rendering the script block
+ */
+ public function setFlushScriptFiles($value)
+ {
+ $this->setViewState('FlushScriptFiles', TPropertyValue::ensureBoolean($value));
+ }
+
+ /**
+ * Calls the client script manager to add each of the requested client
+ * script libraries.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $scripts = preg_split('/,|\s+/', $this->getPradoScripts());
+ $cs = $this->getPage()->getClientScript();
+ foreach($scripts as $script)
+ {
+ if(($script = trim($script))!=='')
+ $cs->registerPradoScript($script);
+ }
+ }
+
+ /**
+ * Renders the body content as javascript block.
+ * Overrides parent implementation, parent renderChildren method is called during
+ * {@link registerCustomScript}.
+ * @param THtmlWriter the renderer
+ */
+ public function render($writer)
+ {
+ if ($this->getFlushScriptFiles())
+ $this->getPage()->getClientScript()->flushScriptFiles($writer, $this);
+ $this->renderCustomScriptFile($writer);
+ $this->renderCustomScript($writer);
+ }
+
+ /**
+ * Renders the custom script file.
+ * @param THtmLWriter the renderer
+ */
+ protected function renderCustomScriptFile($writer)
+ {
+ if(($scriptUrl = $this->getScriptUrl())!=='')
+ $writer->write("<script type=\"text/javascript\" src=\"$scriptUrl\"></script>\n");
+ }
+
+ /**
+ * Registers the body content as javascript.
+ * @param THtmlWriter the renderer
+ */
+ protected function renderCustomScript($writer)
+ {
+ if($this->getHasControls())
+ {
+ $writer->write("<script type=\"text/javascript\">\n/*<![CDATA[*/\n");
+ $this->renderChildren($writer);
+ $writer->write("\n/*]]>*/\n</script>\n");
+ }
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TColorPicker.php b/lib/prado/framework/Web/UI/WebControls/TColorPicker.php
new file mode 100644
index 0000000..fbe71c0
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TColorPicker.php
@@ -0,0 +1,286 @@
+<?php
+/**
+ * TColorPicker class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TColorPicker class.
+ *
+ * TColorPicker displays a text box for color input purpose.
+ * Next to the textbox there's a button filled with the current chosen color.
+ * Users can write a color name directly in the text box as an hex triplet (also known as HTML notation, eg: #FF00FF).
+ * Alternatively, if the <b>ShowColorPicker</b> property is enabled (it is by default), users can click the button
+ * to have a color picker UI appear. A color chan be chosen directly by clicking on the color picker.
+ *
+ * TColorPicker has three different color picker UI <b>Mode</b>s:
+ * # <b>Simple</b> - Grid with 12 simple colors.
+ * # <b>Basic</b> - Grid with the most common 70 colors. This is the default mode.
+ * # <b>Full</b> - Full-featured color picker.
+ *
+ * The <b>CssClass</b> property can be used to override the CSS class name
+ * for the color picker panel. The <b>ColorStyle</b> property sets the packages
+ * styles available. E.g. <b>default</b>.
+ *
+ * If the <b>Mode</b> property is set to <b>Full</b>, the color picker panel will
+ * display an "Ok" and "Cancel" buttons. You can customize the button labels setting the <b>OKButtonText</b>
+ * and <b>CancelButtonText</b> properties.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TColorPicker extends TTextBox
+{
+ const SCRIPT_PATH = 'prado/colorpicker';
+
+ private $_clientSide;
+
+ /**
+ * @return boolean whether the color picker should pop up when the button is clicked.
+ */
+ public function getShowColorPicker()
+ {
+ return $this->getViewState('ShowColorPicker',true);
+ }
+
+ /**
+ * Sets whether to pop up the color picker when the button is clicked.
+ * @param boolean whether to show the color picker popup
+ */
+ public function setShowColorPicker($value)
+ {
+ $this->setViewState('ShowColorPicker',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @param TColorPickerMode color picker UI mode
+ */
+ public function setMode($value)
+ {
+ $this->setViewState('Mode', TPropertyValue::ensureEnum($value, 'TColorPickerMode'), TColorPickerMode::Basic);
+ }
+
+ /**
+ * @return TColorPickerMode current color picker UI mode. Defaults to TColorPickerMode::Basic.
+ */
+ public function getMode()
+ {
+ return $this->getViewState('Mode', TColorPickerMode::Basic);
+ }
+
+ /**
+ * @param string set the color picker style
+ */
+ public function setColorPickerStyle($value)
+ {
+ $this->setViewState('ColorStyle', $value, 'default');
+ }
+
+ /**
+ * @return string current color picker style
+ */
+ public function getColorPickerStyle()
+ {
+ return $this->getViewState('ColorStyle', 'default');
+ }
+
+ /**
+ * @return string text for the color picker OK button. Default is "OK".
+ */
+ public function getOKButtonText()
+ {
+ return $this->getViewState('OKButtonText', 'OK');
+ }
+
+ /**
+ * @param string text for the color picker OK button
+ */
+ public function setOKButtonText($value)
+ {
+ $this->setViewState('OKButtonText', $value, 'OK');
+ }
+
+ /**
+ * @return string text for the color picker Cancel button. Default is "Cancel".
+ */
+ public function getCancelButtonText()
+ {
+ return $this->getViewState('CancelButtonText', 'Cancel');
+ }
+
+ /**
+ * @param string text for the color picker Cancel button
+ */
+ public function setCancelButtonText($value)
+ {
+ $this->setViewState('CancelButtonText', $value, 'Cancel');
+ }
+
+ /**
+ * @return TColorPickerClientSide javascript event options.
+ */
+ public function getClientSide()
+ {
+ if($this->_clientSide===null)
+ $this->_clientSide = $this->createClientSide();
+ return $this->_clientSide;
+ }
+
+ /**
+ * @return TColorPickerClientSide javascript validator event options.
+ */
+ protected function createClientSide()
+ {
+ return new TColorPickerClientSide;
+ }
+
+ /**
+ * Get javascript color picker options.
+ * @return array color picker client-side options
+ */
+ protected function getPostBackOptions()
+ {
+ $options = parent::getPostBackOptions();
+ $options['ClassName'] = $this->getCssClass();
+ $options['ShowColorPicker'] = $this->getShowColorPicker();
+ if($options['ShowColorPicker'])
+ {
+ $mode = $this->getMode();
+ if($mode == TColorPickerMode::Full) $options['Mode'] = $mode;
+ else if($mode == TColorPickerMode::Simple) $options['Palette'] = 'Tiny';
+ $options['OKButtonText'] = $this->getOKButtonText();
+ $options['CancelButtonText'] = $this->getCancelButtonText();
+ }
+ $options = array_merge($options,$this->getClientSide()->getOptions()->toArray());
+ return $options;
+ }
+
+ /**
+ * @param string asset file in the self::SCRIPT_PATH directory.
+ * @return string asset file url.
+ */
+ protected function getAssetUrl($file='')
+ {
+ $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
+ return $base.'/'.self::SCRIPT_PATH.'/'.$file;
+ }
+
+ /**
+ * Publish the color picker Css asset files.
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->publishColorPickerAssets();
+ }
+
+ /**
+ * Publish the color picker assets.
+ */
+ protected function publishColorPickerAssets()
+ {
+ $cs = $this->getPage()->getClientScript();
+ $key = "prado:".get_class($this);
+ $imgs['button.gif'] = $this->getAssetUrl('button.gif');
+ $imgs['background.png'] = $this->getAssetUrl('background.png');
+ $options = TJavaScript::encode($imgs);
+ $code = "Prado.WebUI.TColorPicker.UIImages = {$options};";
+ $cs->registerEndScript($key, $code);
+ $cs->registerPradoScript("colorpicker");
+ $url = $this->getAssetUrl($this->getColorPickerStyle().'.css');
+ if(!$cs->isStyleSheetFileRegistered($url))
+ $cs->registerStyleSheetFile($url, $url);
+ }
+
+ /**
+ * Renders additional body content.
+ * This method overrides parent implementation by adding
+ * additional color picker button.
+ * @param THtmlWriter writer
+ */
+ public function renderEndTag($writer)
+ {
+ parent::renderEndTag($writer);
+
+ $color = $this->getText();
+ $writer->addAttribute('class', 'TColorPicker_button');
+ $writer->renderBeginTag('span');
+
+ $writer->addAttribute('id', $this->getClientID().'_button');
+ $writer->addAttribute('src', $this->getAssetUrl('button.gif'));
+ if($color !== '')
+ $writer->addAttribute('style', "background-color:{$color};");
+ $writer->addAttribute('width', '20');
+ $writer->addAttribute('height', '20');
+ $writer->addAttribute('alt', '');
+ $writer->renderBeginTag('img');
+ $writer->renderEndTag();
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TColorPicker';
+ }
+}
+
+/**
+ * TColorPickerMode class.
+ * TColorPickerMode defines the enumerable type for the possible UI mode
+ * that a {@link TColorPicker} control can take.
+ *
+ * The following enumerable values are defined:
+ * # Simple - Grid with 12 simple colors.
+ * # Basic - Grid with the most common 70 colors. This is the default mode.
+ * # Full - Full-featured color picker.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TColorPickerMode extends TEnumerable
+{
+ const Simple='Simple';
+ const Basic='Basic';
+ const Full='Full';
+}
+
+/**
+ * TColorPickerClientSide class.
+ *
+ * Client-side javascript code options.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1
+ */
+class TColorPickerClientSide extends TClientSideOptions
+{
+ /**
+ * @return string javascript code for when a color is selected.
+ */
+ public function getOnColorSelected()
+ {
+ return $this->getOption('OnColorSelected');
+ }
+
+ /**
+ * @param string javascript code for when a color is selected.
+ */
+ public function setOnColorSelected($javascript)
+ {
+ $this->setFunction('OnColorSelected', $javascript);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TCompareValidator.php b/lib/prado/framework/Web/UI/WebControls/TCompareValidator.php
new file mode 100644
index 0000000..3048895
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TCompareValidator.php
@@ -0,0 +1,262 @@
+<?php
+/**
+ * TCompareValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TCompareValidator class
+ *
+ * TCompareValidator compares the value entered by the user into an input
+ * control with the value entered into another input control or a constant value.
+ * To compare the associated input control with another input control,
+ * set the {@link setControlToCompare ControlToCompare} property to the ID path
+ * of the control to compare with. To compare the associated input control with
+ * a constant value, specify the constant value to compare with by setting the
+ * {@link setValueToCompare ValueToCompare} property.
+ *
+ * The {@link setDataType DataType} property is used to specify the data type
+ * of both comparison values. Both values are automatically converted to this data
+ * type before the comparison operation is performed. The following value types are supported:
+ * - <b>Integer</b> A 32-bit signed integer data type.
+ * - <b>Float</b> A double-precision floating point number data type.
+ * - <b>Date</b> A date data type. The format can be specified by the
+ * {@link setDateFormat DateFormat} property
+ * - <b>String</b> A string data type.
+ *
+ * Use the {@link setOperator Operator} property to specify the type of comparison
+ * to perform. Valid operators include Equal, NotEqual, GreaterThan, GreaterThanEqual,
+ * LessThan and LessThanEqual.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCompareValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TCompareValidator';
+ }
+
+ /**
+ * @return TValidationDataType the data type that the values being compared are converted to before the comparison is made. Defaults to TValidationDataType::String.
+ */
+ public function getDataType()
+ {
+ return $this->getViewState('DataType',TValidationDataType::String);
+ }
+
+ /**
+ * Sets the data type that the values being
+ * compared are converted to before the comparison is made.
+ * @param TValidationDataType the data type
+ */
+ public function setDataType($value)
+ {
+ $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TValidationDataType'),TValidationDataType::String);
+ }
+
+ /**
+ * @return string the input component to compare with the input control being validated.
+ */
+ public function getControlToCompare()
+ {
+ return $this->getViewState('ControlToCompare','');
+ }
+
+ /**
+ * Sets the input component to compare with the input control being validated.
+ * @param string the ID path of the component to compare with
+ */
+ public function setControlToCompare($value)
+ {
+ $this->setViewState('ControlToCompare',$value,'');
+ }
+
+ /**
+ * @return string the constant value to compare with the value entered by the user into the input component being validated.
+ */
+ public function getValueToCompare()
+ {
+ return $this->getViewState('ValueToCompare','');
+ }
+
+ /**
+ * Sets the constant value to compare with the value entered by the user into the input component being validated.
+ * @param string the constant value
+ */
+ public function setValueToCompare($value)
+ {
+ $this->setViewState('ValueToCompare',$value,'');
+ }
+
+ /**
+ * @return TValidationCompareOperator the comparison operation to perform. Defaults to TValidationCompareOperator::Equal.
+ */
+ public function getOperator()
+ {
+ return $this->getViewState('Operator',TValidationCompareOperator::Equal);
+ }
+
+ /**
+ * Sets the comparison operation to perform
+ * @param TValidationCompareOperator the comparison operation
+ */
+ public function setOperator($value)
+ {
+ $this->setViewState('Operator',TPropertyValue::ensureEnum($value,'TValidationCompareOperator'),TValidationCompareOperator::Equal);
+ }
+
+ /**
+ * Sets the date format for a date validation
+ * @param string the date format value
+ */
+ public function setDateFormat($value)
+ {
+ $this->setViewState('DateFormat', $value, '');
+ }
+
+ /**
+ * @return string the date validation date format if any
+ */
+ public function getDateFormat()
+ {
+ return $this->getViewState('DateFormat', '');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input data compares successfully.
+ * The validation always succeeds if ControlToValidate is not specified
+ * or the input data is empty.
+ * @return boolean whether the validation succeeds
+ */
+ public function evaluateIsValid()
+ {
+ if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
+ return true;
+
+ if(($controlToCompare=$this->getControlToCompare())!=='')
+ {
+ if(($control2=$this->findControl($controlToCompare))===null)
+ throw new TInvalidDataValueException('comparevalidator_controltocompare_invalid');
+ if(($value2=$this->getValidationValue($control2))==='')
+ return false;
+ }
+ else
+ $value2=$this->getValueToCompare();
+
+ $values = $this->getComparisonValues($value, $value2);
+ switch($this->getOperator())
+ {
+ case TValidationCompareOperator::Equal:
+ return $values[0] == $values[1];
+ case TValidationCompareOperator::NotEqual:
+ return $values[0] != $values[1];
+ case TValidationCompareOperator::GreaterThan:
+ return $values[0] > $values[1];
+ case TValidationCompareOperator::GreaterThanEqual:
+ return $values[0] >= $values[1];
+ case TValidationCompareOperator::LessThan:
+ return $values[0] < $values[1];
+ case TValidationCompareOperator::LessThanEqual:
+ return $values[0] <= $values[1];
+ }
+
+ return false;
+ }
+
+ /**
+ * Parse the pair of values into the appropriate value type.
+ * @param string value one
+ * @param string second value
+ * @return array appropriate type of the value pair, array($value1, $value2);
+ */
+ protected function getComparisonValues($value1, $value2)
+ {
+ switch($this->getDataType())
+ {
+ case TValidationDataType::Integer:
+ return array(intval($value1), intval($value2));
+ case TValidationDataType::Float:
+ return array(floatval($value1), floatval($value2));
+ case TValidationDataType::Date:
+ $dateFormat = $this->getDateFormat();
+ if($dateFormat!=='')
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $dateFormat);
+ return array($formatter->parse($value1), $formatter->parse($value2));
+ }
+ else
+ return array(strtotime($value1), strtotime($value2));
+ }
+ return array($value1, $value2);
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options = parent::getClientScriptOptions();
+ if(($name=$this->getControlToCompare())!=='')
+ {
+ if(($control=$this->findControl($name))!==null)
+ $options['ControlToCompare']=$control->getClientID();
+ }
+ if(($value=$this->getValueToCompare())!=='')
+ $options['ValueToCompare']=$value;
+ if(($operator=$this->getOperator())!==TValidationCompareOperator::Equal)
+ $options['Operator']=$operator;
+ $options['DataType']=$this->getDataType();
+ if(($dateFormat=$this->getDateFormat())!=='')
+ $options['DateFormat']=$dateFormat;
+ return $options;
+ }
+}
+
+
+/**
+ * TValidationCompareOperator class.
+ * TValidationCompareOperator defines the enumerable type for the comparison operations
+ * that {@link TCompareValidator} can perform validation with.
+ *
+ * The following enumerable values are defined:
+ * - Equal
+ * - NotEqual
+ * - GreaterThan
+ * - GreaterThanEqual
+ * - LessThan
+ * - LessThanEqual
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TValidationCompareOperator extends TEnumerable
+{
+ const Equal='Equal';
+ const NotEqual='NotEqual';
+ const GreaterThan='GreaterThan';
+ const GreaterThanEqual='GreaterThanEqual';
+ const LessThan='LessThan';
+ const LessThanEqual='LessThanEqual';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TConditional.php b/lib/prado/framework/Web/UI/WebControls/TConditional.php
new file mode 100644
index 0000000..d9bc168
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TConditional.php
@@ -0,0 +1,141 @@
+<?php
+/**
+ * TConditional class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TConditional class.
+ *
+ * TConditional displays appropriate content based on the evaluation result
+ * of a PHP expression specified via {@link setCondition Condition}.
+ * If the result is true, it instantiates the template {@link getTrueTemplate TrueTemplate};
+ * otherwise, the template {@link getFalseTemplate FalseTemplate} is instantiated.
+ * The PHP expression is evaluated right before {@link onInit} stage of the control lifecycle.
+ *
+ * Since {@link setCondition Condition} is evaluated at a very early stage, it is recommended
+ * you set {@link setCondition Condition} in template and the expression should not refer to
+ * objects that are available on or after {@link onInit} lifecycle.
+ *
+ * A typical usage of TConditional is shown as following:
+ * <code>
+ * <com:TConditional Condition="$this->User->IsGuest">
+ * <prop:TrueTemplate>
+ * <a href="path/to/login">Login</a>
+ * </prop:TrueTemplate>
+ * <prop:FalseTemplate>
+ * <a href="path/to/logout">Logout</a>
+ * </prop:FalseTemplate>
+ * </com:TConditional>
+ * </code>
+ *
+ * TConditional is very light. It instantiates either {@link getTrueTemplate TrueTemplate}
+ * or {@link getFalseTemplate FalseTemplate}, but never both. And the condition is evaluated only once.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TConditional extends TControl
+{
+ private $_condition='true';
+ private $_trueTemplate;
+ private $_falseTemplate;
+ private $_creatingChildren=false;
+
+ /**
+ * Processes an object that is created during parsing template.
+ * This method overrides the parent implementation by removing
+ * all contents enclosed in the template tag.
+ * @param string|TComponent text string or component parsed and instantiated in template
+ * @see createdOnTemplate
+ */
+ public function addParsedObject($object)
+ {
+ if($this->_creatingChildren)
+ parent::addParsedObject($object);
+ }
+
+ /**
+ * Creates child controls.
+ * This method overrides the parent implementation. It evaluates {@link getCondition Condition}
+ * and instantiate the corresponding template.
+ */
+ public function createChildControls()
+ {
+ $this->_creatingChildren=true;
+ $result=true;
+ try
+ {
+ $result=$this->getTemplateControl()->evaluateExpression($this->_condition);
+ }
+ catch(Exception $e)
+ {
+ throw new TInvalidDataValueException('conditional_condition_invalid',$this->_condition,$e->getMessage());
+ }
+ if($result)
+ {
+ if($this->_trueTemplate)
+ $this->_trueTemplate->instantiateIn($this->getTemplateControl(),$this);
+ }
+ else if($this->_falseTemplate)
+ $this->_falseTemplate->instantiateIn($this->getTemplateControl(),$this);
+ $this->_creatingChildren=false;
+ }
+
+ /**
+ * @return string the PHP expression used for determining which template to use. Defaults to 'true', meaning using TrueTemplate.
+ */
+ public function getCondition()
+ {
+ return $this->_condition;
+ }
+
+ /**
+ * Sets the PHP expression to be evaluated for conditionally displaying content.
+ * The context of the expression is the template control containing TConditional.
+ * @param string the PHP expression used for determining which template to use.
+ */
+ public function setCondition($value)
+ {
+ $this->_condition=TPropertyValue::ensureString($value);
+ }
+
+ /**
+ * @return ITemplate the template applied when {@link getCondition Condition} is true.
+ */
+ public function getTrueTemplate()
+ {
+ return $this->_trueTemplate;
+ }
+
+ /**
+ * @param ITemplate the template applied when {@link getCondition Condition} is true.
+ */
+ public function setTrueTemplate(ITemplate $value)
+ {
+ $this->_trueTemplate=$value;
+ }
+
+ /**
+ * @return ITemplate the template applied when {@link getCondition Condition} is false.
+ */
+ public function getFalseTemplate()
+ {
+ return $this->_falseTemplate;
+ }
+
+ /**
+ * @param ITemplate the template applied when {@link getCondition Condition} is false.
+ */
+ public function setFalseTemplate(ITemplate $value)
+ {
+ $this->_falseTemplate=$value;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TContent.php b/lib/prado/framework/Web/UI/WebControls/TContent.php
new file mode 100644
index 0000000..1a0fd37
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TContent.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * TContent class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TContent class
+ *
+ * TContent specifies a block of content on a control's template
+ * that will be injected at somewhere of the master control's template.
+ * TContentPlaceHolder and {@link TContent} together implement a decoration
+ * pattern for prado templated controls. A template control
+ * (called content control) can specify a master control
+ * whose template contains some TContentPlaceHolder controls.
+ * {@link TContent} controls on the content control's template will replace the corresponding
+ * {@link TContentPlaceHolder} controls on the master control's template.
+ * This is called content injection. It is done by matching the IDs of
+ * {@link TContent} and {@link TContentPlaceHolder} controls.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TContent extends TControl implements INamingContainer
+{
+ /**
+ * This method is invoked after the control is instantiated on a template.
+ * This overrides the parent implementation by registering the content control
+ * to the template owner control.
+ * @param TControl potential parent of this control
+ */
+ public function createdOnTemplate($parent)
+ {
+ if(($id=$this->getID())==='')
+ throw new TConfigurationException('content_id_required');
+ $this->getTemplateControl()->registerContent($id,$this);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TContentPlaceHolder.php b/lib/prado/framework/Web/UI/WebControls/TContentPlaceHolder.php
new file mode 100644
index 0000000..0355467
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TContentPlaceHolder.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * TContentPlaceHolder class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TContentPlaceHolder class
+ *
+ * TContentPlaceHolder reserves a place on a template where a {@link TContent}
+ * control can inject itself and its children in. TContentPlaceHolder and {@link TContent}
+ * together implement a decoration pattern for prado templated controls.
+ * A template control (called content control) can specify a master control
+ * whose template contains some TContentPlaceHolder controls.
+ * {@link TContent} controls on the content control's template will replace the corresponding
+ * {@link TContentPlaceHolder} controls on the master control's template.
+ * This is called content injection. It is done by matching the IDs of
+ * {@link TContent} and {@link TContentPlaceHolder} controls.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TContentPlaceHolder extends TControl
+{
+ /**
+ * This method is invoked after the control is instantiated on a template.
+ * This overrides the parent implementation by registering the content placeholder
+ * control to the template owner control. The placeholder control will NOT
+ * be added to the potential parent control!
+ * @param TControl potential parent of this control
+ */
+ public function createdOnTemplate($parent)
+ {
+ if(($id=$this->getID())==='')
+ throw new TConfigurationException('contentplaceholder_id_required');
+ $this->getTemplateControl()->registerContentPlaceHolder($id,$this);
+ $parent->getControls()->add($this);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TCustomValidator.php b/lib/prado/framework/Web/UI/WebControls/TCustomValidator.php
new file mode 100644
index 0000000..ca31a2a
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TCustomValidator.php
@@ -0,0 +1,204 @@
+<?php
+/**
+ * TCustomValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TCustomValidator class
+ *
+ * TCustomValidator performs user-defined validation (either
+ * server-side or client-side or both) on an input component.
+ *
+ * To create a server-side validation function, provide a handler for
+ * the {@link onServerValidate OnServerValidate} event that performs the validation.
+ * The data string of the input control to validate can be accessed
+ * by {@link TServerValidateEventParameter::getValue Value} of the event parameter.
+ * The result of the validation should be stored in the
+ * {@link TServerValidateEventParameter::getIsValid IsValid} property of the event
+ * parameter.
+ *
+ * To create a client-side validation function, add the client-side
+ * validation javascript function to the page template.
+ * The function should have the following signature:
+ * <code>
+ * <script type="text/javascript"><!--
+ * function ValidationFunctionName(sender, parameter)
+ * {
+ * // if(parameter == ...)
+ * // return true;
+ * // else
+ * // return false;
+ * }
+ * --></script>
+ * </code>
+ * Use the {@link setClientValidationFunction ClientValidationFunction} property
+ * to specify the name of the client-side validation script function associated
+ * with the TCustomValidator.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCustomValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TCustomValidator';
+ }
+
+ /**
+ * @return string the name of the custom client-side script function used for validation.
+ */
+ public function getClientValidationFunction()
+ {
+ return $this->getViewState('ClientValidationFunction','');
+ }
+
+ /**
+ * Sets the name of the custom client-side script function used for validation.
+ * @param string the script function name
+ */
+ public function setClientValidationFunction($value)
+ {
+ $this->setViewState('ClientValidationFunction',$value,'');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if {@link onServerValidate} returns true.
+ * @return boolean whether the validation succeeds
+ */
+ public function evaluateIsValid()
+ {
+ $value = '';
+ if($this->getValidationTarget()!==null)
+ $value=$this->getValidationValue($this->getValidationTarget());
+ return $this->onServerValidate($value);
+ }
+
+ /**
+ * This method is invoked when the server side validation happens.
+ * It will raise the <b>OnServerValidate</b> event.
+ * The method also allows derived classes to handle the event without attaching a delegate.
+ * <b>Note</b> The derived classes should call parent implementation
+ * to ensure the <b>OnServerValidate</b> event is raised.
+ * @param string the value to be validated
+ * @return boolean whether the value is valid
+ */
+ public function onServerValidate($value)
+ {
+ $param=new TServerValidateEventParameter($value,true);
+ $this->raiseEvent('OnServerValidate',$this,$param);
+ return $param->getIsValid();
+ }
+
+ /**
+ * @return TControl control to be validated. Null if no control is found.
+ */
+ public function getValidationTarget()
+ {
+ if(($id=$this->getControlToValidate())!=='' && ($control=$this->findControl($id))!==null)
+ return $control;
+ else if(($id=$this->getControlToValidate())!=='')
+ throw new TInvalidDataTypeException('basevalidator_validatable_required',get_class($this));
+ else
+ return null;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options=parent::getClientScriptOptions();
+ if(($clientJs=$this->getClientValidationFunction())!=='')
+ $options['ClientValidationFunction']=$clientJs;
+ return $options;
+ }
+
+ /**
+ * Only register the client-side validator if
+ * {@link setClientValidationFunction ClientValidationFunction} is set.
+ */
+ protected function registerClientScriptValidator()
+ {
+ if($this->getClientValidationFunction()!=='')
+ parent::registerClientScriptValidator();
+ }
+}
+
+/**
+ * TServerValidateEventParameter class
+ *
+ * TServerValidateEventParameter encapsulates the parameter data for
+ * <b>OnServerValidate</b> event of TCustomValidator components.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TServerValidateEventParameter extends TEventParameter
+{
+ /**
+ * the value to be validated
+ * @var string
+ */
+ private $_value='';
+ /**
+ * whether the value is valid
+ * @var boolean
+ */
+ private $_isValid=true;
+
+ /**
+ * Constructor.
+ * @param string property value to be validated
+ * @param boolean whether the value is valid
+ */
+ public function __construct($value,$isValid)
+ {
+ $this->_value=$value;
+ $this->setIsValid($isValid);
+ }
+
+ /**
+ * @return string value to be validated
+ */
+ public function getValue()
+ {
+ return $this->_value;
+ }
+
+ /**
+ * @return boolean whether the value is valid
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+
+ /**
+ * @param boolean whether the value is valid
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TDataBoundControl.php b/lib/prado/framework/Web/UI/WebControls/TDataBoundControl.php
new file mode 100644
index 0000000..8078b6f
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TDataBoundControl.php
@@ -0,0 +1,582 @@
+<?php
+/**
+ * TDataBoundControl class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataSourceControl');
+Prado::using('System.Web.UI.WebControls.TDataSourceView');
+Prado::using('System.Collections.TPagedDataSource');
+
+/**
+ * TDataBoundControl class.
+ *
+ * TDataBoundControl is the based class for controls that need to populate
+ * data from data sources. It provides basic properties and methods that allow
+ * the derived controls to associate with data sources and retrieve data from them.
+ *
+ * TBC....
+ *
+ * TDataBoundControl is equipped with paging capabilities. By setting
+ * {@link setAllowPaging AllowPaging} to true, the input data will be paged
+ * and only one page of data is actually populated into the data-bound control.
+ * This saves a lot of memory when dealing with larget datasets.
+ *
+ * To specify the number of data items displayed on each page, set
+ * the {@link setPageSize PageSize} property, and to specify which
+ * page of data to be displayed, set {@link setCurrentPageIndex CurrentPageIndex}.
+ *
+ * When the size of the original data is too big to be loaded all in the memory,
+ * one can enable custom paging. In custom paging, the total number of data items
+ * is specified manually via {@link setVirtualItemCount VirtualItemCount},
+ * and the data source only needs to contain the current page of data. To enable
+ * custom paging, set {@link setAllowCustomPaging AllowCustomPaging} to true.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TDataBoundControl extends TWebControl
+{
+ private $_initialized=false;
+ private $_dataSource=null;
+ private $_requiresBindToNull=false;
+ private $_requiresDataBinding=false;
+ private $_prerendered=false;
+ private $_currentView=null;
+ private $_currentDataSource=null;
+ private $_currentViewValid=false;
+ private $_currentDataSourceValid=false;
+ private $_currentViewIsFromDataSourceID=false;
+ private $_parameters=null;
+ private $_isDataBound=false;
+
+ /**
+ * @return Traversable data source object, defaults to null.
+ */
+ public function getDataSource()
+ {
+ return $this->_dataSource;
+ }
+
+ /**
+ * Sets the data source object associated with the databound control.
+ * The data source must implement Traversable interface.
+ * If an array is given, it will be converted to xxx.
+ * If a string is given, it will be converted to xxx.
+ * @param Traversable|array|string data source object
+ */
+ public function setDataSource($value)
+ {
+ $this->_dataSource=$this->validateDataSource($value);
+ $this->onDataSourceChanged();
+ }
+
+ /**
+ * @return string ID path to the data source control. Defaults to empty.
+ */
+ public function getDataSourceID()
+ {
+ return $this->getViewState('DataSourceID','');
+ }
+
+ /**
+ * @param string ID path to the data source control. The data source
+ * control must be locatable via {@link TControl::findControl} call.
+ */
+ public function setDataSourceID($value)
+ {
+ $dsid=$this->getViewState('DataSourceID','');
+ if($dsid!=='' && $value==='')
+ $this->_requiresBindToNull=true;
+ $this->setViewState('DataSourceID',$value,'');
+ $this->onDataSourceChanged();
+ }
+
+ /**
+ * @return boolean if the databound control uses the data source specified
+ * by {@link setDataSourceID}, or it uses the data source object specified
+ * by {@link setDataSource}.
+ */
+ protected function getUsingDataSourceID()
+ {
+ return $this->getDataSourceID()!=='';
+ }
+
+ /**
+ * Sets {@link setRequiresDataBinding RequiresDataBinding} as true if the control is initialized.
+ * This method is invoked when either {@link setDataSource} or {@link setDataSourceID} is changed.
+ */
+ public function onDataSourceChanged()
+ {
+ $this->_currentViewValid=false;
+ $this->_currentDataSourceValid=false;
+ if($this->getInitialized())
+ $this->setRequiresDataBinding(true);
+ }
+
+ /**
+ * @return boolean whether the databound control has been initialized.
+ * By default, the control is initialized after its viewstate has been restored.
+ */
+ protected function getInitialized()
+ {
+ return $this->_initialized;
+ }
+
+ /**
+ * Sets a value indicating whether the databound control is initialized.
+ * If initialized, any modification to {@link setDataSource DataSource} or
+ * {@link setDataSourceID DataSourceID} will set {@link setRequiresDataBinding RequiresDataBinding}
+ * as true.
+ * @param boolean a value indicating whether the databound control is initialized.
+ */
+ protected function setInitialized($value)
+ {
+ $this->_initialized=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether databind has been invoked in the previous page request
+ */
+ protected function getIsDataBound()
+ {
+ return $this->_isDataBound;
+ }
+
+ /**
+ * @param boolean if databind has been invoked in this page request
+ */
+ protected function setIsDataBound($value)
+ {
+ $this->_isDataBound=$value;
+ }
+
+ /**
+ * @return boolean whether a databind call is required (by the data bound control)
+ */
+ protected function getRequiresDataBinding()
+ {
+ return $this->_requiresDataBinding;
+ }
+
+ /**
+ * @return boolean whether paging is enabled. Defaults to false.
+ */
+ public function getAllowPaging()
+ {
+ return $this->getViewState('AllowPaging',false);
+ }
+
+ /**
+ * @param boolean whether paging is enabled
+ */
+ public function setAllowPaging($value)
+ {
+ $this->setViewState('AllowPaging',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether the custom paging is enabled. Defaults to false.
+ */
+ public function getAllowCustomPaging()
+ {
+ return $this->getViewState('AllowCustomPaging',false);
+ }
+
+ /**
+ * Sets a value indicating whether the custom paging should be enabled.
+ * When the pager is in custom paging mode, the {@link setVirtualItemCount VirtualItemCount}
+ * property is used to determine the paging, and the data items in the
+ * {@link setDataSource DataSource} are considered to be in the current page.
+ * @param boolean whether the custom paging is enabled
+ */
+ public function setAllowCustomPaging($value)
+ {
+ $this->setViewState('AllowCustomPaging',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return integer the zero-based index of the current page. Defaults to 0.
+ */
+ public function getCurrentPageIndex()
+ {
+ return $this->getViewState('CurrentPageIndex',0);
+ }
+
+ /**
+ * @param integer the zero-based index of the current page
+ * @throws TInvalidDataValueException if the value is less than 0
+ */
+ public function setCurrentPageIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=0;
+ $this->setViewState('CurrentPageIndex',$value,0);
+ }
+
+ /**
+ * @return integer the number of data items on each page. Defaults to 10.
+ */
+ public function getPageSize()
+ {
+ return $this->getViewState('PageSize',10);
+ }
+
+ /**
+ * @param integer the number of data items on each page.
+ * @throws TInvalidDataValueException if the value is less than 1
+ */
+ public function setPageSize($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<1)
+ throw new TInvalidDataValueException('databoundcontrol_pagesize_invalid',get_class($this));
+ $this->setViewState('PageSize',TPropertyValue::ensureInteger($value),10);
+ }
+
+ /**
+ * @return integer number of pages of data items available
+ */
+ public function getPageCount()
+ {
+ return $this->getViewState('PageCount',1);
+ }
+
+ /**
+ * @return integer virtual number of data items in the data source. Defaults to 0.
+ * @see setAllowCustomPaging
+ */
+ public function getVirtualItemCount()
+ {
+ return $this->getViewState('VirtualItemCount',0);
+ }
+
+ /**
+ * @param integer virtual number of data items in the data source.
+ * @throws TInvalidDataValueException if the value is less than 0
+ * @see setAllowCustomPaging
+ */
+ public function setVirtualItemCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('databoundcontrol_virtualitemcount_invalid',get_class($this));
+ $this->setViewState('VirtualItemCount',$value,0);
+ }
+
+ /**
+ * Sets a value indicating whether a databind call is required by the data bound control.
+ * If true and the control has been prerendered while it uses the data source
+ * specified by {@link setDataSourceID}, a databind call will be called by this method.
+ * @param boolean whether a databind call is required.
+ */
+ protected function setRequiresDataBinding($value)
+ {
+ $value=TPropertyValue::ensureBoolean($value);
+ if($value && $this->_prerendered)
+ {
+ $this->_requiresDataBinding=true;
+ $this->ensureDataBound();
+ }
+ else
+ $this->_requiresDataBinding=$value;
+ }
+
+ /**
+ * Ensures any pending {@link dataBind} is called.
+ * This method calls {@link dataBind} if the data source is specified
+ * by {@link setDataSourceID} or if {@link getRequiresDataBinding RequiresDataBinding}
+ * is true.
+ */
+ protected function ensureDataBound()
+ {
+ if($this->_requiresDataBinding && ($this->getUsingDataSourceID() || $this->_requiresBindToNull))
+ {
+ $this->dataBind();
+ $this->_requiresBindToNull=false;
+ }
+ }
+
+ /**
+ * @return TPagedDataSource creates a paged data source
+ */
+ protected function createPagedDataSource()
+ {
+ $ds=new TPagedDataSource;
+ $ds->setCurrentPageIndex($this->getCurrentPageIndex());
+ $ds->setPageSize($this->getPageSize());
+ $ds->setAllowPaging($this->getAllowPaging());
+ $ds->setAllowCustomPaging($this->getAllowCustomPaging());
+ $ds->setVirtualItemCount($this->getVirtualItemCount());
+ return $ds;
+ }
+
+ /**
+ * Performs databinding.
+ * This method overrides the parent implementation by calling
+ * {@link performSelect} which fetches data from data source and does
+ * the actual binding work.
+ */
+ public function dataBind()
+ {
+ $this->setRequiresDataBinding(false);
+ $this->dataBindProperties();
+ $this->onDataBinding(null);
+
+ if(($view=$this->getDataSourceView())!==null)
+ $data=$view->select($this->getSelectParameters());
+ else
+ $data=null;
+
+ if($data instanceof Traversable)
+ {
+ if($this->getAllowPaging())
+ {
+ $ds=$this->createPagedDataSource();
+ $ds->setDataSource($data);
+ $this->setViewState('PageCount',$ds->getPageCount());
+ if($ds->getCurrentPageIndex()>=$ds->getPageCount())
+ {
+ $ds->setCurrentPageIndex($ds->getPageCount()-1);
+ $this->setCurrentPageIndex($ds->getCurrentPageIndex());
+ }
+ $this->performDataBinding($ds);
+ }
+ else
+ {
+ $this->clearViewState('PageCount');
+ $this->performDataBinding($data);
+ }
+ }
+ $this->setIsDataBound(true);
+ $this->onDataBound(null);
+ }
+
+ public function dataSourceViewChanged($sender,$param)
+ {
+ if(!$this->_ignoreDataSourceViewChanged)
+ $this->setRequiresDataBinding(true);
+ }
+
+ protected function getDataSourceView()
+ {
+ if(!$this->_currentViewValid)
+ {
+ if($this->_currentView && $this->_currentViewIsFromDataSourceID)
+ $this->_currentView->detachEventHandler('DataSourceViewChanged',array($this,'dataSourceViewChanged'));
+ if(($dataSource=$this->determineDataSource())!==null)
+ {
+ if(($view=$dataSource->getView($this->getDataMember()))===null)
+ throw new TInvalidDataValueException('databoundcontrol_datamember_invalid',$this->getDataMember());
+ if($this->_currentViewIsFromDataSourceID=$this->getUsingDataSourceID())
+ $view->attachEventHandler('OnDataSourceViewChanged',array($this,'dataSourceViewChanged'));
+ $this->_currentView=$view;
+ }
+ else
+ $this->_currentView=null;
+ $this->_currentViewValid=true;
+ }
+ return $this->_currentView;
+ }
+
+ protected function determineDataSource()
+ {
+ if(!$this->_currentDataSourceValid)
+ {
+ if(($dsid=$this->getDataSourceID())!=='')
+ {
+ if(($dataSource=$this->getNamingContainer()->findControl($dsid))===null)
+ throw new TInvalidDataValueException('databoundcontrol_datasourceid_inexistent',$dsid);
+ else if(!($dataSource instanceof IDataSource))
+ throw new TInvalidDataValueException('databoundcontrol_datasourceid_invalid',$dsid);
+ else
+ $this->_currentDataSource=$dataSource;
+ }
+ else if(($dataSource=$this->getDataSource())!==null)
+ $this->_currentDataSource=new TReadOnlyDataSource($dataSource,$this->getDataMember());
+ else
+ $this->_currentDataSource=null;
+ $this->_currentDataSourceValid=true;
+ }
+ return $this->_currentDataSource;
+ }
+
+ abstract protected function performDataBinding($data);
+
+ /**
+ * Raises <b>OnDataBound</b> event.
+ * This method should be invoked after a databind is performed.
+ * It is mainly used by framework and component developers.
+ */
+ public function onDataBound($param)
+ {
+ $this->raiseEvent('OnDataBound',$this,$param);
+ }
+
+ /**
+ * Sets page's <b>OnPreLoad</b> event handler as {@link pagePreLoad}.
+ * If viewstate is disabled and the current request is a postback,
+ * {@link setRequiresDataBinding RequiresDataBinding} will be set true.
+ * This method overrides the parent implementation.
+ * @param TEventParameter event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $page=$this->getPage();
+ $page->attachEventHandler('OnPreLoad',array($this,'pagePreLoad'));
+ }
+
+ /**
+ * Sets {@link getInitialized} as true.
+ * This method is invoked when page raises <b>PreLoad</b> event.
+ * @param mixed event sender
+ * @param TEventParameter event parameter
+ */
+ public function pagePreLoad($sender,$param)
+ {
+ $this->_initialized=true;
+ $isPostBack=$this->getPage()->getIsPostBack();
+ if(!$isPostBack || ($isPostBack && (!$this->getEnableViewState(true) || !$this->getIsDataBound())))
+ $this->setRequiresDataBinding(true);
+ }
+
+ /**
+ * Ensures any pending databind is performed.
+ * This method overrides the parent implementation.
+ * @param TEventParameter event parameter
+ */
+ public function onPreRender($param)
+ {
+ $this->_prerendered=true;
+ $this->ensureDataBound();
+ parent::onPreRender($param);
+ }
+
+ /**
+ * Validates if the parameter is a valid data source.
+ * If it is a string or an array, it will be converted as a TList object.
+ * @param Traversable|array|string data source to be validated
+ * @return Traversable the data that is traversable
+ * @throws TInvalidDataTypeException if the data is neither null nor Traversable
+ */
+ protected function validateDataSource($value)
+ {
+ if(is_string($value))
+ {
+ $list=new TList;
+ foreach(TPropertyValue::ensureArray($value) as $key=>$value)
+ {
+ if(is_array($value))
+ $list->add($value);
+ else
+ $list->add(array($value,is_string($key)?$key:$value));
+ }
+ return $list;
+ }
+ else if(is_array($value))
+ return new TMap($value);
+ else if($value instanceof TDbDataReader) {
+ // read array from TDbDataReader since it's forward-only stream and can only be traversed once
+ return $value->readAll();
+ }
+ else if(($value instanceof Traversable) || $value===null)
+ return $value;
+ else
+ throw new TInvalidDataTypeException('databoundcontrol_datasource_invalid',get_class($this));
+ }
+
+ public function getDataMember()
+ {
+ return $this->getViewState('DataMember','');
+ }
+
+ public function setDataMember($value)
+ {
+ $this->setViewState('DataMember',$value,'');
+ }
+
+ public function getSelectParameters()
+ {
+ if(!$this->_parameters)
+ $this->_parameters=new TDataSourceSelectParameters;
+ return $this->_parameters;
+ }
+}
+
+
+/**
+ * TListItemType class.
+ * TListItemType defines the enumerable type for the possible types
+ * that databound list items could take.
+ *
+ * The following enumerable values are defined:
+ * - Header: header item
+ * - Footer: footer item
+ * - Item: content item (neither header nor footer)
+ * - Separator: separator between items
+ * - AlternatingItem: alternating content item
+ * - EditItem: content item in edit mode
+ * - SelectedItem: selected content item
+ * - Pager: pager
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TListItemType extends TEnumerable
+{
+ const Header='Header';
+ const Footer='Footer';
+ const Item='Item';
+ const Separator='Separator';
+ const AlternatingItem='AlternatingItem';
+ const EditItem='EditItem';
+ const SelectedItem='SelectedItem';
+ const Pager='Pager';
+}
+
+
+/**
+ * IItemDataRenderer interface.
+ *
+ * IItemDataRenderer defines the interface that an item renderer
+ * needs to implement. Besides the {@link getData Data} property, a list item
+ * renderer also needs to provide {@link getItemIndex ItemIndex} and
+ * {@link getItemType ItemType} property.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.0
+ */
+interface IItemDataRenderer extends IDataRenderer
+{
+ /**
+ * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection.
+ * If the item is not in the collection (e.g. it is a header item), it returns -1.
+ * @return integer zero-based index of the item.
+ */
+ public function getItemIndex();
+
+ /**
+ * Sets the zero-based index for the item.
+ * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
+ * @param integer zero-based index of the item.
+ */
+ public function setItemIndex($value);
+
+ /**
+ * @return TListItemType the item type.
+ */
+ public function getItemType();
+
+ /**
+ * @param TListItemType the item type.
+ */
+ public function setItemType($value);
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TDataGrid.php b/lib/prado/framework/Web/UI/WebControls/TDataGrid.php
new file mode 100644
index 0000000..109252a
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TDataGrid.php
@@ -0,0 +1,2244 @@
+<?php
+/**
+ * TDataGrid related class files.
+ * This file contains the definition of the following classes:
+ * TDataGrid, TDataGridItem, TDataGridItemCollection, TDataGridColumnCollection,
+ * TDataGridPagerStyle, TDataGridItemEventParameter,
+ * TDataGridCommandEventParameter, TDataGridSortCommandEventParameter,
+ * TDataGridPageChangedEventParameter
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TBaseList, TPagedDataSource, TDummyDataSource and TTable classes
+ */
+Prado::using('System.Web.UI.WebControls.TBaseDataList');
+Prado::using('System.Collections.TPagedDataSource');
+Prado::using('System.Collections.TDummyDataSource');
+Prado::using('System.Web.UI.WebControls.TTable');
+Prado::using('System.Web.UI.WebControls.TPanel');
+Prado::using('System.Web.UI.WebControls.TDataGridPagerStyle');
+
+/**
+ * TDataGrid class
+ *
+ * TDataGrid represents a data bound and updatable grid control.
+ *
+ * To populate data into the datagrid, sets its {@link setDataSource DataSource}
+ * to a tabular data source and call {@link dataBind()}.
+ * Each row of data will be represented by an item in the {@link getItems Items}
+ * collection of the datagrid.
+ *
+ * An item can be at one of three states: browsing, selected and edit.
+ * The state determines how the item will be displayed. For example, if an item
+ * is in edit state, it may be displayed as a table row with input text boxes
+ * if the columns are of type {@link TBoundColumn}; and if in browsing state,
+ * they are displayed as static text.
+ *
+ * To change the state of an item, set {@link setEditItemIndex EditItemIndex}
+ * or {@link setSelectedItemIndex SelectedItemIndex} property.
+ *
+ * Each datagrid item has a {@link TDataGridItem::getItemType type}
+ * which tells the position and state of the item in the datalist. An item in the header
+ * of the repeater is of type Header. A body item may be of either
+ * Item, AlternatingItem, SelectedItem or EditItem, depending whether the item
+ * index is odd or even, whether it is being selected or edited.
+ *
+ * A datagrid is specified with a list of columns. Each column specifies how the corresponding
+ * table column will be displayed. For example, the header/footer text of that column,
+ * the cells in that column, and so on. The following column types are currently
+ * provided by the framework,
+ * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data.
+ * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons
+ * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource.
+ * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state
+ * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource.
+ * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource.
+ * - {@link TTemplateColumn}, displaying content based on templates.
+ *
+ * There are three ways to specify columns for a datagrid.
+ * <ul>
+ * <li>Automatically generated based on data source.
+ * By setting {@link setAutoGenerateColumns AutoGenerateColumns} to true,
+ * a list of columns will be automatically generated based on the schema of the data source.
+ * Each column corresponds to a column of the data.</li>
+ * <li>Specified in template. For example,
+ * <code>
+ * <com:TDataGrid ...>
+ * <com:TBoundColumn .../>
+ * <com:TEditCommandColumn .../>
+ * </com:TDataGrid>
+ * </code>
+ * </li>
+ * <li>Manually created in code. Columns can be manipulated via
+ * the {@link setColumns Columns} property of the datagrid. For example,
+ * <code>
+ * $column=new TBoundColumn;
+ * $datagrid->Columns[]=$column;
+ * </code>
+ * </li>
+ * </ul>
+ * Note, automatically generated columns cannot be accessed via
+ * the {@link getColumns Columns} property.
+ *
+ * TDataGrid supports sorting. If the {@link setAllowSorting AllowSorting}
+ * is set to true, a column with nonempty {@link setSortExpression SortExpression}
+ * will have its header text displayed as a clickable link button.
+ * Clicking on the link button will raise {@link onSortCommand OnSortCommand}
+ * event. You can respond to this event, sort the data source according
+ * to the event parameter, and then invoke {@link databind()} on the datagrid
+ * to show to end users the sorted data.
+ *
+ * TDataGrid supports paging. If the {@link setAllowPaging AllowPaging}
+ * is set to true, a pager will be displayed on top and/or bottom of the table.
+ * How the pager will be displayed is determined by the {@link getPagerStyle PagerStyle}
+ * property. Clicking on a pager button will raise an {@link onPageIndexChanged OnPageIndexChanged}
+ * event. You can respond to this event, specify the page to be displayed by
+ * setting {@link setCurrentPageIndex CurrentPageIndex}</b> property,
+ * and then invoke {@link databind()} on the datagrid to show to end users
+ * a new page of data.
+ *
+ * TDataGrid supports two kinds of paging. The first one is based on the number of data items in
+ * datasource. The number of pages {@link getPageCount PageCount} is calculated based
+ * the item number and the {@link setPageSize PageSize} property.
+ * The datagrid will manage which section of the data source to be displayed
+ * based on the {@link setCurrentPageIndex CurrentPageIndex} property.
+ * The second approach calculates the page number based on the
+ * {@link setVirtualItemCount VirtualItemCount} property and
+ * the {@link setPageSize PageSize} property. The datagrid will always
+ * display from the beginning of the datasource up to the number of
+ * {@link setPageSize PageSize} data items. This approach is especially
+ * useful when the datasource may contain too many data items to be managed by
+ * the datagrid efficiently.
+ *
+ * When the datagrid contains a button control that raises an {@link onCommand OnCommand}
+ * event, the event will be bubbled up to the datagrid control.
+ * If the event's command name is recognizable by the datagrid control,
+ * a corresponding item event will be raised. The following item events will be
+ * raised upon a specific command:
+ * - OnEditCommand, if CommandName=edit
+ * - OnCancelCommand, if CommandName=cancel
+ * - OnSelectCommand, if CommandName=select
+ * - OnDeleteCommand, if CommandName=delete
+ * - OnUpdateCommand, if CommandName=update
+ * - onPageIndexChanged, if CommandName=page
+ * - OnSortCommand, if CommandName=sort
+ * Note, an {@link onItemCommand OnItemCommand} event is raised in addition to
+ * the above specific command events.
+ *
+ * TDataGrid also raises an {@link onItemCreated OnItemCreated} event for
+ * every newly created datagrid item. You can respond to this event to customize
+ * the content or style of the newly created item.
+ *
+ * Note, the data bound to the datagrid are reset to null after databinding.
+ * There are several ways to access the data associated with a datagrid row:
+ * - Access the data in {@link onItemDataBound OnItemDataBound} event
+ * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
+ * the specified datagrid row and use the key to fetch the corresponding data
+ * from some persistent storage such as DB.
+ * - Save the data in viewstate and get it back during postbacks.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGrid extends TBaseDataList implements INamingContainer
+{
+ /**
+ * datagrid item types
+ * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead.
+ */
+ const IT_HEADER='Header';
+ const IT_FOOTER='Footer';
+ const IT_ITEM='Item';
+ const IT_SEPARATOR='Separator';
+ const IT_ALTERNATINGITEM='AlternatingItem';
+ const IT_EDITITEM='EditItem';
+ const IT_SELECTEDITEM='SelectedItem';
+ const IT_PAGER='Pager';
+
+ /**
+ * Command name that TDataGrid understands.
+ */
+ const CMD_SELECT='Select';
+ const CMD_EDIT='Edit';
+ const CMD_UPDATE='Update';
+ const CMD_DELETE='Delete';
+ const CMD_CANCEL='Cancel';
+ const CMD_SORT='Sort';
+ const CMD_PAGE='Page';
+ const CMD_PAGE_NEXT='Next';
+ const CMD_PAGE_PREV='Previous';
+ const CMD_PAGE_FIRST='First';
+ const CMD_PAGE_LAST='Last';
+
+ /**
+ * @var TDataGridColumnCollection manually created column collection
+ */
+ private $_columns=null;
+ /**
+ * @var TDataGridColumnCollection automatically created column collection
+ */
+ private $_autoColumns=null;
+ /**
+ * @var TList all columns including both manually and automatically created columns
+ */
+ private $_allColumns=null;
+ /**
+ * @var TDataGridItemCollection datagrid item collection
+ */
+ private $_items=null;
+ /**
+ * @var TDataGridItem header item
+ */
+ private $_header=null;
+ /**
+ * @var TDataGridItem footer item
+ */
+ private $_footer=null;
+ /**
+ * @var TPagedDataSource paged data source object
+ */
+ private $_pagedDataSource=null;
+ private $_topPager=null;
+ private $_bottomPager=null;
+ /**
+ * @var ITemplate template used when empty data is bounded
+ */
+ private $_emptyTemplate=null;
+ /**
+ * @var boolean whether empty template is effective
+ */
+ private $_useEmptyTemplate=false;
+
+ /**
+ * @return string tag name (table) of the datagrid
+ */
+ protected function getTagName()
+ {
+ return 'table';
+ }
+
+ /**
+ * @return string Name of the class used in AutoGenerateColumns mode
+ */
+ protected function getAutoGenerateColumnName()
+ {
+ return 'TBoundColumn';
+ }
+
+ /**
+ * Adds objects parsed in template to datagrid.
+ * Datagrid columns are added into {@link getColumns Columns} collection.
+ * @param mixed object parsed in template
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TDataGridColumn)
+ $this->getColumns()->add($object);
+ else
+ parent::addParsedObject($object); // this is needed by EmptyTemplate
+ }
+
+ /**
+ * @return TDataGridColumnCollection manually specified datagrid columns
+ */
+ public function getColumns()
+ {
+ if(!$this->_columns)
+ $this->_columns=new TDataGridColumnCollection($this);
+ return $this->_columns;
+ }
+
+ /**
+ * @return TDataGridColumnCollection automatically generated datagrid columns
+ */
+ public function getAutoColumns()
+ {
+ if(!$this->_autoColumns)
+ $this->_autoColumns=new TDataGridColumnCollection($this);
+ return $this->_autoColumns;
+ }
+
+ /**
+ * @return TDataGridItemCollection datagrid item collection
+ */
+ public function getItems()
+ {
+ if(!$this->_items)
+ $this->_items=new TDataGridItemCollection;
+ return $this->_items;
+ }
+
+ /**
+ * @return integer number of items
+ */
+ public function getItemCount()
+ {
+ return $this->_items?$this->_items->getCount():0;
+ }
+
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableStyle} to be used by datagrid.
+ * @return TTableStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableStyle;
+ }
+
+ /**
+ * @return string the URL of the background image for the datagrid
+ */
+ public function getBackImageUrl()
+ {
+ return $this->getStyle()->getBackImageUrl();
+ }
+
+ /**
+ * @param string the URL of the background image for the datagrid
+ */
+ public function setBackImageUrl($value)
+ {
+ $this->getStyle()->setBackImageUrl($value);
+ }
+
+ /**
+ * @return TTableItemStyle the style for every item
+ */
+ public function getItemStyle()
+ {
+ if(($style=$this->getViewState('ItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('ItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for each alternating item
+ */
+ public function getAlternatingItemStyle()
+ {
+ if(($style=$this->getViewState('AlternatingItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('AlternatingItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for selected item
+ */
+ public function getSelectedItemStyle()
+ {
+ if(($style=$this->getViewState('SelectedItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('SelectedItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for edit item
+ */
+ public function getEditItemStyle()
+ {
+ if(($style=$this->getViewState('EditItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('EditItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for header
+ */
+ public function getHeaderStyle()
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('HeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for footer
+ */
+ public function getFooterStyle()
+ {
+ if(($style=$this->getViewState('FooterStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('FooterStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TDataGridPagerStyle the style for pager
+ */
+ public function getPagerStyle()
+ {
+ if(($style=$this->getViewState('PagerStyle',null))===null)
+ {
+ $style=new TDataGridPagerStyle;
+ $this->setViewState('PagerStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TStyle the style for thead element, if any
+ * @since 3.1.1
+ */
+ public function getTableHeadStyle()
+ {
+ if(($style=$this->getViewState('TableHeadStyle',null))===null)
+ {
+ $style=new TStyle;
+ $this->setViewState('TableHeadStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TStyle the style for tbody element, if any
+ * @since 3.1.1
+ */
+ public function getTableBodyStyle()
+ {
+ if(($style=$this->getViewState('TableBodyStyle',null))===null)
+ {
+ $style=new TStyle;
+ $this->setViewState('TableBodyStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TStyle the style for tfoot element, if any
+ * @since 3.1.1
+ */
+ public function getTableFootStyle()
+ {
+ if(($style=$this->getViewState('TableFootStyle',null))===null)
+ {
+ $style=new TStyle;
+ $this->setViewState('TableFootStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string caption for the datagrid
+ */
+ public function getCaption()
+ {
+ return $this->getViewState('Caption','');
+ }
+
+ /**
+ * @param string caption for the datagrid
+ */
+ public function setCaption($value)
+ {
+ $this->setViewState('Caption',$value,'');
+ }
+
+ /**
+ * @return TTableCaptionAlign datagrid caption alignment. Defaults to TTableCaptionAlign::NotSet.
+ */
+ public function getCaptionAlign()
+ {
+ return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet);
+ }
+
+ /**
+ * @param TTableCaptionAlign datagrid caption alignment. Valid values include
+ */
+ public function setCaptionAlign($value)
+ {
+ $this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet);
+ }
+
+ /**
+ * @return TDataGridItem the header item
+ */
+ public function getHeader()
+ {
+ return $this->_header;
+ }
+
+ /**
+ * @return TDataGridItem the footer item
+ */
+ public function getFooter()
+ {
+ return $this->_footer;
+ }
+
+ /**
+ * @return TDataGridPager the pager displayed at the top of datagrid. It could be null if paging is disabled.
+ */
+ public function getTopPager()
+ {
+ return $this->_topPager;
+ }
+
+ /**
+ * @return TDataGridPager the pager displayed at the bottom of datagrid. It could be null if paging is disabled.
+ */
+ public function getBottomPager()
+ {
+ return $this->_bottomPager;
+ }
+
+ /**
+ * @return TDataGridItem the selected item, null if no item is selected.
+ */
+ public function getSelectedItem()
+ {
+ $index=$this->getSelectedItemIndex();
+ $items=$this->getItems();
+ if($index>=0 && $index<$items->getCount())
+ return $items->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return integer the zero-based index of the selected item in {@link getItems Items}.
+ * A value -1 means no item selected.
+ */
+ public function getSelectedItemIndex()
+ {
+ return $this->getViewState('SelectedItemIndex',-1);
+ }
+
+ /**
+ * Selects an item by its index in {@link getItems Items}.
+ * Previously selected item will be un-selected.
+ * If the item to be selected is already in edit mode, it will remain in edit mode.
+ * If the index is less than 0, any existing selection will be cleared up.
+ * @param integer the selected item index
+ */
+ public function setSelectedItemIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ if(($current=$this->getSelectedItemIndex())!==$value)
+ {
+ $this->setViewState('SelectedItemIndex',$value,-1);
+ $items=$this->getItems();
+ $itemCount=$items->getCount();
+ if($current>=0 && $current<$itemCount)
+ {
+ $item=$items->itemAt($current);
+ if($item->getItemType()!==TListItemType::EditItem)
+ $item->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item);
+ }
+ if($value>=0 && $value<$itemCount)
+ {
+ $item=$items->itemAt($value);
+ if($item->getItemType()!==TListItemType::EditItem)
+ $item->setItemType(TListItemType::SelectedItem);
+ }
+ }
+ }
+
+ /**
+ * @return TDataGridItem the edit item
+ */
+ public function getEditItem()
+ {
+ $index=$this->getEditItemIndex();
+ $items=$this->getItems();
+ if($index>=0 && $index<$items->getCount())
+ return $items->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return integer the zero-based index of the edit item in {@link getItems Items}.
+ * A value -1 means no item is in edit mode.
+ */
+ public function getEditItemIndex()
+ {
+ return $this->getViewState('EditItemIndex',-1);
+ }
+
+ /**
+ * Edits an item by its index in {@link getItems Items}.
+ * Previously editting item will change to normal item state.
+ * If the index is less than 0, any existing edit item will be cleared up.
+ * @param integer the edit item index
+ */
+ public function setEditItemIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ if(($current=$this->getEditItemIndex())!==$value)
+ {
+ $this->setViewState('EditItemIndex',$value,-1);
+ $items=$this->getItems();
+ $itemCount=$items->getCount();
+ if($current>=0 && $current<$itemCount)
+ $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item);
+ if($value>=0 && $value<$itemCount)
+ $items->itemAt($value)->setItemType(TListItemType::EditItem);
+ }
+ }
+
+ /**
+ * @return boolean whether sorting is enabled. Defaults to false.
+ */
+ public function getAllowSorting()
+ {
+ return $this->getViewState('AllowSorting',false);
+ }
+
+ /**
+ * @param boolean whether sorting is enabled
+ */
+ public function setAllowSorting($value)
+ {
+ $this->setViewState('AllowSorting',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether datagrid columns should be automatically generated. Defaults to true.
+ */
+ public function getAutoGenerateColumns()
+ {
+ return $this->getViewState('AutoGenerateColumns',true);
+ }
+
+ /**
+ * @param boolean whether datagrid columns should be automatically generated
+ */
+ public function setAutoGenerateColumns($value)
+ {
+ $this->setViewState('AutoGenerateColumns',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the header should be displayed. Defaults to true.
+ */
+ public function getShowHeader()
+ {
+ return $this->getViewState('ShowHeader',true);
+ }
+
+ /**
+ * @param boolean whether the header should be displayed
+ */
+ public function setShowHeader($value)
+ {
+ $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the footer should be displayed. Defaults to false.
+ */
+ public function getShowFooter()
+ {
+ return $this->getViewState('ShowFooter',false);
+ }
+
+ /**
+ * @param boolean whether the footer should be displayed
+ */
+ public function setShowFooter($value)
+ {
+ $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return ITemplate the template applied when no data is bound to the datagrid
+ */
+ public function getEmptyTemplate()
+ {
+ return $this->_emptyTemplate;
+ }
+
+ /**
+ * @param ITemplate the template applied when no data is bound to the datagrid
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setEmptyTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_emptyTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datagrid_template_required','EmptyTemplate');
+ }
+
+ /**
+ * This method overrides parent's implementation to handle
+ * {@link onItemCommand OnItemCommand} event which is bubbled from
+ * {@link TDataGridItem} child controls.
+ * If the event parameter is {@link TDataGridCommandEventParameter} and
+ * the command name is a recognized one, which includes 'select', 'edit',
+ * 'delete', 'update', and 'cancel' (case-insensitive), then a
+ * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
+ * This method should only be used by control developers.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TDataGridCommandEventParameter)
+ {
+ $this->onItemCommand($param);
+ $command=$param->getCommandName();
+ if(strcasecmp($command,self::CMD_SELECT)===0)
+ {
+ $this->setSelectedItemIndex($param->getItem()->getItemIndex());
+ $this->onSelectedIndexChanged($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_EDIT)===0)
+ {
+ $this->onEditCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_DELETE)===0)
+ {
+ $this->onDeleteCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_UPDATE)===0)
+ {
+ $this->onUpdateCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_CANCEL)===0)
+ {
+ $this->onCancelCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_SORT)===0)
+ {
+ $this->onSortCommand(new TDataGridSortCommandEventParameter($sender,$param));
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_PAGE)===0)
+ {
+ $p=$param->getCommandParameter();
+ if(strcasecmp($p,self::CMD_PAGE_NEXT)===0)
+ $pageIndex=$this->getCurrentPageIndex()+1;
+ else if(strcasecmp($p,self::CMD_PAGE_PREV)===0)
+ $pageIndex=$this->getCurrentPageIndex()-1;
+ else if(strcasecmp($p,self::CMD_PAGE_FIRST)===0)
+ $pageIndex=0;
+ else if(strcasecmp($p,self::CMD_PAGE_LAST)===0)
+ $pageIndex=$this->getPageCount()-1;
+ else
+ $pageIndex=TPropertyValue::ensureInteger($p)-1;
+ $this->onPageIndexChanged(new TDataGridPageChangedEventParameter($sender,$pageIndex));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Raises <b>OnCancelCommand</b> event.
+ * This method is invoked when a button control raises <b>OnCommand</b> event
+ * with <b>cancel</b> command name.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onCancelCommand($param)
+ {
+ $this->raiseEvent('OnCancelCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnDeleteCommand</b> event.
+ * This method is invoked when a button control raises <b>OnCommand</b> event
+ * with <b>delete</b> command name.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onDeleteCommand($param)
+ {
+ $this->raiseEvent('OnDeleteCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnEditCommand</b> event.
+ * This method is invoked when a button control raises <b>OnCommand</b> event
+ * with <b>edit</b> command name.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onEditCommand($param)
+ {
+ $this->raiseEvent('OnEditCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnItemCommand</b> event.
+ * This method is invoked when a button control raises <b>OnCommand</b> event.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onItemCommand($param)
+ {
+ $this->raiseEvent('OnItemCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnSortCommand</b> event.
+ * This method is invoked when a button control raises <b>OnCommand</b> event
+ * with <b>sort</b> command name.
+ * @param TDataGridSortCommandEventParameter event parameter
+ */
+ public function onSortCommand($param)
+ {
+ $this->raiseEvent('OnSortCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnUpdateCommand</b> event.
+ * This method is invoked when a button control raises <b>OnCommand</b> event
+ * with <b>update</b> command name.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onUpdateCommand($param)
+ {
+ $this->raiseEvent('OnUpdateCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnItemCreated</b> event.
+ * This method is invoked right after a datagrid item is created and before
+ * added to page hierarchy.
+ * @param TDataGridItemEventParameter event parameter
+ */
+ public function onItemCreated($param)
+ {
+ $this->raiseEvent('OnItemCreated',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnPagerCreated</b> event.
+ * This method is invoked right after a datagrid pager is created and before
+ * added to page hierarchy.
+ * @param TDataGridPagerEventParameter event parameter
+ */
+ public function onPagerCreated($param)
+ {
+ $this->raiseEvent('OnPagerCreated',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnItemDataBound</b> event.
+ * This method is invoked for each datagrid item after it performs
+ * databinding.
+ * @param TDataGridItemEventParameter event parameter
+ */
+ public function onItemDataBound($param)
+ {
+ $this->raiseEvent('OnItemDataBound',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnPageIndexChanged</b> event.
+ * This method is invoked when current page is changed.
+ * @param TDataGridPageChangedEventParameter event parameter
+ */
+ public function onPageIndexChanged($param)
+ {
+ $this->raiseEvent('OnPageIndexChanged',$this,$param);
+ }
+
+ /**
+ * Saves item count in viewstate.
+ * This method is invoked right before control state is to be saved.
+ */
+ public function saveState()
+ {
+ parent::saveState();
+ if(!$this->getEnableViewState(true))
+ return;
+ if($this->_items)
+ $this->setViewState('ItemCount',$this->_items->getCount(),0);
+ else
+ $this->clearViewState('ItemCount');
+ if($this->_autoColumns)
+ {
+ $state=array();
+ foreach($this->_autoColumns as $column)
+ $state[]=$column->saveState();
+ $this->setViewState('AutoColumns',$state,array());
+ }
+ else
+ $this->clearViewState('AutoColumns');
+ if($this->_columns)
+ {
+ $state=array();
+ foreach($this->_columns as $column)
+ $state[]=$column->saveState();
+ $this->setViewState('Columns',$state,array());
+ }
+ else
+ $this->clearViewState('Columns');
+ }
+
+ /**
+ * Loads item count information from viewstate.
+ * This method is invoked right after control state is loaded.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ if(!$this->getEnableViewState(true))
+ return;
+ if(!$this->getIsDataBound())
+ {
+ $state=$this->getViewState('AutoColumns',array());
+ if(!empty($state))
+ {
+ $this->_autoColumns=new TDataGridColumnCollection($this);
+ foreach($state as $st)
+ {
+ $column=new $this->AutoGenerateColumnName;
+ $column->loadState($st);
+ $this->_autoColumns->add($column);
+ }
+ }
+ else
+ $this->_autoColumns=null;
+ $state=$this->getViewState('Columns',array());
+ if($this->_columns && $this->_columns->getCount()===count($state))
+ {
+ $i=0;
+ foreach($this->_columns as $column)
+ {
+ $column->loadState($state[$i]);
+ $i++;
+ }
+ }
+ $this->restoreGridFromViewState();
+ }
+ }
+
+ /**
+ * Clears up all items in the datagrid.
+ */
+ public function reset()
+ {
+ $this->getControls()->clear();
+ $this->getItems()->clear();
+ $this->_header=null;
+ $this->_footer=null;
+ $this->_topPager=null;
+ $this->_bottomPager=null;
+ $this->_useEmptyTemplate=false;
+ }
+
+ /**
+ * Restores datagrid content from viewstate.
+ */
+ protected function restoreGridFromViewState()
+ {
+ $this->reset();
+
+ $allowPaging=$this->getAllowPaging();
+
+ $itemCount=$this->getViewState('ItemCount',0);
+ $dsIndex=$this->getViewState('DataSourceIndex',0);
+
+ $columns=new TList($this->getColumns());
+ $columns->mergeWith($this->_autoColumns);
+ $this->_allColumns=$columns;
+
+ $items=$this->getItems();
+
+ if($columns->getCount())
+ {
+ foreach($columns as $column)
+ $column->initialize();
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+ for($index=0;$index<$itemCount;++$index)
+ {
+ if($index===0)
+ {
+ if($allowPaging)
+ $this->_topPager=$this->createPager();
+ $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,false,null,$columns);
+ }
+ if($index===$editIndex)
+ $itemType=TListItemType::EditItem;
+ else if($index===$selectedIndex)
+ $itemType=TListItemType::SelectedItem;
+ else if($index % 2)
+ $itemType=TListItemType::AlternatingItem;
+ else
+ $itemType=TListItemType::Item;
+ $items->add($this->createItemInternal($index,$dsIndex,$itemType,false,null,$columns));
+ $dsIndex++;
+ }
+ if($index>0)
+ {
+ $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,false,null,$columns);
+ if($allowPaging)
+ $this->_bottomPager=$this->createPager();
+ }
+ }
+ if(!$dsIndex && $this->_emptyTemplate!==null)
+ {
+ $this->_useEmptyTemplate=true;
+ $this->_emptyTemplate->instantiateIn($this);
+ }
+ }
+
+ /**
+ * Performs databinding to populate datagrid items from data source.
+ * This method is invoked by {@link dataBind()}.
+ * You may override this function to provide your own way of data population.
+ * @param Traversable the bound data
+ */
+ protected function performDataBinding($data)
+ {
+ $this->reset();
+ $keys=$this->getDataKeys();
+ $keys->clear();
+ $keyField=$this->getDataKeyField();
+
+ // get all columns
+ if($this->getAutoGenerateColumns())
+ {
+ $columns=new TList($this->getColumns());
+ $autoColumns=$this->createAutoColumns($data);
+ $columns->mergeWith($autoColumns);
+ }
+ else
+ $columns=$this->getColumns();
+ $this->_allColumns=$columns;
+
+ $items=$this->getItems();
+
+ $index=0;
+ $allowPaging=$this->getAllowPaging() && ($data instanceof TPagedDataSource);
+ $dsIndex=$allowPaging?$data->getFirstIndexInPage():0;
+ $this->setViewState('DataSourceIndex',$dsIndex,0);
+ if($columns->getCount())
+ {
+ foreach($columns as $column)
+ $column->initialize();
+
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+ foreach($data as $key=>$row)
+ {
+ if($keyField!=='')
+ $keys->add($this->getDataFieldValue($row,$keyField));
+ else
+ $keys->add($key);
+ if($index===0)
+ {
+ if($allowPaging)
+ $this->_topPager=$this->createPager();
+ $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,true,null,$columns);
+ }
+ if($index===$editIndex)
+ $itemType=TListItemType::EditItem;
+ else if($index===$selectedIndex)
+ $itemType=TListItemType::SelectedItem;
+ else if($index % 2)
+ $itemType=TListItemType::AlternatingItem;
+ else
+ $itemType=TListItemType::Item;
+ $items->add($this->createItemInternal($index,$dsIndex,$itemType,true,$row,$columns));
+ $index++;
+ $dsIndex++;
+ }
+ if($index>0)
+ {
+ $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,true,null,$columns);
+ if($allowPaging)
+ $this->_bottomPager=$this->createPager();
+ }
+ }
+ $this->setViewState('ItemCount',$index,0);
+ if(!$dsIndex && $this->_emptyTemplate!==null)
+ {
+ $this->_useEmptyTemplate=true;
+ $this->_emptyTemplate->instantiateIn($this);
+ $this->dataBindChildren();
+ }
+ }
+
+ /**
+ * Merges consecutive cells who have the same text.
+ * @since 3.1.1
+ */
+ private function groupCells()
+ {
+ if(($columns=$this->_allColumns)===null)
+ return;
+ $items=$this->getItems();
+ foreach($columns as $id=>$column)
+ {
+ if(!$column->getEnableCellGrouping())
+ continue;
+ $prevCell=null;
+ $prevCellText=null;
+ foreach($items as $item)
+ {
+ $itemType=$item->getItemType();
+ $cell=$item->getCells()->itemAt($id);
+ if(!$cell->getVisible())
+ continue;
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem)
+ {
+ if(($cellText=$this->getCellText($cell))==='')
+ {
+ $prevCell=null;
+ $prevCellText=null;
+ continue;
+ }
+ if($prevCell===null || $prevCellText!==$cellText)
+ {
+ $prevCell=$cell;
+ $prevCellText=$cellText;
+ }
+ else
+ {
+ if(($rowSpan=$prevCell->getRowSpan())===0)
+ $rowSpan=1;
+ $prevCell->setRowSpan($rowSpan+1);
+ $cell->setVisible(false);
+ }
+ }
+ }
+ }
+ }
+
+ private function getCellText($cell)
+ {
+ if(($data=$cell->getText())==='' && $cell->getHasControls())
+ {
+ $controls=$cell->getControls();
+ foreach($controls as $control)
+ {
+ if($control instanceof IDataRenderer)
+ return $control->getData();
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Creates a datagrid item instance based on the item type and index.
+ * @param integer zero-based item index
+ * @param TListItemType item type
+ * @return TDataGridItem created data list item
+ */
+ protected function createItem($itemIndex,$dataSourceIndex,$itemType)
+ {
+ return new TDataGridItem($itemIndex,$dataSourceIndex,$itemType);
+ }
+
+ private function createItemInternal($itemIndex,$dataSourceIndex,$itemType,$dataBind,$dataItem,$columns)
+ {
+ $item=$this->createItem($itemIndex,$dataSourceIndex,$itemType);
+ $this->initializeItem($item,$columns);
+ $param=new TDataGridItemEventParameter($item);
+ if($dataBind)
+ {
+ $item->setDataItem($dataItem);
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ $item->dataBind();
+ $this->onItemDataBound($param);
+ }
+ else
+ {
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ }
+ return $item;
+ }
+
+ /**
+ * Initializes a datagrid item and cells inside it
+ * @param TDataGrid datagrid item to be initialized
+ * @param TDataGridColumnCollection datagrid columns to be used to initialize the cells in the item
+ */
+ protected function initializeItem($item,$columns)
+ {
+ $cells=$item->getCells();
+ $itemType=$item->getItemType();
+ $index=0;
+ foreach($columns as $column)
+ {
+ if($itemType===TListItemType::Header)
+ $cell=new TTableHeaderCell;
+ else
+ $cell=new TTableCell;
+ if(($id=$column->getID())!=='')
+ $item->registerObject($id,$cell);
+ $cells->add($cell);
+ $column->initializeCell($cell,$index,$itemType);
+ $index++;
+ }
+ }
+
+ protected function createPager()
+ {
+ $pager=new TDataGridPager($this);
+ $this->buildPager($pager);
+ $this->onPagerCreated(new TDataGridPagerEventParameter($pager));
+ $this->getControls()->add($pager);
+ return $pager;
+ }
+
+ /**
+ * Builds the pager content based on pager style.
+ * @param TDataGridPager the container for the pager
+ */
+ protected function buildPager($pager)
+ {
+ switch($this->getPagerStyle()->getMode())
+ {
+ case TDataGridPagerMode::NextPrev:
+ $this->buildNextPrevPager($pager);
+ break;
+ case TDataGridPagerMode::Numeric:
+ $this->buildNumericPager($pager);
+ break;
+ }
+ }
+
+ /**
+ * Creates a pager button.
+ * Depending on the button type, a TLinkButton or a TButton may be created.
+ * If it is enabled (clickable), its command name and parameter will also be set.
+ * Derived classes may override this method to create additional types of buttons, such as TImageButton.
+ * @param mixed the container pager instance of TActiveDatagridPager
+ * @param string button type, either LinkButton or PushButton
+ * @param boolean whether the button should be enabled
+ * @param string caption of the button
+ * @param string CommandName corresponding to the OnCommand event of the button
+ * @param string CommandParameter corresponding to the OnCommand event of the button
+ * @return mixed the button instance
+ */
+ protected function createPagerButton($pager,$buttonType,$enabled,$text,$commandName,$commandParameter)
+ {
+ if($buttonType===TDataGridPagerButtonType::LinkButton)
+ {
+ if($enabled)
+ $button=new TLinkButton;
+ else
+ {
+ $button=new TLabel;
+ $button->setText($text);
+ return $button;
+ }
+ }
+ else
+ {
+ $button=new TButton;
+ if(!$enabled)
+ $button->setEnabled(false);
+ }
+ $button->setText($text);
+ $button->setCommandName($commandName);
+ $button->setCommandParameter($commandParameter);
+ $button->setCausesValidation(false);
+ return $button;
+ }
+
+ /**
+ * Builds a next-prev pager
+ * @param TDataGridPager the container for the pager
+ */
+ protected function buildNextPrevPager($pager)
+ {
+ $style=$this->getPagerStyle();
+ $buttonType=$style->getButtonType();
+ $controls=$pager->getControls();
+ $currentPageIndex=$this->getCurrentPageIndex();
+ if($currentPageIndex===0)
+ {
+ if(($text=$style->getFirstPageText())!=='')
+ {
+ $label=$this->createPagerButton($pager,$buttonType,false,$text,'','');
+ $controls->add($label);
+ $controls->add("\n");
+ }
+
+ $label=$this->createPagerButton($pager,$buttonType,false,$style->getPrevPageText(),'','');
+ $controls->add($label);
+ }
+ else
+ {
+ if(($text=$style->getFirstPageText())!=='')
+ {
+ $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST);
+ $controls->add($button);
+ $controls->add("\n");
+ }
+
+ $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,self::CMD_PAGE_PREV);
+ $controls->add($button);
+ }
+ $controls->add("\n");
+ if($currentPageIndex===$this->getPageCount()-1)
+ {
+ $label=$this->createPagerButton($pager,$buttonType,false,$style->getNextPageText(),'','');
+ $controls->add($label);
+ if(($text=$style->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $label=$this->createPagerButton($pager,$buttonType,false,$text,'','');
+ $controls->add($label);
+ }
+ }
+ else
+ {
+ $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,self::CMD_PAGE_NEXT);
+ $controls->add($button);
+ if(($text=$style->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST);
+ $controls->add($button);
+ }
+ }
+ }
+
+ /**
+ * Builds a numeric pager
+ * @param TDataGridPager the container for the pager
+ */
+ protected function buildNumericPager($pager)
+ {
+ $style=$this->getPagerStyle();
+ $buttonType=$style->getButtonType();
+ $controls=$pager->getControls();
+ $pageCount=$this->getPageCount();
+ $pageIndex=$this->getCurrentPageIndex()+1;
+ $maxButtonCount=$style->getPageButtonCount();
+ $buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount;
+ $startPageIndex=1;
+ $endPageIndex=$buttonCount;
+ if($pageIndex>$endPageIndex)
+ {
+ $startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1;
+ if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount)
+ $endPageIndex=$pageCount;
+ if($endPageIndex-$startPageIndex+1<$maxButtonCount)
+ {
+ if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1)
+ $startPageIndex=1;
+ }
+ }
+
+ if($startPageIndex>1)
+ {
+ if(($text=$style->getFirstPageText())!=='')
+ {
+ $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST);
+ $controls->add($button);
+ $controls->add("\n");
+ }
+ $prevPageIndex=$startPageIndex-1;
+ $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex");
+ $controls->add($button);
+ $controls->add("\n");
+ }
+
+ for($i=$startPageIndex;$i<=$endPageIndex;++$i)
+ {
+ if($i===$pageIndex)
+ {
+ $label=$this->createPagerButton($pager,$buttonType,false,"$i",'','');
+ $controls->add($label);
+ }
+ else
+ {
+ $button=$this->createPagerButton($pager,$buttonType,true,"$i",self::CMD_PAGE,"$i");
+ $controls->add($button);
+ }
+ if($i<$endPageIndex)
+ $controls->add("\n");
+ }
+
+ if($pageCount>$endPageIndex)
+ {
+ $controls->add("\n");
+ $nextPageIndex=$endPageIndex+1;
+ $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,"$nextPageIndex");
+ $controls->add($button);
+ if(($text=$style->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST);
+ $controls->add($button);
+ }
+ }
+ }
+
+ /**
+ * Automatically generates datagrid columns based on datasource schema
+ * @param Traversable data source bound to the datagrid
+ * @return TDataGridColumnCollection
+ */
+ protected function createAutoColumns($dataSource)
+ {
+ if(!$dataSource)
+ return null;
+ $autoColumns=$this->getAutoColumns();
+ $autoColumns->clear();
+ foreach($dataSource as $row)
+ {
+ foreach($row as $key=>$value)
+ {
+ $column=new $this->AutoGenerateColumnName;
+ if(is_string($key))
+ {
+ $column->setHeaderText($key);
+ $column->setDataField($key);
+ $column->setSortExpression($key);
+ $autoColumns->add($column);
+ }
+ else
+ {
+ $column->setHeaderText(TListItemType::Item);
+ $column->setDataField($key);
+ $column->setSortExpression(TListItemType::Item);
+ $autoColumns->add($column);
+ }
+ }
+ break;
+ }
+ return $autoColumns;
+ }
+
+ /**
+ * Applies styles to items, header, footer and separators.
+ * Item styles are applied in a hierarchical way. Style in higher hierarchy
+ * will inherit from styles in lower hierarchy.
+ * Starting from the lowest hierarchy, the item styles include
+ * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
+ * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
+ * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
+ * {@link getEditItemStyle EditItemStyle} will also have red background color
+ * unless it is set to a different value explicitly.
+ */
+ protected function applyItemStyles()
+ {
+ $itemStyle=$this->getViewState('ItemStyle',null);
+
+ $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null);
+ if($itemStyle!==null)
+ {
+ if($alternatingItemStyle===null)
+ $alternatingItemStyle=$itemStyle;
+ else
+ $alternatingItemStyle->mergeWith($itemStyle);
+ }
+
+ $selectedItemStyle=$this->getViewState('SelectedItemStyle',null);
+
+ $editItemStyle=$this->getViewState('EditItemStyle',null);
+ if($selectedItemStyle!==null)
+ {
+ if($editItemStyle===null)
+ $editItemStyle=$selectedItemStyle;
+ else
+ $editItemStyle->mergeWith($selectedItemStyle);
+ }
+
+ $headerStyle=$this->getViewState('HeaderStyle',null);
+ $footerStyle=$this->getViewState('FooterStyle',null);
+ $pagerStyle=$this->getViewState('PagerStyle',null);
+ $separatorStyle=$this->getViewState('SeparatorStyle',null);
+
+ foreach($this->getControls() as $index=>$item)
+ {
+ if(!($item instanceof TDataGridItem) && !($item instanceof TDataGridPager))
+ continue;
+ $itemType=$item->getItemType();
+ switch($itemType)
+ {
+ case TListItemType::Header:
+ if($headerStyle)
+ $item->getStyle()->mergeWith($headerStyle);
+ if(!$this->getShowHeader())
+ $item->setVisible(false);
+ break;
+ case TListItemType::Footer:
+ if($footerStyle)
+ $item->getStyle()->mergeWith($footerStyle);
+ if(!$this->getShowFooter())
+ $item->setVisible(false);
+ break;
+ case TListItemType::Separator:
+ if($separatorStyle)
+ $item->getStyle()->mergeWith($separatorStyle);
+ break;
+ case TListItemType::Item:
+ if($itemStyle)
+ $item->getStyle()->mergeWith($itemStyle);
+ break;
+ case TListItemType::AlternatingItem:
+ if($alternatingItemStyle)
+ $item->getStyle()->mergeWith($alternatingItemStyle);
+ break;
+ case TListItemType::SelectedItem:
+ if($selectedItemStyle)
+ $item->getStyle()->mergeWith($selectedItemStyle);
+ if($index % 2==1)
+ {
+ if($itemStyle)
+ $item->getStyle()->mergeWith($itemStyle);
+ }
+ else
+ {
+ if($alternatingItemStyle)
+ $item->getStyle()->mergeWith($alternatingItemStyle);
+ }
+ break;
+ case TListItemType::EditItem:
+ if($editItemStyle)
+ $item->getStyle()->mergeWith($editItemStyle);
+ if($index % 2==1)
+ {
+ if($itemStyle)
+ $item->getStyle()->mergeWith($itemStyle);
+ }
+ else
+ {
+ if($alternatingItemStyle)
+ $item->getStyle()->mergeWith($alternatingItemStyle);
+ }
+ break;
+ case TListItemType::Pager:
+ if($pagerStyle)
+ {
+ $item->getStyle()->mergeWith($pagerStyle);
+ if($index===0)
+ {
+ if($pagerStyle->getPosition()===TDataGridPagerPosition::Bottom || !$pagerStyle->getVisible())
+ $item->setVisible(false);
+ }
+ else
+ {
+ if($pagerStyle->getPosition()===TDataGridPagerPosition::Top || !$pagerStyle->getVisible())
+ $item->setVisible(false);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ if($this->_columns && $itemType!==TListItemType::Pager)
+ {
+ $n=$this->_columns->getCount();
+ $cells=$item->getCells();
+ for($i=0;$i<$n;++$i)
+ {
+ $cell=$cells->itemAt($i);
+ $column=$this->_columns->itemAt($i);
+ if(!$column->getVisible())
+ $cell->setVisible(false);
+ else
+ {
+ if($itemType===TListItemType::Header)
+ $style=$column->getHeaderStyle(false);
+ else if($itemType===TListItemType::Footer)
+ $style=$column->getFooterStyle(false);
+ else
+ $style=$column->getItemStyle(false);
+ if($style!==null)
+ $cell->getStyle()->mergeWith($style);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Renders the openning tag for the datagrid control which will render table caption if present.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderBeginTag($writer)
+ {
+ parent::renderBeginTag($writer);
+ if(($caption=$this->getCaption())!=='')
+ {
+ if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet)
+ $writer->addAttribute('align',strtolower($align));
+ $writer->renderBeginTag('caption');
+ $writer->write($caption);
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Renders the datagrid.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->getHasControls())
+ {
+ $this->groupCells();
+ if($this->_useEmptyTemplate)
+ {
+ $control=new TWebControl;
+ $control->setID($this->getClientID());
+ $control->copyBaseAttributes($this);
+ if($this->getHasStyle())
+ $control->getStyle()->copyFrom($this->getStyle());
+ $control->renderBeginTag($writer);
+ $this->renderContents($writer);
+ $control->renderEndTag($writer);
+ }
+ else if($this->getViewState('ItemCount',0)>0)
+ {
+ $this->applyItemStyles();
+ if($this->_topPager)
+ {
+ $this->_topPager->renderControl($writer);
+ $writer->writeLine();
+ }
+ $this->renderTable($writer);
+ if($this->_bottomPager)
+ {
+ $writer->writeLine();
+ $this->_bottomPager->renderControl($writer);
+ }
+ }
+ }
+ }
+
+ /**
+ * Renders the tabular data.
+ * @param THtmlWriter writer
+ */
+ protected function renderTable($writer)
+ {
+ $this->renderBeginTag($writer);
+ if($this->_header && $this->_header->getVisible())
+ {
+ $writer->writeLine();
+ if($style=$this->getViewState('TableHeadStyle',null))
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('thead');
+ $this->_header->render($writer);
+ $writer->renderEndTag();
+ }
+ $writer->writeLine();
+ if($style=$this->getViewState('TableBodyStyle',null))
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('tbody');
+ foreach($this->getItems() as $item)
+ $item->renderControl($writer);
+ $writer->renderEndTag();
+
+ if($this->_footer && $this->_footer->getVisible())
+ {
+ $writer->writeLine();
+ if($style=$this->getViewState('TableFootStyle',null))
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('tfoot');
+ $this->_footer->render($writer);
+ $writer->renderEndTag();
+ }
+
+ $writer->writeLine();
+ $this->renderEndTag($writer);
+ }
+}
+
+/**
+ * TDataGridItemEventParameter class
+ *
+ * TDataGridItemEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onItemCreated OnItemCreated} event of {@link TDataGrid} controls.
+ * The {@link getItem Item} property indicates the datagrid item related with the event.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridItemEventParameter extends TEventParameter
+{
+ /**
+ * The TDataGridItem control responsible for the event.
+ * @var TDataGridItem
+ */
+ private $_item=null;
+
+ /**
+ * Constructor.
+ * @param TDataGridItem datagrid item related with the corresponding event
+ */
+ public function __construct(TDataGridItem $item)
+ {
+ $this->_item=$item;
+ }
+
+ /**
+ * @return TDataGridItem datagrid item related with the corresponding event
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+}
+
+/**
+ * TDataGridPagerEventParameter class
+ *
+ * TDataGridPagerEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onPagerCreated OnPagerCreated} event of {@link TDataGrid} controls.
+ * The {@link getPager Pager} property indicates the datagrid pager related with the event.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridPagerEventParameter extends TEventParameter
+{
+ /**
+ * The TDataGridPager control responsible for the event.
+ * @var TDataGridPager
+ */
+ protected $_pager=null;
+
+ /**
+ * Constructor.
+ * @param TDataGridPager datagrid pager related with the corresponding event
+ */
+ public function __construct(TDataGridPager $pager)
+ {
+ $this->_pager=$pager;
+ }
+
+ /**
+ * @return TDataGridPager datagrid pager related with the corresponding event
+ */
+ public function getPager()
+ {
+ return $this->_pager;
+ }
+}
+
+/**
+ * TDataGridCommandEventParameter class
+ *
+ * TDataGridCommandEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onItemCommand ItemCommand} event of {@link TDataGrid} controls.
+ *
+ * The {@link getItem Item} property indicates the datagrid item related with the event.
+ * The {@link getCommandSource CommandSource} refers to the control that originally
+ * raises the Command event.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridCommandEventParameter extends TCommandEventParameter
+{
+ /**
+ * @var TDataGridItem the TDataGridItem control responsible for the event.
+ */
+ private $_item=null;
+ /**
+ * @var TControl the control originally raises the <b>Command</b> event.
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TDataGridItem datagrid item responsible for the event
+ * @param TControl original event sender
+ * @param TCommandEventParameter original event parameter
+ */
+ public function __construct($item,$source,TCommandEventParameter $param)
+ {
+ $this->_item=$item;
+ $this->_source=$source;
+ parent::__construct($param->getCommandName(),$param->getCommandParameter());
+ }
+
+ /**
+ * @return TDataGridItem the TDataGridItem control responsible for the event.
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+
+ /**
+ * @return TControl the control originally raises the <b>Command</b> event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+}
+
+/**
+ * TDataGridSortCommandEventParameter class
+ *
+ * TDataGridSortCommandEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onSortCommand SortCommand} event of {@link TDataGrid} controls.
+ *
+ * The {@link getCommandSource CommandSource} property refers to the control
+ * that originally raises the OnCommand event, while {@link getSortExpression SortExpression}
+ * gives the sort expression carried with the sort command.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridSortCommandEventParameter extends TEventParameter
+{
+ /**
+ * @var string sort expression
+ */
+ private $_sortExpression='';
+ /**
+ * @var TControl original event sender
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TControl the control originally raises the <b>OnCommand</b> event.
+ * @param TDataGridCommandEventParameter command event parameter
+ */
+ public function __construct($source,TDataGridCommandEventParameter $param)
+ {
+ $this->_source=$source;
+ $this->_sortExpression=$param->getCommandParameter();
+ }
+
+ /**
+ * @return TControl the control originally raises the <b>OnCommand</b> event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+
+ /**
+ * @return string sort expression
+ */
+ public function getSortExpression()
+ {
+ return $this->_sortExpression;
+ }
+}
+
+/**
+ * TDataGridPageChangedEventParameter class
+ *
+ * TDataGridPageChangedEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onPageIndexChanged PageIndexChanged} event of {@link TDataGrid} controls.
+ *
+ * The {@link getCommandSource CommandSource} property refers to the control
+ * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex}
+ * returns the new page index carried with the page command.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridPageChangedEventParameter extends TEventParameter
+{
+ /**
+ * @var integer new page index
+ */
+ private $_newIndex;
+ /**
+ * @var TControl original event sender
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TControl the control originally raises the <b>OnCommand</b> event.
+ * @param integer new page index
+ */
+ public function __construct($source,$newPageIndex)
+ {
+ $this->_source=$source;
+ $this->_newIndex=$newPageIndex;
+ }
+
+ /**
+ * @return TControl the control originally raises the <b>OnCommand</b> event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+
+ /**
+ * @return integer new page index
+ */
+ public function getNewPageIndex()
+ {
+ return $this->_newIndex;
+ }
+}
+
+/**
+ * TDataGridItem class
+ *
+ * A TDataGridItem control represents an item in the {@link TDataGrid} control,
+ * such as heading section, footer section, or a data item.
+ * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
+ * and {@link getDataItem DataItem} properties, respectively. The type of the item
+ * is given by {@link getItemType ItemType} property. Property {@link getDataSourceIndex DataSourceIndex}
+ * gives the index of the item from the bound data source.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridItem extends TTableRow implements INamingContainer
+{
+ /**
+ * @var integer index of the data item in the Items collection of datagrid
+ */
+ private $_itemIndex='';
+ /**
+ * @var integer index of the item from the bound data source
+ */
+ private $_dataSourceIndex=0;
+ /**
+ * type of the TDataGridItem
+ * @var string
+ */
+ private $_itemType='';
+ /**
+ * value of the data item
+ * @var mixed
+ */
+ private $_data=null;
+
+ /**
+ * Constructor.
+ * @param integer zero-based index of the item in the item collection of datagrid
+ * @param TListItemType item type
+ */
+ public function __construct($itemIndex,$dataSourceIndex,$itemType)
+ {
+ $this->_itemIndex=$itemIndex;
+ $this->_dataSourceIndex=$dataSourceIndex;
+ $this->setItemType($itemType);
+ if($itemType===TListItemType::Header)
+ $this->setTableSection(TTableRowSection::Header);
+ else if($itemType===TListItemType::Footer)
+ $this->setTableSection(TTableRowSection::Footer);
+ }
+
+ /**
+ * @return TListItemType item type.
+ */
+ public function getItemType()
+ {
+ return $this->_itemType;
+ }
+
+ /**
+ * @param TListItemType item type
+ */
+ public function setItemType($value)
+ {
+ $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
+ }
+
+ /**
+ * @return integer zero-based index of the item in the item collection of datagrid
+ */
+ public function getItemIndex()
+ {
+ return $this->_itemIndex;
+ }
+
+ /**
+ * @return integer the index of the datagrid item from the bound data source
+ */
+ public function getDataSourceIndex()
+ {
+ return $this->_dataSourceIndex;
+ }
+
+ /**
+ * @return mixed data associated with the item
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * @param mixed data to be associated with the item
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->_data=$value;
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @return mixed data associated with the item
+ * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
+ */
+ public function getDataItem()
+ {
+ return $this->getData();
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @param mixed data to be associated with the item
+ * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
+ */
+ public function setDataItem($value)
+ {
+ return $this->setData($value);
+ }
+
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for <b>OnCommand</b> event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+
+/**
+ * TDataGridPager class.
+ *
+ * TDataGridPager represents a datagrid pager.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridPager extends TPanel implements INamingContainer
+{
+ private $_dataGrid;
+
+ /**
+ * Constructor.
+ * @param TDataGrid datagrid object
+ */
+ public function __construct($dataGrid)
+ {
+ $this->_dataGrid=$dataGrid;
+ }
+
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for <b>OnCommand</b> event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * @return TDataGrid the datagrid owning this pager
+ */
+ public function getDataGrid()
+ {
+ return $this->_dataGrid;
+ }
+
+ /**
+ * @return string item type.
+ */
+ public function getItemType()
+ {
+ return TListItemType::Pager;
+ }
+}
+
+
+/**
+ * TDataGridItemCollection class.
+ *
+ * TDataGridItemCollection represents a collection of data grid items.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridItemCollection extends TList
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by inserting only TDataGridItem.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridItem.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TDataGridItem)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('datagriditemcollection_datagriditem_required');
+ }
+}
+
+/**
+ * TDataGridColumnCollection class.
+ *
+ * TDataGridColumnCollection represents a collection of data grid columns.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridColumnCollection extends TList
+{
+ /**
+ * the control that owns this collection.
+ * @var TControl
+ */
+ private $_o;
+
+ /**
+ * Constructor.
+ * @param TDataGrid the control that owns this collection.
+ */
+ public function __construct(TDataGrid $owner)
+ {
+ $this->_o=$owner;
+ }
+
+ /**
+ * @return TDataGrid the control that owns this collection.
+ */
+ protected function getOwner()
+ {
+ return $this->_o;
+ }
+
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by inserting only TDataGridColumn.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridColumn.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TDataGridColumn)
+ {
+ $item->setOwner($this->_o);
+ parent::insertAt($index,$item);
+ }
+ else
+ throw new TInvalidDataTypeException('datagridcolumncollection_datagridcolumn_required');
+ }
+}
+
+/**
+ * TDataGridPagerMode class.
+ * TDataGridPagerMode defines the enumerable type for the possible modes that a datagrid pager can take.
+ *
+ * The following enumerable values are defined:
+ * - NextPrev: pager buttons are displayed as next and previous pages
+ * - Numeric: pager buttons are displayed as numeric page numbers
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDataGridPagerMode extends TEnumerable
+{
+ const NextPrev='NextPrev';
+ const Numeric='Numeric';
+}
+
+
+/**
+ * TDataGridPagerButtonType class.
+ * TDataGridPagerButtonType defines the enumerable type for the possible types of datagrid pager buttons.
+ *
+ * The following enumerable values are defined:
+ * - LinkButton: link buttons
+ * - PushButton: form submit buttons
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDataGridPagerButtonType extends TEnumerable
+{
+ const LinkButton='LinkButton';
+ const PushButton='PushButton';
+}
+
+
+/**
+ * TDataGridPagerPosition class.
+ * TDataGridPagerPosition defines the enumerable type for the possible positions that a datagrid pager can be located at.
+ *
+ * The following enumerable values are defined:
+ * - Bottom: pager appears only at the bottom of the data grid.
+ * - Top: pager appears only at the top of the data grid.
+ * - TopAndBottom: pager appears on both top and bottom of the data grid.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDataGridPagerPosition extends TEnumerable
+{
+ const Bottom='Bottom';
+ const Top='Top';
+ const TopAndBottom='TopAndBottom';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TDataGridColumn.php b/lib/prado/framework/Web/UI/WebControls/TDataGridColumn.php
new file mode 100644
index 0000000..2f547ff
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TDataGridColumn.php
@@ -0,0 +1,564 @@
+<?php
+/**
+ * TDataGridColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Util.TDataFieldAccessor');
+Prado::using('System.Web.UI.WebControls.TDataGrid');
+
+/**
+ * TDataGridColumn class
+ *
+ * TDataGridColumn serves as the base class for the different column types of
+ * the {@link TDataGrid} control.
+ * TDataGridColumn defines the properties and methods that are common among
+ * all datagrid column types. In particular, it initializes header and footer
+ * cells according to {@link setHeaderText HeaderText} and {@link getHeaderStyle HeaderStyle}
+ * {@link setFooterText FooterText} and {@link getFooterStyle FooterStyle} properties.
+ * If {@link setHeaderImageUrl HeaderImageUrl} is specified, the image
+ * will be displayed instead in the header cell.
+ * The {@link getItemStyle ItemStyle} is applied to cells that belong to
+ * non-header and -footer datagrid items.
+ *
+ * When the datagrid enables sorting, if the {@link setSortExpression SortExpression}
+ * is not empty, the header cell will display a button (linkbutton or imagebutton)
+ * that will bubble the sort command event to the datagrid.
+ *
+ * Since v3.1.0, TDataGridColumn has introduced two new properties {@link setHeaderRenderer HeaderRenderer}
+ * and {@link setFooterRenderer FooterRenderer} which can be used to specify
+ * the layout of header and footer column cells.
+ * A renderer refers to a control class that is to be instantiated as a control.
+ * For more details, see {@link TRepeater} and {@link TDataList}.
+ *
+ * Since v3.1.1, TDataGridColumn has introduced {@link setEnableCellGrouping EnableCellGrouping}.
+ * If a column has this property set true, consecutive cells having the same content in this
+ * column will be grouped into one cell.
+ * Note, there are some limitations to cell grouping. We determine the cell content according to
+ * the cell's {@link TTableCell::getText Text} property. If the text is empty and the cell has
+ * some child controls, we will pick up the first control who implements {@link IDataRenderer}
+ * and obtain its {@link IDataRenderer::getData Data} property.
+ *
+ * The following datagrid column types are provided by the framework currently,
+ * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data.
+ * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons
+ * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state
+ * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource.
+ * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource.
+ * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource.
+ * - {@link TTemplateColumn}, displaying content based on templates.
+ *
+ * To create your own column class, simply override {@link initializeCell()} method,
+ * which is the major logic for managing the data and presentation of cells in the column.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TDataGridColumn extends TApplicationComponent
+{
+ private $_id='';
+ private $_owner=null;
+ private $_viewState=array();
+
+ /**
+ * @return string the ID of the column.
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * Sets the ID of the column.
+ * By explicitly specifying the column ID, one can access the column
+ * by $templateControl->ColumnID.
+ * @param string the ID of the column.
+ * @throws TInvalidDataValueException if the ID is of bad format
+ */
+ public function setID($value)
+ {
+ if(!preg_match(TControl::ID_FORMAT,$value))
+ throw new TInvalidDataValueException('datagridcolumn_id_invalid',get_class($this),$value);
+ $this->_id=$value;
+ }
+
+ /**
+ * @return string the text to be displayed in the header of this column
+ */
+ public function getHeaderText()
+ {
+ return $this->getViewState('HeaderText','');
+ }
+
+ /**
+ * @param string text to be displayed in the header of this column
+ */
+ public function setHeaderText($value)
+ {
+ $this->setViewState('HeaderText',$value,'');
+ }
+
+ /**
+ * @return string the url of the image to be displayed in header
+ */
+ public function getHeaderImageUrl()
+ {
+ return $this->getViewState('HeaderImageUrl','');
+ }
+
+ /**
+ * @param string the url of the image to be displayed in header
+ */
+ public function setHeaderImageUrl($value)
+ {
+ $this->setViewState('HeaderImageUrl',$value,'');
+ }
+
+ /**
+ * @return string the class name for the column header cell renderer. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getHeaderRenderer()
+ {
+ return $this->getViewState('HeaderRenderer','');
+ }
+
+ /**
+ * Sets the column header cell renderer class.
+ *
+ * If not empty, the class will be used to instantiate as a child control in the column header cell.
+ * If the class implements {@link IDataRenderer}, the <b>Data</b> property
+ * will be set as the {@link getFooterText FooterText}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @since 3.1.0
+ */
+ public function setHeaderRenderer($value)
+ {
+ $this->setViewState('HeaderRenderer',$value,'');
+ }
+
+ /**
+ * @param boolean whether to create a style if previously not existing
+ * @return TTableItemStyle the style for header
+ */
+ public function getHeaderStyle($createStyle=true)
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))===null && $createStyle)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('HeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string the text to be displayed in the footer of this column
+ */
+ public function getFooterText()
+ {
+ return $this->getViewState('FooterText','');
+ }
+
+ /**
+ * @param string text to be displayed in the footer of this column
+ */
+ public function setFooterText($value)
+ {
+ $this->setViewState('FooterText',$value,'');
+ }
+
+ /**
+ * @return string the class name for the column footer cell renderer. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getFooterRenderer()
+ {
+ return $this->getViewState('FooterRenderer','');
+ }
+
+ /**
+ * Sets the column footer cell renderer class.
+ *
+ * If not empty, the class will be used to instantiate as a child control in the column footer cell.
+ * If the class implements {@link IDataRenderer}, the <b>Data</b> property
+ * will be set as the {@link getFooterText FooterText}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @since 3.1.0
+ */
+ public function setFooterRenderer($value)
+ {
+ $this->setViewState('FooterRenderer',$value,'');
+ }
+
+ /**
+ * @param boolean whether to create a style if previously not existing
+ * @return TTableItemStyle the style for footer
+ */
+ public function getFooterStyle($createStyle=true)
+ {
+ if(($style=$this->getViewState('FooterStyle',null))===null && $createStyle)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('FooterStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @param boolean whether to create a style if previously not existing
+ * @return TTableItemStyle the style for item
+ */
+ public function getItemStyle($createStyle=true)
+ {
+ if(($style=$this->getViewState('ItemStyle',null))===null && $createStyle)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('ItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string the name of the field or expression for sorting
+ */
+ public function getSortExpression()
+ {
+ return $this->getViewState('SortExpression','');
+ }
+
+ /**
+ * @param string the name of the field or expression for sorting
+ */
+ public function setSortExpression($value)
+ {
+ $this->setViewState('SortExpression',$value,'');
+ }
+
+ /**
+ * @return boolean whether cells having the same content should be grouped together. Defaults to false.
+ * @since 3.1.1
+ */
+ public function getEnableCellGrouping()
+ {
+ return $this->getViewState('EnableCellGrouping',false);
+ }
+
+ /**
+ * @param boolean whether cells having the same content should be grouped together.
+ * @since 3.1.1
+ */
+ public function setEnableCellGrouping($value)
+ {
+ $this->setViewState('EnableCellGrouping',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether the column is visible. Defaults to true.
+ */
+ public function getVisible($checkParents=true)
+ {
+ return $this->getViewState('Visible',true);
+ }
+
+ /**
+ * @param boolean whether the column is visible
+ */
+ public function setVisible($value)
+ {
+ $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Returns a viewstate value.
+ *
+ * @param string the name of the viewstate value to be returned
+ * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
+ * @return mixed the viewstate value corresponding to $key
+ */
+ protected function getViewState($key,$defaultValue=null)
+ {
+ return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue;
+ }
+
+ /**
+ * Sets a viewstate value.
+ *
+ * Make sure that the viewstate value must be serializable and unserializable.
+ * @param string the name of the viewstate value
+ * @param mixed the viewstate value to be set
+ * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
+ */
+ protected function setViewState($key,$value,$defaultValue=null)
+ {
+ if($value===$defaultValue)
+ unset($this->_viewState[$key]);
+ else
+ $this->_viewState[$key]=$value;
+ }
+
+ /**
+ * Loads persistent state values.
+ * @param mixed state values
+ */
+ public function loadState($state)
+ {
+ $this->_viewState=$state;
+ }
+
+ /**
+ * Saves persistent state values.
+ * @return mixed values to be saved
+ */
+ public function saveState()
+ {
+ return $this->_viewState;
+ }
+
+ /**
+ * @return TDataGrid datagrid that owns this column
+ */
+ public function getOwner()
+ {
+ return $this->_owner;
+ }
+
+ /**
+ * @param TDataGrid datagrid object that owns this column
+ */
+ public function setOwner(TDataGrid $value)
+ {
+ $this->_owner=$value;
+ }
+
+ /**
+ * Initializes the column.
+ * This method is invoked by {@link TDataGrid} when the column
+ * is about to be used to initialize datagrid items.
+ * Derived classes may override this method to do additional initialization.
+ */
+ public function initialize()
+ {
+ }
+
+ /**
+ * Fetches the value of the data at the specified field.
+ * If the data is an array, the field is used as an array key.
+ * If the data is an of {@link TMap}, {@link TList} or their derived class,
+ * the field is used as a key value.
+ * If the data is a component, the field is used as the name of a property.
+ * @param mixed data containing the field of value
+ * @param string the data field
+ * @return mixed data value at the specified field
+ * @throws TInvalidDataValueException if the data or the field is invalid.
+ */
+ protected function getDataFieldValue($data,$field)
+ {
+ return TDataFieldAccessor::getDataFieldValue($data,$field);
+ }
+
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * The default implementation sets the content of header and footer cells.
+ * If sorting is enabled by the grid and sort expression is specified in the column,
+ * the header cell will show a link/image button. Otherwise, the header/footer cell
+ * will only show static text/image.
+ * This method can be overriden to provide customized intialization to column cells.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Header)
+ $this->initializeHeaderCell($cell,$columnIndex);
+ else if($itemType===TListItemType::Footer)
+ $this->initializeFooterCell($cell,$columnIndex);
+ }
+
+ /**
+ * Returns a value indicating whether this column allows sorting.
+ * The column allows sorting only when {@link getSortExpression SortExpression}
+ * is not empty and the datagrid allows sorting.
+ * @return boolean whether this column allows sorting
+ */
+ public function getAllowSorting()
+ {
+ return $this->getSortExpression()!=='' && (!$this->_owner || $this->_owner->getAllowSorting());
+ }
+
+ /**
+ * Initializes the header cell.
+ *
+ * This method attempts to use {@link getHeaderRenderer HeaderRenderer} to
+ * instantiate the header cell. If that is not available, it will populate
+ * the cell with an image or a text string, depending on {@link getHeaderImageUrl HeaderImageUrl}
+ * and {@link getHeaderText HeaderText} property values.
+ *
+ * If the column allows sorting, image or text will be created as
+ * a button which issues <b>Sort</b> command upon user click.
+ *
+ * @param TTableCell the cell to be initialized
+ * @param integer the index to the Columns property that the cell resides in.
+ */
+ protected function initializeHeaderCell($cell,$columnIndex)
+ {
+ $text=$this->getHeaderText();
+
+ if(($classPath=$this->getHeaderRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ $cell->getControls()->add($control);
+ if($control instanceof IDataRenderer)
+ {
+ if($control instanceof IItemDataRenderer)
+ {
+ $item=$cell->getParent();
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $control->setData($text);
+ }
+ }
+ else if($this->getAllowSorting())
+ {
+ $sortExpression=$this->getSortExpression();
+ if(($url=$this->getHeaderImageUrl())!=='')
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton');
+ $button->setImageUrl($url);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ if($text!=='')
+ $button->setAlternateText($text);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else if($text!=='')
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton');
+ $button->setText($text);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else
+ $cell->setText('&nbsp;');
+ }
+ else
+ {
+ if(($url=$this->getHeaderImageUrl())!=='')
+ {
+ $image=Prado::createComponent('System.Web.UI.WebControls.TImage');
+ $image->setImageUrl($url);
+ if($text!=='')
+ $image->setAlternateText($text);
+ $cell->getControls()->add($image);
+ }
+ else if($text!=='')
+ $cell->setText($text);
+ else
+ $cell->setText('&nbsp;');
+ }
+ }
+
+ /**
+ * Initializes the footer cell.
+ *
+ * This method attempts to use {@link getFooterRenderer FooterRenderer} to
+ * instantiate the footer cell. If that is not available, it will populate
+ * the cell with a text string specified by {@link getFooterImageUrl FooterImageUrl}
+ *
+ * @param TTableCell the cell to be initialized
+ * @param integer the index to the Columns property that the cell resides in.
+ */
+ protected function initializeFooterCell($cell,$columnIndex)
+ {
+ $text=$this->getFooterText();
+ if(($classPath=$this->getFooterRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ $cell->getControls()->add($control);
+ if($control instanceof IDataRenderer)
+ {
+ if($control instanceof IItemDataRenderer)
+ {
+ $item=$cell->getParent();
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $control->setData($text);
+ }
+ }
+ else if($text!=='')
+ $cell->setText($text);
+ else
+ $cell->setText('&nbsp;');
+ }
+
+ /**
+ * Formats the text value according to a format string.
+ * If the format string is empty, the original value is converted into
+ * a string and returned.
+ * If the format string starts with '#', the string is treated as a PHP expression
+ * within which the token '{0}' is translated with the data value to be formated.
+ * Otherwise, the format string and the data value are passed
+ * as the first and second parameters in {@link sprintf}.
+ * @param string format string
+ * @param mixed the data to be formatted
+ * @return string the formatted result
+ */
+ protected function formatDataValue($formatString,$value)
+ {
+ if($formatString==='')
+ return TPropertyValue::ensureString($value);
+ else if($formatString[0]==='#')
+ {
+ $expression=strtr(substr($formatString,1),array('{0}'=>'$value'));
+ try
+ {
+ if(eval("\$result=$expression;")===false)
+ throw new Exception('');
+ return $result;
+ }
+ catch(Exception $e)
+ {
+ throw new TInvalidDataValueException('datagridcolumn_expression_invalid',get_class($this),$expression,$e->getMessage());
+ }
+ }
+ else
+ return sprintf($formatString,$value);
+ }
+}
+
+
+/**
+ * TButtonColumnType class.
+ * TButtonColumnType defines the enumerable type for the possible types of buttons
+ * that can be used in a {@link TButtonColumn}.
+ *
+ * The following enumerable values are defined:
+ * - LinkButton: link buttons
+ * - PushButton: form buttons
+ * - ImageButton: image buttons
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TButtonColumnType extends TEnumerable
+{
+ const LinkButton='LinkButton';
+ const PushButton='PushButton';
+ const ImageButton='ImageButton';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TDataGridItemRenderer.php b/lib/prado/framework/Web/UI/WebControls/TDataGridItemRenderer.php
new file mode 100644
index 0000000..23cf515
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TDataGridItemRenderer.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * TDataGridItemRenderer class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataGrid');
+Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
+
+/**
+ * TDataGridItemRenderer class
+ *
+ * TDataGridItemRenderer can be used as a convenient base class to
+ * define an item renderer class specific for {@link TDataGrid}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.0
+ */
+class TDataGridItemRenderer extends TItemDataRenderer
+{
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TDataGridPagerStyle.php b/lib/prado/framework/Web/UI/WebControls/TDataGridPagerStyle.php
new file mode 100644
index 0000000..b96d0cd
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TDataGridPagerStyle.php
@@ -0,0 +1,253 @@
+<?php
+/**
+ * TDataGridPagerStyle class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataGrid');
+
+/**
+ * TDataGridPagerStyle class.
+ *
+ * TDataGridPagerStyle specifies the styles available for a datagrid pager.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridPagerStyle extends TPanelStyle
+{
+ private $_mode=null;
+ private $_nextText=null;
+ private $_prevText=null;
+ private $_firstText=null;
+ private $_lastText=null;
+ private $_buttonCount=null;
+ private $_position=null;
+ private $_visible=null;
+ private $_buttonType=null;
+
+ /**
+ * @return TDataGridPagerMode pager mode. Defaults to TDataGridPagerMode::NextPrev.
+ */
+ public function getMode()
+ {
+ return $this->_mode===null?TDataGridPagerMode::NextPrev : $this->_mode;
+ }
+
+ /**
+ * @param TDataGridPagerMode pager mode.
+ */
+ public function setMode($value)
+ {
+ $this->_mode=TPropertyValue::ensureEnum($value,'TDataGridPagerMode');
+ }
+
+ /**
+ * @return TDataGridPagerButtonType the type of command button. Defaults to TDataGridPagerButtonType::LinkButton.
+ */
+ public function getButtonType()
+ {
+ return $this->_buttonType===null?TDataGridPagerButtonType::LinkButton:$this->_buttonType;
+ }
+
+ /**
+ * @param TDataGridPagerButtonType the type of command button
+ */
+ public function setButtonType($value)
+ {
+ $this->_buttonType=TPropertyValue::ensureEnum($value,'TDataGridPagerButtonType');
+ }
+
+ /**
+ * @return string text for the next page button. Defaults to '>'.
+ */
+ public function getNextPageText()
+ {
+ return $this->_nextText===null?'>':$this->_nextText;
+ }
+
+ /**
+ * @param string text for the next page button.
+ */
+ public function setNextPageText($value)
+ {
+ $this->_nextText=$value;
+ }
+
+ /**
+ * @return string text for the previous page button. Defaults to '<'.
+ */
+ public function getPrevPageText()
+ {
+ return $this->_prevText===null?'<':$this->_prevText;
+ }
+
+ /**
+ * @param string text for the previous page button.
+ */
+ public function setPrevPageText($value)
+ {
+ $this->_prevText=$value;
+ }
+
+ /**
+ * @return string text for the first page button. Defaults to '<<'.
+ */
+ public function getFirstPageText()
+ {
+ return $this->_firstText===null?'<<':$this->_firstText;
+ }
+
+ /**
+ * @param string text for the first page button.
+ */
+ public function setFirstPageText($value)
+ {
+ $this->_firstText=$value;
+ }
+
+ /**
+ * @return string text for the last page button. Defaults to '>>'.
+ */
+ public function getLastPageText()
+ {
+ return $this->_lastText===null?'>>':$this->_lastText;
+ }
+
+ /**
+ * @param string text for the last page button.
+ */
+ public function setLastPageText($value)
+ {
+ $this->_lastText=$value;
+ }
+
+ /**
+ * @return integer maximum number of pager buttons to be displayed. Defaults to 10.
+ */
+ public function getPageButtonCount()
+ {
+ return $this->_buttonCount===null?10:$this->_buttonCount;
+ }
+
+ /**
+ * @param integer maximum number of pager buttons to be displayed
+ * @throws TInvalidDataValueException if the value is less than 1.
+ */
+ public function setPageButtonCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<1)
+ throw new TInvalidDataValueException('datagridpagerstyle_pagebuttoncount_invalid');
+ $this->_buttonCount=$value;
+ }
+
+ /**
+ * @return TDataGridPagerPosition where the pager is to be displayed. Defaults to TDataGridPagerPosition::Bottom.
+ */
+ public function getPosition()
+ {
+ return $this->_position===null?TDataGridPagerPosition::Bottom:$this->_position;
+ }
+
+ /**
+ * @param TDataGridPagerPosition where the pager is to be displayed.
+ */
+ public function setPosition($value)
+ {
+ $this->_position=TPropertyValue::ensureEnum($value,'TDataGridPagerPosition');
+ }
+
+ /**
+ * @return boolean whether the pager is visible. Defaults to true.
+ */
+ public function getVisible()
+ {
+ return $this->_visible===null?true:$this->_visible;
+ }
+
+ /**
+ * @param boolean whether the pager is visible.
+ */
+ public function setVisible($value)
+ {
+ $this->_visible=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * Resets the style to the original empty state.
+ */
+ public function reset()
+ {
+ parent::reset();
+ $this->_visible=null;
+ $this->_position=null;
+ $this->_buttonCount=null;
+ $this->_prevText=null;
+ $this->_nextText=null;
+ $this->_mode=null;
+ $this->_buttonType=null;
+ }
+
+ /**
+ * Copies the fields in a new style to this style.
+ * If a style field is set in the new style, the corresponding field
+ * in this style will be overwritten.
+ * @param TStyle the new style
+ */
+ public function copyFrom($style)
+ {
+ parent::copyFrom($style);
+ if($style instanceof TDataGridPagerStyle)
+ {
+ if($style->_visible!==null)
+ $this->_visible=$style->_visible;
+ if($style->_position!==null)
+ $this->_position=$style->_position;
+ if($style->_buttonCount!==null)
+ $this->_buttonCount=$style->_buttonCount;
+ if($style->_prevText!==null)
+ $this->_prevText=$style->_prevText;
+ if($style->_nextText!==null)
+ $this->_nextText=$style->_nextText;
+ if($style->_mode!==null)
+ $this->_mode=$style->_mode;
+ if($style->_buttonType!==null)
+ $this->_buttonType=$style->_buttonType;
+ }
+ }
+
+ /**
+ * Merges the style with a new one.
+ * If a style field is not set in this style, it will be overwritten by
+ * the new one.
+ * @param TStyle the new style
+ */
+ public function mergeWith($style)
+ {
+ parent::mergeWith($style);
+ if($style instanceof TDataGridPagerStyle)
+ {
+ if($this->_visible===null)
+ $this->_visible=$style->_visible;
+ if($this->_position===null)
+ $this->_position=$style->_position;
+ if($this->_buttonCount===null)
+ $this->_buttonCount=$style->_buttonCount;
+ if($this->_prevText===null)
+ $this->_prevText=$style->_prevText;
+ if($this->_nextText===null)
+ $this->_nextText=$style->_nextText;
+ if($this->_mode===null)
+ $this->_mode=$style->_mode;
+ if($this->_buttonType===null)
+ $this->_buttonType=$style->_buttonType;
+ }
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TDataList.php b/lib/prado/framework/Web/UI/WebControls/TDataList.php
new file mode 100644
index 0000000..a3cf8b6
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TDataList.php
@@ -0,0 +1,1760 @@
+<?php
+/**
+ * TDataList class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TBaseDataList class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseDataList');
+/**
+ * Includes TRepeatInfo class
+ */
+Prado::using('System.Web.UI.WebControls.TRepeatInfo');
+
+/**
+ * TDataList class
+ *
+ * TDataList represents a data bound and updatable list control.
+ *
+ * Like {@link TRepeater}, TDataList displays its content repeatedly based on
+ * the data fetched from {@link setDataSource DataSource}.
+ * The repeated contents in TDataList are called items, which are controls and
+ * can be accessed through {@link getItems Items}. When {@link dataBind()} is
+ * invoked, TDataList creates an item for each row of data and binds the data
+ * row to the item. Optionally, a TDataList can have a header, a footer and/or
+ * separators between items.
+ *
+ * TDataList differs from {@link TRepeater} in that it supports tiling the items
+ * in different manners and it maintains status of items to handle data update.
+ *
+ * The layout of the repeated contents are specified by inline templates.
+ * TDataList items, header, footer, etc. are being instantiated with the corresponding
+ * templates when data is being bound to the repeater.
+ *
+ * Since v3.1.0, the layout can also be by renderers. A renderer is a control class
+ * that can be instantiated as datalist items, header, etc. A renderer can thus be viewed
+ * as an external template (in fact, it can also be non-templated controls).
+ *
+ * A renderer can be any control class.
+ * - If the class implements {@link IDataRenderer}, the <b>Data</b>
+ * property will be set as the data row during databinding. Many PRADO controls
+ * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc.
+ * - If the class implements {@link IItemDataRenderer}, the <b>ItemIndex</b> property will be set
+ * as the zero-based index of the item in the datalist item collection, and
+ * the <b>ItemType</b> property as the item's type (such as TListItemType::Item).
+ * {@link TDataListItemRenderer} may be used as the convenient base class which
+ * already implements {@link IDataItemRenderer}.
+ *
+ * The following properties are used to specify different types of template and renderer
+ * for a datalist:
+ * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}:
+ * for each repeated row of data
+ * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}:
+ * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer}
+ * will be used instead.
+ * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}:
+ * for the datalist header.
+ * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}:
+ * for the datalist footer.
+ * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}:
+ * for content to be displayed between items.
+ * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}:
+ * used when data bound to the datalist is empty.
+ * - {@link setEditItemTemplate EditItemTemplate}, {@link setEditItemRenderer EditItemRenderer}:
+ * for the row being editted.
+ * - {@link setSelectedItemTemplate SelectedItemTemplate}, {@link setSelectedItemRenderer SelectedItemRenderer}:
+ * for the row being selected.
+ *
+ * If a content type is defined with both a template and a renderer, the latter takes precedence.
+ *
+ * When {@link dataBind()} is being called, TDataList undergoes the following lifecycles for each row of data:
+ * - create item based on templates or renderers
+ * - set the row of data to the item
+ * - raise {@link onItemCreated OnItemCreated}:
+ * - add the item as a child control
+ * - call dataBind() of the item
+ * - raise {@link onItemDataBound OnItemDataBound}:
+ *
+ * TDataList raises an {@link onItemCommand OnItemCommand} whenever a button control
+ * within some datalist item raises a <b>OnCommand</b> event. Therefore,
+ * you can handle all sorts of <b>OnCommand</b> event in a central place by
+ * writing an event handler for {@link onItemCommand OnItemCommand}.
+ *
+ * An additional event is raised if the <b>OnCommand</b> event has one of the following
+ * command names:
+ * - edit: user wants to edit an item. <b>OnEditCommand</b> event will be raised.
+ * - update: user wants to save the change to an item. <b>OnUpdateCommand</b> event will be raised.
+ * - select: user selects an item. <b>OnSelectedIndexChanged</b> event will be raised.
+ * - delete: user deletes an item. <b>OnDeleteCommand</b> event will be raised.
+ * - cancel: user cancels previously editting action. <b>OnCancelCommand</b> event will be raised.
+ *
+ * TDataList provides a few properties to support tiling the items.
+ * The number of columns used to display the data items is specified via
+ * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
+ * governs the order of the items being rendered.
+ * The layout of the data items in the list is specified via {@link setRepeatLayout RepeatLayout},
+ * which can take one of the following values:
+ * - Table (default): items are organized using HTML table and cells.
+ * When using this layout, one can set {@link setCellPadding CellPadding} and
+ * {@link setCellSpacing CellSpacing} to adjust the cellpadding and cellpadding
+ * of the table, and {@link setCaption Caption} and {@link setCaptionAlign CaptionAlign}
+ * to add a table caption with the specified alignment.
+ * - Flow: items are organized using HTML spans and breaks.
+ * - Raw: TDataList does not generate any HTML tags to do the tiling.
+ *
+ * Items in TDataList can be in one of the three status: normal browsing,
+ * being editted and being selected. To change the status of a particular
+ * item, set {@link setSelectedItemIndex SelectedItemIndex} or
+ * {@link setEditItemIndex EditItemIndex}. The former will change
+ * the indicated item to selected mode, which will cause the item to
+ * use {@link setSelectedItemTemplate SelectedItemTemplate} or
+ * {@link setSelectedItemRenderer SelectedItemRenderer} for presentation.
+ * The latter will change the indicated item to edit mode and to use corresponding
+ * template or renderer.
+ * Note, if an item is in edit mode, then selecting this item will have no effect.
+ *
+ * Different styles may be applied to items in different status. The style
+ * application is performed in a hierarchical way: Style in higher hierarchy
+ * will inherit from styles in lower hierarchy.
+ * Starting from the lowest hierarchy, the item styles include
+ * - item's own style
+ * - {@link getItemStyle ItemStyle}
+ * - {@link getAlternatingItemStyle AlternatingItemStyle}
+ * - {@link getSelectedItemStyle SelectedItemStyle}
+ * - {@link getEditItemStyle EditItemStyle}.
+ * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
+ * {@link getEditItemStyle EditItemStyle} will also have red background color
+ * unless it is set to a different value explicitly.
+ *
+ * When a page containing a datalist is post back, the datalist will restore automatically
+ * all its contents, including items, header, footer and separators.
+ * However, the data row associated with each item will not be recovered and become null.
+ * To access the data, use one of the following ways:
+ * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
+ * the specified datalist item and use the key to fetch the corresponding data
+ * from some persistent storage such as DB.
+ * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback.
+ * Be aware though, if the size of your dataset is big, your page size will become big. Some
+ * complex data may also have serializing problem if saved in viewstate.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataList extends TBaseDataList implements INamingContainer, IRepeatInfoUser
+{
+ /**
+ * Command name that TDataList understands. They are case-insensitive.
+ */
+ const CMD_SELECT='Select';
+ const CMD_EDIT='Edit';
+ const CMD_UPDATE='Update';
+ const CMD_DELETE='Delete';
+ const CMD_CANCEL='Cancel';
+
+ /**
+ * @var TDataListItemCollection item list
+ */
+ private $_items=null;
+ /**
+ * @var Itemplate various item templates
+ */
+ private $_itemTemplate=null;
+ private $_emptyTemplate=null;
+ private $_alternatingItemTemplate=null;
+ private $_selectedItemTemplate=null;
+ private $_editItemTemplate=null;
+ private $_headerTemplate=null;
+ private $_footerTemplate=null;
+ private $_separatorTemplate=null;
+ /**
+ * @var TControl header item
+ */
+ private $_header=null;
+ /**
+ * @var TControl footer item
+ */
+ private $_footer=null;
+
+ /**
+ * @return TDataListItemCollection item list
+ */
+ public function getItems()
+ {
+ if(!$this->_items)
+ $this->_items=new TDataListItemCollection;
+ return $this->_items;
+ }
+
+ /**
+ * @return integer number of items
+ */
+ public function getItemCount()
+ {
+ return $this->_items?$this->_items->getCount():0;
+ }
+
+ /**
+ * @return string the class name for datalist items. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getItemRenderer()
+ {
+ return $this->getViewState('ItemRenderer','');
+ }
+
+ /**
+ * Sets the item renderer class.
+ *
+ * If not empty, the class will be used to instantiate as datalist items.
+ * This property takes precedence over {@link getItemTemplate ItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setItemTemplate
+ * @since 3.1.0
+ */
+ public function setItemRenderer($value)
+ {
+ $this->setViewState('ItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for alternative datalist items. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getAlternatingItemRenderer()
+ {
+ return $this->getViewState('AlternatingItemRenderer','');
+ }
+
+ /**
+ * Sets the alternative item renderer class.
+ *
+ * If not empty, the class will be used to instantiate as alternative datalist items.
+ * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setAlternatingItemTemplate
+ * @since 3.1.0
+ */
+ public function setAlternatingItemRenderer($value)
+ {
+ $this->setViewState('AlternatingItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for the datalist item being editted. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getEditItemRenderer()
+ {
+ return $this->getViewState('EditItemRenderer','');
+ }
+
+ /**
+ * Sets the renderer class for the datalist item being editted.
+ *
+ * If not empty, the class will be used to instantiate as the datalist item.
+ * This property takes precedence over {@link getEditItemTemplate EditItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setEditItemTemplate
+ * @since 3.1.0
+ */
+ public function setEditItemRenderer($value)
+ {
+ $this->setViewState('EditItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for the datalist item being selected. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getSelectedItemRenderer()
+ {
+ return $this->getViewState('SelectedItemRenderer','');
+ }
+
+ /**
+ * Sets the renderer class for the datalist item being selected.
+ *
+ * If not empty, the class will be used to instantiate as the datalist item.
+ * This property takes precedence over {@link getSelectedItemTemplate SelectedItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setSelectedItemTemplate
+ * @since 3.1.0
+ */
+ public function setSelectedItemRenderer($value)
+ {
+ $this->setViewState('SelectedItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for datalist item separators. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getSeparatorRenderer()
+ {
+ return $this->getViewState('SeparatorRenderer','');
+ }
+
+ /**
+ * Sets the datalist item separator renderer class.
+ *
+ * If not empty, the class will be used to instantiate as datalist item separators.
+ * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setSeparatorTemplate
+ * @since 3.1.0
+ */
+ public function setSeparatorRenderer($value)
+ {
+ $this->setViewState('SeparatorRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for datalist header item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getHeaderRenderer()
+ {
+ return $this->getViewState('HeaderRenderer','');
+ }
+
+ /**
+ * Sets the datalist header renderer class.
+ *
+ * If not empty, the class will be used to instantiate as datalist header item.
+ * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setHeaderTemplate
+ * @since 3.1.0
+ */
+ public function setHeaderRenderer($value)
+ {
+ $this->setViewState('HeaderRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for datalist footer item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getFooterRenderer()
+ {
+ return $this->getViewState('FooterRenderer','');
+ }
+
+ /**
+ * Sets the datalist footer renderer class.
+ *
+ * If not empty, the class will be used to instantiate as datalist footer item.
+ * This property takes precedence over {@link getFooterTemplate FooterTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setFooterTemplate
+ * @since 3.1.0
+ */
+ public function setFooterRenderer($value)
+ {
+ $this->setViewState('FooterRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for empty datalist item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getEmptyRenderer()
+ {
+ return $this->getViewState('EmptyRenderer','');
+ }
+
+ /**
+ * Sets the datalist empty renderer class.
+ *
+ * The empty renderer is created as the child of the datalist
+ * if data bound to the datalist is empty.
+ * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setEmptyTemplate
+ * @since 3.1.0
+ */
+ public function setEmptyRenderer($value)
+ {
+ $this->setViewState('EmptyRenderer',$value,'');
+ }
+
+ /**
+ * @return ITemplate the template for item
+ */
+ public function getItemTemplate()
+ {
+ return $this->_itemTemplate;
+ }
+
+ /**
+ * @param ITemplate the template for item
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_itemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','ItemTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for item
+ */
+ public function getItemStyle()
+ {
+ if(($style=$this->getViewState('ItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('ItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return ITemplate the template for each alternating item
+ */
+ public function getAlternatingItemTemplate()
+ {
+ return $this->_alternatingItemTemplate;
+ }
+
+ /**
+ * @param ITemplate the template for each alternating item
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setAlternatingItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_alternatingItemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','AlternatingItemType');
+ }
+
+ /**
+ * @return TTableItemStyle the style for each alternating item
+ */
+ public function getAlternatingItemStyle()
+ {
+ if(($style=$this->getViewState('AlternatingItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('AlternatingItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return ITemplate the selected item template
+ */
+ public function getSelectedItemTemplate()
+ {
+ return $this->_selectedItemTemplate;
+ }
+
+ /**
+ * @param ITemplate the selected item template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setSelectedItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_selectedItemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','SelectedItemTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for selected item
+ */
+ public function getSelectedItemStyle()
+ {
+ if(($style=$this->getViewState('SelectedItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('SelectedItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return ITemplate the edit item template
+ */
+ public function getEditItemTemplate()
+ {
+ return $this->_editItemTemplate;
+ }
+
+ /**
+ * @param ITemplate the edit item template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setEditItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_editItemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','EditItemTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for edit item
+ */
+ public function getEditItemStyle()
+ {
+ if(($style=$this->getViewState('EditItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('EditItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return ITemplate the header template
+ */
+ public function getHeaderTemplate()
+ {
+ return $this->_headerTemplate;
+ }
+
+ /**
+ * @param ITemplate the header template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setHeaderTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_headerTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','HeaderTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for header
+ */
+ public function getHeaderStyle()
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('HeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TControl the header item
+ */
+ public function getHeader()
+ {
+ return $this->_header;
+ }
+
+ /**
+ * @return ITemplate the footer template
+ */
+ public function getFooterTemplate()
+ {
+ return $this->_footerTemplate;
+ }
+
+ /**
+ * @param ITemplate the footer template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setFooterTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_footerTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','FooterTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for footer
+ */
+ public function getFooterStyle()
+ {
+ if(($style=$this->getViewState('FooterStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('FooterStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TControl the footer item
+ */
+ public function getFooter()
+ {
+ return $this->_footer;
+ }
+
+ /**
+ * @return ITemplate the template applied when no data is bound to the datalist
+ */
+ public function getEmptyTemplate()
+ {
+ return $this->_emptyTemplate;
+ }
+
+ /**
+ * @param ITemplate the template applied when no data is bound to the datalist
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setEmptyTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_emptyTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','EmptyTemplate');
+ }
+
+ /**
+ * @return ITemplate the separator template
+ */
+ public function getSeparatorTemplate()
+ {
+ return $this->_separatorTemplate;
+ }
+
+ /**
+ * @param ITemplate the separator template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setSeparatorTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_separatorTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','SeparatorTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for separator
+ */
+ public function getSeparatorStyle()
+ {
+ if(($style=$this->getViewState('SeparatorStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('SeparatorStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return integer the zero-based index of the selected item in {@link getItems Items}.
+ * A value -1 means no item selected.
+ */
+ public function getSelectedItemIndex()
+ {
+ return $this->getViewState('SelectedItemIndex',-1);
+ }
+
+ /**
+ * Selects an item by its index in {@link getItems Items}.
+ * Previously selected item will be un-selected.
+ * If the item to be selected is already in edit mode, it will remain in edit mode.
+ * If the index is less than 0, any existing selection will be cleared up.
+ * @param integer the selected item index
+ */
+ public function setSelectedItemIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ if(($current=$this->getSelectedItemIndex())!==$value)
+ {
+ $this->setViewState('SelectedItemIndex',$value,-1);
+ $items=$this->getItems();
+ $itemCount=$items->getCount();
+ if($current>=0 && $current<$itemCount)
+ {
+ $item=$items->itemAt($current);
+ if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem)
+ $item->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item);
+ }
+ if($value>=0 && $value<$itemCount)
+ {
+ $item=$items->itemAt($value);
+ if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem)
+ $item->setItemType(TListItemType::SelectedItem);
+ }
+ }
+ }
+
+ /**
+ * @return TControl the selected item, null if no item is selected.
+ */
+ public function getSelectedItem()
+ {
+ $index=$this->getSelectedItemIndex();
+ $items=$this->getItems();
+ if($index>=0 && $index<$items->getCount())
+ return $items->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return mixed the key value of the currently selected item
+ * @throws TInvalidOperationException if {@link getDataKeyField DataKeyField} is empty.
+ */
+ public function getSelectedDataKey()
+ {
+ if($this->getDataKeyField()==='')
+ throw new TInvalidOperationException('datalist_datakeyfield_required');
+ $index=$this->getSelectedItemIndex();
+ $dataKeys=$this->getDataKeys();
+ if($index>=0 && $index<$dataKeys->getCount())
+ return $dataKeys->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return integer the zero-based index of the edit item in {@link getItems Items}.
+ * A value -1 means no item is in edit mode.
+ */
+ public function getEditItemIndex()
+ {
+ return $this->getViewState('EditItemIndex',-1);
+ }
+
+ /**
+ * Edits an item by its index in {@link getItems Items}.
+ * Previously editting item will change to normal item state.
+ * If the index is less than 0, any existing edit item will be cleared up.
+ * @param integer the edit item index
+ */
+ public function setEditItemIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ if(($current=$this->getEditItemIndex())!==$value)
+ {
+ $this->setViewState('EditItemIndex',$value,-1);
+ $items=$this->getItems();
+ $itemCount=$items->getCount();
+ if($current>=0 && $current<$itemCount)
+ $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item);
+ if($value>=0 && $value<$itemCount)
+ $items->itemAt($value)->setItemType(TListItemType::EditItem);
+ }
+ }
+
+ /**
+ * @return TControl the edit item
+ */
+ public function getEditItem()
+ {
+ $index=$this->getEditItemIndex();
+ $items=$this->getItems();
+ if($index>=0 && $index<$items->getCount())
+ return $items->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return boolean whether the header should be shown. Defaults to true.
+ */
+ public function getShowHeader()
+ {
+ return $this->getViewState('ShowHeader',true);
+ }
+
+ /**
+ * @param boolean whether to show header
+ */
+ public function setShowHeader($value)
+ {
+ $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the footer should be shown. Defaults to true.
+ */
+ public function getShowFooter()
+ {
+ return $this->getViewState('ShowFooter',true);
+ }
+
+ /**
+ * @param boolean whether to show footer
+ */
+ public function setShowFooter($value)
+ {
+ $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return TRepeatInfo repeat information (primarily used by control developers)
+ */
+ protected function getRepeatInfo()
+ {
+ if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null)
+ {
+ $repeatInfo=new TRepeatInfo;
+ $this->setViewState('RepeatInfo',$repeatInfo,null);
+ }
+ return $repeatInfo;
+ }
+
+ /**
+ * @return string caption of the table layout
+ */
+ public function getCaption()
+ {
+ return $this->getRepeatInfo()->getCaption();
+ }
+
+ /**
+ * @param string caption of the table layout
+ */
+ public function setCaption($value)
+ {
+ $this->getRepeatInfo()->setCaption($value);
+ }
+
+ /**
+ * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet.
+ */
+ public function getCaptionAlign()
+ {
+ return $this->getRepeatInfo()->getCaptionAlign();
+ }
+
+ /**
+ * @return TTableCaptionAlign alignment of the caption of the table layout.
+ */
+ public function setCaptionAlign($value)
+ {
+ $this->getRepeatInfo()->setCaptionAlign($value);
+ }
+
+ /**
+ * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set.
+ */
+ public function getRepeatColumns()
+ {
+ return $this->getRepeatInfo()->getRepeatColumns();
+ }
+
+ /**
+ * @param integer the number of columns that the list should be displayed with.
+ */
+ public function setRepeatColumns($value)
+ {
+ $this->getRepeatInfo()->setRepeatColumns($value);
+ }
+
+ /**
+ * @return TRepeatDirection the direction of traversing the list, defaults to TRepeatDirection::Vertical
+ */
+ public function getRepeatDirection()
+ {
+ return $this->getRepeatInfo()->getRepeatDirection();
+ }
+
+ /**
+ * @param TRepeatDirection the direction of traversing the list
+ */
+ public function setRepeatDirection($value)
+ {
+ $this->getRepeatInfo()->setRepeatDirection($value);
+ }
+
+ /**
+ * @return TRepeatLayout how the list should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table.
+ */
+ public function getRepeatLayout()
+ {
+ return $this->getRepeatInfo()->getRepeatLayout();
+ }
+
+ /**
+ * @param TRepeatLayout how the list should be displayed, using table or using line breaks
+ */
+ public function setRepeatLayout($value)
+ {
+ $this->getRepeatInfo()->setRepeatLayout($value);
+ }
+
+ /**
+ * This method overrides parent's implementation to handle
+ * {@link onItemCommand OnItemCommand} event which is bubbled from
+ * datalist items and their child controls.
+ * If the event parameter is {@link TDataListCommandEventParameter} and
+ * the command name is a recognized one, which includes 'select', 'edit',
+ * 'delete', 'update', and 'cancel' (case-insensitive), then a
+ * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
+ * This method should only be used by control developers.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TDataListCommandEventParameter)
+ {
+ $this->onItemCommand($param);
+ $command=$param->getCommandName();
+ if(strcasecmp($command,self::CMD_SELECT)===0)
+ {
+ if(($item=$param->getItem()) instanceof IItemDataRenderer)
+ $this->setSelectedItemIndex($item->getItemIndex());
+ $this->onSelectedIndexChanged($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_EDIT)===0)
+ {
+ $this->onEditCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_DELETE)===0)
+ {
+ $this->onDeleteCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_UPDATE)===0)
+ {
+ $this->onUpdateCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_CANCEL)===0)
+ {
+ $this->onCancelCommand($param);
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * Raises <b>OnItemCreated</b> event.
+ * This method is invoked after a data list item is created and instantiated with
+ * template, but before added to the page hierarchy.
+ * The datalist item control responsible for the event
+ * can be determined from the event parameter.
+ * If you override this method, be sure to call parent's implementation
+ * so that event handlers have chance to respond to the event.
+ * @param TDataListItemEventParameter event parameter
+ */
+ public function onItemCreated($param)
+ {
+ $this->raiseEvent('OnItemCreated',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnItemDataBound</b> event.
+ * This method is invoked right after an item is data bound.
+ * The datalist item control responsible for the event
+ * can be determined from the event parameter.
+ * If you override this method, be sure to call parent's implementation
+ * so that event handlers have chance to respond to the event.
+ * @param TDataListItemEventParameter event parameter
+ */
+ public function onItemDataBound($param)
+ {
+ $this->raiseEvent('OnItemDataBound',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnItemCommand</b> event.
+ * This method is invoked when a child control of the data list
+ * raises an <b>OnCommand</b> event.
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onItemCommand($param)
+ {
+ $this->raiseEvent('OnItemCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnEditCommand</b> event.
+ * This method is invoked when a child control of the data list
+ * raises an <b>OnCommand</b> event and the command name is 'edit' (case-insensitive).
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onEditCommand($param)
+ {
+ $this->raiseEvent('OnEditCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnDeleteCommand</b> event.
+ * This method is invoked when a child control of the data list
+ * raises an <b>OnCommand</b> event and the command name is 'delete' (case-insensitive).
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onDeleteCommand($param)
+ {
+ $this->raiseEvent('OnDeleteCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnUpdateCommand</b> event.
+ * This method is invoked when a child control of the data list
+ * raises an <b>OnCommand</b> event and the command name is 'update' (case-insensitive).
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onUpdateCommand($param)
+ {
+ $this->raiseEvent('OnUpdateCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnCancelCommand</b> event.
+ * This method is invoked when a child control of the data list
+ * raises an <b>OnCommand</b> event and the command name is 'cancel' (case-insensitive).
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onCancelCommand($param)
+ {
+ $this->raiseEvent('OnCancelCommand',$this,$param);
+ }
+
+ /**
+ * Returns a value indicating whether this control contains header item.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean whether the datalist has header
+ */
+ public function getHasHeader()
+ {
+ return ($this->getShowHeader() && ($this->_headerTemplate!==null || $this->getHeaderRenderer()!==''));
+ }
+
+ /**
+ * Returns a value indicating whether this control contains footer item.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean whether the datalist has footer
+ */
+ public function getHasFooter()
+ {
+ return ($this->getShowFooter() && ($this->_footerTemplate!==null || $this->getFooterRenderer()!==''));
+ }
+
+ /**
+ * Returns a value indicating whether this control contains separator items.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean always false.
+ */
+ public function getHasSeparators()
+ {
+ return $this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
+ }
+
+ /**
+ * Returns a style used for rendering items.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
+ * @param integer index of the item being rendered
+ * @return TStyle item style
+ */
+ public function generateItemStyle($itemType,$index)
+ {
+ if(($item=$this->getItem($itemType,$index))!==null && ($item instanceof IStyleable) && $item->getHasStyle())
+ {
+ $style=$item->getStyle();
+ $item->clearStyle();
+ return $style;
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Renders an item in the list.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @param THtmlWriter writer for rendering purpose
+ * @param TRepeatInfo repeat information
+ * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
+ * @param integer zero-based index of the item in the item list
+ */
+ public function renderItem($writer,$repeatInfo,$itemType,$index)
+ {
+ $item=$this->getItem($itemType,$index);
+ if($repeatInfo->getRepeatLayout()===TRepeatLayout::Raw && get_class($item)==='TDataListItem')
+ $item->setTagName('div');
+ $item->renderControl($writer);
+ }
+
+ /**
+ * @param TListItemType item type
+ * @param integer item index
+ * @return TControl data list item with the specified item type and index
+ */
+ private function getItem($itemType,$index)
+ {
+ switch($itemType)
+ {
+ case TListItemType::Item:
+ case TListItemType::AlternatingItem:
+ case TListItemType::SelectedItem:
+ case TListItemType::EditItem:
+ return $this->getItems()->itemAt($index);
+ case TListItemType::Header:
+ return $this->getControls()->itemAt(0);
+ case TListItemType::Footer:
+ return $this->getControls()->itemAt($this->getControls()->getCount()-1);
+ case TListItemType::Separator:
+ $i=$index+$index+1;
+ if($this->_headerTemplate!==null || $this->getHeaderRenderer()!=='')
+ $i++;
+ return $this->getControls()->itemAt($i);
+ }
+ return null;
+ }
+
+ /**
+ * Creates a datalist item.
+ * This method invokes {@link createItem} to create a new datalist item.
+ * @param integer zero-based item index.
+ * @param TListItemType item type
+ * @return TControl the created item, null if item is not created
+ */
+ private function createItemInternal($itemIndex,$itemType)
+ {
+ if(($item=$this->createItem($itemIndex,$itemType))!==null)
+ {
+ $param=new TDataListItemEventParameter($item);
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ return $item;
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Creates a datalist item and performs databinding.
+ * This method invokes {@link createItem} to create a new datalist item.
+ * @param integer zero-based item index.
+ * @param TListItemType item type
+ * @param mixed data to be associated with the item
+ * @return TControl the created item, null if item is not created
+ */
+ private function createItemWithDataInternal($itemIndex,$itemType,$dataItem)
+ {
+ if(($item=$this->createItem($itemIndex,$itemType))!==null)
+ {
+ $param=new TDataListItemEventParameter($item);
+ if($item instanceof IDataRenderer)
+ $item->setData($dataItem);
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ $item->dataBind();
+ $this->onItemDataBound($param);
+ return $item;
+ }
+ else
+ return null;
+ }
+
+ private function getAlternatingItemDisplay()
+ {
+ if(($classPath=$this->getAlternatingItemRenderer())==='' && $this->_alternatingItemTemplate===null)
+ return array($this->getItemRenderer(),$this->_itemTemplate);
+ else
+ return array($classPath,$this->_alternatingItemTemplate);
+ }
+
+ private function getSelectedItemDisplay($itemIndex)
+ {
+ if(($classPath=$this->getSelectedItemRenderer())==='' && $this->_selectedItemTemplate===null)
+ {
+ if($itemIndex%2===0)
+ return array($this->getItemRenderer(),$this->_itemTemplate);
+ else
+ return $this->getAlternatingItemDisplay();
+ }
+ else
+ return array($classPath,$this->_selectedItemTemplate);
+ }
+
+ private function getEditItemDisplay($itemIndex)
+ {
+ if(($classPath=$this->getEditItemRenderer())==='' && $this->_editItemTemplate===null)
+ return $this->getSelectedItemDisplay($itemIndex);
+ else
+ return array($classPath,$this->_editItemTemplate);
+ }
+
+ /**
+ * Creates a datalist item instance based on the item type and index.
+ * @param integer zero-based item index
+ * @param TListItemType item type
+ * @return TControl created datalist item
+ */
+ protected function createItem($itemIndex,$itemType)
+ {
+ $template=null;
+ $classPath=null;
+ switch($itemType)
+ {
+ case TListItemType::Item :
+ $classPath=$this->getItemRenderer();
+ $template=$this->_itemTemplate;
+ break;
+ case TListItemType::AlternatingItem :
+ list($classPath,$template)=$this->getAlternatingItemDisplay();
+ break;
+ case TListItemType::SelectedItem:
+ list($classPath,$template)=$this->getSelectedItemDisplay($itemIndex);
+ break;
+ case TListItemType::EditItem:
+ list($classPath,$template)=$this->getEditItemDisplay($itemIndex);
+ break;
+ case TListItemType::Header :
+ $classPath=$this->getHeaderRenderer();
+ $template=$this->_headerTemplate;
+ break;
+ case TListItemType::Footer :
+ $classPath=$this->getFooterRenderer();
+ $template=$this->_footerTemplate;
+ break;
+ case TListItemType::Separator :
+ $classPath=$this->getSeparatorRenderer();
+ $template=$this->_separatorTemplate;
+ break;
+ default:
+ throw new TInvalidDataValueException('datalist_itemtype_unknown',$itemType);
+ }
+ if($classPath!=='')
+ {
+ $item=Prado::createComponent($classPath);
+ if($item instanceof IItemDataRenderer)
+ {
+ $item->setItemIndex($itemIndex);
+ $item->setItemType($itemType);
+ }
+ }
+ else if($template!==null)
+ {
+ $item=new TDataListItem;
+ $item->setItemIndex($itemIndex);
+ $item->setItemType($itemType);
+ $template->instantiateIn($item);
+ }
+ else
+ $item=null;
+
+ return $item;
+ }
+
+ /**
+ * Creates empty datalist content.
+ */
+ protected function createEmptyContent()
+ {
+ if(($classPath=$this->getEmptyRenderer())!=='')
+ $this->getControls()->add(Prado::createComponent($classPath));
+ else if($this->_emptyTemplate!==null)
+ $this->_emptyTemplate->instantiateIn($this);
+ }
+
+ /**
+ * Applies styles to items, header, footer and separators.
+ * Item styles are applied in a hierarchical way. Style in higher hierarchy
+ * will inherit from styles in lower hierarchy.
+ * Starting from the lowest hierarchy, the item styles include
+ * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
+ * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
+ * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
+ * {@link getEditItemStyle EditItemStyle} will also have red background color
+ * unless it is set to a different value explicitly.
+ */
+ protected function applyItemStyles()
+ {
+ $itemStyle=$this->getViewState('ItemStyle',null);
+
+ $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null);
+ if($itemStyle!==null)
+ {
+ if($alternatingItemStyle===null)
+ $alternatingItemStyle=$itemStyle;
+ else
+ $alternatingItemStyle->mergeWith($itemStyle);
+ }
+
+ $selectedItemStyle=$this->getViewState('SelectedItemStyle',null);
+
+ $editItemStyle=$this->getViewState('EditItemStyle',null);
+ if($selectedItemStyle!==null)
+ {
+ if($editItemStyle===null)
+ $editItemStyle=$selectedItemStyle;
+ else
+ $editItemStyle->mergeWith($selectedItemStyle);
+ }
+
+ // apply header style if any
+ if($this->_header!==null && $this->_header instanceof IStyleable)
+ {
+ if($headerStyle=$this->getViewState('HeaderStyle',null))
+ $this->_header->getStyle()->mergeWith($headerStyle);
+ }
+
+ // apply footer style if any
+ if($this->_footer!==null && $this->_footer instanceof IStyleable)
+ {
+ if($footerStyle=$this->getViewState('FooterStyle',null))
+ $this->_footer->getStyle()->mergeWith($footerStyle);
+ }
+
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+
+ // apply item styles if any
+ foreach($this->getItems() as $index=>$item)
+ {
+ if($index===$editIndex)
+ $style=$editItemStyle;
+ else if($index===$selectedIndex)
+ $style=$selectedItemStyle;
+ else if($index%2===0)
+ $style=$itemStyle;
+ else
+ $style=$alternatingItemStyle;
+ if($style && $item instanceof IStyleable)
+ $item->getStyle()->mergeWith($style);
+ }
+
+ // apply separator style if any
+ if(($separatorStyle=$this->getViewState('SeparatorStyle',null))!==null && $this->getHasSeparators())
+ {
+ $controls=$this->getControls();
+ $count=$controls->getCount();
+ for($i=$this->_header?2:1;$i<$count;$i+=2)
+ {
+ if(($separator=$controls->itemAt($i)) instanceof IStyleable)
+ $separator->getStyle()->mergeWith($separatorStyle);
+ }
+ }
+ }
+
+ /**
+ * Saves item count in viewstate.
+ * This method is invoked right before control state is to be saved.
+ */
+ public function saveState()
+ {
+ parent::saveState();
+ if($this->_items)
+ $this->setViewState('ItemCount',$this->_items->getCount(),0);
+ else
+ $this->clearViewState('ItemCount');
+ }
+
+ /**
+ * Loads item count information from viewstate.
+ * This method is invoked right after control state is loaded.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ if(!$this->getIsDataBound())
+ $this->restoreItemsFromViewState();
+ $this->clearViewState('ItemCount');
+ }
+
+ /**
+ * Clears up all items in the data list.
+ */
+ public function reset()
+ {
+ $this->getControls()->clear();
+ $this->getItems()->clear();
+ $this->_header=null;
+ $this->_footer=null;
+ }
+
+ /**
+ * Creates data list items based on viewstate information.
+ */
+ protected function restoreItemsFromViewState()
+ {
+ $this->reset();
+ if(($itemCount=$this->getViewState('ItemCount',0))>0)
+ {
+ $items=$this->getItems();
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+ $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
+ $this->_header=$this->createItemInternal(-1,TListItemType::Header);
+ for($i=0;$i<$itemCount;++$i)
+ {
+ if($hasSeparator && $i>0)
+ $this->createItemInternal($i-1,TListItemType::Separator);
+ if($i===$editIndex)
+ $itemType=TListItemType::EditItem;
+ else if($i===$selectedIndex)
+ $itemType=TListItemType::SelectedItem;
+ else
+ $itemType=$i%2?TListItemType::AlternatingItem : TListItemType::Item;
+ $items->add($this->createItemInternal($i,$itemType));
+ }
+ $this->_footer=$this->createItemInternal(-1,TListItemType::Footer);
+ }
+ else
+ $this->createEmptyContent();
+ $this->clearChildState();
+ }
+
+ /**
+ * Performs databinding to populate data list items from data source.
+ * This method is invoked by dataBind().
+ * You may override this function to provide your own way of data population.
+ * @param Traversable the data
+ */
+ protected function performDataBinding($data)
+ {
+ $this->reset();
+ $keys=$this->getDataKeys();
+ $keys->clear();
+ $keyField=$this->getDataKeyField();
+ $itemIndex=0;
+ $items=$this->getItems();
+ $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+ foreach($data as $key=>$dataItem)
+ {
+ if($keyField!=='')
+ $keys->add($this->getDataFieldValue($dataItem,$keyField));
+ else
+ $keys->add($key);
+ if($itemIndex===0)
+ $this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null);
+ if($hasSeparator && $itemIndex>0)
+ $this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null);
+ if($itemIndex===$editIndex)
+ $itemType=TListItemType::EditItem;
+ else if($itemIndex===$selectedIndex)
+ $itemType=TListItemType::SelectedItem;
+ else
+ $itemType=$itemIndex%2?TListItemType::AlternatingItem : TListItemType::Item;
+ $items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem));
+ $itemIndex++;
+ }
+ if($itemIndex>0)
+ $this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null);
+ else
+ {
+ $this->createEmptyContent();
+ $this->dataBindChildren();
+ }
+ $this->setViewState('ItemCount',$itemIndex,0);
+ }
+
+ /**
+ * Renders the data list control.
+ * This method overrides the parent implementation.
+ * @param THtmlWriter writer for rendering purpose.
+ */
+ public function render($writer)
+ {
+ if($this->getHasControls())
+ {
+ if($this->getItemCount()>0)
+ {
+ $this->applyItemStyles();
+ $repeatInfo=$this->getRepeatInfo();
+ $repeatInfo->renderRepeater($writer,$this);
+ }
+ else if($this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='')
+ parent::render($writer);
+ }
+ }
+}
+
+
+/**
+ * TDataListItemEventParameter class
+ *
+ * TDataListItemEventParameter encapsulates the parameter data for
+ * {@link TDataList::onItemCreated ItemCreated} event of {@link TDataList} controls.
+ * The {@link getItem Item} property indicates the DataList item related with the event.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataListItemEventParameter extends TEventParameter
+{
+ /**
+ * The datalist item control responsible for the event.
+ * @var TControl
+ */
+ private $_item=null;
+
+ /**
+ * Constructor.
+ * @param TControl DataList item related with the corresponding event
+ */
+ public function __construct($item)
+ {
+ $this->_item=$item;
+ }
+
+ /**
+ * @return TControl datalist item related with the corresponding event
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+}
+
+/**
+ * TDataListCommandEventParameter class
+ *
+ * TDataListCommandEventParameter encapsulates the parameter data for
+ * {@link TDataList::onItemCommand ItemCommand} event of {@link TDataList} controls.
+ *
+ * The {@link getItem Item} property indicates the DataList item related with the event.
+ * The {@link getCommandSource CommandSource} refers to the control that originally
+ * raises the Command event.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataListCommandEventParameter extends TCommandEventParameter
+{
+ /**
+ * @var TControl the datalist item control responsible for the event.
+ */
+ private $_item=null;
+ /**
+ * @var TControl the control originally raises the <b>OnCommand</b> event.
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TControl datalist item responsible for the event
+ * @param TControl original event sender
+ * @param TCommandEventParameter original event parameter
+ */
+ public function __construct($item,$source,TCommandEventParameter $param)
+ {
+ $this->_item=$item;
+ $this->_source=$source;
+ parent::__construct($param->getCommandName(),$param->getCommandParameter());
+ }
+
+ /**
+ * @return TControl the datalist item control responsible for the event.
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+
+ /**
+ * @return TControl the control originally raises the <b>OnCommand</b> event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+}
+
+/**
+ * TDataListItem class
+ *
+ * A TDataListItem control represents an item in the {@link TDataList} control,
+ * such as heading section, footer section, or a data item.
+ * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
+ * and {@link getDataItem DataItem} properties, respectively. The type of the item
+ * is given by {@link getItemType ItemType} property.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataListItem extends TWebControl implements INamingContainer, IItemDataRenderer
+{
+ /**
+ * index of the data item in the Items collection of DataList
+ */
+ private $_itemIndex;
+ /**
+ * type of the TDataListItem
+ * @var TListItemType
+ */
+ private $_itemType;
+ /**
+ * value of the data associated with this item
+ * @var mixed
+ */
+ private $_data;
+
+ private $_tagName='span';
+
+ /**
+ * Returns the tag name used for this control.
+ * @return string tag name of the control to be rendered
+ */
+ protected function getTagName()
+ {
+ return $this->_tagName;
+ }
+
+ /**
+ * @param string tag name of the control to be rendered
+ */
+ public function setTagName($value)
+ {
+ $this->_tagName=$value;
+ }
+
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableItemStyle} to be used by a datalist item.
+ * @return TStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableItemStyle;
+ }
+
+ /**
+ * @return TListItemType item type
+ */
+ public function getItemType()
+ {
+ return $this->_itemType;
+ }
+
+ /**
+ * @param TListItemType item type.
+ */
+ public function setItemType($value)
+ {
+ $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
+ }
+
+ /**
+ * @return integer zero-based index of the item in the item collection of datalist
+ */
+ public function getItemIndex()
+ {
+ return $this->_itemIndex;
+ }
+
+ /**
+ * Sets the zero-based index for the item.
+ * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
+ * @param integer zero-based index of the item.
+ */
+ public function setItemIndex($value)
+ {
+ $this->_itemIndex=TPropertyValue::ensureInteger($value);
+ }
+
+ /**
+ * @return mixed data associated with the item
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * @param mixed data to be associated with the item
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->_data=$value;
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @return mixed data associated with the item
+ * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
+ */
+ public function getDataItem()
+ {
+ return $this->getData();
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @param mixed data to be associated with the item
+ * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
+ */
+ public function setDataItem($value)
+ {
+ return $this->setData($value);
+ }
+
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for <b>OnCommand</b> event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+/**
+ * TDataListItemCollection class.
+ *
+ * TDataListItemCollection represents a collection of data list items.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataListItemCollection extends TList
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by inserting only TControl descendants.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a TControl descendant.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TControl)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('datalistitemcollection_datalistitem_required');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TDataListItemRenderer.php b/lib/prado/framework/Web/UI/WebControls/TDataListItemRenderer.php
new file mode 100644
index 0000000..d7cb59c
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TDataListItemRenderer.php
@@ -0,0 +1,170 @@
+<?php
+/**
+ * TDataListItemRenderer class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataList');
+Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
+
+/**
+ * TDataListItemRenderer class
+ *
+ * TDataListItemRenderer can be used as a convenient base class to
+ * define an item renderer class specific for {@link TDataList}.
+ *
+ * TDataListItemRenderer extends {@link TItemDataRenderer} and implements
+ * the bubbling scheme for the OnCommand event of data list items.
+ *
+ * TDataListItemRenderer also implements the {@link IStyleable} interface,
+ * which allows TDataList to apply CSS styles to the renders.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.0
+ */
+class TDataListItemRenderer extends TItemDataRenderer implements IStyleable
+{
+ /**
+ * Creates a style object to be used by the control.
+ * This method may be overriden by controls to provide customized style.
+ * @return TStyle
+ */
+ protected function createStyle()
+ {
+ return new TTableItemStyle;
+ }
+
+ /**
+ * @return boolean whether the control has defined any style information
+ */
+ public function getHasStyle()
+ {
+ return $this->getViewState('Style',null)!==null;
+ }
+
+ /**
+ * @return TStyle the object representing the css style of the control
+ */
+ public function getStyle()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style;
+ else
+ {
+ $style=$this->createStyle();
+ $this->setViewState('Style',$style,null);
+ return $style;
+ }
+ }
+
+ /**
+ * Removes all style data.
+ */
+ public function clearStyle()
+ {
+ $this->clearViewState('Style');
+ }
+
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for <b>OnCommand</b> event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Returns the tag name used for this control.
+ * By default, the tag name is 'span'.
+ * You can override this method to provide customized tag names.
+ * If the tag name is empty, the opening and closing tag will NOT be rendered.
+ * @return string tag name of the control to be rendered
+ */
+ protected function getTagName()
+ {
+ return 'span';
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * By default, this method renders the style string.
+ * The method can be overriden to provide customized attribute rendering.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ if($style=$this->getViewState('Style',null))
+ $style->addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the control.
+ * This method overrides the parent implementation by replacing it with
+ * the following sequence:
+ * - {@link renderBeginTag}
+ * - {@link renderContents}
+ * - {@link renderEndTag}
+ * If the {@link getTagName TagName} is empty, only {@link renderContents} is invoked.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->getTagName()!=='')
+ {
+ $this->renderBeginTag($writer);
+ $this->renderContents($writer);
+ $this->renderEndTag($writer);
+ }
+ else
+ $this->renderContents($writer);
+ }
+
+ /**
+ * Renders the openning tag for the control (including attributes)
+ * This method is invoked when {@link getTagName TagName} is not empty.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderBeginTag($writer)
+ {
+ $this->addAttributesToRender($writer);
+ $writer->renderBeginTag($this->getTagName());
+ }
+
+ /**
+ * Renders the body content enclosed between the control tag.
+ * By default, child controls and text strings will be rendered.
+ * You can override this method to provide customized content rendering.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ parent::renderChildren($writer);
+ }
+
+ /**
+ * Renders the closing tag for the control
+ * This method is invoked when {@link getTagName TagName} is not empty.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderEndTag($writer)
+ {
+ $writer->renderEndTag();
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TDataRenderer.php b/lib/prado/framework/Web/UI/WebControls/TDataRenderer.php
new file mode 100644
index 0000000..6e76013
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TDataRenderer.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * TDataRenderer class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ * @since 3.1.2
+ */
+
+/**
+ * TDataRenderer class
+ *
+ * TDataRenderer is the convenient base class for template-based renderer controls.
+ * It extends {@link TTemplateControl} and implements the methods required
+ * by the {@link IDataRenderer} interface.
+ *
+ * The following property is provided by TDataRenderer:
+ * - {@link getData Data}: data associated with this renderer.
+
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.2
+ */
+abstract class TDataRenderer extends TTemplateControl implements IDataRenderer
+{
+ /**
+ * @var mixed data associated with this renderer
+ */
+ private $_data;
+
+ /**
+ * @return mixed data associated with the item
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * @param mixed data to be associated with the item
+ */
+ public function setData($value)
+ {
+ $this->_data=$value;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TDataSourceControl.php b/lib/prado/framework/Web/UI/WebControls/TDataSourceControl.php
new file mode 100644
index 0000000..ff47a78
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TDataSourceControl.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * IDataSource, TDataSourceControl, TReadOnlyDataSource class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * IDataSource class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+interface IDataSource
+{
+ public function getView($viewName);
+ public function getViewNames();
+ public function onDataSourceChanged($param);
+}
+
+/**
+ * TDataSourceControl class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TDataSourceControl extends TControl implements IDataSource
+{
+ public function getView($viewName)
+ {
+ return null;
+ }
+
+ public function getViewNames()
+ {
+ return array();
+ }
+
+ public function onDataSourceChanged($param)
+ {
+ $this->raiseEvent('OnDataSourceChanged',$this,$param);
+ }
+
+ public function focus()
+ {
+ throw new TNotSupportedException('datasourcecontrol_focus_unsupported');
+ }
+
+ public function getEnableTheming()
+ {
+ return false;
+ }
+
+ public function setEnableTheming($value)
+ {
+ throw new TNotSupportedException('datasourcecontrol_enabletheming_unsupported');
+ }
+
+ public function getSkinID()
+ {
+ return '';
+ }
+
+ public function setSkinID($value)
+ {
+ throw new TNotSupportedException('datasourcecontrol_skinid_unsupported');
+ }
+
+ public function getVisible($checkParents=true)
+ {
+ return false;
+ }
+
+ public function setVisible($value)
+ {
+ throw new TNotSupportedException('datasourcecontrol_visible_unsupported');
+ }
+}
+
+/**
+ * TDataSourceControl class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TReadOnlyDataSource extends TDataSourceControl
+{
+ private $_dataSource;
+ private $_dataMember;
+
+ public function __construct($dataSource,$dataMember)
+ {
+ if(!is_array($dataSource) && !($dataSource instanceof IDataSource) && !($dataSource instanceof Traversable))
+ throw new TInvalidDataTypeException('readonlydatasource_datasource_invalid');
+ $this->_dataSource=$dataSource;
+ $this->_dataMember=$dataMember;
+ }
+
+ public function getView($viewName)
+ {
+ if($this->_dataSource instanceof IDataSource)
+ return $this->_dataSource->getView($viewName);
+ else
+ return new TReadOnlyDataSourceView($this,$this->_dataMember,$this->_dataSource);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TDataSourceView.php b/lib/prado/framework/Web/UI/WebControls/TDataSourceView.php
new file mode 100644
index 0000000..ed6d868
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TDataSourceView.php
@@ -0,0 +1,202 @@
+<?php
+/**
+ * TDataSourceSelectParameters, TDataSourceView, TReadOnlyDataSourceView class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataSourceSelectParameters class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataSourceSelectParameters extends TComponent
+{
+ private $_retrieveTotalRowCount=false;
+ private $_startRowIndex=0;
+ private $_totalRowCount=0;
+ private $_maximumRows=0;
+
+ public function getStartRowIndex()
+ {
+ return $this->_startRowIndex;
+ }
+
+ public function setStartRowIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=0;
+ $this->_startRowIndex=$value;
+ }
+
+ public function getMaximumRows()
+ {
+ return $this->_maximumRows;
+ }
+
+ public function setMaximumRows($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=0;
+ $this->_maximumRows=$value;
+ }
+
+ public function getRetrieveTotalRowCount()
+ {
+ return $this->_retrieveTotalRowCount;
+ }
+
+ public function setRetrieveTotalRowCount($value)
+ {
+ $this->_retrieveTotalRowCount=TPropertyValue::ensureBoolean($value);
+ }
+
+ public function getTotalRowCount()
+ {
+ return $this->_totalRowCount;
+ }
+
+ public function setTotalRowCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=0;
+ $this->_totalRowCount=$value;
+ }
+}
+
+/**
+ * TDataSourceView class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TDataSourceView extends TComponent
+{
+ private $_owner;
+ private $_name;
+
+ public function __construct(IDataSource $owner,$viewName)
+ {
+ $this->_owner=$owner;
+ $this->_name=$viewName;
+ }
+
+ /**
+ * Performs DB selection based on specified parameters.
+ * @param ???
+ * @return Traversable
+ */
+ abstract public function select($parameters);
+
+ /**
+ * Inserts a DB record.
+ * @param array|TMap
+ * @return integer affected rows
+ */
+ public function insertAt($values)
+ {
+ throw new TNotSupportedException('datasourceview_insert_unsupported');
+ }
+
+ /**
+ * Updates DB record(s) with the specified keys and new values
+ * @param array|TMap keys for specifying the records to be updated
+ * @param array|TMap new values
+ * @return integer affected rows
+ */
+ public function update($keys,$values)
+ {
+ throw new TNotSupportedException('datasourceview_update_unsupported');
+ }
+
+ /**
+ * Deletes DB row(s) with the specified keys.
+ * @param array|TMap keys for specifying the rows to be deleted
+ * @return integer affected rows
+ */
+ public function delete($keys)
+ {
+ throw new TNotSupportedException('datasourceview_delete_unsupported');
+ }
+
+ public function getCanDelete()
+ {
+ return false;
+ }
+
+ public function getCanInsert()
+ {
+ return false;
+ }
+
+ public function getCanPage()
+ {
+ return false;
+ }
+
+ public function getCanGetRowCount()
+ {
+ return false;
+ }
+
+ public function getCanSort()
+ {
+ return false;
+ }
+
+ public function getCanUpdate()
+ {
+ return false;
+ }
+
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ public function getDataSource()
+ {
+ return $this->_owner;
+ }
+
+ public function onDataSourceViewChanged($param)
+ {
+ $this->raiseEvent('OnDataSourceViewChanged',$this,$param);
+ }
+}
+
+/**
+ * TReadOnlyDataSourceView class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TReadOnlyDataSourceView extends TDataSourceView
+{
+ private $_dataSource=null;
+
+ public function __construct(IDataSource $owner,$viewName,$dataSource)
+ {
+ parent::__construct($owner,$viewName);
+ if($dataSource===null || is_array($dataSource))
+ $this->_dataSource=new TMap($dataSource);
+ else if($dataSource instanceof Traversable)
+ $this->_dataSource=$dataSource;
+ else
+ throw new TInvalidDataTypeException('readonlydatasourceview_datasource_invalid');
+ }
+
+ public function select($parameters)
+ {
+ return $this->_dataSource;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TDataTypeValidator.php b/lib/prado/framework/Web/UI/WebControls/TDataTypeValidator.php
new file mode 100644
index 0000000..b78a962
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TDataTypeValidator.php
@@ -0,0 +1,139 @@
+<?php
+/**
+ * TDataTypeValidator class.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TDataTypeValidator class
+ *
+ * TDataTypeValidator verifies if the input data is of the type specified
+ * by {@link setDataType DataType}.
+ * The following data types are supported:
+ * - <b>Integer</b> A 32-bit signed integer data type.
+ * - <b>Float</b> A double-precision floating point number data type.
+ * - <b>Date</b> A date data type.
+ * - <b>String</b> A string data type.
+ * For <b>Date</b> type, the property {@link setDateFormat DateFormat}
+ * will be used to determine how to parse the date string. If it is not
+ * provided, the string will be assumed to be in GNU datetime format.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataTypeValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TDataTypeValidator';
+ }
+
+ /**
+ * @return TValidationDataType the data type that the values being compared are converted to before the comparison is made. Defaults to TValidationDataType::String.
+ */
+ public function getDataType()
+ {
+ return $this->getViewState('DataType','String');
+ }
+
+ /**
+ * Sets the data type that the values being compared are converted to before the comparison is made.
+ * @param TValidationDataType the data type
+ */
+ public function setDataType($value)
+ {
+ $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TValidationDataType'),TValidationDataType::String);
+ }
+
+ /**
+ * Sets the date format for a date validation
+ * @param string the date format value
+ */
+ public function setDateFormat($value)
+ {
+ $this->setViewState('DateFormat', $value, '');
+ }
+
+ /**
+ * @return string the date validation date format if any
+ */
+ public function getDateFormat()
+ {
+ return $this->getViewState('DateFormat', '');
+ }
+
+
+ /**
+ * Determine if the given value is of a particular type using RegExp.
+ * @param string value to check
+ * @return boolean true if value fits the type expression.
+ */
+ protected function evaluateDataTypeCheck($value)
+ {
+ if($value=='')
+ return true;
+
+ switch($this->getDataType())
+ {
+ case TValidationDataType::Integer:
+ return preg_match('/^[-+]?[0-9]+$/',trim($value));
+ case TValidationDataType::Float:
+ return preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value));
+ case TValidationDataType::Date:
+ $dateFormat = $this->getDateFormat();
+ if(strlen($dateFormat))
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$dateFormat);
+ return $formatter->isValidDate($value);
+ }
+ else
+ return strtotime($value) > 0;
+ }
+ return true;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options = parent::getClientScriptOptions();
+ $options['DataType']=$this->getDataType();
+ if(($dateFormat=$this->getDateFormat())!=='')
+ $options['DateFormat']=$dateFormat;
+ return $options;
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input data is of valid type.
+ * The validation always succeeds if ControlToValidate is not specified
+ * or the input data is empty.
+ * @return boolean whether the validation succeeds
+ */
+ public function evaluateIsValid()
+ {
+ if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
+ return true;
+
+ return $this->evaluateDataTypeCheck($value);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TDatePicker.php b/lib/prado/framework/Web/UI/WebControls/TDatePicker.php
new file mode 100644
index 0000000..3f9e445
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TDatePicker.php
@@ -0,0 +1,978 @@
+<?php
+/**
+ * TDatePicker class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTextBox class
+ */
+Prado::using('System.Web.UI.WebControls.TTextBox');
+
+/**
+ *
+ * TDatePicker class.
+ *
+ * TDatePicker displays a text box for date input purpose.
+ * When the text box receives focus, a calendar will pop up and users can
+ * pick up from it a date that will be automatically entered into the text box.
+ * The format of the date string displayed in the text box is determined by
+ * the <b>DateFormat</b> property. Valid formats are the combination of the
+ * following tokens,
+ *
+ * <code>
+ * Character Format Pattern (en-US)
+ * -----------------------------------------
+ * d day digit
+ * dd padded day digit e.g. 01, 02
+ * M month digit
+ * MM padded month digit
+ * MMMM localized month name, e.g. March, April
+ * yy 2 digit year
+ * yyyy 4 digit year
+ * -----------------------------------------
+ * </code>
+ *
+ * TDatePicker has four <b>Mode</b> to show the date picker popup.
+ *
+ * # <b>Basic</b> -- Only shows a text input, focusing on the input shows the
+ * date picker. This way you can access the popup using only
+ * the keyboard. Note that because of this, TAB-bing through
+ * this control will automatically select the current date if
+ * no previous date was selected. If you close the popup (eg.
+ * pressing the ESC key) you'll need to un-focus and re-focus
+ * the control again for the popup to reappear.
+ * # <b>Clickable</b> -- Only shows a text input, clicking on the input shows the
+ * date picker. This mode solves the two small problems of the
+ * Basic mode. It was first introduced in Prado 3.2.
+ * # <b>Button</b> -- Shows a button next to the text input, clicking on the
+ * button shows the date, button text can be by the
+ * <b>ButtonText</b> property
+ * # <b>ImageButton</b> -- Shows an image next to the text input, clicking on
+ * the image shows the date picker, image source can be
+ * change through the <b>ButtonImageUrl</b> property.
+ *
+ * The <b>CssClass</b> property can be used to override the css class name
+ * for the date picker panel. <b>CalendarStyle</b> property sets the packages
+ * styles available. E.g. <b>default</b>.
+ *
+ * The <b>InputMode</b> property can be set to "TextBox" or "DropDownList" with
+ * default as "TextBox".
+ * In <b>DropDownList</b> mode, in addition to the popup date picker, three
+ * drop down list (day, month and year) are presented to select the date .
+ *
+ * The <b>PositionMode</b> property can be set to "Top" or "Bottom" with default
+ * as "Bottom". It specifies the position of the calendar popup, relative to the
+ * input field.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @author Carl G. Mathisen <carlgmathisen@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDatePicker extends TTextBox
+{
+ /**
+ * Script path relative to the TClientScriptManager::SCRIPT_PATH
+ */
+ const SCRIPT_PATH = 'prado/datepicker';
+
+ /**
+ * @var TDatePickerClientScript validator client-script options.
+ */
+ private $_clientScript;
+ /**
+ * AutoPostBack is not supported.
+ */
+ public function setAutoPostBack($value)
+ {
+ throw new TNotSupportedException('tdatepicker_autopostback_unsupported',
+ get_class($this));
+ }
+
+ /**
+ * @return string the format of the date string
+ */
+ public function getDateFormat()
+ {
+ return $this->getViewState('DateFormat','dd-MM-yyyy');
+ }
+
+ /**
+ * Sets the format of the date string.
+ * @param string the format of the date string
+ */
+ public function setDateFormat($value)
+ {
+ $this->setViewState('DateFormat',$value,'dd-MM-yyyy');
+ }
+
+ /**
+ * @return boolean whether the calendar window should pop up when the control receives focus
+ */
+ public function getShowCalendar()
+ {
+ return $this->getViewState('ShowCalendar',true);
+ }
+
+ /**
+ * Sets whether to pop up the calendar window when the control receives focus
+ * @param boolean whether to show the calendar window
+ */
+ public function setShowCalendar($value)
+ {
+ $this->setViewState('ShowCalendar',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Gets the current culture.
+ * @return string current culture, e.g. en_AU.
+ */
+ public function getCulture()
+ {
+ return $this->getViewState('Culture', '');
+ }
+
+ /**
+ * Sets the culture/language for the date picker.
+ * @param string a culture string, e.g. en_AU.
+ */
+ public function setCulture($value)
+ {
+ $this->setViewState('Culture', $value, '');
+ }
+
+ /**
+ * @param TDatePickerInputMode input method of date values
+ */
+ public function setInputMode($value)
+ {
+ $this->setViewState('InputMode', TPropertyValue::ensureEnum($value, 'TDatePickerInputMode'), TDatePickerInputMode::TextBox);
+ }
+
+ /**
+ * @return TDatePickerInputMode input method of date values. Defaults to TDatePickerInputMode::TextBox.
+ */
+ public function getInputMode()
+ {
+ return $this->getViewState('InputMode', TDatePickerInputMode::TextBox);
+ }
+
+ /**
+ * @param TDatePickerMode calendar UI mode
+ */
+ public function setMode($value)
+ {
+ $this->setViewState('Mode', TPropertyValue::ensureEnum($value, 'TDatePickerMode'), TDatePickerMode::Basic);
+ }
+
+ /**
+ * @return TDatePickerMode current calendar UI mode.
+ */
+ public function getMode()
+ {
+ return $this->getViewState('Mode', TDatePickerMode::Basic);
+ }
+ /**
+ * @param string the image url for "Image" UI mode.
+ */
+ public function setButtonImageUrl($value)
+ {
+ $this->setViewState('ImageUrl', $value, '');
+ }
+
+ /**
+ * @return string the image url for "Image" UI mode.
+ */
+ public function getButtonImageUrl()
+ {
+ return $this->getViewState('ImageUrl', '');
+ }
+
+ /**
+ * @param string set the calendar style
+ */
+ public function setCalendarStyle($value)
+ {
+ $this->setViewState('CalendarStyle', $value, 'default');
+ }
+
+ /**
+ * @return string current calendar style
+ */
+ public function getCalendarStyle()
+ {
+ return $this->getViewState('CalendarStyle', 'default');
+ }
+
+ /**
+ * Set the first day of week, with 0 as Sunday, 1 as Monday, etc.
+ * @param integer 0 for Sunday, 1 for Monday, 2 for Tuesday, etc.
+ */
+ public function setFirstDayOfWeek($value)
+ {
+ $this->setViewState('FirstDayOfWeek', TPropertyValue::ensureInteger($value), 1);
+ }
+
+ /**
+ * @return integer first day of the week
+ */
+ public function getFirstDayOfWeek()
+ {
+ return $this->getViewState('FirstDayOfWeek', 1);
+ }
+
+ /**
+ * @return string text for the date picker button. Default is "...".
+ */
+ public function getButtonText()
+ {
+ return $this->getViewState('ButtonText', '...');
+ }
+
+ /**
+ * @param string text for the date picker button
+ */
+ public function setButtonText($value)
+ {
+ $this->setViewState('ButtonText', $value, '...');
+ }
+
+ /**
+ * @param integer date picker starting year, default is 2000.
+ */
+ public function setFromYear($value)
+ {
+ $this->setViewState('FromYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))-5);
+ }
+
+ /**
+ * @return integer date picker starting year, default is -5 years
+ */
+ public function getFromYear()
+ {
+ return $this->getViewState('FromYear', intval(@date('Y'))-5);
+ }
+
+ /**
+ * @param integer date picker ending year, default +10 years
+ */
+ public function setUpToYear($value)
+ {
+ $this->setViewState('UpToYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))+10);
+ }
+
+ /**
+ * @return integer date picker ending year, default +10 years
+ */
+ public function getUpToYear()
+ {
+ return $this->getViewState('UpToYear', intval(@date('Y'))+10);
+ }
+
+ /**
+ * @param TDatePickerPositionMode calendar UI position
+ */
+ public function setPositionMode($value)
+ {
+ $this->setViewState('PositionMode', TPropertyValue::ensureEnum($value, 'TDatePickerPositionMode'), TDatePickerPositionMode::Bottom);
+ }
+
+ /**
+ * @return TDatePickerPositionMode current calendar UI position.
+ */
+ public function getPositionMode()
+ {
+ return $this->getViewState('PositionMode', TDatePickerPositionMode::Bottom);
+ }
+
+ /**
+ * @return integer current selected date from the date picker as timestamp, NULL if timestamp is not set previously.
+ */
+ public function getTimeStamp()
+ {
+ if(trim($this->getText())==='')
+ return null;
+ else
+ return $this->getTimeStampFromText();
+ }
+
+ /**
+ * Sets the date for the date picker using timestamp.
+ * @param float time stamp for the date picker
+ */
+ public function setTimeStamp($value)
+ {
+ if($value===null || (is_string($value) && trim($value)===''))
+ $this->setText('');
+ else
+ {
+ $date = TPropertyValue::ensureFloat($value);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$this->getDateFormat());
+ $this->setText($formatter->format($date));
+ }
+ }
+
+ /**
+ * Returns the timestamp selected by the user.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getTimeStamp()}.
+ * @return integer the timestamp of the TDatePicker control.
+ * @see getTimeStamp
+ * @since 3.1.2
+ */
+ public function getData()
+ {
+ return $this->getTimeStamp();
+ }
+
+ /**
+ * Sets the timestamp represented by this control.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setTimeStamp()}.
+ * @param integer the timestamp of the TDatePicker control.
+ * @see setTimeStamp
+ * @since 3.1.2
+ */
+ public function setData($value)
+ {
+ $this->setTimeStamp($value);
+ }
+
+ /**
+ * @return string the date string.
+ */
+ public function getDate()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * @param string date string
+ */
+ public function setDate($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * Gets the TDatePickerClientScript to set the TDatePicker event handlers.
+ *
+ * The date picker on the client-side supports the following events.
+ * # <tt>OnDateChanged</tt> -- raised when the date is changed.
+ *
+ * You can attach custom javascript code to each of these events
+ *
+ * @return TDatePickerClientScript javascript validator event options.
+ */
+ public function getClientSide()
+ {
+ if($this->_clientScript===null)
+ $this->_clientScript = $this->createClientScript();
+ return $this->_clientScript;
+ }
+
+ /**
+ * @return TDatePickerClientScript javascript validator event options.
+ */
+ protected function createClientScript()
+ {
+ return new TDatePickerClientScript;
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return integer the interger timestamp if valid, otherwise the original text.
+ */
+ public function getValidationPropertyValue()
+ {
+ if(($text = $this->getText()) === '')
+ return '';
+ $date = $this->getTimeStamp();
+ return $date == null ? $text : $date;
+ }
+
+ /**
+ * Publish the date picker Css asset files.
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->publishCalendarStyle();
+ $this->registerCalendarClientScriptPre();
+ }
+
+ /**
+ * Renders body content.
+ * This method overrides parent implementation by adding
+ * additional date picker button if Mode is Button or ImageButton.
+ * @param THtmlWriter writer
+ */
+ public function render($writer)
+ {
+ if($this->getInputMode() == TDatePickerInputMode::TextBox)
+ {
+ parent::render($writer);
+ $this->renderDatePickerButtons($writer);
+ }
+ else
+ {
+ $this->renderDropDownListCalendar($writer);
+ if($this->hasDayPattern())
+ {
+ $this->renderClientControlScript($writer);
+ $this->renderDatePickerButtons($writer);
+ }
+ }
+ }
+
+ /**
+ * Renders the date picker popup buttons.
+ */
+ protected function renderDatePickerButtons($writer)
+ {
+ if($this->getShowCalendar())
+ {
+ switch ($this->getMode())
+ {
+ case TDatePickerMode::Button:
+ $this->renderButtonDatePicker($writer);
+ break;
+ case TDatePickerMode::ImageButton :
+ $this->renderImageButtonDatePicker($writer);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Loads user input data. Override parent implementation, when InputMode
+ * is DropDownList call getDateFromPostData to get date data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if($this->getInputMode() == TDatePickerInputMode::TextBox)
+ return parent::loadPostData($key, $values);
+ $value = $this->getDateFromPostData($key, $values);
+ if(!$this->getReadOnly() && $this->getText()!==$value)
+ {
+ $this->setText($value);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Loads date from drop down list data.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return array the date selected
+ */
+ protected function getDateFromPostData($key, $values)
+ {
+ $date = @getdate();
+
+ if(isset($values[$key.'$day']))
+ $day = intval($values[$key.'$day']);
+ else
+ $day = $date['mday'];
+
+ if(isset($values[$key.'$month']))
+ $month = intval($values[$key.'$month']) + 1;
+ else
+ $month = $date['mon'];
+
+ if(isset($values[$key.'$year']))
+ $year = intval($values[$key.'$year']);
+ else
+ $year = $date['year'];
+
+ $s = Prado::createComponent('System.Util.TDateTimeStamp');
+ $date = $s->getTimeStamp(0, 0, 0, $month, $day, $year);
+ //$date = @mktime(0, 0, 0, $month, $day, $year);
+
+ $pattern = $this->getDateFormat();
+ $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $pattern);
+ return $formatter->format($date);
+ }
+
+ /**
+ * Get javascript date picker options.
+ * @return array date picker client-side options
+ */
+ protected function getDatePickerOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['InputMode'] = $this->getInputMode();
+ $options['Format'] = $this->getDateFormat();
+ $options['FirstDayOfWeek'] = $this->getFirstDayOfWeek();
+ if(($cssClass=$this->getCssClass())!=='')
+ $options['ClassName'] = $cssClass;
+ $options['CalendarStyle'] = $this->getCalendarStyle();
+ $options['FromYear'] = $this->getFromYear();
+ $options['UpToYear'] = $this->getUpToYear();
+ switch($this->getMode())
+ {
+ case TDatePickerMode::Basic:
+ break;
+ case TDatePickerMode::Clickable:
+ $options['TriggerEvent'] = "click";
+ break;
+ default:
+ $options['Trigger'] = $this->getDatePickerButtonID();
+ break;
+ }
+ $options['PositionMode'] = $this->getPositionMode();
+
+ $options = array_merge($options, $this->getCulturalOptions());
+ if($this->_clientScript!==null)
+ $options = array_merge($options,
+ $this->_clientScript->getOptions()->toArray());
+ return $options;
+ }
+
+ /**
+ * Get javascript localization options, e.g. month and weekday names.
+ * @return array localization options.
+ */
+ protected function getCulturalOptions()
+ {
+ if($this->getCurrentCulture() == 'en')
+ return array();
+
+ $date = $this->getLocalizedCalendarInfo();
+ $options['MonthNames'] = $date->getMonthNames();
+ $options['AbbreviatedMonthNames'] = $date->getAbbreviatedMonthNames();
+ $options['ShortWeekDayNames'] = $date->getAbbreviatedDayNames();
+
+ return $options;
+ }
+
+ /**
+ * @return string the current culture, falls back to application if culture is not set.
+ */
+ protected function getCurrentCulture()
+ {
+ $app = $this->getApplication()->getGlobalization(false);
+ return $this->getCulture() == '' ?
+ ($app ? $app->getCulture() : 'en') : $this->getCulture();
+ }
+
+ /**
+ * @return DateTimeFormatInfo date time format information for the current culture.
+ */
+ protected function getLocalizedCalendarInfo()
+ {
+ //expensive operations
+ $culture = $this->getCurrentCulture();
+ Prado::using('System.I18N.core.DateTimeFormatInfo');
+ $info = Prado::createComponent('System.I18N.core.CultureInfo', $culture);
+ return $info->getDateTimeFormat();
+ }
+
+ /**
+ * Renders the drop down list date picker.
+ */
+ protected function renderDropDownListCalendar($writer)
+ {
+ if($this->getMode() == TDatePickerMode::Basic)
+ $this->setMode(TDatePickerMode::ImageButton);
+ parent::addAttributesToRender($writer);
+ $writer->removeAttribute('name');
+ $writer->removeAttribute('type');
+ $writer->addAttribute('id', $this->getClientID());
+
+ if(strlen($class = $this->getCssClass()) > 0)
+ $writer->addAttribute('class', $class);
+ $writer->renderBeginTag('span');
+
+ $s = Prado::createComponent('System.Util.TDateTimeStamp');
+ $date = $s->getDate($this->getTimeStampFromText());
+ //$date = @getdate($this->getTimeStampFromText());
+
+ $this->renderCalendarSelections($writer, $date);
+
+ //render a hidden input field
+ $writer->addAttribute('name', $this->getUniqueID());
+ $writer->addAttribute('type', 'hidden');
+ $writer->addAttribute('value', $this->getText());
+ $writer->renderBeginTag('input');
+
+ $writer->renderEndTag();
+ $writer->renderEndTag();
+ }
+
+ protected function hasDayPattern()
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
+ $this->getDateFormat());
+ return ($formatter->getDayPattern()!==null);
+ }
+
+ /**
+ * Renders the calendar drop down list depending on the DateFormat pattern.
+ * @param THtmlWriter the Html writer to render the drop down lists.
+ * @param array the current selected date
+ */
+ protected function renderCalendarSelections($writer, $date)
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
+ $this->getDateFormat());
+
+ foreach($formatter->getDayMonthYearOrdering() as $type)
+ {
+ if($type == 'day')
+ $this->renderCalendarDayOptions($writer,$date['mday']);
+ elseif($type == 'month')
+ $this->renderCalendarMonthOptions($writer,$date['mon']);
+ elseif($type == 'year')
+ $this->renderCalendarYearOptions($writer,$date['year']);
+ }
+ }
+
+ /**
+ * Gets the date from the text input using TSimpleDateFormatter
+ * @return integer current selected date timestamp
+ */
+ protected function getTimeStampFromText()
+ {
+ $pattern = $this->getDateFormat();
+ $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$pattern);
+ return $formatter->parse($this->getText());
+ }
+
+ /**
+ * Renders a drop down lists.
+ * @param THtmlWriter the writer used for the rendering purpose
+ * @param array list of selection options
+ * @param mixed selected key.
+ */
+ private function renderDropDownListOptions($writer,$options,$selected=null)
+ {
+ foreach($options as $k => $v)
+ {
+ $writer->addAttribute('value', $k);
+ if($k == $selected)
+ $writer->addAttribute('selected', 'selected');
+ $writer->renderBeginTag('option');
+ $writer->write($v);
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Renders the day drop down list options.
+ * @param THtmlWriter the writer used for the rendering purpose
+ * @param mixed selected day.
+ */
+ protected function renderCalendarDayOptions($writer, $selected=null)
+ {
+ $days = $this->getDropDownDayOptions();
+ $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'day');
+ $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'day');
+ $writer->addAttribute('class', 'datepicker_day_options');
+ if($this->getReadOnly() || !$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->renderBeginTag('select');
+ $this->renderDropDownListOptions($writer, $days, $selected);
+ $writer->renderEndTag();
+ }
+
+ /**
+ * @return array list of day options for a drop down list.
+ */
+ protected function getDropDownDayOptions()
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
+ $this->getDateFormat());
+ $days = array();
+ $requiresPadding = $formatter->getDayPattern() === 'dd';
+ for($i=1;$i<=31;$i++)
+ {
+ $days[$i] = $requiresPadding ? str_pad($i, 2, '0', STR_PAD_LEFT) : $i;
+ }
+ return $days;
+ }
+
+ /**
+ * Renders the month drop down list options.
+ * @param THtmlWriter the writer used for the rendering purpose
+ * @param mixed selected month.
+ */
+ protected function renderCalendarMonthOptions($writer, $selected=null)
+ {
+ $info = $this->getLocalizedCalendarInfo();
+ $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'month');
+ $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'month');
+ $writer->addAttribute('class', 'datepicker_month_options');
+ if($this->getReadOnly() || !$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->renderBeginTag('select');
+ $this->renderDropDownListOptions($writer,
+ $this->getLocalizedMonthNames($info), $selected-1);
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Returns the localized month names that depends on the month format pattern.
+ * "MMMM" will return the month names, "MM" or "MMM" return abbr. month names
+ * and "M" return month digits.
+ * @param DateTimeFormatInfo localized date format information.
+ * @return array localized month names.
+ */
+ protected function getLocalizedMonthNames($info)
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
+ $this->getDateFormat());
+ switch($formatter->getMonthPattern())
+ {
+ case 'MMM': return $info->getAbbreviatedMonthNames();
+ case 'MM':
+ $array = array();
+ for($i=1;$i<=12;$i++)
+ $array[$i-1] = $i < 10 ? '0'.$i : $i;
+ return $array;
+ case 'M':
+ $array = array(); for($i=1;$i<=12;$i++) $array[$i-1] = $i;
+ return $array;
+ default : return $info->getMonthNames();
+ }
+ }
+
+ /**
+ * Renders the year drop down list options.
+ * @param THtmlWriter the writer used for the rendering purpose
+ * @param mixed selected year.
+ */
+ protected function renderCalendarYearOptions($writer, $selected=null)
+ {
+ $years = array();
+ for($i = $this->getFromYear(); $i <= $this->getUpToYear(); $i++)
+ $years[$i] = $i;
+ $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'year');
+ $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'year');
+ $writer->addAttribute('class', 'datepicker_year_options');
+ if($this->getReadOnly() || !$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->renderBeginTag('select');
+ $this->renderDropDownListOptions($writer, $years, $selected);
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Gets the ID for the date picker trigger button.
+ * @return string unique button ID
+ */
+ protected function getDatePickerButtonID()
+ {
+ return $this->getClientID().'button';
+ }
+
+ /**
+ * Adds an additional button such that when clicked it shows the date picker.
+ * @return THtmlWriter writer
+ */
+ protected function renderButtonDatePicker($writer)
+ {
+ $writer->addAttribute('id', $this->getDatePickerButtonID());
+ $writer->addAttribute('type', 'button');
+ $writer->addAttribute('class', $this->getCssClass().' TDatePickerButton');
+ $writer->addAttribute('value',$this->getButtonText());
+ if(!$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->renderBeginTag("input");
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Adds an additional image button such that when clicked it shows the date picker.
+ * @return THtmlWriter writer
+ */
+ protected function renderImageButtonDatePicker($writer)
+ {
+ $url = $this->getButtonImageUrl();
+ $url = empty($url) ? $this->getAssetUrl('calendar.png') : $url;
+ $writer->addAttribute('id', $this->getDatePickerButtonID());
+ $writer->addAttribute('src', $url);
+ $writer->addAttribute('alt', ' ');
+ $writer->addAttribute('class', $this->getCssClass().' TDatePickerImageButton');
+ if(!$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->addAttribute('type', 'image');
+ $writer->addAttribute('onclick', 'return false;');
+ $writer->renderBeginTag('input');
+ $writer->renderEndTag();
+ }
+
+ /**
+ * @param string date picker asset file in the self::SCRIPT_PATH directory.
+ * @return string date picker asset url.
+ */
+ protected function getAssetUrl($file='')
+ {
+ $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
+ return $base.'/'.self::SCRIPT_PATH.'/'.$file;
+ }
+
+ /**
+ * Publish the calendar style Css asset file.
+ * @return string Css file url.
+ */
+ protected function publishCalendarStyle()
+ {
+ $url = $this->getAssetUrl($this->getCalendarStyle().'.css');
+ $cs = $this->getPage()->getClientScript();
+ if(!$cs->isStyleSheetFileRegistered($url))
+ $cs->registerStyleSheetFile($url, $url);
+ return $url;
+ }
+
+ /**
+ * Add the client id to the input textbox, and register the client scripts.
+ * @param THtmlWriter writer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ }
+
+ /**
+ * Registers the javascript code to initialize the date picker.
+ */
+ protected function registerCalendarClientScriptPre()
+ {
+ if($this->getShowCalendar())
+ {
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPradoScript("datepicker");
+ }
+ }
+
+ protected function renderClientControlScript($writer)
+ {
+ if($this->getShowCalendar())
+ {
+ $cs = $this->getPage()->getClientScript();
+ if(!$cs->isEndScriptRegistered('TDatePicker.spacer'))
+ {
+ $spacer = $this->getAssetUrl('spacer.gif');
+ $code = "Prado.WebUI.TDatePicker.spacer = '$spacer';";
+ $cs->registerEndScript('TDatePicker.spacer', $code);
+ }
+
+ $options = TJavaScript::encode($this->getDatePickerOptions());
+ $code = "new Prado.WebUI.TDatePicker($options);";
+ $cs->registerEndScript("prado:".$this->getClientID(), $code);
+ }
+ }
+}
+
+/**
+ * TDatePickerClientScript class.
+ *
+ * Client-side date picker event {@link setOnDateChanged OnDateChanged}
+ * can be modified through the {@link TDatePicker::getClientSide ClientSide}
+ * property of a date picker.
+ *
+ * The <tt>OnDateChanged</tt> event is raise when the date picker's date
+ * is changed.
+ * The formatted date according to {@link TDatePicker::getDateFormat DateFormat} is sent
+ * as parameter to this event
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDatePickerClientScript extends TClientSideOptions
+{
+ /**
+ * Javascript code to execute when the date picker's date is changed.
+ * @param string javascript code
+ */
+ public function setOnDateChanged($javascript)
+ {
+ $this->setFunction('OnDateChanged', $javascript);
+ }
+
+ /**
+ * @return string javascript code to execute when the date picker's date is changed.
+ */
+ public function getOnDateChanged()
+ {
+ return $this->getOption('OnDateChanged');
+ }
+}
+
+
+/**
+ * TDatePickerInputMode class.
+ * TDatePickerInputMode defines the enumerable type for the possible datepicker input methods.
+ *
+ * The following enumerable values are defined:
+ * - TextBox: text boxes are used to input date values
+ * - DropDownList: dropdown lists are used to pick up date values
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDatePickerInputMode extends TEnumerable
+{
+ const TextBox='TextBox';
+ const DropDownList='DropDownList';
+}
+
+/**
+ * TDatePickerMode class.
+ * TDatePickerMode defines the enumerable type for the possible UI mode
+ * that a {@link TDatePicker} control can take.
+ *
+ * The following enumerable values are defined:
+ * - Basic: Only shows a text input, focusing on the input shows the date picker
+ * - Clickable: Only shows a text input, clicking on the input shows the date picker (since 3.2)
+ * - Button: Shows a button next to the text input, clicking on the button shows the date, button text can be by the
+ * - ImageButton: Shows an image next to the text input, clicking on the image shows the date picker,
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDatePickerMode extends TEnumerable
+{
+ const Basic='Basic';
+ const Clickable='Clickable';
+ const Button='Button';
+ const ImageButton='ImageButton';
+}
+
+/**
+ * TDatePickerPositionMode class.
+ * TDatePickerPositionMode defines the positions available for the calendar popup, relative to the corresponding input.
+ *
+ * The following enumerable values are defined:
+ * - Top: the date picker is placed above the input field
+ * - Bottom: the date picker is placed below the input field
+ *
+ * @author Carl G. Mathisen <carlgmathisen@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.4
+ */
+class TDatePickerPositionMode extends TEnumerable
+{
+ const Top='Top';
+ const Bottom='Bottom';
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TDropDownList.php b/lib/prado/framework/Web/UI/WebControls/TDropDownList.php
new file mode 100644
index 0000000..0598d24
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TDropDownList.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * TDropDownList class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TListControl class
+ */
+Prado::using('System.Web.UI.WebControls.TListControl');
+
+/**
+ * TDropDownList class
+ *
+ * TDropDownList displays a dropdown list on a Web page.
+ * It inherits all properties and events from {@link TListControl}.
+ *
+ * Since v3.0.3, TDropDownList starts to support optgroup. To specify an option group for
+ * a list item, set a Group attribute with it,
+ * <code>
+ * $listitem->Attributes->Group="Group Name";
+ * // or <com:TListItem Attributes.Group="Group Name" .../> in template
+ * </code>
+ *
+ * Since v3.1.1, TDropDownList starts to support prompt text. That is, a prompt item can be
+ * displayed as the first list item by specifying either {@link setPromptText PromptText} or
+ * {@link setPromptValue PromptValue}, or both. Choosing the prompt item will unselect the TDropDownList.
+ *
+ * When a prompt item is set, its index in the list is set to -1. So, the {@link getSelectedIndex SelectedIndex}
+ * property is not affected by a prompt item: the items list will still be zero-based.
+ *
+ * The {@link clearSelection clearSelection} method will select the prompt item if existing, otherway the first
+ * available item in the dropdown list will be selected.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDropDownList extends TListControl implements IPostBackDataHandler, IValidatable
+{
+ private $_dataChanged=false;
+ private $_isValid=true;
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $writer->addAttribute('name',$this->getUniqueID());
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TDropDownList';
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if(!$this->getEnabled(true))
+ return false;
+ $this->ensureDataBound();
+ $selection=isset($values[$key])?$values[$key]:null;
+ if($selection!==null)
+ {
+ $index=$this->getItems()->findIndexByValue($selection,false);
+ if($this->getSelectedIndex()!==$index)
+ {
+ $this->setSelectedIndex($index);
+ return $this->_dataChanged=true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method is required by {@link IPostBackDataHandler} interface.
+ * It is invoked by the framework when {@link getSelectedIndex SelectedIndex} property
+ * is changed on postback.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ if($this->getAutoPostBack() && $this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onSelectedIndexChanged(null);
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * @throws TNotSupportedException if this method is invoked
+ */
+ public function setSelectedIndices($indices)
+ {
+ throw new TNotSupportedException('dropdownlist_selectedindices_unsupported');
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getSelectedValue();
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TDropDownListColumn.php b/lib/prado/framework/Web/UI/WebControls/TDropDownListColumn.php
new file mode 100644
index 0000000..507dafd
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TDropDownListColumn.php
@@ -0,0 +1,319 @@
+<?php
+/**
+ * TDropDownListColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+Prado::using('System.Web.UI.WebControls.TDropDownList');
+
+/**
+ * TDropDownListColumn class
+ *
+ * TDropDownListColumn represents a column that is bound to a field in a data source.
+ * The cells in the column will be displayed using the data indexed by
+ * {@link setDataTextField DataTextField}. You can customize the display by
+ * setting {@link setDataTextFormatString DataTextFormatString}.
+ *
+ * If {@link setReadOnly ReadOnly} is false, TDropDownListColumn will display cells in edit mode
+ * with dropdown lists. Otherwise, a static text is displayed.
+ * The currently selected dropndown list item is specified by the data indexed with
+ * {@link setDataValueField DataValueField}.
+ *
+ * There are two approaches to specify the list items available for selection.
+ * The first approach uses template syntax as follows,
+ * <code>
+ * <com:TDropDownListColumn ....>
+ * <com:TListItem Value="1" Text="first item" />
+ * <com:TListItem Value="2" Text="second item" />
+ * <com:TListItem Value="3" Text="third item" />
+ * </com:TDropDownListColumn>
+ * </code>
+ * The second approach specifies a data source to be bound to the dropdown lists
+ * by setting {@link setListDataSource ListDataSource}. Like generic list controls,
+ * you may also want to specify which data fields are used for item values and texts
+ * by setting {@link setListValueField ListValueField} and
+ * {@link setListTextField ListTextField}, respectively.
+ * Furthermore, the item texts may be formatted by using {@link setListTextFormatString ListTextFormatString}.
+ * Note, if you specify {@link setListDataSource ListDataSource}, do it before
+ * calling the datagrid's dataBind().
+ *
+ * The dropdown list control in the TDropDownListColumn can be accessed by one of
+ * the following two methods:
+ * <code>
+ * $datagridItem->DropDownListColumnID->DropDownList
+ * $datagridItem->DropDownListColumnID->Controls[0]
+ * </code>
+ * The second method is possible because the dropdown list control created within the
+ * datagrid cell is the first child.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDropDownListColumn extends TDataGridColumn
+{
+ private $_stateLoaded=false;
+ private $_dataBound=false;
+ private $_listControl=null;
+
+ public function __construct()
+ {
+ $this->_listControl=new TDropDownList;
+ }
+
+ /**
+ * Loads items from viewstate.
+ * This method overrides the parent implementation by loading list items
+ * @param mixed state values
+ */
+ public function loadState($state)
+ {
+ parent::loadState($state);
+ $this->_stateLoaded=true;
+ if(!$this->_dataBound)
+ $this->_listControl->getItems()->loadState($this->getViewState('Items',null));
+ }
+
+ /**
+ * Saves items into viewstate.
+ * This method overrides the parent implementation by saving list items
+ */
+ public function saveState()
+ {
+ $this->setViewState('Items',$this->_listControl->getItems()->saveState(),null);
+ return parent::saveState();
+ }
+
+ /**
+ * Adds object parsed from template to the control.
+ * This method adds only {@link TListItem} objects into the {@link getItems Items} collection.
+ * All other objects are ignored.
+ * @param mixed object parsed from template
+ */
+ public function addParsedObject($object)
+ {
+ // Do not add items from template if items are loaded from viewstate
+ if(!$this->_stateLoaded && ($object instanceof TListItem))
+ {
+ $object->setSelected(false);
+ $index=$this->_listControl->getItems()->add($object);
+ }
+ }
+
+ /**
+ * @return string the field of the data source that provides the text content of the column.
+ */
+ public function getDataTextField()
+ {
+ return $this->getViewState('DataTextField','');
+ }
+
+ /**
+ * Sets the field of the data source that provides the text content of the column.
+ * If this is not set, the data specified via {@link getDataValueField DataValueField}
+ * will be displayed in the column.
+ * @param string the field of the data source that provides the text content of the column.
+ */
+ public function setDataTextField($value)
+ {
+ $this->setViewState('DataTextField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the bound data will be displayed.
+ */
+ public function getDataTextFormatString()
+ {
+ return $this->getViewState('DataTextFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the bound data will be displayed.
+ */
+ public function setDataTextFormatString($value)
+ {
+ $this->setViewState('DataTextFormatString',$value,'');
+ }
+
+ /**
+ * @return string the field of the data source that provides the key selecting an item in dropdown list.
+ */
+ public function getDataValueField()
+ {
+ return $this->getViewState('DataValueField','');
+ }
+
+ /**
+ * Sets the field of the data source that provides the key selecting an item in dropdown list.
+ * If this is not present, the data specified via {@link getDataTextField DataTextField} (without
+ * applying the formatting string) will be used for selection, instead.
+ * @param string the field of the data source that provides the key selecting an item in dropdown list.
+ */
+ public function setDataValueField($value)
+ {
+ $this->setViewState('DataValueField',$value,'');
+ }
+
+ /**
+ * @return boolean whether the items in the column can be edited. Defaults to false.
+ */
+ public function getReadOnly()
+ {
+ return $this->getViewState('ReadOnly',false);
+ }
+
+ /**
+ * @param boolean whether the items in the column can be edited
+ */
+ public function setReadOnly($value)
+ {
+ $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return Traversable data source to be bound to the dropdown list boxes.
+ */
+ public function getListDataSource()
+ {
+ return $this->_listControl->getDataSource();
+ }
+
+ /**
+ * @param Traversable|array|string data source to be bound to the dropdown list boxes.
+ */
+ public function setListDataSource($value)
+ {
+ $this->_listControl->setDataSource($value);
+ }
+
+ /**
+ * @return string the data field used to populate the values of the dropdown list items. Defaults to empty.
+ */
+ public function getListValueField()
+ {
+ return $this->getViewState('ListValueField','');
+ }
+
+ /**
+ * @param string the data field used to populate the values of the dropdown list items
+ */
+ public function setListValueField($value)
+ {
+ $this->setViewState('ListValueField',$value,'');
+ }
+
+ /**
+ * @return string the data field used to populate the texts of the dropdown list items. Defaults to empty.
+ */
+ public function getListTextField()
+ {
+ return $this->getViewState('ListTextField','');
+ }
+
+ /**
+ * @param string the data field used to populate the texts of the dropdown list items
+ */
+ public function setListTextField($value)
+ {
+ $this->setViewState('ListTextField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the list item texts will be displayed.
+ */
+ public function getListTextFormatString()
+ {
+ return $this->getViewState('ListTextFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the list item texts will be displayed.
+ */
+ public function setListTextFormatString($value)
+ {
+ $this->setViewState('ListTextFormatString',$value,'');
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates a textbox for item in edit mode and the column is not read-only.
+ * Otherwise it displays a static text.
+ * The caption of the button and the static text are retrieved
+ * from the datasource.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if(!$this->_dataBound && $this->_listControl->getDataSource()!==null)
+ {
+ $this->_listControl->setDataTextField($this->getListTextField());
+ $this->_listControl->setDataValueField($this->getListValueField());
+ $this->_listControl->setDataTextFormatString($this->getListTextFormatString());
+ $this->_listControl->dataBind();
+ $this->_dataBound=true;
+ }
+ switch($itemType)
+ {
+ case TListItemType::EditItem:
+ if(!$this->getReadOnly())
+ {
+ $listControl=clone $this->_listControl;
+ $cell->getControls()->add($listControl);
+ $cell->registerObject('DropDownList',$listControl);
+ $control=$listControl;
+ }
+ else
+ $control=$cell;
+ $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ break;
+ case TListItemType::Item:
+ case TListItemType::AlternatingItem:
+ case TListItemType::SelectedItem:
+ if($this->getDataTextField()!=='' || $this->getDataValueField()!=='')
+ $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ break;
+ default:
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ break;
+ }
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $data=$item->getData();
+ if(($valueField=$this->getDataValueField())!=='')
+ $value=$this->getDataFieldValue($data,$valueField);
+ else
+ $value='';
+ if(($textField=$this->getDataTextField())!=='')
+ {
+ $text=$this->getDataFieldValue($data,$textField);
+ if($valueField==='')
+ $value=$text;
+ $formatString=$this->getDataTextFormatString();
+ $text=$this->formatDataValue($formatString,$text);
+ }
+ else
+ $text=$value;
+ if($sender instanceof TTableCell)
+ $sender->setText($text);
+ else if($sender instanceof TDropDownList)
+ $sender->setSelectedValue($value);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TEditCommandColumn.php b/lib/prado/framework/Web/UI/WebControls/TEditCommandColumn.php
new file mode 100644
index 0000000..36e188f
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TEditCommandColumn.php
@@ -0,0 +1,263 @@
+<?php
+/**
+ * TEditCommandColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+
+/**
+ * TEditCommandColumn class
+ *
+ * TEditCommandColumn contains the Edit command buttons for editing data items in each row.
+ *
+ * TEditCommandColumn will create an edit button if a cell is not in edit mode.
+ * Otherwise an update button and a cancel button will be created within the cell.
+ * The button captions are specified using {@link setEditText EditText},
+ * {@link setUpdateText UpdateText}, and {@link setCancelText CancelText}.
+ *
+ * The buttons in the column can be set to display as hyperlinks, push or image buttons
+ * by setting the {@link setButtonType ButtonType} property.
+ *
+ * When an edit button is clicked, the datagrid will generate an
+ * {@link onEditCommand OnEditCommand} event. When an update/cancel button
+ * is clicked, the datagrid will generate an
+ * {@link onUpdateCommand OnUpdateCommand} or an {@link onCancelCommand OnCancelCommand}
+ * You can write these event handlers to change the state of specific datagrid item.
+ *
+ * The {@link setCausesValidation CausesValidation} and {@link setValidationGroup ValidationGroup}
+ * properties affect the corresponding properties of the edit and update buttons.
+ * The cancel button does not cause validation by default.
+ *
+ * The command buttons in the column can be accessed by one of the following methods:
+ * <code>
+ * $datagridItem->ButtonColumnID->EditButton (or UpdateButton, CancelButton)
+ * $datagridItem->ButtonColumnID->Controls[0]
+ * </code>
+ * The second method is possible because the button control created within the
+ * datagrid cell is the first child.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TEditCommandColumn extends TDataGridColumn
+{
+ /**
+ * @return TButtonColumnType the type of command button. Defaults to TButtonColumnType::LinkButton.
+ */
+ public function getButtonType()
+ {
+ return $this->getViewState('ButtonType',TButtonColumnType::LinkButton);
+ }
+
+ /**
+ * @param TButtonColumnType the type of command button.
+ */
+ public function setButtonType($value)
+ {
+ $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonColumnType'),TButtonColumnType::LinkButton);
+ }
+
+ /**
+ * @return string the caption of the edit button. Defaults to 'Edit'.
+ */
+ public function getEditText()
+ {
+ return $this->getViewState('EditText','Edit');
+ }
+
+ /**
+ * @param string the caption of the edit button
+ */
+ public function setEditText($value)
+ {
+ $this->setViewState('EditText',$value,'Edit');
+ }
+
+ /**
+ * @return string the URL of the image file for edit image buttons
+ */
+ public function getEditImageUrl()
+ {
+ return $this->getViewState('EditImageUrl','');
+ }
+
+ /**
+ * @param string the URL of the image file for edit image buttons
+ */
+ public function setEditImageUrl($value)
+ {
+ $this->setViewState('EditImageUrl',$value,'');
+ }
+
+ /**
+ * @return string the caption of the update button. Defaults to 'Update'.
+ */
+ public function getUpdateText()
+ {
+ return $this->getViewState('UpdateText','Update');
+ }
+
+ /**
+ * @param string the caption of the update button
+ */
+ public function setUpdateText($value)
+ {
+ $this->setViewState('UpdateText',$value,'Update');
+ }
+
+ /**
+ * @return string the URL of the image file for update image buttons
+ */
+ public function getUpdateImageUrl()
+ {
+ return $this->getViewState('UpdateImageUrl','');
+ }
+
+ /**
+ * @param string the URL of the image file for update image buttons
+ */
+ public function setUpdateImageUrl($value)
+ {
+ $this->setViewState('UpdateImageUrl',$value,'');
+ }
+
+ /**
+ * @return string the caption of the cancel button. Defaults to 'Cancel'.
+ */
+ public function getCancelText()
+ {
+ return $this->getViewState('CancelText','Cancel');
+ }
+
+ /**
+ * @param string the caption of the cancel button
+ */
+ public function setCancelText($value)
+ {
+ $this->setViewState('CancelText',$value,'Cancel');
+ }
+
+ /**
+ * @return string the URL of the image file for cancel image buttons
+ */
+ public function getCancelImageUrl()
+ {
+ return $this->getViewState('CancelImageUrl','');
+ }
+
+ /**
+ * @param string the URL of the image file for cancel image buttons
+ */
+ public function setCancelImageUrl($value)
+ {
+ $this->setViewState('CancelImageUrl',$value,'');
+ }
+
+ /**
+ * @return boolean whether postback event trigger by edit or update button will cause input validation, default is true
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by edit or update button will cause input validation
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the group of validators which the edit or update button causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the edit or update button causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates an update and a cancel button for cell in edit mode.
+ * Otherwise it creates an edit button.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem)
+ {
+ $button=$this->createButton('Edit',$this->getEditText(),false,'');
+ $cell->getControls()->add($button);
+ $cell->registerObject('EditButton',$button);
+ }
+ else if($itemType===TListItemType::EditItem)
+ {
+ $controls=$cell->getControls();
+ $button=$this->createButton('Update',$this->getUpdateText(),$this->getCausesValidation(),$this->getValidationGroup());
+ $controls->add($button);
+ $cell->registerObject('UpdateButton',$button);
+ $controls->add('&nbsp;');
+ $button=$this->createButton('Cancel',$this->getCancelText(),false,'');
+ $controls->add($button);
+ $cell->registerObject('CancelButton',$button);
+ }
+ else
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ }
+
+ /**
+ * Creates a button and initializes its properties.
+ * The button type is determined by {@link getButtonType ButtonType}.
+ * @param string command name associated with the button
+ * @param string button caption
+ * @param boolean whether the button should cause validation
+ * @param string the validation group that the button belongs to
+ * @return mixed the newly created button.
+ */
+ protected function createButton($commandName,$text,$causesValidation,$validationGroup)
+ {
+ if($this->getButtonType()===TButtonColumnType::LinkButton)
+ $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton');
+ else if($this->getButtonType()===TButtonColumnType::PushButton)
+ $button=Prado::createComponent('System.Web.UI.WebControls.TButton');
+ else // image buttons
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton');
+ if(strcasecmp($commandName,'Update')===0)
+ $url=$this->getUpdateImageUrl();
+ else if(strcasecmp($commandName,'Cancel')===0)
+ $url=$this->getCancelImageUrl();
+ else
+ $url=$this->getEditImageUrl();
+ $button->setImageUrl($url);
+ }
+ $button->setText($text);
+ $button->setCommandName($commandName);
+ $button->setCausesValidation($causesValidation);
+ $button->setValidationGroup($validationGroup);
+ return $button;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TEmailAddressValidator.php b/lib/prado/framework/Web/UI/WebControls/TEmailAddressValidator.php
new file mode 100644
index 0000000..bb95372
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TEmailAddressValidator.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * TEmailAddressValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TRegularExpressionValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TRegularExpressionValidator');
+
+/**
+ * TEmailAddressValidator class
+ *
+ * TEmailAddressValidator validates whether the value of an associated
+ * input component is a valid email address. If {@link getCheckMXRecord CheckMXRecord}
+ * is true, it will check MX record for the email adress, provided
+ * checkdnsrr() is available in the installed PHP.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TEmailAddressValidator extends TRegularExpressionValidator
+{
+ /**
+ * Regular expression used to validate the email address
+ * @see http://www.regular-expressions.info/email.html
+ */
+ const EMAIL_REGEXP='[a-zA-Z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?';
+
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TEmailAddressValidator';
+ }
+
+ /**
+ * @return string the regular expression that determines the pattern used to validate a field.
+ */
+ public function getRegularExpression()
+ {
+ $regex=parent::getRegularExpression();
+ return $regex===''?self::EMAIL_REGEXP:$regex;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ public function evaluateIsValid()
+ {
+ $value=$this->getValidationValue($this->getValidationTarget());
+ $valid=$valid=is_string($value) && strlen($value)<=254 && parent::evaluateIsValid();
+
+ if($valid && $this->getCheckMXRecord() && function_exists('checkdnsrr'))
+ {
+ if($value!=='')
+ {
+ if(($pos=strpos($value,'@'))!==false)
+ {
+ $domain=substr($value,$pos+1);
+ return $domain===''?false:checkdnsrr($domain,'MX');
+ }
+ else
+ return false;
+ }
+ }
+ return $valid;
+ }
+
+ /**
+ * @return boolean whether to check MX record for the email address being validated. Defaults to true.
+ */
+ public function getCheckMXRecord()
+ {
+ return $this->getViewState('CheckMXRecord',false);
+ }
+
+ /**
+ * @param boolean whether to check MX record for the email address being validated.
+ * Note, if {@link checkdnsrr} is not available, this check will not be performed.
+ */
+ public function setCheckMXRecord($value)
+ {
+ $this->setViewState('CheckMXRecord',TPropertyValue::ensureBoolean($value),false);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TExpression.php b/lib/prado/framework/Web/UI/WebControls/TExpression.php
new file mode 100644
index 0000000..57bbb59
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TExpression.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * TExpression class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TExpression class
+ *
+ * TExpression evaluates a PHP expression and renders the result.
+ * The expression is evaluated during the rendering stage. The expression being
+ * evaluated can be set via the property {@link setExpression Expression}.
+ * The context of the expression evaluated is the TExpression object itself.
+ *
+ * Note, since TExpression allows evaluation of arbitrary PHP expression,
+ * make sure {@link setExpression Expression} does not come directly from user input.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TExpression extends TControl
+{
+ /**
+ * @var string PHP expression to be evaluated
+ */
+ private $_e='';
+
+ /**
+ * @return string the expression to be evaluated
+ */
+ public function getExpression()
+ {
+ return $this->_e;
+ }
+
+ /**
+ * @param string the expression to be evaluated
+ */
+ public function setExpression($value)
+ {
+ $this->_e=$value;
+ }
+
+ /**
+ * Renders the evaluation result of the expression.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->_e!=='')
+ $writer->write($this->evaluateExpression($this->_e));
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TFileUpload.php b/lib/prado/framework/Web/UI/WebControls/TFileUpload.php
new file mode 100644
index 0000000..c8853c5
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TFileUpload.php
@@ -0,0 +1,279 @@
+<?php
+/**
+ * TFileUpload class file
+ *
+ * @author Marcus Nyeholt <tanus@users.sourceforge.net>, Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TFileUpload class
+ *
+ * TFileUpload displays a file upload field on a page. Upon postback,
+ * the text entered into the field will be treated as the name of the file
+ * that will be uploaded to the server. The property {@link getHasFile HasFile}
+ * indicates whether the file upload is successful. If successful, the file
+ * may be obtained by calling {@link saveAs} to save it at a specified place.
+ * You can use {@link getFileName FileName}, {@link getFileType FileType},
+ * {@link getFileSize FileSize} to get the original client-side file name,
+ * the file mime type, and the file size information. If the upload is not
+ * successful, {@link getErrorCode ErrorCode} contains the error code
+ * describing the cause of failure.
+ *
+ * TFileUpload raises {@link onFileUpload OnFileUpload} event if a file is uploaded
+ * (whether it succeeds or not).
+ *
+ * @author Marcus Nyeholt <tanus@users.sourceforge.net>, Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TFileUpload extends TWebControl implements IPostBackDataHandler, IValidatable
+{
+ /**
+ * Maximum file size (in bytes) allowed to be uploaded, defaults to 1MB.
+ */
+ const MAX_FILE_SIZE=1048576;
+ /**
+ * @var integer the size of the uploaded file (in bytes)
+ */
+ private $_fileSize=0;
+ /**
+ * @var string The original name of the file on the client machine
+ */
+ private $_fileName='';
+ /**
+ * @var string the name of the temporary file storing the uploaded file
+ */
+ private $_localName='';
+ /**
+ * @var string the uploaded file mime type
+ */
+ private $_fileType='';
+ /**
+ * @var integer error code of the current file upload
+ */
+ protected $_errorCode=UPLOAD_ERR_NO_FILE;
+ private $_dataChanged=false;
+ private $_isValid=true;
+
+ /**
+ * @return string tag name of the file upload control
+ */
+ protected function getTagName()
+ {
+ return 'input';
+ }
+
+ /**
+ * Sets name attribute to the unique ID of the control.
+ * This method overrides the parent implementation with additional file update control specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $this->getPage()->ensureRenderInForm($this);
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('type','file');
+ $writer->addAttribute('name',$this->getUniqueID());
+ $isEnabled=$this->getEnabled(true);
+ if(!$isEnabled && $this->getEnabled()) // in this case parent will not render 'disabled'
+ $writer->addAttribute('disabled','disabled');
+ }
+
+ /**
+ * Sets Enctype of the form on the page.
+ * This method overrides the parent implementation and is invoked before render.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ if(($form=$this->getPage()->getForm())!==null)
+ $form->setEnctype('multipart/form-data');
+ $this->getPage()->getClientScript()->registerHiddenField('MAX_FILE_SIZE',$this->getMaxFileSize());
+ if($this->getEnabled(true))
+ $this->getPage()->registerRequiresPostData($this);
+ }
+
+ /**
+ * @return integer the maximum file size, defaults to 1MB (1048576 bytes).
+ * @see setMaxFileSize
+ */
+ public function getMaxFileSize()
+ {
+ return $this->getViewState('MaxFileSize',self::MAX_FILE_SIZE);
+ }
+
+ /**
+ * Sets the maximum size that a file can be uploaded.
+ * Note, this is an advisory value to the browser. Sets this property with
+ * a reasonably large size to save users the trouble of waiting
+ * for a big file being transferred only to find that it was too big
+ * and the transfer failed.
+ * @param int the maximum upload size allowed for a file.
+ */
+ public function setMaxFileSize($size)
+ {
+ $this->setViewState('MaxFileSize',TPropertyValue::ensureInteger($size),self::MAX_FILE_SIZE);
+ }
+
+ /**
+ * @return string the original full path name of the file on the client machine
+ */
+ public function getFileName()
+ {
+ return $this->_fileName;
+ }
+
+ /**
+ * @return integer the actual size of the uploaded file in bytes
+ */
+ public function getFileSize()
+ {
+ return $this->_fileSize;
+ }
+
+ /**
+ * @return string the MIME-type of the uploaded file (such as "image/gif").
+ * This mime type is not checked on the server side and do not take its value for granted.
+ */
+ public function getFileType()
+ {
+ return $this->_fileType;
+ }
+
+ /**
+ * @return string the local name of the file (where it is after being uploaded).
+ * Note, PHP will delete this file automatically after finishing this round of request.
+ */
+ public function getLocalName()
+ {
+ return $this->_localName;
+ }
+
+ /**
+ * Returns an error code describing the status of this file uploading.
+ * @return integer the error code
+ * @see http://www.php.net/manual/en/features.file-upload.errors.php
+ */
+ public function getErrorCode()
+ {
+ return $this->_errorCode;
+ }
+
+ /**
+ * @return boolean whether the file is uploaded successfully
+ */
+ public function getHasFile()
+ {
+ return $this->_errorCode===UPLOAD_ERR_OK;
+ }
+
+ /**
+ * Saves the uploaded file.
+ * @param string the file name used to save the uploaded file
+ * @param boolean whether to delete the temporary file after saving.
+ * If true, you will not be able to save the uploaded file again.
+ * @return boolean true if the file saving is successful
+ */
+ public function saveAs($fileName,$deleteTempFile=true)
+ {
+ if($this->_errorCode===UPLOAD_ERR_OK)
+ {
+ if($deleteTempFile)
+ return move_uploaded_file($this->_localName,$fileName);
+ else if(is_uploaded_file($this->_localName))
+ return file_put_contents($fileName,file_get_contents($this->_localName))!==false;
+ else
+ return false;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if(isset($_FILES[$key]))
+ {
+ $this->_fileName=$_FILES[$key]['name'];
+ $this->_fileSize=$_FILES[$key]['size'];
+ $this->_fileType=$_FILES[$key]['type'];
+ $this->_errorCode=$_FILES[$key]['error'];
+ $this->_localName=$_FILES[$key]['tmp_name'];
+ return $this->_dataChanged=true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method calls {@link onFileUpload} method.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ $this->onFileUpload(null);
+ }
+
+ /**
+ * This method is invoked when a file is uploaded during a postback.
+ * The method raises <b>OnFileUpload</b> event to fire up the event handler.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event delegates can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onFileUpload($param)
+ {
+ $this->raiseEvent('OnFileUpload',$this,$param);
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Returns the original file name as the property value to be validated.
+ * This method is required by IValidatable property.
+ * @return mixed the property value to be validated
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getFileName();
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TFlushOutput.php b/lib/prado/framework/Web/UI/WebControls/TFlushOutput.php
new file mode 100644
index 0000000..a88b91f
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TFlushOutput.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * TFlushOutput class file
+ *
+ * @author Berczi Gabor <gabor.berczi@devworx.hu>
+ * @link https://github.com/pradosoft/prado
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TFlushOutput class.
+ *
+ * TFlushOutput enables forced flushing of the current output buffer
+ * at (a) certain point(s) in the page, after rendering of all previous
+ * controls has been completed.
+ *
+ * To use TFlushOutput, simply place it in a template where you want
+ * the have the output buffered between the start of the page or the
+ * last TFlushOutput to be sent to the client immediately
+ * <code>
+ * <com:TFlushOutput />
+ * </code>
+ *
+ * You can specify whether you want to keep buffering of the output
+ * (if it was enabled) till the next occourence of a <com: TFlushOutput />
+ * or the end of the page rendering, or stop buffering, by using the
+ * {@link setContinueBuffering ContinueBuffering}.
+ *
+ * @author Berczi Gabor <gabor.berczi@devworx.hu>
+ * @package System.Web.UI.WebControls
+ * @since 3.1
+ */
+class TFlushOutput extends TControl
+{
+ /**
+ * @var boolean whether to continue buffering of output
+ */
+ private $_continueBuffering=true;
+
+
+ /**
+ * Constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->EnableViewState = false;
+ }
+
+ /**
+ * @return Tells whether buffering of output can continue after this point
+ */
+ public function getContinueBuffering()
+ {
+ return $this->_continueBuffering;
+ }
+
+ /**
+ * @param boolean sets whether buffering of output can continue after this point
+ */
+ public function setContinueBuffering($value)
+ {
+ $this->_continueBuffering = TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * Flushes the output of all completely rendered controls to the client.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+//$writer->write('<!-- flush -->');
+ // ajax responses can't be parsed by the client side before loaded and returned completely,
+ // so don't bother with flushing output somewhere mid-page if refreshing in a callback
+ if (!$this->Page->IsCallback)
+ {
+ $this->Page->flushWriter();
+// $this->Application->flushOutput($this->ContinueBuffering);
+ }
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TFont.php b/lib/prado/framework/Web/UI/WebControls/TFont.php
new file mode 100644
index 0000000..52a5db7
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TFont.php
@@ -0,0 +1,316 @@
+<?php
+/**
+ * TFont class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TFont class
+ *
+ * TFont encapsulates the CSS style fields related with font settings.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TFont extends TComponent
+{
+ /**
+ * Bits indicating the font states.
+ */
+ const IS_BOLD=0x01;
+ const IS_ITALIC=0x02;
+ const IS_OVERLINE=0x04;
+ const IS_STRIKEOUT=0x08;
+ const IS_UNDERLINE=0x10;
+
+ /**
+ * Bits indicating whether particular font states are changed.
+ */
+ const IS_SET_BOLD=0x01000;
+ const IS_SET_ITALIC=0x02000;
+ const IS_SET_OVERLINE=0x04000;
+ const IS_SET_STRIKEOUT=0x08000;
+ const IS_SET_UNDERLINE=0x10000;
+ const IS_SET_SIZE=0x20000;
+ const IS_SET_NAME=0x40000;
+
+ /**
+ * @var integer bits representing various states
+ */
+ private $_flags=0;
+ /**
+ * @var string font name
+ */
+ private $_name='';
+ /**
+ * @var string font size
+ */
+ private $_size='';
+
+ /**
+ * @return boolean whether the font is in bold face. Defaults to false.
+ */
+ public function getBold()
+ {
+ return ($this->_flags & self::IS_BOLD)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is in bold face
+ */
+ public function setBold($value)
+ {
+ $this->_flags |= self::IS_SET_BOLD;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_BOLD;
+ else
+ $this->_flags &= ~self::IS_BOLD;
+ }
+
+ /**
+ * @return boolean whether the font is in italic face. Defaults to false.
+ */
+ public function getItalic()
+ {
+ return ($this->_flags & self::IS_ITALIC)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is italic
+ */
+ public function setItalic($value)
+ {
+ $this->_flags |= self::IS_SET_ITALIC;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_ITALIC;
+ else
+ $this->_flags &= ~self::IS_ITALIC;
+ }
+
+ /**
+ * @return boolean whether the font is overlined. Defaults to false.
+ */
+ public function getOverline()
+ {
+ return ($this->_flags & self::IS_OVERLINE)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is overlined
+ */
+ public function setOverline($value)
+ {
+ $this->_flags |= self::IS_SET_OVERLINE;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_OVERLINE;
+ else
+ $this->_flags &= ~self::IS_OVERLINE;
+ }
+
+ /**
+ * @return string the font size
+ */
+ public function getSize()
+ {
+ return $this->_size;
+ }
+
+ /**
+ * @param string the font size
+ */
+ public function setSize($value)
+ {
+ $this->_flags |= self::IS_SET_SIZE;
+ $this->_size=$value;
+ }
+
+ /**
+ * @return boolean whether the font is strikeout. Defaults to false.
+ */
+ public function getStrikeout()
+ {
+ return ($this->_flags & self::IS_STRIKEOUT)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is strikeout
+ */
+ public function setStrikeout($value)
+ {
+ $this->_flags |= self::IS_SET_STRIKEOUT;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_STRIKEOUT;
+ else
+ $this->_flags &= ~self::IS_STRIKEOUT;
+ }
+
+ /**
+ * @return boolean whether the font is underlined. Defaults to false.
+ */
+ public function getUnderline()
+ {
+ return ($this->_flags & self::IS_UNDERLINE)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is underlined
+ */
+ public function setUnderline($value)
+ {
+ $this->_flags |= self::IS_SET_UNDERLINE;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_UNDERLINE;
+ else
+ $this->_flags &= ~self::IS_UNDERLINE;
+ }
+
+ /**
+ * @return string the font name (family)
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @param string the font name (family)
+ */
+ public function setName($value)
+ {
+ $this->_flags |= self::IS_SET_NAME;
+ $this->_name=$value;
+ }
+
+ /**
+ * @return boolean whether the font is empty
+ */
+ public function getIsEmpty()
+ {
+ return !$this->_flags;
+ }
+
+ /**
+ * Clears up the font.
+ */
+ public function reset()
+ {
+ $this->_flags=0;
+ $this->_name='';
+ $this->_size='';
+ }
+
+ /**
+ * Merges the font with a new one.
+ * If a font field is not set in the font, it will be overwritten with
+ * the new one.
+ * @param TFont the new font
+ */
+ public function mergeWith($font)
+ {
+ if($font===null || $font->_flags===0)
+ return;
+ if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
+ $this->setBold($font->getBold());
+ if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
+ $this->setItalic($font->getItalic());
+ if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
+ $this->setOverline($font->getOverline());
+ if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
+ $this->setStrikeout($font->getStrikeout());
+ if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
+ $this->setUnderline($font->getUnderline());
+ if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
+ $this->setSize($font->getSize());
+ if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
+ $this->setName($font->getName());
+ }
+
+ /**
+ * Copies the fields in a new font to this font.
+ * If a font field is set in the new font, the corresponding field
+ * in this font will be overwritten.
+ * @param TFont the new font
+ */
+ public function copyFrom($font)
+ {
+ if($font===null || $font->_flags===0)
+ return;
+ if($font->_flags & self::IS_SET_BOLD)
+ $this->setBold($font->getBold());
+ if($font->_flags & self::IS_SET_ITALIC)
+ $this->setItalic($font->getItalic());
+ if($font->_flags & self::IS_SET_OVERLINE)
+ $this->setOverline($font->getOverline());
+ if($font->_flags & self::IS_SET_STRIKEOUT)
+ $this->setStrikeout($font->getStrikeout());
+ if($font->_flags & self::IS_SET_UNDERLINE)
+ $this->setUnderline($font->getUnderline());
+ if($font->_flags & self::IS_SET_SIZE)
+ $this->setSize($font->getSize());
+ if($font->_flags & self::IS_SET_NAME)
+ $this->setName($font->getName());
+ }
+
+ /**
+ * @return string the font in a css style string representation.
+ */
+ public function toString()
+ {
+ if($this->_flags===0)
+ return '';
+ $str='';
+ if($this->_flags & self::IS_SET_BOLD)
+ $str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
+ if($this->_flags & self::IS_SET_ITALIC)
+ $str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
+ $textDec='';
+ if($this->_flags & self::IS_UNDERLINE)
+ $textDec.='underline';
+ if($this->_flags & self::IS_OVERLINE)
+ $textDec.=' overline';
+ if($this->_flags & self::IS_STRIKEOUT)
+ $textDec.=' line-through';
+ $textDec=ltrim($textDec);
+ if($textDec!=='')
+ $str.='text-decoration:'.$textDec.';';
+ if($this->_size!=='')
+ $str.='font-size:'.$this->_size.';';
+ if($this->_name!=='')
+ $str.='font-family:'.$this->_name.';';
+ return $str;
+ }
+
+ /**
+ * Adds attributes related to CSS styles to renderer.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function addAttributesToRender($writer)
+ {
+ if($this->_flags===0)
+ return;
+ if($this->_flags & self::IS_SET_BOLD)
+ $writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
+ if($this->_flags & self::IS_SET_ITALIC)
+ $writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
+ $textDec='';
+ if($this->_flags & self::IS_UNDERLINE)
+ $textDec.='underline';
+ if($this->_flags & self::IS_OVERLINE)
+ $textDec.=' overline';
+ if($this->_flags & self::IS_STRIKEOUT)
+ $textDec.=' line-through';
+ $textDec=ltrim($textDec);
+ if($textDec!=='')
+ $writer->addStyleAttribute('text-decoration',$textDec);
+ if($this->_size!=='')
+ $writer->addStyleAttribute('font-size',$this->_size);
+ if($this->_name!=='')
+ $writer->addStyleAttribute('font-family',$this->_name);
+ }
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/THead.php b/lib/prado/framework/Web/UI/WebControls/THead.php
new file mode 100644
index 0000000..c7c9b57
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/THead.php
@@ -0,0 +1,372 @@
+<?php
+/**
+ * THead class file
+ *
+ * @author Marcus Nyeholt <tanus@users.sourceforge.net> and Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI
+ */
+
+/**
+ * THead class
+ *
+ * THead displays a head element on a page. It displays the content
+ * enclosed in its body and the page title set by the
+ * {@link setTitle Title} property. In addition, stylesheets and JavaScripts registered via
+ * {@link TClientScriptManager::registerStyleSheet}, {@link TClientScriptManager::registerStyleSheetFile}
+ * {@link TClientScriptManager::registerHeadJavaScript}, and
+ * {@link TClientScriptManager::registerHeadJavaScriptFile} will also be displayed
+ * in the head.
+ * THead also manages and displays meta tags through its {@link getMetaTags MetaTags}
+ * property. You can add a meta object to the collection in code dynamically,
+ * or add it in template using the following syntax,
+ * <code>
+ * <com:THead>
+ * <com:TMetaTag HttpEquiv="Pragma" Content="no-cache" />
+ * <com:TMetaTag Name="keywords" Content="Prado" />
+ * </com:THead>
+ * </code>
+ *
+ * Note, {@link TPage} has a property {@link TPage::getHead Head} that refers to
+ * the THead control currently on the page. A page can have at most one THead
+ * control. Although not required, it is recommended to place a THead on your page.
+ * Without a THead on the page, stylesheets and javascripts in the current page
+ * theme will not be rendered.
+ *
+ * @author Marcus Nyeholt <tanus@users.sourceforge.net> and Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class THead extends TControl
+{
+ /**
+ * @var TList list of meta name tags to be loaded by {@link THead}
+ */
+ private $_metaTags=null;
+
+ /**
+ * Registers the head control with the current page.
+ * This method is invoked when the control enters 'Init' stage.
+ * The method raises 'Init' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $this->getPage()->setHead($this);
+ }
+
+ /**
+ * Processes an object that is created during parsing template.
+ * This method adds TMetaTag components into the {@link getMetaTags MetaTags}
+ * collection of the head control.
+ * @param string|TComponent text string or component parsed and instantiated in template
+ * @see createdOnTemplate
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TMetaTag)
+ $this->getMetaTags()->add($object);
+ else
+ parent::addParsedObject($object);
+ }
+
+ /**
+ * @return string the page title.
+ */
+ public function getTitle()
+ {
+ return $this->getViewState('Title','');
+ }
+
+ /**
+ * Sets the page title.
+ * This title will be rendered only if the {@link TPage::getTitle Title} property
+ * of the page is empty.
+ * @param string the page title.
+ */
+ public function setTitle($value)
+ {
+ $this->setViewState('Title',$value,'');
+ }
+
+ /**
+ * @return string base URL of the page. This URL is rendered as the 'href' attribute of <base> tag. Defaults to ''.
+ */
+ public function getBaseUrl()
+ {
+ return $this->getViewState('BaseUrl','');
+ }
+
+ /**
+ * @param string base URL of the page. This URL is rendered as the 'href' attribute of <base> tag.
+ */
+ public function setBaseUrl($url)
+ {
+ $this->setViewState('BaseUrl',$url,'');
+ }
+
+ /**
+ * @return string the URL for the shortcut icon of the page. Defaults to ''.
+ */
+ public function getShortcutIcon()
+ {
+ return $this->getViewState('ShortcutIcon','');
+ }
+
+ /**
+ * @param string the URL for the shortcut icon of the page.
+ */
+ public function setShortcutIcon($url)
+ {
+ $this->setViewState('ShortcutIcon',$url,'');
+ }
+
+ /**
+ * @return TMetaTagCollection meta tag collection
+ */
+ public function getMetaTags()
+ {
+ if(($metaTags=$this->getViewState('MetaTags',null))===null)
+ {
+ $metaTags=new TMetaTagCollection;
+ $this->setViewState('MetaTags',$metaTags,null);
+ }
+ return $metaTags;
+ }
+
+ /**
+ * Renders the head control.
+ * @param THtmlWriter the writer for rendering purpose.
+ */
+ public function render($writer)
+ {
+ $page=$this->getPage();
+ $title=$this->getTitle();
+ $writer->write("<head>\n<title>".THttpUtility::htmlEncode($title)."</title>\n");
+ if(($baseUrl=$this->getBaseUrl())!=='')
+ $writer->write('<base href="'.$baseUrl."\" />\n");
+ if(($icon=$this->getShortcutIcon())!=='')
+ $writer->write('<link rel="shortcut icon" href="'.$icon."\" />\n");
+
+ if(($metaTags=$this->getMetaTags())!==null)
+ {
+ foreach($metaTags as $metaTag)
+ {
+ $metaTag->render($writer);
+ $writer->writeLine();
+ }
+ }
+ $cs=$page->getClientScript();
+ $cs->renderStyleSheetFiles($writer);
+ $cs->renderStyleSheets($writer);
+ if($page->getClientSupportsJavaScript())
+ {
+ $cs->renderHeadScriptFiles($writer);
+ $cs->renderHeadScripts($writer);
+ }
+ parent::render($writer);
+ $writer->write("</head>\n");
+ }
+}
+
+/**
+ * TMetaTag class.
+ *
+ * TMetaTag represents a meta tag appearing in a page head section.
+ * You can set its {@link setID ID}, {@link setHttpEquiv HttpEquiv},
+ * {@link setName Name}, {@link setContent Content}, {@link setScheme Scheme}
+ * properties, which correspond to id, http-equiv, name, content, and scheme
+ * attributes for a meta tag, respectively.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TMetaTag extends TComponent
+{
+ /**
+ * @var string id of the meta tag
+ */
+ private $_id='';
+ /**
+ * @var string http-equiv attribute of the meta tag
+ */
+ private $_httpEquiv='';
+ /**
+ * @var string name attribute of the meta tag
+ */
+ private $_name='';
+ /**
+ * @var string content attribute of the meta tag
+ */
+ private $_content='';
+ /**
+ * @var string scheme attribute of the meta tag
+ */
+ private $_scheme='';
+
+ /**
+ * @return string id of the meta tag
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * @param string id of the meta tag
+ */
+ public function setID($value)
+ {
+ $this->_id=$value;
+ }
+
+ /**
+ * @return string http-equiv attribute of the meta tag
+ */
+ public function getHttpEquiv()
+ {
+ return $this->_httpEquiv;
+ }
+
+ /**
+ * @param string http-equiv attribute of the meta tag
+ */
+ public function setHttpEquiv($value)
+ {
+ $this->_httpEquiv=$value;
+ }
+
+ /**
+ * @return string name attribute of the meta tag
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @param string name attribute of the meta tag
+ */
+ public function setName($value)
+ {
+ $this->_name=$value;
+ }
+
+ /**
+ * @return string content attribute of the meta tag
+ */
+ public function getContent()
+ {
+ return $this->_content;
+ }
+
+ /**
+ * @param string content attribute of the meta tag
+ */
+ public function setContent($value)
+ {
+ $this->_content=$value;
+ }
+
+ /**
+ * @return string scheme attribute of the meta tag
+ */
+ public function getScheme()
+ {
+ return $this->_scheme;
+ }
+
+ /**
+ * @param string scheme attribute of the meta tag
+ */
+ public function setScheme($value)
+ {
+ $this->_scheme=$value;
+ }
+
+ /**
+ * Renders the meta tag.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->_id!=='')
+ $writer->addAttribute('id',$this->_id);
+ if($this->_name!=='')
+ $writer->addAttribute('name',$this->_name);
+ if($this->_httpEquiv!=='')
+ $writer->addAttribute('http-equiv',$this->_httpEquiv);
+ if($this->_scheme!=='')
+ $writer->addAttribute('scheme',$this->_scheme);
+ $writer->addAttribute('content',$this->_content);
+ $writer->renderBeginTag('meta');
+ $writer->renderEndTag();
+ }
+}
+
+
+/**
+ * TMetaTagCollection class
+ *
+ * TMetaTagCollection represents a collection of meta tags
+ * contained in a {@link THead} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TMetaTagCollection extends TList
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing type
+ * check on the item being added.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TMetaTag}
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TMetaTag)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('metatagcollection_metatag_invalid');
+ }
+
+ /**
+ * Finds the lowest cardinal index of the meta tag whose id is the one being looked for.
+ * @param string the ID of the meta tag to be looked for
+ * @return integer the index of the meta tag found, -1 if not found.
+ */
+ public function findIndexByID($id)
+ {
+ $index=0;
+ foreach($this as $item)
+ {
+ if($item->getID()===$id)
+ return $index;
+ $index++;
+ }
+ return -1;
+ }
+
+ /**
+ * Finds the item whose value is the one being looked for.
+ * @param string the id of the meta tag to be looked for
+ * @return TMetaTag the meta tag found, null if not found.
+ */
+ public function findMetaTagByID($id)
+ {
+ if(($index=$this->findIndexByID($id))>=0)
+ return $this->itemAt($index);
+ else
+ return null;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/THeader1.php b/lib/prado/framework/Web/UI/WebControls/THeader1.php
new file mode 100644
index 0000000..5eee499
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/THeader1.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * THeader1 class file
+ *
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * THeader1 class
+ *
+ * This is a simple class to enable your application to have headers but then have your
+ * theme be able to redefine the TagName
+ * This is also useful for the {@link TWebControlDecorator} (used by themes).
+ *
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.2a
+ */
+
+class THeader1 extends THtmlElement {
+
+ /**
+ * @return string tag name
+ */
+ public function getDefaultTagName()
+ {
+ return 'h1';
+ }
+
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/THeader2.php b/lib/prado/framework/Web/UI/WebControls/THeader2.php
new file mode 100644
index 0000000..c54b52f
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/THeader2.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * THeader2 class file
+ *
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * THeader2 class
+ *
+ * This is a simple class to enable your application to have headers but then have your
+ * theme be able to redefine the TagName
+ * This is also useful for the {@link TWebControlDecorator} (used by themes).
+ *
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.2a
+ */
+
+class THeader2 extends THtmlElement {
+
+ /**
+ * @return string tag name
+ */
+ public function getDefaultTagName()
+ {
+ return 'h2';
+ }
+
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/THeader3.php b/lib/prado/framework/Web/UI/WebControls/THeader3.php
new file mode 100644
index 0000000..ef89e02
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/THeader3.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * THeader3 class file
+ *
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * THeader3 class
+ *
+ * This is a simple class to enable your application to have headers but then have your
+ * theme be able to redefine the TagName
+ * This is also useful for the {@link TWebControlDecorator} (used by themes).
+ *
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.2a
+ */
+
+class THeader3 extends THtmlElement {
+
+ /**
+ * @return string tag name
+ */
+ public function getDefaultTagName()
+ {
+ return 'h3';
+ }
+
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/THeader4.php b/lib/prado/framework/Web/UI/WebControls/THeader4.php
new file mode 100644
index 0000000..d2dada4
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/THeader4.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * THeader4 class file
+ *
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * THeader4 class
+ *
+ * This is a simple class to enable your application to have headers but then have your
+ * theme be able to redefine the TagName
+ * This is also useful for the {@link TWebControlDecorator} (used by themes).
+ *
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+
+class THeader4 extends THtmlElement {
+
+ /**
+ * @return string tag name
+ */
+ public function getDefaultTagName()
+ {
+ return 'h4';
+ }
+
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/THeader5.php b/lib/prado/framework/Web/UI/WebControls/THeader5.php
new file mode 100644
index 0000000..582567d
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/THeader5.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * THeader5 class file
+ *
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * THeader5 class
+ *
+ * This is a simple class to enable your application to have headers but then have your
+ * theme be able to redefine the TagName
+ * This is also useful for the {@link TWebControlDecorator} (used by themes).
+ *
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+
+class THeader5 extends THtmlElement {
+
+ /**
+ * @return string tag name
+ */
+ public function getDefaultTagName()
+ {
+ return 'h5';
+ }
+
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/THeader6.php b/lib/prado/framework/Web/UI/WebControls/THeader6.php
new file mode 100644
index 0000000..ae876f8
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/THeader6.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * THeader6 class file
+ *
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * THeader6 class
+ *
+ * This is a simple class to enable your application to have headers but then have your
+ * theme be able to redefine the TagName
+ * This is also useful for the {@link TWebControlDecorator} (used by themes).
+ *
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+
+class THeader6 extends THtmlElement {
+
+ /**
+ * @return string tag name
+ */
+ public function getDefaultTagName()
+ {
+ return 'h6';
+ }
+
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/THiddenField.php b/lib/prado/framework/Web/UI/WebControls/THiddenField.php
new file mode 100644
index 0000000..8ea1c5b
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/THiddenField.php
@@ -0,0 +1,222 @@
+<?php
+/**
+ * THiddenField class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.xisc.com/
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * THiddenField class
+ *
+ * THiddenField displays a hidden input field on a Web page.
+ * The value of the input field can be accessed via {@link getValue Value} property.
+ * If upon postback the value is changed, a {@link onValueChanged OnValueChanged}
+ * event will be raised.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class THiddenField extends TControl implements IPostBackDataHandler, IValidatable, IDataRenderer
+{
+ private $_dataChanged=false;
+ private $_isValid=true;
+
+ /**
+ * @return string tag name of the hidden field.
+ */
+ protected function getTagName()
+ {
+ return 'input';
+ }
+
+ /**
+ * Sets focus to this control.
+ * This method overrides the parent implementation by forbidding setting focus to this control.
+ */
+ public function focus()
+ {
+ throw new TNotSupportedException('hiddenfield_focus_unsupported');
+ }
+
+ /**
+ * Renders the control.
+ * This method overrides the parent implementation by rendering
+ * the hidden field input element.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ $uniqueID=$this->getUniqueID();
+ $this->getPage()->ensureRenderInForm($this);
+ $writer->addAttribute('type','hidden');
+ if($uniqueID!=='')
+ $writer->addAttribute('name',$uniqueID);
+ if($this->getID()!=='')
+ $writer->addAttribute('id',$this->getClientID());
+ if(($value=$this->getValue())!=='')
+ $writer->addAttribute('value',$value);
+
+ if($this->getHasAttributes())
+ {
+ foreach($this->getAttributes() as $name=>$value)
+ $writer->addAttribute($name,$value);
+ }
+
+ $writer->renderBeginTag('input');
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Loads hidden field data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ $value=$values[$key];
+ if($value===$this->getValue())
+ return false;
+ else
+ {
+ $this->setValue($value);
+ return $this->_dataChanged=true;
+ }
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getValue();
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method calls {@link onValueChanged} method.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ $this->onValueChanged(null);
+ }
+
+ /**
+ * This method is invoked when the value of the {@link getValue Value} property changes between posts to the server.
+ * The method raises 'OnValueChanged' event to fire up the event delegates.
+ * If you override this method, be sure to call the parent implementation
+ * so that the attached event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onValueChanged($param)
+ {
+ $this->raiseEvent('OnValueChanged',$this,$param);
+ }
+
+ /**
+ * @return string the value of the THiddenField
+ */
+ public function getValue()
+ {
+ return $this->getViewState('Value','');
+ }
+
+ /**
+ * Sets the value of the THiddenField
+ * @param string the value to be set
+ */
+ public function setValue($value)
+ {
+ $this->setViewState('Value',$value,'');
+ }
+
+ /**
+ * Returns the value of the hidden field.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getValue()}.
+ * @return string value of the hidden field
+ * @see getValue
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getValue();
+ }
+
+ /**
+ * Sets the value of the hidden field.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setValue()}.
+ * @param string value of the hidden field
+ * @see setValue
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setValue($value);
+ }
+
+
+ /**
+ * @return boolean whether theming is enabled for this control. Defaults to false.
+ */
+ public function getEnableTheming()
+ {
+ return false;
+ }
+
+ /**
+ * @param boolean whether theming is enabled for this control.
+ * @throws TNotSupportedException This method is always thrown when calling this method.
+ */
+ public function setEnableTheming($value)
+ {
+ throw new TNotSupportedException('hiddenfield_theming_unsupported');
+ }
+
+ /**
+ * @param string Skin ID
+ * @throws TNotSupportedException This method is always thrown when calling this method.
+ */
+ public function setSkinID($value)
+ {
+ throw new TNotSupportedException('hiddenfield_skinid_unsupported');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/THtmlArea.php b/lib/prado/framework/Web/UI/WebControls/THtmlArea.php
new file mode 100644
index 0000000..7fc5969
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/THtmlArea.php
@@ -0,0 +1,535 @@
+<?php
+/**
+ * THtmlArea class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTextBox class
+ */
+Prado::using('System.Web.UI.WebControls.TTextBox');
+
+/**
+ * THtmlArea class
+ *
+ * THtmlArea wraps the visual editting functionalities provided by the
+ * TinyMCE project {@link http://tinymce.moxiecode.com/}.
+ *
+ * THtmlArea displays a WYSIWYG text area on the Web page for user input
+ * in the HTML format. The text displayed in the THtmlArea component is
+ * specified or determined by using the <b>Text</b> property.
+ *
+ * To enable the visual editting on the client side, set the property
+ * <b>EnableVisualEdit</b> to true (which is default value).
+ * To set the size of the editor when the visual editting is enabled,
+ * set the <b>Width</b> and <b>Height</b> properties instead of
+ * <b>Columns</b> and <b>Rows</b> because the latter has no meaning
+ * under the situation.
+ *
+ * The default editor gives only the basic tool bar. To change or add
+ * additional tool bars, use the {@link setOptions Options} property to add additional
+ * editor options with each options on a new line.
+ * See http://tinymce.moxiecode.com/tinymce/docs/index.html
+ * for a list of options. The options can be change/added as shown in the
+ * following example.
+ * <code>
+ * <com:THtmlArea>
+ * <prop:Options>
+ * plugins : "contextmenu,paste"
+ * language : "zh_cn"
+ * </prop:Options>
+ * </com:THtmlArea>
+ * </code>
+ *
+ * Compatibility
+ * The client-side visual editting capability is supported by
+ * Internet Explorer 5.0+ for Windows and Gecko-based browser.
+ * If the browser does not support the visual editting,
+ * a traditional textarea will be displayed.
+ *
+ * Browser support
+ *
+ * <code>
+ * Windows XP MacOS X 10.4
+ * ----------------------------------------------------
+ * MSIE 6 OK
+ * MSIE 5.5 SP2 OK
+ * MSIE 5.0 OK
+ * Mozilla 1.7.x OK OK
+ * Firefox 1.0.x OK OK
+ * Firefox 1.5b2 OK OK
+ * Safari 2.0 (412) OK(1)
+ * Opera 9 Preview 1 OK(1) OK(1)
+ * ----------------------------------------------------
+ * * (1) - Partialy working
+ * ----------------------------------------------------
+ * </code>
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class THtmlArea extends TTextBox
+{
+ /**
+ * @var array list of locale => language file pairs.
+ */
+ private static $_langs = array(
+ 'ar' => 'ar',
+ 'az' => 'az',
+ 'be' => 'be',
+ 'bg' => 'bg',
+ 'bn' => 'bn',
+ 'br' => 'br',
+ 'bs' => 'bs',
+ 'ca' => 'ca',
+ 'ch' => 'ch',
+ 'cn' => 'cn',
+ 'cs' => 'cs',
+ 'cy' => 'cy',
+ 'da' => 'da',
+ 'de' => 'de',
+ 'dv' => 'dv',
+ 'el' => 'el',
+ 'en' => 'en',
+ 'eo' => 'eo',
+ 'es' => 'es',
+ 'et' => 'et',
+ 'eu' => 'eu',
+ 'fa' => 'fa',
+ 'fi' => 'fi',
+ 'fr' => 'fr',
+ 'gl' => 'gl',
+ 'gu' => 'gu',
+ 'he' => 'he',
+ 'hi' => 'hi',
+ 'hr' => 'hr',
+ 'hu' => 'hu',
+ 'hy' => 'hy',
+ 'ia' => 'ia',
+ 'id' => 'id',
+ 'is' => 'is',
+ 'it' => 'it',
+ 'ja' => 'ja',
+ 'ka' => 'ka',
+ 'kl' => 'kl',
+ 'km' => 'km',
+ 'ko' => 'ko',
+ 'lb' => 'lb',
+ 'lt' => 'lt',
+ 'lv' => 'lv',
+ 'mk' => 'mk',
+ 'ml' => 'ml',
+ 'mn' => 'mn',
+ 'ms' => 'ms',
+ 'my' => 'my',
+ 'nb' => 'nb',
+ 'nl' => 'nl',
+ 'nn' => 'nn',
+ 'no' => 'no',
+ 'pl' => 'pl',
+ 'ps' => 'ps',
+ 'pt' => 'pt',
+ 'ro' => 'ro',
+ 'ru' => 'ru',
+ 'sc' => 'sc',
+ 'se' => 'se',
+ 'si' => 'si',
+ 'sk' => 'sk',
+ 'sl' => 'sl',
+ 'sq' => 'sq',
+ 'sr' => 'sr',
+ 'sv' => 'sv',
+ 'ta' => 'ta',
+ 'te' => 'te',
+ 'th' => 'th',
+ 'tn' => 'tn',
+ 'tr' => 'tr',
+ 'tt' => 'tt',
+ 'tw' => 'tw',
+ 'uk' => 'vi',
+ 'ur' => 'vi',
+ 'vi' => 'vi',
+ 'zh_CN' => 'zh-cn',
+ 'zh_TW' => 'zh-tw',
+ 'zh' => 'zh',
+ 'zu' => 'zu',
+ );
+
+ /**
+ * @var array list of default plugins to load, override using getAvailablePlugins();
+ */
+ private static $_plugins = array(
+ 'advhr',
+ 'advimage',
+ 'advlink',
+ 'advlist',
+ 'autolink',
+ 'autoresize',
+ 'autosave',
+ 'bbcode',
+ 'contextmenu',
+ 'directionality',
+ 'emotions',
+ 'example',
+ 'fullpage',
+ 'fullscreen',
+ 'iespell',
+ 'inlinepopups',
+ 'insertdatetime',
+ 'layer',
+ 'legacyoutput',
+ 'lists',
+ 'media',
+ 'nonbreaking',
+ 'noneditable',
+ 'pagebreak',
+ 'paste',
+ 'preview',
+ 'print',
+ 'save',
+ 'searchreplace',
+ 'spellchecker',
+ 'style',
+ 'tabfocus',
+ 'table',
+ 'template',
+ 'visualchars',
+ 'wordc',
+ 'wordcount',
+ 'xhtmlxtras'
+ );
+
+ /**
+ * @var array default themes to load
+ */
+ private static $_themes = array(
+ 'simple',
+ 'advanced'
+ );
+
+ /**
+ * Constructor.
+ * Sets default width and height.
+ */
+ public function __construct()
+ {
+ $this->setWidth('470px');
+ $this->setHeight('250px');
+ }
+
+ /**
+ * Overrides the parent implementation.
+ * TextMode for THtmlArea control is always 'MultiLine'
+ * @return string the behavior mode of the THtmlArea component.
+ */
+ public function getTextMode()
+ {
+ return 'MultiLine';
+ }
+
+ /**
+ * Overrides the parent implementation.
+ * TextMode for THtmlArea is always 'MultiLine' and cannot be changed to others.
+ * @param string the text mode
+ */
+ public function setTextMode($value)
+ {
+ throw new TInvalidOperationException("htmlarea_textmode_readonly");
+ }
+
+ /**
+ * @return boolean whether change of the content should cause postback. Return false if EnableVisualEdit is true.
+ */
+ public function getAutoPostBack()
+ {
+ return $this->getEnableVisualEdit() ? false : parent::getAutoPostBack();
+ }
+
+ /**
+ * @return boolean whether to show WYSIWYG text editor. Defaults to true.
+ */
+ public function getEnableVisualEdit()
+ {
+ return $this->getViewState('EnableVisualEdit',true);
+ }
+
+ /**
+ * Sets whether to show WYSIWYG text editor.
+ * @param boolean whether to show WYSIWYG text editor
+ */
+ public function setEnableVisualEdit($value)
+ {
+ $this->setViewState('EnableVisualEdit',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Gets the current culture.
+ * @return string current culture, e.g. en_AU.
+ */
+ public function getCulture()
+ {
+ return $this->getViewState('Culture', '');
+ }
+
+ /**
+ * Sets the culture/language for the html area
+ * @param string a culture string, e.g. en_AU.
+ */
+ public function setCulture($value)
+ {
+ $this->setViewState('Culture', $value, '');
+ }
+
+ /**
+ * Gets the list of options for the WYSIWYG (TinyMCE) editor
+ * @see http://tinymce.moxiecode.com/tinymce/docs/index.html
+ * @return string options
+ */
+ public function getOptions()
+ {
+ return $this->getViewState('Options', '');
+ }
+
+ /**
+ * Sets the list of options for the WYSIWYG (TinyMCE) editor
+ * @see http://tinymce.moxiecode.com/tinymce/docs/index.html
+ * @param string options
+ */
+ public function setOptions($value)
+ {
+ $this->setViewState('Options', $value, '');
+ }
+
+ /**
+ * @param string path to custom plugins to be copied.
+ */
+ public function setCustomPluginPath($value)
+ {
+ $this->setViewState('CustomPluginPath', $value);
+ }
+
+ /**
+ * @return string path to custom plugins to be copied.
+ */
+ public function getCustomPluginPath()
+ {
+ return $this->getViewState('CustomPluginPath');
+ }
+
+ /**
+ * @return boolean enable compression of the javascript files, default is true.
+ */
+ public function getEnableCompression()
+ {
+ return $this->getViewState('EnableCompression', true);
+ }
+
+ /**
+ * @param boolean enable compression of the javascript files, default is true.
+ */
+ public function setEnableCompression($value)
+ {
+ $this->setViewState('EnableCompression', TPropertyValue::ensureBoolean($value));
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This method overrides the parent implementation by registering
+ * additional javacript code.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ if($this->getEnableVisualEdit() && $this->getEnabled(true))
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $this->registerEditorClientScript($writer);
+ }
+
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Returns a list of plugins to be loaded.
+ * Override this method to customize.
+ * @return array list of plugins to be loaded
+ */
+ public function getAvailablePlugins()
+ {
+ return self::$_plugins;
+ }
+
+ /**
+ * @return array list of available themese
+ */
+ public function getAvailableThemes()
+ {
+ return self::$_themes;
+ }
+
+ protected function getCompressionOptions()
+ {
+ return array(
+ 'plugins' => implode(',', $this->getAvailablePlugins()),
+ 'themes' => implode(',', $this->getAvailableThemes()),
+ 'languages' => $this->getLanguageSuffix($this->getCulture()),
+ 'disk_cache' => true,
+ 'debug' => false
+ );
+ }
+
+ protected function loadJavascriptLibrary()
+ {
+ $scripts = $this->getPage()->getClientScript();
+ $scripts->registerPradoScript('htmlarea');
+ $scripts->registerScriptFile('prado:THtmlArea', $this->getScriptUrl());
+ }
+
+ /**
+ * Registers the editor javascript file and code to initialize the editor.
+ */
+ protected function registerEditorClientScript($writer)
+ {
+ $this->loadJavascriptLibrary();
+ $scripts = $this->getPage()->getClientScript();
+ $options = array(
+ 'EditorOptions' => $this->getEditorOptions()
+ );
+ if($this->getEnableCompression())
+ $options['CompressionOptions'] = $this->getCompressionOptions();
+
+ $options = TJavaScript::encode($options,true,true);
+ $script = "new {$this->getClientClassName()}($options)";
+ $scripts->registerEndScript('prado:THtmlArea'.$this->ClientID,$script);
+ }
+
+ /**
+ * @return string editor script URL.
+ */
+ protected function getScriptUrl()
+ {
+ if($this->getEnableCompression())
+ return $this->getScriptDeploymentPath().'/tiny_mce/tiny_mce_gzip.js';
+ else
+ return $this->getScriptDeploymentPath().'/tiny_mce/tiny_mce.js';
+ }
+
+ /**
+ * Gets the editor script base URL by publishing the tarred source via TTarAssetManager.
+ * @return string URL base path to the published editor script
+ */
+ protected function getScriptDeploymentPath()
+ {
+ $tarfile = Prado::getPathOfNamespace('System.3rdParty.TinyMCE.tiny_mce', '.tar');
+ $md5sum = Prado::getPathOfNamespace('System.3rdParty.TinyMCE.tiny_mce', '.md5');
+ if($tarfile===null || $md5sum===null)
+ throw new TConfigurationException('htmlarea_tarfile_invalid');
+ $url = $this->getApplication()->getAssetManager()->publishTarFile($tarfile, $md5sum);
+ $this->copyCustomPlugins($url);
+ return $url;
+ }
+
+ protected function copyCustomPlugins($url)
+ {
+ if($plugins = $this->getCustomPluginPath())
+ {
+ $assets = $this->getApplication()->getAssetManager();
+ $path = is_dir($plugins) ? $plugins : Prado::getPathOfNameSpace($plugins);
+ $dest = $assets->getBasePath().'/'.basename($url).'/tiny_mce/plugins/';
+ if(!is_dir($dest) || $this->getApplication()->getMode()!==TApplicationMode::Performance)
+ $assets->copyDirectory($path, $dest);
+ }
+ }
+
+ /**
+ * Default editor options gives basic tool bar only.
+ * @return array editor initialization options.
+ */
+ protected function getEditorOptions()
+ {
+ $options['mode'] = 'exact';
+ $options['elements'] = $this->getClientID();
+ $options['language'] = $this->getLanguageSuffix($this->getCulture());
+ $options['theme'] = 'advanced';
+
+ //make it basic advanced to fit into 1 line of buttons.
+ //$options['theme_advanced_buttons1'] = 'bold,italic,underline,strikethrough,separator,justifyleft,justifycenter,justifyright, justifyfull,separator,bullist,numlist,separator,undo,redo,separator,link,unlink,separator,charmap,separator,code,help';
+ //$options['theme_advanced_buttons2'] = ' ';
+ $options['theme_advanced_buttons1'] = 'formatselect,fontselect,fontsizeselect,separator,bold,italic,underline,strikethrough,sub,sup';
+ $options['theme_advanced_buttons2'] = 'justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,separator,outdent,indent,separator,forecolor,backcolor,separator,hr,link,unlink,image,charmap,separator,removeformat,code,help';
+ $options['theme_advanced_buttons3'] = '';
+
+ $options['theme_advanced_toolbar_location'] = 'top';
+ $options['theme_advanced_toolbar_align'] = 'left';
+ $options['theme_advanced_path_location'] = 'bottom';
+ $options['extended_valid_elements'] = 'a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]';
+ if($this->getReadOnly())
+ $options['readonly'] = true;
+
+ $options = array_merge($options, $this->parseEditorOptions($this->getOptions()));
+ return $options;
+ }
+
+ /**
+ * Parse additional options set in the Options property.
+ * @return array additional custom options
+ */
+ protected function parseEditorOptions($string)
+ {
+ $options = array();
+ $substrings = preg_split('/,\s*\n|\n/', trim($string));
+ foreach($substrings as $bits)
+ {
+ $option = explode(":",$bits,2);
+
+ if(count($option) == 2)
+ {
+ $value=trim(trim($option[1]),"'\"");
+ if (($s=strtolower($value))==='false')
+ $value=false;
+ elseif ($s==='true')
+ $value=true;
+ $options[trim($option[0])] = $value;
+ }
+ }
+ return $options;
+ }
+
+ /**
+ * @return string localized editor interface language extension.
+ */
+ protected function getLanguageSuffix($culture)
+ {
+ $app = $this->getApplication()->getGlobalization();
+ if(empty($culture) && ($app!==null))
+ $culture = $app->getCulture();
+ $variants = array();
+ if($app!==null)
+ $variants = $app->getCultureVariants($culture);
+
+ foreach($variants as $variant)
+ {
+ if(isset(self::$_langs[$variant]))
+ return self::$_langs[$variant];
+ }
+
+ return 'en';
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.THtmlArea';
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/THtmlArea4.php b/lib/prado/framework/Web/UI/WebControls/THtmlArea4.php
new file mode 100644
index 0000000..9485150
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/THtmlArea4.php
@@ -0,0 +1,479 @@
+<?php
+/**
+ * THtmlArea4 class file.
+ *
+ * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTextBox class
+ */
+Prado::using('System.Web.UI.WebControls.TTextBox');
+
+/**
+ * THtmlArea4 class
+ *
+ * THtmlArea4 wraps the visual editing functionalities provided by the
+ * version 4 of TinyMCE project {@link http://tinymce.com/}. It has been
+ * developed as a plug'n'play substitute for {@link THtmlArea}, that is
+ * based on the previous iteration (version 3) of the same project.
+ * Please note that both components can't be used together in the same page.
+ *
+ * THtmlArea displays a WYSIWYG text area on the Web page for user input
+ * in the HTML format. The text displayed in the THtmlArea component is
+ * specified or determined by using the <b>Text</b> property.
+ *
+ * To enable the visual editting on the client side, set the property
+ * <b>EnableVisualEdit</b> to true (which is default value).
+ * To set the size of the editor when the visual editting is enabled,
+ * set the <b>Width</b> and <b>Height</b> properties instead of
+ * <b>Columns</b> and <b>Rows</b> because the latter has no meaning
+ * under the situation.
+ *
+ * The default editor gives only the basic tool bar. To change or add
+ * additional tool bars, use the {@link setOptions Options} property to add additional
+ * editor options with each options on a new line.
+ * See http://www.tinymce.com/wiki.php/Configuration
+ * for a list of options. The options can be change/added as shown in the
+ * following example.
+ * <code>
+ * <com:THtmlArea>
+ * <prop:Options>
+ * language : "de"
+ * plugins: [ advlist anchor autolink autoresize autosave bbcode charmap code contextmenu directionality emoticons fullpage fullscreen hr image importcss insertdatetime layer legacyoutput link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor visualblocks visualchars wordcount ]
+ * toolbar: "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media",
+ * statusbar: false
+ * </prop:Options>
+ * </com:THtmlArea>
+ * </code>
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class THtmlArea4 extends TTextBox
+{
+ /**
+ * @var array list of locale => language file pairs.
+ */
+ private static $_langs = array(
+ 'ar' => 'ar',
+ 'bg_BG' => 'bg_BG',
+ 'bs' => 'bs',
+ 'ca' => 'ca',
+ 'cs' => 'cs',
+ 'cy' => 'cy',
+ 'da' => 'da',
+ 'de' => 'de',
+ 'de_AT' => 'de_AT',
+ 'el' => 'el',
+ 'es' => 'es',
+ 'et' => 'et',
+ 'eu' => 'eu',
+ 'fa' => 'fa',
+ 'fi' => 'fi',
+ 'fo' => 'fo',
+ 'fr_FR' => 'fr_FR',
+ 'gl' => 'gl',
+ 'he_IL' => 'he_IL',
+ 'hr' => 'hr',
+ 'hu_HU' => 'hu_HU',
+ 'id' => 'id',
+ 'it' => 'it',
+ 'ja' => 'ja',
+ 'ka_GE' => 'ka_GE',
+ 'ko_KR' => 'ko_KR',
+ 'lb' => 'lb',
+ 'lt' => 'lt',
+ 'lv' => 'lv',
+ 'nb_NO' => 'nb_NO',
+ 'nl' => 'nl',
+ 'pl' => 'pl',
+ 'pt_BR' => 'pt_BR',
+ 'pt_PT' => 'pt_PT',
+ 'ro' => 'ro',
+ 'ru' => 'ru',
+ 'si_LK' => 'si_LK',
+ 'sk' => 'sk',
+ 'sl_SI' => 'sl_SI',
+ 'sr' => 'sr',
+ 'sv_SE' => 'sv_SE',
+ 'ta' => 'ta',
+ 'ta_IN' => 'ta_IN',
+ 'th_TH' => 'th_TH',
+ 'tr_TR' => 'tr_TR',
+ 'ug' => 'ug',
+ 'uk' => 'uk',
+ 'uk_UA' => 'uk_UA',
+ 'vi' => 'vi',
+ 'vi_VN' => 'vi_VN',
+ 'zh_CN' => 'zh_CN',
+ 'zh_TW' => 'zh_TW',
+ );
+
+ /**
+ * @var array list of default plugins to load, override using getAvailablePlugins();
+ */
+ private static $_plugins = array(
+ 'advlist',
+ 'anchor',
+ 'autolink',
+ 'autoresize',
+ 'autosave',
+ 'bbcode',
+ 'charmap',
+ 'code',
+ 'contextmenu',
+ 'directionality',
+ 'emoticons',
+ 'fullpage',
+ 'fullscreen',
+ 'hr',
+ 'image',
+ 'importcss',
+ 'insertdatetime',
+ 'layer',
+ 'legacyoutput',
+ 'link',
+ 'lists',
+ 'media',
+ 'nonbreaking',
+ 'noneditable',
+ 'pagebreak',
+ 'paste',
+ 'preview',
+ 'print',
+ 'save',
+ 'searchreplace',
+ 'spellchecker',
+ 'tabfocus',
+ 'table',
+ 'template',
+ 'textcolor',
+ 'visualblocks',
+ 'visualchars',
+ 'wordcount',
+ );
+
+ /**
+ * @var array default themes to load
+ */
+ private static $_themes = array(
+ 'modern',
+ );
+
+ /**
+ * Constructor.
+ * Sets default width and height.
+ */
+ public function __construct()
+ {
+ $this->setWidth('600px');
+ $this->setHeight('250px');
+ }
+
+ /**
+ * Overrides the parent implementation.
+ * TextMode for THtmlArea control is always 'MultiLine'
+ * @return string the behavior mode of the THtmlArea component.
+ */
+ public function getTextMode()
+ {
+ return 'MultiLine';
+ }
+
+ /**
+ * Overrides the parent implementation.
+ * TextMode for THtmlArea is always 'MultiLine' and cannot be changed to others.
+ * @param string the text mode
+ */
+ public function setTextMode($value)
+ {
+ throw new TInvalidOperationException("htmlarea_textmode_readonly");
+ }
+
+ /**
+ * @return boolean whether change of the content should cause postback. Return false if EnableVisualEdit is true.
+ */
+ public function getAutoPostBack()
+ {
+ return $this->getEnableVisualEdit() ? false : parent::getAutoPostBack();
+ }
+
+ /**
+ * @return boolean whether to show WYSIWYG text editor. Defaults to true.
+ */
+ public function getEnableVisualEdit()
+ {
+ return $this->getViewState('EnableVisualEdit',true);
+ }
+
+ /**
+ * Sets whether to show WYSIWYG text editor.
+ * @param boolean whether to show WYSIWYG text editor
+ */
+ public function setEnableVisualEdit($value)
+ {
+ $this->setViewState('EnableVisualEdit',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Gets the current culture.
+ * @return string current culture, e.g. de_AT.
+ */
+ public function getCulture()
+ {
+ return $this->getViewState('Culture', '');
+ }
+
+ /**
+ * Sets the culture/language for the html area
+ * @param string a culture string, e.g. de_AT.
+ */
+ public function setCulture($value)
+ {
+ $this->setViewState('Culture', $value, '');
+ }
+
+ /**
+ * Gets the list of options for the WYSIWYG (TinyMCE) editor
+ * @see http://www.tinymce.com/wiki.php/Configuration
+ * @return string options
+ */
+ public function getOptions()
+ {
+ return $this->getViewState('Options', '');
+ }
+
+ /**
+ * Sets the list of options for the WYSIWYG (TinyMCE) editor
+ * @see http://www.tinymce.com/wiki.php/Configuration
+ * @param string options
+ */
+ public function setOptions($value)
+ {
+ $this->setViewState('Options', $value, '');
+ }
+
+ /**
+ * @param string path to custom plugins to be copied.
+ */
+ public function setCustomPluginPath($value)
+ {
+ $this->setViewState('CustomPluginPath', $value);
+ }
+
+ /**
+ * @return string path to custom plugins to be copied.
+ */
+ public function getCustomPluginPath()
+ {
+ return $this->getViewState('CustomPluginPath');
+ }
+
+ /**
+ * @return boolean enable compression of the javascript files, default is true.
+ * @deprecated since 3.2.3: tinyMCE 4 doesn't support this anymore
+ */
+ public function getEnableCompression()
+ {
+ return $this->getViewState('EnableCompression', true);
+ }
+
+ /**
+ * @param boolean enable compression of the javascript files, default is true.
+ * @deprecated since 3.2.3: tinyMCE 4 doesn't support this anymore
+ */
+ public function setEnableCompression($value)
+ {
+ $this->setViewState('EnableCompression', TPropertyValue::ensureBoolean($value));
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This method overrides the parent implementation by registering
+ * additional javacript code.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ if($this->getEnableVisualEdit() && $this->getEnabled(true))
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $this->registerEditorClientScript($writer);
+ }
+
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Returns a list of plugins to be loaded.
+ * Override this method to customize.
+ * @return array list of plugins to be loaded
+ */
+ public function getAvailablePlugins()
+ {
+ return self::$_plugins;
+ }
+
+ /**
+ * @return array list of available themese
+ */
+ public function getAvailableThemes()
+ {
+ return self::$_themes;
+ }
+
+ /**
+ * @deprecated since 3.2.3. tinyMCE4 doesn's use this anymore
+ */
+ protected function getCompressionOptions()
+ {
+ return array();
+ }
+
+ protected function loadJavascriptLibrary()
+ {
+ $scripts = $this->getPage()->getClientScript();
+ $scripts->registerPradoScript('htmlarea4');
+ $scripts->registerScriptFile('prado:THtmlArea4', $this->getScriptUrl());
+ }
+
+ /**
+ * Registers the editor javascript file and code to initialize the editor.
+ */
+ protected function registerEditorClientScript($writer)
+ {
+ $this->loadJavascriptLibrary();
+ $scripts = $this->getPage()->getClientScript();
+ $options = array(
+ 'EditorOptions' => $this->getEditorOptions()
+ );
+
+ $options = TJavaScript::encode($options,true,true);
+ $script = "new {$this->getClientClassName()}($options)";
+ $scripts->registerEndScript('prado:THtmlArea4'.$this->ClientID,$script);
+ }
+
+ /**
+ * @return string editor script URL.
+ */
+ protected function getScriptUrl()
+ {
+ return $this->getScriptDeploymentPath().'/tinymce.min.js';
+ }
+
+ /**
+ * Gets the editor script base URL by publishing the tarred source via TTarAssetManager.
+ * @return string URL base path to the published editor script
+ */
+ protected function getScriptDeploymentPath()
+ {
+ $basedir = Prado::getPathOfNamespace('System.Web.Javascripts.source.tinymce-405');
+ $url = $this->getApplication()->getAssetManager()->publishFilePath($basedir);
+ $this->copyCustomPlugins($url);
+ return $url;
+ }
+
+ protected function copyCustomPlugins($url)
+ {
+ if($plugins = $this->getCustomPluginPath())
+ {
+ $assets = $this->getApplication()->getAssetManager();
+ $path = is_dir($plugins) ? $plugins : Prado::getPathOfNameSpace($plugins);
+ $dest = $assets->getBasePath().'/'.basename($url).'/plugins/';
+ if(!is_dir($dest) || $this->getApplication()->getMode()!==TApplicationMode::Performance)
+ $assets->copyDirectory($path, $dest);
+ }
+ }
+
+ /**
+ * Default editor options gives basic tool bar only.
+ * @return array editor initialization options.
+ */
+ protected function getEditorOptions()
+ {
+ $options['mode'] = 'exact';
+ $options['elements'] = $this->getClientID();
+ $options['language'] = $this->getLanguageSuffix($this->getCulture());
+ //$options['theme'] = 'modern'; //default
+ // mimic previous (tinyMCE3) sizing behaviour
+ $options['width'] = $this->getWidth();
+ $options['height'] = $this->getHeight();
+ $options['resize'] = 'both';
+ $options['menubar'] = false;
+ if($this->getReadOnly())
+ {
+ $options['readonly'] = true;
+ $options['toolbar'] = false;
+ $options['menubar'] = false;
+ $options['statusbar'] = false;
+ }
+
+ $options['extended_valid_elements'] = 'a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]';
+
+ $options = array_merge($options, $this->parseEditorOptions($this->getOptions()));
+ return $options;
+ }
+
+ /**
+ * Parse additional options set in the Options property.
+ * @return array additional custom options
+ */
+ protected function parseEditorOptions($string)
+ {
+ $options = array();
+ $substrings = preg_split('/,\s*\n|\n/', trim($string));
+ foreach($substrings as $bits)
+ {
+ $option = explode(":",$bits,2);
+
+ if(count($option) == 2)
+ {
+ $value=trim(trim($option[1]),"'\"");
+ if (($s=strtolower($value))==='false')
+ $value=false;
+ elseif ($s==='true')
+ $value=true;
+ $options[trim($option[0])] = $value;
+ }
+ }
+ return $options;
+ }
+
+ /**
+ * @return string localized editor interface language extension.
+ */
+ protected function getLanguageSuffix($culture)
+ {
+ $app = $this->getApplication()->getGlobalization();
+ if(empty($culture) && ($app!==null))
+ $culture = $app->getCulture();
+ $variants = array();
+ if($app!==null)
+ $variants = $app->getCultureVariants($culture);
+
+ foreach($variants as $variant)
+ {
+ if(isset(self::$_langs[$variant]))
+ return self::$_langs[$variant];
+ }
+
+ return 'en';
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.THtmlArea4';
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/THtmlElement.php b/lib/prado/framework/Web/UI/WebControls/THtmlElement.php
new file mode 100644
index 0000000..6efd608
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/THtmlElement.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * THtmlElement class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TWebControl');
+
+/**
+ * THtmlElement class.
+ *
+ * THtmlElement represents a generic HTML element whose tag name is specified
+ * via {@link setTagName TagName} property. Because THtmlElement extends from
+ * {@link TWebControl}, it enjoys all its functionalities.
+ *
+ * To change the default tag your subclass should override {@link getDefaultTagName}
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.2
+ */
+class THtmlElement extends TWebControl
+{
+ /**
+ * @var the tag of this element
+ */
+ private $_tagName=null;
+
+ /**
+ * @return string the tag name of this control. Defaults to 'span'.
+ */
+ public function getTagName()
+ {
+ return ($this->_tagName !== null) ? $this->_tagName : ($this->_tagName = $this->getDefaultTagName());
+ }
+
+ /**
+ * @param string the tag name of this control.
+ */
+ public function setTagName($value)
+ {
+ $this->_tagName=TPropertyValue::ensureString($value);
+ }
+
+ /**
+ * This is the default tag when no other is specified
+ * @return string the default tag
+ */
+ public function getDefaultTagName() {
+ return 'span';
+ }
+
+ /**
+ * This tells you if this TagName has deviated from the original
+ * @return boolean true if TagName has deviated from the default.
+ */
+ public function getIsMutated() {
+ return $this->_tagName !== null && $this->_tagName != $this->getDefaultTagName();
+ }
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/THyperLink.php b/lib/prado/framework/Web/UI/WebControls/THyperLink.php
new file mode 100644
index 0000000..8e8d3f5
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/THyperLink.php
@@ -0,0 +1,250 @@
+<?php
+/**
+ * THyperLink class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.xisc.com/
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * THyperLink class
+ *
+ * THyperLink displays a hyperlink on a page. The hyperlink URL is specified
+ * via the {@link setNavigateUrl NavigateUrl} property, and link text is via
+ * the {@link setText Text} property. It is also possible to display an image
+ * by setting the {@link setImageUrl ImageUrl} property. In this case,
+ * the alignment of the image displayed is set by the
+ * {@link setImageAlign ImageAlign} property and {@link getText Text} is
+ * displayed as the alternate text of the image.
+ *
+ * The link target is specified via the {@link setTarget Target} property.
+ * If both {@link getImageUrl ImageUrl} and {@link getText Text} are empty,
+ * the content enclosed within the control tag will be rendered.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class THyperLink extends TWebControl implements IDataRenderer
+{
+ /**
+ * @return string tag name of the hyperlink
+ */
+ protected function getTagName()
+ {
+ return 'a';
+ }
+
+ /**
+ * Adds attributes related to a hyperlink element to renderer.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $isEnabled=$this->getEnabled(true);
+ if($this->getEnabled() && !$isEnabled)
+ $writer->addAttribute('disabled','disabled');
+ parent::addAttributesToRender($writer);
+ if(($url=$this->getNavigateUrl())!=='' && $isEnabled)
+ $writer->addAttribute('href',$url);
+ if(($target=$this->getTarget())!=='')
+ $writer->addAttribute('target',$target);
+ }
+
+ /**
+ * Renders the body content of the hyperlink.
+ * @param THtmlWriter the writer for rendering
+ */
+ public function renderContents($writer)
+ {
+ if(($imageUrl=$this->getImageUrl())==='')
+ {
+ if(($text=$this->getText())!=='')
+ $writer->write(THttpUtility::htmlEncode($text));
+ else if($this->getHasControls())
+ parent::renderContents($writer);
+ else
+ $writer->write(THttpUtility::htmlEncode($this->getNavigateUrl()));
+ }
+ else
+ {
+ $this->createImage($imageUrl)->renderControl($writer);
+ }
+ }
+
+ /**
+ * Gets the TImage for rendering the ImageUrl property. This is not for
+ * creating dynamic images.
+ * @param string image url.
+ * @return TImage image control for rendering.
+ */
+ protected function createImage($imageUrl)
+ {
+ $image=Prado::createComponent('System.Web.UI.WebControls.TImage');
+ $image->setImageUrl($imageUrl);
+ if(($width=$this->getImageWidth())!=='')
+ $image->setWidth($width);
+ if(($height=$this->getImageHeight())!=='')
+ $image->setHeight($height);
+ if(($toolTip=$this->getToolTip())!=='')
+ $image->setToolTip($toolTip);
+ if(($text=$this->getText())!=='')
+ $image->setAlternateText($text);
+ if(($align=$this->getImageAlign())!=='')
+ $image->setImageAlign($align);
+ $image->setBorderWidth('0');
+ return $image;
+ }
+
+ /**
+ * @return string the text caption of the THyperLink
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text caption of the THyperLink.
+ * @param string the text caption to be set
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * @return string the alignment of the image with respective to other elements on the page, defaults to empty.
+ */
+ public function getImageAlign()
+ {
+ return $this->getViewState('ImageAlign','');
+ }
+
+ /**
+ * Sets the alignment of the image with respective to other elements on the page.
+ * Possible values include: absbottom, absmiddle, baseline, bottom, left,
+ * middle, right, texttop, and top. If an empty string is passed in,
+ * imagealign attribute will not be rendered.
+ * @param string the alignment of the image
+ */
+ public function setImageAlign($value)
+ {
+ $this->setViewState('ImageAlign',$value,'');
+ }
+
+ /**
+ * @return string height of the image in the THyperLink
+ */
+ public function getImageHeight()
+ {
+ return $this->getViewState('ImageHeight','');
+ }
+
+ /**
+ * Sets the height of the image in the THyperLink
+ * @param string height of the image in the THyperLink
+ */
+ public function setImageHeight($value)
+ {
+ $this->setViewSTate('ImageHeight',$value,'');
+ }
+
+ /**
+ * @return string the location of the image file for the THyperLink
+ */
+ public function getImageUrl()
+ {
+ return $this->getViewState('ImageUrl','');
+ }
+
+ /**
+ * Sets the location of image file of the THyperLink.
+ * @param string the image file location
+ */
+ public function setImageUrl($value)
+ {
+ $this->setViewState('ImageUrl',$value,'');
+ }
+
+ /**
+ * @return string width of the image in the THyperLink
+ */
+ public function getImageWidth()
+ {
+ return $this->getViewState('ImageWidth','');
+ }
+
+ /**
+ * Sets the width of the image in the THyperLink
+ * @param string width of the image
+ */
+ public function setImageWidth($value)
+ {
+ $this->setViewState('ImageWidth',$value,'');
+ }
+
+ /**
+ * @return string the URL to link to when the THyperLink component is clicked.
+ */
+ public function getNavigateUrl()
+ {
+ return $this->getViewState('NavigateUrl','');
+ }
+
+ /**
+ * Sets the URL to link to when the THyperLink component is clicked.
+ * @param string the URL
+ */
+ public function setNavigateUrl($value)
+ {
+ $this->setViewState('NavigateUrl',$value,'');
+ }
+
+ /**
+ * Returns the URL to link to when the THyperLink component is clicked.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string the text caption
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the URL to link to when the THyperLink component is clicked.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string the text caption to be set
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * @return string the target window or frame to display the Web page content linked to when the THyperLink component is clicked.
+ */
+ public function getTarget()
+ {
+ return $this->getViewState('Target','');
+ }
+
+ /**
+ * Sets the target window or frame to display the Web page content linked to when the THyperLink component is clicked.
+ * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string.
+ */
+ public function setTarget($value)
+ {
+ $this->setViewState('Target',$value,'');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/THyperLinkColumn.php b/lib/prado/framework/Web/UI/WebControls/THyperLinkColumn.php
new file mode 100644
index 0000000..d24616a
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/THyperLinkColumn.php
@@ -0,0 +1,271 @@
+<?php
+/**
+ * THyperLinkColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+/**
+ * THyperLink class file
+ */
+Prado::using('System.Web.UI.WebControls.THyperLink');
+
+/**
+ * THyperLinkColumn class
+ *
+ * THyperLinkColumn contains a hyperlink for each item in the column.
+ * You can set the text and the url of the hyperlink by {@link setText Text}
+ * and {@link setNavigateUrl NavigateUrl} properties, respectively.
+ * You can also bind the text and url to specific data field in datasource
+ * by setting {@link setDataTextField DataTextField} and
+ * {@link setDataNavigateUrlField DataNavigateUrlField}.
+ * Both can be formatted before rendering according to the
+ * {@link setDataTextFormatString DataTextFormatString} and
+ * and {@link setDataNavigateUrlFormatString DataNavigateUrlFormatString}
+ * properties, respectively. If both {@link setText Text} and {@link setDataTextField DataTextField}
+ * are present, the latter takes precedence.
+ * The same rule applies to {@link setNavigateUrl NavigateUrl} and
+ * {@link setDataNavigateUrlField DataNavigateUrlField} properties.
+ *
+ * The hyperlinks in the column can be accessed by one of the following two methods:
+ * <code>
+ * $datagridItem->HyperLinkColumnID->HyperLink
+ * $datagridItem->HyperLinkColumnID->Controls[0]
+ * </code>
+ * The second method is possible because the hyperlink control created within the
+ * datagrid cell is the first child.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class THyperLinkColumn extends TDataGridColumn
+{
+ /**
+ * @return string the text caption of the hyperlink
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text caption of the hyperlink.
+ * @param string the text caption to be set
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * @return string the field name from the data source to bind to the hyperlink caption
+ */
+ public function getDataTextField()
+ {
+ return $this->getViewState('DataTextField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the hyperlink caption
+ */
+ public function setDataTextField($value)
+ {
+ $this->setViewState('DataTextField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the hyperlink caption will be displayed.
+ */
+ public function getDataTextFormatString()
+ {
+ return $this->getViewState('DataTextFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the hyperlink caption will be displayed.
+ */
+ public function setDataTextFormatString($value)
+ {
+ $this->setViewState('DataTextFormatString',$value,'');
+ }
+
+ /**
+ * @return string height of the image in the THyperLink
+ */
+ public function getImageHeight()
+ {
+ return $this->getViewState('ImageHeight','');
+ }
+
+ /**
+ * @param string height of the image in the THyperLink
+ */
+ public function setImageHeight($value)
+ {
+ $this->setViewState('ImageHeight',$value,'');
+ }
+
+ /**
+ * @return string url of the image in the THyperLink
+ */
+ public function getImageUrl()
+ {
+ return $this->getViewState('ImageUrl','');
+ }
+
+ /**
+ * @param string url of the image in the THyperLink
+ */
+ public function setImageUrl($value)
+ {
+ $this->setViewState('ImageUrl',$value,'');
+ }
+
+ /**
+ * @return string width of the image in the THyperLink
+ */
+ public function getImageWidth()
+ {
+ return $this->getViewState('ImageWidth','');
+ }
+
+ /**
+ * @param string width of the image in the THyperLink
+ */
+ public function setImageWidth($value)
+ {
+ $this->setViewState('ImageWidth',$value,'');
+ }
+
+ /**
+ * @return string the URL to link to when the hyperlink is clicked.
+ */
+ public function getNavigateUrl()
+ {
+ return $this->getViewState('NavigateUrl','');
+ }
+
+ /**
+ * Sets the URL to link to when the hyperlink is clicked.
+ * @param string the URL
+ */
+ public function setNavigateUrl($value)
+ {
+ $this->setViewState('NavigateUrl',$value,'');
+ }
+
+ /**
+ * @return string the field name from the data source to bind to the navigate url of hyperlink
+ */
+ public function getDataNavigateUrlField()
+ {
+ return $this->getViewState('DataNavigateUrlField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the navigate url of hyperlink
+ */
+ public function setDataNavigateUrlField($value)
+ {
+ $this->setViewState('DataNavigateUrlField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the navigate url of hyperlink will be displayed.
+ */
+ public function getDataNavigateUrlFormatString()
+ {
+ return $this->getViewState('DataNavigateUrlFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the navigate url of hyperlink will be displayed.
+ */
+ public function setDataNavigateUrlFormatString($value)
+ {
+ $this->setViewState('DataNavigateUrlFormatString',$value,'');
+ }
+
+ /**
+ * @return string the target window or frame to display the Web page content linked to when the hyperlink is clicked.
+ */
+ public function getTarget()
+ {
+ return $this->getViewState('Target','');
+ }
+
+ /**
+ * Sets the target window or frame to display the Web page content linked to when the hyperlink is clicked.
+ * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string.
+ */
+ public function setTarget($value)
+ {
+ $this->setViewState('Target',$value,'');
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates a hyperlink within the cell.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
+ {
+ $link=new THyperLink;
+ if(($url = $this->getImageUrl())!=='')
+ {
+ $link->setImageUrl($url);
+ if(($width=$this->getImageWidth())!=='')
+ $link->setImageWidth($width);
+ if(($height=$this->getImageHeight())!=='')
+ $link->setImageHeight($height);
+ }
+ $link->setText($this->getText());
+ $link->setNavigateUrl($this->getNavigateUrl());
+ $link->setTarget($this->getTarget());
+ if($this->getDataTextField()!=='' || $this->getDataNavigateUrlField()!=='')
+ $link->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ $cell->getControls()->add($link);
+ $cell->registerObject('HyperLink',$link);
+ }
+ else
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $data=$item->getData();
+ if(($field=$this->getDataTextField())!=='')
+ {
+ $value=$this->getDataFieldValue($data,$field);
+ $text=$this->formatDataValue($this->getDataTextFormatString(),$value);
+ $sender->setText($text);
+ }
+ if(($field=$this->getDataNavigateUrlField())!=='')
+ {
+ $value=$this->getDataFieldValue($data,$field);
+ $url=$this->formatDataValue($this->getDataNavigateUrlFormatString(),$value);
+ $sender->setNavigateUrl($url);
+ }
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TImage.php b/lib/prado/framework/Web/UI/WebControls/TImage.php
new file mode 100644
index 0000000..8538545
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TImage.php
@@ -0,0 +1,155 @@
+<?php
+/**
+ * TImage class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TImage class
+ *
+ * TImage displays an image on a page. The image is specified via the
+ * {@link setImageUrl ImageUrl} property which takes a relative or absolute
+ * URL to the image file. The alignment of the image displayed is set by
+ * the {@link setImageAlign ImageAlign} property. To set alternative texts
+ * or long description of the image, use {@link setAlternateText AlternateText}
+ * or {@link setDescriptionUrl DescriptionUrl} property, respectively.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TImage extends TWebControl implements IDataRenderer
+{
+ /**
+ * @return string tag name of image control
+ */
+ protected function getTagName()
+ {
+ return 'img';
+ }
+
+ /**
+ * Adds attributes related to an HTML image element to renderer.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $writer->addAttribute('src',$this->getImageUrl());
+ $writer->addAttribute('alt',$this->getAlternateText());
+ if(($desc=$this->getDescriptionUrl())!=='')
+ $writer->addAttribute('longdesc',$desc);
+ if(($align=$this->getImageAlign())!=='')
+ $writer->addAttribute('align',$align);
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the body content of the image.
+ * Nothing to be rendered within image tags.
+ * @param THtmlWriter the writer for rendering
+ */
+ public function renderContents($writer)
+ {
+ }
+
+ /**
+ * @return string the alternative text displayed in the TImage component when the image is unavailable.
+ */
+ public function getAlternateText()
+ {
+ return $this->getViewState('AlternateText','');
+ }
+
+ /**
+ * Sets the alternative text to be displayed in the TImage when the image is unavailable.
+ * @param string the alternative text
+ */
+ public function setAlternateText($value)
+ {
+ $this->setViewState('AlternateText',$value,'');
+ }
+
+ /**
+ * @return string the alignment of the image with respective to other elements on the page, defaults to empty.
+ */
+ public function getImageAlign()
+ {
+ return $this->getViewState('ImageAlign','');
+ }
+
+ /**
+ * Sets the alignment of the image with respective to other elements on the page.
+ * Possible values include: absbottom, absmiddle, baseline, bottom, left,
+ * middle, right, texttop, and top. If an empty string is passed in,
+ * imagealign attribute will not be rendered.
+ * @param string the alignment of the image
+ */
+ public function setImageAlign($value)
+ {
+ $this->setViewState('ImageAlign',$value,'');
+ }
+
+ /**
+ * @return string the URL of the image file
+ */
+ public function getImageUrl()
+ {
+ return $this->getViewState('ImageUrl','');
+ }
+
+ /**
+ * @param string the URL of the image file
+ */
+ public function setImageUrl($value)
+ {
+ $this->setViewState('ImageUrl',$value,'');
+ }
+
+ /**
+ * Returns the URL of the image file.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getImageUrl()}.
+ * @return string the URL of the image file.
+ * @see getImageUrl
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getImageUrl();
+ }
+
+ /**
+ * Sets the URL of the image.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setImageUrl()}.
+ * @param string the URL of the image file.
+ * @see setImageUrl
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setImageUrl($value);
+ }
+
+ /**
+ * @return string the URL to long description
+ */
+ public function getDescriptionUrl()
+ {
+ return $this->getViewState('DescriptionUrl','');
+ }
+
+ /**
+ * @param string the URL to the long description of the image.
+ */
+ public function setDescriptionUrl($value)
+ {
+ $this->setViewState('DescriptionUrl',$value,'');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TImageButton.php b/lib/prado/framework/Web/UI/WebControls/TImageButton.php
new file mode 100644
index 0000000..288def3
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TImageButton.php
@@ -0,0 +1,438 @@
+<?php
+/**
+ * TImageButton class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TImage class file
+ */
+Prado::using('System.Web.UI.WebControls.TImage');
+
+/**
+ * TImageButton class
+ *
+ * TImageButton creates an image button on the page. It is used to submit data to a page.
+ * You can create either a <b>submit</b> button or a <b>command</b> button.
+ *
+ * A <b>command</b> button has a command name (specified by
+ * the {@link setCommandName CommandName} property) and and a command parameter
+ * (specified by {@link setCommandParameter CommandParameter} property)
+ * associated with the button. This allows you to create multiple TLinkButton
+ * components on a Web page and programmatically determine which one is clicked
+ * with what parameter. You can provide an event handler for
+ * {@link onCommand OnCommand} event to programmatically control the actions performed
+ * when the command button is clicked. In the event handler, you can determine
+ * the {@link setCommandName CommandName} property value and
+ * the {@link setCommandParameter CommandParameter} property value
+ * through the {@link TCommandParameter::getName Name} and
+ * {@link TCommandParameter::getParameter Parameter} properties of the event
+ * parameter which is of type {@link TCommandEventParameter}.
+ *
+ * A <b>submit</b> button does not have a command name associated with the button
+ * and clicking on it simply posts the Web page back to the server.
+ * By default, a TImageButton control is a submit button.
+ * You can provide an event handler for the {@link onClick OnClick} event
+ * to programmatically control the actions performed when the submit button is clicked.
+ * The coordinates of the clicking point can be obtained from the {@link onClick OnClick}
+ * event parameter, which is of type {@link TImageClickEventParameter}.
+ *
+ * Clicking on button can trigger form validation, if
+ * {@link setCausesValidation CausesValidation} is true.
+ * And the validation may be restricted within a certain group of validator
+ * controls by setting {@link setValidationGroup ValidationGroup} property.
+ * If validation is successful, the data will be post back to the same page.
+ *
+ * TImageButton displays the {@link setText Text} property as the hint text to the displayed image.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TImageButton extends TImage implements IPostBackDataHandler, IPostBackEventHandler, IButtonControl
+{
+ /**
+ * @var integer x coordinate that the image is being clicked at
+ */
+ private $_x=0;
+ /**
+ * @var integer y coordinate that the image is being clicked at
+ */
+ private $_y=0;
+ private $_dataChanged=false;
+
+ /**
+ * @return string tag name of the button
+ */
+ protected function getTagName()
+ {
+ return 'input';
+ }
+
+ /**
+ * @return boolean whether to render javascript.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether to render javascript.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This overrides the parent implementation with additional button specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $page=$this->getPage();
+ $page->ensureRenderInForm($this);
+ $writer->addAttribute('type','image');
+ if(($uniqueID=$this->getUniqueID())!=='')
+ $writer->addAttribute('name',$uniqueID);
+ if($this->getEnabled(true))
+ {
+ if($this->getEnableClientScript() && $this->needPostBackScript())
+ $this->renderClientControlScript($writer);
+ }
+ else if($this->getEnabled()) // in this case, parent will not render 'disabled'
+ $writer->addAttribute('disabled','disabled');
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the client-script code.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TImageButton';
+ }
+
+ /**
+ * @return boolean whether to perform validation if the button is clicked
+ */
+ protected function canCauseValidation()
+ {
+ if($this->getCausesValidation())
+ {
+ $group=$this->getValidationGroup();
+ return $this->getPage()->getValidators($group)->getCount()>0;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * @param boolean set by a panel to register this button as the default button for the panel.
+ */
+ public function setIsDefaultButton($value)
+ {
+ $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean true if this button is registered as a default button for a panel.
+ */
+ public function getIsDefaultButton()
+ {
+ return $this->getViewState('IsDefaultButton', false);
+ }
+
+ /**
+ * @return boolean whether the button needs javascript to do postback
+ */
+ protected function needPostBackScript()
+ {
+ return $this->canCauseValidation() || $this->getIsDefaultButton();
+ }
+
+ /**
+ * Returns postback specifications for the button.
+ * This method is used by framework and control developers.
+ * @return array parameters about how the button defines its postback behavior.
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['EventTarget'] = $this->getUniqueID();
+
+ return $options;
+ }
+
+ /**
+ * This method checks if the TImageButton is clicked and loads the coordinates of the clicking position.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ $uid=$this->getUniqueID();
+ if(isset($values["{$uid}_x"]) && isset($values["{$uid}_y"]))
+ {
+ $this->_x=intval($values["{$uid}_x"]);
+ $this->_y=intval($values["{$uid}_y"]);
+ if($this->getPage()->getPostBackEventTarget()===null)
+ $this->getPage()->setPostBackEventTarget($this);
+ $this->_dataChanged=true;
+ }
+ return false;
+ }
+
+ /**
+ * A dummy implementation for the IPostBackDataHandler interface.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ // no post data to handle
+ }
+
+ /**
+ * This method is invoked when the button is clicked.
+ * The method raises 'OnClick' event to fire up the event handlers.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handler can be invoked.
+ * @param TImageClickEventParameter event parameter to be passed to the event handlers
+ */
+ public function onClick($param)
+ {
+ $this->raiseEvent('OnClick',$this,$param);
+ }
+
+ /**
+ * This method is invoked when the button is clicked.
+ * The method raises 'OnCommand' event to fire up the event handlers.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TCommandEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCommand($param)
+ {
+ $this->raiseEvent('OnCommand',$this,$param);
+ $this->raiseBubbleEvent($this,$param);
+ }
+
+ /**
+ * Raises the postback event.
+ * This method is required by {@link IPostBackEventHandler} interface.
+ * If {@link getCausesValidation CausesValidation} is true, it will
+ * invoke the page's {@link TPage::validate validate} method first.
+ * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events.
+ * This method is mainly used by framework and control developers.
+ * @param TEventParameter the event parameter
+ */
+ public function raisePostBackEvent($param)
+ {
+ if($this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onClick(new TImageClickEventParameter($this->_x,$this->_y));
+ $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter()));
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * @return boolean whether postback event trigger by this button will cause input validation, default is true
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by this button will cause input validation
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function getCommandName()
+ {
+ return $this->getViewState('CommandName','');
+ }
+
+ /**
+ * @param string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandName($value)
+ {
+ $this->setViewState('CommandName',$value,'');
+ }
+
+ /**
+ * @return string the parameter associated with the {@link onCommand OnCommand} event
+ */
+ public function getCommandParameter()
+ {
+ return $this->getViewState('CommandParameter','');
+ }
+
+ /**
+ * @param string the parameter associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandParameter($value)
+ {
+ $this->setViewState('CommandParameter',$value,'');
+ }
+
+ /**
+ * @return string the group of validators which the button causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the button causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return string caption of the button
+ */
+ public function getText()
+ {
+ return $this->getAlternateText();
+ }
+
+ /**
+ * @param string caption of the button
+ */
+ public function setText($value)
+ {
+ $this->setAlternateText($value);
+ }
+
+ /**
+ * Registers the image button to receive postback data during postback.
+ * This is necessary because an image button, when postback, does not have
+ * direct mapping between post data and the image button name.
+ * This method overrides the parent implementation and is invoked before render.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->getPage()->registerRequiresPostData($this);
+ }
+
+ /**
+ * Renders the body content enclosed between the control tag.
+ * This overrides the parent implementation with nothing to be rendered.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ }
+}
+
+/**
+ * TImageClickEventParameter class
+ *
+ * TImageClickEventParameter encapsulates the parameter data for
+ * {@link TImageButton::onClick Click} event of {@link TImageButton} controls.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TImageClickEventParameter extends TEventParameter
+{
+ /**
+ * the X coordinate of the clicking point
+ * @var integer
+ */
+ private $_x=0;
+ /**
+ * the Y coordinate of the clicking point
+ * @var integer
+ */
+ private $_y=0;
+
+ /**
+ * Constructor.
+ * @param integer X coordinate of the clicking point
+ * @param integer Y coordinate of the clicking point
+ */
+ public function __construct($x,$y)
+ {
+ $this->_x=$x;
+ $this->_y=$y;
+ }
+
+ /**
+ * @return integer X coordinate of the clicking point, defaults to 0
+ */
+ public function getX()
+ {
+ return $this->_x;
+ }
+
+ /**
+ * @param integer X coordinate of the clicking point
+ */
+ public function setX($value)
+ {
+ $this->_x=TPropertyValue::ensureInteger($value);
+ }
+
+ /**
+ * @return integer Y coordinate of the clicking point, defaults to 0
+ */
+ public function getY()
+ {
+ return $this->_y;
+ }
+
+ /**
+ * @param integer Y coordinate of the clicking point
+ */
+ public function setY($value)
+ {
+ $this->_y=TPropertyValue::ensureInteger($value);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TImageMap.php b/lib/prado/framework/Web/UI/WebControls/TImageMap.php
new file mode 100644
index 0000000..8775496
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TImageMap.php
@@ -0,0 +1,828 @@
+<?php
+/**
+ * TImageMap and related class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TImage class file
+ */
+Prado::using('System.Web.UI.WebControls.TImage');
+
+/**
+ * TImageMap class
+ *
+ * TImageMap represents an image on a page. Hotspot regions can be defined
+ * within the image. Depending on the {@link setHotSpotMode HotSpotMode},
+ * clicking on the hotspots may trigger a postback or navigate to a specified
+ * URL. The hotspots defined may be accessed via {@link getHotSpots HotSpots}.
+ * Each hotspot is described as a {@link THotSpot}, which can be a circle,
+ * rectangle, polygon, etc. To add hotspot in a template, use the following,
+ * <code>
+ * <com:TImageMap>
+ * <com:TCircleHotSpot ... />
+ * <com:TRectangleHotSpot ... />
+ * <com:TPolygonHotSpot ... />
+ * </com:TImageMap>
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TImageMap extends TImage implements IPostBackEventHandler
+{
+ const MAP_NAME_PREFIX='ImageMap';
+
+ /**
+ * Processes an object that is created during parsing template.
+ * This method adds {@link THotSpot} objects into the hotspot collection
+ * of the imagemap.
+ * @param string|TComponent text string or component parsed and instantiated in template
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof THotSpot)
+ $this->getHotSpots()->add($object);
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This overrides the parent implementation with additional imagemap specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ if($this->getHotSpots()->getCount()>0)
+ {
+ $writer->addAttribute('usemap','#'.self::MAP_NAME_PREFIX.$this->getClientID());
+ $writer->addAttribute('id',$this->getUniqueID());
+ }
+ if($this->getEnabled() && !$this->getEnabled(true))
+ $writer->addAttribute('disabled','disabled');
+ }
+
+ /**
+ * Renders this imagemap.
+ * @param THtmlWriter
+ */
+ public function render($writer)
+ {
+ parent::render($writer);
+
+ $hotspots=$this->getHotSpots();
+
+ if($hotspots->getCount()>0)
+ {
+ $clientID=$this->getClientID();
+ $cs=$this->getPage()->getClientScript();
+ $writer->writeLine();
+ $writer->addAttribute('name',self::MAP_NAME_PREFIX.$clientID);
+ $writer->renderBeginTag('map');
+ $writer->writeLine();
+ if(($mode=$this->getHotSpotMode())===THotSpotMode::NotSet)
+ $mode=THotSpotMode::Navigate;
+ $target=$this->getTarget();
+ $i=0;
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['StopEvent'] = true;
+ $cs=$this->getPage()->getClientScript();
+ foreach($hotspots as $hotspot)
+ {
+ if($hotspot->getHotSpotMode()===THotSpotMode::NotSet)
+ $hotspot->setHotSpotMode($mode);
+ if($target!=='' && $hotspot->getTarget()==='')
+ $hotspot->setTarget($target);
+ if($hotspot->getHotSpotMode()===THotSpotMode::PostBack)
+ {
+ $id=$clientID.'_'.$i;
+ $writer->addAttribute('id',$id);
+ $writer->addAttribute('href','#'.$id); //create unique no-op url references
+ $options['ID']=$id;
+ $options['EventParameter']="$i";
+ $options['CausesValidation']=$hotspot->getCausesValidation();
+ $options['ValidationGroup']=$hotspot->getValidationGroup();
+ $cs->registerPostBackControl($this->getClientClassName(),$options);
+ }
+ $hotspot->render($writer);
+ $writer->writeLine();
+ $i++;
+ }
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TImageMap';
+ }
+
+ /**
+ * Raises the postback event.
+ * This method is required by {@link IPostBackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TEventParameter the event parameter
+ */
+ public function raisePostBackEvent($param)
+ {
+ $postBackValue=null;
+ if($param!=='')
+ {
+ $index=TPropertyValue::ensureInteger($param);
+ $hotspots=$this->getHotSpots();
+ if($index>=0 && $index<$hotspots->getCount())
+ {
+ $hotspot=$hotspots->itemAt($index);
+ if(($mode=$hotspot->getHotSpotMode())===THotSpotMode::NotSet)
+ $mode=$this->getHotSpotMode();
+ if($mode===THotSpotMode::PostBack)
+ {
+ $postBackValue=$hotspot->getPostBackValue();
+ if($hotspot->getCausesValidation())
+ $this->getPage()->validate($hotspot->getValidationGroup());
+ }
+ }
+ }
+ if($postBackValue!==null)
+ $this->onClick(new TImageMapEventParameter($postBackValue));
+ }
+
+ /**
+ * @return THotSpotMode the behavior of hotspot regions in this imagemap when they are clicked. Defaults to THotSpotMode::NotSet.
+ */
+ public function getHotSpotMode()
+ {
+ return $this->getViewState('HotSpotMode',THotSpotMode::NotSet);
+ }
+
+ /**
+ * Sets the behavior of hotspot regions in this imagemap when they are clicked.
+ * If an individual hotspot has a mode other than 'NotSet', the mode set in this
+ * imagemap will be ignored. By default, 'NotSet' is equivalent to 'Navigate'.
+ * @param THotSpotMode the behavior of hotspot regions in this imagemap when they are clicked.
+ */
+ public function setHotSpotMode($value)
+ {
+ $this->setViewState('HotSpotMode',TPropertyValue::ensureEnum($value,'THotSpotMode'),THotSpotMode::NotSet);
+ }
+
+ /**
+ * @return THotSpotCollection collection of hotspots defined in this imagemap.
+ */
+ public function getHotSpots()
+ {
+ if(($hotspots=$this->getViewState('HotSpots',null))===null)
+ {
+ $hotspots=new THotSpotCollection;
+ $this->setViewState('HotSpots',$hotspots);
+ }
+ return $hotspots;
+ }
+
+ /**
+ * @return string the target window or frame to display the new page when a hotspot region is clicked within the imagemap. Defaults to ''.
+ */
+ public function getTarget()
+ {
+ return $this->getViewState('Target','');
+ }
+
+ /**
+ * @param string the target window or frame to display the new page when a hotspot region is clicked within the imagemap.
+ */
+ public function setTarget($value)
+ {
+ $this->setViewState('Target',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * Raises <b>OnClick</b> event.
+ * This method is invoked when a hotspot region is clicked within the imagemap.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handler can be invoked.
+ * @param TImageMapEventParameter event parameter to be passed to the event handlers
+ */
+ public function onClick($param)
+ {
+ $this->raiseEvent('OnClick',$this,$param);
+ }
+}
+
+/**
+ * TImageMapEventParameter class.
+ *
+ * TImageMapEventParameter represents a postback event parameter
+ * when a hotspot is clicked and posts back in a {@link TImageMap}.
+ * To retrieve the post back value associated with the hotspot being clicked,
+ * access {@link getPostBackValue PostBackValue}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TImageMapEventParameter extends TEventParameter
+{
+ private $_postBackValue;
+
+ /**
+ * Constructor.
+ * @param string post back value associated with the hotspot clicked
+ */
+ public function __construct($postBackValue)
+ {
+ $this->_postBackValue=$postBackValue;
+ }
+
+ /**
+ * @return string post back value associated with the hotspot clicked
+ */
+ public function getPostBackValue()
+ {
+ return $this->_postBackValue;
+ }
+}
+
+/**
+ * THotSpotCollection class.
+ *
+ * THotSpotCollection represents a collection of hotspots in an imagemap.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class THotSpotCollection extends TList
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by inserting only {@link THotSpot}.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a THotSpot.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof THotSpot)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('hotspotcollection_hotspot_required');
+ }
+}
+
+
+/**
+ * THotSpot class.
+ *
+ * THotSpot implements the basic functionality common to all hot spot shapes.
+ * Derived classes include {@link TCircleHotSpot}, {@link TPolygonHotSpot}
+ * and {@link TRectangleHotSpot}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class THotSpot extends TComponent
+{
+ private $_viewState=array();
+
+ /**
+ * Returns a viewstate value.
+ *
+ * This function is very useful in defining getter functions for component properties
+ * that must be kept in viewstate.
+ * @param string the name of the viewstate value to be returned
+ * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
+ * @return mixed the viewstate value corresponding to $key
+ */
+ protected function getViewState($key,$defaultValue=null)
+ {
+ return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue;
+ }
+
+ /**
+ * Sets a viewstate value.
+ *
+ * This function is very useful in defining setter functions for control properties
+ * that must be kept in viewstate.
+ * Make sure that the viewstate value must be serializable and unserializable.
+ * @param string the name of the viewstate value
+ * @param mixed the viewstate value to be set
+ * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
+ */
+ protected function setViewState($key,$value,$defaultValue=null)
+ {
+ if($value===$defaultValue)
+ unset($this->_viewState[$key]);
+ else
+ $this->_viewState[$key]=$value;
+ }
+
+ /**
+ * @return string shape of the hotspot, can be 'circle', 'rect', 'poly', etc.
+ */
+ abstract public function getShape();
+ /**
+ * @return string coordinates defining the hotspot shape.
+ */
+ abstract public function getCoordinates();
+
+ /**
+ * @return string the access key that allows you to quickly navigate to the HotSpot region. Defaults to ''.
+ */
+ public function getAccessKey()
+ {
+ return $this->getViewState('AccessKey','');
+ }
+
+ /**
+ * @param string the access key that allows you to quickly navigate to the HotSpot region.
+ */
+ public function setAccessKey($value)
+ {
+ $this->setViewState('AccessKey',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string the alternate text to display for a HotSpot object. Defaults to ''.
+ */
+ public function getAlternateText()
+ {
+ return $this->getViewState('AlternateText','');
+ }
+
+ /**
+ * @param string the alternate text to display for a HotSpot object.
+ */
+ public function setAlternateText($value)
+ {
+ $this->setViewState('AlternateText',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return THotSpotMode the behavior of a HotSpot object when it is clicked. Defaults to THotSpotMode::NotSet.
+ */
+ public function getHotSpotMode()
+ {
+ return $this->getViewState('HotSpotMode',THotSpotMode::NotSet);
+ }
+
+ /**
+ * @param THotSpotMode the behavior of a HotSpot object when it is clicked.
+ */
+ public function setHotSpotMode($value)
+ {
+ $this->setViewState('HotSpotMode',TPropertyValue::ensureEnum($value,'THotSpotMode'),THotSpotMode::NotSet);
+ }
+
+ /**
+ * @return string the URL to navigate to when a HotSpot object is clicked. Defaults to ''.
+ */
+ public function getNavigateUrl()
+ {
+ return $this->getViewState('NavigateUrl','');
+ }
+
+ /**
+ * @param string the URL to navigate to when a HotSpot object is clicked.
+ */
+ public function setNavigateUrl($value)
+ {
+ $this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string a value that is post back when the HotSpot is clicked. Defaults to ''.
+ */
+ public function getPostBackValue()
+ {
+ return $this->getViewState('PostBackValue','');
+ }
+
+ /**
+ * @param string a value that is post back when the HotSpot is clicked.
+ */
+ public function setPostBackValue($value)
+ {
+ $this->setViewState('PostBackValue',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return integer the tab index of the HotSpot region. Defaults to 0.
+ */
+ public function getTabIndex()
+ {
+ return $this->getViewState('TabIndex',0);
+ }
+
+ /**
+ * @param integer the tab index of the HotSpot region.
+ */
+ public function setTabIndex($value)
+ {
+ $this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return boolean whether postback event trigger by this hotspot will cause input validation, default is true
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by this hotspot will cause input validation
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the group of validators which the hotspot causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the hotspot causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return string the target window or frame to display the new page when the HotSpot region
+ * is clicked. Defaults to ''.
+ */
+ public function getTarget()
+ {
+ return $this->getViewState('Target','');
+ }
+
+ /**
+ * @param string the target window or frame to display the new page when the HotSpot region
+ * is clicked.
+ */
+ public function setTarget($value)
+ {
+ $this->setViewState('Target',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return boolean whether the hotspot has custom attributes
+ */
+ public function getHasAttributes()
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->getCount()>0;
+ else
+ return false;
+ }
+
+ /**
+ * Returns the list of custom attributes.
+ * Custom attributes are name-value pairs that may be rendered
+ * as HTML tags' attributes.
+ * @return TAttributeCollection the list of custom attributes
+ */
+ public function getAttributes()
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes;
+ else
+ {
+ $attributes=new TAttributeCollection;
+ $this->setViewState('Attributes',$attributes,null);
+ return $attributes;
+ }
+ }
+
+ /**
+ * @return boolean whether the named attribute exists
+ */
+ public function hasAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->contains($name);
+ else
+ return false;
+ }
+
+ /**
+ * @return string attribute value, null if attribute does not exist
+ */
+ public function getAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->itemAt($name);
+ else
+ return null;
+ }
+
+ /**
+ * Sets a custom hotspot attribute.
+ * @param string attribute name
+ * @param string value of the attribute
+ */
+ public function setAttribute($name,$value)
+ {
+ $this->getAttributes()->add($name,$value);
+ }
+
+ /**
+ * Removes the named attribute.
+ * @param string the name of the attribute to be removed.
+ * @return string attribute value removed, null if attribute does not exist.
+ */
+ public function removeAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->remove($name);
+ else
+ return null;
+ }
+
+ /**
+ * Renders this hotspot.
+ * @param THtmlWriter
+ */
+ public function render($writer)
+ {
+ $writer->addAttribute('shape',$this->getShape());
+ $writer->addAttribute('coords',$this->getCoordinates());
+ if(($mode=$this->getHotSpotMode())===THotSpotMode::NotSet)
+ $mode=THotSpotMode::Navigate;
+ if($mode===THotSpotMode::Navigate)
+ {
+ $writer->addAttribute('href',$this->getNavigateUrl());
+ if(($target=$this->getTarget())!=='')
+ $writer->addAttribute('target',$target);
+ }
+ else if($mode===THotSpotMode::Inactive)
+ $writer->addAttribute('nohref','true');
+ $text=$this->getAlternateText();
+ $writer->addAttribute('title',$text);
+ $writer->addAttribute('alt',$text);
+ if(($accessKey=$this->getAccessKey())!=='')
+ $writer->addAttribute('accesskey',$accessKey);
+ if(($tabIndex=$this->getTabIndex())!==0)
+ $writer->addAttribute('tabindex',"$tabIndex");
+ if($this->getHasAttributes())
+ {
+ foreach($this->getAttributes() as $name=>$value)
+ $writer->addAttribute($name,$value);
+ }
+ $writer->renderBeginTag('area');
+ $writer->renderEndTag();
+ }
+}
+
+/**
+ * Class TCircleHotSpot.
+ *
+ * TCircleHotSpot defines a circular hot spot region in a {@link TImageMap}
+ * control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCircleHotSpot extends THotSpot
+{
+ /**
+ * @return string shape of this hotspot.
+ */
+ public function getShape()
+ {
+ return 'circle';
+ }
+
+ /**
+ * @return string coordinates defining this hotspot shape
+ */
+ public function getCoordinates()
+ {
+ return $this->getX().','.$this->getY().','.$this->getRadius();
+ }
+
+ /**
+ * @return integer radius of the circular HotSpot region. Defaults to 0.
+ */
+ public function getRadius()
+ {
+ return $this->getViewState('Radius',0);
+ }
+
+ /**
+ * @param integer radius of the circular HotSpot region.
+ */
+ public function setRadius($value)
+ {
+ $this->setViewState('Radius',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return integer the X coordinate of the center of the circular HotSpot region. Defaults to 0.
+ */
+ public function getX()
+ {
+ return $this->getViewState('X',0);
+ }
+
+ /**
+ * @param integer the X coordinate of the center of the circular HotSpot region.
+ */
+ public function setX($value)
+ {
+ $this->setViewState('X',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return integer the Y coordinate of the center of the circular HotSpot region. Defaults to 0.
+ */
+ public function getY()
+ {
+ return $this->getViewState('Y',0);
+ }
+
+ /**
+ * @param integer the Y coordinate of the center of the circular HotSpot region.
+ */
+ public function setY($value)
+ {
+ $this->setViewState('Y',TPropertyValue::ensureInteger($value),0);
+ }
+}
+
+/**
+ * Class TRectangleHotSpot.
+ *
+ * TRectangleHotSpot defines a rectangle hot spot region in a {@link
+ * TImageMap} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRectangleHotSpot extends THotSpot
+{
+ /**
+ * @return string shape of this hotspot.
+ */
+ public function getShape()
+ {
+ return 'rect';
+ }
+
+ /**
+ * @return string coordinates defining this hotspot shape
+ */
+ public function getCoordinates()
+ {
+ return $this->getLeft().','.$this->getTop().','.$this->getRight().','.$this->getBottom();
+ }
+
+ /**
+ * @return integer the Y coordinate of the bottom side of the rectangle HotSpot region. Defaults to 0.
+ */
+ public function getBottom()
+ {
+ return $this->getViewState('Bottom',0);
+ }
+
+ /**
+ * @param integer the Y coordinate of the bottom side of the rectangle HotSpot region.
+ */
+ public function setBottom($value)
+ {
+ $this->setViewState('Bottom',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return integer the X coordinate of the right side of the rectangle HotSpot region. Defaults to 0.
+ */
+ public function getLeft()
+ {
+ return $this->getViewState('Left',0);
+ }
+
+ /**
+ * @param integer the X coordinate of the right side of the rectangle HotSpot region.
+ */
+ public function setLeft($value)
+ {
+ $this->setViewState('Left',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return integer the X coordinate of the right side of the rectangle HotSpot region. Defaults to 0.
+ */
+ public function getRight()
+ {
+ return $this->getViewState('Right',0);
+ }
+
+ /**
+ * @param integer the X coordinate of the right side of the rectangle HotSpot region.
+ */
+ public function setRight($value)
+ {
+ $this->setViewState('Right',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return integer the Y coordinate of the top side of the rectangle HotSpot region. Defaults to 0.
+ */
+ public function getTop()
+ {
+ return $this->getViewState('Top',0);
+ }
+
+ /**
+ * @param integer the Y coordinate of the top side of the rectangle HotSpot region.
+ */
+ public function setTop($value)
+ {
+ $this->setViewState('Top',TPropertyValue::ensureInteger($value),0);
+ }
+}
+
+/**
+ * Class TPolygonHotSpot.
+ *
+ * TPolygonHotSpot defines a polygon hot spot region in a {@link
+ * TImageMap} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TPolygonHotSpot extends THotSpot
+{
+ /**
+ * @return string shape of this hotspot.
+ */
+ public function getShape()
+ {
+ return 'poly';
+ }
+
+ /**
+ * @return string coordinates of the vertices defining the polygon.
+ * Coordinates are concatenated together with comma ','. Each pair
+ * represents (x,y) of a vertex.
+ */
+ public function getCoordinates()
+ {
+ return $this->getViewState('Coordinates','');
+ }
+
+ /**
+ * @param string coordinates of the vertices defining the polygon.
+ * Coordinates are concatenated together with comma ','. Each pair
+ * represents (x,y) of a vertex.
+ */
+ public function setCoordinates($value)
+ {
+ $this->setViewState('Coordinates',$value,'');
+ }
+}
+
+
+/**
+ * THotSpotMode class.
+ * THotSpotMode defines the enumerable type for the possible hot spot modes.
+ *
+ * The following enumerable values are defined:
+ * - NotSet: the mode is not specified
+ * - Navigate: clicking on the hotspot will redirect the browser to a different page
+ * - PostBack: clicking on the hotspot will cause a postback
+ * - Inactive: the hotspot is inactive (not clickable)
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class THotSpotMode extends TEnumerable
+{
+ const NotSet='NotSet';
+ const Navigate='Navigate';
+ const PostBack='PostBack';
+ const Inactive='Inactive';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TInlineFrame.php b/lib/prado/framework/Web/UI/WebControls/TInlineFrame.php
new file mode 100644
index 0000000..3d18235
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TInlineFrame.php
@@ -0,0 +1,314 @@
+<?php
+/**
+ * TInlineFrame class file.
+ *
+ * @author Jason Ragsdale <jrags@jasrags.net>
+ * @author Harry Pottash <hpottash@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TInlineFrame class
+ *
+ * TInlineFrame displays an inline frame (iframe) on a Web page.
+ * The location of the frame content is specified by {@link setFrameUrl FrameUrl}.
+ * The frame's alignment is specified by {@link setAlign Align}.
+ * The {@link setMarginWidth MarginWidth} and {@link setMarginHeight MarginHeight}
+ * properties define the number of pixels to use as the left/right margins and
+ * top/bottom margins, respectively, within the inline frame.
+ * The {@link setScrollBars ScrollBars} property specifies whether scrollbars are
+ * provided for the inline frame. And {@link setDescriptionUrl DescriptionUrl}
+ * gives the URI of a long description of the frame's contents.
+ *
+ * Original Prado v2 IFrame Author Information
+ * @author Jason Ragsdale <jrags@jasrags.net>
+ * @author Harry Pottash <hpottash@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TInlineFrame extends TWebControl implements IDataRenderer
+{
+ /**
+ * @return string tag name of the iframe.
+ */
+ protected function getTagName()
+ {
+ return 'iframe';
+ }
+
+ /**
+ * @return TInlineFrameAlign alignment of the iframe. Defaults to TInlineFrameAlign::NotSet.
+ */
+ public function getAlign()
+ {
+ return $this->getViewState('Align',TInlineFrameAlign::NotSet);
+ }
+
+ /**
+ * @param TInlineFrameAlign alignment of the iframe.
+ */
+ public function setAlign($value)
+ {
+ $this->setViewState('Align',TPropertyValue::ensureEnum($value,'TInlineFrameAlign'),TInlineFrameAlign::NotSet);
+ }
+
+ /**
+ * @return string the URL to long description
+ */
+ public function getDescriptionUrl()
+ {
+ return $this->getViewState('DescriptionUrl','');
+ }
+
+ /**
+ * @param string the URL to the long description of the image.
+ */
+ public function setDescriptionUrl($value)
+ {
+ $this->setViewState('DescriptionUrl',$value,'');
+ }
+
+ /**
+ * @return boolean whether there should be a visual separator between the frames. Defaults to true.
+ */
+ public function getShowBorder()
+ {
+ return $this->getViewState('ShowBorder',true);
+ }
+
+ /**
+ * @param boolean whether there should be a visual separator between the frames.
+ */
+ public function setShowBorder($value)
+ {
+ $this->setViewState('ShowBorder',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string URL that this iframe will load content from. Defaults to ''.
+ */
+ public function getFrameUrl()
+ {
+ return $this->getViewState('FrameUrl','');
+ }
+
+ /**
+ * @param string URL that this iframe will load content from.
+ */
+ public function setFrameUrl($value)
+ {
+ $this->setViewState('FrameUrl',$value,'');
+ }
+
+ /**
+ * Returns the URL that this iframe will load content from
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getFrameUrl()}.
+ * @return string the URL that this iframe will load content from
+ * @see getFrameUrl
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getFrameUrl();
+ }
+
+ /**
+ * Sets the URL that this iframe will load content from.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setFrameUrl()}.
+ * @param string the URL that this iframe will load content from
+ * @see setFrameUrl
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setFrameUrl($value);
+ }
+
+ /**
+ * @return TInlineFrameScrollBars the visibility and position of scroll bars in an iframe. Defaults to TInlineFrameScrollBars::Auto.
+ */
+ public function getScrollBars()
+ {
+ return $this->getViewState('ScrollBars',TInlineFrameScrollBars::Auto);
+ }
+
+ /**
+ * @param TInlineFrameScrollBars the visibility and position of scroll bars in an iframe.
+ */
+ public function setScrollBars($value)
+ {
+ $this->setViewState('ScrollBars',TPropertyValue::ensureEnum($value,'TInlineFrameScrollBars'),TInlineFrameScrollBars::Auto);
+ }
+
+ /**
+ * @return integer the width of the control
+ */
+ public function getWidth()
+ {
+ return $this->getViewState('Width',-1);
+ }
+
+ /**
+ * @param integer the width of the control
+ */
+ public function setWidth($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ $this->setViewState('Width',$value,-1);
+ }
+
+ /**
+ * @return integer the height of the control
+ */
+ public function getHeight()
+ {
+ return $this->getViewState('Height',-1);
+ }
+
+ /**
+ * @param integer the height of the control
+ */
+ public function setHeight($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ $this->setViewState('Height',$value,-1);
+ }
+
+ /**
+ * @return integer the amount of space, in pixels, that should be left between
+ * the frame's contents and the left and right margins. Defaults to -1, meaning not set.
+ */
+ public function getMarginWidth()
+ {
+ return $this->getViewState('MarginWidth',-1);
+ }
+
+ /**
+ * @param integer the amount of space, in pixels, that should be left between
+ * the frame's contents and the left and right margins.
+ */
+ public function setMarginWidth($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ $this->setViewState('MarginWidth',$value,-1);
+ }
+
+ /**
+ * @return integer the amount of space, in pixels, that should be left between
+ * the frame's contents and the top and bottom margins. Defaults to -1, meaning not set.
+ */
+ public function getMarginHeight()
+ {
+ return $this->getViewState('MarginHeight',-1);
+ }
+
+ /**
+ * @param integer the amount of space, in pixels, that should be left between
+ * the frame's contents and the top and bottom margins.
+ */
+ public function setMarginHeight($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ $this->setViewState('MarginHeight',$value,-1);
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This overrides the parent implementation with additional button specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ if($this->getID()!=='')
+ $writer->addAttribute('name',$this->getUniqueID());
+
+ if(($src=$this->getFrameUrl())!=='')
+ $writer->addAttribute('src',$src);
+
+ if(($align=strtolower($this->getAlign()))!=='notset')
+ $writer->addAttribute('align',$align);
+
+ $scrollBars=$this->getScrollBars();
+ if($scrollBars===TInlineFrameScrollBars::None)
+ $writer->addAttribute('scrolling','no');
+ else if($scrollBars===TInlineFrameScrollBars::Both)
+ $writer->addAttribute('scrolling','yes');
+
+ if (!$this->getShowBorder())
+ $writer->addAttribute('frameborder','0');
+
+ if(($longdesc=$this->getDescriptionUrl())!=='')
+ $writer->addAttribute('longdesc',$longdesc);
+
+ if (($width=$this->getWidth())!==-1)
+ $writer->addAttribute('width',$width);
+
+ if (($height=$this->getHeight())!==-1)
+ $writer->addAttribute('height',$height);
+
+ if(($marginheight=$this->getMarginHeight())!==-1)
+ $writer->addAttribute('marginheight',$marginheight);
+
+ if(($marginwidth=$this->getMarginWidth())!==-1)
+ $writer->addAttribute('marginwidth',$marginwidth);
+
+ parent::addAttributesToRender($writer);
+ }
+}
+
+/**
+ * TInlineFrameAlign class.
+ * TInlineFrameAlign defines the enumerable type for the possible alignments
+ * that the content in a {@link TInlineFrame} could be.
+ *
+ * The following enumerable values are defined:
+ * - NotSet: the alignment is not specified.
+ * - Left: left aligned
+ * - Right: right aligned
+ * - Top: top aligned
+ * - Middle: middle aligned
+ * - Bottom: bottom aligned
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TInlineFrameAlign extends TEnumerable
+{
+ const NotSet='NotSet';
+ const Left='Left';
+ const Right='Right';
+ const Top='Top';
+ const Middle='Middle';
+ const Bottom='Bottom';
+}
+
+/**
+ * TInlineFrameScrollBars class.
+ * TInlineFrameScrollBars defines the enumerable type for the possible scroll bar mode
+ * that a {@link TInlineFrame} control could use.
+ *
+ * The following enumerable values are defined:
+ * - None: no scroll bars.
+ * - Auto: scroll bars automatically appeared when needed.
+ * - Both: show both horizontal and vertical scroll bars all the time.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TInlineFrameScrollBars extends TEnumerable
+{
+ const None='None';
+ const Auto='Auto';
+ const Both='Both';
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TItemDataRenderer.php b/lib/prado/framework/Web/UI/WebControls/TItemDataRenderer.php
new file mode 100644
index 0000000..1800fa7
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TItemDataRenderer.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * TItemDataRenderer class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ * @since 3.1.2
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataBoundControl');
+Prado::using('System.Web.UI.WebControls.TDataRenderer');
+
+/**
+ * TItemDataRenderer class
+ *
+ * TItemDataRenderer is the convient base class for template-based item data renderers.
+ * It implements the {@link IItemDataRenderer} interface, and because
+ * TItemDataRenderer extends from {@link TTemplateControl}, derived child
+ * classes can have templates to define their presentational layout.
+ *
+ * The following properties are provided by TItemDataRenderer:
+ * - {@link getItemIndex ItemIndex}: zero-based index of this renderer in the item list collection.
+ * - {@link getItemType ItemType}: item type of this renderer, such as TListItemType::AlternatingItem
+ * - {@link getData Data}: data associated with this renderer
+
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.2
+ */
+abstract class TItemDataRenderer extends TDataRenderer implements IItemDataRenderer
+{
+ /**
+ * index of the data item in the Items collection of repeater
+ */
+ private $_itemIndex;
+ /**
+ * type of the TRepeaterItem
+ * @var TListItemType
+ */
+ private $_itemType;
+
+ /**
+ * @return TListItemType item type
+ */
+ public function getItemType()
+ {
+ return $this->_itemType;
+ }
+
+ /**
+ * @param TListItemType item type.
+ */
+ public function setItemType($value)
+ {
+ $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
+ }
+
+ /**
+ * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection.
+ * If the item is not in the collection (e.g. it is a header item), it returns -1.
+ * @return integer zero-based index of the item.
+ */
+ public function getItemIndex()
+ {
+ return $this->_itemIndex;
+ }
+
+ /**
+ * Sets the zero-based index for the item.
+ * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
+ * @param integer zero-based index of the item.
+ */
+ public function setItemIndex($value)
+ {
+ $this->_itemIndex=TPropertyValue::ensureInteger($value);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TJavascriptLogger.php b/lib/prado/framework/Web/UI/WebControls/TJavascriptLogger.php
new file mode 100644
index 0000000..83f9fcb
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TJavascriptLogger.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * TJavascriptLogger class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TJavascriptLogger class.
+ *
+ * Provides logging for client-side javascript. Example: template code
+ * <code><com:TJavascriptLogger /></code>
+ *
+ * Client-side javascript code to log info, error, warn, debug
+ * <code>Logger.warn('A warning');
+ * Logger.info('something happend');
+ * </code>
+ *
+ * To see the logger and console, press ALT-D (or CTRL-D on OS X).
+ * More information on the logger can be found at
+ * http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/
+ *
+ * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TJavascriptLogger extends TWebControl
+{
+ private static $_keyCodes = array(
+ '0'=>48, '1'=>49, '2'=>50, '3'=>51, '4'=>52, '5'=>53, '6'=>54, '7'=>55, '8'=>56, '9'=>57,
+ 'a'=>65, 'b'=>66, 'c'=>67, 'd'=>68, 'e'=>69, 'f'=>70, 'g'=>71, 'h'=>72,
+ 'i'=>73, 'j'=>74, 'k'=>75, 'l'=>76, 'm'=>77, 'n'=>78, 'o'=>79, 'p'=>80,
+ 'q'=>81, 'r'=>82, 's'=>83, 't'=>84, 'u'=>85, 'v'=>86, 'w'=>87, 'x'=>88, 'y'=>89, 'z'=>90);
+
+ /**
+ * @return string tag name of the panel
+ */
+ protected function getTagName()
+ {
+ return 'div';
+ }
+
+ /**
+ * @param string keyboard key for toggling the console, default is J.
+ */
+ public function setToggleKey($value)
+ {
+ $this->setViewState('ToggleKey', $value, 'j');
+ }
+
+ /**
+ * @return string keyboard key for toggling the console.
+ */
+ public function getToggleKey()
+ {
+ return $this->getViewState('ToggleKey', 'j');
+ }
+
+ /**
+ * Registers the required logger javascript.
+ * @param TEventParameter event parameter
+ */
+ public function onPreRender($param)
+ {
+ $key = strtolower($this->getToggleKey());
+ $code = isset(self::$_keyCodes[$key]) ? self::$_keyCodes[$key] : 74;
+ $js = "var logConsole; jQuery(function() { logConsole = new LogConsole($code)}); ";
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerBeginScript($this->getClientID(),$js);
+ $cs->registerPradoScript('logger');
+ }
+
+ /**
+ * Register the required javascript libraries and
+ * display some general usage information.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ $code = strtoupper($this->getToggleKey());
+ $info = '(<a href="http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/" target="_blank">more info</a>).';
+ $link = '<a href="javascript:if(logConsole)logConsole.toggle()">toggle the javascript log console.</a>';
+ $usage = 'Press ALT-'.$code.' (Or CTRL-'.$code.' on OS X) to';
+ $writer->write("{$usage} {$link} {$info}");
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TKeyboard.php b/lib/prado/framework/Web/UI/WebControls/TKeyboard.php
new file mode 100644
index 0000000..15a4aa3
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TKeyboard.php
@@ -0,0 +1,187 @@
+<?php
+/**
+ * TKeyboard class file.
+ *
+ * @author Sergey Morkovkin <sergeymorkovkin@mail.ru> and Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+
+/**
+ * Class TKeyboard.
+ *
+ * TKeyboard displays a virtual keyboard that users can click on to enter input in
+ * an associated text box. It helps to reduce the keyboard recording hacking.
+ *
+ * To use TKeyboard, write a template like following:
+ * <code>
+ * <com:TTextBox ID="PasswordInput" />
+ * <com:TKeyboard ForControl="PasswordInput" />
+ * </code>
+ *
+ * A TKeyboard control is associated with a {@link TTextBox} control by specifying {@link setForControl ForControl}
+ * to be the ID of that control. When the textbox is in focus, a virtual keyboard will pop up; and when
+ * the text box is losing focus, the keyboard will hide automatically. Set {@link setAutoHide AutoHide} to
+ * false to keep the keyboard showing all the time.
+ *
+ * The appearance of the keyboard can also be changed by specifying a customized CSS file via
+ * {@link setCssUrl CssUrl}. By default, the CSS class name for the keyboard is 'Keyboard'. This may
+ * also be changed by specifying {@link setKeyboardCssClass KeyboardCssClass}.
+ *
+ * @author Sergey Morkovkin <sergeymorkovkin@mail.ru> and Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TKeyboard extends TWebControl
+{
+ /**
+ * @return string the ID path of the {@link TTextBox} control
+ */
+ public function getForControl()
+ {
+ return $this->getViewState('ForControl','');
+ }
+
+ /**
+ * Sets the ID path of the {@link TTextBox} control.
+ * The ID path is the dot-connected IDs of the controls reaching from
+ * the keyboard's naming container to the target control.
+ * @param string the ID path
+ */
+ public function setForControl($value)
+ {
+ $this->setViewState('ForControl', TPropertyValue::ensureString($value));
+ }
+
+ /**
+ * @return boolean whether the keyboard should be hidden when the textbox is not in focus. Defaults to true.
+ */
+ public function getAutoHide()
+ {
+ return $this->getViewState('AutoHide', true);
+ }
+
+ /**
+ * @param boolean whether the keyboard should be hidden when the textbox is not in focus.
+ */
+ public function setAutoHide($value)
+ {
+ $this->setViewState('AutoHide', TPropertyValue::ensureBoolean($value), true);
+ }
+
+ /**
+ * @return string the CSS class name for the keyboard <div> element. Defaults to 'Keyboard'.
+ */
+ public function getKeyboardCssClass()
+ {
+ return $this->getViewState('KeyboardCssClass', 'Keyboard');
+ }
+
+ /**
+ * Sets a value indicating the CSS class name for the keyboard <div> element.
+ * Note, if you change this property, make sure you also supply a customized CSS file
+ * by specifying {@link setCssUrl CssUrl} which uses the new CSS class name for styling.
+ * @param string the CSS class name for the keyboard <div> element.
+ */
+ public function setKeyboardCssClass($value)
+ {
+ $this->setViewState('KeyboardCssClass', $value, 'Keyboard');
+ }
+
+ /**
+ * @return string the URL for the CSS file to customize the appearance of the keyboard.
+ */
+ public function getCssUrl()
+ {
+ return $this->getViewState('CssUrl', '');
+ }
+
+ /**
+ * @param string the URL for the CSS file to customize the appearance of the keyboard.
+ */
+ public function setCssUrl($value)
+ {
+ $this->setViewState('CssUrl', $value, '');
+ }
+
+ /**
+ * Registers CSS and JS.
+ * This method is invoked right before the control rendering, if the control is visible.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ if($this->getPage()->getClientSupportsJavaScript())
+ {
+ $this->registerStyleSheet();
+ $this->registerClientScript();
+ }
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This method overrides the parent implementation with additional TKeyboard specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ if($this->getPage()->getClientSupportsJavaScript())
+ $writer->addAttribute('id',$this->getClientID());
+ }
+
+ /**
+ * Registers the CSS relevant to the TKeyboard.
+ * It will register the CSS file specified by {@link getCssUrl CssUrl}.
+ * If that is not set, it will use the default CSS.
+ */
+ protected function registerStyleSheet()
+ {
+ if(($url=$this->getCssUrl())==='')
+ $url=$this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'keyboard.css');
+ $this->getPage()->getClientScript()->registerStyleSheetFile($url,$url);
+ }
+
+ /**
+ * Registers the relevant JavaScript.
+ */
+ protected function registerClientScript()
+ {
+ $options=TJavaScript::encode($this->getClientOptions());
+ $className=$this->getClientClassName();
+ $cs=$this->getPage()->getClientScript();
+ $cs->registerPradoScript('keyboard');
+ $cs->registerEndScript('prado:'.$this->getClientID(), "new $className($options);");
+ }
+
+ /**
+ * @return string the Javascript class name for this control
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TKeyboard';
+ }
+
+ /**
+ * @return array the JavaScript options for this control
+ */
+ protected function getClientOptions()
+ {
+ if(($forControl=$this->getForControl())==='')
+ throw new TConfigurationException('keyboard_forcontrol_required');
+ if(($target=$this->findControl($forControl))===null)
+ throw new TConfigurationException('keyboard_forcontrol_invalid',$forControl);
+
+ $options['ID'] = $this->getClientID();
+ $options['ForControl'] = $target->getClientID();
+ $options['AutoHide'] = $this->getAutoHide();
+ $options['CssClass'] = $this->getKeyboardCssClass();
+
+ return $options;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TLabel.php b/lib/prado/framework/Web/UI/WebControls/TLabel.php
new file mode 100644
index 0000000..bf43b4d
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TLabel.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * TLabel class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TLabel class
+ *
+ * TLabel displays a piece of text on a Web page.
+ * Use {@link setText Text} property to set the text to be displayed.
+ * TLabel will render the contents enclosed within its component tag
+ * if {@link setText Text} is empty.
+ * To use TLabel as a form label, associate it with a control by setting the
+ * {@link setForControl ForControl} property.
+ * The associated control must be locatable within the label's naming container.
+ * If the associated control is not visible, the label will not be rendered, either.
+ *
+ * Note, {@link setText Text} will NOT be encoded for rendering.
+ * Make sure it does not contain dangerous characters that you want to avoid.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TLabel extends TWebControl implements IDataRenderer
+{
+ private $_forControl='';
+
+ /**
+ * @return string tag name of the label, returns 'label' if there is an associated control, 'span' otherwise.
+ */
+ protected function getTagName()
+ {
+ return ($this->getForControl()==='')?'span':'label';
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ * @throws TInvalidDataValueException if associated control cannot be found using the ID
+ */
+ protected function addAttributesToRender($writer)
+ {
+ if($this->_forControl!=='')
+ $writer->addAttribute('for',$this->_forControl);
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the label.
+ * It overrides the parent implementation by checking if an associated
+ * control is visible or not. If not, the label will not be rendered.
+ * @param THtmlWriter writer
+ */
+ public function render($writer)
+ {
+ if(($aid=$this->getForControl())!=='')
+ {
+ if($control=$this->findControl($aid))
+ {
+ if($control->getVisible(true))
+ {
+ $this->_forControl=$control->getClientID();
+ parent::render($writer);
+ }
+ }
+ else
+ throw new TInvalidDataValueException('label_associatedcontrol_invalid',$aid);
+ }
+ else
+ parent::render($writer);
+ }
+
+ /**
+ * Renders the body content of the label.
+ * @param THtmlWriter the renderer
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())==='')
+ parent::renderContents($writer);
+ else
+ $writer->write($text);
+ }
+
+ /**
+ * @return string the text value of the label
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * @param string the text value of the label
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * Returns the text value of the label.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string the text value of the label
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the text value of the label.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string the text value of the label
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * @return string the associated control ID
+ */
+ public function getForControl()
+ {
+ return $this->getViewState('ForControl','');
+ }
+
+ /**
+ * Sets the ID of the control that the label is associated with.
+ * The control must be locatable via {@link TControl::findControl} using the ID.
+ * @param string the associated control ID
+ */
+ public function setForControl($value)
+ {
+ $this->setViewState('ForControl',$value,'');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TLinkButton.php b/lib/prado/framework/Web/UI/WebControls/TLinkButton.php
new file mode 100644
index 0000000..dadea1d
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TLinkButton.php
@@ -0,0 +1,332 @@
+<?php
+/**
+ * TLinkButton class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TLinkButton class
+ *
+ * TLinkButton creates a hyperlink style button on the page.
+ * TLinkButton has the same appearance as a hyperlink. However, it is mainly
+ * used to submit data to a page. Like {@link TButton}, you can create either
+ * a <b>submit</b> button or a <b>command</b> button.
+ *
+ * A <b>command</b> button has a command name (specified by
+ * the {@link setCommandName CommandName} property) and and a command parameter
+ * (specified by {@link setCommandParameter CommandParameter} property)
+ * associated with the button. This allows you to create multiple TLinkButton
+ * components on a Web page and programmatically determine which one is clicked
+ * with what parameter. You can provide an event handler for
+ * {@link onCommand OnCommand} event to programmatically control the actions performed
+ * when the command button is clicked. In the event handler, you can determine
+ * the {@link setCommandName CommandName} property value and
+ * the {@link setCommandParameter CommandParameter} property value
+ * through the {@link TCommandParameter::getName Name} and
+ * {@link TCommandParameter::getParameter Parameter} properties of the event
+ * parameter which is of type {@link TCommandEventParameter}.
+ *
+ * A <b>submit</b> button does not have a command name associated with the button
+ * and clicking on it simply posts the Web page back to the server.
+ * By default, a TLinkButton component is a submit button.
+ * You can provide an event handler for the {@link onClick OnClick} event
+ * to programmatically control the actions performed when the submit button is clicked.
+ *
+ * Clicking on button can trigger form validation, if
+ * {@link setCausesValidation CausesValidation} is true.
+ * And the validation may be restricted within a certain group of validator
+ * controls by setting {@link setValidationGroup ValidationGroup} property.
+ * If validation is successful, the data will be post back to the same page.
+ *
+ * TLinkButton will display the {@link setText Text} property value
+ * as the hyperlink text. If {@link setText Text} is empty, the body content
+ * of TLinkButton will be displayed. Therefore, you can use TLinkButton
+ * as an image button by enclosing an &lt;img&gt; tag as the body of TLinkButton.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TLinkButton extends TWebControl implements IPostBackEventHandler, IButtonControl, IDataRenderer
+{
+ /**
+ * @return string tag name of the button
+ */
+ protected function getTagName()
+ {
+ return 'a';
+ }
+
+ /**
+ * @return boolean whether to render javascript.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether to render javascript.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This overrides the parent implementation with additional button specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $page=$this->getPage();
+ $page->ensureRenderInForm($this);
+
+ $writer->addAttribute('id',$this->getClientID());
+
+ // We call parent implementation here because some attributes
+ // may be overwritten in the following
+ parent::addAttributesToRender($writer);
+
+ if($this->getEnabled(true) && $this->getEnableClientScript())
+ {
+ $this->renderLinkButtonHref($writer);
+ $this->renderClientControlScript($writer);
+ }
+ else if($this->getEnabled()) // in this case, parent will not render 'disabled'
+ $writer->addAttribute('disabled','disabled');
+ }
+
+ /**
+ * Renders the client-script code.
+ * @param THtmlWriter renderer
+ */
+ protected function renderClientControlScript($writer)
+ {
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+
+ /**
+ * @param boolean set by a panel to register this button as the default button for the panel.
+ */
+ public function setIsDefaultButton($value)
+ {
+ $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean true if this button is registered as a default button for a panel.
+ */
+ public function getIsDefaultButton()
+ {
+ return $this->getViewState('IsDefaultButton', false);
+ }
+
+ /**
+ * Renders the Href for link button.
+ * @param THtmlWriter renderer
+ */
+ protected function renderLinkButtonHref($writer)
+ {
+ //create unique no-op url references
+ $nop = "javascript:;//".$this->getClientID();
+ $writer->addAttribute('href', $nop);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TLinkButton';
+ }
+
+ /**
+ * Returns postback specifications for the button.
+ * This method is used by framework and control developers.
+ * @return array parameters about how the button defines its postback behavior.
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['StopEvent'] = true;
+
+ return $options;
+ }
+
+ /**
+ * Renders the body content enclosed between the control tag.
+ * If {@link getText Text} is not empty, it will be rendered. Otherwise,
+ * the body content enclosed in the control tag will be rendered.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())==='')
+ parent::renderContents($writer);
+ else
+ $writer->write($text);
+ }
+
+ /**
+ * @return string the text caption of the button
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * @param string the text caption to be set
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * Returns the caption of the button.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string caption of the button.
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the caption of the button.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string caption of the button
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * @return string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function getCommandName()
+ {
+ return $this->getViewState('CommandName','');
+ }
+
+ /**
+ * @param string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandName($value)
+ {
+ $this->setViewState('CommandName',$value,'');
+ }
+
+ /**
+ * @return string the parameter associated with the {@link onCommand OnCommand} event
+ */
+ public function getCommandParameter()
+ {
+ return $this->getViewState('CommandParameter','');
+ }
+
+ /**
+ * @param string the parameter associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandParameter($value)
+ {
+ $this->setViewState('CommandParameter',$value,'');
+ }
+
+ /**
+ * @return boolean whether postback event trigger by this button will cause input validation
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * Sets the value indicating whether postback event trigger by this button will cause input validation.
+ * @param string the text caption to be set
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the group of validators which the button causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the button causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * Raises the postback event.
+ * This method is required by {@link IPostBackEventHandler} interface.
+ * If {@link getCausesValidation CausesValidation} is true, it will
+ * invoke the page's {@link TPage::validate validate} method first.
+ * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events.
+ * This method is mainly used by framework and control developers.
+ * @param TEventParameter the event parameter
+ */
+ public function raisePostBackEvent($param)
+ {
+ if($this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onClick(null);
+ $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter()));
+ }
+
+ /**
+ * This method is invoked when the button is clicked.
+ * The method raises 'OnClick' event to fire up the event handlers.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handler can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onClick($param)
+ {
+ $this->raiseEvent('OnClick',$this,$param);
+ }
+
+ /**
+ * This method is invoked when the button is clicked.
+ * The method raises 'OnCommand' event to fire up the event handlers.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TCommandEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCommand($param)
+ {
+ $this->raiseEvent('OnCommand',$this,$param);
+ $this->raiseBubbleEvent($this,$param);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TListBox.php b/lib/prado/framework/Web/UI/WebControls/TListBox.php
new file mode 100644
index 0000000..520fc5e
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TListBox.php
@@ -0,0 +1,259 @@
+<?php
+/**
+ * TListBox class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TListControl class
+ */
+Prado::using('System.Web.UI.WebControls.TListControl');
+
+/**
+ * TListBox class
+ *
+ * TListBox displays a list box on a Web page that allows single or multiple selection.
+ * The list box allows multiple selections if {@link setSelectionMode SelectionMode}
+ * is TListSelectionMode::Multiple. It takes single selection only if Single.
+ * The property {@link setRows Rows} specifies how many rows of options are visible
+ * at a time. See {@link TListControl} for inherited properties.
+ *
+ * Since v3.0.3, TListBox starts to support optgroup. To specify an option group for
+ * a list item, set a Group attribute with it,
+ * <code>
+ * $listitem->Attributes->Group="Group Name";
+ * // or <com:TListItem Attributes.Group="Group Name" .../> in template
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TListBox extends TListControl implements IPostBackDataHandler, IValidatable
+{
+ private $_dataChanged=false;
+ private $_isValid=true;
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This method overrides the parent implementation with additional list box specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $rows=$this->getRows();
+ $writer->addAttribute('size',"$rows");
+ if($this->getSelectionMode()===TListSelectionMode::Multiple)
+ $writer->addAttribute('name',$this->getUniqueID().'[]');
+ else
+ $writer->addAttribute('name',$this->getUniqueID());
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TListBox';
+ }
+
+ /**
+ * Registers the list control to load post data on postback.
+ * This method overrides the parent implementation.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ if($this->getEnabled(true))
+ $this->getPage()->registerRequiresPostData($this);
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if(!$this->getEnabled(true))
+ return false;
+ $this->ensureDataBound();
+ $selections=isset($values[$key])?$values[$key]:null;
+ if($selections!==null)
+ {
+ $items=$this->getItems();
+ if($this->getSelectionMode()===TListSelectionMode::Single)
+ {
+ $selection=is_array($selections)?$selections[0]:$selections;
+ $index=$items->findIndexByValue($selection,false);
+ if($this->getSelectedIndex()!==$index)
+ {
+ $this->setSelectedIndex($index);
+ return $this->_dataChanged=true;
+ }
+ else
+ return false;
+ }
+ if(!is_array($selections))
+ $selections=array($selections);
+ $list=array();
+ foreach($selections as $selection)
+ $list[]=$items->findIndexByValue($selection,false);
+ $list2=$this->getSelectedIndices();
+ $n=count($list);
+ $flag=false;
+ if($n===count($list2))
+ {
+ sort($list,SORT_NUMERIC);
+ for($i=0;$i<$n;++$i)
+ {
+ if($list[$i]!==$list2[$i])
+ {
+ $flag=true;
+ break;
+ }
+ }
+ }
+ else
+ $flag=true;
+ if($flag)
+ {
+ $this->setSelectedIndices($list);
+ $this->_dataChanged=true;
+ }
+ return $flag;
+ }
+ else if($this->getSelectedIndex()!==-1)
+ {
+ $this->clearSelection();
+ return $this->_dataChanged=true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method is required by {@link IPostBackDataHandler} interface.
+ * It is invoked by the framework when {@link getSelectedIndices SelectedIndices} property
+ * is changed on postback.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ if($this->getAutoPostBack() && $this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onSelectedIndexChanged(null);
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * @return boolean whether this control allows multiple selection
+ */
+ protected function getIsMultiSelect()
+ {
+ return $this->getSelectionMode()===TListSelectionMode::Multiple;
+ }
+
+ /**
+ * @return integer the number of rows to be displayed in the list control
+ */
+ public function getRows()
+ {
+ return $this->getViewState('Rows', 4);
+ }
+
+ /**
+ * @param integer the number of rows to be displayed in the list control
+ */
+ public function setRows($value)
+ {
+ $value=TPropertyValue::ensureInteger($value);
+ if($value<=0)
+ $value=4;
+ $this->setViewState('Rows', $value, 4);
+ }
+
+ /**
+ * @return TListSelectionMode the selection mode (Single, Multiple). Defaults to TListSelectionMode::Single.
+ */
+ public function getSelectionMode()
+ {
+ return $this->getViewState('SelectionMode', TListSelectionMode::Single);
+ }
+
+ /**
+ * @param TListSelectionMode the selection mode
+ */
+ public function setSelectionMode($value)
+ {
+ $this->setViewState('SelectionMode',TPropertyValue::ensureEnum($value,'TListSelectionMode'),TListSelectionMode::Single);
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getSelectedValue();
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+}
+
+
+/**
+ * TListSelectionMode class.
+ * TListSelectionMode defines the enumerable type for the possible selection modes of a {@link TListBox}.
+ *
+ * The following enumerable values are defined:
+ * - Single: single selection
+ * - Multiple: allow multiple selection
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TListSelectionMode extends TEnumerable
+{
+ const Single='Single';
+ const Multiple='Multiple';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TListControl.php b/lib/prado/framework/Web/UI/WebControls/TListControl.php
new file mode 100644
index 0000000..ff89a74
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TListControl.php
@@ -0,0 +1,923 @@
+<?php
+
+/**
+ * TListControl class file
+ *
+ * @author Robin J. Rogge <rojaro@gmail.com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes the supporting classes
+ */
+Prado::using('System.Web.UI.WebControls.TDataBoundControl');
+Prado::using('System.Web.UI.WebControls.TListItem');
+Prado::using('System.Collections.TListItemCollection');
+Prado::using('System.Collections.TAttributeCollection');
+Prado::using('System.Util.TDataFieldAccessor');
+
+/**
+ * TListControl class
+ *
+ * TListControl is a base class for list controls, such as {@link TListBox},
+ * {@link TDropDownList}, {@link TCheckBoxList}, etc.
+ * It manages the items and their status in a list control.
+ * It also implements how the items can be populated from template and
+ * data source.
+ *
+ * The property {@link getItems} returns a list of the items in the control.
+ * To specify or determine which item is selected, use the
+ * {@link getSelectedIndex SelectedIndex} property that indicates the zero-based
+ * index of the selected item in the item list. You may also use
+ * {@link getSelectedItem SelectedItem} and {@link getSelectedValue SelectedValue}
+ * to get the selected item and its value. For multiple selection lists
+ * (such as {@link TCheckBoxList} and {@link TListBox}), property
+ * {@link getSelectedIndices SelectedIndices} is useful.
+ *
+ * TListControl implements {@link setAutoPostBack AutoPostBack} which allows
+ * a list control to postback the page if the selections of the list items are changed.
+ * The {@link setCausesValidation CausesValidation} and {@link setValidationGroup ValidationGroup}
+ * properties may be used to specify that validation be performed when auto postback occurs.
+ *
+ * There are three ways to populate the items in a list control: from template,
+ * using {@link setDataSource DataSource} and using {@link setDataSourceID DataSourceID}.
+ * The latter two are covered in {@link TDataBoundControl}. To specify items via
+ * template, using the following template syntax:
+ * <code>
+ * <com:TListControl>
+ * <com:TListItem Value="xxx" Text="yyy" >
+ * <com:TListItem Value="xxx" Text="yyy" Selected="true" >
+ * <com:TListItem Value="xxx" Text="yyy" >
+ * </com:TListControl>
+ * </code>
+ *
+ * When {@link setDataSource DataSource} or {@link setDataSourceID DataSourceID}
+ * is used to populate list items, the {@link setDataTextField DataTextField} and
+ * {@link setDataValueField DataValueField} properties are used to specify which
+ * columns of the data will be used to populate the text and value of the items.
+ * For example, if a data source is as follows,
+ * <code>
+ * $dataSource=array(
+ * array('name'=>'John', 'age'=>31),
+ * array('name'=>'Cary', 'age'=>28),
+ * array('name'=>'Rose', 'age'=>35),
+ * );
+ * </code>
+ * setting {@link setDataTextField DataTextField} and {@link setDataValueField DataValueField}
+ * to 'name' and 'age' will make the first item's text be 'John', value be 31,
+ * the second item's text be 'Cary', value be 28, and so on.
+ * The {@link setDataTextFormatString DataTextFormatString} property may be further
+ * used to format how the item should be displayed. See {@link formatDataValue()}
+ * for an explanation of the format string.
+ *
+ * The {@link setPromptText PromptText} and {@link setPromptValue PromptValue} properties can
+ * be used to add a dummy list item that will be rendered first.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TListControl extends TDataBoundControl implements IDataRenderer
+{
+ /**
+ * @var TListItemCollection item list
+ */
+ private $_items=null;
+ /**
+ * @var boolean whether items are restored from viewstate
+ */
+ private $_stateLoaded=false;
+ /**
+ * @var mixed the following selection variables are used
+ * to keep selections when Items are not available
+ */
+ private $_cachedSelectedIndex=-1;
+ private $_cachedSelectedValue=null;
+ private $_cachedSelectedIndices=null;
+ private $_cachedSelectedValues=null;
+
+ /**
+ * @return string tag name of the list control
+ */
+ protected function getTagName()
+ {
+ return 'select';
+ }
+
+ /**
+ * @return boolean whether to render javascript.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether to render javascript.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $page=$this->getPage();
+ $page->ensureRenderInForm($this);
+ if($this->getIsMultiSelect())
+ $writer->addAttribute('multiple','multiple');
+ if($this->getEnabled(true))
+ {
+ if($this->getAutoPostBack()
+ && $this->getEnableClientScript()
+ && $page->getClientSupportsJavaScript())
+ {
+ $this->renderClientControlScript($writer);
+ }
+ }
+ else if($this->getEnabled())
+ $writer->addAttribute('disabled','disabled');
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the javascript for list control.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $this->getPage()->getClientScript()->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * Derived classes may override this method and return customized js class names.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TListControl';
+ }
+
+ /**
+ * @return array postback options for JS postback code
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['EventTarget'] = $this->getUniqueID();
+ return $options;
+ }
+
+ /**
+ * Adds object parsed from template to the control.
+ * This method adds only {@link TListItem} objects into the {@link getItems Items} collection.
+ * All other objects are ignored.
+ * @param mixed object parsed from template
+ */
+ public function addParsedObject($object)
+ {
+ // Do not add items from template if items are loaded from viewstate
+ if(!$this->_stateLoaded && ($object instanceof TListItem))
+ {
+ $index=$this->getItems()->add($object);
+ if(($this->_cachedSelectedValue!==null && $this->_cachedSelectedValue===$object->getValue()) || ($this->_cachedSelectedIndex===$index))
+ {
+ $object->setSelected(true);
+ $this->_cachedSelectedValue=null;
+ $this->_cachedSelectedIndex=-1;
+ }
+ }
+ }
+
+ /**
+ * Performs databinding to populate list items from data source.
+ * This method is invoked by dataBind().
+ * You may override this function to provide your own way of data population.
+ * @param Traversable the data
+ */
+ protected function performDataBinding($data)
+ {
+ $items=$this->getItems();
+ if(!$this->getAppendDataBoundItems())
+ $items->clear();
+ $textField=$this->getDataTextField();
+ if($textField==='')
+ $textField=0;
+ $valueField=$this->getDataValueField();
+ if($valueField==='')
+ $valueField=1;
+ $textFormat=$this->getDataTextFormatString();
+ $groupField=$this->getDataGroupField();
+ foreach($data as $key=>$object)
+ {
+ $item=$items->createListItem();
+ if(is_array($object) || is_object($object))
+ {
+ $text=TDataFieldAccessor::getDataFieldValue($object,$textField);
+ $value=TDataFieldAccessor::getDataFieldValue($object,$valueField);
+ $item->setValue($value);
+ if($groupField!=='')
+ $item->setAttribute('Group',TDataFieldAccessor::getDataFieldValue($object,$groupField));
+ }
+ else
+ {
+ $text=$object;
+ $item->setValue("$key");
+ }
+ $item->setText($this->formatDataValue($textFormat,$text));
+ }
+ // SelectedValue or SelectedIndex may be set before databinding
+ // so we make them be effective now
+ if($this->_cachedSelectedValue!==null)
+ {
+ $this->setSelectedValue($this->_cachedSelectedValue);
+ $this->resetCachedSelections();
+ }
+ else if($this->_cachedSelectedIndex!==-1)
+ {
+ $this->setSelectedIndex($this->_cachedSelectedIndex);
+ $this->resetCachedSelections();
+ }
+ else if($this->_cachedSelectedValues!==null)
+ {
+ $this->setSelectedValues($this->_cachedSelectedValues);
+ $this->resetCachedSelections();
+ }
+ else if($this->_cachedSelectedIndices!==null)
+ {
+ $this->setSelectedIndices($this->_cachedSelectedIndices);
+ $this->resetCachedSelections();
+ }
+ }
+
+ private function resetCachedSelections()
+ {
+ $this->_cachedSelectedValue=null;
+ $this->_cachedSelectedIndex=-1;
+ $this->_cachedSelectedValues=null;
+ $this->_cachedSelectedIndices=null;
+ }
+
+ /**
+ * Creates a collection object to hold list items.
+ * This method may be overriden to create a customized collection.
+ * @return TListItemCollection the collection object
+ */
+ protected function createListItemCollection()
+ {
+ return new TListItemCollection;
+ }
+
+ /**
+ * Saves items into viewstate.
+ * This method is invoked right before control state is to be saved.
+ */
+ public function saveState()
+ {
+ parent::saveState();
+ if($this->_items)
+ $this->setViewState('Items',$this->_items->saveState(),null);
+ else
+ $this->clearViewState('Items');
+ }
+
+ /**
+ * Loads items from viewstate.
+ * This method is invoked right after control state is loaded.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ $this->_stateLoaded=true;
+ if(!$this->getIsDataBound())
+ {
+ $this->_items=$this->createListItemCollection();
+ $this->_items->loadState($this->getViewState('Items',null));
+ }
+ $this->clearViewState('Items');
+ }
+
+ /**
+ * @return boolean whether this is a multiselect control. Defaults to false.
+ */
+ protected function getIsMultiSelect()
+ {
+ return false;
+ }
+
+ /**
+ * @return boolean whether performing databind should append items or clear the existing ones. Defaults to false.
+ */
+ public function getAppendDataBoundItems()
+ {
+ return $this->getViewState('AppendDataBoundItems',false);
+ }
+
+ /**
+ * @param boolean whether performing databind should append items or clear the existing ones.
+ */
+ public function setAppendDataBoundItems($value)
+ {
+ $this->setViewState('AppendDataBoundItems',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean a value indicating whether an automatic postback to the server
+ * will occur whenever the user makes change to the list control and then tabs out of it.
+ * Defaults to false.
+ */
+ public function getAutoPostBack()
+ {
+ return $this->getViewState('AutoPostBack',false);
+ }
+
+ /**
+ * Sets the value indicating if postback automatically.
+ * An automatic postback to the server will occur whenever the user
+ * makes change to the list control and then tabs out of it.
+ * @param boolean the value indicating if postback automatically
+ */
+ public function setAutoPostBack($value)
+ {
+ $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether postback event trigger by this list control will cause input validation, default is true.
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by this list control will cause input validation.
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the field of the data source that provides the text content of the list items.
+ */
+ public function getDataTextField()
+ {
+ return $this->getViewState('DataTextField','');
+ }
+
+ /**
+ * @param string the field of the data source that provides the text content of the list items.
+ */
+ public function setDataTextField($value)
+ {
+ $this->setViewState('DataTextField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how data bound to the list control is displayed.
+ */
+ public function getDataTextFormatString()
+ {
+ return $this->getViewState('DataTextFormatString','');
+ }
+
+ /**
+ * Sets data text format string.
+ * The format string is used in {@link TDataValueFormatter::format()} to format the Text property value
+ * of each item in the list control.
+ * @param string the formatting string used to control how data bound to the list control is displayed.
+ * @see TDataValueFormatter::format()
+ */
+ public function setDataTextFormatString($value)
+ {
+ $this->setViewState('DataTextFormatString',$value,'');
+ }
+
+ /**
+ * @return string the field of the data source that provides the value of each list item.
+ */
+ public function getDataValueField()
+ {
+ return $this->getViewState('DataValueField','');
+ }
+
+ /**
+ * @param string the field of the data source that provides the value of each list item.
+ */
+ public function setDataValueField($value)
+ {
+ $this->setViewState('DataValueField',$value,'');
+ }
+
+ /**
+ * @return string the field of the data source that provides the label of the list item groups
+ */
+ public function getDataGroupField()
+ {
+ return $this->getViewState('DataGroupField','');
+ }
+
+ /**
+ * @param string the field of the data source that provides the label of the list item groups
+ */
+ public function setDataGroupField($value)
+ {
+ $this->setViewState('DataGroupField',$value,'');
+ }
+
+ /**
+ * @return integer the number of items in the list control
+ */
+ public function getItemCount()
+ {
+ return $this->_items?$this->_items->getCount():0;
+ }
+
+ /**
+ * @return boolean whether the list control contains any items.
+ */
+ public function getHasItems()
+ {
+ return ($this->_items && $this->_items->getCount()>0);
+ }
+
+ /**
+ * @return TListItemCollection the item collection
+ */
+ public function getItems()
+ {
+ if(!$this->_items)
+ $this->_items=$this->createListItemCollection();
+ return $this->_items;
+ }
+
+ /**
+ * @return integer the index (zero-based) of the item being selected, -1 if no item is selected.
+ */
+ public function getSelectedIndex()
+ {
+ if($this->_items)
+ {
+ $n=$this->_items->getCount();
+ for($i=0;$i<$n;++$i)
+ if($this->_items->itemAt($i)->getSelected())
+ return $i;
+ }
+ return -1;
+ }
+
+ /**
+ * @param integer the index (zero-based) of the item to be selected
+ */
+ public function setSelectedIndex($index)
+ {
+ if(($index=TPropertyValue::ensureInteger($index))<0)
+ $index=-1;
+ if($this->_items)
+ {
+ $this->clearSelection();
+ if($index>=0 && $index<$this->_items->getCount())
+ $this->_items->itemAt($index)->setSelected(true);
+ }
+ $this->_cachedSelectedIndex=$index;
+ if($this->getAdapter() instanceof IListControlAdapter)
+ $this->getAdapter()->setSelectedIndex($index);
+ }
+
+ /**
+ * @return array list of index of items that are selected
+ */
+ public function getSelectedIndices()
+ {
+ $selections=array();
+ if($this->_items)
+ {
+ $n=$this->_items->getCount();
+ for($i=0;$i<$n;++$i)
+ if($this->_items->itemAt($i)->getSelected())
+ $selections[]=$i;
+ }
+ return $selections;
+ }
+
+ /**
+ * @param array list of index of items to be selected
+ */
+ public function setSelectedIndices($indices)
+ {
+ if($this->getIsMultiSelect())
+ {
+ if($this->_items)
+ {
+ $this->clearSelection();
+ $n=$this->_items->getCount();
+ foreach($indices as $index)
+ {
+ if($index>=0 && $index<$n)
+ $this->_items->itemAt($index)->setSelected(true);
+ }
+ }
+ $this->_cachedSelectedIndices=$indices;
+ }
+ else
+ throw new TNotSupportedException('listcontrol_multiselect_unsupported',get_class($this));
+
+ if($this->getAdapter() instanceof IListControlAdapter)
+ $this->getAdapter()->setSelectedIndices($indices);
+ }
+
+ /**
+ * @return TListItem|null the selected item with the lowest cardinal index, null if no item is selected.
+ */
+ public function getSelectedItem()
+ {
+ if(($index=$this->getSelectedIndex())>=0)
+ return $this->_items->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * Returns the value of the selected item with the lowest cardinal index.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getSelectedValue()}.
+ * @return string the value of the selected item with the lowest cardinal index, empty if no selection.
+ * @see getSelectedValue
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getSelectedValue();
+ }
+
+ /**
+ * Selects an item by the specified value.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setSelectedValue()}.
+ * @param string the value of the item to be selected.
+ * @see setSelectedValue
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setSelectedValue($value);
+ }
+
+ /**
+ * @return string the value of the selected item with the lowest cardinal index, empty if no selection
+ */
+ public function getSelectedValue()
+ {
+ $index=$this->getSelectedIndex();
+ return $index>=0?$this->getItems()->itemAt($index)->getValue():'';
+ }
+
+ /**
+ * Sets selection by item value.
+ * Existing selections will be cleared if the item value is found in the item collection.
+ * Note, if the value is null, existing selections will also be cleared.
+ * @param string the value of the item to be selected.
+ */
+ public function setSelectedValue($value)
+ {
+ if($this->_items)
+ {
+ if($value===null)
+ $this->clearSelection();
+ else if(($item=$this->_items->findItemByValue($value))!==null)
+ {
+ $this->clearSelection();
+ $item->setSelected(true);
+ }
+ else
+ $this->clearSelection();
+ }
+ $this->_cachedSelectedValue=$value;
+ if($this->getAdapter() instanceof IListControlAdapter)
+ $this->getAdapter()->setSelectedValue($value);
+ }
+
+
+ /**
+ * @return array list of the selected item values (strings)
+ */
+ public function getSelectedValues()
+ {
+ $values=array();
+ if($this->_items)
+ {
+ foreach($this->_items as $item)
+ {
+ if($item->getSelected())
+ $values[]=$item->getValue();
+ }
+ }
+ return $values;
+ }
+
+ /**
+ * @param array list of the selected item values
+ */
+ public function setSelectedValues($values)
+ {
+ if($this->getIsMultiSelect())
+ {
+ if($this->_items)
+ {
+ $this->clearSelection();
+ $lookup=array();
+ foreach($this->_items as $item)
+ $lookup[$item->getValue()]=$item;
+ foreach($values as $value)
+ {
+ if(isset($lookup["$value"]))
+ $lookup["$value"]->setSelected(true);
+ }
+ }
+ $this->_cachedSelectedValues=$values;
+ }
+ else
+ throw new TNotSupportedException('listcontrol_multiselect_unsupported',get_class($this));
+
+ if($this->getAdapter() instanceof IListControlAdapter)
+ $this->getAdapter()->setSelectedValues($values);
+ }
+
+ /**
+ * @return string selected value
+ */
+ public function getText()
+ {
+ return $this->getSelectedValue();
+ }
+
+ /**
+ * @param string value to be selected
+ */
+ public function setText($value)
+ {
+ $this->setSelectedValue($value);
+ }
+
+ /**
+ * Clears all existing selections.
+ */
+ public function clearSelection()
+ {
+ if($this->_items)
+ {
+ foreach($this->_items as $item)
+ $item->setSelected(false);
+ }
+
+ if($this->getAdapter() instanceof IListControlAdapter)
+ $this->getAdapter()->clearSelection();
+ }
+
+ /**
+ * @return string the group of validators which the list control causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the list control causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return string the prompt text which is to be displayed as the first list item.
+ * @since 3.1.1
+ */
+ public function getPromptText()
+ {
+ return $this->getViewState('PromptText','');
+ }
+
+ /**
+ * @param string the prompt text which is to be displayed as the first list item.
+ * @since 3.1.1
+ */
+ public function setPromptText($value)
+ {
+ $this->setViewState('PromptText',$value,'');
+ }
+
+ /**
+ * @return string the prompt selection value.
+ * @see getPromptText
+ * @since 3.1.1
+ */
+ public function getPromptValue()
+ {
+ return $this->getViewState('PromptValue','');
+ }
+
+ /**
+ * @param string the prompt selection value. If empty, {@link getPromptText PromptText} will be used as the value.
+ * @see setPromptText
+ * @since 3.1.1
+ */
+ public function setPromptValue($value)
+ {
+ $this->setViewState('PromptValue',(string)$value,'');
+ }
+
+ /**
+ * Raises OnSelectedIndexChanged event when selection is changed.
+ * This method is invoked when the list control has its selection changed
+ * by end-users.
+ * @param TEventParameter event parameter
+ */
+ public function onSelectedIndexChanged($param)
+ {
+ $this->raiseEvent('OnSelectedIndexChanged',$this,$param);
+ $this->onTextChanged($param);
+ }
+
+ /**
+ * Raises OnTextChanged event when selection is changed.
+ * This method is invoked when the list control has its selection changed
+ * by end-users.
+ * @param TEventParameter event parameter
+ */
+ public function onTextChanged($param)
+ {
+ $this->raiseEvent('OnTextChanged',$this,$param);
+ }
+
+ /**
+ * Renders the prompt text, if any.
+ * @param THtmlWriter writer
+ * @since 3.1.1
+ */
+ protected function renderPrompt($writer)
+ {
+ $text=$this->getPromptText();
+ $value=$this->getPromptValue();
+ if($value==='')
+ $value=$text;
+ if($value!=='')
+ {
+ $writer->addAttribute('value',$value);
+ $writer->renderBeginTag('option');
+ $writer->write(THttpUtility::htmlEncode($text));
+ $writer->renderEndTag();
+ $writer->writeLine();
+ }
+ }
+
+ /**
+ * Renders body content of the list control.
+ * This method renders items contained in the list control as the body content.
+ * @param THtmlWriter writer
+ */
+ public function renderContents($writer)
+ {
+ $this->renderPrompt($writer);
+
+ if($this->_items)
+ {
+ $writer->writeLine();
+ $previousGroup=null;
+ foreach($this->_items as $item)
+ {
+ if($item->getEnabled())
+ {
+ if($item->getHasAttributes())
+ {
+ $group=$item->getAttributes()->remove('Group');
+ if($group!==$previousGroup)
+ {
+ if($previousGroup!==null)
+ {
+ $writer->renderEndTag();
+ $writer->writeLine();
+ $previousGroup=null;
+ }
+ if($group!==null)
+ {
+ $writer->addAttribute('label',$group);
+ $writer->renderBeginTag('optgroup');
+ $writer->writeLine();
+ $previousGroup=$group;
+ }
+ }
+ foreach($item->getAttributes() as $name=>$value)
+ $writer->addAttribute($name,$value);
+ }
+ else if($previousGroup!==null)
+ {
+ $writer->renderEndTag();
+ $writer->writeLine();
+ $previousGroup=null;
+ }
+ if($item->getSelected())
+ $writer->addAttribute('selected','selected');
+ $writer->addAttribute('value',$item->getValue());
+ $writer->renderBeginTag('option');
+ $writer->write(THttpUtility::htmlEncode($item->getText()));
+ $writer->renderEndTag();
+ $writer->writeLine();
+ }
+ }
+ if($previousGroup!==null)
+ {
+ $writer->renderEndTag();
+ $writer->writeLine();
+ }
+ }
+ }
+
+ /**
+ * Formats the text value according to a format string.
+ * If the format string is empty, the original value is converted into
+ * a string and returned.
+ * If the format string starts with '#', the string is treated as a PHP expression
+ * within which the token '{0}' is translated with the data value to be formated.
+ * Otherwise, the format string and the data value are passed
+ * as the first and second parameters in {@link sprintf}.
+ * @param string format string
+ * @param mixed the data to be formatted
+ * @return string the formatted result
+ */
+ protected function formatDataValue($formatString,$value)
+ {
+ if($formatString==='')
+ return TPropertyValue::ensureString($value);
+ else if($formatString[0]==='#')
+ {
+ $expression=strtr(substr($formatString,1),array('{0}'=>'$value'));
+ try
+ {
+ if(eval("\$result=$expression;")===false)
+ throw new Exception('');
+ return $result;
+ }
+ catch(Exception $e)
+ {
+ throw new TInvalidDataValueException('listcontrol_expression_invalid',get_class($this),$expression,$e->getMessage());
+ }
+ }
+ else
+ return sprintf($formatString,$value);
+ }
+}
+
+/**
+ * IListControlAdapter interface
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ Sun Jun 25 04:53:43 EST 2006 $
+ * @package System.Web.UI.ActiveControls
+ * @since 3.0
+ */
+interface IListControlAdapter
+{
+ /**
+ * Selects an item based on zero-base index on the client side.
+ * @param integer the index (zero-based) of the item to be selected
+ */
+ public function setSelectedIndex($index);
+ /**
+ * Selects a list of item based on zero-base indices on the client side.
+ * @param array list of index of items to be selected
+ */
+ public function setSelectedIndices($indices);
+
+ /**
+ * Sets selection by item value on the client side.
+ * @param string the value of the item to be selected.
+ */
+ public function setSelectedValue($value);
+
+ /**
+ * Sets selection by a list of item values on the client side.
+ * @param array list of the selected item values
+ */
+ public function setSelectedValues($values);
+
+ /**
+ * Clears all existing selections on the client side.
+ */
+ public function clearSelection();
+}
+
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TListControlValidator.php b/lib/prado/framework/Web/UI/WebControls/TListControlValidator.php
new file mode 100644
index 0000000..76096ef
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TListControlValidator.php
@@ -0,0 +1,223 @@
+<?php
+/**
+ * TListControlValidator class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TListControlValidator class.
+ *
+ * TListControlValidator checks the number of selection and their values
+ * for a <b>TListControl that allows multiple selection</b>.
+ *
+ * You can specify the minimum or maximum (or both) number of selections
+ * required using the {@link setMinSelection MinSelection} and
+ * {@link setMaxSelection MaxSelection} properties, respectively. In addition,
+ * you can specify a comma separated list of required selected values via the
+ * {@link setRequiredSelections RequiredSelections} property.
+ *
+ * Examples
+ * - At least two selections
+ * <code>
+ * <com:TListBox ID="listbox" SelectionMode="Multiple">
+ * <com:TListItem Text="item1" Value="value1" />
+ * <com:TListItem Text="item2" Value="value2" />
+ * <com:TListItem Text="item3" Value="value3" />
+ * </com:TListBox>
+ *
+ * <com:TListControlValidator
+ * ControlToValidate="listbox"
+ * MinSelection="2"
+ * ErrorMessage="Please select at least 2" />
+ * </code>
+ * - "value1" must be selected <b>and</b> at least 1 other
+ * <code>
+ * <com:TCheckBoxList ID="checkboxes">
+ * <com:TListItem Text="item1" Value="value1" />
+ * <com:TListItem Text="item2" Value="value2" />
+ * <com:TListItem Text="item3" Value="value3" />
+ * </com:TCheckBoxList>
+ *
+ * <com:TListControlValidator
+ * ControlToValidate="checkboxes"
+ * RequiredSelections="value1"
+ * MinSelection="2"
+ * ErrorMessage="Please select 'item1' and at least 1 other" />
+ * </code>
+ *
+ * @author Xiang Wei Zhuo <weizhuo[at]gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TListControlValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TListControlValidator';
+ }
+
+ /**
+ * @return integer min number of selections. Defaults to -1, meaning not set.
+ */
+ public function getMinSelection()
+ {
+ return $this->getViewState('MinSelection',-1);
+ }
+
+ /**
+ * @param integer minimum number of selections.
+ */
+ public function setMinSelection($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ $this->setViewState('MinSelection',$value,-1);
+ }
+
+ /**
+ * @return integer max number of selections. Defaults to -1, meaning not set.
+ */
+ public function getMaxSelection()
+ {
+ return $this->getViewState('MaxSelection',-1);
+ }
+
+ /**
+ * @param integer max number of selections.
+ */
+ public function setMaxSelection($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ $this->setViewState('MaxSelection',$value,-1);
+ }
+
+ /**
+ * Get a comma separated list of required selected values.
+ * @return string comma separated list of required values.
+ */
+ public function getRequiredSelections()
+ {
+ return $this->getViewState('RequiredSelections','');
+ }
+
+ /**
+ * Set the list of required values, using aa comma separated list.
+ * @param string comma separated list of required values.
+ */
+ public function setRequiredSelections($value)
+ {
+ $this->setViewState('RequiredSelections',$value,'');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input component changes its data
+ * from the InitialValue or the input component is not given.
+ * @return boolean whether the validation succeeds
+ */
+ protected function evaluateIsValid()
+ {
+ $control=$this->getValidationTarget();
+
+ $exists = true;
+ $values = $this->getSelection($control);
+ $count = count($values);
+ $required = $this->getRequiredValues();
+
+ //if required, check the values
+ if(!empty($required))
+ {
+ if($count < count($required) )
+ return false;
+ foreach($required as $require)
+ $exists = $exists && in_array($require, $values);
+ }
+
+ $min = $this->getMinSelection();
+ $max = $this->getMaxSelection();
+
+ if($min !== -1 && $max !== -1)
+ return $exists && $count >= $min && $count <= $max;
+ else if($min === -1 && $max !== -1)
+ return $exists && $count <= $max;
+ else if($min !== -1 && $max === -1)
+ return $exists && $count >= $min;
+ else
+ return $exists;
+ }
+
+ /**
+ * @param TListControl control to validate
+ * @return array number of selected values and its values.
+ */
+ protected function getSelection($control)
+ {
+ $values = array();
+
+ //get the data
+ foreach($control->getItems() as $item)
+ {
+ if($item->getSelected())
+ $values[] = $item->getValue();
+ }
+ return $values;
+ }
+
+ /**
+ * @return array list of required values.
+ */
+ protected function getRequiredValues()
+ {
+ $required = array();
+ $string = $this->getRequiredSelections();
+ if(!empty($string))
+ $required = preg_split('/,\s*/', $string);
+ return $required;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options = parent::getClientScriptOptions();
+ $control = $this->getValidationTarget();
+
+ if(!$control instanceof TListControl)
+ {
+ throw new TConfigurationException(
+ 'listcontrolvalidator_invalid_control',
+ $this->getID(),$this->getControlToValidate(), get_class($control));
+ }
+
+ $min = $this->getMinSelection();
+ $max = $this->getMaxSelection();
+ if($min !== -1)
+ $options['Min']= $min;
+ if($max !== -1)
+ $options['Max']= $max;
+ $required = $this->getRequiredSelections();
+ if(strlen($required) > 0)
+ $options['Required']= $required;
+ $options['TotalItems'] = $control->getItemCount();
+
+ return $options;
+ }
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TListItem.php b/lib/prado/framework/Web/UI/WebControls/TListItem.php
new file mode 100644
index 0000000..aec006d
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TListItem.php
@@ -0,0 +1,182 @@
+<?php
+/**
+ * TListItem class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TListItem class.
+ *
+ * TListItem represents an item in a list control. Each item has a {@link setText Text}
+ * property and a {@link setValue Value} property. If either one of them is not set,
+ * it will take the value of the other property.
+ * An item can be {@link setSelected Selected} or {@link setEnabled Enabled},
+ * and it can have additional {@link getAttributes Attributes} which may be rendered
+ * if the list control supports so.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TListItem extends TComponent
+{
+ /**
+ * @var TMap list of custom attributes
+ */
+ private $_attributes=null;
+ /**
+ * @var string text of the item
+ */
+ private $_text;
+ /**
+ * @var string value of the item
+ */
+ private $_value;
+ /**
+ * @var boolean whether the item is enabled
+ */
+ private $_enabled;
+ /**
+ * @var boolean whether the item is selected
+ */
+ private $_selected;
+
+ /**
+ * Constructor.
+ * @param string text of the item
+ * @param string value of the item
+ * @param boolean whether the item is enabled
+ * @param boolean whether the item is selected
+ */
+ public function __construct($text='',$value='',$enabled=true,$selected=false)
+ {
+ $this->setText($text);
+ $this->setValue($value);
+ $this->setEnabled($enabled);
+ $this->setSelected($selected);
+ }
+
+ /**
+ * @return boolean whether the item is enabled
+ */
+ public function getEnabled()
+ {
+ return $this->_enabled;
+ }
+
+ /**
+ * @param boolean whether the item is enabled
+ */
+ public function setEnabled($value)
+ {
+ $this->_enabled=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether the item is selected
+ */
+ public function getSelected()
+ {
+ return $this->_selected;
+ }
+
+ /**
+ * @param boolean whether the item is selected
+ */
+ public function setSelected($value)
+ {
+ $this->_selected=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return string text of the item
+ */
+ public function getText()
+ {
+ return $this->_text===''?$this->_value:$this->_text;
+ }
+
+ /**
+ * @param string text of the item
+ */
+ public function setText($value)
+ {
+ $this->_text=TPropertyValue::ensureString($value);
+ }
+
+ /**
+ * @return string value of the item
+ */
+ public function getValue()
+ {
+ return $this->_value===''?$this->_text:$this->_value;
+ }
+
+ /**
+ * @param string value of the item
+ */
+ public function setValue($value)
+ {
+ $this->_value=TPropertyValue::ensureString($value);
+ }
+
+ /**
+ * @return TAttributeCollection custom attributes
+ */
+ public function getAttributes()
+ {
+ if(!$this->_attributes)
+ $this->_attributes=new TAttributeCollection;
+ return $this->_attributes;
+ }
+
+ /**
+ * @return boolean whether the item has any custom attribute
+ */
+ public function getHasAttributes()
+ {
+ return $this->_attributes && $this->_attributes->getCount()>0;
+ }
+
+ /**
+ * @param string name of the attribute
+ * @return boolean whether the named attribute exists
+ */
+ public function hasAttribute($name)
+ {
+ return $this->_attributes?$this->_attributes->contains($name):false;
+ }
+
+ /**
+ * @return string the named attribute value, null if attribute does not exist
+ */
+ public function getAttribute($name)
+ {
+ return $this->_attributes?$this->_attributes->itemAt($name):null;
+ }
+
+ /**
+ * @param string attribute name
+ * @param string value of the attribute
+ */
+ public function setAttribute($name,$value)
+ {
+ $this->getAttributes()->add($name,$value);
+ }
+
+ /**
+ * Removes the named attribute.
+ * @param string the name of the attribute to be removed.
+ * @return string attribute value removed, empty string if attribute does not exist.
+ */
+ public function removeAttribute($name)
+ {
+ return $this->_attributes?$this->_attributes->remove($name):null;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TLiteral.php b/lib/prado/framework/Web/UI/WebControls/TLiteral.php
new file mode 100644
index 0000000..f2306b4
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TLiteral.php
@@ -0,0 +1,110 @@
+<?php
+/**
+ * TLiteral class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TLiteral class
+ *
+ * TLiteral displays a static text on the Web page.
+ * TLiteral is similar to the TLabel control, except that the TLiteral
+ * control does not have style properties (e.g. BackColor, Font, etc.)
+ * You can programmatically control the text displayed in the control by setting
+ * the {@link setText Text} property. The text displayed may be HTML-encoded
+ * if the {@link setEncode Encode} property is set true (defaults to false).
+ *
+ * TLiteral will render the contents enclosed within its component tag
+ * if {@link setText Text} is empty.
+ *
+ * Note, if {@link setEncode Encode} is false, make sure {@link setText Text}
+ * does not contain unwanted characters that may bring security vulnerabilities.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TLiteral extends TControl implements IDataRenderer
+{
+ /**
+ * @return string the static text of the TLiteral
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the static text of the TLiteral
+ * @param string the text to be set
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * Returns the static text of the TLiteral.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string the static text of the TLiteral
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the static text of the TLiteral.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string the static text of the TLiteral
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * @return boolean whether the rendered text should be HTML-encoded. Defaults to false.
+ */
+ public function getEncode()
+ {
+ return $this->getViewState('Encode',false);
+ }
+
+ /**
+ * @param boolean whether the rendered text should be HTML-encoded.
+ */
+ public function setEncode($value)
+ {
+ $this->setViewState('Encode',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Renders the literal control.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if(($text=$this->getText())!=='')
+ {
+ if($this->getEncode())
+ $writer->write(THttpUtility::htmlEncode($text));
+ else
+ $writer->write($text);
+ }
+ else
+ parent::render($writer);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TLiteralColumn.php b/lib/prado/framework/Web/UI/WebControls/TLiteralColumn.php
new file mode 100644
index 0000000..3cf3c3a
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TLiteralColumn.php
@@ -0,0 +1,147 @@
+<?php
+/**
+ * TLiteralColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+
+/**
+ * TLiteralColumn class
+ *
+ * TLiteralColumn represents a static text column that is bound to a field in a data source.
+ * The cells in the column will be displayed with static texts using the data indexed by
+ * {@link setDataField DataField}. You can customize the display by
+ * setting {@link setDataFormatString DataFormatString}.
+ *
+ * If {@link setDataField DataField} is not specified, the cells will be filled
+ * with {@link setText Text}.
+ *
+ * If {@link setEncode Encode} is true, the static texts will be HTML-encoded.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.5
+ */
+class TLiteralColumn extends TDataGridColumn
+{
+ /**
+ * @return string the field name from the data source to bind to the column
+ */
+ public function getDataField()
+ {
+ return $this->getViewState('DataField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the column
+ */
+ public function setDataField($value)
+ {
+ $this->setViewState('DataField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the bound data will be displayed.
+ */
+ public function getDataFormatString()
+ {
+ return $this->getViewState('DataFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the bound data will be displayed.
+ */
+ public function setDataFormatString($value)
+ {
+ $this->setViewState('DataFormatString',$value,'');
+ }
+
+ /**
+ * @return string static text to be displayed in the column. Defaults to empty.
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * @param string static text to be displayed in the column.
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * @return boolean whether the rendered text should be HTML-encoded. Defaults to false.
+ */
+ public function getEncode()
+ {
+ return $this->getViewState('Encode',false);
+ }
+
+ /**
+ * @param boolean whether the rendered text should be HTML-encoded.
+ */
+ public function setEncode($value)
+ {
+ $this->setViewState('Encode',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::EditItem || $itemType===TListItemType::SelectedItem)
+ {
+ if($this->getDataField()!=='')
+ {
+ $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ } else {
+ $text=$this->getText();
+ if($this->getEncode())
+ $text=THttpUtility::htmlEncode($text);
+ $cell->setText($text);
+ }
+ }
+ else
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $data=$item->getData();
+ $formatString=$this->getDataFormatString();
+ if(($field=$this->getDataField())!=='')
+ $value=$this->formatDataValue($formatString,$this->getDataFieldValue($data,$field));
+ else
+ $value=$this->formatDataValue($formatString,$data);
+ if($sender instanceof TTableCell)
+ {
+ if($this->getEncode())
+ $value=THttpUtility::htmlEncode($value);
+ $sender->setText($value);
+ }
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TMarkdown.php b/lib/prado/framework/Web/UI/WebControls/TMarkdown.php
new file mode 100644
index 0000000..7a99b1f
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TMarkdown.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * TMarkdown class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TTextHighlighter and MarkdownParser classes
+ */
+Prado::using('System.Web.UI.WebControls.TTextHighlighter');
+Prado::using('System.3rdParty.Parsedown.Parsedown');
+
+/**
+ * TMarkdown class
+ *
+ * TMarkdown is a control that produces HTML from code with markdown syntax.
+ *
+ * Markdown is a text-to-HTML conversion tool for web writers. Markdown allows
+ * you to write using an easy-to-read, easy-to-write plain text format, then
+ * convert it to structurally valid XHTML (or HTML).
+ * Further documentation regarding Markdown can be found at
+ * http://daringfireball.net/projects/markdown/
+ *
+ * To use TMarkdown, simply enclose the content to be rendered within
+ * the body of TMarkdown in a template.
+ *
+ * See https://daringfireball.net/projects/markdown/basics for
+ * details on the Markdown syntax usage.
+ *
+ * TMarkdown also performs syntax highlighting for code blocks whose language
+ * is recognized by {@link TTextHighlighter}.
+ * The language of a code block must be specified in the first line of the block
+ * and enclosed within a pair of square brackets (e.g. [php]).
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.1
+ */
+class TMarkdown extends TTextHighlighter
+{
+ /**
+ * Processes a text string.
+ * This method is required by the parent class.
+ * @param string text string to be processed
+ * @return string the processed text result
+ */
+ public function processText($text)
+ {
+ $result = Parsedown::instance()->parse($text);
+ return preg_replace_callback(
+ '/<pre><code class="language-(\w+)">((.|\n)*?)<\\/code><\\/pre>/im',
+ array($this, 'highlightCode'), $result);
+ }
+
+ /**
+ * Highlights source code using TTextHighlighter
+ * @param array matches of code blocks
+ * @return string highlighted code.
+ */
+ protected function highlightCode($matches)
+ {
+ $text = html_entity_decode($matches[2],ENT_QUOTES,'UTF-8');
+ $this->setLanguage($matches[1]);
+ return parent::processText($text);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TMultiView.php b/lib/prado/framework/Web/UI/WebControls/TMultiView.php
new file mode 100644
index 0000000..5f338d7
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TMultiView.php
@@ -0,0 +1,374 @@
+<?php
+/**
+ * TMultiView and TView class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TMultiView class
+ *
+ * TMultiView serves as a container for a group of {@link TView} controls.
+ * The view collection can be retrieved by {@link getViews Views}.
+ * Each view contains child controls. TMultiView determines which view and its
+ * child controls are visible. At any time, at most one view is visible (called
+ * active). To make a view active, set {@link setActiveView ActiveView} or
+ * {@link setActiveViewIndex ActiveViewIndex}.
+ *
+ * TMultiView also responds to specific command events raised from button controls
+ * contained in current active view. A command event with name 'NextView'
+ * will cause TMultiView to make the next available view active.
+ * Other command names recognized by TMultiView include
+ * - PreviousView : switch to previous view
+ * - SwitchViewID : switch to a view by its ID path
+ * - SwitchViewIndex : switch to a view by its index in the {@link getViews Views} collection.
+ *
+ * TMultiView raises {@link OnActiveViewChanged OnActiveViewChanged} event
+ * when its active view is changed during a postback.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TMultiView extends TControl
+{
+ const CMD_NEXTVIEW='NextView';
+ const CMD_PREVIOUSVIEW='PreviousView';
+ const CMD_SWITCHVIEWID='SwitchViewID';
+ const CMD_SWITCHVIEWINDEX='SwitchViewIndex';
+ private $_cachedActiveViewIndex=-1;
+ private $_ignoreBubbleEvents=false;
+
+ /**
+ * Processes an object that is created during parsing template.
+ * This method overrides the parent implementation by adding only {@link TView}
+ * controls as children.
+ * @param string|TComponent text string or component parsed and instantiated in template
+ * @see createdOnTemplate
+ * @throws TConfigurationException if controls other than {@link TView} is being added
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TView)
+ $this->getControls()->add($object);
+ else if(!is_string($object))
+ throw new TConfigurationException('multiview_view_required');
+ }
+
+ /**
+ * Creates a control collection object that is to be used to hold child controls
+ * @return TViewCollection control collection
+ */
+ protected function createControlCollection()
+ {
+ return new TViewCollection($this);
+ }
+
+ /**
+ * @return integer the zero-based index of the current view in the view collection. -1 if no active view. Default is -1.
+ */
+ public function getActiveViewIndex()
+ {
+ if($this->_cachedActiveViewIndex>-1)
+ return $this->_cachedActiveViewIndex;
+ else
+ return $this->getControlState('ActiveViewIndex',-1);
+ }
+
+ /**
+ * @param integer the zero-based index of the current view in the view collection. -1 if no active view.
+ * @throws TInvalidDataValueException if the view index is invalid
+ */
+ public function setActiveViewIndex($value)
+ {
+ if(($index=TPropertyValue::ensureInteger($value))<0)
+ $index=-1;
+ $views=$this->getViews();
+ $count=$views->getCount();
+ if($count===0 && $this->getControlStage()<TControl::CS_CHILD_INITIALIZED)
+ $this->_cachedActiveViewIndex=$index;
+ else if($index<$count)
+ {
+ $this->setControlState('ActiveViewIndex',$index,-1);
+ $this->_cachedActiveViewIndex=-1;
+ if($index>=0)
+ $this->activateView($views->itemAt($index),true);
+ }
+ else
+ throw new TInvalidDataValueException('multiview_activeviewindex_invalid',$index);
+ }
+
+ /**
+ * @return TView the currently active view, null if no active view
+ * @throws TInvalidDataValueException if the current active view index is invalid
+ */
+ public function getActiveView()
+ {
+ $index=$this->getActiveViewIndex();
+ $views=$this->getViews();
+ if($index>=$views->getCount())
+ throw new TInvalidDataValueException('multiview_activeviewindex_invalid',$index);
+ if($index<0)
+ return null;
+ $view=$views->itemAt($index);
+ if(!$view->getActive())
+ $this->activateView($view,false);
+ return $view;
+ }
+
+ /**
+ * @param TView the view to be activated
+ * @throws TInvalidOperationException if the view is not in the view collection
+ */
+ public function setActiveView($view)
+ {
+ if(($index=$this->getViews()->indexOf($view))>=0)
+ $this->setActiveViewIndex($index);
+ else
+ throw new TInvalidOperationException('multiview_view_inexistent');
+ }
+
+ /**
+ * Activates the specified view.
+ * If there is any view currently active, it will be deactivated.
+ * @param TView the view to be activated
+ * @param boolean whether to trigger OnActiveViewChanged event.
+ */
+ protected function activateView($view,$triggerViewChangedEvent=true)
+ {
+ if($view->getActive())
+ return;
+ $triggerEvent=$triggerViewChangedEvent && ($this->getControlStage()>=TControl::CS_STATE_LOADED || ($this->getPage() && !$this->getPage()->getIsPostBack()));
+ foreach($this->getViews() as $v)
+ {
+ if($v===$view)
+ {
+ $view->setActive(true);
+ if($triggerEvent)
+ {
+ $view->onActivate(null);
+ $this->onActiveViewChanged(null);
+ }
+ }
+ else if($v->getActive())
+ {
+ $v->setActive(false);
+ if($triggerEvent)
+ $v->onDeactivate(null);
+ }
+ }
+ }
+
+ /**
+ * @return TViewCollection the view collection
+ */
+ public function getViews()
+ {
+ return $this->getControls();
+ }
+
+ /**
+ * Makes the multiview ignore all bubbled events.
+ * This is method is used internally by framework and control
+ * developers.
+ */
+ public function ignoreBubbleEvents()
+ {
+ $this->_ignoreBubbleEvents=true;
+ }
+
+ /**
+ * Initializes the active view if any.
+ * This method overrides the parent implementation.
+ * @param TEventParameter event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ if($this->_cachedActiveViewIndex>=0)
+ $this->setActiveViewIndex($this->_cachedActiveViewIndex);
+ }
+
+ /**
+ * Raises <b>OnActiveViewChanged</b> event.
+ * The event is raised when the currently active view is changed to a new one
+ * @param TEventParameter event parameter
+ */
+ public function onActiveViewChanged($param)
+ {
+ $this->raiseEvent('OnActiveViewChanged',$this,$param);
+ }
+
+ /**
+ * Processes the events bubbled from child controls.
+ * The method handles view-related command events.
+ * @param TControl sender of the event
+ * @param mixed event parameter
+ * @return boolean whether this event is handled
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if(!$this->_ignoreBubbleEvents && ($param instanceof TCommandEventParameter))
+ {
+ switch($param->getCommandName())
+ {
+ case self::CMD_NEXTVIEW:
+ if(($index=$this->getActiveViewIndex())<$this->getViews()->getCount()-1)
+ $this->setActiveViewIndex($index+1);
+ else
+ $this->setActiveViewIndex(-1);
+ return true;
+ case self::CMD_PREVIOUSVIEW:
+ if(($index=$this->getActiveViewIndex())>=0)
+ $this->setActiveViewIndex($index-1);
+ return true;
+ case self::CMD_SWITCHVIEWID:
+ $view=$this->findControl($viewID=$param->getCommandParameter());
+ if($view!==null && $view->getParent()===$this)
+ {
+ $this->setActiveView($view);
+ return true;
+ }
+ else
+ throw new TInvalidDataValueException('multiview_viewid_invalid', $viewID);
+ case self::CMD_SWITCHVIEWINDEX:
+ $index=TPropertyValue::ensureInteger($param->getCommandParameter());
+ $this->setActiveViewIndex($index);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Loads state into the wizard.
+ * This method is invoked by the framework when the control state is being saved.
+ */
+ public function loadState()
+ {
+ // a dummy call to ensure the view is activated
+ $this->getActiveView();
+ }
+
+ /**
+ * Renders the currently active view.
+ * @param THtmlWriter the writer for the rendering purpose.
+ */
+ public function render($writer)
+ {
+ if(($view=$this->getActiveView())!==null)
+ $view->renderControl($writer);
+ }
+}
+
+/**
+ * TViewCollection class.
+ * TViewCollection represents a collection that only takes {@link TView} instances
+ * as collection elements.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TViewCollection extends TControlCollection
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by ensuring only {@link TView}
+ * controls be added into the collection.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is neither a string nor a TControl.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TView)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('viewcollection_view_required');
+ }
+}
+
+/**
+ * TView class
+ *
+ * TView is a container for a group of controls. TView must be contained
+ * within a {@link TMultiView} control in which only one view can be active
+ * at one time.
+ *
+ * To activate a view, set {@link setActive Active} to true.
+ * When a view is activated, it raises {@link onActivate OnActivate} event;
+ * and when a view is deactivated, it raises {@link onDeactivate OnDeactivate}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TView extends TControl
+{
+ private $_active=false;
+
+ /**
+ * Raises <b>OnActivate</b> event.
+ * @param TEventParameter event parameter
+ */
+ public function onActivate($param)
+ {
+ $this->raiseEvent('OnActivate',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnDeactivate</b> event.
+ * @param TEventParameter event parameter
+ */
+ public function onDeactivate($param)
+ {
+ $this->raiseEvent('OnDeactivate',$this,$param);
+ }
+
+ /**
+ * @return boolean whether this view is active. Defaults to false.
+ */
+ public function getActive()
+ {
+ return $this->_active;
+ }
+
+ /**
+ * @param boolean whether this view is active.
+ */
+ public function setActive($value)
+ {
+ $value=TPropertyValue::ensureBoolean($value);
+ $this->_active=$value;
+ parent::setVisible($value);
+ }
+
+ /**
+ * @param boolean whether the parents should also be checked if visible
+ * @return boolean whether this view is visible.
+ * The view is visible if it is active and its parent is visible.
+ */
+ public function getVisible($checkParents=true)
+ {
+ if(($parent=$this->getParent())===null)
+ return $this->getActive();
+ else if($this->getActive())
+ return $parent->getVisible($checkParents);
+ else
+ return false;
+ }
+
+ /**
+ * @param boolean
+ * @throws TInvalidOperationException whenever this method is invoked.
+ */
+ public function setVisible($value)
+ {
+ throw new TInvalidOperationException('view_visible_readonly');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TOutputCache.php b/lib/prado/framework/Web/UI/WebControls/TOutputCache.php
new file mode 100644
index 0000000..5615418
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TOutputCache.php
@@ -0,0 +1,616 @@
+<?php
+/**
+ * TOutputCache class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TOutputCache class.
+ *
+ * TOutputCache enables caching a portion of a Web page, also known as
+ * partial caching. The content being cached can be either static or
+ * dynamic.
+ *
+ * To use TOutputCache, simply enclose the content to be cached
+ * within the TOutputCache component tag on a template, e.g.,
+ * <code>
+ * <com:TOutputCache>
+ * content to be cached
+ * </com:TOutputCache>
+ * </code>
+ * where content to be cached can be static text and/or component tags.
+ *
+ * The validity of the cached content is determined based on two factors:
+ * the {@link setDuration Duration} and the cache dependency.
+ * The former specifies the number of seconds that the data can remain
+ * valid in cache (defaults to 60s), while the latter specifies conditions
+ * that the cached data depends on. If a dependency changes,
+ * (e.g. relevant data in DB are updated), the cached data will be invalidated.
+ *
+ * There are two ways to specify cache dependency. One may write event handlers
+ * to respond to the {@link onCheckDependency OnCheckDependency} event and set
+ * the event parameter's {@link TOutputCacheCheckDependencyEventParameter::getIsValid IsValid}
+ * property to indicate whether the cached data remains valid or not.
+ * One can also extend TOutputCache and override its {@link getCacheDependency}
+ * function. While the former is easier to use, the latter offers more extensibility.
+ *
+ * The content fetched from cache may be variated with respect to
+ * some parameters. It supports variation with respect to request parameters,
+ * which is specified by {@link setVaryByParam VaryByParam} property.
+ * If a specified request parameter is different, a different version of
+ * cached content is used. This is extremely useful if a page's content
+ * may be variated according to some GET parameters.
+ * The content being cached may also be variated with user sessions if
+ * {@link setVaryBySession VaryBySession} is set true.
+ * To variate the cached content by other factors, override {@link calculateCacheKey()} method.
+ *
+ * Output caches can be nested. An outer cache takes precedence over an
+ * inner cache. This means, if the content cached by the inner cache expires
+ * or is invalidated, while that by the outer cache not, the outer cached
+ * content will be used.
+ *
+ * Note, TOutputCache is effective only for non-postback page requests
+ * and when cache module is enabled.
+ *
+ * Do not attempt to address child controls of TOutputCache when the cached
+ * content is to be used. Use {@link getContentCached ContentCached} property
+ * to determine whether the content is cached or not.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1
+ */
+class TOutputCache extends TControl implements INamingContainer
+{
+ const CACHE_ID_PREFIX='prado:outputcache';
+ private $_cacheModuleID='';
+ private $_dataCached=false;
+ private $_cacheAvailable=false;
+ private $_cacheChecked=false;
+ private $_cacheKey=null;
+ private $_duration=60;
+ private $_cache=null;
+ private $_contents;
+ private $_state;
+ private $_actions=array();
+ private $_varyByParam='';
+ private $_keyPrefix='';
+ private $_varyBySession=false;
+ private $_cachePostBack=false;
+ private $_cacheTime=0;
+
+ /**
+ * Returns a value indicating whether body contents are allowed for this control.
+ * This method overrides the parent implementation by checking if cached
+ * content is available or not. If yes, it returns false, otherwise true.
+ * @param boolean whether body contents are allowed for this control.
+ */
+ public function getAllowChildControls()
+ {
+ $this->determineCacheability();
+ return !$this->_dataCached;
+ }
+
+ private function determineCacheability()
+ {
+ if(!$this->_cacheChecked)
+ {
+ $this->_cacheChecked=true;
+ if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
+ {
+ if($this->_cacheModuleID!=='')
+ {
+ $this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
+ if(!($this->_cache instanceof ICache))
+ throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
+ }
+ else
+ $this->_cache=$this->getApplication()->getCache();
+ if($this->_cache!==null)
+ {
+ $this->_cacheAvailable=true;
+ $data=$this->_cache->get($this->getCacheKey());
+ if(is_array($data))
+ {
+ $param=new TOutputCacheCheckDependencyEventParameter;
+ $param->setCacheTime(isset($data[3])?$data[3]:0);
+ $this->onCheckDependency($param);
+ $this->_dataCached=$param->getIsValid();
+ }
+ else
+ $this->_dataCached=false;
+ if($this->_dataCached)
+ list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
+ }
+ }
+ }
+ }
+
+ /**
+ * Performs the Init step for the control and all its child controls.
+ * This method overrides the parent implementation by setting up
+ * the stack of the output cache in the page.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function initRecursive($namingContainer=null)
+ {
+ if($this->_cacheAvailable && !$this->_dataCached)
+ {
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::initRecursive($namingContainer);
+ $stack->pop();
+ }
+ else
+ parent::initRecursive($namingContainer);
+ }
+
+ /**
+ * Performs the Load step for the control and all its child controls.
+ * This method overrides the parent implementation by setting up
+ * the stack of the output cache in the page. If the data is restored
+ * from cache, it also recovers the actions associated with the cached data.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function loadRecursive()
+ {
+ if($this->_cacheAvailable && !$this->_dataCached)
+ {
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::loadRecursive();
+ $stack->pop();
+ }
+ else
+ {
+ if($this->_dataCached)
+ $this->performActions();
+ parent::loadRecursive();
+ }
+ }
+
+ private function performActions()
+ {
+ $page=$this->getPage();
+ $cs=$page->getClientScript();
+ foreach($this->_actions as $action)
+ {
+ if($action[0]==='Page.ClientScript')
+ call_user_func_array(array($cs,$action[1]),$action[2]);
+ else if($action[0]==='Page')
+ call_user_func_array(array($page,$action[1]),$action[2]);
+ else
+ call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
+ }
+ }
+
+ /**
+ * Performs the PreRender step for the control and all its child controls.
+ * This method overrides the parent implementation by setting up
+ * the stack of the output cache in the page.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function preRenderRecursive()
+ {
+ if($this->_cacheAvailable && !$this->_dataCached)
+ {
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::preRenderRecursive();
+ $stack->pop();
+ }
+ else
+ parent::preRenderRecursive();
+ }
+
+ /**
+ * Loads state (viewstate and controlstate) into a control and its children.
+ * This method overrides the parent implementation by loading
+ * cached state if available.
+ * This method should only be used by framework developers.
+ * @param array the collection of the state
+ * @param boolean whether the viewstate should be loaded
+ */
+ protected function loadStateRecursive(&$state,$needViewState=true)
+ {
+ $st=unserialize($state);
+ parent::loadStateRecursive($st,$needViewState);
+ }
+
+ /**
+ * Saves all control state (viewstate and controlstate) as a collection.
+ * This method overrides the parent implementation by saving state
+ * into cache if needed.
+ * This method should only be used by framework developers.
+ * @param boolean whether the viewstate should be saved
+ * @return array the collection of the control state (including its children's state).
+ */
+ protected function &saveStateRecursive($needViewState=true)
+ {
+ if($this->_dataCached)
+ return $this->_state;
+ else
+ {
+ $st=parent::saveStateRecursive($needViewState);
+ // serialization is needed to avoid undefined classes when loading state
+ $this->_state=serialize($st);
+ return $this->_state;
+ }
+ }
+
+ /**
+ * Registers an action associated with the content being cached.
+ * The registered action will be replayed if the content stored
+ * in the cache is served to end-users.
+ * @param string context of the action method. This is a property-path
+ * referring to the context object (e.g. Page, Page.ClientScript)
+ * @param string method name of the context object
+ * @param array list of parameters to be passed to the action method
+ */
+ public function registerAction($context,$funcName,$funcParams)
+ {
+ $this->_actions[]=array($context,$funcName,$funcParams);
+ }
+
+ public function getCacheKey()
+ {
+ if($this->_cacheKey===null)
+ $this->_cacheKey=$this->calculateCacheKey();
+ return $this->_cacheKey;
+ }
+
+ /**
+ * Calculates the cache key.
+ * The key is calculated based on the unique ID of this control
+ * and the request parameters specified via {@link setVaryByParam VaryByParam}.
+ * If {@link getVaryBySession VaryBySession} is true, the session ID
+ * will also participate in the key calculation.
+ * This method may be overriden to support other variations in
+ * the calculated cache key.
+ * @return string cache key
+ */
+ protected function calculateCacheKey()
+ {
+ $key=$this->getBaseCacheKey();
+ if($this->_varyBySession)
+ $key.=$this->getSession()->getSessionID();
+ if($this->_varyByParam!=='')
+ {
+ $params=array();
+ $request=$this->getRequest();
+ foreach(explode(',',$this->_varyByParam) as $name)
+ {
+ $name=trim($name);
+ $params[$name]=$request->itemAt($name);
+ }
+ $key.=serialize($params);
+ }
+ $param=new TOutputCacheCalculateKeyEventParameter;
+ $this->onCalculateKey($param);
+ $key.=$param->getCacheKey();
+ return $key;
+ }
+
+ /**
+ * @return string basic cache key without variations
+ */
+ protected function getBaseCacheKey()
+ {
+ return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
+ }
+
+ /**
+ * @return string the ID of the cache module. Defaults to '', meaning the primary cache module is used.
+ */
+ public function getCacheModuleID()
+ {
+ return $this->_cacheModuleID;
+ }
+
+ /**
+ * @param string the ID of the cache module. If empty, the primary cache module will be used.
+ */
+ public function setCacheModuleID($value)
+ {
+ $this->_cacheModuleID=$value;
+ }
+
+ /**
+ * Sets the prefix of the cache key.
+ * This method is used internally by {@link TTemplate}.
+ * @param string key prefix
+ */
+ public function setCacheKeyPrefix($value)
+ {
+ $this->_keyPrefix=$value;
+ }
+
+ /**
+ * @return integer the timestamp of the cached content. This is only valid if the content is being cached.
+ * @since 3.1.1
+ */
+ public function getCacheTime()
+ {
+ return $this->_cacheTime;
+ }
+
+ /**
+ * Returns the dependency of the data to be cached.
+ * The default implementation simply returns null, meaning no specific dependency.
+ * This method may be overriden to associate the data to be cached
+ * with additional dependencies.
+ * @return ICacheDependency
+ */
+ protected function getCacheDependency()
+ {
+ return null;
+ }
+
+ /**
+ * @return boolean whether content enclosed is cached or not
+ */
+ public function getContentCached()
+ {
+ return $this->_dataCached;
+ }
+
+ /**
+ * @return integer number of seconds that the data can remain in cache. Defaults to 60 seconds.
+ * Note, if cache dependency changes or cache space is limited,
+ * the data may be purged out of cache earlier.
+ */
+ public function getDuration()
+ {
+ return $this->_duration;
+ }
+
+ /**
+ * @param integer number of seconds that the data can remain in cache. If 0, it means data is not cached.
+ * @throws TInvalidDataValueException if the value is smaller than 0.
+ */
+ public function setDuration($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
+ $this->_duration=$value;
+ }
+
+ /**
+ * @return string a semicolon-separated list of strings used to vary the output cache. Defaults to ''.
+ */
+ public function getVaryByParam()
+ {
+ return $this->_varyByParam;
+ }
+
+ /**
+ * Sets the names of the request parameters that should be used in calculating the cache key.
+ * The names should be concatenated by semicolons.
+ * By setting this value, the output cache will use different cached data
+ * for each different set of request parameter values.
+ * @return string a semicolon-separated list of strings used to vary the output cache.
+ */
+ public function setVaryByParam($value)
+ {
+ $this->_varyByParam=trim($value);
+ }
+
+ /**
+ * @return boolean whether the content being cached should be differentiated according to user sessions. Defaults to false.
+ */
+ public function getVaryBySession()
+ {
+ return $this->_varyBySession;
+ }
+
+ /**
+ * @param boolean whether the content being cached should be differentiated according to user sessions.
+ */
+ public function setVaryBySession($value)
+ {
+ $this->_varyBySession=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether cached output will be used on postback requests. Defaults to false.
+ */
+ public function getCachingPostBack()
+ {
+ return $this->_cachePostBack;
+ }
+
+ /**
+ * Sets a value indicating whether cached output will be used on postback requests.
+ * By default, this is disabled. Be very cautious when enabling it.
+ * If the cached content including interactive user controls such as
+ * TTextBox, TDropDownList, your page may fail to render on postbacks.
+ * @param boolean whether cached output will be used on postback requests.
+ */
+ public function setCachingPostBack($value)
+ {
+ $this->_cachePostBack=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * This event is raised when the output cache is checking cache dependency.
+ * An event handler may be written to check customized dependency conditions.
+ * The checking result should be saved by setting {@link TOutputCacheCheckDependencyEventParameter::setIsValid IsValid}
+ * property of the event parameter (which defaults to true).
+ * @param TOutputCacheCheckDependencyEventParameter event parameter
+ */
+ public function onCheckDependency($param)
+ {
+ $this->raiseEvent('OnCheckDependency',$this,$param);
+ }
+
+ /**
+ * This event is raised when the output cache is calculating cache key.
+ * By varying cache keys, one can obtain different versions of cached content.
+ * An event handler may be written to add variety of the key calculation.
+ * The value set in {@link TOutputCacheCalculateKeyEventParameter::setCacheKey CacheKey} of
+ * this event parameter will be appended to the default key calculation scheme.
+ * @param TOutputCacheCalculateKeyEventParameter event parameter
+ */
+ public function onCalculateKey($param)
+ {
+ $this->raiseEvent('OnCalculateKey',$this,$param);
+ }
+
+ /**
+ * Renders the output cache control.
+ * This method overrides the parent implementation by capturing the output
+ * from its child controls and saving it into cache, if output cache is needed.
+ * @param THtmlWriter
+ */
+ public function render($writer)
+ {
+ if($this->_dataCached)
+ $writer->write($this->_contents);
+ else if($this->_cacheAvailable)
+ {
+ $textwriter = new TTextWriter();
+ $multiwriter = new TOutputCacheTextWriterMulti(array($writer->getWriter(),$textwriter));
+ $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $multiwriter);
+
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::render($htmlWriter);
+ $stack->pop();
+
+ $content=$textwriter->flush();
+ $data=array($content,$this->_state,$this->_actions,time());
+ $this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
+ }
+ else
+ parent::render($writer);
+ }
+}
+
+/**
+ * TOutputCacheCheckDependencyEventParameter class
+ *
+ * TOutputCacheCheckDependencyEventParameter encapsulates the parameter data for
+ * <b>OnCheckDependency</b> event of {@link TOutputCache} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TOutputCacheCheckDependencyEventParameter extends TEventParameter
+{
+ private $_isValid=true;
+ private $_cacheTime=0;
+
+ /**
+ * @return boolean whether the dependency remains valid. Defaults to true.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+
+ /**
+ * @param boolean whether the dependency remains valid
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return integer the timestamp of the cached result. You may use this to help determine any dependency is changed.
+ * @since 3.1.1
+ */
+ public function getCacheTime()
+ {
+ return $this->_cacheTime;
+ }
+
+ /**
+ * @param integer the timestamp of the cached result. This is used internally.
+ * @since 3.1.1
+ */
+ public function setCacheTime($value)
+ {
+ $this->_cacheTime=TPropertyValue::ensureInteger($value);
+ }
+}
+
+
+/**
+ * TOutputCacheCalculateKeyEventParameter class
+ *
+ * TOutputCacheCalculateKeyEventParameter encapsulates the parameter data for
+ * <b>OnCalculateKey</b> event of {@link TOutputCache} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TOutputCacheCalculateKeyEventParameter extends TEventParameter
+{
+ /**
+ * @var string cache key to be appended to the default calculation scheme.
+ */
+ private $_cacheKey='';
+
+ /**
+ * @return string cache key to be appended to the default calculation scheme.
+ */
+ public function getCacheKey()
+ {
+ return $this->_cacheKey;
+ }
+
+ /**
+ * @param string cache key to be appended to the default calculation scheme
+ */
+ public function setCacheKey($value)
+ {
+ $this->_cacheKey=TPropertyValue::ensureString($value);
+ }
+}
+
+/**
+ * TOutputCacheTextWriterMulti class
+ *
+ * TOutputCacheTextWriterMulti is an internal class used by
+ * TOutputCache to write simultaneously to multiple writers.
+ *
+ * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+class TOutputCacheTextWriterMulti extends TTextWriter
+{
+ protected $_writers;
+
+ public function __construct(Array $writers)
+ {
+ //parent::__construct();
+ $this->_writers = $writers;
+ }
+
+ public function write($s)
+ {
+ foreach($this->_writers as $writer)
+ $writer->write($s);
+ }
+
+ public function flush()
+ {
+ foreach($this->_writers as $writer)
+ $s = $writer->flush();
+ return $s;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TPager.php b/lib/prado/framework/Web/UI/WebControls/TPager.php
new file mode 100644
index 0000000..467c0f7
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TPager.php
@@ -0,0 +1,810 @@
+<?php
+/**
+ * TPager class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TPager class.
+ *
+ * TPager creates a pager that provides UI for end-users to interactively
+ * specify which page of data to be rendered in a {@link TDataBoundControl}-derived control,
+ * such as {@link TDataList}, {@link TRepeater}, {@link TCheckBoxList}, etc.
+ * The target data-bound control is specified by {@link setControlToPaginate ControlToPaginate},
+ * which must be the ID path of the target control reaching from the pager's
+ * naming container. Note, the target control must have its {@link TDataBoundControl::setAllowPaging AllowPaging}
+ * set to true.
+ *
+ * TPager can display three different UIs, specified via {@link setMode Mode}:
+ * - NextPrev: a next page and a previous page button are rendered.
+ * - Numeric: a list of page index buttons are rendered.
+ * - List: a dropdown list of page indices are rendered.
+ *
+ * When the pager mode is either NextPrev or Numeric, the paging buttons may be displayed
+ * in three types by setting {@link setButtonType ButtonType}:
+ * - LinkButton: a hyperlink button
+ * - PushButton: a normal button
+ * - ImageButton: an image button (please set XXXPageImageUrl properties accordingly to specify the button images.)
+ *
+ * Since Prado 3.2.1, you can use the {@link setButtonCssClass ButtonCssClass} property to specify a css class
+ * that will be applied to each button created by the pager in NextPrev or Numeric mode.
+ *
+ * TPager raises an {@link onPageIndexChanged OnPageIndexChanged} event when
+ * the end-user interacts with it and specifies a new page (e.g. clicking
+ * on a page button that leads to a new page.) The new page index may be obtained
+ * from the event parameter's property {@link TPagerPageChangedEventParameter::getNewPageIndex NewPageIndex}.
+ * Normally, in the event handler, one can set the {@link TDataBoundControl::getCurrentPageIndex CurrentPageIndex}
+ * to this new page index so that the new page of data is rendered.
+ *
+ * Multiple pagers can be associated with the same data-bound control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.2
+ */
+class TPager extends TWebControl implements INamingContainer
+{
+ /**
+ * Command name that TPager understands.
+ */
+ const CMD_PAGE='Page';
+ const CMD_PAGE_NEXT='Next';
+ const CMD_PAGE_PREV='Previous';
+ const CMD_PAGE_FIRST='First';
+ const CMD_PAGE_LAST='Last';
+
+ private $_pageCount=0;
+
+ /**
+ * Restores the pager state.
+ * This method overrides the parent implementation and is invoked when
+ * the control is loading persistent state.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ if($this->getEnableViewState(true))
+ {
+ $this->getControls()->clear();
+ $this->buildPager();
+ }
+ }
+
+ /**
+ * @return string the ID path of the control whose content would be paginated.
+ */
+ public function getControlToPaginate()
+ {
+ return $this->getViewState('ControlToPaginate','');
+ }
+
+ /**
+ * Sets the ID path of the control whose content would be paginated.
+ * The ID path is the dot-connected IDs of the controls reaching from
+ * the pager's naming container to the target control.
+ * @param string the ID path
+ */
+ public function setControlToPaginate($value)
+ {
+ $this->setViewState('ControlToPaginate',$value,'');
+ }
+
+ /**
+ * @return string the css class of the buttons.
+ * @since 3.2.1
+ */
+ public function getButtonCssClass()
+ {
+ return $this->getViewState('ButtonCssClass','');
+ }
+
+ /**
+ * @param Sets the css class of the buttons that will be rendered by this pager.
+ * @since 3.2.1
+ */
+ public function setButtonCssClass($value)
+ {
+ $this->setViewState('ButtonCssClass',TPropertyValue::ensureString($value,''),'');
+ }
+
+ /**
+ * @return TPagerMode pager mode. Defaults to TPagerMode::NextPrev.
+ */
+ public function getMode()
+ {
+ return $this->getViewState('Mode',TPagerMode::NextPrev);
+ }
+
+ /**
+ * @param TPagerMode pager mode.
+ */
+ public function setMode($value)
+ {
+ $this->setViewState('Mode',TPropertyValue::ensureEnum($value,'TPagerMode'),TPagerMode::NextPrev);
+ }
+
+ /**
+ * @return TPagerButtonType the type of command button for paging. Defaults to TPagerButtonType::LinkButton.
+ */
+ public function getButtonType()
+ {
+ return $this->getViewState('ButtonType',TPagerButtonType::LinkButton);
+ }
+
+ /**
+ * @param TPagerButtonType the type of command button for paging.
+ */
+ public function setButtonType($value)
+ {
+ $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TPagerButtonType'),TPagerButtonType::LinkButton);
+ }
+
+ /**
+ * @return string text for the next page button. Defaults to '>'.
+ */
+ public function getNextPageText()
+ {
+ return $this->getViewState('NextPageText','>');
+ }
+
+ /**
+ * @param string text for the next page button.
+ */
+ public function setNextPageText($value)
+ {
+ $this->setViewState('NextPageText',$value,'>');
+ }
+
+ /**
+ * @return string text for the previous page button. Defaults to '<'.
+ */
+ public function getPrevPageText()
+ {
+ return $this->getViewState('PrevPageText','<');
+ }
+
+ /**
+ * @param string text for the next page button.
+ */
+ public function setPrevPageText($value)
+ {
+ $this->setViewState('PrevPageText',$value,'<');
+ }
+
+ /**
+ * @return string text for the first page button. Defaults to '<<'.
+ */
+ public function getFirstPageText()
+ {
+ return $this->getViewState('FirstPageText','<<');
+ }
+
+ /**
+ * @param string text for the first page button. If empty, the first page button will not be rendered.
+ */
+ public function setFirstPageText($value)
+ {
+ $this->setViewState('FirstPageText',$value,'<<');
+ }
+
+ /**
+ * @return string text for the last page button. Defaults to '>>'.
+ */
+ public function getLastPageText()
+ {
+ return $this->getViewState('LastPageText','>>');
+ }
+
+ /**
+ * @param string text for the last page button. If empty, the last page button will not be rendered.
+ */
+ public function setLastPageText($value)
+ {
+ $this->setViewState('LastPageText',$value,'>>');
+ }
+
+ /**
+ * @return string the image URL for the first page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function getFirstPageImageUrl()
+ {
+ return $this->getViewState('FirstPageImageUrl','');
+ }
+
+ /**
+ * @param string the image URL for the first page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function setFirstPageImageUrl($value)
+ {
+ $this->setViewState('FirstPageImageUrl',$value);
+ }
+
+ /**
+ * @return string the image URL for the last page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function getLastPageImageUrl()
+ {
+ return $this->getViewState('LastPageImageUrl','');
+ }
+
+ /**
+ * @param string the image URL for the last page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function setLastPageImageUrl($value)
+ {
+ $this->setViewState('LastPageImageUrl',$value);
+ }
+
+ /**
+ * @return string the image URL for the next page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function getNextPageImageUrl()
+ {
+ return $this->getViewState('NextPageImageUrl','');
+ }
+
+ /**
+ * @param string the image URL for the next page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function setNextPageImageUrl($value)
+ {
+ $this->setViewState('NextPageImageUrl',$value);
+ }
+
+ /**
+ * @return string the image URL for the previous page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function getPrevPageImageUrl()
+ {
+ return $this->getViewState('PrevPageImageUrl','');
+ }
+
+ /**
+ * @param string the image URL for the previous page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function setPrevPageImageUrl($value)
+ {
+ $this->setViewState('PrevPageImageUrl',$value);
+ }
+
+ /**
+ * @return string the image URL for the numeric page buttons. This is only used when {@link getButtonType ButtonType} is 'ImageButton' and {@link getMode Mode} is 'Numeric'.
+ * @see setNumericPageImageUrl
+ * @since 3.1.1
+ */
+ public function getNumericPageImageUrl()
+ {
+ return $this->getViewState('NumericPageImageUrl','');
+ }
+
+ /**
+ * Sets the image URL for the numeric page buttons.
+ * This is actually a template for generating a set of URLs corresponding to numeric button 1, 2, 3, .., etc.
+ * Use {0} as the placeholder for the numbers.
+ * For example, the image URL http://example.com/images/button{0}.gif
+ * will be replaced as http://example.com/images/button1.gif, http://example.com/images/button2.gif, etc.
+ * @param string the image URL for the numeric page buttons. This is only used when {@link getButtonType ButtonType} is 'ImageButton' and {@link getMode Mode} is 'Numeric'.
+ * @since 3.1.1
+ */
+ public function setNumericPageImageUrl($value)
+ {
+ $this->setViewState('NumericPageImageUrl',$value);
+ }
+
+ /**
+ * @return integer maximum number of pager buttons to be displayed. Defaults to 10.
+ */
+ public function getPageButtonCount()
+ {
+ return $this->getViewState('PageButtonCount',10);
+ }
+
+ /**
+ * @param integer maximum number of pager buttons to be displayed
+ * @throws TInvalidDataValueException if the value is less than 1.
+ */
+ public function setPageButtonCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<1)
+ throw new TInvalidDataValueException('pager_pagebuttoncount_invalid');
+ $this->setViewState('PageButtonCount',$value,10);
+ }
+
+ /**
+ * @return integer the zero-based index of the current page. Defaults to 0.
+ */
+ public function getCurrentPageIndex()
+ {
+ return $this->getViewState('CurrentPageIndex',0);
+ }
+
+ /**
+ * @param integer the zero-based index of the current page
+ * @throws TInvalidDataValueException if the value is less than 0
+ */
+ protected function setCurrentPageIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('pager_currentpageindex_invalid');
+ $this->setViewState('CurrentPageIndex',$value,0);
+ }
+
+ /**
+ * @return integer number of pages of data items available
+ */
+ public function getPageCount()
+ {
+ return $this->getViewState('PageCount',0);
+ }
+
+ /**
+ * @param integer number of pages of data items available
+ * @throws TInvalidDataValueException if the value is less than 0
+ */
+ protected function setPageCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('pager_pagecount_invalid');
+ $this->setViewState('PageCount',$value,0);
+ }
+
+ /**
+ * @return boolean whether the current page is the first page Defaults to false.
+ */
+ public function getIsFirstPage()
+ {
+ return $this->getCurrentPageIndex()===0;
+ }
+
+ /**
+ * @return boolean whether the current page is the last page
+ */
+ public function getIsLastPage()
+ {
+ return $this->getCurrentPageIndex()===$this->getPageCount()-1;
+ }
+
+ /**
+ * Performs databinding to populate data items from data source.
+ * This method is invoked by {@link dataBind()}.
+ * You may override this function to provide your own way of data population.
+ * @param Traversable the bound data
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+
+ $controlID=$this->getControlToPaginate();
+ if(($targetControl=$this->getNamingContainer()->findControl($controlID))===null || !($targetControl instanceof TDataBoundControl))
+ throw new TConfigurationException('pager_controltopaginate_invalid',$controlID);
+
+ if($targetControl->getAllowPaging())
+ {
+ $this->_pageCount=$targetControl->getPageCount();
+ $this->getControls()->clear();
+ $this->setPageCount($targetControl->getPageCount());
+ $this->setCurrentPageIndex($targetControl->getCurrentPageIndex());
+ $this->buildPager();
+ }
+ else
+ $this->_pageCount=0;
+ }
+
+ /**
+ * Renders the control.
+ * The method overrides the parent implementation by rendering
+ * the pager only when there are two or more pages.
+ * @param THtmlWriter the writer
+ */
+ public function render($writer)
+ {
+ if($this->_pageCount>1)
+ parent::render($writer);
+ }
+
+ /**
+ * Builds the pager content based on the pager mode.
+ * Current implementation includes building 'NextPrev', 'Numeric' and 'DropDownList' pagers.
+ * Derived classes may override this method to provide additional pagers.
+ */
+ protected function buildPager()
+ {
+ switch($this->getMode())
+ {
+ case TPagerMode::NextPrev:
+ $this->buildNextPrevPager();
+ break;
+ case TPagerMode::Numeric:
+ $this->buildNumericPager();
+ break;
+ case TPagerMode::DropDownList:
+ $this->buildListPager();
+ break;
+ }
+ }
+
+ /**
+ * Creates a pager button.
+ * Depending on the button type, a TLinkButton or a TButton may be created.
+ * If it is enabled (clickable), its command name and parameter will also be set.
+ * Derived classes may override this method to create additional types of buttons, such as TImageButton.
+ * @param string button type, either LinkButton or PushButton
+ * @param boolean whether the button should be enabled
+ * @param string caption of the button.
+ * @param string CommandName corresponding to the OnCommand event of the button.
+ * @param string CommandParameter corresponding to the OnCommand event of the button
+ * @return mixed the button instance
+ */
+ protected function createPagerButton($buttonType,$enabled,$text,$commandName,$commandParameter)
+ {
+ if($buttonType===TPagerButtonType::LinkButton)
+ {
+ if($enabled)
+ $button=new TLinkButton;
+ else
+ {
+ $button=new TLabel;
+ $button->setText($text);
+ $button->setCssClass($this->getButtonCssClass());
+ return $button;
+ }
+ }
+ else
+ {
+ if($buttonType===TPagerButtonType::ImageButton)
+ {
+ $button=new TImageButton;
+ $button->setImageUrl($this->getPageImageUrl($text,$commandName));
+ }
+ else
+ $button=new TButton;
+ if(!$enabled)
+ $button->setEnabled(false);
+ }
+ $button->setText($text);
+ $button->setCommandName($commandName);
+ $button->setCommandParameter($commandParameter);
+ $button->setCausesValidation(false);
+ $button->setCssClass($this->getButtonCssClass());
+ return $button;
+ }
+
+ /**
+ * @param string the caption of the image button
+ * @param string the command name associated with the image button
+ * @since 3.1.1
+ */
+ protected function getPageImageUrl($text,$commandName)
+ {
+ switch($commandName)
+ {
+ case self::CMD_PAGE:
+ $url=$this->getNumericPageImageUrl();
+ return str_replace('{0}',$text,$url);
+ case self::CMD_PAGE_NEXT:
+ return $this->getNextPageImageUrl();
+ case self::CMD_PAGE_PREV:
+ return $this->getPrevPageImageUrl();
+ case self::CMD_PAGE_FIRST:
+ return $this->getFirstPageImageUrl();
+ case self::CMD_PAGE_LAST:
+ return $this->getLastPageImageUrl();
+ default:
+ return '';
+ }
+ }
+
+ /**
+ * Builds a next-prev pager
+ */
+ protected function buildNextPrevPager()
+ {
+ $buttonType=$this->getButtonType();
+ $controls=$this->getControls();
+ if($this->getIsFirstPage())
+ {
+ if(($text=$this->getFirstPageText())!=='')
+ {
+ $label=$this->createPagerButton($buttonType,false,$text,self::CMD_PAGE_FIRST,'');
+ $controls->add($label);
+ $controls->add("\n");
+ }
+ $label=$this->createPagerButton($buttonType,false,$this->getPrevPageText(),self::CMD_PAGE_PREV,'');
+ $controls->add($label);
+ }
+ else
+ {
+ if(($text=$this->getFirstPageText())!=='')
+ {
+ $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_FIRST,'');
+ $controls->add($button);
+ $controls->add("\n");
+ }
+ $button=$this->createPagerButton($buttonType,true,$this->getPrevPageText(),self::CMD_PAGE_PREV,'');
+ $controls->add($button);
+ }
+ $controls->add("\n");
+ if($this->getIsLastPage())
+ {
+ $label=$this->createPagerButton($buttonType,false,$this->getNextPageText(),self::CMD_PAGE_NEXT,'');
+ $controls->add($label);
+ if(($text=$this->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $label=$this->createPagerButton($buttonType,false,$text,self::CMD_PAGE_LAST,'');
+ $controls->add($label);
+ }
+ }
+ else
+ {
+ $button=$this->createPagerButton($buttonType,true,$this->getNextPageText(),self::CMD_PAGE_NEXT,'');
+ $controls->add($button);
+ if(($text=$this->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_LAST,'');
+ $controls->add($button);
+ }
+ }
+ }
+
+ /**
+ * Builds a numeric pager
+ */
+ protected function buildNumericPager()
+ {
+ $buttonType=$this->getButtonType();
+ $controls=$this->getControls();
+ $pageCount=$this->getPageCount();
+ $pageIndex=$this->getCurrentPageIndex()+1;
+ $maxButtonCount=$this->getPageButtonCount();
+ $buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount;
+ $startPageIndex=1;
+ $endPageIndex=$buttonCount;
+ if($pageIndex>$endPageIndex)
+ {
+ $startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1;
+ if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount)
+ $endPageIndex=$pageCount;
+ if($endPageIndex-$startPageIndex+1<$maxButtonCount)
+ {
+ if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1)
+ $startPageIndex=1;
+ }
+ }
+
+ if($startPageIndex>1)
+ {
+ if(($text=$this->getFirstPageText())!=='')
+ {
+ $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_FIRST,'');
+ $controls->add($button);
+ $controls->add("\n");
+ }
+ $prevPageIndex=$startPageIndex-1;
+ $button=$this->createPagerButton($buttonType,true,$this->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex");
+ $controls->add($button);
+ $controls->add("\n");
+ }
+
+ for($i=$startPageIndex;$i<=$endPageIndex;++$i)
+ {
+ if($i===$pageIndex)
+ {
+ $label=$this->createPagerButton($buttonType,false,"$i",self::CMD_PAGE,'');
+ $controls->add($label);
+ }
+ else
+ {
+ $button=$this->createPagerButton($buttonType,true,"$i",self::CMD_PAGE,"$i");
+ $controls->add($button);
+ }
+ if($i<$endPageIndex)
+ $controls->add("\n");
+ }
+
+ if($pageCount>$endPageIndex)
+ {
+ $controls->add("\n");
+ $nextPageIndex=$endPageIndex+1;
+ $button=$this->createPagerButton($buttonType,true,$this->getNextPageText(),self::CMD_PAGE,"$nextPageIndex");
+ $controls->add($button);
+ if(($text=$this->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_LAST,'');
+ $controls->add($button);
+ }
+ }
+ }
+
+ /**
+ * Builds a dropdown list pager
+ */
+ protected function buildListPager()
+ {
+ $list=new TDropDownList;
+ $this->getControls()->add($list);
+ $list->setDataSource(range(1,$this->getPageCount()));
+ $list->dataBind();
+ $list->setSelectedIndex($this->getCurrentPageIndex());
+ $list->setAutoPostBack(true);
+ $list->attachEventHandler('OnSelectedIndexChanged',array($this,'listIndexChanged'));
+ }
+
+ /**
+ * Event handler to the OnSelectedIndexChanged event of the dropdown list.
+ * This handler will raise {@link onPageIndexChanged OnPageIndexChanged} event.
+ * @param TDropDownList the dropdown list control raising the event
+ * @param TEventParameter event parameter
+ */
+ public function listIndexChanged($sender,$param)
+ {
+ $pageIndex=$sender->getSelectedIndex();
+ $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
+ }
+
+ /**
+ * This event is raised when page index is changed due to a page button click.
+ * @param TPagerPageChangedEventParameter event parameter
+ */
+ public function onPageIndexChanged($param)
+ {
+ $this->raiseEvent('OnPageIndexChanged',$this,$param);
+ }
+
+ /**
+ * Processes a bubbled event.
+ * This method overrides parent's implementation by wrapping event parameter
+ * for <b>OnCommand</b> event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $command=$param->getCommandName();
+ if(strcasecmp($command,self::CMD_PAGE)===0)
+ {
+ $pageIndex=TPropertyValue::ensureInteger($param->getCommandParameter())-1;
+ $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_PAGE_NEXT)===0)
+ {
+ $pageIndex=$this->getCurrentPageIndex()+1;
+ $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_PAGE_PREV)===0)
+ {
+ $pageIndex=$this->getCurrentPageIndex()-1;
+ $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_PAGE_FIRST)===0)
+ {
+ $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,0));
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_PAGE_LAST)===0)
+ {
+ $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$this->getPageCount()-1));
+ return true;
+ }
+ return false;
+ }
+ else
+ return false;
+ }
+}
+
+/**
+ * TPagerPageChangedEventParameter class
+ *
+ * TPagerPageChangedEventParameter encapsulates the parameter data for
+ * {@link TPager::onPageIndexChanged PageIndexChanged} event of {@link TPager} controls.
+ *
+ * The {@link getCommandSource CommandSource} property refers to the control
+ * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex}
+ * returns the new page index carried with the page command.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.2
+ */
+class TPagerPageChangedEventParameter extends TEventParameter
+{
+ /**
+ * @var integer new page index
+ */
+ private $_newIndex;
+ /**
+ * @var TControl original event sender
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TControl the control originally raises the <b>OnCommand</b> event.
+ * @param integer new page index
+ */
+ public function __construct($source,$newPageIndex)
+ {
+ $this->_source=$source;
+ $this->_newIndex=$newPageIndex;
+ }
+
+ /**
+ * @return TControl the control originally raises the <b>OnCommand</b> event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+
+ /**
+ * @return integer new page index
+ */
+ public function getNewPageIndex()
+ {
+ return $this->_newIndex;
+ }
+}
+
+
+/**
+ * TPagerMode class.
+ * TPagerMode defines the enumerable type for the possible modes that a {@link TPager} control can take.
+ *
+ * The following enumerable values are defined:
+ * - NextPrev: pager buttons are displayed as next and previous pages
+ * - Numeric: pager buttons are displayed as numeric page numbers
+ * - DropDownList: a dropdown list is used to select pages
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TPagerMode extends TEnumerable
+{
+ const NextPrev='NextPrev';
+ const Numeric='Numeric';
+ const DropDownList='DropDownList';
+}
+
+
+/**
+ * TPagerButtonType class.
+ * TPagerButtonType defines the enumerable type for the possible types of pager buttons.
+ *
+ * The following enumerable values are defined:
+ * - LinkButton: link buttons
+ * - PushButton: form submit buttons
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TPagerButtonType extends TEnumerable
+{
+ const LinkButton='LinkButton';
+ const PushButton='PushButton';
+ const ImageButton='ImageButton';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TPanel.php b/lib/prado/framework/Web/UI/WebControls/TPanel.php
new file mode 100644
index 0000000..22d44a5
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TPanel.php
@@ -0,0 +1,239 @@
+<?php
+/**
+ * TPanel class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TPanelStyle class file
+ */
+Prado::using('System.Web.UI.WebControls.TPanelStyle');
+
+/**
+ * TPanel class
+ *
+ * TPanel represents a component that acts as a container for other component.
+ * It is especially useful when you want to generate components programmatically
+ * or hide/show a group of components.
+ *
+ * By default, TPanel displays a &lt;div&gt; element on a page.
+ * Children of TPanel are displayed as the body content of the element.
+ * The property {@link setWrap Wrap} can be used to set whether the body content
+ * should wrap or not. {@link setHorizontalAlign HorizontalAlign} governs how
+ * the content is aligned horizontally, and {@link getDirection Direction} indicates
+ * the content direction (left to right or right to left). You can set
+ * {@link setBackImageUrl BackImageUrl} to give a background image to the panel,
+ * and you can ste {@link setGroupingText GroupingText} so that the panel is
+ * displayed as a field set with a legend text. Finally, you can specify
+ * a default button to be fired when users press 'return' key within the panel
+ * by setting the {@link setDefaultButton DefaultButton} property.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TPanel extends TWebControl
+{
+ /**
+ * @var string ID path to the default button
+ */
+ private $_defaultButton='';
+
+ /**
+ * @return string tag name of the panel
+ */
+ protected function getTagName()
+ {
+ return 'div';
+ }
+
+ /**
+ * Creates a style object to be used by the control.
+ * This method overrides the parent impementation by creating a TPanelStyle object.
+ * @return TPanelStyle the style used by TPanel.
+ */
+ protected function createStyle()
+ {
+ return new TPanelStyle;
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ * @throws TInvalidDataValueException if default button is not right.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ if(($butt=$this->getDefaultButton())!=='')
+ $writer->addAttribute('id',$this->getClientID());
+ }
+
+ /**
+ * @return boolean whether the content wraps within the panel. Defaults to true.
+ */
+ public function getWrap()
+ {
+ return $this->getStyle()->getWrap();
+ }
+
+ /**
+ * Sets the value indicating whether the content wraps within the panel.
+ * @param boolean whether the content wraps within the panel.
+ */
+ public function setWrap($value)
+ {
+ $this->getStyle()->setWrap($value);
+ }
+
+ /**
+ * @return string the horizontal alignment of the contents within the panel, defaults to 'NotSet'.
+ */
+ public function getHorizontalAlign()
+ {
+ return $this->getStyle()->getHorizontalAlign();
+ }
+
+ /**
+ * Sets the horizontal alignment of the contents within the panel.
+ * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center'
+ * @param string the horizontal alignment
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->getStyle()->setHorizontalAlign($value);
+ }
+
+ /**
+ * @return string the URL of the background image for the panel component.
+ */
+ public function getBackImageUrl()
+ {
+ return $this->getStyle()->getBackImageUrl();
+ }
+
+ /**
+ * Sets the URL of the background image for the panel component.
+ * @param string the URL
+ */
+ public function setBackImageUrl($value)
+ {
+ $this->getStyle()->setBackImageUrl($value);
+ }
+
+ /**
+ * @return string alignment of the content in the panel. Defaults to 'NotSet'.
+ */
+ public function getDirection()
+ {
+ return $this->getStyle()->getDirection();
+ }
+
+ /**
+ * @param string alignment of the content in the panel.
+ * Valid values include 'NotSet', 'LeftToRight', 'RightToLeft'.
+ */
+ public function setDirection($value)
+ {
+ $this->getStyle()->setDirection($value);
+ }
+
+ /**
+ * @return string the ID path to the default button. Defaults to empty.
+ */
+ public function getDefaultButton()
+ {
+ return $this->_defaultButton;
+ }
+
+ /**
+ * Specifies the default button for the panel.
+ * The default button will be fired (clicked) whenever a user enters 'return'
+ * key within the panel.
+ * The button must be locatable via the function call {@link TControl::findControl findControl}.
+ * @param string the ID path to the default button.
+ */
+ public function setDefaultButton($value)
+ {
+ $this->_defaultButton=$value;
+ }
+
+ /**
+ * @return string the legend text when the panel is used as a fieldset. Defaults to empty.
+ */
+ public function getGroupingText()
+ {
+ return $this->getViewState('GroupingText','');
+ }
+
+ /**
+ * @param string the legend text. If this value is not empty, the panel will be rendered as a fieldset.
+ */
+ public function setGroupingText($value)
+ {
+ $this->setViewState('GroupingText',$value,'');
+ }
+
+ /**
+ * @return string the visibility and position of scroll bars in a panel control, defaults to None.
+ */
+ public function getScrollBars()
+ {
+ return $this->getStyle()->getScrollBars();
+ }
+
+ /**
+ * @param string the visibility and position of scroll bars in a panel control.
+ * Valid values include None, Auto, Both, Horizontal and Vertical.
+ */
+ public function setScrollBars($value)
+ {
+ $this->getStyle()->setScrollBars($value);
+ }
+
+ /**
+ * Renders the openning tag for the control (including attributes)
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderBeginTag($writer)
+ {
+ parent::renderBeginTag($writer);
+ if(($text=$this->getGroupingText())!=='')
+ {
+ $writer->renderBeginTag('fieldset');
+ $writer->renderBeginTag('legend');
+ $writer->write($text);
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Renders the closing tag for the control
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderEndTag($writer)
+ {
+ if($this->getGroupingText()!=='')
+ $writer->renderEndTag();
+ parent::renderEndTag($writer);
+ }
+
+ public function render($writer)
+ {
+ parent::render($writer);
+
+ if(($butt=$this->getDefaultButton())!=='')
+ {
+ if(($button=$this->findControl($butt))===null)
+ throw new TInvalidDataValueException('panel_defaultbutton_invalid',$butt);
+ else
+ $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
+ }
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TPanelStyle.php b/lib/prado/framework/Web/UI/WebControls/TPanelStyle.php
new file mode 100644
index 0000000..2e0f1a2
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TPanelStyle.php
@@ -0,0 +1,274 @@
+<?php
+/**
+ * TPanelStyle class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TStyle class file
+ */
+Prado::using('System.Web.UI.WebControls.TStyle');
+
+/**
+ * TPanelStyle class.
+ * TPanelStyle represents the CSS style specific for panel HTML tag.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TPanelStyle extends TStyle
+{
+ /**
+ * @var string the URL of the background image for the panel component
+ */
+ private $_backImageUrl=null;
+ /**
+ * @var string alignment of the content in the panel.
+ */
+ private $_direction=null;
+ /**
+ * @var string horizontal alignment of the contents within the panel
+ */
+ private $_horizontalAlign=null;
+ /**
+ * @var string visibility and position of scroll bars
+ */
+ private $_scrollBars=null;
+ /**
+ * @var boolean whether the content wraps within the panel
+ */
+ private $_wrap=null;
+
+ /**
+ * Adds attributes related to CSS styles to renderer.
+ * This method overrides the parent implementation.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function addAttributesToRender($writer)
+ {
+ if(($url=trim($this->getBackImageUrl()))!=='')
+ $this->setStyleField('background-image','url('.$url.')');
+
+ switch($this->getScrollBars())
+ {
+ case TScrollBars::Horizontal: $this->setStyleField('overflow-x','scroll'); break;
+ case TScrollBars::Vertical: $this->setStyleField('overflow-y','scroll'); break;
+ case TScrollBars::Both: $this->setStyleField('overflow','scroll'); break;
+ case TScrollBars::Auto: $this->setStyleField('overflow','auto'); break;
+ }
+
+ if(($align=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
+ $this->setStyleField('text-align',strtolower($align));
+
+ if(!$this->getWrap())
+ $this->setStyleField('white-space','nowrap');
+
+ if(($direction=$this->getDirection())!==TContentDirection::NotSet)
+ {
+ if($direction===TContentDirection::LeftToRight)
+ $this->setStyleField('direction','ltr');
+ else
+ $this->setStyleField('direction','rtl');
+ }
+
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * @return string the URL of the background image for the panel component.
+ */
+ public function getBackImageUrl()
+ {
+ return $this->_backImageUrl===null?'':$this->_backImageUrl;
+ }
+
+ /**
+ * Sets the URL of the background image for the panel component.
+ * @param string the URL
+ */
+ public function setBackImageUrl($value)
+ {
+ $this->_backImageUrl=$value;
+ }
+
+ /**
+ * @return TContentDirection alignment of the content in the panel. Defaults to TContentDirection::NotSet.
+ */
+ public function getDirection()
+ {
+ return $this->_direction===null?TContentDirection::NotSet:$this->_direction;
+ }
+
+ /**
+ * @param TContentDirection alignment of the content in the panel.
+ */
+ public function setDirection($value)
+ {
+ $this->_direction=TPropertyValue::ensureEnum($value,'TContentDirection');
+ }
+
+ /**
+ * @return boolean whether the content wraps within the panel. Defaults to true.
+ */
+ public function getWrap()
+ {
+ return $this->_wrap===null?true:$this->_wrap;
+ }
+
+ /**
+ * Sets the value indicating whether the content wraps within the panel.
+ * @param boolean whether the content wraps within the panel.
+ */
+ public function setWrap($value)
+ {
+ $this->_wrap=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return THorizontalAlign the horizontal alignment of the contents within the panel, defaults to THorizontalAlign::NotSet.
+ */
+ public function getHorizontalAlign()
+ {
+ return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
+ }
+
+ /**
+ * Sets the horizontal alignment of the contents within the panel.
+ * @param THorizontalAlign the horizontal alignment
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
+ }
+
+ /**
+ * @return TScrollBars the visibility and position of scroll bars in a panel control, defaults to TScrollBars::None.
+ */
+ public function getScrollBars()
+ {
+ return $this->_scrollBars===null?TScrollBars::None:$this->_scrollBars;
+ }
+
+ /**
+ * @param TScrollBars the visibility and position of scroll bars in a panel control.
+ */
+ public function setScrollBars($value)
+ {
+ $this->_scrollBars=TPropertyValue::ensureEnum($value,'TScrollBars');
+ }
+
+ /**
+ * Sets the style attributes to default values.
+ * This method overrides the parent implementation by
+ * resetting additional TPanelStyle specific attributes.
+ */
+ public function reset()
+ {
+ parent::reset();
+ $this->_backImageUrl=null;
+ $this->_direction=null;
+ $this->_horizontalAlign=null;
+ $this->_scrollBars=null;
+ $this->_wrap=null;
+ }
+
+ /**
+ * Copies the fields in a new style to this style.
+ * If a style field is set in the new style, the corresponding field
+ * in this style will be overwritten.
+ * @param TStyle the new style
+ */
+ public function copyFrom($style)
+ {
+ parent::copyFrom($style);
+ if($style instanceof TPanelStyle)
+ {
+ if($style->_backImageUrl!==null)
+ $this->_backImageUrl=$style->_backImageUrl;
+ if($style->_direction!==null)
+ $this->_direction=$style->_direction;
+ if($style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($style->_scrollBars!==null)
+ $this->_scrollBars=$style->_scrollBars;
+ if($style->_wrap!==null)
+ $this->_wrap=$style->_wrap;
+ }
+ }
+
+ /**
+ * Merges the style with a new one.
+ * If a style field is not set in this style, it will be overwritten by
+ * the new one.
+ * @param TStyle the new style
+ */
+ public function mergeWith($style)
+ {
+ parent::mergeWith($style);
+ if($style instanceof TPanelStyle)
+ {
+ if($this->_backImageUrl===null && $style->_backImageUrl!==null)
+ $this->_backImageUrl=$style->_backImageUrl;
+ if($this->_direction===null && $style->_direction!==null)
+ $this->_direction=$style->_direction;
+ if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($this->_scrollBars===null && $style->_scrollBars!==null)
+ $this->_scrollBars=$style->_scrollBars;
+ if($this->_wrap===null && $style->_wrap!==null)
+ $this->_wrap=$style->_wrap;
+ }
+ }
+}
+
+/**
+ * TContentDirection class.
+ * TContentDirection defines the enumerable type for the possible directions that a panel can be at.
+ *
+ * The following enumerable values are defined:
+ * - NotSet: the direction is not specified
+ * - LeftToRight: content in a panel is left to right
+ * - RightToLeft: content in a panel is right to left
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TContentDirection extends TEnumerable
+{
+ const NotSet='NotSet';
+ const LeftToRight='LeftToRight';
+ const RightToLeft='RightToLeft';
+}
+
+/**
+ * TScrollBars class.
+ * TScrollBars defines the enumerable type for the possible scroll bar mode
+ * that a {@link TPanel} control could use.
+ *
+ * The following enumerable values are defined:
+ * - None: no scroll bars.
+ * - Auto: scroll bars automatically appeared when needed.
+ * - Both: show both horizontal and vertical scroll bars all the time.
+ * - Horizontal: horizontal scroll bar only
+ * - Vertical: vertical scroll bar only
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TScrollBars extends TEnumerable
+{
+ const None='None';
+ const Auto='Auto';
+ const Both='Both';
+ const Horizontal='Horizontal';
+ const Vertical='Vertical';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TPlaceHolder.php b/lib/prado/framework/Web/UI/WebControls/TPlaceHolder.php
new file mode 100644
index 0000000..65f5ba2
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TPlaceHolder.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * TPlaceHolder class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TPlaceHolder class
+ *
+ * TPlaceHolder reserves a place on a template, where static texts or controls
+ * may be inserted. You may add or remove texts or child controls of TPlaceHolder
+ * by manipulating the {@link TControl::getControls Controls} property.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TPlaceHolder extends TControl
+{
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TRadioButton.php b/lib/prado/framework/Web/UI/WebControls/TRadioButton.php
new file mode 100644
index 0000000..cfdb795
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TRadioButton.php
@@ -0,0 +1,304 @@
+<?php
+/**
+ * TRadioButton class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TCheckBox parent class
+ */
+Prado::using('System.Web.UI.WebControls.TCheckBox');
+
+/**
+ * TRadioButton class
+ *
+ * TRadioButton displays a radio button on the page.
+ * You can specify the caption to display beside the radio buttonby setting
+ * the {@link setText Text} property. The caption can appear either on the right
+ * or left of the radio button, which is determined by the {@link setTextAlign TextAlign}
+ * property.
+ *
+ * To determine whether the TRadioButton component is checked, test the {@link getChecked Checked}
+ * property. The {@link onCheckedChanged OnCheckedChanged} event is raised when
+ * the {@link getChecked Checked} state of the TRadioButton component changes
+ * between posts to the server. You can provide an event handler for
+ * the {@link onCheckedChanged OnCheckedChanged} event to to programmatically
+ * control the actions performed when the state of the TRadioButton component changes
+ * between posts to the server.
+ *
+ * TRadioButton uses {@link setGroupName GroupName} to group together a set of radio buttons.
+ * Once the {@link setGroupName GroupName} is set, you can use the {@link getRadioButtonsInGroup}
+ * method to get an array of TRadioButtons having the same group name.
+ *
+ * If {@link setAutoPostBack AutoPostBack} is set true, changing the radio button state
+ * will cause postback action. And if {@link setCausesValidation CausesValidation}
+ * is true, validation will also be processed, which can be further restricted within
+ * a {@link setValidationGroup ValidationGroup}.
+ *
+ * Note, {@link setText Text} is rendered as is. Make sure it does not contain unwanted characters
+ * that may bring security vulnerabilities.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRadioButton extends TCheckBox
+{
+ /**
+ * @param array list of radio buttons that are on the current page hierarchy
+ */
+ private static $_activeButtons=array();
+ /**
+ * @var integer number of radio buttons created
+ */
+ private static $_buttonCount=0;
+ /**
+ * @var integer global ID of this radiobutton
+ */
+ private $_globalID;
+ /**
+ * @var string previous UniqueID (used to calculate UniqueGroup)
+ */
+ private $_previousUniqueID=null;
+ /**
+ * @var string the name used to fetch radiobutton post data
+ */
+ private $_uniqueGroupName=null;
+
+ /**
+ * Constructor.
+ * Registers the radiobutton in a global radiobutton collection.
+ * If overridden, the parent implementation must be invoked first.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->_globalID = self::$_buttonCount++;
+ }
+
+ /**
+ * Registers the radio button groupings. If overriding onInit method,
+ * ensure to call parent implemenation.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ self::$_activeButtons[$this->_globalID]=$this;
+ }
+
+ /**
+ * Unregisters the radio button groupings. If overriding onInit method,
+ * ensure to call parent implemenation.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onUnLoad($param)
+ {
+ unset(self::$_activeButtons[$this->_globalID]);
+ parent::onUnLoad($param);
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ $uniqueGroupName=$this->getUniqueGroupName();
+ $value=isset($values[$uniqueGroupName])?$values[$uniqueGroupName]:null;
+ if($value!==null && $value===$this->getValueAttribute())
+ {
+ if(!$this->getChecked())
+ {
+ $this->setChecked(true);
+ return true;
+ }
+ else
+ return false;
+ }
+ else if($this->getChecked())
+ $this->setChecked(false);
+ return false;
+ }
+
+ /**
+ * @return string the name of the group that the radio button belongs to. Defaults to empty.
+ */
+ public function getGroupName()
+ {
+ return $this->getViewState('GroupName','');
+ }
+
+ /**
+ * Sets the name of the group that the radio button belongs to.
+ * The group is unique among the control's naming container.
+ * @param string the group name
+ * @see setUniqueGroupName
+ */
+ public function setGroupName($value)
+ {
+ $this->setViewState('GroupName',$value,'');
+ $this->_uniqueGroupName=null;
+ }
+
+ /**
+ * @return string the name used to fetch radiobutton post data
+ */
+ public function getUniqueGroupName()
+ {
+ if(($groupName=$this->getViewState('UniqueGroupName',''))!=='')
+ return $groupName;
+ else if(($uniqueID=$this->getUniqueID())!==$this->_previousUniqueID || $this->_uniqueGroupName===null)
+ {
+ $groupName=$this->getGroupName();
+ $this->_previousUniqueID=$uniqueID;
+ if($uniqueID!=='')
+ {
+ if(($pos=strrpos($uniqueID,TControl::ID_SEPARATOR))!==false)
+ {
+ if($groupName!=='')
+ $groupName=substr($uniqueID,0,$pos+1).$groupName;
+ else if(is_a($this->getNamingContainer(), 'TRadioButtonList'))
+ $groupName=substr($uniqueID,0,$pos);
+ }
+ if($groupName==='')
+ $groupName=$uniqueID;
+ }
+ $this->_uniqueGroupName=$groupName;
+ }
+ return $this->_uniqueGroupName;
+ }
+
+ /**
+ * Sets the unique group name that the radio button belongs to.
+ * A unique group is a radiobutton group unique among the whole page hierarchy,
+ * while the {@link setGroupName GroupName} specifies a group that is unique
+ * among the control's naming container only.
+ * For example, each cell of a {@link TDataGrid} is a naming container.
+ * If you specify {@link setGroupName GroupName} for a radiobutton in a cell,
+ * it groups together radiobutton within a cell, but not the other, even though
+ * they have the same {@link setGroupName GroupName}.
+ * On the contratry, if {@link setUniqueGroupName UniqueGroupName} is used instead,
+ * it will group all appropriate radio buttons on the whole page hierarchy.
+ * Note, when both {@link setUniqueGroupName UniqueGroupName} and
+ * {@link setGroupName GroupName}, the former takes precedence.
+ * @param string the group name
+ * @see setGroupName
+ */
+ public function setUniqueGroupName($value)
+ {
+ $this->setViewState('UniqueGroupName',$value,'');
+ }
+
+ /**
+ * Gets an array of radiobuttons whose group name is the same as this radiobutton's.
+ * Note, only those radiobuttons that are on the current page hierarchy may be
+ * returned in the result.
+ * @return array list of TRadioButton with the same group
+ */
+ public function getRadioButtonsInGroup()
+ {
+ $group = $this->getUniqueGroupName();
+ $buttons = array();
+ foreach(self::$_activeButtons as $control)
+ {
+ if($control->getUniqueGroupName() === $group)
+ $buttons[] = $control;
+ }
+ return $buttons;
+ }
+
+ /**
+ * @return string the value attribute to be rendered
+ */
+ protected function getValueAttribute()
+ {
+ if(($value=parent::getValueAttribute())==='')
+ return $this->getUniqueID();
+ else
+ return $value;
+ }
+
+ /**
+ * @return boolean whether to render javascript.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether to render javascript.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Renders a radiobutton input element.
+ * @param THtmlWriter the writer for the rendering purpose
+ * @param string checkbox id
+ * @param string onclick js
+ */
+ protected function renderInputTag($writer,$clientID,$onclick)
+ {
+ if($clientID!=='')
+ $writer->addAttribute('id',$clientID);
+ $writer->addAttribute('type','radio');
+ $writer->addAttribute('name',$this->getUniqueGroupName());
+ $writer->addAttribute('value',$this->getValueAttribute());
+ if(!empty($onclick))
+ $writer->addAttribute('onclick',$onclick);
+ if($this->getChecked())
+ $writer->addAttribute('checked','checked');
+ if(!$this->getEnabled(true))
+ $writer->addAttribute('disabled','disabled');
+
+ $page=$this->getPage();
+ if($this->getEnabled(true)
+ && $this->getEnableClientScript()
+ && $this->getAutoPostBack()
+ && $page->getClientSupportsJavaScript())
+ {
+ $this->renderClientControlScript($writer);
+ }
+
+ if(($accesskey=$this->getAccessKey())!=='')
+ $writer->addAttribute('accesskey',$accesskey);
+ if(($tabindex=$this->getTabIndex())>0)
+ $writer->addAttribute('tabindex',"$tabindex");
+ if($attributes=$this->getViewState('InputAttributes',null))
+ $writer->addAttributes($attributes);
+ $writer->renderBeginTag('input');
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Renders the client-script code.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TRadioButton';
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TRadioButtonList.php b/lib/prado/framework/Web/UI/WebControls/TRadioButtonList.php
new file mode 100644
index 0000000..dc9e2da
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TRadioButtonList.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * TRadioButtonList class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TRadioButton class
+ */
+Prado::using('System.Web.UI.WebControls.TRadioButton');
+/**
+ * Includes TCheckBoxList class
+ */
+Prado::using('System.Web.UI.WebControls.TCheckBoxList');
+
+/**
+ * TRadioButtonList class
+ *
+ * TRadioButtonList displays a list of radiobuttons on a Web page.
+ *
+ * TRadioButtonList inherits all properties and events of {@link TCheckBoxList}.
+ * Each TRadioButtonList displays one group of radiobuttons, i.e., at most
+ * one radiobutton can be selected at a time.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRadioButtonList extends TCheckBoxList
+{
+ /**
+ * @return boolean whether this control supports multiple selection. Always false for radiobutton list.
+ */
+ protected function getIsMultiSelect()
+ {
+ return false;
+ }
+
+ /**
+ * Creates a control used for repetition (used as a template).
+ * @return TControl the control to be repeated
+ */
+ protected function createRepeatedControl()
+ {
+ return new TRadioButtonItem;
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ $value=isset($values[$key])?$values[$key]:'';
+ $oldSelection=$this->getSelectedIndex();
+ $this->ensureDataBound();
+ foreach($this->getItems() as $index=>$item)
+ {
+ if($item->getEnabled() && $item->getValue()===$value)
+ {
+ if($index===$oldSelection)
+ return false;
+ else
+ {
+ $this->setSelectedIndex($index);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @throws TNotSupportedException if this method is invoked
+ */
+ public function setSelectedIndices($indices)
+ {
+ throw new TNotSupportedException('radiobuttonlist_selectedindices_unsupported');
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TRadioButtonList';
+ }
+}
+
+class TRadioButtonItem extends TRadioButton {
+ /**
+ * Override client implementation to avoid emitting the javascript
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TRangeValidator.php b/lib/prado/framework/Web/UI/WebControls/TRangeValidator.php
new file mode 100644
index 0000000..a6668f4
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TRangeValidator.php
@@ -0,0 +1,357 @@
+<?php
+/**
+ * TRangeValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TRangeValidator class
+ *
+ * TRangeValidator tests whether an input value is within a specified range.
+ *
+ * TRangeValidator uses three key properties to perform its validation.
+ * The {@link setMinValue MinValue} and {@link setMaxValue MaxValue}
+ * properties specify the minimum and maximum values of the valid range.
+ * The {@link setDataType DataType} property is used to specify the
+ * data type of the value and the minimum and maximum range values.
+ * These values are converted to this data type before the validation
+ * operation is performed. The following value types are supported:
+ * - <b>Integer</b> A 32-bit signed integer data type.
+ * - <b>Float</b> A double-precision floating point number data type.
+ * - <b>Date</b> A date data type. The date format can be specified by
+ * setting {@link setDateFormat DateFormat} property, which must be recognizable
+ * by {@link TSimpleDateFormatter}. If the property is not set,
+ * the GNU date syntax is assumed.
+ * - <b>String</b> A string data type.
+ * - <b>StringLength</b> check for string length.
+ *
+ * If {@link setStrictComparison StrictComparison} is true, then the ranges
+ * are compared as strictly less than the max value and/or strictly greater than the min value.
+ *
+ * The TRangeValidator allows a special DataType "StringLength" that
+ * can be used to verify minimum and maximum string length. The
+ * {@link setCharset Charset} property can be used to force a particular
+ * charset for comparison. Otherwise, the application charset is used and is
+ * defaulted as UTF-8.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRangeValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TRangeValidator';
+ }
+
+ /**
+ * @return string the minimum value of the validation range.
+ */
+ public function getMinValue()
+ {
+ return $this->getViewState('MinValue','');
+ }
+
+ /**
+ * Sets the minimum value of the validation range.
+ * @param string the minimum value
+ */
+ public function setMinValue($value)
+ {
+ $this->setViewState('MinValue',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string the maximum value of the validation range.
+ */
+ public function getMaxValue()
+ {
+ return $this->getViewState('MaxValue','');
+ }
+
+ /**
+ * Sets the maximum value of the validation range.
+ * @param string the maximum value
+ */
+ public function setMaxValue($value)
+ {
+ $this->setViewState('MaxValue',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @param boolean true to perform strict comparison (i.e. strictly less than max and/or strictly greater than min).
+ */
+ public function setStrictComparison($value)
+ {
+ $this->setViewState('StrictComparison', TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean true to perform strict comparison.
+ */
+ public function getStrictComparison()
+ {
+ return $this->getViewState('StrictComparison', false);
+ }
+
+ /**
+ * @return TRangeValidationDataType the data type that the values being compared are
+ * converted to before the comparison is made. Defaults to TRangeValidationDataType::String.
+ */
+ public function getDataType()
+ {
+ return $this->getViewState('DataType',TRangeValidationDataType::String);
+ }
+
+ /**
+ * Sets the data type that the values being compared are converted to before the comparison is made.
+ * @param TRangeValidationDataType the data type
+ */
+ public function setDataType($value)
+ {
+ $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TRangeValidationDataType'),TRangeValidationDataType::String);
+ }
+
+ /**
+ * Sets the date format for a date validation
+ * @param string the date format value
+ */
+ public function setDateFormat($value)
+ {
+ $this->setViewState('DateFormat', $value, '');
+ }
+
+ /**
+ * @return string the date validation date format if any
+ */
+ public function getDateFormat()
+ {
+ return $this->getViewState('DateFormat', '');
+ }
+
+ /**
+ * @param string charset for string length comparison.
+ */
+ public function setCharset($value)
+ {
+ $this->setViewState('Charset', $value, '');
+ }
+
+ /**
+ * @return string charset for string length comparison.
+ */
+ public function getCharset()
+ {
+ return $this->getViewState('Charset', '');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input data is within the range.
+ * The validation always succeeds if the input data is empty.
+ * @return boolean whether the validation succeeds
+ */
+ protected function evaluateIsValid()
+ {
+ $value=$this->getValidationValue($this->getValidationTarget());
+ if($value==='')
+ return true;
+
+ switch($this->getDataType())
+ {
+ case TRangeValidationDataType::Integer:
+ return $this->isValidInteger($value);
+ case TRangeValidationDataType::Float:
+ return $this->isValidFloat($value);
+ case TRangeValidationDataType::Date:
+ return $this->isValidDate($value);
+ case TRangeValidationDataType::StringLength:
+ return $this->isValidStringLength($value);
+ default:
+ return $this->isValidString($value);
+ }
+ }
+
+ /**
+ * Determine if the value is within the integer range.
+ * @param string value to validate true
+ * @return boolean true if within integer range.
+ */
+ protected function isValidInteger($value)
+ {
+ $minValue=$this->getMinValue();
+ $maxValue=$this->getMaxValue();
+
+ $valid=preg_match('/^[-+]?[0-9]+$/',trim($value));
+ $value=intval($value);
+ if($minValue!=='')
+ $valid=$valid && $this->isGreaterThan($value, intval($minValue));
+ if($maxValue!=='')
+ $valid=$valid && $this->isLessThan($value,intval($maxValue));
+ return $valid;
+ }
+
+ protected function isLessThan($left,$right)
+ {
+ return $this->getStrictComparison() ? $left < $right : $left <= $right;
+ }
+
+ protected function isGreaterThan($left, $right)
+ {
+ return $this->getStrictComparison() ? $left > $right : $left >= $right;
+ }
+
+ /**
+ * Determine if the value is within the specified float range.
+ * @param string value to validate
+ * @return boolean true if within range.
+ */
+ protected function isValidFloat($value)
+ {
+ $minValue=$this->getMinValue();
+ $maxValue=$this->getMaxValue();
+
+ $valid=preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value));
+ $value=floatval($value);
+ if($minValue!=='')
+ $valid=$valid && $this->isGreaterThan($value,floatval($minValue));
+ if($maxValue!=='')
+ $valid=$valid && $this->isLessThan($value,floatval($maxValue));
+ return $valid;
+ }
+
+ /**
+ * Determine if the date is within the specified range.
+ * Uses pradoParseDate and strtotime to get the date from string.
+ * @param string date as string to validate
+ * @return boolean true if within range.
+ */
+ protected function isValidDate($value)
+ {
+ $minValue=$this->getMinValue();
+ $maxValue=$this->getMaxValue();
+
+ $valid=true;
+
+ $dateFormat = $this->getDateFormat();
+ if($dateFormat!=='')
+ {
+ $formatter=Prado::createComponent('System.Util.TSimpleDateFormatter', $dateFormat);
+ $value = $formatter->parse($value);
+ if($minValue!=='')
+ $valid=$valid && $this->isGreaterThan($value,$formatter->parse($minValue));
+ if($maxValue!=='')
+ $valid=$valid && $this->isLessThan($value,$formatter->parse($maxValue));
+ return $valid;
+ }
+ else
+ {
+ $value=strtotime($value);
+ if($minValue!=='')
+ $valid=$valid && $this->isGreaterThan($value,strtotime($minValue));
+ if($maxValue!=='')
+ $valid=$valid && $this->isLessThan($value,strtotime($maxValue));
+ return $valid;
+ }
+ }
+
+ /**
+ * Compare the string with a minimum and a maxiumum value.
+ * Uses strcmp for comparision.
+ * @param string value to compare with.
+ * @return boolean true if the string is within range.
+ */
+ protected function isValidString($value)
+ {
+ $minValue=$this->getMinValue();
+ $maxValue=$this->getMaxValue();
+
+ $valid=true;
+ if($minValue!=='')
+ $valid=$valid && $this->isGreaterThan(strcmp($value,$minValue),0);
+ if($maxValue!=='')
+ $valid=$valid && $this->isLessThan(strcmp($value,$maxValue),0);
+ return $valid;
+ }
+
+ /**
+ * @param string string for comparision
+ * @return boolean true if min and max string length are satisfied.
+ */
+ protected function isValidStringLength($value)
+ {
+ $minValue=$this->getMinValue();
+ $maxValue=$this->getMaxValue();
+
+ $valid=true;
+ $charset = $this->getCharset();
+ if($charset==='')
+ {
+ $app= $this->getApplication()->getGlobalization();
+ $charset = $app ? $app->getCharset() : null;
+ if(!$charset)
+ $charset = 'UTF-8';
+ }
+
+ $length = iconv_strlen($value, $charset);
+ if($minValue!=='')
+ $valid = $valid && $this->isGreaterThan($length,intval($minValue));
+ if($maxValue!=='')
+ $valid = $valid && $this->isLessThan($length,intval($maxValue));
+ return $valid;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options=parent::getClientScriptOptions();
+ $options['MinValue']=$this->getMinValue();
+ $options['MaxValue']=$this->getMaxValue();
+ $options['DataType']=$this->getDataType();
+ $options['StrictComparison']=$this->getStrictComparison();
+ if(($dateFormat=$this->getDateFormat())!=='')
+ $options['DateFormat']=$dateFormat;
+ return $options;
+ }
+}
+
+
+/**
+ * TRangeValidationDataType class.
+ * TRangeValidationDataType defines the enumerable type for the possible data types that
+ * a range validator can validate upon.
+ *
+ * The following enumerable values are defined:
+ * - Integer
+ * - Float
+ * - Date
+ * - String
+ * - StringLength
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TRangeValidationDataType extends TValidationDataType
+{
+ const StringLength='StringLength';
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TRatingList.php b/lib/prado/framework/Web/UI/WebControls/TRatingList.php
new file mode 100644
index 0000000..0f1f364
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TRatingList.php
@@ -0,0 +1,359 @@
+<?php
+/**
+ * TRatingList class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TRadioButtonList class
+ */
+Prado::using('System.Web.UI.WebControls.TRadioButtonList');
+
+/**
+ * TRatingList class.
+ *
+ * This class is EXPERIMENTAL.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRatingList extends TRadioButtonList
+{
+ /**
+ * Script path relative to the TClientScriptManager::SCRIPT_PATH
+ */
+ const SCRIPT_PATH='prado/ratings';
+
+ /**
+ * @var array list of published rating images.
+ */
+ private $_ratingImages = array();
+
+ /**
+ * Sets the default repeat direction to horizontal.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setRepeatDirection(TRepeatDirection::Horizontal);
+ }
+
+ /**
+ * @return boolean whether the items in the column can be edited. Defaults to false.
+ */
+ public function getReadOnly()
+ {
+ return $this->getViewState('ReadOnly',false);
+ }
+
+ /**
+ * @param boolean whether the items in the column can be edited
+ */
+ public function setReadOnly($value)
+ {
+ $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Wrapper for {@link setReadOnly ReadOnly} property.
+ * @return boolean whether the rating list can be edited. Defaults to true.
+ */
+ public function getAllowInput()
+ {
+ return !$this->getReadOnly();
+ }
+
+ /**
+ * Wrapper for {@link setReadOnly ReadOnly} property.
+ * @param boolean whether the rating list can be edited
+ */
+ public function setAllowInput($value)
+ {
+ $this->setReadOnly(!TPropertyValue::ensureBoolean($value));
+ }
+
+ /**
+ * Wrapper for {@link setReadOnly ReadOnly} property.
+ * @param boolean whether the rating list can be edited
+ */
+ public function setEnabled($value)
+ {
+ $this->setReadOnly(!TPropertyValue::ensureBoolean($value));
+ }
+
+ /**
+ * The repeat layout must be Table.
+ * @param string repeat layout type
+ * @throws TInvaliddataValueException when repeat layout is not Table.
+ */
+ public function setRepeatLayout($value)
+ {
+ if($value!==TRepeatLayout::Table)
+ throw new TInvalidDataValueException('ratinglist_table_layout_only');
+ else
+ parent::setRepeatLayout($value);
+ }
+
+ /**
+ * @return float rating value.
+ */
+ public function getRating()
+ {
+ $rating = $this->getViewState('Rating', null);
+ if ($rating === null)
+ return $this->getSelectedIndex()+1;
+ else
+ return $rating;
+ }
+
+ /**
+ * @param float rating value, also sets the selected Index
+ */
+ public function setRating($value)
+ {
+ $value = TPropertyValue::ensureFloat($value);
+ $this->setViewState('Rating', $value, null);
+ $index = $this->getRatingIndex($value);
+ parent::setSelectedIndex($index);
+ }
+
+ public function setSelectedIndex($value)
+ {
+ $this->setRating($value+1);
+ parent::setSelectedIndex($value);
+ }
+
+ /**
+ * @param float rating value
+ * @return int rating as integer
+ */
+ protected function getRatingIndex($rating)
+ {
+ $interval = $this->getHalfRatingInterval();
+ $base = intval($rating)-1;
+ $remainder = $rating-$base-1;
+ return $remainder > $interval[1] ? $base+1 : $base;
+ }
+
+ /**
+ * @param int change the rating selection index
+ */
+ public function onSelectedIndexChanged($param)
+ {
+ $value = $this->getRating();
+ $value = TPropertyValue::ensureInteger($value);
+ $this->setRating($value);
+ parent::onSelectedIndexChanged($param);
+ }
+
+ /**
+ * @return string control or html element ID for displaying a caption.
+ */
+ public function getCaptionID()
+ {
+ return $this->getViewState('CaptionID', '');
+ }
+
+ /**
+ * @param string control or html element ID for displaying a caption.
+ */
+ public function setCaptionID($value)
+ {
+ $this->setViewState('CaptionID', $value, '');
+ }
+
+ protected function getCaptionControl()
+ {
+ if(($id=$this->getCaptionID())!=='')
+ {
+ if($control=$this->getPage()->findControl($id))
+ return $control;
+ if($control=$this->getNamingContainer()->findControl($id))
+ return $control;
+ }
+ throw new TInvalidDataValueException(
+ 'ratinglist_invalid_caption_id',$id,$this->getID());
+ }
+
+ /**
+ * @return string caption text. Default is "Rate It:".
+ */
+ public function getCaption()
+ {
+ return $this->getCaptionControl()->getText();
+ }
+
+ /**
+ * @return TRatingListStyle current rating style
+ */
+ public function setCaption($value)
+ {
+ $this->getCaptionControl()->setText($value);
+ }
+
+ /**
+ * @param string set the rating style, default is "default"
+ */
+ public function setRatingStyle($value)
+ {
+ $this->setViewState('RatingStyle', $value, 'default');
+ }
+
+ /**
+ * @return TRatingListStyle current rating style
+ */
+ public function getRatingStyle()
+ {
+ return $this->getViewState('RatingStyle', 'default');
+ }
+
+ /**
+ * @return string rating style css class name.
+ */
+ protected function getRatingStyleCssClass()
+ {
+ return 'TRatingList_'.$this->getRatingStyle();
+ }
+
+ /**
+ * Sets the interval such that those rating values within the interval
+ * will be considered as a half star rating.
+ * @param array rating display half value interval, default is array(0.3, 0.7);
+ */
+ public function setHalfRatingInterval($value)
+ {
+ $this->setViewState('HalfRating',
+ TPropertyValue::ensureArray($value), array(0.3, 0.7));
+ }
+
+ /**
+ * @return array rating display half value interval, default is array(0.3, 0.7);
+ */
+ public function getHalfRatingInterval()
+ {
+ return $this->getViewState('HalfRating', array(0.3, 0.7));
+ }
+
+ /**
+ * @return array list of post back options.
+ */
+ protected function getPostBackOptions()
+ {
+ $options = parent::getPostBackOptions();
+ $options['AutoPostBack'] = $this->getAutoPostBack();
+ $options['ReadOnly'] = $this->getReadOnly();
+ $options['Style'] = $this->getRatingStyleCssClass();
+ $options['CaptionID'] = $this->getCaptionControlID();
+ $options['SelectedIndex'] = $this->getSelectedIndex();
+ $options['Rating'] = $this->getRating();
+ $options['HalfRating'] = $this->getHalfRatingInterval();
+ return $options;
+ }
+
+ /**
+ * @return string find the client ID of the caption control.
+ */
+ protected function getCaptionControlID()
+ {
+ if(($id=$this->getCaptionID())!=='')
+ {
+ if($control=$this->getParent()->findControl($id))
+ {
+ if($control->getVisible(true))
+ return $control->getClientID();
+ }
+ else
+ return $id;
+ }
+ return '';
+ }
+
+ /**
+ * Publish the the rating style css file and rating image files.
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->publishStyle($this->getRatingStyle());
+ $this->_ratingImages = $this->publishImages($this->getRatingStyle());
+ $this->registerClientScript();
+ }
+
+ /**
+ * @param string rating style name
+ * @return string URL of the css style file
+ */
+ protected function publishStyle($style)
+ {
+ $cs = $this->getPage()->getClientScript();
+ $url = $this->getAssetUrl($style.'.css');
+ if(!$cs->isStyleSheetFileRegistered($url))
+ $cs->registerStyleSheetFile($url, $url);
+ return $url;
+ }
+
+ /**
+ * @param string rating style name
+ * @param string rating image file extension, default is '.gif'
+ * @return array URL of publish the rating images
+ */
+ protected function publishImages($style, $fileExt='.gif')
+ {
+ $types = array('blank', 'selected', 'half', 'combined');
+ $files = array();
+ foreach($types as $type)
+ $files[$type] = $this->getAssetUrl("{$style}_{$type}{$fileExt}");
+ return $files;
+ }
+
+ /**
+ * Registers the relevant JavaScript.
+ */
+ protected function registerClientScript()
+ {
+ $cs=$this->getPage()->getClientScript();
+ $cs->registerPradoScript('ratings');
+ }
+
+ /**
+ * @param string asset file in the self::SCRIPT_PATH directory.
+ * @return string asset file url.
+ */
+ protected function getAssetUrl($file='')
+ {
+ $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
+ return $base.'/'.self::SCRIPT_PATH.'/'.$file;
+ }
+
+ /**
+ * Add rating style class name to the class attribute
+ * when {@link setReadOnly ReadOnly} property is true and when the
+ * {@link setCssClass CssClass} property is empty.
+ * @param THtmlWriter renderer
+ */
+ public function render($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $this->getPage()->getClientScript()->registerPostBackControl(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ parent::render($writer);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TRatingList';
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TReCaptcha.php b/lib/prado/framework/Web/UI/WebControls/TReCaptcha.php
new file mode 100644
index 0000000..89053d1
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TReCaptcha.php
@@ -0,0 +1,271 @@
+<?php
+
+/**
+ * TReCaptcha class file
+ *
+ * @author Bérczi Gábor <gabor.berczi@devworx.hu>
+ * @link http://www.devworx.hu/
+ * @copyright Copyright &copy; 2011 DevWorx
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+ Prado::using('System.3rdParty.ReCaptcha.recaptchalib');
+
+/**
+ * TReCaptcha class.
+ *
+ * TReCaptcha displays a reCAPTCHA (a token displayed as an image) that can be used
+ * to determine if the input is entered by a real user instead of some program. It can
+ * also prevent multiple submits of the same form either by accident, or on purpose (ie. spamming).
+ *
+ * The reCAPTCHA to solve (a string consisting of two separate words) displayed is automatically
+ * generated by the reCAPTCHA system at recaptcha.net. However, in order to use the services
+ * of the site you will need to register and get a public and a private API key pair, and
+ * supply those to the reCAPTCHA control through setting the {@link setPrivateKey PrivateKey}
+ * and {@link setPublicKey PublicKey} properties.
+ *
+ * Currently the reCAPTCHA API supports only one reCAPTCHA field per page, so you MUST make sure that all
+ * your input is protected and validated by a single reCAPTCHA control. Placing more than one reCAPTCHA
+ * control on the page will lead to unpredictable results, and the user will most likely unable to solve
+ * any of them successfully.
+ *
+ * Upon postback, user input can be validated by calling {@link validate()}.
+ * The {@link TReCaptchaValidator} control can also be used to do validation, which provides
+ * server-side validation. Calling (@link validate()) will invalidate the token supplied, so all consecutive
+ * calls to the method - without solving a new captcha - will return false. Therefore if implementing a multi-stage
+ * input process, you must make sure that you call validate() only once, either at the end of the input process, or
+ * you store the result till the end of the processing.
+ *
+ * The following template shows a typical use of TReCaptcha control:
+ * <code>
+ * <com:TReCaptcha ID="Captcha"
+ * PublicKey="..."
+ * PrivateKey="..."
+ * />
+ * <com:TReCaptchaValidator ControlToValidate="Captcha"
+ * ErrorMessage="You are challenged!" />
+ * </code>
+ *
+ * @author Bérczi Gábor <gabor.berczi@devworx.hu>
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+class TReCaptcha extends TWebControl implements IValidatable
+{
+ private $_isValid=true;
+
+ const ChallengeFieldName = 'recaptcha_challenge_field';
+ const ResponseFieldName = 'recaptcha_response_field';
+
+ public function getTagName()
+ {
+ return 'span';
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+ public function getValidationPropertyValue()
+ {
+ return $this->Request[$this->getChallengeFieldName()];
+ }
+
+ public function getPublicKey()
+ {
+ return $this->getViewState('PublicKey');
+ }
+
+ public function setPublicKey($value)
+ {
+ return $this->setViewState('PublicKey', TPropertyValue::ensureString($value));
+ }
+
+ public function getPrivateKey()
+ {
+ return $this->getViewState('PrivateKey');
+ }
+
+ public function setPrivateKey($value)
+ {
+ return $this->setViewState('PrivateKey', TPropertyValue::ensureString($value));
+ }
+
+ public function getThemeName()
+ {
+ return $this->getViewState('ThemeName');
+ }
+
+ public function setThemeName($value)
+ {
+ return $this->setViewState('ThemeName', TPropertyValue::ensureString($value));
+ }
+
+ public function getCustomTranslations()
+ {
+ return TPropertyValue::ensureArray($this->getViewState('CustomTranslations'));
+ }
+
+ public function setCustomTranslations($value)
+ {
+ return $this->setViewState('CustomTranslations', TPropertyValue::ensureArray($value));
+ }
+
+ public function getLanguage()
+ {
+ return $this->getViewState('Language');
+ }
+
+ public function setLanguage($value)
+ {
+ return $this->setViewState('Language', TPropertyValue::ensureString($value));
+ }
+
+ public function getCallbackScript()
+ {
+ return $this->getViewState('CallbackScript');
+ }
+
+ public function setCallbackScript($value)
+ {
+ return $this->setViewState('CallbackScript', TPropertyValue::ensureString($value));
+ }
+
+ protected function getChallengeFieldName()
+ {
+ return /*$this->ClientID.'_'.*/self::ChallengeFieldName;
+ }
+
+ public function getResponseFieldName()
+ {
+ return /*$this->ClientID.'_'.*/self::ResponseFieldName;
+ }
+
+ public function getClientSideOptions()
+ {
+ $options = array();
+ if ($theme = $this->getThemeName())
+ $options['theme'] = $theme;
+ if ($lang = $this->getLanguage())
+ $options['lang'] = $lang;
+ if ($trans = $this->getCustomTranslations())
+ $options['custom_translations'] = $trans;
+ return $options;
+ }
+
+ public function validate()
+ {
+ if (!
+ (
+ ($challenge = @$_POST[$this->getChallengeFieldName()])
+ and
+ ($response = @$_POST[$this->getResponseFieldName()])
+ )
+ )
+ return false;
+
+ $resp = recaptcha_check_answer(
+ $this->getPrivateKey(),
+ $_SERVER["REMOTE_ADDR"],
+ $challenge,
+ $response
+ );
+ return ($resp->is_valid==1);
+ }
+
+ /**
+ * Checks for API keys
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+
+ if("" == $this->getPublicKey())
+ throw new TConfigurationException('recaptcha_publickey_unknown');
+ if("" == $this->getPrivateKey())
+ throw new TConfigurationException('recaptcha_privatekey_unknown');
+
+ // need to register captcha fields so they will be sent back also in callbacks
+ $page = $this->getPage();
+ $page->registerRequiresPostData($this->getChallengeFieldName());
+ $page->registerRequiresPostData($this->getResponseFieldName());
+ }
+
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ }
+
+ public function regenerateToken()
+ {
+ // if we're in a callback, then schedule re-rendering of the control
+ // if not, don't do anything, because a new challenge will be rendered anyway
+ if ($this->Page->IsCallback)
+ $this->Page->CallbackClient->jQuery($this->getClientID().' #recaptcha_reload','click');
+ }
+
+ public function renderContents($writer)
+ {
+ $readyscript = 'jQuery(document).trigger('.TJavaScript::quoteString('captchaready:'.$this->getClientID()).')';
+ $cs = $this->Page->ClientScript;
+ $id = $this->getClientID();
+ $divid = $id.'_1_recaptchadiv';
+ $writer->write('<div id="'.htmlspecialchars($divid).'">');
+
+ if (!$this->Page->IsCallback)
+ {
+ $writer->write(TJavaScript::renderScriptBlock(
+ 'var RecaptchaOptions = '.TJavaScript::jsonEncode($this->getClientSideOptions()).';'
+ ));
+
+ $html = recaptcha_get_html($this->getPublicKey());
+ /*
+ reCAPTCHA currently does not support multiple validations per page
+ $html = str_replace(
+ array(self::ChallengeFieldName,self::ResponseFieldName),
+ array($this->getChallengeFieldName(),$this->getResponseFieldName()),
+ $html
+ );
+ */
+ $writer->write($html);
+
+ $cs->registerEndScript('ReCaptcha::EventScript', 'jQuery(document).ready(function() { '.$readyscript.'; } );');
+ }
+ else
+ {
+ $options = $this->getClientSideOptions();
+ $options['callback'] = new TJavaScriptLiteral('function() { '.$readyscript.'; '.$this->getCallbackScript().'; }');
+ $cs->registerScriptFile('ReCaptcha::AjaxScript', 'http://www.google.com/recaptcha/api/js/recaptcha_ajax.js');
+ $cs->registerEndScript('ReCaptcha::CreateScript::'.$id, implode(' ', array(
+ 'if (!jQuery('.TJavaScript::quoteString('#'.$this->getResponseFieldName()).'))',
+ '{',
+ 'Recaptcha.destroy();',
+ 'Recaptcha.create(',
+ TJavaScript::quoteString($this->getPublicKey()).', ',
+ TJavaScript::quoteString($divid).', ',
+ TJavaScript::encode($options),
+ ');',
+ '}',
+ )));
+ }
+
+ $writer->write('</div>');
+ }
+
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TReCaptchaValidator.php b/lib/prado/framework/Web/UI/WebControls/TReCaptchaValidator.php
new file mode 100644
index 0000000..de3b42a
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TReCaptchaValidator.php
@@ -0,0 +1,135 @@
+<?php
+
+/**
+ * TReCaptchaValidator class file
+ *
+ * @author Bérczi Gábor <gabor.berczi@devworx.hu>
+ * @link http://www.devworx.hu/
+ * @copyright Copyright &copy; 2011 DevWorx
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+Prado::using('System.Web.UI.WebControls.TReCaptcha');
+
+/**
+ * TReCaptchaValidator class
+ *
+ * TReCaptchaValidator validates user input against a reCAPTCHA represented by
+ * a {@link TReCaptcha} control. The input control fails validation if its value
+ * is not the same as the token displayed in reCAPTCHA. Note, if the user does
+ * not enter any thing, it is still considered as failing the validation.
+ *
+ * To use TReCaptchaValidator, specify the {@link setControlToValidate ControlToValidate}
+ * to be the ID path of the {@link TReCaptcha} control.
+ *
+ * @author Bérczi Gábor <gabor.berczi@devworx.hu>
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+class TReCaptchaValidator extends TBaseValidator
+{
+ protected $_isvalid = null;
+
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TReCaptchaValidator';
+ }
+
+ public function getEnableClientScript()
+ {
+ return true;
+ }
+
+ protected function getCaptchaControl()
+ {
+ $control = $this->getValidationTarget();
+ if (!$control)
+ throw new Exception('No target control specified for TReCaptchaValidator');
+ if (!($control instanceof TReCaptcha))
+ throw new Exception('TReCaptchaValidator only works with TReCaptcha controls');
+ return $control;
+ }
+
+ public function getClientScriptOptions()
+ {
+ $options = parent::getClientScriptOptions();
+ $options['ResponseFieldName'] = $this->getCaptchaControl()->getResponseFieldName();
+ return $options;
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input control has the same value
+ * as the one displayed in the corresponding RECAPTCHA control.
+ *
+ * @return boolean whether the validation succeeds
+ */
+ protected function evaluateIsValid()
+ {
+ // check validity only once (if trying to evaulate multiple times, all redundant checks would fail)
+ if (is_null($this->_isvalid))
+ {
+ $control = $this->getCaptchaControl();
+ $this->_isvalid = $control->validate();
+ }
+ return ($this->_isvalid==true);
+ }
+
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+
+ $cs = $this->Page->getClientScript();
+ $cs->registerPradoScript('validator');
+
+ // communicate validation status to the client side
+ $value = $this->_isvalid===false ? '0' : '1';
+ $cs->registerHiddenField($this->getClientID().'_1',$value);
+
+ // update validator display
+ if ($control = $this->getValidationTarget())
+ {
+ $fn = 'captchaUpdateValidatorStatus_'.$this->getClientID();
+
+ // check if we need to request a new captcha too
+ if ($this->Page->IsCallback)
+ {
+ if ($control->getVisible(true))
+ if (!is_null($this->_isvalid))
+ {
+ // if the response has been tested and we reach the pre-render phase
+ // then we need to regenerate the token, because it won't test positive
+ // anymore, even if solves correctly
+
+ $control->regenerateToken();
+ }
+ }
+
+ $cs->registerEndScript($this->getClientID().'::validate', implode(' ',array(
+ // this function will be used to update the validator
+ 'function '.$fn.'(valid)',
+ '{',
+ ' jQuery('.TJavaScript::quoteString('#'.$this->getClientID().'_1').').val(valid);',
+ ' Prado.Validation.validateControl('.TJavaScript::quoteString($control->ClientID).'); ',
+ '}',
+ '',
+ // update the validator to the result if we're in a callback
+ // (if we're in initial rendering or a postback then the result will be rendered directly to the page html anyway)
+ $this->Page->IsCallback ? $fn.'('.$value.');' : '',
+ '',
+ // install event handler that clears the validation error when user changes the captcha response field
+ 'jQuery("#'.$control->getClientID().'").on("keyup", '.TJavaScript::quoteString('#'.$control->getResponseFieldName()).', function() { ',
+ $fn.'("1");',
+ '});',
+ )));
+ }
+ }
+
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TRegularExpressionValidator.php b/lib/prado/framework/Web/UI/WebControls/TRegularExpressionValidator.php
new file mode 100644
index 0000000..1cdff8b
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TRegularExpressionValidator.php
@@ -0,0 +1,142 @@
+<?php
+/**
+ * TRequiredFieldValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TRegularExpressionValidator class
+ *
+ * TRegularExpressionValidator validates whether the value of an associated
+ * input component matches the pattern specified by a regular expression.
+ *
+ * You can specify the regular expression by setting the {@link setRegularExpression RegularExpression}
+ * property. Some commonly used regular expressions include:
+ * <pre>
+ * French Phone Number: (0( \d|\d ))?\d\d \d\d(\d \d| \d\d )\d\d
+ * French Postal Code: \d{5}
+ * German Phone Number: ((\(0\d\d\) |(\(0\d{3}\) )?\d )?\d\d \d\d \d\d|\(0\d{4}\) \d \d\d-\d\d?)
+ * German Postal Code: (D-)?\d{5}
+ * Email Address: \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
+ * Japanese Phone Number: (0\d{1,4}-|\(0\d{1,4}\) ?)?\d{1,4}-\d{4}
+ * Japanese Postal Code: \d{3}(-(\d{4}|\d{2}))?
+ * P.R.C. Phone Number: (\(\d{3}\)|\d{3}-)?\d{8}
+ * P.R.C. Postal Code: \d{6}
+ * P.R.C. Social Security Number: \d{18}|\d{15}
+ * U.S. Phone Number: ((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}
+ * U.S. ZIP Code: \d{5}(-\d{4})?
+ * U.S. Social Security Number: \d{3}-\d{2}-\d{4}
+ * </pre>
+ *
+ * Note, the validation succeeds if the associated input control contains empty input.
+ * Use a {@link TRequiredFieldValidator} to ensure the input is not empty.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRegularExpressionValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TRegularExpressionValidator';
+ }
+
+ /**
+ * @return string the regular expression that determines the pattern used to validate a field.
+ */
+ public function getRegularExpression()
+ {
+ return $this->getViewState('RegularExpression','');
+ }
+
+ /**
+ * @param string the regular expression that determines the pattern used to validate a field.
+ */
+ public function setRegularExpression($value)
+ {
+ $this->setViewState('RegularExpression',$value,'');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input data matches the regular expression.
+ * The validation always succeeds if ControlToValidate is not specified
+ * or the regular expression is empty, or the input data is empty.
+ * @return boolean whether the validation succeeds
+ */
+ public function evaluateIsValid()
+ {
+ if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
+ return true;
+ if(($expression=addcslashes($this->getRegularExpression(),"/"))!=='')
+ {
+ $mods = $this->getPatternModifiers();
+ return preg_match("/^$expression\$/{$mods}",$value);
+ }
+ else
+ return true;
+ }
+
+ /**
+ * @param string pattern modifiers for server side validation,
+ * see http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
+ */
+ public function setPatternModifiers($value)
+ {
+ $this->setViewState('PatternModifiers', $value);
+ }
+
+ /**
+ * @return string pattern modifiers, no modifiers by default.
+ */
+ public function getPatternModifiers()
+ {
+ return $this->getViewState('PatternModifiers', '');
+ }
+
+ /**
+ * @param string pattern modifiers for clientside.
+ * (Only 'g','i' and 'm' are available.)
+ */
+ public function setClientSidePatternModifiers($value)
+ {
+ $this->setViewState('ClientSidePatternModifiers', $value);
+ }
+
+ /**
+ * @return string clientside pattern modifiers, no modifiers by default.
+ */
+ public function getClientSidePatternModifiers()
+ {
+ return $this->getViewState('ClientSidePatternModifiers', '');
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options = parent::getClientScriptOptions();
+ $options['ValidationExpression']=$this->getRegularExpression();
+ $options['PatternModifiers']=$this->getClientSidePatternModifiers();
+ return $options;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TRepeatInfo.php b/lib/prado/framework/Web/UI/WebControls/TRepeatInfo.php
new file mode 100644
index 0000000..f5823d7
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TRepeatInfo.php
@@ -0,0 +1,555 @@
+<?php
+/**
+ * IRepeatInfoUser, TRepeatInfo class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TTable');
+
+/**
+ * IRepeatInfoUser interface.
+ * This interface must be implemented by classes who want to use {@link TRepeatInfo}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+interface IRepeatInfoUser
+{
+ /**
+ * @return boolean whether the repeat user contains footer
+ */
+ public function getHasFooter();
+ /**
+ * @return boolean whether the repeat user contains header
+ */
+ public function getHasHeader();
+ /**
+ * @return boolean whether the repeat user contains separators
+ */
+ public function getHasSeparators();
+ /**
+ * @return integer number of items to be rendered (excluding header, footer and separators)
+ */
+ public function getItemCount();
+ /**
+ * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
+ * @param integer zero-based index of the current rendering item.
+ * @return TStyle CSS style used for rendering items (including header, footer and separators)
+ */
+ public function generateItemStyle($itemType,$index);
+ /**
+ * Renders an item.
+ * @param THtmlWriter writer for the rendering purpose
+ * @param TRepeatInfo repeat information
+ * @param string item type
+ * @param integer zero-based index of the item being rendered
+ */
+ public function renderItem($writer,$repeatInfo,$itemType,$index);
+}
+
+/**
+ * TRepeatInfo class.
+ * TRepeatInfo represents repeat information for controls like {@link TCheckBoxList}.
+ * The layout of the repeated items is specified via {@link setRepeatLayout RepeatLayout},
+ * which can be either Table (default), Flow or Raw.
+ * A table layout uses HTML table cells to organize the items while
+ * a flow layout uses line breaks to organize the items.
+ * The number of columns used to display the items is specified via
+ * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
+ * governs the order of the items being rendered.
+ *
+ * Note, the Raw layout does not contain any formatting tags and thus ignores
+ * the column and repeat direction settings.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRepeatInfo extends TComponent
+{
+ /**
+ * @var string caption of the table used to organize the repeated items
+ */
+ private $_caption='';
+ /**
+ * @var TTableCaptionAlign alignment of the caption of the table used to organize the repeated items
+ */
+ private $_captionAlign=TTableCaptionAlign::NotSet;
+ /**
+ * @var integer number of columns that the items should be arranged in
+ */
+ private $_repeatColumns=0;
+ /**
+ * @var TRepeatDirection direction of the repetition
+ */
+ private $_repeatDirection=TRepeatDirection::Vertical;
+ /**
+ * @var TRepeatLayout layout of the repeated items
+ */
+ private $_repeatLayout=TRepeatLayout::Table;
+
+ /**
+ * @return string caption of the table layout
+ */
+ public function getCaption()
+ {
+ return $this->_caption;
+ }
+
+ /**
+ * @param string caption of the table layout
+ */
+ public function setCaption($value)
+ {
+ $this->_caption=$value;
+ }
+
+ /**
+ * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet.
+ */
+ public function getCaptionAlign()
+ {
+ return $this->_captionAlign;
+ }
+
+ /**
+ * @return TTableCaptionAlign alignment of the caption of the table layout.
+ */
+ public function setCaptionAlign($value)
+ {
+ $this->_captionAlign=TPropertyValue::ensureEnum($value,'TTableCaptionAlign');
+ }
+
+ /**
+ * @return integer the number of columns that the repeated items should be displayed in. Defaults to 0, meaning not set.
+ */
+ public function getRepeatColumns()
+ {
+ return $this->_repeatColumns;
+ }
+
+ /**
+ * @param integer the number of columns that the repeated items should be displayed in.
+ */
+ public function setRepeatColumns($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('repeatinfo_repeatcolumns_invalid');
+ $this->_repeatColumns=$value;
+ }
+
+ /**
+ * @return TRepeatDirection the direction of traversing the repeated items, defaults to TRepeatDirection::Vertical
+ */
+ public function getRepeatDirection()
+ {
+ return $this->_repeatDirection;
+ }
+
+ /**
+ * @param TRepeatDirection the direction of traversing the repeated items
+ */
+ public function setRepeatDirection($value)
+ {
+ $this->_repeatDirection=TPropertyValue::ensureEnum($value,'TRepeatDirection');
+ }
+
+ /**
+ * @return TRepeatLayout how the repeated items should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table.
+ */
+ public function getRepeatLayout()
+ {
+ return $this->_repeatLayout;
+ }
+
+ /**
+ * @param TRepeatLayout how the repeated items should be displayed, using table or using line breaks.
+ */
+ public function setRepeatLayout($value)
+ {
+ $this->_repeatLayout=TPropertyValue::ensureEnum($value,'TRepeatLayout');
+ }
+
+ /**
+ * Renders the repeated items.
+ * @param THtmlWriter writer for the rendering purpose
+ * @param IRepeatInfoUser repeat information user
+ */
+ public function renderRepeater($writer, IRepeatInfoUser $user)
+ {
+ if($this->_repeatLayout===TRepeatLayout::Table)
+ {
+ $control=new TTable;
+ if($this->_caption!=='')
+ {
+ $control->setCaption($this->_caption);
+ $control->setCaptionAlign($this->_captionAlign);
+ }
+ }
+ else if($this->_repeatLayout===TRepeatLayout::Raw)
+ {
+ $this->renderRawContents($writer,$user);
+ return;
+ }
+ else
+ $control=new TWebControl;
+ $control->setID($user->getClientID());
+ $control->copyBaseAttributes($user);
+ if($user->getHasStyle())
+ $control->getStyle()->copyFrom($user->getStyle());
+ $control->renderBeginTag($writer);
+ $writer->writeLine();
+
+ if($this->_repeatDirection===TRepeatDirection::Vertical)
+ $this->renderVerticalContents($writer,$user);
+ else
+ $this->renderHorizontalContents($writer,$user);
+
+ $control->renderEndTag($writer);
+ }
+
+ /**
+ * Renders contents in raw format.
+ * @param THtmlWriter writer for the rendering purpose
+ * @param IRepeatInfoUser repeat information user
+ */
+ protected function renderRawContents($writer,$user)
+ {
+ if($user->getHasHeader())
+ $user->renderItem($writer,$this,'Header',-1);
+
+ // render items
+ $hasSeparators=$user->getHasSeparators();
+ $itemCount=$user->getItemCount();
+ for($i=0;$i<$itemCount;++$i)
+ {
+ $user->renderItem($writer,$this,'Item',$i);
+ if($hasSeparators && $i!=$itemCount-1)
+ $user->renderItem($writer,$this,'Separator',$i);
+ }
+ if($user->getHasFooter())
+ $user->renderItem($writer,$this,'Footer',-1);
+ }
+
+ /**
+ * Renders contents in horizontal repeat direction.
+ * @param THtmlWriter writer for the rendering purpose
+ * @param IRepeatInfoUser repeat information user
+ */
+ protected function renderHorizontalContents($writer,$user)
+ {
+ $tableLayout=($this->_repeatLayout===TRepeatLayout::Table);
+ $hasSeparators=$user->getHasSeparators();
+ $itemCount=$user->getItemCount();
+ $columns=$this->_repeatColumns===0?$itemCount:$this->_repeatColumns;
+ $totalColumns=$hasSeparators?$columns+$columns:$columns;
+ $needBreak=$columns<$itemCount;
+
+ if($user->getHasHeader())
+ $this->renderHeader($writer,$user,$tableLayout,$totalColumns,$needBreak);
+
+ // render items
+ if($tableLayout)
+ {
+ $writer->renderBeginTag('tbody');
+ $column=0;
+ for($i=0;$i<$itemCount;++$i)
+ {
+ if($column==0)
+ $writer->renderBeginTag('tr');
+ if(($style=$user->generateItemStyle('Item',$i))!==null)
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('td');
+ $user->renderItem($writer,$this,'Item',$i);
+ $writer->renderEndTag();
+ $writer->writeLine();
+ if($hasSeparators && $i!=$itemCount-1)
+ {
+ if(($style=$user->generateItemStyle('Separator',$i))!==null)
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('td');
+ $user->renderItem($writer,$this,'Separator',$i);
+ $writer->renderEndTag();
+ $writer->writeLine();
+ }
+ $column++;
+ if($i==$itemCount-1)
+ {
+ $restColumns=$columns-$column;
+ if($hasSeparators)
+ $restColumns=$restColumns?$restColumns+$restColumns+1:1;
+ for($j=0;$j<$restColumns;++$j)
+ $writer->write("<td></td>\n");
+ }
+ if($column==$columns || $i==$itemCount-1)
+ {
+ $writer->renderEndTag();
+ $writer->writeLine();
+ $column=0;
+ }
+ }
+ $writer->renderEndTag();
+ }
+ else
+ {
+ $column=0;
+ for($i=0;$i<$itemCount;++$i)
+ {
+ $user->renderItem($writer,$this,'Item',$i);
+ if($hasSeparators && $i!=$itemCount-1)
+ $user->renderItem($writer,$this,'Separator',$i);
+ $column++;
+ if($column==$columns || $i==$itemCount-1)
+ {
+ if($needBreak)
+ $writer->writeBreak();
+ $column=0;
+ }
+ $writer->writeLine();
+ }
+ }
+
+ if($user->getHasFooter())
+ $this->renderFooter($writer,$user,$tableLayout,$totalColumns,$needBreak);
+ }
+
+ /**
+ * Renders contents in veritcal repeat direction.
+ * @param THtmlWriter writer for the rendering purpose
+ * @param IRepeatInfoUser repeat information user
+ */
+ protected function renderVerticalContents($writer,$user)
+ {
+ $tableLayout=($this->_repeatLayout===TRepeatLayout::Table);
+ $hasSeparators=$user->getHasSeparators();
+ $itemCount=$user->getItemCount();
+ if($this->_repeatColumns<=1)
+ {
+ $rows=$itemCount;
+ $columns=1;
+ $lastColumns=1;
+ }
+ else
+ {
+ $columns=$this->_repeatColumns;
+ $rows=(int)(($itemCount+$columns-1)/$columns);
+ if($rows==0 && $itemCount>0)
+ $rows=1;
+ if(($lastColumns=$itemCount%$columns)==0)
+ $lastColumns=$columns;
+ }
+ $totalColumns=$hasSeparators?$columns+$columns:$columns;
+
+ if($user->getHasHeader())
+ $this->renderHeader($writer,$user,$tableLayout,$totalColumns,false);
+
+ if($tableLayout)
+ {
+ $writer->renderBeginTag('tbody');
+ $renderedItems=0;
+ for($row=0;$row<$rows;++$row)
+ {
+ $index=$row;
+ $writer->renderBeginTag('tr');
+ for($col=0;$col<$columns;++$col)
+ {
+ if($renderedItems>=$itemCount)
+ break;
+ if($col>0)
+ {
+ $index+=$rows;
+ if($col-1>=$lastColumns)
+ $index--;
+ }
+ if($index>=$itemCount)
+ continue;
+ $renderedItems++;
+ if(($style=$user->generateItemStyle('Item',$index))!==null)
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('td');
+ $user->renderItem($writer,$this,'Item',$index);
+ $writer->renderEndTag();
+ $writer->writeLine();
+ if(!$hasSeparators)
+ continue;
+ if($renderedItems<$itemCount-1)
+ {
+ if($columns==1)
+ {
+ $writer->renderEndTag();
+ $writer->renderBeginTag('tr');
+ }
+ if(($style=$user->generateItemStyle('Separator',$index))!==null)
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('td');
+ $user->renderItem($writer,$this,'Separator',$index);
+ $writer->renderEndTag();
+ $writer->writeLine();
+ }
+ else if($columns>1)
+ $writer->write("<td></td>\n");
+ }
+ if($row==$rows-1)
+ {
+ $restColumns=$columns-$lastColumns;
+ if($hasSeparators)
+ $restColumns+=$restColumns;
+ for($col=0;$col<$restColumns;++$col)
+ $writer->write("<td></td>\n");
+ }
+ $writer->renderEndTag();
+ $writer->writeLine();
+ }
+ $writer->renderEndTag();
+ }
+ else
+ {
+ $renderedItems=0;
+ for($row=0;$row<$rows;++$row)
+ {
+ $index=$row;
+ for($col=0;$col<$columns;++$col)
+ {
+ if($renderedItems>=$itemCount)
+ break;
+ if($col>0)
+ {
+ $index+=$rows;
+ if($col-1>=$lastColumns)
+ $index--;
+ }
+ if($index>=$itemCount)
+ continue;
+ $renderedItems++;
+ $user->renderItem($writer,$this,'Item',$index);
+ $writer->writeLine();
+ if(!$hasSeparators)
+ continue;
+ if($renderedItems<$itemCount-1)
+ {
+ if($columns==1)
+ $writer->writeBreak();
+ $user->renderItem($writer,$this,'Separator',$index);
+ }
+ $writer->writeLine();
+ }
+ if($row<$rows-1 || $user->getHasFooter())
+ $writer->writeBreak();
+ }
+ }
+
+ if($user->getHasFooter())
+ $this->renderFooter($writer,$user,$tableLayout,$totalColumns,false);
+
+ }
+
+ /**
+ * Renders header.
+ * @param THtmlWriter writer for the rendering purpose
+ * @param IRepeatInfoUser repeat information user
+ * @param boolean whether to render using table layout
+ * @param integer number of columns to be rendered
+ * @param boolean if a line break is needed at the end
+ */
+ protected function renderHeader($writer,$user,$tableLayout,$columns,$needBreak)
+ {
+ if($tableLayout)
+ {
+ $writer->renderBeginTag('thead');
+ $writer->renderBeginTag('tr');
+ if($columns>1)
+ $writer->addAttribute('colspan',"$columns");
+ $writer->addAttribute('scope','col');
+ if(($style=$user->generateItemStyle('Header',-1))!==null)
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('th');
+ $user->renderItem($writer,$this,'Header',-1);
+ $writer->renderEndTag();
+ $writer->renderEndTag();
+ $writer->renderEndTag();
+ }
+ else
+ {
+ $user->renderItem($writer,$this,'Header',-1);
+ if($needBreak)
+ $writer->writeBreak();
+ }
+ $writer->writeLine();
+ }
+
+ /**
+ * Renders footer.
+ * @param THtmlWriter writer for the rendering purpose
+ * @param IRepeatInfoUser repeat information user
+ * @param boolean whether to render using table layout
+ * @param integer number of columns to be rendered
+ */
+ protected function renderFooter($writer,$user,$tableLayout,$columns)
+ {
+ if($tableLayout)
+ {
+ $writer->renderBeginTag('tfoot');
+ $writer->renderBeginTag('tr');
+ if($columns>1)
+ $writer->addAttribute('colspan',"$columns");
+ if(($style=$user->generateItemStyle('Footer',-1))!==null)
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('td');
+ $user->renderItem($writer,$this,'Footer',-1);
+ $writer->renderEndTag();
+ $writer->renderEndTag();
+ $writer->renderEndTag();
+ }
+ else
+ $user->renderItem($writer,$this,'Footer',-1);
+ $writer->writeLine();
+ }
+}
+
+
+/**
+ * TRepeatDirection class.
+ * TRepeatDirection defines the enumerable type for the possible directions
+ * that repeated contents can repeat along
+ *
+ * The following enumerable values are defined:
+ * - Vertical
+ * - Horizontal
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TRepeatDirection extends TEnumerable
+{
+ const Vertical='Vertical';
+ const Horizontal='Horizontal';
+}
+
+/**
+ * TRepeatLayout class.
+ * TRepeatLayout defines the enumerable type for the possible layouts
+ * that repeated contents can take.
+ *
+ * The following enumerable values are defined:
+ * - Table: the repeated contents are organized using an HTML table
+ * - Flow: the repeated contents are organized using HTML spans and breaks
+ * - Raw: the repeated contents are stacked together without any additional decorations
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TRepeatLayout extends TEnumerable
+{
+ const Table='Table';
+ const Flow='Flow';
+ const Raw='Raw';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TRepeater.php b/lib/prado/framework/Web/UI/WebControls/TRepeater.php
new file mode 100644
index 0000000..3d295a2
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TRepeater.php
@@ -0,0 +1,1019 @@
+<?php
+/**
+ * TRepeater class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TDataBoundControl and TDataFieldAccessor cass
+ */
+Prado::using('System.Web.UI.WebControls.TDataBoundControl');
+Prado::using('System.Util.TDataFieldAccessor');
+
+/**
+ * TRepeater class.
+ *
+ * TRepeater displays its content repeatedly based on the data fetched from
+ * {@link setDataSource DataSource}.
+ * The repeated contents in TRepeater are called items, which are controls and
+ * can be accessed through {@link getItems Items}. When {@link dataBind()} is invoked,
+ * TRepeater creates an item for each row of data and binds the data row to the item.
+ * Optionally, a repeater can have a header, a footer and/or separators between items.
+ *
+ * The layout of the repeated contents are specified by inline templates.
+ * Repeater items, header, footer, etc. are being instantiated with the corresponding
+ * templates when data is being bound to the repeater.
+ *
+ * Since v3.1.0, the layout can also be specified by renderers. A renderer is a control class
+ * that can be instantiated as repeater items, header, etc. A renderer can thus be viewed
+ * as an external template (in fact, it can also be non-templated controls).
+ *
+ * A renderer can be any control class.
+ * - If the class implements {@link IDataRenderer}, the <b>Data</b>
+ * property will be set as the data row during databinding. Many PRADO controls
+ * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc.
+ * - If the class implements {@link IItemDataRenderer}, the <b>ItemIndex</b> property will be set
+ * as the zero-based index of the item in the repeater item collection, and
+ * the <b>ItemType</b> property as the item's type (such as TListItemType::Item).
+ * {@link TRepeaterItemRenderer} may be used as the convenient base class which
+ * already implements {@link IDataItemRenderer}.
+ *
+ * The following properties are used to specify different types of template and renderer
+ * for a repeater:
+ * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}:
+ * for each repeated row of data
+ * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}:
+ * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer}
+ * will be used instead.
+ * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}:
+ * for the repeater header.
+ * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}:
+ * for the repeater footer.
+ * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}:
+ * for content to be displayed between items.
+ * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}:
+ * used when data bound to the repeater is empty.
+ *
+ * If a content type is defined with both a template and a renderer, the latter takes precedence.
+ *
+ * When {@link dataBind()} is being called, TRepeater undergoes the following lifecycles for each row of data:
+ * - create item based on templates or renderers
+ * - set the row of data to the item
+ * - raise {@link onItemCreated OnItemCreated}:
+ * - add the item as a child control
+ * - call dataBind() of the item
+ * - raise {@link onItemDataBound OnItemDataBound}:
+ *
+ * TRepeater raises an {@link onItemCommand OnItemCommand} whenever a button control
+ * within some repeater item raises a <b>OnCommand</b> event. Therefore,
+ * you can handle all sorts of <b>OnCommand</b> event in a central place by
+ * writing an event handler for {@link onItemCommand OnItemCommand}.
+ *
+ * When a page containing a repeater is post back, the repeater will restore automatically
+ * all its contents, including items, header, footer and separators.
+ * However, the data row associated with each item will not be recovered and become null.
+ * To access the data, use one of the following ways:
+ * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
+ * the specified repeater item and use the key to fetch the corresponding data
+ * from some persistent storage such as DB.
+ * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback.
+ * Be aware though, if the size of your dataset is big, your page size will become big. Some
+ * complex data may also have serializing problem if saved in viewstate.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRepeater extends TDataBoundControl implements INamingContainer
+{
+ /**
+ * Repeater item types
+ * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead.
+ */
+ const IT_HEADER='Header';
+ const IT_FOOTER='Footer';
+ const IT_ITEM='Item';
+ const IT_SEPARATOR='Separator';
+ const IT_ALTERNATINGITEM='AlternatingItem';
+
+ /**
+ * @var ITemplate template for repeater items
+ */
+ private $_itemTemplate=null;
+ /**
+ * @var ITemplate template for each alternating item
+ */
+ private $_alternatingItemTemplate=null;
+ /**
+ * @var ITemplate template for header
+ */
+ private $_headerTemplate=null;
+ /**
+ * @var ITemplate template for footer
+ */
+ private $_footerTemplate=null;
+ /**
+ * @var ITemplate template used for repeater when no data is bound
+ */
+ private $_emptyTemplate=null;
+ /**
+ * @var ITemplate template for separator
+ */
+ private $_separatorTemplate=null;
+ /**
+ * @var TRepeaterItemCollection list of repeater items
+ */
+ private $_items=null;
+ /**
+ * @var TControl header item
+ */
+ private $_header=null;
+ /**
+ * @var TControl footer item
+ */
+ private $_footer=null;
+
+
+ /**
+ * @return string the class name for repeater items. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getItemRenderer()
+ {
+ return $this->getViewState('ItemRenderer','');
+ }
+
+ /**
+ * Sets the item renderer class.
+ *
+ * If not empty, the class will be used to instantiate as repeater items.
+ * This property takes precedence over {@link getItemTemplate ItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setItemTemplate
+ * @since 3.1.0
+ */
+ public function setItemRenderer($value)
+ {
+ $this->setViewState('ItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for alternative repeater items. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getAlternatingItemRenderer()
+ {
+ return $this->getViewState('AlternatingItemRenderer','');
+ }
+
+ /**
+ * Sets the alternative item renderer class.
+ *
+ * If not empty, the class will be used to instantiate as alternative repeater items.
+ * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setAlternatingItemTemplate
+ * @since 3.1.0
+ */
+ public function setAlternatingItemRenderer($value)
+ {
+ $this->setViewState('AlternatingItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for repeater item separators. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getSeparatorRenderer()
+ {
+ return $this->getViewState('SeparatorRenderer','');
+ }
+
+ /**
+ * Sets the repeater item separator renderer class.
+ *
+ * If not empty, the class will be used to instantiate as repeater item separators.
+ * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setSeparatorTemplate
+ * @since 3.1.0
+ */
+ public function setSeparatorRenderer($value)
+ {
+ $this->setViewState('SeparatorRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for repeater header item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getHeaderRenderer()
+ {
+ return $this->getViewState('HeaderRenderer','');
+ }
+
+ /**
+ * Sets the repeater header renderer class.
+ *
+ * If not empty, the class will be used to instantiate as repeater header item.
+ * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setHeaderTemplate
+ * @since 3.1.0
+ */
+ public function setHeaderRenderer($value)
+ {
+ $this->setViewState('HeaderRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for repeater footer item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getFooterRenderer()
+ {
+ return $this->getViewState('FooterRenderer','');
+ }
+
+ /**
+ * Sets the repeater footer renderer class.
+ *
+ * If not empty, the class will be used to instantiate as repeater footer item.
+ * This property takes precedence over {@link getFooterTemplate FooterTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setFooterTemplate
+ * @since 3.1.0
+ */
+ public function setFooterRenderer($value)
+ {
+ $this->setViewState('FooterRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for empty repeater item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getEmptyRenderer()
+ {
+ return $this->getViewState('EmptyRenderer','');
+ }
+
+ /**
+ * Sets the repeater empty renderer class.
+ *
+ * The empty renderer is created as the child of the repeater
+ * if data bound to the repeater is empty.
+ * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setEmptyTemplate
+ * @since 3.1.0
+ */
+ public function setEmptyRenderer($value)
+ {
+ $this->setViewState('EmptyRenderer',$value,'');
+ }
+
+ /**
+ * @return ITemplate the template for repeater items
+ */
+ public function getItemTemplate()
+ {
+ return $this->_itemTemplate;
+ }
+
+ /**
+ * @param ITemplate the template for repeater items
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_itemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('repeater_template_required','ItemTemplate');
+ }
+
+ /**
+ * @return ITemplate the alternative template string for the item
+ */
+ public function getAlternatingItemTemplate()
+ {
+ return $this->_alternatingItemTemplate;
+ }
+
+ /**
+ * @param ITemplate the alternative item template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setAlternatingItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_alternatingItemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('repeater_template_required','AlternatingItemTemplate');
+ }
+
+ /**
+ * @return ITemplate the header template
+ */
+ public function getHeaderTemplate()
+ {
+ return $this->_headerTemplate;
+ }
+
+ /**
+ * @param ITemplate the header template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setHeaderTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_headerTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('repeater_template_required','HeaderTemplate');
+ }
+
+ /**
+ * @return ITemplate the footer template
+ */
+ public function getFooterTemplate()
+ {
+ return $this->_footerTemplate;
+ }
+
+ /**
+ * @param ITemplate the footer template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setFooterTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_footerTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('repeater_template_required','FooterTemplate');
+ }
+
+ /**
+ * @return ITemplate the template applied when no data is bound to the repeater
+ */
+ public function getEmptyTemplate()
+ {
+ return $this->_emptyTemplate;
+ }
+
+ /**
+ * @param ITemplate the template applied when no data is bound to the repeater
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setEmptyTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_emptyTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('repeater_template_required','EmptyTemplate');
+ }
+
+ /**
+ * @return ITemplate the separator template
+ */
+ public function getSeparatorTemplate()
+ {
+ return $this->_separatorTemplate;
+ }
+
+ /**
+ * @param ITemplate the separator template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setSeparatorTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_separatorTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('repeater_template_required','SeparatorTemplate');
+ }
+
+ /**
+ * @return TControl the header item
+ */
+ public function getHeader()
+ {
+ return $this->_header;
+ }
+
+ /**
+ * @return TControl the footer item
+ */
+ public function getFooter()
+ {
+ return $this->_footer;
+ }
+
+ /**
+ * @return TRepeaterItemCollection list of repeater item controls
+ */
+ public function getItems()
+ {
+ if(!$this->_items)
+ $this->_items=new TRepeaterItemCollection;
+ return $this->_items;
+ }
+
+ /**
+ * @return string the field of the data source that provides the keys of the list items.
+ */
+ public function getDataKeyField()
+ {
+ return $this->getViewState('DataKeyField','');
+ }
+
+ /**
+ * @param string the field of the data source that provides the keys of the list items.
+ */
+ public function setDataKeyField($value)
+ {
+ $this->setViewState('DataKeyField',$value,'');
+ }
+
+ /**
+ * @return TList the keys used in the data listing control.
+ */
+ public function getDataKeys()
+ {
+ if(($dataKeys=$this->getViewState('DataKeys',null))===null)
+ {
+ $dataKeys=new TList;
+ $this->setViewState('DataKeys',$dataKeys,null);
+ }
+ return $dataKeys;
+ }
+
+ /**
+ * Creates a repeater item.
+ * This method invokes {@link createItem} to create a new repeater item.
+ * @param integer zero-based item index.
+ * @param TListItemType item type
+ * @return TControl the created item, null if item is not created
+ */
+ private function createItemInternal($itemIndex,$itemType)
+ {
+ if(($item=$this->createItem($itemIndex,$itemType))!==null)
+ {
+ $param=new TRepeaterItemEventParameter($item);
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ return $item;
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Creates a repeater item and performs databinding.
+ * This method invokes {@link createItem} to create a new repeater item.
+ * @param integer zero-based item index.
+ * @param TListItemType item type
+ * @param mixed data to be associated with the item
+ * @return TControl the created item, null if item is not created
+ */
+ private function createItemWithDataInternal($itemIndex,$itemType,$dataItem)
+ {
+ if(($item=$this->createItem($itemIndex,$itemType))!==null)
+ {
+ $param=new TRepeaterItemEventParameter($item);
+ if($item instanceof IDataRenderer)
+ $item->setData($dataItem);
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ $item->dataBind();
+ $this->onItemDataBound($param);
+ return $item;
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Creates a repeater item instance based on the item type and index.
+ * @param integer zero-based item index
+ * @param TListItemType item type
+ * @return TControl created repeater item
+ */
+ protected function createItem($itemIndex,$itemType)
+ {
+ $template=null;
+ $classPath=null;
+ switch($itemType)
+ {
+ case TListItemType::Item :
+ $classPath=$this->getItemRenderer();
+ $template=$this->_itemTemplate;
+ break;
+ case TListItemType::AlternatingItem :
+ if(($classPath=$this->getAlternatingItemRenderer())==='' && ($template=$this->_alternatingItemTemplate)===null)
+ {
+ $classPath=$this->getItemRenderer();
+ $template=$this->_itemTemplate;
+ }
+ break;
+ case TListItemType::Header :
+ $classPath=$this->getHeaderRenderer();
+ $template=$this->_headerTemplate;
+ break;
+ case TListItemType::Footer :
+ $classPath=$this->getFooterRenderer();
+ $template=$this->_footerTemplate;
+ break;
+ case TListItemType::Separator :
+ $classPath=$this->getSeparatorRenderer();
+ $template=$this->_separatorTemplate;
+ break;
+ default:
+ throw new TInvalidDataValueException('repeater_itemtype_unknown',$itemType);
+ }
+ if($classPath!=='')
+ {
+ $item=Prado::createComponent($classPath);
+ if($item instanceof IItemDataRenderer)
+ {
+ $item->setItemIndex($itemIndex);
+ $item->setItemType($itemType);
+ }
+ }
+ else if($template!==null)
+ {
+ $item=new TRepeaterItem;
+ $item->setItemIndex($itemIndex);
+ $item->setItemType($itemType);
+ $template->instantiateIn($item);
+ }
+ else
+ $item=null;
+
+ return $item;
+ }
+
+ /**
+ * Creates empty repeater content.
+ */
+ protected function createEmptyContent()
+ {
+ if(($classPath=$this->getEmptyRenderer())!=='')
+ $this->getControls()->add(Prado::createComponent($classPath));
+ else if($this->_emptyTemplate!==null)
+ $this->_emptyTemplate->instantiateIn($this);
+ }
+
+ /**
+ * Renders the repeater.
+ * This method overrides the parent implementation by rendering the body
+ * content as the whole presentation of the repeater. Outer tag is not rendered.
+ * @param THtmlWriter writer
+ */
+ public function render($writer)
+ {
+ if($this->_items && $this->_items->getCount() || $this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='')
+ $this->renderContents($writer);
+ }
+
+ /**
+ * Saves item count in viewstate.
+ * This method is invoked right before control state is to be saved.
+ */
+ public function saveState()
+ {
+ parent::saveState();
+ if($this->_items)
+ $this->setViewState('ItemCount',$this->_items->getCount(),0);
+ else
+ $this->clearViewState('ItemCount');
+ }
+
+ /**
+ * Loads item count information from viewstate.
+ * This method is invoked right after control state is loaded.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ if(!$this->getIsDataBound())
+ $this->restoreItemsFromViewState();
+ $this->clearViewState('ItemCount');
+ }
+
+ /**
+ * Clears up all items in the repeater.
+ */
+ public function reset()
+ {
+ $this->getControls()->clear();
+ $this->getItems()->clear();
+ $this->_header=null;
+ $this->_footer=null;
+ }
+
+ /**
+ * Creates repeater items based on viewstate information.
+ */
+ protected function restoreItemsFromViewState()
+ {
+ $this->reset();
+ if(($itemCount=$this->getViewState('ItemCount',0))>0)
+ {
+ $items=$this->getItems();
+ $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
+ $this->_header=$this->createItemInternal(-1,TListItemType::Header);
+ for($i=0;$i<$itemCount;++$i)
+ {
+ if($hasSeparator && $i>0)
+ $this->createItemInternal($i-1,TListItemType::Separator);
+ $itemType=$i%2==0?TListItemType::Item : TListItemType::AlternatingItem;
+ $items->add($this->createItemInternal($i,$itemType,false,null));
+ }
+ $this->_footer=$this->createItemInternal(-1,TListItemType::Footer);
+ }
+ else
+ $this->createEmptyContent();
+ $this->clearChildState();
+ }
+
+ /**
+ * Performs databinding to populate repeater items from data source.
+ * This method is invoked by dataBind().
+ * You may override this function to provide your own way of data population.
+ * @param Traversable the data
+ */
+ protected function performDataBinding($data)
+ {
+ $this->reset();
+
+ $keys=$this->getDataKeys();
+ $keys->clear();
+ $keyField=$this->getDataKeyField();
+
+ $items=$this->getItems();
+ $itemIndex=0;
+ $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
+ foreach($data as $key=>$dataItem)
+ {
+ if($keyField!=='')
+ $keys->add($this->getDataFieldValue($dataItem,$keyField));
+ else
+ $keys->add($key);
+ if($itemIndex===0)
+ $this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null);
+ if($hasSeparator && $itemIndex>0)
+ $this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null);
+ $itemType=$itemIndex%2==0?TListItemType::Item : TListItemType::AlternatingItem;
+ $items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem));
+ $itemIndex++;
+ }
+ if($itemIndex>0)
+ $this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null);
+ else
+ {
+ $this->createEmptyContent();
+ $this->dataBindChildren();
+ }
+ $this->setViewState('ItemCount',$itemIndex,0);
+ }
+
+ /**
+ * This method overrides parent's implementation to handle
+ * {@link onItemCommand OnItemCommand} event which is bubbled from
+ * repeater items and their child controls.
+ * This method should only be used by control developers.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TRepeaterCommandEventParameter)
+ {
+ $this->onItemCommand($param);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Raises <b>OnItemCreated</b> event.
+ * This method is invoked after a repeater item is created and instantiated with
+ * template, but before added to the page hierarchy.
+ * The repeater item control responsible for the event
+ * can be determined from the event parameter.
+ * If you override this method, be sure to call parent's implementation
+ * so that event handlers have chance to respond to the event.
+ * @param TRepeaterItemEventParameter event parameter
+ */
+ public function onItemCreated($param)
+ {
+ $this->raiseEvent('OnItemCreated',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnItemDataBound</b> event.
+ * This method is invoked right after an item is data bound.
+ * The repeater item control responsible for the event
+ * can be determined from the event parameter.
+ * If you override this method, be sure to call parent's implementation
+ * so that event handlers have chance to respond to the event.
+ * @param TRepeaterItemEventParameter event parameter
+ */
+ public function onItemDataBound($param)
+ {
+ $this->raiseEvent('OnItemDataBound',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnItemCommand</b> event.
+ * This method is invoked after a button control in
+ * a template raises <b>OnCommand</b> event.
+ * The repeater control responsible for the event
+ * can be determined from the event parameter.
+ * The event parameter also contains the information about
+ * the initial sender of the <b>OnCommand</b> event, command name
+ * and command parameter.
+ * You may override this method to provide customized event handling.
+ * Be sure to call parent's implementation so that
+ * event handlers have chance to respond to the event.
+ * @param TRepeaterCommandEventParameter event parameter
+ */
+ public function onItemCommand($param)
+ {
+ $this->raiseEvent('OnItemCommand',$this,$param);
+ }
+
+ /**
+ * Returns the value of the data at the specified field.
+ * If data is an array, TMap or TList, the value will be returned at the index
+ * of the specified field. If the data is a component with a property named
+ * as the field name, the property value will be returned.
+ * Otherwise, an exception will be raised.
+ * @param mixed data item
+ * @param mixed field name
+ * @return mixed data value at the specified field
+ * @throws TInvalidDataValueException if the data is invalid
+ */
+ protected function getDataFieldValue($data,$field)
+ {
+ return TDataFieldAccessor::getDataFieldValue($data,$field);
+ }
+}
+
+/**
+ * TRepeaterItemEventParameter class
+ *
+ * TRepeaterItemEventParameter encapsulates the parameter data for
+ * {@link TRepeater::onItemCreated ItemCreated} event of {@link TRepeater} controls.
+ * The {@link getItem Item} property indicates the repeater item related with the event.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRepeaterItemEventParameter extends TEventParameter
+{
+ /**
+ * The repeater item control responsible for the event.
+ * @var TControl
+ */
+ private $_item=null;
+
+ /**
+ * Constructor.
+ * @param TControl repeater item related with the corresponding event
+ */
+ public function __construct($item)
+ {
+ $this->_item=$item;
+ }
+
+ /**
+ * @return TControl repeater item related with the corresponding event
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+}
+
+/**
+ * TRepeaterCommandEventParameter class
+ *
+ * TRepeaterCommandEventParameter encapsulates the parameter data for
+ * {@link TRepeater::onItemCommand ItemCommand} event of {@link TRepeater} controls.
+ *
+ * The {@link getItem Item} property indicates the repeater item related with the event.
+ * The {@link getCommandSource CommandSource} refers to the control that originally
+ * raises the Command event.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRepeaterCommandEventParameter extends TCommandEventParameter
+{
+ /**
+ * @var TControl the repeater item control responsible for the event.
+ */
+ private $_item=null;
+ /**
+ * @var TControl the control originally raises the <b>OnCommand</b> event.
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TControl repeater item responsible for the event
+ * @param TControl original event sender
+ * @param TCommandEventParameter original event parameter
+ */
+ public function __construct($item,$source,TCommandEventParameter $param)
+ {
+ $this->_item=$item;
+ $this->_source=$source;
+ parent::__construct($param->getCommandName(),$param->getCommandParameter());
+ }
+
+ /**
+ * @return TControl the repeater item control responsible for the event.
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+
+ /**
+ * @return TControl the control originally raises the <b>OnCommand</b> event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+}
+
+/**
+ * TRepeaterItem class
+ *
+ * A TRepeaterItem control represents an item in the {@link TRepeater} control,
+ * such as heading section, footer section, or a data item.
+ * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
+ * and {@link getDataItem DataItem} properties, respectively. The type of the item
+ * is given by {@link getItemType ItemType} property.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRepeaterItem extends TControl implements INamingContainer, IItemDataRenderer
+{
+ /**
+ * index of the data item in the Items collection of repeater
+ */
+ private $_itemIndex;
+ /**
+ * type of the TRepeaterItem
+ * @var TListItemType
+ */
+ private $_itemType;
+ /**
+ * data associated with this item
+ * @var mixed
+ */
+ private $_data;
+
+ /**
+ * @return TListItemType item type
+ */
+ public function getItemType()
+ {
+ return $this->_itemType;
+ }
+
+ /**
+ * @param TListItemType item type.
+ */
+ public function setItemType($value)
+ {
+ $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
+ }
+
+ /**
+ * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection.
+ * If the item is not in the collection (e.g. it is a header item), it returns -1.
+ * @return integer zero-based index of the item.
+ */
+ public function getItemIndex()
+ {
+ return $this->_itemIndex;
+ }
+
+ /**
+ * Sets the zero-based index for the item.
+ * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
+ * @param integer zero-based index of the item.
+ */
+ public function setItemIndex($value)
+ {
+ $this->_itemIndex=TPropertyValue::ensureInteger($value);
+ }
+
+ /**
+ * @return mixed data associated with the item
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * @param mixed data to be associated with the item
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->_data=$value;
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @return mixed data associated with the item
+ * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
+ */
+ public function getDataItem()
+ {
+ return $this->getData();
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @param mixed data to be associated with the item
+ * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
+ */
+ public function setDataItem($value)
+ {
+ return $this->setData($value);
+ }
+
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for <b>OnCommand</b> event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TRepeaterCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+
+/**
+ * TRepeaterItemCollection class.
+ *
+ * TRepeaterItemCollection represents a collection of repeater items.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRepeaterItemCollection extends TList
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by inserting only objects that are descendant of {@link TControl}.
+ * @param integer the speicified position.
+ * @param TControl new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a control.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TControl)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('repeateritemcollection_item_invalid');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TRepeaterItemRenderer.php b/lib/prado/framework/Web/UI/WebControls/TRepeaterItemRenderer.php
new file mode 100644
index 0000000..1ea799c
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TRepeaterItemRenderer.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * TRepeaterItemRenderer class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TRepeater');
+Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
+
+/**
+ * TRepeaterItemRenderer class
+ *
+ * TRepeaterItemRenderer can be used as a convenient base class to
+ * define an item renderer class specific for {@link TRepeater}.
+ *
+ * TRepeaterItemRenderer extends {@link TItemDataRenderer} and implements
+ * the bubbling scheme for the OnCommand event of repeater items.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.0
+ */
+class TRepeaterItemRenderer extends TItemDataRenderer
+{
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for <b>OnCommand</b> event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TRepeaterCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TRequiredFieldValidator.php b/lib/prado/framework/Web/UI/WebControls/TRequiredFieldValidator.php
new file mode 100644
index 0000000..4587db8
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TRequiredFieldValidator.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * TRequiredFieldValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TRequiredFieldValidator class
+ *
+ * TRequiredFieldValidator makes the associated input control a required field.
+ * The input control fails validation if its value does not change from
+ * the {@link setInitialValue InitialValue} property upon losing focus.
+ *
+ * Validation will also succeed if input is of TListControl type and the number
+ * of selected values different from the initial value is greater than zero.
+ *
+ * If the input is of TListControl type and has a {@link TListControl::setPromptValue PromptValue}
+ * set, it will be automatically considered as the validator's {@link setInitialValue InitialValue}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRequiredFieldValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TRequiredFieldValidator';
+ }
+
+ /**
+ * @return string the initial value of the associated input control. Defaults to empty string
+ * unless the control has a prompt value set.
+ * If the associated input control does not change from this initial value
+ * upon postback, the validation fails.
+ */
+ public function getInitialValue()
+ {
+ return $this->getViewState('InitialValue',$this->getControlPromptValue());
+ }
+
+ /**
+ * @return string the initial value of the associated input control. Defaults to empty string.
+ * If the associated input control does not change from this initial value
+ * upon postback, the validation fails.
+ */
+ protected function getControlPromptValue()
+ {
+ $control = $this->getValidationTarget();
+ if($control instanceof TListControl)
+ return $control->getPromptValue();
+ return '';
+ }
+ /**
+ * @param string the initial value of the associated input control.
+ * If the associated input control does not change from this initial value
+ * upon postback, the validation fails.
+ */
+ public function setInitialValue($value)
+ {
+ $this->setViewState('InitialValue',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input component changes its data
+ * from the {@link getInitialValue InitialValue} or the input control is not given.
+ *
+ * Validation will also succeed if input is of TListControl type and the
+ * number of selected values different from the initial value is greater
+ * than zero.
+ *
+ * @return boolean whether the validation succeeds
+ */
+ protected function evaluateIsValid()
+ {
+ $control = $this->getValidationTarget();
+ if($control instanceof TListControl)
+ return $this->validateListControl($control);
+ else if($control instanceof TRadioButton && strlen($control->getGroupName()) > 0)
+ return $this->validateRadioButtonGroup($control);
+ else
+ return $this->validateStandardControl($control);
+ }
+
+ private function validateListControl($control)
+ {
+ $initial = trim($this->getInitialValue());
+ $count = 0;
+ foreach($control->getItems() as $item)
+ {
+ if($item->getSelected() && $item->getValue() != $initial)
+ $count++;
+ }
+ return $count > 0;
+ }
+
+ private function validateRadioButtonGroup($control)
+ {
+ $initial = trim($this->getInitialValue());
+ foreach($control->getRadioButtonsInGroup() as $radio)
+ {
+ if($radio->getChecked())
+ {
+ if(strlen($value = $radio->getValue()) > 0)
+ return $value !== $initial;
+ else
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private function validateStandardControl($control)
+ {
+ $initial = trim($this->getInitialValue());
+ $value=$this->getValidationValue($control);
+ return (is_bool($value) && $value) || trim($value)!==$initial;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options = parent::getClientScriptOptions();
+ $options['InitialValue']=$this->getInitialValue();
+ $control = $this->getValidationTarget();
+ if($control instanceof TListControl)
+ $options['TotalItems'] = $control->getItemCount();
+ if($control instanceof TRadioButton && strlen($control->getGroupName()) > 0)
+ $options['GroupName'] = $control->getGroupName();
+ return $options;
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TSafeHtml.php b/lib/prado/framework/Web/UI/WebControls/TSafeHtml.php
new file mode 100644
index 0000000..16743f9
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TSafeHtml.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * TSafeHtml class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TSafeHtml class
+ *
+ * TSafeHtml is a control that strips down all potentially dangerous
+ * HTML content. It is mainly a wrapper of {@link http://pear.php.net/package/SafeHTML SafeHTML}
+ * project. According to the SafeHTML project, it tries to safeguard
+ * the following situations when the string is to be displayed to end-users,
+ * - Opening tag without its closing tag
+ * - closing tag without its opening tag
+ * - any of these tags: base, basefont, head, html, body, applet, object,
+ * iframe, frame, frameset, script, layer, ilayer, embed, bgsound, link,
+ * meta, style, title, blink, xml, etc.
+ * - any of these attributes: on*, data*, dynsrc
+ * - javascript:/vbscript:/about: etc. protocols
+ * - expression/behavior etc. in styles
+ * - any other active content.
+ *
+ * To use TSafeHtml, simply enclose the content to be secured within
+ * the body of TSafeHtml in a template.
+ *
+ * If the content is encoded in UTF-7, you'll need to enable the {@link setRepackUTF7 RepackUTF7} property
+ * to ensure the contents gets parsed correctly.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TSafeHtml extends TControl
+{
+ /**
+ * Sets whether to parse the contents as UTF-7. This property enables a routine
+ * that repacks the content as UTF-7 before parsing it. Defaults to false.
+ * @param boolean whether to parse the contents as UTF-7
+ */
+ public function setRepackUTF7($value)
+ {
+ $this->setViewState('RepackUTF7',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether to parse the contents as UTF-7. Defaults to false.
+ */
+ public function getRepackUTF7()
+ {
+ return $this->getViewState('RepackUTF7',false);
+ }
+
+ /**
+ * Renders body content.
+ * This method overrides parent implementation by removing
+ * malicious javascript code from the body content
+ * @param THtmlWriter writer
+ */
+ public function render($writer)
+ {
+ $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter());
+ parent::render($htmlWriter);
+ $writer->write($this->parseSafeHtml($htmlWriter->flush()));
+ }
+
+ /**
+ * Use SafeHTML to remove malicous javascript from the HTML content.
+ * @param string HTML content
+ * @return string safer HTML content
+ */
+ protected function parseSafeHtml($text)
+ {
+ $renderer = Prado::createComponent('System.3rdParty.SafeHtml.TSafeHtmlParser');
+ return $renderer->parse($text, $this->getRepackUTF7());
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TSlider.php b/lib/prado/framework/Web/UI/WebControls/TSlider.php
new file mode 100644
index 0000000..593cd2c
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TSlider.php
@@ -0,0 +1,570 @@
+<?php
+/**
+ * TSlider class file.
+ *
+ * @author Christophe Boulain <Christophe.Boulain@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+
+/**
+ * TSlider class
+ *
+ * TSlider displays a slider for numeric input purpose. A slider consists of a 'track',
+ * which define the range of possible value, and a 'handle' which can slide on the track, to select
+ * a value in the range. The track can be either Horizontal or Vertical, depending of the {@link SetDirection Direction}
+ * property. By default, it's horizontal.
+ *
+ * The range boundaries are defined by {@link SetMinValue MinValue} and {@link SetMaxValue MaxValue} properties.
+ * The default range is from 0 to 100.
+ * The {@link SetStepSize StepSize} property can be used to define the <b>step</b> between 2 values inside the range.
+ * Notice that this step will be recomputed if there is more than 200 values between the range boundaries.
+ * You can also provide the allowed values by setting the {@link SetValues Values} array.
+ *
+ * A 'Progress Indicator' can be displayed within the track with the {@link SetProgressIndicator ProgressIndicator} property.
+ *
+ * The TSlider control can be easily customized using CssClasses. You can provide your own css file, using the
+ * {@link SetCssUrl CssUrl} property.
+ * The css class for TSlider can be set by the {@link setCssClass CssClass} property. Default value is "Slider HorizontalSlider"
+ * for an horizontal slider, and "Slider VerticalSlider" for a vertical one.
+ *
+ * If {@link SetAutoPostBack AutoPostBack} property is true, postback is sent as soon as the value changed.
+ *
+ * TSlider raises the {@link onValueChanged} event when the value of the slider has changed during postback.
+ *
+ * You can also attach ClientSide javascript events handler to the slider :
+ * - ClientSide.onSlide is called when the handle is slided on the track. You can get the current value in the <b>value</b>
+ * javascript variable. You can use this event to update on client side a label with the current value
+ * - ClientSide.onChange is called when the slider value has changed (at the end of a move).
+ *
+ * @author Christophe Boulain <Christophe.Boulain@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TSlider extends TWebControl implements IPostBackDataHandler, IDataRenderer
+{
+ const MAX_STEPS=200;
+ /**
+ * @var TSliderHandle handle component
+ */
+ private $_handle;
+ /*
+ * @var boolean Wether the data has changed during postback
+ */
+ private $_dataChanged=false;
+ /**
+ * @var TSliderClientScript Clients side javascripts
+ */
+ private $_clientScript=null;
+
+ /**
+ * @return TSliderDirection Direction of slider (Horizontal or Vertical). Defaults to Horizontal.
+ */
+ public function getDirection()
+ {
+ return $this->getViewState('Direction', TSliderDirection::Horizontal);
+ }
+
+ /**
+ * @param TSliderDirection Direction of slider (Horizontal or Vertical)
+ */
+ public function setDirection($value)
+ {
+ $this->setViewState('Direction', TPropertyValue::ensureEnum($value,'TSliderDirection'),TSliderDirection::Horizontal);
+ }
+
+ /**
+ * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to '' (a default CSS file will be applied in this case.)
+ */
+ public function getCssUrl()
+ {
+ return $this->getViewState('CssUrl','');
+ }
+
+ /**
+ * @param string URL for the CSS file including all relevant CSS class definitions.
+ */
+ public function setCssUrl($value)
+ {
+ $this->setViewState('CssUrl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return float Maximum value for the slider. Defaults to 100.0.
+ */
+ public function getMaxValue()
+ {
+ return $this->getViewState('MaxValue',100.0);
+ }
+
+ /**
+ * @param float Maximum value for slider
+ */
+ public function setMaxValue($value)
+ {
+ $this->setViewState('MaxValue', TPropertyValue::ensureFloat($value),100.0);
+ }
+
+ /**
+ * @return float Minimum value for slider. Defaults to 0.0.
+ */
+ public function getMinValue()
+ {
+ return $this->getViewState('MinValue',0.0);
+ }
+
+ /**
+ * @param float Minimum value for slider
+ */
+ public function setMinValue($value)
+ {
+ $this->setViewState('MinValue', TPropertyValue::ensureFloat($value),0.0);
+ }
+
+ /**
+ * @return float Step size. Defaults to 1.0.
+ */
+ public function getStepSize()
+ {
+ return $this->getViewState('StepSize', 1.0);
+ }
+
+ /**
+ * Sets the step size used to determine the places where the slider handle can stop at.
+ * An evenly distributed stop marks will be generated according to
+ * {@link getMinValue MinValue}, {@link getMaxValue MaxValue} and StepSize.
+ * To use uneven stop marks, set {@link setValues Values}.
+ * @param float Step size.
+ */
+ public function setStepSize($value)
+ {
+ $this->setViewState('StepSize', $value, 1.0);
+ }
+
+ /**
+ * @return boolean wether to display a progress indicator or not. Defaults to true.
+ */
+ public function getProgressIndicator ()
+ {
+ return $this->getViewState('ProgressIndicator', true);
+ }
+
+ /**
+ * @param boolean wether to display a progress indicator or not. Defaults to true.
+ */
+ public function setProgressIndicator ($value)
+ {
+ $this->setViewState('ProgressIndicator', TPropertyValue::ensureBoolean($value), true);
+ }
+ /**
+ * @return float current value of slider
+ */
+ public function getValue()
+ {
+ return $this->getViewState('Value',0.0);
+ }
+
+ /**
+ * @param float current value of slider
+ */
+ public function setValue($value)
+ {
+ $this->setViewState('Value', TPropertyValue::ensureFloat($value),0.0);
+ }
+
+ /**
+ * Returns the value of the TSlider control.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getValue()}.
+ * @return string the value of the TSlider control.
+ * @see getValue
+ */
+ public function getData()
+ {
+ return $this->getValue();
+ }
+
+ /**
+ * Sets the value of the TSlider control.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setValue()}.
+ * @param string the value of the TSlider control.
+ * @see setValue
+ */
+ public function setData($value)
+ {
+ $this->setValue($value);
+ }
+
+ /**
+ * @return array list of allowed values the slider can take. Defaults to an empty array.
+ */
+ public function getValues()
+ {
+ return $this->getViewState('Values', array());
+ }
+
+ /**
+ * Sets the possible values that the slider can take.
+ * If this is set, {@link setStepSize StepSize} will be ignored. The latter
+ * generates a set of evenly distributed candidate values.
+ * @param array list of allowed values the slider can take
+ */
+ public function setValues($value)
+ {
+ $this->setViewState('Values', TPropertyValue::ensureArray($value), array());
+ }
+
+ /**
+ * @return boolean a value indicating whether an automatic postback to the server
+ * will occur whenever the user modifies the slider value. Defaults to false.
+ */
+ public function getAutoPostBack()
+ {
+ return $this->getViewState('AutoPostBack',false);
+ }
+
+ /**
+ * Sets the value indicating if postback automatically.
+ * An automatic postback to the server will occur whenever the user
+ * modifies the slider value.
+ * @param boolean the value indicating if postback automatically
+ */
+ public function setAutoPostBack($value)
+ {
+ $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TSlider';
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method is required by {@link IPostBackDataHandler} interface.
+ * It is invoked by the framework when {@link getValue Value} property
+ * is changed on postback.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ $this->onValueChanged(null);
+ }
+
+ /**
+ * Raises <b>OnValueChanged</b> event.
+ * This method is invoked when the {@link getValue Value}
+ * property changes on postback.
+ * If you override this method, be sure to call the parent implementation to ensure
+ * the invocation of the attached event handlers.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onValueChanged($param)
+ {
+ $this->raiseEvent('OnValueChanged',$this,$param);
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ $value=(float)$values[$this->getClientID().'_1'];
+ if($this->getValue()!==$value)
+ {
+ $this->setValue($value);
+ return $this->_dataChanged=true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Gets the TSliderClientScript to set the TSlider event handlers.
+ *
+ * The slider on the client-side supports the following events.
+ * # <tt>OnSliderMove</tt> -- raised when the slider is moved.
+ * # <tt>OnSliderChanged</tt> -- raised when the slider value is changed
+ *
+ * You can attach custom javascript code to each of these events
+ *
+ * @return TSliderClientScript javascript validator event options.
+ */
+ public function getClientSide()
+ {
+ if($this->_clientScript===null)
+ $this->_clientScript = $this->createClientScript();
+ return $this->_clientScript;
+ }
+
+ /**
+ * @return TSliderClientScript javascript event options.
+ */
+ protected function createClientScript()
+ {
+ return new TSliderClientScript;
+ }
+
+ /**
+ * @return string the HTML tag name for slider. Defaults to div.
+ */
+ public function getTagName ()
+ {
+ return "div";
+ }
+
+ /**
+ * Add the specified css classes to the track
+ * @param THtmlWriter writer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ if ($this->getCssClass()==='')
+ {
+ $class=($this->getDirection()==TSliderDirection::Horizontal)?'HorizontalSlider':'VerticalSlider';
+ $writer->addAttribute('class', 'Slider '.$class);
+ }
+
+ }
+
+ /**
+ * Render the body content
+ */
+ public function renderContents($writer)
+ {
+ // Render the 'Track'
+ $writer->addAttribute('class', 'Track');
+ $writer->addAttribute('id', $this->getClientID().'_track');
+ $writer->renderBeginTag('div');
+ // Render the 'Progress Indicator'
+ if ($this->getProgressIndicator())
+ {
+ $writer->addAttribute('class', 'Progress');
+ $writer->addAttribute('id', $this->getClientID().'_progress');
+ $writer->renderBeginTag('div');
+ $writer->renderEndTag();
+ }
+ // Render the 'Ruler'
+ /*
+ * Removing for now
+ $writer->addAttribute('class', 'RuleContainer');
+ $writer->addAttribute('id', $this->getClientID()."_rule");
+ $writer->renderBeginTag('div');
+ for ($i=0;$i<=100;$i+=10)
+ {
+ $writer->addAttribute('class', 'RuleMark');
+ $attr=($this->getDirection()===TSliderDirection::Horizontal)?"left":"top";
+ $writer->addStyleAttribute($attr, $i.'%');
+ $writer->renderBeginTag('div');
+ $writer->renderEndTag();
+ }
+ $writer->renderEndTag();
+ */
+
+ $writer->renderEndTag();
+
+ // Render the 'Handle'
+ $writer->addAttribute('class', 'Handle');
+ $writer->addAttribute('id', $this->getClientID().'_handle');
+ $writer->renderBeginTag('div');
+ $writer->renderEndTag();
+ }
+ /**
+ * Registers CSS and JS.
+ * This method is invoked right before the control rendering, if the control is visible.
+ * @param mixed event parameter
+ */
+ public function onPreRender ($param)
+ {
+ parent::onPreRender($param);
+ $this->registerStyleSheet();
+ $this->registerSliderClientScript();
+
+ }
+
+ /**
+ * Registers the CSS relevant to the TSlider.
+ * It will register the CSS file specified by {@link getCssUrl CssUrl}.
+ * If that is not set, it will use the default CSS.
+ */
+ protected function registerStyleSheet()
+ {
+ if(($url=$this->getCssUrl())==='')
+ {
+ $manager=$this->getApplication()->getAssetManager();
+ // publish the assets
+ $url=$manager->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'TSlider');
+ $url.='/TSlider.css';
+ }
+ $this->getPage()->getClientScript()->registerStyleSheetFile($url,$url);
+ }
+
+ /**
+ * Registers the javascript code to initialize the slider.
+ */
+ protected function registerSliderClientScript()
+ {
+ $page=$this->getPage();
+ $cs = $page->getClientScript();
+ $cs->registerPradoScript("slider");
+ $id=$this->getClientID();
+ $cs->registerHiddenField($id.'_1',$this->getValue());
+ $page->registerRequiresPostData($this);
+ $cs->registerPostBackControl($this->getClientClassName(),$this->getSliderOptions());
+ }
+
+ /**
+ * Get javascript sliderr options.
+ * @return array slider client-side options
+ */
+ protected function getSliderOptions()
+ {
+ // PostBack Options :
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['AutoPostBack'] = $this->getAutoPostBack();
+
+ // Slider Control options
+ $minValue=$this->getMinValue();
+ $maxValue=$this->getMaxValue();
+ $options['axis'] = strtolower($this->getDirection());
+ $options['maximum'] = $maxValue;
+ $options['minimum'] = $minValue;
+ $options['range'] = array($minValue, $maxValue);
+ $options['sliderValue'] = $this->getValue();
+ $options['disabled'] = !$this->getEnabled();
+ $values=$this->getValues();
+ if (!empty($values))
+ {
+ // Values are provided. Check if min/max are present in them
+ if (!in_array($minValue, $values)) $values[]=$minValue;
+ if (!in_array($maxValue, $values)) $values[]=$maxValue;
+ // Remove all values outsize the range [min..max]
+ foreach ($values as $idx=>$value)
+ {
+ if ($value < $minValue) unset ($values[$idx]);
+ if ($value > $maxValue) unset ($values[$idx]);
+ }
+ }
+ else
+ {
+ // Values are not provided, generate automatically using stepsize
+ $step=$this->getStepSize();
+ // We want at most self::MAX_STEPS values, so, change the step if necessary
+ if (($maxValue-$minValue)/$step > self::MAX_STEPS)
+ {
+ $step=($maxValue-$minValue)/self::MAX_STEPS;
+ }
+ $values=array();
+ for ($i=$minValue;$i<=$maxValue;$i+=$step)
+ $values[]=$i;
+ // Add max if it's not in the array because of step
+ if (!in_array($maxValue, $values)) $values[]=$maxValue;
+ }
+ $options['values'] = $values;
+ if($this->_clientScript!==null)
+ $options = array_merge($options,$this->_clientScript->getOptions()->toArray());
+ return $options;
+ }
+}
+
+/**
+ * TSliderClientScript class.
+ *
+ * Client-side slider events {@link setOnChange OnChange} and {@line setOnMove OnMove}
+ * can be modified through the {@link TSlider:: getClientSide ClientSide}
+ * property of a slider.
+ *
+ * The current value of the slider can be get in the 'value' js variable
+ *
+ * The <tt>OnMove</tt> event is raised when the slider moves
+ * The <tt>OnChange</tt> event is raised when the slider value is changed (or at the end of a move)
+ *
+ * @author Christophe Boulain <Christophe.Boulain@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TSliderClientScript extends TClientSideOptions
+{
+ /**
+ * Javascript code to execute when the slider value is changed.
+ * @param string javascript code
+ */
+ public function setOnChange($javascript)
+ {
+ $code=TJavascript::quoteJsLiteral("function (value) { {$javascript} }");
+ $this->setFunction('onChange', $code);
+ }
+
+ /**
+ * @return string javascript code to execute when the slider value is changed.
+ */
+ public function getOnChange()
+ {
+ return $this->getOption('onChange');
+ }
+
+ /* Javascript code to execute when the slider moves.
+ * @param string javascript code
+ */
+ public function setOnSlide($javascript)
+ {
+ $code=TJavascript::quoteJsLiteral("function (value) { {$javascript} }");
+ $this->setFunction('onSlide', $code);
+ }
+
+ /**
+ * @return string javascript code to execute when the slider moves.
+ */
+ public function getOnSlide()
+ {
+ return $this->getOption('onSlide');
+ }
+}
+
+
+/**
+ * TSliderDirection class.
+ *
+ * TSliderDirection defines the enumerable type for the possible direction that can be used in a {@link TSlider}
+ *
+ * The following enumerable values are defined :
+ * - Horizontal : Horizontal slider
+ * - Vertical : Vertical slider
+ *
+ * @author Christophe Boulain <Christophe.Boulain@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TSliderDirection extends TEnumerable
+{
+ const Horizontal='Horizontal';
+ const Vertical='Vertical';
+}
+
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TStatements.php b/lib/prado/framework/Web/UI/WebControls/TStatements.php
new file mode 100644
index 0000000..e9cbeb3
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TStatements.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * TStatements class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TStatements class
+ *
+ * TStatements executes one or several PHP statements and renders the display
+ * generated during the execution. The execution happens during the rendering stage.
+ * The PHP statements being executed can be set via the property
+ * {@link setStatements Statements}. The context of the statemenets executed
+ * is the TStatements object itself.
+ *
+ * Note, since TStatements allows execution of arbitrary PHP statements,
+ * make sure {@link setStatements Statements} does not come directly from user input.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TStatements extends TControl
+{
+ /**
+ * @var string PHP statements
+ */
+ private $_s='';
+
+ /**
+ * @return string the statements to be executed
+ */
+ public function getStatements()
+ {
+ return $this->_s;
+ }
+
+ /**
+ * @param string the PHP statements to be executed
+ */
+ public function setStatements($value)
+ {
+ $this->_s=$value;
+ }
+
+ /**
+ * Renders the evaluation result of the statements.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->_s!=='')
+ $writer->write($this->evaluateStatements($this->_s));
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TStyle.php b/lib/prado/framework/Web/UI/WebControls/TStyle.php
new file mode 100644
index 0000000..eb47f2f
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TStyle.php
@@ -0,0 +1,885 @@
+<?php
+/**
+ * TStyle class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TFont definition
+ */
+Prado::using('System.Web.UI.WebControls.TFont');
+
+/**
+ * TStyle class
+ *
+ * TStyle encapsulates the CSS style applied to a control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TStyle extends TComponent
+{
+ /**
+ * @var array storage of CSS fields
+ */
+ private $_fields=array();
+ /**
+ * @var TFont font object
+ */
+ private $_font=null;
+ /**
+ * @var string CSS class name
+ */
+ private $_class=null;
+ /**
+ * @var string CSS style string (those not represented by specific fields of TStyle)
+ */
+ private $_customStyle=null;
+ /**
+ * @var string display style
+ */
+ private $_displayStyle='Fixed';
+
+ /**
+ * Constructor.
+ * @param TStyle style to copy from
+ */
+ public function __construct($style=null)
+ {
+ if($style!==null)
+ $this->copyFrom($style);
+ }
+
+ /**
+ * Need to clone the font object.
+ */
+ public function __clone()
+ {
+ if($this->_font!==null)
+ $this->_font = clone($this->_font);
+ }
+
+ /**
+ * @return string the background color of the control
+ */
+ public function getBackColor()
+ {
+ return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
+ }
+
+ /**
+ * @param string the background color of the control
+ */
+ public function setBackColor($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['background-color']);
+ else
+ $this->_fields['background-color']=$value;
+ }
+
+ /**
+ * @return string the border color of the control
+ */
+ public function getBorderColor()
+ {
+ return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
+ }
+
+ /**
+ * @param string the border color of the control
+ */
+ public function setBorderColor($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['border-color']);
+ else
+ $this->_fields['border-color']=$value;
+ }
+
+ /**
+ * @return string the border style of the control
+ */
+ public function getBorderStyle()
+ {
+ return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
+ }
+
+ /**
+ * Sets the border style of the control.
+ * @param string the border style of the control
+ */
+ public function setBorderStyle($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['border-style']);
+ else
+ $this->_fields['border-style']=$value;
+ }
+
+ /**
+ * @return string the border width of the control
+ */
+ public function getBorderWidth()
+ {
+ return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
+ }
+
+ /**
+ * @param string the border width of the control
+ */
+ public function setBorderWidth($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['border-width']);
+ else
+ $this->_fields['border-width']=$value;
+ }
+
+ /**
+ * @return string the CSS class of the control
+ */
+ public function getCssClass()
+ {
+ return $this->_class===null?'':$this->_class;
+ }
+
+ /**
+ * @return boolean true if CSS is set or empty.
+ */
+ public function hasCssClass()
+ {
+ return ($this->_class!==null);
+ }
+
+ /**
+ * @param string the name of the CSS class of the control
+ */
+ public function setCssClass($value)
+ {
+ $this->_class=$value;
+ }
+
+ /**
+ * @return TFont the font of the control
+ */
+ public function getFont()
+ {
+ if($this->_font===null)
+ $this->_font=new TFont;
+ return $this->_font;
+ }
+
+ /**
+ * @return boolean true if font is set.
+ */
+ public function hasFont()
+ {
+ return $this->_font !== null;
+ }
+
+ /**
+ * @param TDisplayStyle control display style, default is TDisplayStyle::Fixed
+ */
+ public function setDisplayStyle($value)
+ {
+ $this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
+ switch($this->_displayStyle)
+ {
+ case TDisplayStyle::None:
+ $this->_fields['display'] = 'none';
+ break;
+ case TDisplayStyle::Dynamic:
+ $this->_fields['display'] = ''; //remove the display property
+ break;
+ case TDisplayStyle::Fixed:
+ $this->_fields['visibility'] = 'visible';
+ break;
+ case TDisplayStyle::Hidden:
+ $this->_fields['visibility'] = 'hidden';
+ break;
+ }
+ }
+
+ /**
+ * @return TDisplayStyle display style
+ */
+ public function getDisplayStyle()
+ {
+ return $this->_displayStyle;
+ }
+
+ /**
+ * @return string the foreground color of the control
+ */
+ public function getForeColor()
+ {
+ return isset($this->_fields['color'])?$this->_fields['color']:'';
+ }
+
+ /**
+ * @param string the foreground color of the control
+ */
+ public function setForeColor($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['color']);
+ else
+ $this->_fields['color']=$value;
+ }
+
+ /**
+ * @return string the height of the control
+ */
+ public function getHeight()
+ {
+ return isset($this->_fields['height'])?$this->_fields['height']:'';
+ }
+
+ /**
+ * @param string the height of the control
+ */
+ public function setHeight($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['height']);
+ else
+ $this->_fields['height']=$value;
+ }
+
+ /**
+ * @return string the custom style of the control
+ */
+ public function getCustomStyle()
+ {
+ return $this->_customStyle===null?'':$this->_customStyle;
+ }
+
+ /**
+ * Sets custom style fields from a string.
+ * Custom style fields will be overwritten by style fields explicitly defined.
+ * @param string the custom style of the control
+ */
+ public function setCustomStyle($value)
+ {
+ $this->_customStyle=$value;
+ }
+
+ /**
+ * @return string a single style field value set via {@link setStyleField}. Defaults to empty string.
+ */
+ public function getStyleField($name)
+ {
+ return isset($this->_fields[$name])?$this->_fields[$name]:'';
+ }
+
+ /**
+ * Sets a single style field value.
+ * Style fields set by this method will overwrite those set by {@link setCustomStyle}.
+ * @param string style field name
+ * @param string style field value
+ */
+ public function setStyleField($name,$value)
+ {
+ $this->_fields[$name]=$value;
+ }
+
+ /**
+ * Clears a single style field value;
+ * @param string style field name
+ */
+ public function clearStyleField($name)
+ {
+ unset($this->_fields[$name]);
+ }
+
+ /**
+ * @return boolean whether a style field has been defined by {@link setStyleField}
+ */
+ public function hasStyleField($name)
+ {
+ return isset($this->_fields[$name]);
+ }
+
+ /**
+ * @return string the width of the control
+ */
+ public function getWidth()
+ {
+ return isset($this->_fields['width'])?$this->_fields['width']:'';
+ }
+
+ /**
+ * @param string the width of the control
+ */
+ public function setWidth($value)
+ {
+ $this->_fields['width']=$value;
+ }
+
+ /**
+ * Resets the style to the original empty state.
+ */
+ public function reset()
+ {
+ $this->_fields=array();
+ $this->_font=null;
+ $this->_class=null;
+ $this->_customStyle=null;
+ }
+
+ /**
+ * Copies the fields in a new style to this style.
+ * If a style field is set in the new style, the corresponding field
+ * in this style will be overwritten.
+ * @param TStyle the new style
+ */
+ public function copyFrom($style)
+ {
+ if($style instanceof TStyle)
+ {
+ $this->_fields=array_merge($this->_fields,$style->_fields);
+ if($style->_class!==null)
+ $this->_class=$style->_class;
+ if($style->_customStyle!==null)
+ $this->_customStyle=$style->_customStyle;
+ if($style->_font!==null)
+ $this->getFont()->copyFrom($style->_font);
+ }
+ }
+
+ /**
+ * Merges the style with a new one.
+ * If a style field is not set in this style, it will be overwritten by
+ * the new one.
+ * @param TStyle the new style
+ */
+ public function mergeWith($style)
+ {
+ if($style instanceof TStyle)
+ {
+ $this->_fields=array_merge($style->_fields,$this->_fields);
+ if($this->_class===null)
+ $this->_class=$style->_class;
+ if($this->_customStyle===null)
+ $this->_customStyle=$style->_customStyle;
+ if($style->_font!==null)
+ $this->getFont()->mergeWith($style->_font);
+ }
+ }
+
+ /**
+ * Adds attributes related to CSS styles to renderer.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function addAttributesToRender($writer)
+ {
+ if($this->_customStyle!==null)
+ {
+ foreach(explode(';',$this->_customStyle) as $style)
+ {
+ $arr=explode(':',$style,2);
+ if(isset($arr[1]) && trim($arr[0])!=='')
+ $writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
+ }
+ }
+ $writer->addStyleAttributes($this->_fields);
+ if($this->_font!==null)
+ $this->_font->addAttributesToRender($writer);
+ if($this->_class!==null)
+ $writer->addAttribute('class',$this->_class);
+ }
+
+ /**
+ * @return array list of style fields.
+ */
+ public function getStyleFields()
+ {
+ return $this->_fields;
+ }
+}
+
+/**
+ * TDisplayStyle defines the enumerable type for the possible styles
+ * that a web control can display.
+ *
+ * The following enumerable values are defined:
+ * - None: the control is not displayed and not included in the layout.
+ * - Dynamic: the control is displayed and included in the layout, the layout flow is dependent on the control (equivalent to display:'' in css).
+ * - Fixed: Similar to Dynamic with CSS "visibility" set "shown".
+ * - Hidden: the control is not displayed and is included in the layout.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1
+ */
+class TDisplayStyle extends TEnumerable
+{
+ const None='None';
+ const Dynamic='Dynamic';
+ const Fixed='Fixed';
+ const Hidden='Hidden';
+}
+
+/**
+ * TTableStyle class.
+ * TTableStyle represents the CSS style specific for HTML table.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTableStyle extends TStyle
+{
+ /**
+ * @var TVerticalAlign the URL of the background image for the table
+ */
+ private $_backImageUrl=null;
+ /**
+ * @var THorizontalAlign horizontal alignment of the contents within the table
+ */
+ private $_horizontalAlign=null;
+ /**
+ * @var integer cellpadding of the table
+ */
+ private $_cellPadding=null;
+ /**
+ * @var integer cellspacing of the table
+ */
+ private $_cellSpacing=null;
+ /**
+ * @var TTableGridLines grid line setting of the table
+ */
+ private $_gridLines=null;
+ /**
+ * @var boolean whether the table border should be collapsed
+ */
+ private $_borderCollapse=null;
+
+ /**
+ * Sets the style attributes to default values.
+ * This method overrides the parent implementation by
+ * resetting additional TTableStyle specific attributes.
+ */
+ public function reset()
+ {
+ $this->_backImageUrl=null;
+ $this->_horizontalAlign=null;
+ $this->_cellPadding=null;
+ $this->_cellSpacing=null;
+ $this->_gridLines=null;
+ $this->_borderCollapse=null;
+ }
+
+ /**
+ * Copies the fields in a new style to this style.
+ * If a style field is set in the new style, the corresponding field
+ * in this style will be overwritten.
+ * @param TStyle the new style
+ */
+ public function copyFrom($style)
+ {
+ parent::copyFrom($style);
+ if($style instanceof TTableStyle)
+ {
+ if($style->_backImageUrl!==null)
+ $this->_backImageUrl=$style->_backImageUrl;
+ if($style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($style->_cellPadding!==null)
+ $this->_cellPadding=$style->_cellPadding;
+ if($style->_cellSpacing!==null)
+ $this->_cellSpacing=$style->_cellSpacing;
+ if($style->_gridLines!==null)
+ $this->_gridLines=$style->_gridLines;
+ if($style->_borderCollapse!==null)
+ $this->_borderCollapse=$style->_borderCollapse;
+ }
+ }
+
+ /**
+ * Merges the style with a new one.
+ * If a style field is not set in this style, it will be overwritten by
+ * the new one.
+ * @param TStyle the new style
+ */
+ public function mergeWith($style)
+ {
+ parent::mergeWith($style);
+ if($style instanceof TTableStyle)
+ {
+ if($this->_backImageUrl===null && $style->_backImageUrl!==null)
+ $this->_backImageUrl=$style->_backImageUrl;
+ if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($this->_cellPadding===null && $style->_cellPadding!==null)
+ $this->_cellPadding=$style->_cellPadding;
+ if($this->_cellSpacing===null && $style->_cellSpacing!==null)
+ $this->_cellSpacing=$style->_cellSpacing;
+ if($this->_gridLines===null && $style->_gridLines!==null)
+ $this->_gridLines=$style->_gridLines;
+ if($this->_borderCollapse===null && $style->_borderCollapse!==null)
+ $this->_borderCollapse=$style->_borderCollapse;
+ }
+ }
+
+
+ /**
+ * Adds attributes related to CSS styles to renderer.
+ * This method overrides the parent implementation.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function addAttributesToRender($writer)
+ {
+ if(($url=trim($this->getBackImageUrl()))!=='')
+ $writer->addStyleAttribute('background-image','url('.$url.')');
+
+ if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
+ $writer->addStyleAttribute('text-align',strtolower($horizontalAlign));
+
+ if(($cellPadding=$this->getCellPadding())>=0)
+ $writer->addAttribute('cellpadding',"$cellPadding");
+
+ if(($cellSpacing=$this->getCellSpacing())>=0)
+ $writer->addAttribute('cellspacing',"$cellSpacing");
+
+ if($this->getBorderCollapse())
+ $writer->addStyleAttribute('border-collapse','collapse');
+
+ switch($this->getGridLines())
+ {
+ case TTableGridLines::Horizontal : $writer->addAttribute('rules','rows'); break;
+ case TTableGridLines::Vertical : $writer->addAttribute('rules','cols'); break;
+ case TTableGridLines::Both : $writer->addAttribute('rules','all'); break;
+ }
+
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * @return string the URL of the background image for the table
+ */
+ public function getBackImageUrl()
+ {
+ return $this->_backImageUrl===null?'':$this->_backImageUrl;
+ }
+
+ /**
+ * Sets the URL of the background image for the table
+ * @param string the URL
+ */
+ public function setBackImageUrl($value)
+ {
+ $this->_backImageUrl=$value;
+ }
+
+ /**
+ * @return THorizontalAlign the horizontal alignment of the contents within the table, defaults to THorizontalAlign::NotSet.
+ */
+ public function getHorizontalAlign()
+ {
+ return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
+ }
+
+ /**
+ * Sets the horizontal alignment of the contents within the table.
+ * @param THorizontalAlign the horizontal alignment
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
+ }
+
+ /**
+ * @return integer cellpadding of the table. Defaults to -1, meaning not set.
+ */
+ public function getCellPadding()
+ {
+ return $this->_cellPadding===null?-1:$this->_cellPadding;
+ }
+
+ /**
+ * @param integer cellpadding of the table. A value equal to -1 clears up the setting.
+ * @throws TInvalidDataValueException if the value is less than -1.
+ */
+ public function setCellPadding($value)
+ {
+ if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
+ throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
+ }
+
+ /**
+ * @return integer cellspacing of the table. Defaults to -1, meaning not set.
+ */
+ public function getCellSpacing()
+ {
+ return $this->_cellSpacing===null?-1:$this->_cellSpacing;
+ }
+
+ /**
+ * @param integer cellspacing of the table. A value equal to -1 clears up the setting.
+ * @throws TInvalidDataValueException if the value is less than -1.
+ */
+ public function setCellSpacing($value)
+ {
+ if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
+ throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
+ }
+
+ /**
+ * @return TTableGridLines the grid line setting of the table. Defaults to TTableGridLines::None.
+ */
+ public function getGridLines()
+ {
+ return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
+ }
+
+ /**
+ * Sets the grid line style of the table.
+ * @param TTableGridLines the grid line setting of the table
+ */
+ public function setGridLines($value)
+ {
+ $this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
+ }
+
+
+ /**
+ * @return boolean whether the table borders should be collapsed. Defaults to false.
+ */
+ public function getBorderCollapse()
+ {
+ return $this->_borderCollapse===null?false:$this->_borderCollapse;
+ }
+
+ /**
+ * @param boolean whether the table borders should be collapsed.
+ */
+ public function setBorderCollapse($value)
+ {
+ $this->_borderCollapse=TPropertyValue::ensureBoolean($value);
+ }
+}
+
+/**
+ * TTableItemStyle class.
+ * TTableItemStyle represents the CSS style specific for HTML table item.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTableItemStyle extends TStyle
+{
+ /**
+ * @var THorizontalAlign horizontal alignment of the contents within the table item
+ */
+ private $_horizontalAlign=null;
+ /**
+ * @var TVerticalAlign vertical alignment of the contents within the table item
+ */
+ private $_verticalAlign=null;
+ /**
+ * @var boolean whether the content wraps within the table item
+ */
+ private $_wrap=null;
+
+ /**
+ * Sets the style attributes to default values.
+ * This method overrides the parent implementation by
+ * resetting additional TTableItemStyle specific attributes.
+ */
+ public function reset()
+ {
+ parent::reset();
+ $this->_verticalAlign=null;
+ $this->_horizontalAlign=null;
+ $this->_wrap=null;
+ }
+
+ /**
+ * Copies the fields in a new style to this style.
+ * If a style field is set in the new style, the corresponding field
+ * in this style will be overwritten.
+ * @param TStyle the new style
+ */
+ public function copyFrom($style)
+ {
+ parent::copyFrom($style);
+ if($style instanceof TTableItemStyle)
+ {
+ if($this->_verticalAlign===null && $style->_verticalAlign!==null)
+ $this->_verticalAlign=$style->_verticalAlign;
+ if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($this->_wrap===null && $style->_wrap!==null)
+ $this->_wrap=$style->_wrap;
+ }
+ }
+
+ /**
+ * Merges the style with a new one.
+ * If a style field is not set in this style, it will be overwritten by
+ * the new one.
+ * @param TStyle the new style
+ */
+ public function mergeWith($style)
+ {
+ parent::mergeWith($style);
+ if($style instanceof TTableItemStyle)
+ {
+ if($style->_verticalAlign!==null)
+ $this->_verticalAlign=$style->_verticalAlign;
+ if($style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($style->_wrap!==null)
+ $this->_wrap=$style->_wrap;
+ }
+ }
+
+ /**
+ * Adds attributes related to CSS styles to renderer.
+ * This method overrides the parent implementation.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function addAttributesToRender($writer)
+ {
+ if(!$this->getWrap())
+ $writer->addStyleAttribute('white-space','nowrap');
+
+ if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
+ $writer->addAttribute('align',strtolower($horizontalAlign));
+
+ if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet)
+ $writer->addAttribute('valign',strtolower($verticalAlign));
+
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * @return THorizontalAlign the horizontal alignment of the contents within the table item, defaults to THorizontalAlign::NotSet.
+ */
+ public function getHorizontalAlign()
+ {
+ return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
+ }
+
+ /**
+ * Sets the horizontal alignment of the contents within the table item.
+ * @param THorizontalAlign the horizontal alignment
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
+ }
+
+ /**
+ * @return TVerticalAlign the vertical alignment of the contents within the table item, defaults to TVerticalAlign::NotSet.
+ */
+ public function getVerticalAlign()
+ {
+ return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
+ }
+
+ /**
+ * Sets the vertical alignment of the contents within the table item.
+ * @param TVerticalAlign the horizontal alignment
+ */
+ public function setVerticalAlign($value)
+ {
+ $this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
+ }
+
+ /**
+ * @return boolean whether the content wraps within the table item. Defaults to true.
+ */
+ public function getWrap()
+ {
+ return $this->_wrap===null?true:$this->_wrap;
+ }
+
+ /**
+ * Sets the value indicating whether the content wraps within the table item.
+ * @param boolean whether the content wraps within the panel.
+ */
+ public function setWrap($value)
+ {
+ $this->_wrap=TPropertyValue::ensureBoolean($value);
+ }
+}
+
+/**
+ * THorizontalAlign class.
+ * THorizontalAlign defines the enumerable type for the possible horizontal alignments in a CSS style.
+ *
+ * The following enumerable values are defined:
+ * - NotSet: the alignment is not specified.
+ * - Left: left aligned
+ * - Right: right aligned
+ * - Center: center aligned
+ * - Justify: the begin and end are justified
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class THorizontalAlign extends TEnumerable
+{
+ const NotSet='NotSet';
+ const Left='Left';
+ const Right='Right';
+ const Center='Center';
+ const Justify='Justify';
+}
+
+/**
+ * TVerticalAlign class.
+ * TVerticalAlign defines the enumerable type for the possible vertical alignments in a CSS style.
+ *
+ * The following enumerable values are defined:
+ * - NotSet: the alignment is not specified.
+ * - Top: top aligned
+ * - Bottom: bottom aligned
+ * - Middle: middle aligned
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TVerticalAlign extends TEnumerable
+{
+ const NotSet='NotSet';
+ const Top='Top';
+ const Bottom='Bottom';
+ const Middle='Middle';
+}
+
+
+/**
+ * TTableGridLines class.
+ * TTableGridLines defines the enumerable type for the possible grid line types of an HTML table.
+ *
+ * The following enumerable values are defined:
+ * - None: no grid lines
+ * - Horizontal: horizontal grid lines only
+ * - Vertical: vertical grid lines only
+ * - Both: both horizontal and vertical grid lines are shown
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TTableGridLines extends TEnumerable
+{
+ const None='None';
+ const Horizontal='Horizontal';
+ const Vertical='Vertical';
+ const Both='Both';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TStyleSheet.php b/lib/prado/framework/Web/UI/WebControls/TStyleSheet.php
new file mode 100644
index 0000000..ae5692d
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TStyleSheet.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * TStyleSheet class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TStyleSheet class.
+ *
+ * TStyleSheet represents the link to a stylesheet file and/or a piece of
+ * stylesheet code. To specify the link to a CSS file, set {@link setStyleSheetUrl StyleSheetUrl}.
+ * The child rendering result of TStyleSheet is treated as CSS code and
+ * is rendered within an appropriate style HTML element.
+ * Therefore, if the child content is not empty, you should place the TStyleSheet
+ * control in the head section of your page to conform to the HTML standard.
+ * If only CSS file URL is specified, you may place the control anywhere on your page
+ * and the style element will be rendered in the right position.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version : $ Tue Jul 4 04:38:16 EST 2006 $
+ * @package System.Web.UI.WebControls
+ * @since 3.0.2
+ */
+class TStyleSheet extends TControl
+{
+ /**
+ * @param string URL to the stylesheet file
+ */
+ public function setStyleSheetUrl($value)
+ {
+ $this->setViewState('StyleSheetUrl', $value);
+ }
+
+ /**
+ * @return string URL to the stylesheet file
+ */
+ public function getStyleSheetUrl()
+ {
+ return $this->getViewState('StyleSheetUrl', '');
+ }
+
+ /**
+ * @return string media type of the CSS (such as 'print', 'screen', etc.). Defaults to empty, meaning the CSS applies to all media types.
+ */
+ public function getMediaType()
+ {
+ return $this->getViewState('MediaType','');
+ }
+
+ /**
+ * @param string media type of the CSS (such as 'print', 'screen', etc.). If empty, it means the CSS applies to all media types.
+ */
+ public function setMediaType($value)
+ {
+ $this->setViewState('MediaType',$value,'');
+ }
+
+ /**
+ * Registers the stylesheet file and content to be rendered.
+ * This method overrides the parent implementation and is invoked right before rendering.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ if(($url=$this->getStyleSheetUrl())!=='')
+ $this->getPage()->getClientScript()->registerStyleSheetFile($url,$url,$this->getMediaType());
+ }
+
+ /**
+ * Renders the control.
+ * This method overrides the parent implementation and renders nothing.
+ * @param ITextWriter writer
+ */
+ public function render($writer)
+ {
+ if($this->getHasControls())
+ {
+ $writer->write("<style type=\"text/css\">\n/*<![CDATA[*/\n");
+ $this->renderChildren($writer);
+ $writer->write("\n/*]]>*/\n</style>\n");
+ }
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TTabPanel.php b/lib/prado/framework/Web/UI/WebControls/TTabPanel.php
new file mode 100644
index 0000000..29baefd
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TTabPanel.php
@@ -0,0 +1,728 @@
+<?php
+/**
+ * TTabPanel class file.
+ *
+ * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+
+/**
+ * Class TTabPanel.
+ *
+ * TTabPanel displays a tabbed panel. Users can click on the tab bar to switching among
+ * different tab views. Each tab view is an independent panel that can contain arbitrary content.
+ *
+ * If the {@link setAutoSwitch AutoSwitch} property is enabled, the user will be able to switch the active view
+ * to another one just hovering its corresponding tab caption.
+ *
+ * A TTabPanel control consists of one or several {@link TTabView} controls representing the possible
+ * tab views. At any time, only one tab view is visible (active), which is specified by any of
+ * the following properties:
+ * - {@link setActiveViewIndex ActiveViewIndex} - the zero-based integer index of the view in the view collection.
+ * - {@link setActiveViewID ActiveViewID} - the text ID of the visible view.
+ * - {@link setActiveView ActiveView} - the visible view instance.
+ * If both {@link setActiveViewIndex ActiveViewIndex} and {@link setActiveViewID ActiveViewID}
+ * are set, the latter takes precedence.
+ *
+ * TTabPanel uses CSS to specify the appearance of the tab bar and panel. By default,
+ * an embedded CSS file will be published which contains the default CSS for TTabPanel.
+ * You may also use your own CSS file by specifying the {@link setCssUrl CssUrl} property.
+ * The following properties specify the CSS classes used for elements in a TTabPanel:
+ * - {@link setCssClass CssClass} - the CSS class name for the outer-most div element (defaults to 'tab-panel');
+ * - {@link setTabCssClass TabCssClass} - the CSS class name for nonactive tab div elements (defaults to 'tab-normal');
+ * - {@link setActiveTabCssClass ActiveTabCssClass} - the CSS class name for the active tab div element (defaults to 'tab-active');
+ * - {@link setViewCssClass ViewCssClass} - the CSS class for the div element enclosing view content (defaults to 'tab-view');
+ *
+ * To use TTabPanel, write a template like following:
+ * <code>
+ * <com:TTabPanel>
+ * <com:TTabView Caption="View 1">
+ * content for view 1
+ * </com:TTabView>
+ * <com:TTabView Caption="View 2">
+ * content for view 2
+ * </com:TTabView>
+ * <com:TTabView Caption="View 3">
+ * content for view 3
+ * </com:TTabView>
+ * </com:TTabPanel>
+ * </code>
+ *
+ * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TTabPanel extends TWebControl implements IPostBackDataHandler
+{
+ private $_dataChanged=false;
+
+ /**
+ * @return string tag name for the control
+ */
+ protected function getTagName()
+ {
+ return 'div';
+ }
+
+ /**
+ * Adds object parsed from template to the control.
+ * This method adds only {@link TTabView} objects into the {@link getViews Views} collection.
+ * All other objects are ignored.
+ * @param mixed object parsed from template
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TTabView)
+ $this->getControls()->add($object);
+ }
+
+ /**
+ * Returns the index of the active tab view.
+ * Note, this property may not return the correct index.
+ * To ensure the correctness, call {@link getActiveView()} first.
+ * @return integer the zero-based index of the active tab view. If -1, it means no active tab view. Default is 0 (the first view is active).
+ */
+ public function getActiveViewIndex()
+ {
+ return $this->getViewState('ActiveViewIndex',0);
+ }
+
+ /**
+ * @param integer the zero-based index of the current view in the view collection. -1 if no active view.
+ * @throws TInvalidDataValueException if the view index is invalid
+ */
+ public function setActiveViewIndex($value)
+ {
+ $this->setViewState('ActiveViewIndex',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * Returns the ID of the active tab view.
+ * Note, this property may not return the correct ID.
+ * To ensure the correctness, call {@link getActiveView()} first.
+ * @return string The ID of the active tab view. Defaults to '', meaning not set.
+ */
+ public function getActiveViewID()
+ {
+ return $this->getViewState('ActiveViewID','');
+ }
+
+ /**
+ * @param string The ID of the active tab view.
+ */
+ public function setActiveViewID($value)
+ {
+ $this->setViewState('ActiveViewID',$value,'');
+ }
+
+ /**
+ * Returns the currently active view.
+ * This method will examin the ActiveViewID, ActiveViewIndex and Views collection to
+ * determine which view is currently active. It will update ActiveViewID and ActiveViewIndex accordingly.
+ * @return TTabView the currently active view, null if no active view
+ * @throws TInvalidDataValueException if the active view ID or index set previously is invalid
+ */
+ public function getActiveView()
+ {
+ $activeView=null;
+ $views=$this->getViews();
+ if(($id=$this->getActiveViewID())!=='')
+ {
+ if(($index=$views->findIndexByID($id))>=0)
+ $activeView=$views->itemAt($index);
+ else
+ throw new TInvalidDataValueException('tabpanel_activeviewid_invalid',$id);
+ }
+ else if(($index=$this->getActiveViewIndex())>=0)
+ {
+ if($index<$views->getCount())
+ $activeView=$views->itemAt($index);
+ else
+ throw new TInvalidDataValueException('tabpanel_activeviewindex_invalid',$index);
+ }
+ else
+ {
+ foreach($views as $index=>$view)
+ {
+ if($view->getActive())
+ {
+ $activeView=$view;
+ break;
+ }
+ }
+ }
+ if($activeView!==null)
+ $this->activateView($activeView);
+ return $activeView;
+ }
+
+ /**
+ * @param TTabView the view to be activated
+ * @throws TInvalidOperationException if the view is not in the view collection
+ */
+ public function setActiveView($view)
+ {
+ if($this->getViews()->indexOf($view)>=0)
+ $this->activateView($view);
+ else
+ throw new TInvalidOperationException('tabpanel_view_inexistent');
+ }
+
+ /**
+ * @return bool status of automatic tab switch on hover
+ */
+ public function getAutoSwitch()
+ {
+ return TPropertyValue::ensureBoolean($this->getViewState('AutoSwitch'));
+ }
+
+ /**
+ * @param bool whether to enable automatic tab switch on hover
+ */
+ public function setAutoSwitch($value)
+ {
+ $this->setViewState('AutoSwitch',TPropertyValue::ensureBoolean($value));
+ }
+
+
+ /**
+ * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to ''.
+ */
+ public function getCssUrl()
+ {
+ return $this->getViewState('CssUrl','default');
+ }
+
+ /**
+ * @param string URL for the CSS file including all relevant CSS class definitions.
+ */
+ public function setCssUrl($value)
+ {
+ $this->setViewState('CssUrl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string CSS class for the whole tab control div. Defaults to 'tab-panel'.
+ */
+ public function getCssClass()
+ {
+ $cssClass=parent::getCssClass();
+ return $cssClass===''?'tab-panel':$cssClass;
+ }
+
+ /**
+ * @return string CSS class for the currently displayed view div. Defaults to 'tab-view'.
+ */
+ public function getViewCssClass()
+ {
+ return $this->getViewStyle()->getCssClass();
+ }
+
+ /**
+ * @param string CSS class for the currently displayed view div.
+ */
+ public function setViewCssClass($value)
+ {
+ $this->getViewStyle()->setCssClass($value);
+ }
+
+ /**
+ * @return TStyle the style for all the view div
+ */
+ public function getViewStyle()
+ {
+ if(($style=$this->getViewState('ViewStyle',null))===null)
+ {
+ $style=new TStyle;
+ $style->setCssClass('tab-view');
+ $this->setViewState('ViewStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string CSS class for non-active tabs. Defaults to 'tab-normal'.
+ */
+ public function getTabCssClass()
+ {
+ return $this->getTabStyle()->getCssClass();
+ }
+
+ /**
+ * @param string CSS class for non-active tabs.
+ */
+ public function setTabCssClass($value)
+ {
+ $this->getTabStyle()->setCssClass($value);
+ }
+
+ /**
+ * @return TStyle the style for all the inactive tab div
+ */
+ public function getTabStyle()
+ {
+ if(($style=$this->getViewState('TabStyle',null))===null)
+ {
+ $style=new TStyle;
+ $style->setCssClass('tab-normal');
+ $this->setViewState('TabStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string CSS class for the active tab. Defaults to 'tab-active'.
+ */
+ public function getActiveTabCssClass()
+ {
+ return $this->getActiveTabStyle()->getCssClass();
+ }
+
+ /**
+ * @param string CSS class for the active tab.
+ */
+ public function setActiveTabCssClass($value)
+ {
+ $this->getActiveTabStyle()->setCssClass($value);
+ }
+
+ /**
+ * @return TStyle the style for the active tab div
+ */
+ public function getActiveTabStyle()
+ {
+ if(($style=$this->getViewState('ActiveTabStyle',null))===null)
+ {
+ $style=new TStyle;
+ $style->setCssClass('tab-active');
+ $this->setViewState('ActiveTabStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * Activates the specified view.
+ * If there is any other view currently active, it will be deactivated.
+ * @param TTabView the view to be activated. If null, all views will be deactivated.
+ */
+ protected function activateView($view)
+ {
+ $this->setActiveViewIndex(-1);
+ $this->setActiveViewID('');
+ foreach($this->getViews() as $index=>$v)
+ {
+ if($view===$v)
+ {
+ $this->setActiveViewIndex($index);
+ $this->setActiveViewID($view->getID(false));
+ $view->setActive(true);
+ }
+ else
+ $v->setActive(false);
+ }
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if(($index=$values[$this->getClientID().'_1'])!==null)
+ {
+ $index=(int)$index;
+ $currentIndex=$this->getActiveViewIndex();
+ if($currentIndex!==$index)
+ {
+ $this->setActiveViewID(''); // clear up view ID
+ $this->setActiveViewIndex($index);
+ return $this->_dataChanged=true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method is required by {@link IPostBackDataHandler} interface.
+ * It is invoked by the framework when {@link getActiveViewIndex ActiveViewIndex} property
+ * is changed on postback.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ // do nothing
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $this->setCssClass($this->getCssClass());
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Registers CSS and JS.
+ * This method is invoked right before the control rendering, if the control is visible.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->getActiveView(); // determine the active view
+ $this->registerStyleSheet();
+
+ $page=$this->getPage();
+ $page->registerRequiresPostData($this);
+ $page->registerRequiresPostData($this->getClientID()."_1");
+ }
+
+ /**
+ * Registers the CSS relevant to the TTabControl.
+ * It will register the CSS file specified by {@link getCssUrl CssUrl}.
+ * If that is not set, it will use the default CSS.
+ */
+ protected function registerStyleSheet()
+ {
+ $url = $this->getCssUrl();
+
+ if($url === '') {
+ return;
+ }
+
+ if($url === 'default') {
+ $url = $this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'tabpanel.css');
+ }
+
+ if($url !== '') {
+ $this->getPage()->getClientScript()->registerStyleSheetFile($url, $url);
+ }
+ }
+
+ /**
+ * Registers the relevant JavaScript.
+ */
+ protected function registerClientScript()
+ {
+ $id=$this->getClientID();
+ $options=TJavaScript::encode($this->getClientOptions());
+ $className=$this->getClientClassName();
+ $cs=$this->getPage()->getClientScript();
+ $cs->registerPradoScript('tabpanel');
+ $code="new $className($options);";
+ $cs->registerEndScript("prado:$id", $code);
+ // ensure an item is always active and visible
+ $index = $this->getActiveViewIndex();
+ if(!$this->getViews()->itemAt($index)->Visible)
+ $index=0;
+ $cs->registerHiddenField($id.'_1', $index);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TTabPanel';
+ }
+
+ /**
+ * @return array the options for JavaScript
+ */
+ protected function getClientOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['ActiveCssClass'] = $this->getActiveTabCssClass();
+ $options['NormalCssClass'] = $this->getTabCssClass();
+ $viewIDs = array();
+ $viewVis = array();
+ foreach($this->getViews() as $view)
+ {
+ $viewIDs[] = $view->getClientID();
+ $viewVis[] = $view->getVisible();
+ }
+ $options['Views'] = $viewIDs;
+ $options['ViewsVis'] = $viewVis;
+ $options['AutoSwitch'] = $this->getAutoSwitch();
+
+ return $options;
+ }
+
+ /**
+ * Creates a control collection object that is to be used to hold child controls
+ * @return TTabViewCollection control collection
+ */
+ protected function createControlCollection()
+ {
+ return new TTabViewCollection($this);
+ }
+
+ /**
+ * @return TTabViewCollection list of {@link TTabView} controls
+ */
+ public function getViews()
+ {
+ return $this->getControls();
+ }
+
+ public function render($writer)
+ {
+ $this->registerClientScript();
+ parent::render($writer);
+ }
+
+ /**
+ * Renders body contents of the tab control.
+ * @param THtmlWriter the writer used for the rendering purpose.
+ */
+ public function renderContents($writer)
+ {
+ $views=$this->getViews();
+ if($views->getCount()>0)
+ {
+ $writer->writeLine();
+ // render tab bar
+ foreach($views as $view)
+ {
+ $view->renderTab($writer);
+ $writer->writeLine();
+ }
+ // render tab views
+ foreach($views as $view)
+ {
+ $view->renderControl($writer);
+ $writer->writeLine();
+ }
+ }
+ }
+}
+
+/**
+ * TTabView class.
+ *
+ * TTabView represents a view in a {@link TTabPanel} control.
+ *
+ * The content in a TTabView can be specified by the {@link setText Text} property
+ * or its child controls. In template syntax, the latter means enclosing the content
+ * within the TTabView component element. If both are set, {@link getText Text} takes precedence.
+ *
+ * Each TTabView is associated with a tab in the tab bar of the TTabPanel control.
+ * The tab caption is specified by {@link setCaption Caption}. If {@link setNavigateUrl NavigateUrl}
+ * is set, the tab will contain a hyperlink pointing to the specified URL. In this case,
+ * clicking on the tab will redirect the browser to the specified URL.
+ *
+ * TTabView may be toggled between visible (active) and invisible (inactive) by
+ * setting the {@link setActive Active} property.
+ *
+ * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TTabView extends TWebControl
+{
+ private $_active=false;
+
+ /**
+ * @return the tag name for the view element
+ */
+ protected function getTagName()
+ {
+ return 'div';
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ if(!$this->getActive() && $this->getPage()->getClientSupportsJavaScript())
+ $this->getStyle()->setStyleField('display','none');
+
+ $this->getStyle()->mergeWith($this->getParent()->getViewStyle());
+
+ parent::addAttributesToRender($writer);
+
+ $writer->addAttribute('id',$this->getClientID());
+ }
+
+ /**
+ * @return string the caption displayed on this tab. Defaults to ''.
+ */
+ public function getCaption()
+ {
+ return $this->getViewState('Caption','');
+ }
+
+ /**
+ * @param string the caption displayed on this tab
+ */
+ public function setCaption($value)
+ {
+ $this->setViewState('Caption',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string the URL of the target page. Defaults to ''.
+ */
+ public function getNavigateUrl()
+ {
+ return $this->getViewState('NavigateUrl','');
+ }
+
+ /**
+ * Sets the URL of the target page.
+ * If not empty, clicking on this tab will redirect the browser to the specified URL.
+ * @param string the URL of the target page.
+ */
+ public function setNavigateUrl($value)
+ {
+ $this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string the text content displayed on this view. Defaults to ''.
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text content to be displayed on this view.
+ * If this is not empty, the child content of the view will be ignored.
+ * @param string the text content displayed on this view
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return boolean whether this tab view is active. Defaults to false.
+ */
+ public function getActive()
+ {
+ return $this->_active;
+ }
+
+ /**
+ * @param boolean whether this tab view is active.
+ */
+ public function setActive($value)
+ {
+ $this->_active=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * Renders body contents of the tab view.
+ * @param THtmlWriter the writer used for the rendering purpose.
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())!=='')
+ $writer->write($text);
+ else if($this->getHasControls())
+ parent::renderContents($writer);
+ }
+
+ /**
+ * Renders the tab associated with the tab view.
+ * @param THtmlWriter the writer for rendering purpose.
+ */
+ public function renderTab($writer)
+ {
+ if($this->getVisible(false) && $this->getPage()->getClientSupportsJavaScript())
+ {
+ $writer->addAttribute('id',$this->getClientID().'_0');
+
+ $style=$this->getActive()?$this->getParent()->getActiveTabStyle():$this->getParent()->getTabStyle();
+ $style->addAttributesToRender($writer);
+
+ $writer->renderBeginTag($this->getTagName());
+
+ $this->renderTabContent($writer);
+
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Renders the content in the tab.
+ * By default, a hyperlink is displayed.
+ * @param THtmlWriter the HTML writer
+ */
+ protected function renderTabContent($writer)
+ {
+ if(($url=$this->getNavigateUrl())==='')
+ $url='javascript://';
+ if(($caption=$this->getCaption())==='')
+ $caption='&nbsp;';
+ $writer->write("<a href=\"{$url}\">{$caption}</a>");
+ }
+}
+
+/**
+ * TTabViewCollection class.
+ *
+ * TTabViewCollection is used to maintain a list of views belong to a {@link TTabPanel}.
+ *
+ * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TTabViewCollection extends TControlCollection
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing sanity check on the type of new item.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TTabView} object.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TTabView)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('tabviewcollection_tabview_required');
+ }
+
+ /**
+ * Finds the index of the tab view whose ID is the same as the one being looked for.
+ * @param string the explicit ID of the tab view to be looked for
+ * @return integer the index of the tab view found, -1 if not found.
+ */
+ public function findIndexByID($id)
+ {
+ foreach($this as $index=>$view)
+ {
+ if($view->getID(false)===$id)
+ return $index;
+ }
+ return -1;
+ }
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TTable.php b/lib/prado/framework/Web/UI/WebControls/TTable.php
new file mode 100644
index 0000000..98dc74e
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TTable.php
@@ -0,0 +1,406 @@
+<?php
+/**
+ * TTable and TTableRowCollection class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTableRow class
+ */
+Prado::using('System.Web.UI.WebControls.TTableRow');
+
+/**
+ * TTable class
+ *
+ * TTable displays an HTML table on a Web page.
+ *
+ * A table may have {@link setCaption Caption}, whose alignment is specified
+ * via {@link setCaptionAlign CaptionAlign}. The table cellpadding and cellspacing
+ * are specified via {@link setCellPadding CellPadding} and {@link setCellSpacing CellSpacing}
+ * properties, respectively. The {@link setGridLines GridLines} specifies how
+ * the table should display its borders. The horizontal alignment of the table
+ * content can be specified via {@link setHorizontalAlign HorizontalAlign},
+ * and {@link setBackImageUrl BackImageUrl} can assign a background image to the table.
+ *
+ * A TTable maintains a list of {@link TTableRow} controls in its
+ * {@link getRows Rows} property. Each {@link TTableRow} represents
+ * an HTML table row.
+ *
+ * To populate the table {@link getRows Rows}, you may either use control template
+ * or dynamically create {@link TTableRow} in code.
+ * In template, do as follows to create the table rows and cells,
+ * <code>
+ * <com:TTable>
+ * <com:TTableRow>
+ * <com:TTableCell Text="content" />
+ * <com:TTableCell Text="content" />
+ * </com:TTableRow>
+ * <com:TTableRow>
+ * <com:TTableCell Text="content" />
+ * <com:TTableCell Text="content" />
+ * </com:TTableRow>
+ * </com:TTable>
+ * </code>
+ * The above can also be accomplished in code as follows,
+ * <code>
+ * $table=new TTable;
+ * $row=new TTableRow;
+ * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
+ * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
+ * $table->Rows->add($row);
+ * $row=new TTableRow;
+ * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
+ * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
+ * $table->Rows->add($row);
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTable extends TWebControl
+{
+ /**
+ * @return string tag name for the table
+ */
+ protected function getTagName()
+ {
+ return 'table';
+ }
+
+ /**
+ * Adds object parsed from template to the control.
+ * This method adds only {@link TTableRow} objects into the {@link getRows Rows} collection.
+ * All other objects are ignored.
+ * @param mixed object parsed from template
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TTableRow)
+ $this->getRows()->add($object);
+ }
+
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableStyle} to be used by the table.
+ * @return TTableStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableStyle;
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $border=0;
+ if($this->getHasStyle())
+ {
+ if($this->getGridLines()!==TTableGridLines::None)
+ {
+ if(($border=$this->getBorderWidth())==='')
+ $border=1;
+ else
+ $border=(int)$border;
+ }
+ }
+ $writer->addAttribute('border',"$border");
+ }
+
+ /**
+ * Creates a control collection object that is to be used to hold child controls
+ * @return TTableRowCollection control collection
+ * @see getControls
+ */
+ protected function createControlCollection()
+ {
+ return new TTableRowCollection($this);
+ }
+
+ /**
+ * @return TTableRowCollection list of {@link TTableRow} controls
+ */
+ public function getRows()
+ {
+ return $this->getControls();
+ }
+
+ /**
+ * @return string table caption
+ */
+ public function getCaption()
+ {
+ return $this->getViewState('Caption','');
+ }
+
+ /**
+ * @param string table caption
+ */
+ public function setCaption($value)
+ {
+ $this->setViewState('Caption',$value,'');
+ }
+
+ /**
+ * @return TTableCaptionAlign table caption alignment. Defaults to TTableCaptionAlign::NotSet.
+ */
+ public function getCaptionAlign()
+ {
+ return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet);
+ }
+
+ /**
+ * @param TTableCaptionAlign table caption alignment.
+ */
+ public function setCaptionAlign($value)
+ {
+ $this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet);
+ }
+
+ /**
+ * @return integer the cellspacing for the table. Defaults to -1, meaning not set.
+ */
+ public function getCellSpacing()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getCellSpacing();
+ else
+ return -1;
+ }
+
+ /**
+ * @param integer the cellspacing for the table. Defaults to -1, meaning not set.
+ */
+ public function setCellSpacing($value)
+ {
+ $this->getStyle()->setCellSpacing($value);
+ }
+
+ /**
+ * @return integer the cellpadding for the table. Defaults to -1, meaning not set.
+ */
+ public function getCellPadding()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getCellPadding();
+ else
+ return -1;
+ }
+
+ /**
+ * @param integer the cellpadding for the table. Defaults to -1, meaning not set.
+ */
+ public function setCellPadding($value)
+ {
+ $this->getStyle()->setCellPadding($value);
+ }
+
+ /**
+ * @return THorizontalAlign the horizontal alignment of the table content. Defaults to THorizontalAlign::NotSet.
+ */
+ public function getHorizontalAlign()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getHorizontalAlign();
+ else
+ return THorizontalAlign::NotSet;
+ }
+
+ /**
+ * @param THorizontalAlign the horizontal alignment of the table content.
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->getStyle()->setHorizontalAlign($value);
+ }
+
+ /**
+ * @return TTableGridLines the grid line setting of the table. Defaults to TTableGridLines::None.
+ */
+ public function getGridLines()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getGridLines();
+ else
+ return TTableGridLines::None;
+ }
+
+ /**
+ * @param TTableGridLines the grid line setting of the table
+ */
+ public function setGridLines($value)
+ {
+ $this->getStyle()->setGridLines($value);
+ }
+
+ /**
+ * @return string the URL of the background image for the table
+ */
+ public function getBackImageUrl()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getBackImageUrl();
+ else
+ return '';
+ }
+
+ /**
+ * Sets the URL of the background image for the table
+ * @param string the URL
+ */
+ public function setBackImageUrl($value)
+ {
+ $this->getStyle()->setBackImageUrl($value);
+ }
+
+ /**
+ * Renders the openning tag for the table control which will render table caption if present.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderBeginTag($writer)
+ {
+ parent::renderBeginTag($writer);
+ if(($caption=$this->getCaption())!=='')
+ {
+ if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet)
+ $writer->addAttribute('align',strtolower($align));
+ $writer->renderBeginTag('caption');
+ $writer->write($caption);
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Renders body contents of the table.
+ * @param THtmlWriter the writer used for the rendering purpose.
+ */
+ public function renderContents($writer)
+ {
+ if($this->getHasControls())
+ {
+ $renderTableSection=false;
+ foreach($this->getControls() as $row)
+ {
+ if($row->getTableSection()!==TTableRowSection::Body)
+ {
+ $renderTableSection=true;
+ break;
+ }
+ }
+ if($renderTableSection)
+ {
+ $currentSection=TTableRowSection::Header;
+ $writer->writeLine();
+ foreach($this->getControls() as $index=>$row)
+ {
+ if(($section=$row->getTableSection())===$currentSection)
+ {
+ if($index===0 && $currentSection===TTableRowSection::Header)
+ $writer->renderBeginTag('thead');
+ }
+ else
+ {
+ if($currentSection===TTableRowSection::Header)
+ {
+ if($index>0)
+ $writer->renderEndTag();
+ if($section===TTableRowSection::Body)
+ $writer->renderBeginTag('tbody');
+ else
+ $writer->renderBeginTag('tfoot');
+ $currentSection=$section;
+ }
+ else if($currentSection===TTableRowSection::Body)
+ {
+ $writer->renderEndTag();
+ if($section===TTableRowSection::Footer)
+ $writer->renderBeginTag('tfoot');
+ else
+ throw new TConfigurationException('table_tablesection_outoforder');
+ $currentSection=$section;
+ }
+ else // Footer
+ throw new TConfigurationException('table_tablesection_outoforder');
+ }
+ $row->renderControl($writer);
+ $writer->writeLine();
+ }
+ $writer->renderEndTag();
+ }
+ else
+ {
+ $writer->writeLine();
+ foreach($this->getControls() as $row)
+ {
+ $row->renderControl($writer);
+ $writer->writeLine();
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * TTableRowCollection class.
+ *
+ * TTableRowCollection is used to maintain a list of rows belong to a table.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTableRowCollection extends TControlCollection
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing additional
+ * operations for each newly added table row.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a TTableRow object.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TTableRow)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('tablerowcollection_tablerow_required');
+ }
+}
+
+
+/**
+ * TTableCaptionAlign class.
+ * TTableCaptionAlign defines the enumerable type for the possible alignments
+ * that a table caption can take.
+ *
+ * The following enumerable values are defined:
+ * - NotSet: alignment not specified
+ * - Top: top aligned
+ * - Bottom: bottom aligned
+ * - Left: left aligned
+ * - Right: right aligned
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TTableCaptionAlign extends TEnumerable
+{
+ const NotSet='NotSet';
+ const Top='Top';
+ const Bottom='Bottom';
+ const Left='Left';
+ const Right='Right';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TTableCell.php b/lib/prado/framework/Web/UI/WebControls/TTableCell.php
new file mode 100644
index 0000000..b0398d2
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TTableCell.php
@@ -0,0 +1,220 @@
+<?php
+/**
+ * TTableCell class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TTableCell class.
+ *
+ * TTableCell displays a table cell on a Web page. Content of the table cell
+ * is specified by the {@link setText Text} property. If {@link setText Text}
+ * is empty, the body contents enclosed by the table cell component tag are rendered.
+ * Note, {@link setText Text} is not HTML-encoded when displayed. So make sure
+ * it does not contain dangerous characters.
+ *
+ * The horizontal and vertical alignments of the contents in the cell
+ * are specified via {@link setHorizontalAlign HorizontalAlign} and
+ * {@link setVerticalAlign VerticalAlign} properties, respectively.
+ *
+ * The colspan and rowspan of the cell are specified via {@link setColumnSpan ColumnSpan}
+ * and {@link setRowSpan RowSpan} properties. And the {@link setWrap Wrap} property
+ * indicates whether the contents in the cell should be wrapped.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTableCell extends TWebControl implements IDataRenderer
+{
+ /**
+ * @return string tag name for the table cell
+ */
+ protected function getTagName()
+ {
+ return 'td';
+ }
+
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableItemStyle} to be used by the table cell.
+ * @return TStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableItemStyle;
+ }
+
+ /**
+ * @return string the horizontal alignment of the contents within the table item, defaults to 'NotSet'.
+ */
+ public function getHorizontalAlign()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getHorizontalAlign();
+ else
+ return 'NotSet';
+ }
+
+ /**
+ * Sets the horizontal alignment of the contents within the table item.
+ * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center'
+ * @param string the horizontal alignment
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->getStyle()->setHorizontalAlign($value);
+ }
+
+ /**
+ * @return string the vertical alignment of the contents within the table item, defaults to 'NotSet'.
+ */
+ public function getVerticalAlign()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getVerticalAlign();
+ else
+ return 'NotSet';
+ }
+
+ /**
+ * Sets the vertical alignment of the contents within the table item.
+ * Valid values include 'NotSet','Top','Bottom','Middle'
+ * @param string the horizontal alignment
+ */
+ public function setVerticalAlign($value)
+ {
+ $this->getStyle()->setVerticalAlign($value);
+ }
+
+ /**
+ * @return integer the columnspan for the table cell, 0 if not set.
+ */
+ public function getColumnSpan()
+ {
+ return $this->getViewState('ColumnSpan', 0);
+ }
+
+ /**
+ * Sets the columnspan for the table cell.
+ * @param integer the columnspan for the table cell, 0 if not set.
+ */
+ public function setColumnSpan($value)
+ {
+ $this->setViewState('ColumnSpan', TPropertyValue::ensureInteger($value), 0);
+ }
+
+ /**
+ * @return integer the rowspan for the table cell, 0 if not set.
+ */
+ public function getRowSpan()
+ {
+ return $this->getViewState('RowSpan', 0);
+ }
+
+ /**
+ * Sets the rowspan for the table cell.
+ * @param integer the rowspan for the table cell, 0 if not set.
+ */
+ public function setRowSpan($value)
+ {
+ $this->setViewState('RowSpan', TPropertyValue::ensureInteger($value), 0);
+ }
+
+ /**
+ * @return boolean whether the text content wraps within a table cell. Defaults to true.
+ */
+ public function getWrap()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getWrap();
+ else
+ return true;
+ }
+
+ /**
+ * Sets the value indicating whether the text content wraps within a table cell.
+ * @param boolean whether the text content wraps within a table cell.
+ */
+ public function setWrap($value)
+ {
+ $this->getStyle()->setWrap($value);
+ }
+
+ /**
+ * @return string the text content of the table cell.
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text content of the table cell.
+ * If the text content is empty, body content (child controls) of the cell will be rendered.
+ * @param string the text content
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * Returns the text content of the table cell.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string the text content of the table cell.
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the text content of the table cell.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string the text content of the table cell.
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ if(($colspan=$this->getColumnSpan())>0)
+ $writer->addAttribute('colspan',"$colspan");
+ if(($rowspan=$this->getRowSpan())>0)
+ $writer->addAttribute('rowspan',"$rowspan");
+ }
+
+ /**
+ * Renders body contents of the table cell.
+ * @param THtmlWriter the writer used for the rendering purpose.
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())!=='')
+ $writer->write($text);
+ else if($this->getHasControls())
+ parent::renderContents($writer);
+ else
+ $writer->write('&nbsp;');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TTableFooterRow.php b/lib/prado/framework/Web/UI/WebControls/TTableFooterRow.php
new file mode 100644
index 0000000..c3e8fe9
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TTableFooterRow.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * TTableFooterRow class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTableRow class.
+ */
+Prado::using('System.Web.UI.WebControls.TTableRow');
+
+/**
+ * TTableFooterRow class.
+ *
+ * TTableFooterRow displays a table footer row.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.1
+ */
+class TTableFooterRow extends TTableRow
+{
+ /**
+ * @return string location of a row in a table. Always returns 'Footer'.
+ */
+ public function getTableSection()
+ {
+ return 'Footer';
+ }
+
+ /**
+ * @param string location of a row in a table.
+ * @throws TInvalidOperationException if this method is invoked
+ */
+ public function setTableSection($value)
+ {
+ throw new TInvalidOperationException('tablefooterrow_tablesection_readonly');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TTableHeaderCell.php b/lib/prado/framework/Web/UI/WebControls/TTableHeaderCell.php
new file mode 100644
index 0000000..bb2953b
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TTableHeaderCell.php
@@ -0,0 +1,121 @@
+<?php
+/**
+ * TTableHeaderCell class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTableCell class
+ */
+Prado::using('System.Web.UI.WebControls.TTableCell');
+
+
+/**
+ * TTableHeaderCell class.
+ *
+ * TTableHeaderCell displays a table header cell on a Web page.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTableHeaderCell extends TTableCell
+{
+ /**
+ * @return string tag name for the table header cell
+ */
+ protected function getTagName()
+ {
+ return 'th';
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ if(($scope=$this->getScope())!==TTableHeaderScope::NotSet)
+ $writer->addAttribute('scope',$scope===TTableHeaderScope::Row?'row':'col');
+ if(($text=$this->getAbbreviatedText())!=='')
+ $writer->addAttribute('abbr',$text);
+ if(($text=$this->getCategoryText())!=='')
+ $writer->addAttribute('axis',$text);
+ }
+
+ /**
+ * @return TTableHeaderScope the scope of the cells that the header cell applies to. Defaults to TTableHeaderScope::NotSet.
+ */
+ public function getScope()
+ {
+ return $this->getViewState('Scope',TTableHeaderScope::NotSet);
+ }
+
+ /**
+ * @param TTableHeaderScope the scope of the cells that the header cell applies to.
+ */
+ public function setScope($value)
+ {
+ $this->setViewState('Scope',TPropertyValue::ensureEnum($value,'TTableHeaderScope'),TTableHeaderScope::NotSet);
+ }
+
+ /**
+ * @return string the abbr attribute of the HTML th element
+ */
+ public function getAbbreviatedText()
+ {
+ return $this->getViewState('AbbreviatedText','');
+ }
+
+ /**
+ * @param string the abbr attribute of the HTML th element
+ */
+ public function setAbbreviatedText($value)
+ {
+ $this->setViewState('AbbreviatedText',$value,'');
+ }
+
+ /**
+ * @return string the axis attribute of the HTML th element
+ */
+ public function getCategoryText()
+ {
+ return $this->getViewState('CategoryText','');
+ }
+
+ /**
+ * @param string the axis attribute of the HTML th element
+ */
+ public function setCategoryText($value)
+ {
+ $this->setViewState('CategoryText',$value,'');
+ }
+}
+
+
+/**
+ * TTableHeaderScope class.
+ * TTableHeaderScope defines the enumerable type for the possible table scopes that a table header is associated with.
+ *
+ * The following enumerable values are defined:
+ * - NotSet: the scope is not specified
+ * - Row: the scope is row-wise
+ * - Column: the scope is column-wise
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TTableHeaderScope extends TEnumerable
+{
+ const NotSet='NotSet';
+ const Row='Row';
+ const Column='Column';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TTableHeaderRow.php b/lib/prado/framework/Web/UI/WebControls/TTableHeaderRow.php
new file mode 100644
index 0000000..7eaedc3
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TTableHeaderRow.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * TTableHeaderRow class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTableRow class.
+ */
+Prado::using('System.Web.UI.WebControls.TTableRow');
+
+/**
+ * TTableHeaderRow class.
+ *
+ * TTableHeaderRow displays a table header row.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.1
+ */
+class TTableHeaderRow extends TTableRow
+{
+ /**
+ * @return string location of a row in a table. Always returns 'Header'.
+ */
+ public function getTableSection()
+ {
+ return 'Header';
+ }
+
+ /**
+ * @param string location of a row in a table.
+ * @throws TInvalidOperationException if this method is invoked
+ */
+ public function setTableSection($value)
+ {
+ throw new TInvalidOperationException('tableheaderrow_tablesection_readonly');
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TTableRow.php b/lib/prado/framework/Web/UI/WebControls/TTableRow.php
new file mode 100644
index 0000000..ebbe9df
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TTableRow.php
@@ -0,0 +1,204 @@
+<?php
+/**
+ * TTableRow and TTableCellCollection class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTableCell class
+ */
+Prado::using('System.Web.UI.WebControls.TTableCell');
+
+/**
+ * TTableRow class.
+ *
+ * TTableRow displays a table row. The table cells in the row can be accessed
+ * via {@link getCells Cells}. The horizontal and vertical alignments of the row
+ * are specified via {@link setHorizontalAlign HorizontalAlign} and
+ * {@link setVerticalAlign VerticalAlign} properties, respectively.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTableRow extends TWebControl
+{
+ /**
+ * @return string tag name for the table
+ */
+ protected function getTagName()
+ {
+ return 'tr';
+ }
+
+ /**
+ * Adds object parsed from template to the control.
+ * This method adds only {@link TTableCell} objects into the {@link getCells Cells} collection.
+ * All other objects are ignored.
+ * @param mixed object parsed from template
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TTableCell)
+ $this->getCells()->add($object);
+ }
+
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableItemStyle} to be used by the table row.
+ * @return TStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableItemStyle;
+ }
+
+ /**
+ * Creates a control collection object that is to be used to hold child controls
+ * @return TTableCellCollection control collection
+ * @see getControls
+ */
+ protected function createControlCollection()
+ {
+ return new TTableCellCollection($this);
+ }
+
+ /**
+ * @return TTableCellCollection list of {@link TTableCell} controls
+ */
+ public function getCells()
+ {
+ return $this->getControls();
+ }
+
+ /**
+ * @return string the horizontal alignment of the contents within the table item, defaults to 'NotSet'.
+ */
+ public function getHorizontalAlign()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getHorizontalAlign();
+ else
+ return 'NotSet';
+ }
+
+ /**
+ * Sets the horizontal alignment of the contents within the table item.
+ * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center'
+ * @param string the horizontal alignment
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->getStyle()->setHorizontalAlign($value);
+ }
+
+ /**
+ * @return string the vertical alignment of the contents within the table item, defaults to 'NotSet'.
+ */
+ public function getVerticalAlign()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getVerticalAlign();
+ else
+ return 'NotSet';
+ }
+
+ /**
+ * Sets the vertical alignment of the contents within the table item.
+ * Valid values include 'NotSet','Top','Bottom','Middle'
+ * @param string the horizontal alignment
+ */
+ public function setVerticalAlign($value)
+ {
+ $this->getStyle()->setVerticalAlign($value);
+ }
+
+ /**
+ * @return TTableRowSection location of a row in a table. Defaults to TTableRowSection::Body.
+ */
+ public function getTableSection()
+ {
+ return $this->getViewState('TableSection',TTableRowSection::Body);
+ }
+
+ /**
+ * @param TTableRowSection location of a row in a table.
+ */
+ public function setTableSection($value)
+ {
+ $this->setViewState('TableSection',TPropertyValue::ensureEnum($value,'TTableRowSection'),TTableRowSection::Body);
+ }
+
+ /**
+ * Renders body contents of the table row
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ if($this->getHasControls())
+ {
+ $writer->writeLine();
+ foreach($this->getControls() as $cell)
+ {
+ $cell->renderControl($writer);
+ $writer->writeLine();
+ }
+ }
+ }
+}
+
+/**
+ * TTableCellCollection class.
+ *
+ * TTableCellCollection is used to maintain a list of cells belong to a table row.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTableCellCollection extends TControlCollection
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing additional
+ * operations for each newly added table cell.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a TTableCell object.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TTableCell)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('tablecellcollection_tablecell_required');
+ }
+}
+
+
+/**
+ * TTableRowSection class.
+ * TTableRowSection defines the enumerable type for the possible table sections
+ * that a {@link TTableRow} can be within.
+ *
+ * The following enumerable values are defined:
+ * - Header: in table header
+ * - Body: in table body
+ * - Footer: in table footer
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TTableRowSection extends TEnumerable
+{
+ const Header='Header';
+ const Body='Body';
+ const Footer='Footer';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TTemplateColumn.php b/lib/prado/framework/Web/UI/WebControls/TTemplateColumn.php
new file mode 100644
index 0000000..b97b61f
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TTemplateColumn.php
@@ -0,0 +1,254 @@
+<?php
+/**
+ * TTemplateColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+
+/**
+ * TTemplateColumn class
+ *
+ * TTemplateColumn customizes the layout of controls in the column with templates.
+ * In particular, you can specify {@link setItemTemplate ItemTemplate},
+ * {@link setEditItemTemplate EditItemTemplate}, {@link setHeaderTemplate HeaderTemplate}
+ * and {@link setFooterTemplate FooterTemplate} to customize specific
+ * type of cells in the column.
+ *
+ * Since v3.1.0, TTemplateColumn has introduced two new properties {@link setItemRenderer ItemRenderer}
+ * and {@link setEditItemRenderer EditItemRenderer} which can be used to specify
+ * the layout of the datagrid cells in browsing and editing mode.
+ * A renderer refers to a control class that is to be instantiated as a control.
+ * For more details, see {@link TRepeater} and {@link TDataList}.
+ *
+ * When a renderer and a template are both defined for a type of item, the former
+ * takes precedence.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTemplateColumn extends TDataGridColumn
+{
+ /**
+ * Various item templates
+ * @var string
+ */
+ private $_itemTemplate=null;
+ private $_editItemTemplate=null;
+ private $_headerTemplate=null;
+ private $_footerTemplate=null;
+
+ /**
+ * @return string the class name for the item cell renderer. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getItemRenderer()
+ {
+ return $this->getViewState('ItemRenderer','');
+ }
+
+ /**
+ * Sets the item cell renderer class.
+ *
+ * If not empty, the class will be used to instantiate as a child control in the item cells of the column.
+ *
+ * If the class implements {@link IDataRenderer}, the <b>Data</b> property
+ * will be set as the row of the data associated with the datagrid item that this cell resides in.
+ *
+ * @param string the renderer class name in namespace format.
+ * @since 3.1.0
+ */
+ public function setItemRenderer($value)
+ {
+ $this->setViewState('ItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for the edit item cell renderer. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getEditItemRenderer()
+ {
+ return $this->getViewState('EditItemRenderer','');
+ }
+
+ /**
+ * Sets the edit item cell renderer class.
+ *
+ * If not empty, the class will be used to instantiate as a child control in the item cell that is in edit mode.
+ *
+ * If the class implements {@link IDataRenderer}, the <b>Data</b> property
+ * will be set as the row of the data associated with the datagrid item that this cell resides in.
+ *
+ * @param string the renderer class name in namespace format.
+ * @since 3.1.0
+ */
+ public function setEditItemRenderer($value)
+ {
+ $this->setViewState('EditItemRenderer',$value,'');
+ }
+
+ /**
+ * @return ITemplate the edit item template
+ */
+ public function getEditItemTemplate()
+ {
+ return $this->_editItemTemplate;
+ }
+
+ /**
+ * @param ITemplate the edit item template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setEditItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_editItemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('templatecolumn_template_required','EditItemTemplate');
+ }
+
+ /**
+ * @return ITemplate the item template
+ */
+ public function getItemTemplate()
+ {
+ return $this->_itemTemplate;
+ }
+
+ /**
+ * @param ITemplate the item template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_itemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('templatecolumn_template_required','ItemTemplate');
+ }
+
+ /**
+ * @return ITemplate the header template
+ */
+ public function getHeaderTemplate()
+ {
+ return $this->_headerTemplate;
+ }
+
+ /**
+ * @param ITemplate the header template.
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setHeaderTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_headerTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('templatecolumn_template_required','HeaderTemplate');
+ }
+
+ /**
+ * @return ITemplate the footer template
+ */
+ public function getFooterTemplate()
+ {
+ return $this->_footerTemplate;
+ }
+
+ /**
+ * @param ITemplate the footer template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setFooterTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_footerTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('templatecolumn_template_required','FooterTemplate');
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It initializes the cell based on different templates
+ * (ItemTemplate, EditItemTemplate, HeaderTemplate, FooterTemplate).
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
+ {
+ if($itemType===TListItemType::EditItem)
+ {
+ if(($classPath=$this->getEditItemRenderer())==='' && ($template=$this->_editItemTemplate)===null)
+ {
+ $classPath=$this->getItemRenderer();
+ $template=$this->_itemTemplate;
+ }
+ }
+ else
+ {
+ $template=$this->_itemTemplate;
+ $classPath=$this->getItemRenderer();
+ }
+ if($classPath!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ $cell->getControls()->add($control);
+ if($control instanceof IItemDataRenderer)
+ {
+ $control->setItemIndex($cell->getParent()->getItemIndex());
+ $control->setItemType($itemType);
+ }
+ if($control instanceof IDataRenderer)
+ $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ }
+ else if($template!==null)
+ $template->instantiateIn($cell);
+ else if($itemType!==TListItemType::EditItem)
+ $cell->setText('&nbsp;');
+ }
+ else if($itemType===TListItemType::Header)
+ {
+ if(($classPath=$this->getHeaderRenderer())!=='')
+ $this->initializeHeaderCell($cell,$columnIndex);
+ else if($this->_headerTemplate!==null)
+ $this->_headerTemplate->instantiateIn($cell);
+ else
+ $this->initializeHeaderCell($cell,$columnIndex);
+ }
+ else if($itemType===TListItemType::Footer)
+ {
+ if(($classPath=$this->getFooterRenderer())!=='')
+ $this->initializeFooterCell($cell,$columnIndex);
+ else if($this->_footerTemplate!==null)
+ $this->_footerTemplate->instantiateIn($cell);
+ else
+ $this->initializeFooterCell($cell,$columnIndex);
+ }
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $sender->setData($item->getData());
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TTextBox.php b/lib/prado/framework/Web/UI/WebControls/TTextBox.php
new file mode 100644
index 0000000..f3a0c16
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TTextBox.php
@@ -0,0 +1,648 @@
+<?php
+/**
+ * TTextBox class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TTextBox class
+ *
+ * TTextBox displays a text box on the Web page for user input.
+ * The text displayed in the TTextBox control is determined by the
+ * {@link setText Text} property. You can create a <b>SingleLine</b>,
+ * a <b>MultiLine</b>, or a <b>Password</b> text box by setting
+ * the {@link setTextMode TextMode} property. If the TTextBox control
+ * is a multiline text box, the number of rows it displays is determined
+ * by the {@link setRows Rows} property, and the {@link setWrap Wrap} property
+ * can be used to determine whether to wrap the text in the component.
+ *
+ * To specify the display width of the text box, in characters, set
+ * the {@link setColumns Columns} property. To prevent the text displayed
+ * in the component from being modified, set the {@link setReadOnly ReadOnly}
+ * property to true. If you want to limit the user input to a specified number
+ * of characters, set the {@link setMaxLength MaxLength} property.
+ * To use AutoComplete feature, set the {@link setAutoCompleteType AutoCompleteType} property.
+ *
+ * If {@link setAutoPostBack AutoPostBack} is set true, updating the text box
+ * and then changing the focus out of it will cause postback action.
+ * And if {@link setCausesValidation CausesValidation} is true, validation will
+ * also be processed, which can be further restricted within
+ * a {@link setValidationGroup ValidationGroup}.
+ *
+ * WARNING: Be careful if you want to display the text collected via TTextBox.
+ * Malicious cross-site script may be injected in. You may use {@link getSafeText SafeText}
+ * to prevent this problem.
+ *
+ * NOTE: If you set {@link setWrap Wrap} to false or use {@link setAutoCompleteType AutoCompleteType},
+ * the generated HTML output for the textbox will not be XHTML-compatible.
+ * Currently, no alternatives are available.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTextBox extends TWebControl implements IPostBackDataHandler, IValidatable, IDataRenderer
+{
+ /**
+ * Default number of rows (for MultiLine text box)
+ */
+ const DEFAULT_ROWS=4;
+ /**
+ * Default number of columns (for MultiLine text box)
+ */
+ const DEFAULT_COLUMNS=20;
+ /**
+ * @var mixed safe text parser
+ */
+ private static $_safeTextParser=null;
+ /**
+ * @var string safe textbox content with javascript stripped off
+ */
+ private $_safeText;
+ private $_dataChanged=false;
+ private $_isValid=true;
+
+ /**
+ * @return string tag name of the textbox
+ */
+ protected function getTagName()
+ {
+ return ($this->getTextMode()==='MultiLine')?'textarea':'input';
+ }
+
+ /**
+ * @return boolean whether to render javascript.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether to render javascript.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This method overrides the parent implementation with additional textbox specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $page=$this->getPage();
+ $page->ensureRenderInForm($this);
+ if(($uid=$this->getUniqueID())!=='')
+ $writer->addAttribute('name',$uid);
+ if(($textMode=$this->getTextMode())===TTextBoxMode::MultiLine)
+ {
+ if(($rows=$this->getRows())<=0)
+ $rows=self::DEFAULT_ROWS;
+ if(($cols=$this->getColumns())<=0)
+ $cols=self::DEFAULT_COLUMNS;
+ $writer->addAttribute('rows',"$rows");
+ $writer->addAttribute('cols',"$cols");
+ if(!$this->getWrap())
+ $writer->addAttribute('wrap','off');
+ }
+ else
+ {
+ if($textMode===TTextBoxMode::SingleLine)
+ {
+ $writer->addAttribute('type','text');
+ if(($text=$this->getText())!=='')
+ $writer->addAttribute('value',$text);
+ }
+ else
+ {
+ if($this->getPersistPassword() && ($text=$this->getText())!=='')
+ $writer->addAttribute('value',$text);
+ $writer->addAttribute('type','password');
+ }
+
+ if(($act=$this->getAutoCompleteType())!=='None')
+ {
+ if($act==='Disabled')
+ $writer->addAttribute('autocomplete','off');
+ else if($act==='Search')
+ $writer->addAttribute('vcard_name','search');
+ else if($act==='HomeCountryRegion')
+ $writer->addAttribute('vcard_name','HomeCountry');
+ else if($act==='BusinessCountryRegion')
+ $writer->addAttribute('vcard_name','BusinessCountry');
+ else
+ {
+ if(strpos($act,'Business')===0)
+ $act='Business'.'.'.substr($act,8);
+ else if(strpos($act,'Home')===0)
+ $act='Home'.'.'.substr($act,4);
+ $writer->addAttribute('vcard_name','vCard.'.$act);
+ }
+ }
+
+ if(($cols=$this->getColumns())>0)
+ $writer->addAttribute('size',"$cols");
+ if(($maxLength=$this->getMaxLength())>0)
+ $writer->addAttribute('maxlength',"$maxLength");
+ }
+ if($this->getReadOnly())
+ $writer->addAttribute('readonly','readonly');
+ $isEnabled=$this->getEnabled(true);
+ if(!$isEnabled && $this->getEnabled()) // in this case parent will not render 'disabled'
+ $writer->addAttribute('disabled','disabled');
+ if($isEnabled
+ && $this->getEnableClientScript()
+ && ( $this->getAutoPostBack() || $textMode===TTextBoxMode::SingleLine)
+ && $page->getClientSupportsJavaScript())
+ {
+ $this->renderClientControlScript($writer);
+ }
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the javascript for textbox.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TTextBox';
+ }
+
+ /**
+ * Gets the post back options for this textbox.
+ * @return array
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['AutoPostBack'] = $this->getAutoPostBack();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['TextMode'] = $this->getTextMode();
+ return $options;
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ $value=$values[$key];
+ if($this->getAutoTrim())
+ $value=trim($value);
+ if(!$this->getReadOnly() && $this->getText()!==$value)
+ {
+ $this->setText($value);
+ return $this->_dataChanged=true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * Raises <b>OnTextChanged</b> event.
+ * This method is invoked when the value of the {@link getText Text}
+ * property changes on postback.
+ * If you override this method, be sure to call the parent implementation to ensure
+ * the invocation of the attached event handlers.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onTextChanged($param)
+ {
+ $this->raiseEvent('OnTextChanged',$this,$param);
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method is required by {@link IPostBackDataHandler} interface.
+ * It is invoked by the framework when {@link getText Text} property
+ * is changed on postback.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ if($this->getAutoPostBack() && $this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onTextChanged(null);
+ }
+
+ /**
+ * Renders the body content of the textbox when it is in MultiLine text mode.
+ * @param THtmlWriter the writer for rendering
+ */
+ public function renderContents($writer)
+ {
+ if($this->getTextMode()==='MultiLine')
+ $writer->write(THttpUtility::htmlEncode($this->getText()));
+ }
+
+ /**
+ * Renders an additional line-break after the opening tag when it
+ * is in MultiLine text mode.
+ * @param THtmlWriter the writer used for the rendering purpose^M
+ */
+ public function renderBeginTag($writer)
+ {
+ parent::renderBeginTag($writer);
+ if($this->getTextMode()==='MultiLine')
+ $writer->write("\n");
+ }
+
+ /**
+ * @return TTextBoxAutoCompleteType the AutoComplete type of the textbox
+ */
+ public function getAutoCompleteType()
+ {
+ return $this->getViewState('AutoCompleteType',TTextBoxAutoCompleteType::None);
+ }
+
+ /**
+ * @param TTextBoxAutoCompleteType the AutoComplete type of the textbox, default value is TTextBoxAutoCompleteType::None.
+ * @throws TInvalidDataValueException if the input parameter is not a valid AutoComplete type
+ */
+ public function setAutoCompleteType($value)
+ {
+ $this->setViewState('AutoCompleteType',TPropertyValue::ensureEnum($value,'TTextBoxAutoCompleteType'),TTextBoxAutoCompleteType::None);
+ }
+
+ /**
+ * @return boolean a value indicating whether an automatic postback to the server
+ * will occur whenever the user modifies the text in the TTextBox control and
+ * then tabs out of the component. Defaults to false.
+ */
+ public function getAutoPostBack()
+ {
+ return $this->getViewState('AutoPostBack',false);
+ }
+
+ /**
+ * Sets the value indicating if postback automatically.
+ * An automatic postback to the server will occur whenever the user
+ * modifies the text in the TTextBox control and then tabs out of the component.
+ * @param boolean the value indicating if postback automatically
+ */
+ public function setAutoPostBack($value)
+ {
+ $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean a value indicating whether the input text should be trimmed spaces. Defaults to false.
+ */
+ public function getAutoTrim()
+ {
+ return $this->getViewState('AutoTrim',false);
+ }
+
+ /**
+ * Sets the value indicating if the input text should be trimmed spaces
+ * @param boolean the value indicating if the input text should be trimmed spaces
+ */
+ public function setAutoTrim($value)
+ {
+ $this->setViewState('AutoTrim',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether postback event trigger by this text box will cause input validation, default is true.
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by this text box will cause input validation.
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return integer the display width of the text box in characters, default is 0 meaning not set.
+ */
+ public function getColumns()
+ {
+ return $this->getViewState('Columns',0);
+ }
+
+ /**
+ * Sets the display width of the text box in characters.
+ * @param integer the display width, set it 0 to clear the setting
+ */
+ public function setColumns($value)
+ {
+ $this->setViewState('Columns',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return integer the maximum number of characters allowed in the text box, default is 0 meaning not set.
+ */
+ public function getMaxLength()
+ {
+ return $this->getViewState('MaxLength',0);
+ }
+
+ /**
+ * Sets the maximum number of characters allowed in the text box.
+ * @param integer the maximum length, set it 0 to clear the setting
+ */
+ public function setMaxLength($value)
+ {
+ $this->setViewState('MaxLength',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return boolean whether the textbox is read only, default is false.
+ */
+ public function getReadOnly()
+ {
+ return $this->getViewState('ReadOnly',false);
+ }
+
+ /**
+ * @param boolean whether the textbox is read only
+ */
+ public function setReadOnly($value)
+ {
+ $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return integer the number of rows displayed in a multiline text box, default is 4
+ */
+ public function getRows()
+ {
+ return $this->getViewState('Rows',self::DEFAULT_ROWS);
+ }
+
+ /**
+ * Sets the number of rows displayed in a multiline text box.
+ * @param integer the number of rows
+ */
+ public function setRows($value)
+ {
+ $this->setViewState('Rows',TPropertyValue::ensureInteger($value),self::DEFAULT_ROWS);
+ }
+
+ /**
+ * @return boolean whether password should be displayed in the textbox during postback. Defaults to false. This property only applies when TextMode='Password'.
+ */
+ public function getPersistPassword()
+ {
+ return $this->getViewState('PersistPassword',false);
+ }
+
+ /**
+ * @param boolean whether password should be displayed in the textbox during postback. This property only applies when TextMode='Password'.
+ */
+ public function setPersistPassword($value)
+ {
+ $this->setViewState('PersistPassword',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return string the text content of the TTextBox control.
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text content of the TTextBox control.
+ * @param string the text content
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ $this->_safeText = null;
+ }
+
+ /**
+ * Returns the text content of the TTextBox control.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string the text content of the TTextBox control.
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the text content of the TTextBox control.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string the text content of the TTextBox control.
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * @return string safe text content with javascript stripped off
+ */
+ public function getSafeText()
+ {
+ if($this->_safeText===null)
+ $this->_safeText=$this->getSafeTextParser()->parse($this->getText());
+ return $this->_safeText;
+ }
+
+ /**
+ * @return mixed safe text parser
+ */
+ protected function getSafeTextParser()
+ {
+ if(!self::$_safeTextParser)
+ self::$_safeTextParser=Prado::createComponent('System.3rdParty.SafeHtml.TSafeHtmlParser');
+ return self::$_safeTextParser;
+ }
+
+ /**
+ * @return TTextBoxMode the behavior mode of the TTextBox component. Defaults to TTextBoxMode::SingleLine.
+ */
+ public function getTextMode()
+ {
+ return $this->getViewState('TextMode',TTextBoxMode::SingleLine);
+ }
+
+ /**
+ * Sets the behavior mode of the TTextBox component.
+ * @param TTextBoxMode the text mode
+ * @throws TInvalidDataValueException if the input value is not a valid text mode.
+ */
+ public function setTextMode($value)
+ {
+ $this->setViewState('TextMode',TPropertyValue::ensureEnum($value,'TTextBoxMode'),TTextBoxMode::SingleLine);
+ }
+
+ /**
+ * @return string the group of validators which the text box causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the text box causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return boolean whether the text content wraps within a multiline text box. Defaults to true.
+ */
+ public function getWrap()
+ {
+ return $this->getViewState('Wrap',true);
+ }
+
+ /**
+ * Sets the value indicating whether the text content wraps within a multiline text box.
+ * @param boolean whether the text content wraps within a multiline text box.
+ */
+ public function setWrap($value)
+ {
+ $this->setViewState('Wrap',TPropertyValue::ensureBoolean($value),true);
+ }
+}
+
+/**
+ * TTextBoxMode class.
+ * TTextBoxMode defines the enumerable type for the possible mode
+ * that a {@link TTextBox} control could be at.
+ *
+ * The following enumerable values are defined:
+ * - SingleLine: the textbox will be a regular single line input
+ * - MultiLine: the textbox will be a textarea allowing multiple line input
+ * - Password: the textbox will hide user input like a password input box
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TTextBoxMode extends TEnumerable
+{
+ const SingleLine='SingleLine';
+ const MultiLine='MultiLine';
+ const Password='Password';
+}
+
+/**
+ * TTextBoxAutoCompleteType class.
+ * TTextBoxAutoCompleteType defines the possible AutoComplete type that is supported
+ * by a {@link TTextBox} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TTextBoxAutoCompleteType extends TEnumerable
+{
+ const BusinessCity='BusinessCity';
+ const BusinessCountryRegion='BusinessCountryRegion';
+ const BusinessFax='BusinessFax';
+ const BusinessPhone='BusinessPhone';
+ const BusinessState='BusinessState';
+ const BusinessStreetAddress='BusinessStreetAddress';
+ const BusinessUrl='BusinessUrl';
+ const BusinessZipCode='BusinessZipCode';
+ const Cellular='Cellular';
+ const Company='Company';
+ const Department='Department';
+ const Disabled='Disabled';
+ const DisplayName='DisplayName';
+ const Email='Email';
+ const FirstName='FirstName';
+ const Gender='Gender';
+ const HomeCity='HomeCity';
+ const HomeCountryRegion='HomeCountryRegion';
+ const HomeFax='HomeFax';
+ const Homepage='Homepage';
+ const HomePhone='HomePhone';
+ const HomeState='HomeState';
+ const HomeStreetAddress='HomeStreetAddress';
+ const HomeZipCode='HomeZipCode';
+ const JobTitle='JobTitle';
+ const LastName='LastName';
+ const MiddleName='MiddleName';
+ const None='None';
+ const Notes='Notes';
+ const Office='Office';
+ const Pager='Pager';
+ const Search='Search';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TTextHighlighter.php b/lib/prado/framework/Web/UI/WebControls/TTextHighlighter.php
new file mode 100644
index 0000000..6183851
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TTextHighlighter.php
@@ -0,0 +1,210 @@
+<?php
+/**
+ * TTextHighlighter class file
+ *
+ * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.3rdParty.TextHighlighter.Text.Highlighter',false);
+Prado::using('System.3rdParty.TextHighlighter.Text.Highlighter.Renderer.Html',false);
+Prado::using('System.Web.UI.WebControls.TTextProcessor');
+
+
+/**
+ * TTextHighlighter class.
+ *
+ * TTextHighlighter does syntax highlighting its body content, including
+ * static text and rendering results of child controls.
+ * You can set {@link setLanguage Language} to specify what kind of syntax
+ * the body content is. Currently, TTextHighlighter supports the following
+ * languages: ABAP, CPP, CSS, DIFF, DTD, HTML, JAVA, JAVASCRIPT, MYSQL, PERL,
+ * PHP, PYTHON, RUBY, SQL, XML and PRADO, where PRADO refers to PRADO template
+ * syntax. By setting {@link setShowLineNumbers ShowLineNumbers}
+ * to true, the highlighted result may be shown with line numbers.
+ *
+ * Note, TTextHighlighter requires {@link THead} to be placed on the page template
+ * because it needs to insert some CSS styles.
+ *
+ * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTextHighlighter extends TTextProcessor
+{
+ private static $_lineNumberStyle=array(TTextHighlighterLineNumberStyle::Li => HL_NUMBERS_LI, TTextHighlighterLineNumberStyle::Table => HL_NUMBERS_TABLE);
+
+ /**
+ * @return string tag name of the panel
+ */
+ protected function getTagName()
+ {
+ return 'div';
+ }
+
+ /**
+ * @return string language whose syntax is to be used for highlighting. Defaults to 'php'.
+ */
+ public function getLanguage()
+ {
+ return $this->getViewState('Language', 'php');
+ }
+
+ /**
+ * @param string language (case-insensitive) whose syntax is to be used for highlighting.
+ * Valid values are those file names (without suffix) that are contained
+ * in '3rdParty/TextHighlighter/Text/Highlighter'. Currently, the following languages are supported:
+ * ABAP, CPP, CSS, DIFF, DTD, HTML, JAVA, JAVASCRIPT,
+ * MYSQL, PERL, PHP, PRADO, PYTHON, RUBY, SQL, XML
+ * If a language is not supported, it will be displayed as plain text.
+ */
+ public function setLanguage($value)
+ {
+ $this->setViewState('Language', $value, 'php');
+ }
+
+ /**
+ * @return boolean whether to show line numbers in the highlighted result.
+ */
+ public function getShowLineNumbers()
+ {
+ return $this->getViewState('ShowLineNumbers', false);
+ }
+
+ /**
+ * @param boolean whether to show line numbers in the highlighted result.
+ */
+ public function setShowLineNumbers($value)
+ {
+ $this->setViewState('ShowLineNumbers', TPropertyValue::ensureBoolean($value), false);
+ }
+
+ /**
+ * @return boolean true will show "Copy Code" link. Defaults to false.
+ */
+ public function getEnableCopyCode()
+ {
+ return $this->getViewState('CopyCode', false);
+ }
+
+ /**
+ * @param boolean true to show the "Copy Code" link.
+ */
+ public function setEnableCopyCode($value)
+ {
+ $this->setViewState('CopyCode', TPropertyValue::ensureBoolean($value), false);
+ }
+
+ /**
+ * @return TTextHighlighterLineNumberStyle style of row number, Table by default
+ */
+ public function getLineNumberStyle()
+ {
+ return $this->getViewState('LineNumberStyle', TTextHighlighterLineNumberStyle::Table);
+ }
+
+ /**
+ * @param TTextHighlighterLineNumberStyle style of row number
+ */
+ public function setLineNumberStyle($value)
+ {
+ $this->setViewState('LineNumberStyle', TPropertyValue::ensureEnum($value,'TTextHighlighterLineNumberStyle'));
+ }
+
+ /**
+ * @return integer tab size. Defaults to 4.
+ */
+ public function getTabSize()
+ {
+ return $this->getViewState('TabSize', 4);
+ }
+
+ /**
+ * @param integer tab size
+ */
+ public function setTabSize($value)
+ {
+ $this->setViewState('TabSize', TPropertyValue::ensureInteger($value));
+ }
+
+ /**
+ * Registers css style for the highlighted result.
+ * This method overrides parent implementation.
+ * @param THtmlWriter writer
+ */
+ public function onPreRender($writer)
+ {
+ parent::onPreRender($writer);
+ $this->registerStyleSheet();
+ }
+
+ /**
+ * Registers the stylesheet for presentation.
+ */
+ protected function registerStyleSheet()
+ {
+ $cs=$this->getPage()->getClientScript();
+ $cssFile=Prado::getPathOfNamespace('System.3rdParty.TextHighlighter.highlight','.css');
+ $cssKey='prado:TTextHighlighter:'.$cssFile;
+ if(!$cs->isStyleSheetFileRegistered($cssKey))
+ $cs->registerStyleSheetFile($cssKey, $this->publishFilePath($cssFile));
+ }
+
+ /**
+ * Processes a text string.
+ * This method is required by the parent class.
+ * @param string text string to be processed
+ * @return string the processed text result
+ */
+ public function processText($text)
+ {
+ try
+ {
+ $highlighter=Text_Highlighter::factory($this->getLanguage());
+ }
+ catch(Exception $e)
+ {
+ $highlighter=false;
+ }
+ if($highlighter===false)
+ return ('<pre>'.htmlentities(trim($text)).'</pre>');
+
+ $options["use_language"]=true;
+ $options["tabsize"] = $this->getTabSize();
+ if ($this->getShowLineNumbers())
+ $options["numbers"] = self::$_lineNumberStyle[$this->getLineNumberStyle()];
+ $highlighter->setRenderer(new Text_Highlighter_Renderer_Html($options));
+ return $highlighter->highlight(trim($text));
+ }
+
+ /**
+ * @return string header template with "Copy code" link.
+ */
+ protected function getHeaderTemplate()
+ {
+ $id = $this->getClientID();
+ return TJavaScript::renderScriptBlock("new Prado.WebUI.TTextHighlighter('{$id}');");
+ }
+
+ public function render($writer)
+ {
+ $this->getPage()->getClientScript()->registerPradoScript('prado');
+ parent::render($writer);
+ }
+
+
+}
+
+/**
+ * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTextHighlighterLineNumberStyle extends TEnumerable
+{
+ const Li='Li';
+ const Table='Table';
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TTextProcessor.php b/lib/prado/framework/Web/UI/WebControls/TTextProcessor.php
new file mode 100644
index 0000000..c213a96
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TTextProcessor.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * TTextProcessor class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TTextProcessor class.
+ *
+ * TTextProcessor is the base class for classes that process or transform
+ * text content into different forms. The text content to be processed
+ * is specified by {@link setText Text} property. If it is not set, the body
+ * content enclosed within the processor control will be processed and rendered.
+ * The body content includes static text strings and the rendering result
+ * of child controls.
+ *
+ * Note, all child classes must implement {@link processText} method.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0.1
+ */
+abstract class TTextProcessor extends TWebControl
+{
+ /**
+ * Processes a text string.
+ * This method must be implemented by child classes.
+ * @param string text string to be processed
+ * @return string the processed text result
+ */
+ abstract public function processText($text);
+
+ /**
+ * HTML-decodes static text.
+ * This method overrides parent implementation.
+ * @param mixed object to be added as body content
+ */
+ public function addParsedObject($object)
+ {
+ if(is_string($object))
+ $object=html_entity_decode($object,ENT_QUOTES,'UTF-8');
+ parent::addParsedObject($object);
+ }
+
+ /**
+ * @return string text to be processed
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * @param string text to be processed
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value);
+ }
+
+ /**
+ * Renders body content.
+ * This method overrides the parent implementation by replacing
+ * the body content with the processed text content.
+ * @param THtmlWriter writer
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())==='' && $this->getHasControls())
+ {
+ $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter());
+ parent::renderContents($htmlWriter);
+ $text=$htmlWriter->flush();
+ }
+ if($text!=='')
+ $writer->write($this->processText($text));
+ }
+
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TValidationSummary.php b/lib/prado/framework/Web/UI/WebControls/TValidationSummary.php
new file mode 100644
index 0000000..2fbdba7
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TValidationSummary.php
@@ -0,0 +1,531 @@
+<?php
+/**
+ * TValidationSummary class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TValidationSummary class
+ *
+ * TValidationSummary displays a summary of validation errors inline on a Web page,
+ * in a message box, or both. By default, a validation summary will collect
+ * {@link TBaseValidator::getErrorMessage ErrorMessage} of all failed validators
+ * on the page. If {@link getValidationGroup ValidationGroup} is not
+ * empty, only those validators who belong to the group will show their error messages
+ * in the summary.
+ *
+ * The summary can be displayed as a list, as a bulleted list, or as a single
+ * paragraph based on the {@link setDisplayMode DisplayMode} property.
+ * The messages shown can be prefixed with {@link setHeaderText HeaderText}.
+ *
+ * The summary can be displayed on the Web page and in a message box by setting
+ * the {@link setShowSummary ShowSummary} and {@link setShowMessageBox ShowMessageBox}
+ * properties, respectively. Note, the latter is only effective when
+ * {@link setEnableClientScript EnableClientScript} is true.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TValidationSummary extends TWebControl
+{
+ /**
+ * @var TClientSideValidationSummaryOptions validation client side options.
+ */
+ private $_clientSide;
+
+ /**
+ * Constructor.
+ * This method sets the foreground color to red.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setForeColor('red');
+ }
+
+ /**
+ * @return TValidationSummaryDisplayStyle the style of displaying the error messages. Defaults to TValidationSummaryDisplayStyle::Fixed.
+ */
+ public function getDisplay()
+ {
+ return $this->getViewState('Display',TValidationSummaryDisplayStyle::Fixed);
+ }
+
+ /**
+ * @param TValidationSummaryDisplayStyle the style of displaying the error messages
+ */
+ public function setDisplay($value)
+ {
+ $this->setViewState('Display',TPropertyValue::ensureEnum($value,'TValidationSummaryDisplayStyle'),TValidationSummaryDisplayStyle::Fixed);
+ }
+
+ /**
+ * @return string the header text displayed at the top of the summary
+ */
+ public function getHeaderText()
+ {
+ return $this->getViewState('HeaderText','');
+ }
+
+ /**
+ * Sets the header text to be displayed at the top of the summary
+ * @param string the header text
+ */
+ public function setHeaderText($value)
+ {
+ $this->setViewState('HeaderText',$value,'');
+ }
+
+ /**
+ * @return TValidationSummaryDisplayMode the mode of displaying error messages. Defaults to TValidationSummaryDisplayMode::BulletList.
+ */
+ public function getDisplayMode()
+ {
+ return $this->getViewState('DisplayMode',TValidationSummaryDisplayMode::BulletList);
+ }
+
+ /**
+ * @param TValidationSummaryDisplayMode the mode of displaying error messages
+ */
+ public function setDisplayMode($value)
+ {
+ $this->setViewState('DisplayMode',TPropertyValue::ensureEnum($value,'TValidationSummaryDisplayMode'),TValidationSummaryDisplayMode::BulletList);
+ }
+
+ /**
+ * @return boolean whether the TValidationSummary component updates itself using client-side script. Defaults to true.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether the TValidationSummary component updates itself using client-side script.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the validation summary is displayed in a message box. Defaults to false.
+ */
+ public function getShowMessageBox()
+ {
+ return $this->getViewState('ShowMessageBox',false);
+ }
+
+ /**
+ * @param boolean whether the validation summary is displayed in a message box.
+ */
+ public function setShowMessageBox($value)
+ {
+ $this->setViewState('ShowMessageBox',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether the validation summary is displayed inline. Defaults to true.
+ */
+ public function getShowSummary()
+ {
+ return $this->getViewState('ShowSummary',true);
+ }
+
+ /**
+ * @param boolean whether the validation summary is displayed inline.
+ */
+ public function setShowSummary($value)
+ {
+ $this->setViewState('ShowSummary',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether scroll summary into viewport or not. Defaults to true.
+ */
+ public function getScrollToSummary()
+ {
+ return $this->getViewState('ScrollToSummary',true);
+ }
+
+ /**
+ * @param boolean whether scroll summary into viewport or not.
+ */
+ public function setScrollToSummary($value)
+ {
+ $this->setViewState('ScrollToSummary',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the validation summary should be anchored. Defaults to false.
+ */
+ public function getShowAnchor()
+ {
+ return $this->getViewState('ShowAnchor',false);
+ }
+
+ /**
+ * @param boolean whether the validation summary should be anchored.
+ */
+ public function setShowAnchor($value)
+ {
+ $this->setViewState('ShowAnchor',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Gets the auto-update for this summary.
+ * @return boolean automatic client-side summary updates. Defaults to true.
+ */
+ public function getAutoUpdate()
+ {
+ return $this->getViewState('AutoUpdate', true);
+ }
+
+ /**
+ * Sets the summary to auto-update on the client-side
+ * @param boolean true for automatic summary updates.
+ */
+ public function setAutoUpdate($value)
+ {
+ $this->setViewState('AutoUpdate', TPropertyValue::ensureBoolean($value), true);
+ }
+
+ /**
+ * @return string the group which this validator belongs to
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group which this validator belongs to
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ protected function addAttributesToRender($writer)
+ {
+ $display=$this->getDisplay();
+ $visible=$this->getEnabled(true) && count($this->getErrorMessages()) > 0;
+ if(!$visible)
+ {
+ if($display===TValidationSummaryDisplayStyle::None || $display===TValidationSummaryDisplayStyle::Dynamic)
+ $writer->addStyleAttribute('display','none');
+ else
+ $writer->addStyleAttribute('visibility','hidden');
+ }
+ $writer->addAttribute('id',$this->getClientID());
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Render the javascript for validation summary.
+ * @param array list of options for validation summary.
+ */
+ protected function renderJsSummary()
+ {
+ if(!$this->getEnabled(true) || !$this->getEnableClientScript())
+ return;
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPradoScript('validator');
+
+ //need to register the validation manager is validation summary is alone.
+ $formID=$this->getPage()->getForm()->getClientID();
+ $scriptKey = "TBaseValidator:$formID";
+ if($this->getEnableClientScript() && !$cs->isEndScriptRegistered($scriptKey))
+ {
+ $manager['FormID'] = $formID;
+ $options = TJavaScript::encode($manager);
+ $cs->registerPradoScript('validator');
+ $cs->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});");
+ }
+
+
+ $options=TJavaScript::encode($this->getClientScriptOptions());
+ $script = "new Prado.WebUI.TValidationSummary({$options});";
+ $cs->registerEndScript($this->getClientID(), $script);
+ }
+
+ /**
+ * Get a list of options for the client-side javascript validation summary.
+ * @return array list of options for the summary
+ */
+ protected function getClientScriptOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['FormID'] = $this->getPage()->getForm()->getClientID();
+ if($this->getShowMessageBox())
+ $options['ShowMessageBox']=true;
+ if(!$this->getShowSummary())
+ $options['ShowSummary']=false;
+
+ $options['ScrollToSummary']=$this->getScrollToSummary();
+ $options['HeaderText']=$this->getHeaderText();
+ $options['DisplayMode']=$this->getDisplayMode();
+
+ $options['Refresh'] = $this->getAutoUpdate();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['Display'] = $this->getDisplay();
+
+ if($this->_clientSide!==null)
+ $options = array_merge($options,$this->_clientSide->getOptions()->toArray());
+
+ return $options;
+ }
+
+ /**
+ * @return TClientSideValidationSummaryOptions client-side validation summary
+ * event options.
+ */
+ public function getClientSide()
+ {
+ if($this->_clientSide===null)
+ $this->_clientSide = $this->createClientScript();
+ return $this->_clientSide;
+ }
+
+ /**
+ * @return TClientSideValidationSummaryOptions javascript validation summary
+ * event options.
+ */
+ protected function createClientScript()
+ {
+ return new TClientSideValidationSummaryOptions;
+ }
+ /**
+ * Get the list of validation error messages.
+ * @return array list of validator error messages.
+ */
+ protected function getErrorMessages()
+ {
+ $validators=$this->getPage()->getValidators($this->getValidationGroup());
+ $messages = array();
+ foreach($validators as $validator)
+ {
+ if(!$validator->getIsValid() && ($msg=$validator->getErrorMessage())!=='')
+ //$messages[] = $validator->getAnchoredMessage($msg);
+ $messages[] = $msg;
+ }
+ return $messages;
+ }
+
+ /**
+ * Overrides parent implementation by rendering TValidationSummary-specific presentation.
+ * @return string the rendering result
+ */
+ public function renderContents($writer)
+ {
+ $this->renderJsSummary();
+ if($this->getShowSummary())
+ {
+// $this->setStyle('display:block');
+ switch($this->getDisplayMode())
+ {
+ case TValidationSummaryDisplayMode::SimpleList:
+ $this->renderList($writer);
+ break;
+ case TValidationSummaryDisplayMode::SingleParagraph:
+ $this->renderSingleParagraph($writer);
+ break;
+ case TValidationSummaryDisplayMode::BulletList:
+ $this->renderBulletList($writer);
+ break;
+ case TValidationSummaryDisplayMode::HeaderOnly:
+ $this->renderHeaderOnly($writer);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Render the validation summary as a simple list.
+ * @param array list of messages
+ * @param string the header text
+ * @return string summary list
+ */
+ protected function renderList($writer)
+ {
+ $header=$this->getHeaderText();
+ $messages=$this->getErrorMessages();
+ $content = '';
+ if(strlen($header))
+ $content.= $header."<br/>\n";
+ foreach($messages as $message)
+ $content.="$message<br/>\n";
+ $writer->write($content);
+ }
+
+ /**
+ * Render the validation summary as a paragraph.
+ * @param array list of messages
+ * @param string the header text
+ * @return string summary paragraph
+ */
+ protected function renderSingleParagraph($writer)
+ {
+ $header=$this->getHeaderText();
+ $messages=$this->getErrorMessages();
+ $content = $header;
+ foreach($messages as $message)
+ $content.= ' '.$message;
+ $writer->write($content);
+ }
+
+ /**
+ * Render the validation summary as a bullet list.
+ * @param array list of messages
+ * @param string the header text
+ * @return string summary bullet list
+ */
+ protected function renderBulletList($writer)
+ {
+ $header=$this->getHeaderText();
+ $messages=$this->getErrorMessages();
+ $content = $header;
+ if(count($messages)>0)
+ {
+ $content .= "<ul>\n";
+ foreach($messages as $message)
+ $content.= '<li>'.$message."</li>\n";
+ $content .= "</ul>\n";
+ }
+ $writer->write($content);
+ }
+
+ /**
+ * Render the validation summary header text only.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function renderHeaderOnly($writer)
+ {
+ $writer->write($this->getHeaderText());
+ }
+}
+
+/**
+ * TClientSideValidationSummaryOptions class.
+ *
+ * Client-side validation summary events such as {@link setOnHideSummary
+ * OnHideSummary} and {@link setOnShowSummary OnShowSummary} can be modified
+ * through the {@link TBaseValidator:: getClientSide ClientSide} property of a
+ * validation summary.
+ *
+ * The <tt>OnHideSummary</tt> event is raise when the validation summary
+ * requests to hide the messages.
+ *
+ * The <tt>OnShowSummary</tt> event is raised when the validation summary
+ * requests to show the messages.
+ *
+ * See the quickstart documentation for further details.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TClientSideValidationSummaryOptions extends TClientSideOptions
+{
+ /**
+ * @return string javascript code for client-side OnHideSummary event.
+ */
+ public function getOnHideSummary()
+ {
+ return $this->getOption('OnHideSummary');
+ }
+
+ /**
+ * Client-side OnHideSummary validation summary event is raise when all the
+ * validators are valid. This will override the default client-side
+ * validation summary behaviour.
+ * @param string javascript code for client-side OnHideSummary event.
+ */
+ public function setOnHideSummary($javascript)
+ {
+ $this->setFunction('OnHideSummary', $javascript);
+ }
+
+ /**
+ * Client-side OnShowSummary event is raise when one or more validators are
+ * not valid. This will override the default client-side validation summary
+ * behaviour.
+ * @param string javascript code for client-side OnShowSummary event.
+ */
+ public function setOnShowSummary($javascript)
+ {
+ $this->setFunction('OnShowSummary', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side OnShowSummary event.
+ */
+ public function getOnShowSummary()
+ {
+ return $this->getOption('OnShowSummary');
+ }
+
+ /**
+ * Ensure the string is a valid javascript function. The code block
+ * is enclosed with "function(summary, validators){ }" block.
+ * @param string javascript code.
+ * @return string javascript function code.
+ */
+ protected function ensureFunction($javascript)
+ {
+ return "function(summary, validators){ {$javascript} }";
+ }
+}
+
+
+/**
+ * TValidationSummaryDisplayMode class.
+ * TValidationSummaryDisplayMode defines the enumerable type for the possible modes
+ * that a {@link TValidationSummary} can organize and display the collected error messages.
+ *
+ * The following enumerable values are defined:
+ * - SimpleList: the error messages are displayed as a list without any decorations.
+ * - SingleParagraph: the error messages are concatenated together into a paragraph.
+ * - BulletList: the error messages are displayed as a bulleted list.
+ * - HeaderOnly: only the HeaderText will be display.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TValidationSummaryDisplayMode extends TEnumerable
+{
+ const SimpleList='SimpleList';
+ const SingleParagraph='SingleParagraph';
+ const BulletList='BulletList';
+ const HeaderOnly='HeaderOnly';
+}
+
+
+/**
+ * TValidationSummaryDisplay class.
+ * TValidationSummaryDisplay defines the enumerable type for the possible styles
+ * that a {@link TValidationSummary} can display the collected error messages.
+ *
+ * The following enumerable values are defined:
+ * - None: the error messages are not displayed
+ * - Dynamic: the error messages are dynamically added to display as the corresponding validators fail
+ * - Fixed: Similar to Dynamic except that the error messages physically occupy the page layout (even though they may not be visible)
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TValidationSummaryDisplayStyle extends TEnumerable
+{
+ const None='None';
+ const Dynamic='Dynamic';
+ const Fixed='Fixed';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TWebControl.php b/lib/prado/framework/Web/UI/WebControls/TWebControl.php
new file mode 100644
index 0000000..619cdd9
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TWebControl.php
@@ -0,0 +1,498 @@
+<?php
+/**
+ * TWebControl class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TStyle and TWebAdapter definition
+ */
+Prado::using('System.Web.UI.WebControls.TStyle');
+Prado::using('System.Web.UI.WebControls.TWebControlAdapter');
+Prado::using('System.Web.UI.WebControls.TWebControlDecorator');
+
+/**
+ * TWebControl class
+ *
+ * TWebControl is the base class for controls that share a common set
+ * of UI-related properties and methods. TWebControl-derived controls
+ * are usually associated with HTML tags. They thus have tag name, attributes
+ * and body contents. You can override {@link getTagName} to specify the tag name,
+ * {@link addAttributesToRender} to specify the attributes to be rendered,
+ * and {@link renderContents} to customize the body content rendering.
+ * TWebControl encapsulates a set of properties related with CSS style fields,
+ * such as {@link getBackColor BackColor}, {@link getBorderWidth BorderWidth}, etc.
+ *
+ * Subclasses of TWebControl typically needs to override {@link addAttributesToRender}
+ * and {@link renderContents}. The former is used to render the attributes
+ * of the HTML tag associated with the control, while the latter is to render
+ * the body contents enclosed within the HTML tag.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWebControl extends TControl implements IStyleable
+{
+ /**
+ * @var boolean ensures the inclusion the id in the tag rendering.
+ */
+ private $_ensureid=false;
+
+ /**
+ * @var TWebControlDecorator this render things before and after both the open and close tag
+ */
+ protected $_decorator;
+
+
+ /**
+ * Subclasses can override getEnsureId or just set this property. eg. If your subclass
+ * control does work with javascript and your class wants to flag that it requires an id
+ * to operate properly. Once set to true, it stays that way.
+ * @param boolean pass true to enable enforcement of the tag attribute id.
+ */
+ public function setEnsureId($value)
+ {
+ $this->_ensureid |= TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return whether this web control must have an id
+ */
+ public function getEnsureId()
+ {
+ return $this->_ensureid;
+ }
+
+ /**
+ * @return TWebControlDecorator
+ */
+ public function getDecorator($create=true)
+ {
+ if($create && !$this->_decorator)
+ $this->_decorator = Prado::createComponent('TWebControlDecorator', $this);
+ return $this->_decorator;
+ }
+
+ /**
+ * Copies basic control attributes from another control.
+ * Properties including AccessKey, ToolTip, TabIndex, Enabled
+ * and Attributes are copied.
+ * @param TWebControl source control
+ */
+ public function copyBaseAttributes(TWebControl $control)
+ {
+ $this->setAccessKey($control->getAccessKey());
+ $this->setToolTip($control->getToolTip());
+ $this->setTabIndex($control->getTabIndex());
+ if(!$control->getEnabled())
+ $this->setEnabled(false);
+ if($control->getHasAttributes())
+ $this->getAttributes()->copyFrom($control->getAttributes());
+ }
+
+ /**
+ * @return string the access key of the control
+ */
+ public function getAccessKey()
+ {
+ return $this->getViewState('AccessKey','');
+ }
+
+ /**
+ * Sets the access key of the control.
+ * Only one-character string can be set, or an exception will be raised.
+ * Pass in an empty string if you want to disable access key.
+ * @param string the access key to be set
+ * @throws TInvalidDataValueException if the access key is specified with more than one character
+ */
+ public function setAccessKey($value)
+ {
+ if(strlen($value)>1)
+ throw new TInvalidDataValueException('webcontrol_accesskey_invalid',get_class($this),$value);
+ $this->setViewState('AccessKey',$value,'');
+ }
+
+ /**
+ * @return string the background color of the control
+ */
+ public function getBackColor()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getBackColor();
+ else
+ return '';
+ }
+
+ /**
+ * @param string the background color of the control
+ */
+ public function setBackColor($value)
+ {
+ $this->getStyle()->setBackColor($value);
+ }
+
+ /**
+ * @return string the border color of the control
+ */
+ public function getBorderColor()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getBorderColor();
+ else
+ return '';
+ }
+
+ /**
+ * @param string the border color of the control
+ */
+ public function setBorderColor($value)
+ {
+ $this->getStyle()->setBorderColor($value);
+ }
+
+ /**
+ * @return string the border style of the control
+ */
+ public function getBorderStyle()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getBorderStyle();
+ else
+ return '';
+ }
+
+ /**
+ * @param string the border style of the control
+ */
+ public function setBorderStyle($value)
+ {
+ $this->getStyle()->setBorderStyle($value);
+ }
+
+ /**
+ * @return string the border width of the control
+ */
+ public function getBorderWidth()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getBorderWidth();
+ else
+ return '';
+ }
+
+ /**
+ * @param string the border width of the control
+ */
+ public function setBorderWidth($value)
+ {
+ $this->getStyle()->setBorderWidth($value);
+ }
+
+ /**
+ * @return TFont the font of the control
+ */
+ public function getFont()
+ {
+ return $this->getStyle()->getFont();
+ }
+
+ /**
+ * @return string the foreground color of the control
+ */
+ public function getForeColor()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getForeColor();
+ else
+ return '';
+ }
+
+ /**
+ * @param string the foreground color of the control
+ */
+ public function setForeColor($value)
+ {
+ $this->getStyle()->setForeColor($value);
+ }
+
+ /**
+ * @return string the height of the control
+ */
+ public function getHeight()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getHeight();
+ else
+ return '';
+ }
+
+ /**
+ * @param TDisplayStyle display style of the control, default is TDisplayStyle::Fixed
+ */
+ public function setDisplay($value)
+ {
+ $this->getStyle()->setDisplayStyle($value);
+ }
+
+ /**
+ * @return TDisplayStyle display style of the control, default is TDisplayStyle::Fixed
+ */
+ public function getDisplay()
+ {
+ return $this->getStyle()->getDisplayStyle();
+ }
+
+ /**
+ * @param string the css class of the control
+ */
+ public function setCssClass($value)
+ {
+ $this->getStyle()->setCssClass($value);
+ }
+
+ /**
+ * @return string the css class of the control
+ */
+ public function getCssClass()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getCssClass();
+ else
+ return '';
+ }
+
+ /**
+ * @param string the height of the control
+ */
+ public function setHeight($value)
+ {
+ $this->getStyle()->setHeight($value);
+ }
+
+ /**
+ * @return boolean whether the control has defined any style information
+ */
+ public function getHasStyle()
+ {
+ return $this->getViewState('Style',null)!==null;
+ }
+
+ /**
+ * Creates a style object to be used by the control.
+ * This method may be overriden by controls to provide customized style.
+ * @return TStyle the default style created for TWebControl
+ */
+ protected function createStyle()
+ {
+ return new TStyle;
+ }
+
+ /**
+ * @return TStyle the object representing the css style of the control
+ */
+ public function getStyle()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style;
+ else
+ {
+ $style=$this->createStyle();
+ $this->setViewState('Style',$style,null);
+ return $style;
+ }
+ }
+
+ /**
+ * Sets the css style string of the control.
+ * The style string will be prefixed to the styles set via other control properties (e.g. Height, Width).
+ * @param string the css style string
+ * @throws TInvalidDataValueException if the parameter is not a string
+ */
+ public function setStyle($value)
+ {
+ if(is_string($value))
+ $this->getStyle()->setCustomStyle($value);
+ else
+ throw new TInvalidDataValueException('webcontrol_style_invalid',get_class($this));
+ }
+
+ /**
+ * Removes all style data.
+ */
+ public function clearStyle()
+ {
+ $this->clearViewState('Style');
+ }
+
+ /**
+ * @return integer the tab index of the control
+ */
+ public function getTabIndex()
+ {
+ return $this->getViewState('TabIndex',0);
+ }
+
+ /**
+ * Sets the tab index of the control.
+ * Pass 0 if you want to disable tab index.
+ * @param integer the tab index to be set
+ */
+ public function setTabIndex($value)
+ {
+ $this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * Returns the tag name used for this control.
+ * By default, the tag name is 'span'.
+ * You can override this method to provide customized tag names.
+ * @return string tag name of the control to be rendered
+ */
+ protected function getTagName()
+ {
+ return 'span';
+ }
+
+ /**
+ * @return string the tooltip of the control
+ */
+ public function getToolTip()
+ {
+ return $this->getViewState('ToolTip','');
+ }
+
+ /**
+ * Sets the tooltip of the control.
+ * Pass an empty string if you want to disable tooltip.
+ * @param string the tooltip to be set
+ */
+ public function setToolTip($value)
+ {
+ $this->setViewState('ToolTip',$value,'');
+ }
+
+ /**
+ * @return string the width of the control
+ */
+ public function getWidth()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style->getWidth();
+ else
+ return '';
+ }
+
+ /**
+ * @param string the width of the control
+ */
+ public function setWidth($value)
+ {
+ $this->getStyle()->setWidth($value);
+ }
+
+
+ /**
+ * If your subclass overrides the onPreRender method be sure to call
+ * this method through parent::onPreRender($param); so your sub-class can be decorated,
+ * among other things.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onPreRender($param) {
+ if($decorator = $this->getDecorator(false))
+ $decorator->instantiate();
+
+ parent::onPreRender($param);
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * By default, the method will render 'id', 'accesskey', 'disabled',
+ * 'tabindex', 'title' and all custom attributes.
+ * The method can be overriden to provide customized attribute rendering.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ if($this->getID()!=='' || $this->getEnsureId())
+ $writer->addAttribute('id',$this->getClientID());
+ if(($accessKey=$this->getAccessKey())!=='')
+ $writer->addAttribute('accesskey',$accessKey);
+ if(!$this->getEnabled())
+ $writer->addAttribute('disabled','disabled');
+ if(($tabIndex=$this->getTabIndex())>0)
+ $writer->addAttribute('tabindex',"$tabIndex");
+ if(($toolTip=$this->getToolTip())!=='')
+ $writer->addAttribute('title',$toolTip);
+ if($style=$this->getViewState('Style',null))
+ $style->addAttributesToRender($writer);
+ if($this->getHasAttributes())
+ {
+ foreach($this->getAttributes() as $name=>$value)
+ $writer->addAttribute($name,$value);
+ }
+ }
+
+ /**
+ * Renders the control.
+ * This method overrides the parent implementation by replacing it with
+ * the following sequence:
+ * - {@link renderBeginTag}
+ * - {@link renderContents}
+ * - {@link renderEndTag}
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ $this->renderBeginTag($writer);
+ $this->renderContents($writer);
+ $this->renderEndTag($writer);
+ }
+
+ /**
+ * Renders the openning tag for the control (including attributes)
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderBeginTag($writer)
+ {
+ if($decorator = $this->getDecorator(false)) {
+ $decorator->renderPreTagText($writer);
+ $this->addAttributesToRender($writer);
+ $writer->renderBeginTag($this->getTagName());
+ $decorator->renderPreContentsText($writer);
+ } else {
+ $this->addAttributesToRender($writer);
+ $writer->renderBeginTag($this->getTagName());
+ }
+ }
+
+ /**
+ * Renders the body content enclosed between the control tag.
+ * By default, child controls and text strings will be rendered.
+ * You can override this method to provide customized content rendering.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ parent::renderChildren($writer);
+ }
+
+ /**
+ * Renders the closing tag for the control
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderEndTag($writer)
+ {
+ if($decorator = $this->getDecorator(false)) {
+ $decorator->renderPostContentsText($writer);
+ $writer->renderEndTag();
+ $decorator->renderPostTagText($writer);
+ } else
+ $writer->renderEndTag($writer);
+ }
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TWebControlAdapter.php b/lib/prado/framework/Web/UI/WebControls/TWebControlAdapter.php
new file mode 100644
index 0000000..50da857
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TWebControlAdapter.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * TWebControlAdapter class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TWebControlAdapter class
+ *
+ * TWebControlAdapter is the base class for adapters that customize
+ * rendering for the Web control to which the adapter is attached.
+ * It may be used to modify the default markup or behavior for specific
+ * browsers.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWebControlAdapter extends TControlAdapter
+{
+ /**
+ * Renders the control to which the adapter is attached.
+ * It calls {@link renderBeginTag}, {@link renderContents} and
+ * {@link renderEndTag} in order.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+ $this->renderBeginTag($writer);
+ $this->renderContents($writer);
+ $this->renderEndTag($writer);
+ }
+
+ /**
+ * Renders the openning tag for the attached control.
+ * Default implementation calls the attached control's corresponding method.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderBeginTag($writer)
+ {
+ $this->getControl()->renderBeginTag($writer);
+ }
+
+ /**
+ * Renders the body contents within the attached control tag.
+ * Default implementation calls the attached control's corresponding method.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ $this->getControl()->renderContents($writer);
+ }
+
+ /**
+ * Renders the closing tag for the attached control.
+ * Default implementation calls the attached control's corresponding method.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderEndTag($writer)
+ {
+ $this->getControl()->renderEndTag($writer);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TWebControlDecorator.php b/lib/prado/framework/Web/UI/WebControls/TWebControlDecorator.php
new file mode 100644
index 0000000..07c7836
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TWebControlDecorator.php
@@ -0,0 +1,382 @@
+<?php
+/**
+ * TWebControlDecorator class file.
+ *
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+
+/**
+ * TWebControlDecorator class
+ *
+ * A TWebControlDecorator can be applied to a {@link TWebControl} to customize its rendering.
+ * TWebControlDecorator can add custom html code before and after both the open and close
+ * tag of a {@link TWebControl}.
+ * The html code can be an user-defined text or an external template file that will be
+ * instantiated and rendered in place.
+ *
+ * This is an easy way to have your look and feel depend upon the theme instead of writing
+ * specific html in your templates to achieve your website desires.
+ * Here is an example of how to code your theme skin:
+ * <code>
+ * <com:THeader3>
+ * <prop:Decorator.PreTagText>
+ * <!-- Surround the control with a div and apply a css class to it -->
+ * <div class="imported-theme-h3-container">
+ * </prop:Decorator.PreTagText>
+ * <prop:Decorator.PostTagText>
+ * <!-- Properly close the tag -->
+ * </div>
+ * </prop:Decorator.PostTagText>
+ * </com:THeader3>
+ * </code>
+ *
+ * The order of the inclusion of the decoration into the page goes like this:
+ * * PreTagTemplate
+ * * PreTagText
+ * * TWebControl Open Tag Rendered
+ * * PreContentsText
+ * * PreContentsTemplate
+ * * TWebControl Children Rendered
+ * * PostContentsTemplate
+ * * PostContentsText
+ * * TWebControl CloseTag Rendered
+ * * PostTagText
+ * * PostTagTemplate
+ *
+ *
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+
+class TWebControlDecorator extends TComponent {
+
+ /**
+ * @var boolean tells if there should only be decoration around the inner content
+ */
+ private $_internalonly;
+
+ /**
+ * @var boolean tells if the decoration uses state in its templates. If there are no templates
+ * in the instance of the decoration this variable is unused.
+ */
+ private $_usestate = false;
+
+ /**
+ * @var TWebControl the control to decorate
+ */
+ private $_control;
+
+ /**
+ * @var TControl to tell the decorator where to place the outer controls
+ */
+ private $_outercontrol;
+
+ /**
+ * @var boolean This tells if the Templates have been
+ */
+ private $_addedTemplateDecoration=false;
+
+
+ /**
+ * @var string the text that goes before the open tag
+ */
+ private $_pretagtext = '';
+ /**
+ * @var string the text that goes after the open tag
+ */
+ private $_precontentstext = '';
+ /**
+ * @var string the text that goes before the close tag
+ */
+ private $_postcontentstext = '';
+ /**
+ * @var string the text that goes after the close tag
+ */
+ private $_posttagtext = '';
+
+
+
+ /**
+ * @var TTemplate the template that goes before the open tag
+ */
+ private $_pretagtemplate;
+ /**
+ * @var TTemplate the template that goes after the open tag
+ */
+ private $_precontentstemplate;
+ /**
+ * @var TTemplate the template that goes before the close tag
+ */
+ private $_postcontentstemplate;
+ /**
+ * @var TTemplate the template that goes after the close tag
+ */
+ private $_posttagtemplate;
+
+ /**
+ * Constructor.
+ * Initializes the control .
+ * @param TWebControl The control that is to be decorated.
+ * @param boolean whether decoration is just around the inner content
+ */
+ public function __construct($control, $onlyinternal = false) {
+ $this->_control = $control;
+ $this->_internalonly = $onlyinternal;
+ }
+
+ /**
+ * @return boolean if the templates in this decoration need state. This defaults to false
+ */
+ public function getUseState()
+ {
+ return $this->_usestate;
+ }
+
+ /**
+ * @param boolean $value true to tell the decoration that the templates need state and should be
+ * placed in a control step before the state is saved.
+ */
+ public function setUseState($value)
+ {
+ $this->_usestate = TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return string gets the text before the open tag in the TWebControl
+ */
+ public function getPreTagText() {
+ return $this->_pretagtext;
+ }
+
+ /**
+ * @param string sets the text before the open tag in the TWebControl
+ */
+ public function setPreTagText($value) {
+ if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
+ $this->_pretagtext = TPropertyValue::ensureString($value);
+ }
+
+
+ /**
+ * @return string the text after the open tag in the TWebControl
+ */
+ public function getPreContentsText() {
+ return $this->_precontentstext;
+ }
+
+ /**
+ * @param string sets the text after the open tag in the TWebControl
+ */
+ public function setPreContentsText($value) {
+ if(!$this->_control->getIsSkinApplied())
+ $this->_precontentstext = TPropertyValue::ensureString($value);
+ }
+
+
+ /**
+ * @return string the text before the close tag in the TWebControl
+ */
+ public function getPostContentsText() {
+ return $this->_postcontentstext;
+ }
+
+ /**
+ * @param string sets the text before the close tag in the TWebControl
+ */
+ public function setPostContentsText($value) {
+ if(!$this->_control->getIsSkinApplied())
+ $this->_postcontentstext = TPropertyValue::ensureString($value);
+ }
+
+
+ /**
+ * @return string the text before the close tag in the TWebControl
+ */
+ public function getPostTagText() {
+ return $this->_posttagtext;
+ }
+
+ /**
+ * @param string sets the text after the close tag in the TWebControl
+ */
+ public function setPostTagText($value) {
+ if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
+ $this->_posttagtext = TPropertyValue::ensureString($value);
+ }
+
+
+ /**
+ * @return TTemplate|null the template before the open tag in the TWebControl. Defaults to null.
+ */
+ public function getPreTagTemplate() {
+ return $this->_pretagtemplate;
+ }
+
+ /**
+ * @param TTemplate sets the template before the open tag in the TWebControl
+ */
+ public function setPreTagTemplate($value) {
+ if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
+ $this->_pretagtemplate = $value;
+ }
+
+
+ /**
+ * @return TTemplate|null the template after the open tag in the TWebControl. Defaults to null.
+ */
+ public function getPreContentsTemplate() {
+ return $this->_precontentstemplate;
+ }
+
+ /**
+ * @param TTemplate sets the template after the open tag in the TWebControl
+ */
+ public function setPreContentsTemplate($value) {
+ if(!$this->_control->getIsSkinApplied())
+ $this->_precontentstemplate = $value;
+ }
+
+
+ /**
+ * @return TTemplate|null the template before the close tag in the TWebControl. Defaults to null.
+ */
+ public function getPostContentsTemplate() {
+ return $this->_postcontentstemplate;
+ }
+
+ /**
+ * @param TTemplate sets the template before the close tag in the TWebControl
+ */
+ public function setPostContentsTemplate($value) {
+ if(!$this->_control->getIsSkinApplied())
+ $this->_postcontentstemplate = $value;
+ }
+
+
+ /**
+ * @return TTemplate|null the template after the close tag in the TWebControl. Defaults to null.
+ */
+ public function getPostTagTemplate() {
+ return $this->_posttagtemplate;
+ }
+
+ /**
+ * @param TTemplate sets the template before the close tag in the TWebControl
+ */
+ public function setPostTagTemplate($value) {
+ if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
+ $this->_posttagtemplate = $value;
+ }
+
+ /**
+ * this is a framework call. The Text decoration can't
+ * influence the object hierarchy because they are rendered into into the writer directly.
+ * This call attaches the ensureTemplateDecoration to the TPage onSaveStateComplete so
+ * these controls don't have page states. This is as close to not influencing the page as possible.
+ */
+ public function instantiate($outercontrol = null) {
+ if($this->getPreTagTemplate() || $this->getPreContentsTemplate() ||
+ $this->getPostContentsTemplate() || $this->getPostTagTemplate()) {
+
+ $this->_outercontrol = $outercontrol;
+ if($this->getUseState())
+ $this->ensureTemplateDecoration();
+ else
+ $this->_control->getPage()->onSaveStateComplete[] = array($this, 'ensureTemplateDecoration');
+ }
+ }
+
+
+ /**
+ * This method places the templates around the open and close tag. This takes a parameter which is
+ * to specify the control to get the outer template decoration. If no outer control is specified
+ * @param TComponent this indicates the component or control to get the outer tag elements, just in case it's
+ * different than attached TWebControl. If none is provided, the outer templates default to the attached
+ * control
+ * @return boolean returns true if the template decorations have been added
+ */
+ public function ensureTemplateDecoration($sender=null, $param=null) {
+
+ $control = $this->_control;
+ $outercontrol = $this->_outercontrol;
+ if($outercontrol === null)
+ $outercontrol = $control;
+
+ if($this->_addedTemplateDecoration)
+ return $this->_addedTemplateDecoration;
+
+ $this->_addedTemplateDecoration = true;
+
+ if($this->getPreContentsTemplate())
+ {
+ $precontents = Prado::createComponent('TCompositeControl');
+ $this->getPreContentsTemplate()->instantiateIn($precontents);
+ $control->getControls()->insertAt(0, $precontents);
+ }
+
+ if($this->getPostContentsTemplate())
+ {
+ $postcontents = Prado::createComponent('TCompositeControl');
+ $this->getPostContentsTemplate()->instantiateIn($postcontents);
+ $control->getControls()->add($postcontents);
+ }
+
+ if(!$outercontrol->getParent())
+ return $this->_addedTemplateDecoration;
+
+
+ if($this->getPreTagTemplate())
+ {
+ $pretag = Prado::createComponent('TCompositeControl');
+ $this->getPreTagTemplate()->instantiateIn($pretag);
+ $outercontrol->getParent()->getControls()->insertBefore($outercontrol, $pretag);
+ }
+
+ if($this->getPostTagTemplate())
+ {
+ $posttag = Prado::createComponent('TCompositeControl');
+ $this->getPostTagTemplate()->instantiateIn($posttag);
+ $outercontrol->getParent()->getControls()->insertAfter($outercontrol, $posttag);
+ }
+ return true;
+ }
+
+
+ /**
+ * This method places the pre tag text into the {@link TTextWriter}
+ * @param {@link TTextWriter} the writer to which the text is written
+ */
+ public function renderPreTagText($writer) {
+ $writer->write($this->getPreTagText());
+ }
+
+ /**
+ * This method places the pre contents text into the {@link TTextWriter}
+ * @param {@link TTextWriter} the writer to which the text is written
+ */
+ public function renderPreContentsText($writer) {
+ $writer->write($this->getPreContentsText());
+ }
+
+ /**
+ * This method places the post contents text into the {@link TTextWriter}
+ * @param {@link TTextWriter} the writer to which the text is written
+ */
+ public function renderPostContentsText($writer) {
+ $writer->write($this->getPostContentsText());
+ }
+
+ /**
+ * This method places the post tag text into the {@link TTextWriter}
+ * @param {@link TTextWriter} the writer to which the text is written
+ */
+ public function renderPostTagText($writer) {
+ $writer->write($this->getPostTagText());
+ }
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/TWizard.php b/lib/prado/framework/Web/UI/WebControls/TWizard.php
new file mode 100644
index 0000000..bacb637
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TWizard.php
@@ -0,0 +1,2145 @@
+<?php
+/**
+ * TWizard and the relevant class definitions.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TMultiView');
+Prado::using('System.Web.UI.WebControls.TPanel');
+Prado::using('System.Web.UI.WebControls.TButton');
+Prado::using('System.Web.UI.WebControls.TLinkButton');
+Prado::using('System.Web.UI.WebControls.TImageButton');
+Prado::using('System.Web.UI.WebControls.TDataList');
+Prado::using('System.Web.UI.WebControls.TWizardNavigationButtonStyle');
+
+/**
+ * Class TWizard.
+ *
+ * TWizard splits a large form and presents the user with a series of smaller
+ * forms to complete. TWizard is analogous to the installation wizard commonly
+ * used to install software in Windows.
+ *
+ * The smaller forms are called wizard steps ({@link TWizardStep}, which can be accessed via
+ * {@link getWizardSteps WizardSteps}. In template, wizard steps can be added
+ * into a wizard using the following syntax,
+ * <code>
+ * <com:TWizard>
+ * <com:TWizardStep Title="step 1">
+ * content in step 1, may contain other controls
+ * </com:TWizardStep>
+ * <com:TWizardStep Title="step 2">
+ * content in step 2, may contain other controls
+ * </com:TWizardStep>
+ * </com:TWizard>
+ * </code>
+ *
+ * Each wizard step can be one of the following types:
+ * - Start : the first step in the wizard.
+ * - Step : the internal steps in the wizard.
+ * - Finish : the last step that allows user interaction.
+ * - Complete : the step that shows a summary to user (no interaction is allowed).
+ * - Auto : the step type is determined by wizard automatically.
+ * At any time, only one step is visible to end-users, which can be obtained
+ * by {@link getActiveStep ActiveStep}. Its index in the step collection is given by
+ * {@link getActiveStepIndex ActiveStepIndex}.
+ *
+ * Wizard content can be customized in many ways.
+ *
+ * The layout of a wizard consists of four parts: header, step content, navigation
+ * and side bar. Their content are affected by the following properties, respectively,
+ * - header: {@link setHeaderText HeaderText} and {@link setHeaderTemplate HeaderTemplate}.
+ * If both are present, the latter takes precedence.
+ * - step: {@link getWizardSteps WizardSteps}.
+ * - navigation: {@link setStartNavigationTemplate StartNavigationTemplate},
+ * {@link setStepNavigationTemplate StepNavigationTemplate},
+ * {@link setFinishNavigationTemplate FinishNavigationTemplate}.
+ * Default templates will be used if above templates are not set.
+ * - side bar: {@link setSideBarTemplate SideBarTemplate}.
+ * A default template will be used if this template is not set.
+ * Its visibility is toggled by {@link setShowSideBar ShowSideBar}.
+ *
+ * The style of these wizard layout components can be customized via the following style properties,
+ * - header: {@link getHeaderStyle HeaderStyle}.
+ * - step: {@link getStepStyle StepStyle}.
+ * - navigation: {@link getNavigationStyle NavigationStyle},
+ * {@link getStartNextButtonStyle StartNextButtonStyle},
+ * {@link getStepNextButtonStyle StepNextButtonStyle},
+ * {@link getStepPreviousButtonStyle StepPreviousButtonStyle},
+ * {@link getFinishPreviousButtonStyle FinishPreviousButtonStyle},
+ * {@link getFinishCompleteButtonStyle FinishCompleteButtonStyle},
+ * {@link getCancelButtonStyle CancelButtonStyle}.
+ * - side bar: {@link getSideBarStyle SideBarStyle} and {@link getSideBarButtonStyle SideBarButtonStyle}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizard extends TWebControl implements INamingContainer
+{
+ /**
+ * Wizard step types.
+ * @deprecated deprecated since version 3.0.4 (use TWizardStepType constants instead)
+ */
+ const ST_AUTO='Auto';
+ const ST_START='Start';
+ const ST_STEP='Step';
+ const ST_FINISH='Finish';
+ const ST_COMPLETE='Complete';
+ /**
+ * Navigation commands.
+ */
+ const CMD_PREVIOUS='PreviousStep';
+ const CMD_NEXT='NextStep';
+ const CMD_CANCEL='Cancel';
+ const CMD_COMPLETE='Complete';
+ const CMD_MOVETO='MoveTo';
+ /**
+ * Side bar button ID
+ */
+ const ID_SIDEBAR_BUTTON='SideBarButton';
+ /**
+ * Side bar data list
+ */
+ const ID_SIDEBAR_LIST='SideBarList';
+
+ /**
+ * @var TMultiView multiview that contains the wizard steps
+ */
+ private $_multiView=null;
+ /**
+ * @var mixed navigation template for the start step.
+ */
+ private $_startNavigationTemplate=null;
+ /**
+ * @var mixed navigation template for internal steps.
+ */
+ private $_stepNavigationTemplate=null;
+ /**
+ * @var mixed navigation template for the finish step.
+ */
+ private $_finishNavigationTemplate=null;
+ /**
+ * @var mixed template for wizard header.
+ */
+ private $_headerTemplate=null;
+ /**
+ * @var mixed template for the side bar.
+ */
+ private $_sideBarTemplate=null;
+ /**
+ * @var TWizardStepCollection
+ */
+ private $_wizardSteps=null;
+ /**
+ * @var TPanel container of the wizard header
+ */
+ private $_header;
+ /**
+ * @var TPanel container of the wizard step content
+ */
+ private $_stepContent;
+ /**
+ * @var TPanel container of the wizard side bar
+ */
+ private $_sideBar;
+ /**
+ * @var TPanel navigation panel
+ */
+ private $_navigation;
+ /**
+ * @var TWizardNavigationContainer container of the start navigation
+ */
+ private $_startNavigation;
+ /**
+ * @var TWizardNavigationContainer container of the step navigation
+ */
+ private $_stepNavigation;
+ /**
+ * @var TWizardNavigationContainer container of the finish navigation
+ */
+ private $_finishNavigation;
+ /**
+ * @var boolean whether ActiveStepIndex was already set
+ */
+ private $_activeStepIndexSet=false;
+ /**
+ * @var TDataList side bar data list.
+ */
+ private $_sideBarDataList;
+ /**
+ * @var boolean whether navigation should be cancelled (a status set in OnSideBarButtonClick)
+ */
+ private $_cancelNavigation=false;
+
+ /**
+ * @return string tag name for the wizard
+ */
+ protected function getTagName()
+ {
+ return 'div';
+ }
+
+ /**
+ * Adds {@link TWizardStep} objects into step collection.
+ * This method overrides the parent implementation and is
+ * invoked when template is being instantiated.
+ * @param mixed object instantiated in template
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TWizardStep)
+ $this->getWizardSteps()->add($object);
+ }
+
+ /**
+ * @return TWizardStep the currently active wizard step
+ */
+ public function getActiveStep()
+ {
+ return $this->getMultiView()->getActiveView();
+ }
+
+ /**
+ * @param TWizardStep step to be activated
+ * @throws TInvalidOperationException if the step is not in the wizard step collection
+ */
+ public function setActiveStep($step)
+ {
+ if(($index=$this->getWizardSteps()->indexOf($step))<0)
+ throw new TInvalidOperationException('wizard_step_invalid');
+ $this->setActiveStepIndex($index);
+ }
+
+ /**
+ * @return integer the zero-based index of the active wizard step
+ */
+ public function getActiveStepIndex()
+ {
+ return $this->getMultiView()->getActiveViewIndex();
+ }
+
+ /**
+ * @param integer the zero-based index of the wizard step to be activated
+ */
+ public function setActiveStepIndex($value)
+ {
+ $value=TPropertyValue::ensureInteger($value);
+ $multiView=$this->getMultiView();
+ if($multiView->getActiveViewIndex()!==$value)
+ {
+ $multiView->setActiveViewIndex($value);
+ $this->_activeStepIndexSet=true;
+ if($this->_sideBarDataList!==null && $this->getSideBarTemplate()!==null)
+ {
+ $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
+ $this->_sideBarDataList->dataBind();
+ }
+ }
+ }
+
+ /**
+ * @return TWizardStepCollection collection of wizard steps
+ */
+ public function getWizardSteps()
+ {
+ if($this->_wizardSteps===null)
+ $this->_wizardSteps=new TWizardStepCollection($this);
+ return $this->_wizardSteps;
+ }
+
+ /**
+ * @return boolean whether to display a cancel button in each wizard step. Defaults to false.
+ */
+ public function getShowCancelButton()
+ {
+ return $this->getViewState('ShowCancelButton',false);
+ }
+
+ /**
+ * @param boolean whether to display a cancel button in each wizard step.
+ */
+ public function setShowCancelButton($value)
+ {
+ $this->setViewState('ShowCancelButton',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether to display a side bar that contains links to wizard steps. Defaults to true.
+ */
+ public function getShowSideBar()
+ {
+ return $this->getViewState('ShowSideBar',true);
+ }
+
+ /**
+ * @param boolean whether to display a side bar that contains links to wizard steps.
+ */
+ public function setShowSideBar($value)
+ {
+ $this->setViewState('ShowSideBar',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return ITemplate navigation template for the start step. Defaults to null.
+ */
+ public function getStartNavigationTemplate()
+ {
+ return $this->_startNavigationTemplate;
+ }
+
+ /**
+ * @param ITemplate navigation template for the start step.
+ */
+ public function setStartNavigationTemplate($value)
+ {
+ $this->_startNavigationTemplate=$value;
+ $this->requiresControlsRecreation();
+ }
+
+ /**
+ * @return ITemplate navigation template for internal steps. Defaults to null.
+ */
+ public function getStepNavigationTemplate()
+ {
+ return $this->_stepNavigationTemplate;
+ }
+
+ /**
+ * @param ITemplate navigation template for internal steps.
+ */
+ public function setStepNavigationTemplate($value)
+ {
+ $this->_stepNavigationTemplate=$value;
+ $this->requiresControlsRecreation();
+ }
+
+ /**
+ * @return ITemplate navigation template for the finish step. Defaults to null.
+ */
+ public function getFinishNavigationTemplate()
+ {
+ return $this->_finishNavigationTemplate;
+ }
+
+ /**
+ * @param ITemplate navigation template for the finish step.
+ */
+ public function setFinishNavigationTemplate($value)
+ {
+ $this->_finishNavigationTemplate=$value;
+ $this->requiresControlsRecreation();
+ }
+
+ /**
+ * @return ITemplate template for wizard header. Defaults to null.
+ */
+ public function getHeaderTemplate()
+ {
+ return $this->_headerTemplate;
+ }
+
+ /**
+ * @param ITemplate template for wizard header.
+ */
+ public function setHeaderTemplate($value)
+ {
+ $this->_headerTemplate=$value;
+ $this->requiresControlsRecreation();
+ }
+
+ /**
+ * @return ITemplate template for the side bar. Defaults to null.
+ */
+ public function getSideBarTemplate()
+ {
+ return $this->_sideBarTemplate;
+ }
+
+ /**
+ * @param ITemplate template for the side bar.
+ */
+ public function setSideBarTemplate($value)
+ {
+ $this->_sideBarTemplate=$value;
+ $this->requiresControlsRecreation();
+ }
+
+ /**
+ * @return string header text. Defaults to ''.
+ */
+ public function getHeaderText()
+ {
+ return $this->getViewState('HeaderText','');
+ }
+
+ /**
+ * @param string header text.
+ */
+ public function setHeaderText($value)
+ {
+ $this->setViewState('HeaderText',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string the URL that the browser will be redirected to if the cancel button in the
+ * wizard is clicked. Defaults to ''.
+ */
+ public function getCancelDestinationUrl()
+ {
+ return $this->getViewState('CancelDestinationUrl','');
+ }
+
+ /**
+ * @param string the URL that the browser will be redirected to if the cancel button in the
+ * wizard is clicked.
+ */
+ public function setCancelDestinationUrl($value)
+ {
+ $this->setViewState('CancelDestinationUrl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string the URL that the browser will be redirected to if the wizard finishes.
+ * Defaults to ''.
+ */
+ public function getFinishDestinationUrl()
+ {
+ return $this->getViewState('FinishDestinationUrl','');
+ }
+
+ /**
+ * @param string the URL that the browser will be redirected to if the wizard finishes.
+ */
+ public function setFinishDestinationUrl($value)
+ {
+ $this->setViewState('FinishDestinationUrl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return TStyle the style for the buttons displayed in the side bar.
+ */
+ public function getSideBarButtonStyle()
+ {
+ if(($style=$this->getViewState('SideBarButtonStyle',null))===null)
+ {
+ $style=new TStyle;
+ $this->setViewState('SideBarButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TStyle the style common for all navigation buttons.
+ */
+ public function getNavigationButtonStyle()
+ {
+ if(($style=$this->getViewState('NavigationButtonStyle',null))===null)
+ {
+ $style=new TStyle;
+ $this->setViewState('NavigationButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TWizardNavigationButtonStyle the style for the next button in the start wizard step.
+ */
+ public function getStartNextButtonStyle()
+ {
+ if(($style=$this->getViewState('StartNextButtonStyle',null))===null)
+ {
+ $style=new TWizardNavigationButtonStyle;
+ $style->setButtonText('Next');
+ $this->setViewState('StartNextButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TWizardNavigationButtonStyle the style for the next button in each internal wizard step.
+ */
+ public function getStepNextButtonStyle()
+ {
+ if(($style=$this->getViewState('StepNextButtonStyle',null))===null)
+ {
+ $style=new TWizardNavigationButtonStyle;
+ $style->setButtonText('Next');
+ $this->setViewState('StepNextButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TWizardNavigationButtonStyle the style for the previous button in the start wizard step.
+ */
+ public function getStepPreviousButtonStyle()
+ {
+ if(($style=$this->getViewState('StepPreviousButtonStyle',null))===null)
+ {
+ $style=new TWizardNavigationButtonStyle;
+ $style->setButtonText('Previous');
+ $this->setViewState('StepPreviousButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TWizardNavigationButtonStyle the style for the complete button in the finish wizard step.
+ */
+ public function getFinishCompleteButtonStyle()
+ {
+ if(($style=$this->getViewState('FinishCompleteButtonStyle',null))===null)
+ {
+ $style=new TWizardNavigationButtonStyle;
+ $style->setButtonText('Complete');
+ $this->setViewState('FinishCompleteButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TWizardNavigationButtonStyle the style for the previous button in the start wizard step.
+ */
+ public function getFinishPreviousButtonStyle()
+ {
+ if(($style=$this->getViewState('FinishPreviousButtonStyle',null))===null)
+ {
+ $style=new TWizardNavigationButtonStyle;
+ $style->setButtonText('Previous');
+ $this->setViewState('FinishPreviousButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TWizardNavigationButtonStyle the style for the cancel button
+ */
+ public function getCancelButtonStyle()
+ {
+ if(($style=$this->getViewState('CancelButtonStyle',null))===null)
+ {
+ $style=new TWizardNavigationButtonStyle;
+ $style->setButtonText('Cancel');
+ $this->setViewState('CancelButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TPanelStyle the style for the side bar.
+ */
+ public function getSideBarStyle()
+ {
+ if(($style=$this->getViewState('SideBarStyle',null))===null)
+ {
+ $style=new TPanelStyle;
+ $this->setViewState('SideBarStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TPanelStyle the style for the header.
+ */
+ public function getHeaderStyle()
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))===null)
+ {
+ $style=new TPanelStyle;
+ $this->setViewState('HeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TPanelStyle the style for each internal wizard step.
+ */
+ public function getStepStyle()
+ {
+ if(($style=$this->getViewState('StepStyle',null))===null)
+ {
+ $style=new TPanelStyle;
+ $this->setViewState('StepStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TPanelStyle the style for the navigation panel.
+ */
+ public function getNavigationStyle()
+ {
+ if(($style=$this->getViewState('NavigationStyle',null))===null)
+ {
+ $style=new TPanelStyle;
+ $this->setViewState('NavigationStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return boolean whether to use default layout to arrange side bar and the rest wizard components. Defaults to true.
+ */
+ public function getUseDefaultLayout()
+ {
+ return $this->getViewState('UseDefaultLayout',true);
+ }
+
+ /**
+ * @param boolean whether to use default layout to arrange side bar and the rest wizard components.
+ * If true, an HTML table will be used which places the side bar in the left cell
+ * while the rest components in the right cell.
+ */
+ public function setUseDefaultLayout($value)
+ {
+ $this->setViewState('UseDefaultLayout',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return TPanel container of the wizard header
+ */
+ public function getHeader()
+ {
+ return $this->_header;
+ }
+
+ /**
+ * @return TPanel container of the wizard step content
+ */
+ public function getStepContent()
+ {
+ return $this->_stepContent;
+ }
+
+ /**
+ * @return TPanel container of the wizard side bar
+ */
+ public function getSideBar()
+ {
+ return $this->_sideBar;
+ }
+
+ /**
+ * @return TWizardNavigationContainer container of the start navigation
+ */
+ public function getStartNavigation()
+ {
+ return $this->_startNavigation;
+ }
+
+ /**
+ * @return TWizardNavigationContainer container of the step navigation
+ */
+ public function getStepNavigation()
+ {
+ return $this->_stepNavigation;
+ }
+
+ /**
+ * @return TWizardNavigationContainer container of the finish navigation
+ */
+ public function getFinishNavigation()
+ {
+ return $this->_finishNavigation;
+ }
+
+ /**
+ * Raises <b>OnActiveStepChanged</b> event.
+ * This event is raised when the current visible step is changed in the
+ * wizard.
+ * @param TEventParameter event parameter
+ */
+ public function onActiveStepChanged($param)
+ {
+ $this->raiseEvent('OnActiveStepChanged',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnCancelButtonClick</b> event.
+ * This event is raised when a cancel navigation button is clicked in the
+ * current active step.
+ * @param TEventParameter event parameter
+ */
+ public function onCancelButtonClick($param)
+ {
+ $this->raiseEvent('OnCancelButtonClick',$this,$param);
+ if(($url=$this->getCancelDestinationUrl())!=='')
+ $this->getResponse()->redirect($url);
+ }
+
+ /**
+ * Raises <b>OnCompleteButtonClick</b> event.
+ * This event is raised when a finish navigation button is clicked in the
+ * current active step.
+ * @param TWizardNavigationEventParameter event parameter
+ */
+ public function onCompleteButtonClick($param)
+ {
+ $this->raiseEvent('OnCompleteButtonClick',$this,$param);
+ if(($url=$this->getFinishDestinationUrl())!=='')
+ $this->getResponse()->redirect($url);
+ }
+
+ /**
+ * Raises <b>OnNextButtonClick</b> event.
+ * This event is raised when a next navigation button is clicked in the
+ * current active step.
+ * @param TWizardNavigationEventParameter event parameter
+ */
+ public function onNextButtonClick($param)
+ {
+ $this->raiseEvent('OnNextButtonClick',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnPreviousButtonClick</b> event.
+ * This event is raised when a previous navigation button is clicked in the
+ * current active step.
+ * @param TWizardNavigationEventParameter event parameter
+ */
+ public function onPreviousButtonClick($param)
+ {
+ $this->raiseEvent('OnPreviousButtonClick',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnSideBarButtonClick</b> event.
+ * This event is raised when a link button in the side bar is clicked.
+ * @param TWizardNavigationEventParameter event parameter
+ */
+ public function onSideBarButtonClick($param)
+ {
+ $this->raiseEvent('OnSideBarButtonClick',$this,$param);
+ }
+
+ /**
+ * Returns the multiview that holds the wizard steps.
+ * This method should only be used by control developers.
+ * @return TMultiView the multiview holding wizard steps
+ */
+ public function getMultiView()
+ {
+ if($this->_multiView===null)
+ {
+ $this->_multiView=new TMultiView;
+ $this->_multiView->setID('WizardMultiView');
+ $this->_multiView->attachEventHandler('OnActiveViewChanged',array($this,'onActiveStepChanged'));
+ $this->_multiView->ignoreBubbleEvents();
+ }
+ return $this->_multiView;
+ }
+
+ /**
+ * Adds a wizard step to the multiview.
+ * This method should only be used by control developers.
+ * It is invoked when a step is added into the step collection of the wizard.
+ * @param TWizardStep wizard step to be added into multiview.
+ */
+ public function addedWizardStep($step)
+ {
+ if(($wizard=$step->getWizard())!==null)
+ $wizard->getWizardSteps()->remove($step);
+ $step->setWizard($this);
+ $this->wizardStepsChanged();
+ }
+
+ /**
+ * Removes a wizard step from the multiview.
+ * This method should only be used by control developers.
+ * It is invoked when a step is removed from the step collection of the wizard.
+ * @param TWizardStep wizard step to be removed from multiview.
+ */
+ public function removedWizardStep($step)
+ {
+ $step->setWizard(null);
+ $this->wizardStepsChanged();
+ }
+
+ /**
+ * Creates the child controls of the wizard.
+ * This method overrides the parent implementation.
+ * @param TEventParameter event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $this->ensureChildControls();
+ $this->setEnsureId(true);
+ if($this->getActiveStepIndex()<0 && $this->getWizardSteps()->getCount()>0)
+ $this->setActiveStepIndex(0);
+ }
+
+ /**
+ * Saves the current active step index into history.
+ * This method is invoked by the framework when the control state is being saved.
+ */
+ public function saveState()
+ {
+ $index=$this->getActiveStepIndex();
+ $history=$this->getHistory();
+ if(!$history->getCount() || $history->peek()!==$index)
+ $history->push($index);
+ }
+
+ /**
+ * Indicates the wizard needs to recreate all child controls.
+ */
+ protected function requiresControlsRecreation()
+ {
+ if($this->getChildControlsCreated())
+ $this->setChildControlsCreated(false);
+ }
+
+ /**
+ * Renders the wizard.
+ * @param THtmlWriter
+ */
+ public function render($writer)
+ {
+ $this->ensureChildControls();
+ if($this->getHasControls())
+ {
+ if($this->getUseDefaultLayout())
+ {
+ $this->applyControlProperties();
+ $this->renderBeginTag($writer);
+ $writer->write("\n<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" height=\"100%\" width=\"100%\">\n<tr><td width=\"1\" valign=\"top\">\n");
+ $this->_sideBar->renderControl($writer);
+ $writer->write("\n</td><td valign=\"top\">\n");
+ $this->_header->renderControl($writer);
+ $this->_stepContent->renderControl($writer);
+ $this->_navigation->renderControl($writer);
+ $writer->write("\n</td></tr></table>\n");
+ $this->renderEndTag($writer);
+ }
+ else
+ {
+ $this->applyControlProperties();
+ $this->renderBeginTag($writer);
+ $this->_sideBar->renderControl($writer);
+ $this->_header->renderControl($writer);
+ $this->_stepContent->renderControl($writer);
+ $this->_navigation->renderControl($writer);
+ $this->renderEndTag($writer);
+ }
+ }
+ }
+
+ /**
+ * Applies various properties to the components of wizard
+ */
+ protected function applyControlProperties()
+ {
+ $this->applyHeaderProperties();
+ $this->applySideBarProperties();
+ $this->applyStepContentProperties();
+ $this->applyNavigationProperties();
+ }
+
+ /**
+ * Applies properties to the wizard header
+ */
+ protected function applyHeaderProperties()
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))!==null)
+ $this->_header->getStyle()->mergeWith($style);
+ if($this->getHeaderTemplate()===null)
+ {
+ $this->_header->getControls()->clear();
+ $this->_header->getControls()->add($this->getHeaderText());
+ }
+ }
+
+ /**
+ * Applies properties to the wizard sidebar
+ */
+ protected function applySideBarProperties()
+ {
+ $this->_sideBar->setVisible($this->getShowSideBar());
+ if($this->_sideBarDataList!==null && $this->getShowSideBar())
+ {
+ $this->_sideBarDataList->setDataSource($this->getWizardSteps());
+ $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
+ $this->_sideBarDataList->dataBind();
+ if(($style=$this->getViewState('SideBarButtonStyle',null))!==null)
+ {
+ foreach($this->_sideBarDataList->getItems() as $item)
+ {
+ if(($button=$item->findControl('SideBarButton'))!==null)
+ $button->getStyle()->mergeWith($style);
+ }
+ }
+ }
+ if(($style=$this->getViewState('SideBarStyle',null))!==null)
+ $this->_sideBar->getStyle()->mergeWith($style);
+ }
+
+ /**
+ * Applies properties to the wizard step content
+ */
+ protected function applyStepContentProperties()
+ {
+ if(($style=$this->getViewState('StepStyle',null))!==null)
+ $this->_stepContent->getStyle()->mergeWith($style);
+ }
+
+ /**
+ * Apply properties to various navigation panels.
+ */
+ protected function applyNavigationProperties()
+ {
+ $wizardSteps=$this->getWizardSteps();
+ $activeStep=$this->getActiveStep();
+ $activeStepIndex=$this->getActiveStepIndex();
+
+ if(!$this->_navigation)
+ return;
+ else if($activeStepIndex<0 || $activeStepIndex>=$wizardSteps->getCount())
+ {
+ $this->_navigation->setVisible(false);
+ return;
+ }
+
+ // set visibility of different types of navigation panel
+ $showStandard=true;
+ foreach($wizardSteps as $step)
+ {
+ if(($step instanceof TTemplatedWizardStep) && ($container=$step->getNavigationContainer())!==null)
+ {
+ if($activeStep===$step)
+ {
+ $container->setVisible(true);
+ $showStandard=false;
+ }
+ else
+ $container->setVisible(false);
+ }
+ }
+ $activeStepType=$this->getStepType($activeStep);
+ if($activeStepType===TWizardStepType::Complete)
+ {
+ $this->_sideBar->setVisible(false);
+ $this->_header->setVisible(false);
+ }
+ $this->_startNavigation->setVisible($showStandard && $activeStepType===self::ST_START);
+ $this->_stepNavigation->setVisible($showStandard && $activeStepType===self::ST_STEP);
+ $this->_finishNavigation->setVisible($showStandard && $activeStepType===self::ST_FINISH);
+
+ if(($navigationStyle=$this->getViewState('NavigationStyle',null))!==null)
+ $this->_navigation->getStyle()->mergeWith($navigationStyle);
+
+ $displayCancelButton=$this->getShowCancelButton();
+ $cancelButtonStyle=$this->getCancelButtonStyle();
+ $buttonStyle=$this->getViewState('NavigationButtonStyle',null);
+ if($buttonStyle!==null)
+ $cancelButtonStyle->mergeWith($buttonStyle);
+
+ // apply styles to start navigation buttons
+ if(($cancelButton=$this->_startNavigation->getCancelButton())!==null)
+ {
+ $cancelButton->setVisible($displayCancelButton);
+ $cancelButtonStyle->apply($cancelButton);
+ }
+ if(($button=$this->_startNavigation->getNextButton())!==null)
+ {
+ $button->setVisible(true);
+ $style=$this->getStartNextButtonStyle();
+ if($buttonStyle!==null)
+ $style->mergeWith($buttonStyle);
+ $style->apply($button);
+ if($activeStepType===TWizardStepType::Start)
+ $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
+ }
+
+ // apply styles to finish navigation buttons
+ if(($cancelButton=$this->_finishNavigation->getCancelButton())!==null)
+ {
+ $cancelButton->setVisible($displayCancelButton);
+ $cancelButtonStyle->apply($cancelButton);
+ }
+ if(($button=$this->_finishNavigation->getPreviousButton())!==null)
+ {
+ $button->setVisible($this->allowNavigationToPreviousStep());
+ $style=$this->getFinishPreviousButtonStyle();
+ if($buttonStyle!==null)
+ $style->mergeWith($buttonStyle);
+ $style->apply($button);
+ }
+ if(($button=$this->_finishNavigation->getCompleteButton())!==null)
+ {
+ $button->setVisible(true);
+ $style=$this->getFinishCompleteButtonStyle();
+ if($buttonStyle!==null)
+ $style->mergeWith($buttonStyle);
+ $style->apply($button);
+ if($activeStepType===TWizardStepType::Finish)
+ $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
+ }
+
+ // apply styles to step navigation buttons
+ if(($cancelButton=$this->_stepNavigation->getCancelButton())!==null)
+ {
+ $cancelButton->setVisible($displayCancelButton);
+ $cancelButtonStyle->apply($cancelButton);
+ }
+ if(($button=$this->_stepNavigation->getPreviousButton())!==null)
+ {
+ $button->setVisible($this->allowNavigationToPreviousStep());
+ $style=$this->getStepPreviousButtonStyle();
+ if($buttonStyle!==null)
+ $style->mergeWith($buttonStyle);
+ $style->apply($button);
+ }
+ if(($button=$this->_stepNavigation->getNextButton())!==null)
+ {
+ $button->setVisible(true);
+ $style=$this->getStepNextButtonStyle();
+ if($buttonStyle!==null)
+ $style->mergeWith($buttonStyle);
+ $style->apply($button);
+ if($activeStepType===TWizardStepType::Step)
+ $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
+ }
+ }
+
+ /**
+ * @return TStack history containing step indexes that were navigated before
+ */
+ protected function getHistory()
+ {
+ if(($history=$this->getControlState('History',null))===null)
+ {
+ $history=new TStack;
+ $this->setControlState('History',$history);
+ }
+ return $history;
+ }
+
+ /**
+ * Determines the type of the specified wizard step.
+ * @param TWizardStep
+ * @return TWizardStepType type of the step
+ */
+ protected function getStepType($wizardStep)
+ {
+ if(($type=$wizardStep->getStepType())===TWizardStepType::Auto)
+ {
+ $steps=$this->getWizardSteps();
+ if(($index=$steps->indexOf($wizardStep))>=0)
+ {
+ $stepCount=$steps->getCount();
+ if($stepCount===1 || ($index<$stepCount-1 && $steps->itemAt($index+1)->getStepType()===TWizardStepType::Complete))
+ return TWizardStepType::Finish;
+ else if($index===0)
+ return TWizardStepType::Start;
+ else if($index===$stepCount-1)
+ return TWizardStepType::Finish;
+ else
+ return TWizardStepType::Step;
+ }
+ else
+ return $type;
+ }
+ else
+ return $type;
+ }
+
+ /**
+ * Clears up everything within the wizard.
+ */
+ protected function reset()
+ {
+ $this->getControls()->clear();
+ $this->_header=null;
+ $this->_stepContent=null;
+ $this->_sideBar=null;
+ $this->_sideBarDataList=null;
+ $this->_navigation=null;
+ $this->_startNavigation=null;
+ $this->_stepNavigation=null;
+ $this->_finishNavigation=null;
+ }
+
+ /**
+ * Creates child controls within the wizard
+ */
+ public function createChildControls()
+ {
+ $this->reset();
+ $this->createSideBar();
+ $this->createHeader();
+ $this->createStepContent();
+ $this->createNavigation();
+// $this->clearChildState();
+ }
+
+ /**
+ * Creates the wizard header.
+ */
+ protected function createHeader()
+ {
+ $this->_header=new TPanel;
+ if(($template=$this->getHeaderTemplate())!==null)
+ $template->instantiateIn($this->_header);
+ else
+ $this->_header->getControls()->add($this->getHeaderText());
+ $this->getControls()->add($this->_header);
+ }
+
+ /**
+ * Creates the wizard side bar
+ */
+ protected function createSideBar()
+ {
+ if($this->getShowSideBar())
+ {
+ if(($template=$this->getSideBarTemplate())===null)
+ $template=new TWizardSideBarTemplate;
+ $this->_sideBar=new TPanel;
+ $template->instantiateIn($this->_sideBar);
+ $this->getControls()->add($this->_sideBar);
+
+ if(($this->_sideBarDataList=$this->_sideBar->findControl(self::ID_SIDEBAR_LIST))!==null)
+ {
+ $this->_sideBarDataList->attachEventHandler('OnItemCommand',array($this,'dataListItemCommand'));
+ $this->_sideBarDataList->attachEventHandler('OnItemDataBound',array($this,'dataListItemDataBound'));
+ $this->_sideBarDataList->setDataSource($this->getWizardSteps());
+ $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
+ $this->_sideBarDataList->dataBind();
+ }
+ }
+ else
+ {
+ $this->_sideBar=new TPanel;
+ $this->getControls()->add($this->_sideBar);
+ }
+ }
+
+ /**
+ * Event handler for sidebar datalist's OnItemCommand event.
+ * This method is used internally by wizard. It mainly
+ * sets the active step index according to the button clicked in the sidebar.
+ * @param mixed sender of the event
+ * @param TDataListCommandEventParameter
+ */
+ public function dataListItemCommand($sender,$param)
+ {
+ $item=$param->getItem();
+ if($param->getCommandName()===self::CMD_MOVETO)
+ {
+ $stepIndex=$this->getActiveStepIndex();
+ $newStepIndex=TPropertyValue::ensureInteger($param->getCommandParameter());
+ $navParam=new TWizardNavigationEventParameter($stepIndex);
+ $navParam->setNextStepIndex($newStepIndex);
+
+ // if the button clicked causes validation which fails,
+ // by default we will cancel navigation to the new step
+ $button=$param->getCommandSource();
+ if(($button instanceof IButtonControl) && $button->getCausesValidation() && ($page=$this->getPage())!==null && !$page->getIsValid())
+ $navParam->setCancelNavigation(true);
+
+ $this->_activeStepIndexSet=false;
+ $this->onSideBarButtonClick($navParam);
+ $this->_cancelNavigation=$navParam->getCancelNavigation();
+ if(!$this->_cancelNavigation)
+ {
+ if(!$this->_activeStepIndexSet && $this->allowNavigationToStep($newStepIndex))
+ $this->setActiveStepIndex($newStepIndex);
+ }
+ else
+ $this->setActiveStepIndex($stepIndex);
+ }
+ }
+
+ /**
+ * Event handler for sidebar datalist's OnItemDataBound event.
+ * This method is used internally by wizard. It mainly configures
+ * the buttons in the sidebar datalist.
+ * @param mixed sender of the event
+ * @param TDataListItemEventParameter
+ */
+ public function dataListItemDataBound($sender,$param)
+ {
+ $item=$param->getItem();
+ $itemType=$item->getItemType();
+ if($itemType==='Item' || $itemType==='AlternatingItem' || $itemType==='SelectedItem' || $itemType==='EditItem')
+ {
+ if(($button=$item->findControl(self::ID_SIDEBAR_BUTTON))!==null)
+ {
+ $step=$item->getData();
+ if(($this->getStepType($step)===TWizardStepType::Complete))
+ $button->setEnabled(false);
+ if(($title=$step->getTitle())!=='')
+ $button->setText($title);
+ else
+ $button->setText($step->getID(false));
+ $index=$this->getWizardSteps()->indexOf($step);
+ $button->setCommandName(self::CMD_MOVETO);
+ $button->setCommandParameter("$index");
+ }
+ }
+ }
+
+ /**
+ * Creates wizard step content.
+ */
+ protected function createStepContent()
+ {
+ foreach($this->getWizardSteps() as $step)
+ {
+ if($step instanceof TTemplatedWizardStep)
+ $step->ensureChildControls();
+ }
+ $multiView=$this->getMultiView();
+ $this->_stepContent=new TPanel;
+ $this->_stepContent->getControls()->add($multiView);
+ $this->getControls()->add($this->_stepContent);
+ if($multiView->getViews()->getCount())
+ $multiView->setActiveViewIndex(0);
+ }
+
+ /**
+ * Creates navigation panel.
+ */
+ protected function createNavigation()
+ {
+ $this->_navigation=new TPanel;
+ $this->getControls()->add($this->_navigation);
+ $controls=$this->_navigation->getControls();
+ foreach($this->getWizardSteps() as $step)
+ {
+ if($step instanceof TTemplatedWizardStep)
+ {
+ $step->instantiateNavigationTemplate();
+ if(($panel=$step->getNavigationContainer())!==null)
+ $controls->add($panel);
+ }
+ }
+ $this->_startNavigation=$this->createStartNavigation();
+ $controls->add($this->_startNavigation);
+ $this->_stepNavigation=$this->createStepNavigation();
+ $controls->add($this->_stepNavigation);
+ $this->_finishNavigation=$this->createFinishNavigation();
+ $controls->add($this->_finishNavigation);
+ }
+
+ /**
+ * Creates start navigation panel.
+ */
+ protected function createStartNavigation()
+ {
+ if(($template=$this->getStartNavigationTemplate())===null)
+ $template=new TWizardStartNavigationTemplate($this);
+ $navigation=new TWizardNavigationContainer;
+ $template->instantiateIn($navigation);
+ return $navigation;
+ }
+
+ /**
+ * Creates step navigation panel.
+ */
+ protected function createStepNavigation()
+ {
+ if(($template=$this->getStepNavigationTemplate())===null)
+ $template=new TWizardStepNavigationTemplate($this);
+ $navigation=new TWizardNavigationContainer;
+ $template->instantiateIn($navigation);
+ return $navigation;
+ }
+
+ /**
+ * Creates finish navigation panel.
+ */
+ protected function createFinishNavigation()
+ {
+ if(($template=$this->getFinishNavigationTemplate())===null)
+ $template=new TWizardFinishNavigationTemplate($this);
+ $navigation=new TWizardNavigationContainer;
+ $template->instantiateIn($navigation);
+ return $navigation;
+ }
+
+ /**
+ * Updates the sidebar datalist if any.
+ * This method is invoked when any wizard step is changed.
+ */
+ public function wizardStepsChanged()
+ {
+ if($this->_sideBarDataList!==null)
+ {
+ $this->_sideBarDataList->setDataSource($this->getWizardSteps());
+ $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
+ $this->_sideBarDataList->dataBind();
+ }
+ }
+
+ /**
+ * Determines the index of the previous step based on history.
+ * @param boolean whether the first item in the history stack should be popped
+ * up after calling this method.
+ */
+ protected function getPreviousStepIndex($popStack)
+ {
+ $history=$this->getHistory();
+ if($history->getCount()>=0)
+ {
+ $activeStepIndex=$this->getActiveStepIndex();
+ $previousStepIndex=-1;
+ if($popStack)
+ {
+ $previousStepIndex=$history->pop();
+ if($activeStepIndex===$previousStepIndex && $history->getCount()>0)
+ $previousStepIndex=$history->pop();
+ }
+ else
+ {
+ $previousStepIndex=$history->peek();
+ if($activeStepIndex===$previousStepIndex && $history->getCount()>1)
+ {
+ $saveIndex=$history->pop();
+ $previousStepIndex=$history->peek();
+ $history->push($saveIndex);
+ }
+ }
+ return $activeStepIndex===$previousStepIndex ? -1 : $previousStepIndex;
+ }
+ else
+ return -1;
+ }
+
+ /**
+ * @return boolean whether navigation to the previous step is allowed
+ */
+ protected function allowNavigationToPreviousStep()
+ {
+ if(($index=$this->getPreviousStepIndex(false))!==-1)
+ return $this->getWizardSteps()->itemAt($index)->getAllowReturn();
+ else
+ return false;
+ }
+
+ /**
+ * @param integer index of the step
+ * @return boolean whether navigation to the specified step is allowed
+ */
+ protected function allowNavigationToStep($index)
+ {
+ if($this->getHistory()->contains($index))
+ return $this->getWizardSteps()->itemAt($index)->getAllowReturn();
+ else
+ return true;
+ }
+
+ /**
+ * Handles bubbled events.
+ * This method mainly translate certain command events into
+ * wizard-specific events.
+ * @param mixed sender of the original command event
+ * @param TEventParameter event parameter
+ * @throws TInvalidDataValueException if a navigation command is associated with an invalid parameter
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $command=$param->getCommandName();
+ if(strcasecmp($command,self::CMD_CANCEL)===0)
+ {
+ $this->onCancelButtonClick($param);
+ return true;
+ }
+
+ $type=$this->getStepType($this->getActiveStep());
+ $index=$this->getActiveStepIndex();
+ $navParam=new TWizardNavigationEventParameter($index);
+ if(($sender instanceof IButtonControl) && $sender->getCausesValidation() && ($page=$this->getPage())!==null && !$page->getIsValid())
+ $navParam->setCancelNavigation(true);
+
+ $handled=false;
+ $movePrev=false;
+ $this->_activeStepIndexSet=false;
+
+ if(strcasecmp($command,self::CMD_NEXT)===0)
+ {
+ if($type!==self::ST_START && $type!==self::ST_STEP)
+ throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_NEXT);
+ if($index<$this->getWizardSteps()->getCount()-1)
+ $navParam->setNextStepIndex($index+1);
+ $this->onNextButtonClick($navParam);
+ $handled=true;
+ }
+ else if(strcasecmp($command,self::CMD_PREVIOUS)===0)
+ {
+ if($type!==self::ST_FINISH && $type!==self::ST_STEP)
+ throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_PREVIOUS);
+ $movePrev=true;
+ if(($prevIndex=$this->getPreviousStepIndex(false))>=0)
+ $navParam->setNextStepIndex($prevIndex);
+ $this->onPreviousButtonClick($navParam);
+ $handled=true;
+ }
+ else if(strcasecmp($command,self::CMD_COMPLETE)===0)
+ {
+ if($type!==self::ST_FINISH)
+ throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_COMPLETE);
+ if($index<$this->getWizardSteps()->getCount()-1)
+ $navParam->setNextStepIndex($index+1);
+ $this->onCompleteButtonClick($navParam);
+ $handled=true;
+ }
+ else if(strcasecmp($command,self::CMD_MOVETO)===0)
+ {
+ if($this->_cancelNavigation) // may be set in onSideBarButtonClick
+ $navParam->setCancelNavigation(true);
+ $requestedStep=$param->getCommandParameter();
+ if (!is_numeric($requestedStep))
+ {
+ $requestedIndex=-1;
+ foreach ($this->getWizardSteps() as $index=>$step)
+ if ($step->getId()===$requestedStep)
+ {
+ $requestedIndex=$index;
+ break;
+ }
+ if ($requestedIndex<0)
+ throw new TConfigurationException('wizard_step_invalid');
+ }
+ else
+ $requestedIndex=TPropertyValue::ensureInteger($requestedStep);
+ $navParam->setNextStepIndex($requestedIndex);
+ $handled=true;
+ }
+
+ if($handled)
+ {
+ if(!$navParam->getCancelNavigation())
+ {
+ $nextStepIndex=$navParam->getNextStepIndex();
+ if(!$this->_activeStepIndexSet && $this->allowNavigationToStep($nextStepIndex))
+ {
+ if($movePrev)
+ $this->getPreviousStepIndex(true); // pop out the previous move from history
+ $this->setActiveStepIndex($nextStepIndex);
+ }
+ }
+ else
+ $this->setActiveStepIndex($index);
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+
+/**
+ * TWizardStep class.
+ *
+ * TWizardStep represents a wizard step. The wizard owning the step
+ * can be obtained by {@link getWizard Wizard}.
+ * To specify the type of the step, set {@link setStepType StepType};
+ * For step title, set {@link setTitle Title}. If a step can be re-visited,
+ * set {@link setAllowReturn AllowReturn} to true.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardStep extends TView
+{
+ private $_wizard;
+
+ /**
+ * @return TWizard the wizard owning this step
+ */
+ public function getWizard()
+ {
+ return $this->_wizard;
+ }
+
+ /**
+ * Sets the wizard owning this step.
+ * This method is used internally by {@link TWizard}.
+ * @param TWizard the wizard owning this step
+ */
+ public function setWizard($wizard)
+ {
+ $this->_wizard=$wizard;
+ }
+
+ /**
+ * @return string the title for this step.
+ */
+ public function getTitle()
+ {
+ return $this->getViewState('Title','');
+ }
+
+ /**
+ * @param string the title for this step.
+ */
+ public function setTitle($value)
+ {
+ $this->setViewState('Title',$value,'');
+ if($this->_wizard)
+ $this->_wizard->wizardStepsChanged();
+ }
+
+ /**
+ * @return boolean whether this step can be re-visited. Default to true.
+ */
+ public function getAllowReturn()
+ {
+ return $this->getViewState('AllowReturn',true);
+ }
+
+ /**
+ * @param boolean whether this step can be re-visited.
+ */
+ public function setAllowReturn($value)
+ {
+ $this->setViewState('AllowReturn',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return TWizardStepType the wizard step type. Defaults to TWizardStepType::Auto.
+ */
+ public function getStepType()
+ {
+ return $this->getViewState('StepType',TWizardStepType::Auto);
+ }
+
+ /**
+ * @param TWizardStepType the wizard step type.
+ */
+ public function setStepType($type)
+ {
+ $type=TPropertyValue::ensureEnum($type,'TWizardStepType');
+ if($type!==$this->getStepType())
+ {
+ $this->setViewState('StepType',$type,TWizardStepType::Auto);
+ if($this->_wizard)
+ $this->_wizard->wizardStepsChanged();
+ }
+ }
+}
+
+
+/**
+ * TCompleteWizardStep class.
+ *
+ * TCompleteWizardStep represents a wizard step of type TWizardStepType::Complete.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCompleteWizardStep extends TWizardStep
+{
+ /**
+ * @return TWizardStepType the wizard step type. Always TWizardStepType::Complete.
+ */
+ public function getStepType()
+ {
+ return TWizardStepType::Complete;
+ }
+
+ /**
+ * @param string the wizard step type.
+ * @throws TInvalidOperationException whenever this method is invoked.
+ */
+ public function setStepType($value)
+ {
+ throw new TInvalidOperationException('completewizardstep_steptype_readonly');
+ }
+}
+
+
+/**
+ * TTemplatedWizardStep class.
+ *
+ * TTemplatedWizardStep represents a wizard step whose content and navigation
+ * can be customized using templates. To customize the step content, specify
+ * {@link setContentTemplate ContentTemplate}. To customize navigation specific
+ * to the step, specify {@link setNavigationTemplate NavigationTemplate}. Note,
+ * if the navigation template is not specified, default navigation will be used.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTemplatedWizardStep extends TWizardStep implements INamingContainer
+{
+ /**
+ * @var ITemplate the template for displaying the navigation UI of a wizard step.
+ */
+ private $_navigationTemplate=null;
+ /**
+ * @var ITemplate the template for displaying the content within the wizard step.
+ */
+ private $_contentTemplate=null;
+ /**
+ * @var TWizardNavigationContainer
+ */
+ private $_navigationContainer=null;
+
+ /**
+ * Creates child controls.
+ * This method mainly instantiates the content template, if any.
+ */
+ public function createChildControls()
+ {
+ $this->getControls()->clear();
+ if($this->_contentTemplate)
+ $this->_contentTemplate->instantiateIn($this);
+ }
+
+ /**
+ * Ensures child controls are created.
+ * @param mixed event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $this->ensureChildControls();
+ }
+
+ /**
+ * @return ITemplate the template for the content of the wizard step.
+ */
+ public function getContentTemplate()
+ {
+ return $this->_contentTemplate;
+ }
+
+ /**
+ * @param ITemplate the template for the content of the wizard step.
+ */
+ public function setContentTemplate($value)
+ {
+ $this->_contentTemplate=$value;
+ }
+
+ /**
+ * @return ITemplate the template for displaying the navigation UI of a wizard step. Defaults to null.
+ */
+ public function getNavigationTemplate()
+ {
+ return $this->_navigationTemplate;
+ }
+
+ /**
+ * @param ITemplate the template for displaying the navigation UI of a wizard step.
+ */
+ public function setNavigationTemplate($value)
+ {
+ $this->_navigationTemplate=$value;
+ }
+
+ /**
+ * @return TWizardNavigationContainer the control containing the navigation.
+ * It could be null if no navigation template is specified.
+ */
+ public function getNavigationContainer()
+ {
+ return $this->_navigationContainer;
+ }
+
+ /**
+ * Instantiates the navigation template if any
+ */
+ public function instantiateNavigationTemplate()
+ {
+ if(!$this->_navigationContainer && $this->_navigationTemplate)
+ {
+ $this->_navigationContainer=new TWizardNavigationContainer;
+ $this->_navigationTemplate->instantiateIn($this->_navigationContainer);
+ }
+ }
+}
+
+
+/**
+ * TWizardStepCollection class.
+ *
+ * TWizardStepCollection represents the collection of wizard steps owned
+ * by a {@link TWizard}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardStepCollection extends TList
+{
+ /**
+ * @var TWizard
+ */
+ private $_wizard;
+
+ /**
+ * Constructor.
+ * @param TWizard wizard that owns this collection
+ */
+ public function __construct(TWizard $wizard)
+ {
+ $this->_wizard=$wizard;
+ }
+
+ /**
+ * Inserts an item at the specified position.
+ * This method overrides the parent implementation by checking if
+ * the item being added is a {@link TWizardStep}.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item being added is not TWizardStep.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TWizardStep)
+ {
+ parent::insertAt($index,$item);
+ $this->_wizard->getMultiView()->getViews()->insertAt($index,$item);
+ $this->_wizard->addedWizardStep($item);
+ }
+ else
+ throw new TInvalidDataTypeException('wizardstepcollection_wizardstep_required');
+ }
+
+ /**
+ * Removes an item at the specified position.
+ * @param integer the index of the item to be removed.
+ * @return mixed the removed item.
+ */
+ public function removeAt($index)
+ {
+ $step=parent::removeAt($index);
+ $this->_wizard->getMultiView()->getViews()->remove($step);
+ $this->_wizard->removedWizardStep($step);
+ return $step;
+ }
+}
+
+
+/**
+ * TWizardNavigationContainer class.
+ *
+ * TWizardNavigationContainer represents a control containing
+ * a wizard navigation. The navigation may contain a few buttons, including
+ * {@link getPreviousButton PreviousButton}, {@link getNextButton NextButton},
+ * {@link getCancelButton CancelButton}, {@link getCompleteButton CompleteButton}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardNavigationContainer extends TControl implements INamingContainer
+{
+ private $_previousButton=null;
+ private $_nextButton=null;
+ private $_cancelButton=null;
+ private $_completeButton=null;
+
+ /**
+ * @return mixed the previous button
+ */
+ public function getPreviousButton()
+ {
+ return $this->_previousButton;
+ }
+
+ /**
+ * @param mixed the previous button
+ */
+ public function setPreviousButton($value)
+ {
+ $this->_previousButton=$value;
+ }
+
+ /**
+ * @return mixed the next button
+ */
+ public function getNextButton()
+ {
+ return $this->_nextButton;
+ }
+
+ /**
+ * @param mixed the next button
+ */
+ public function setNextButton($value)
+ {
+ $this->_nextButton=$value;
+ }
+
+ /**
+ * @return mixed the cancel button
+ */
+ public function getCancelButton()
+ {
+ return $this->_cancelButton;
+ }
+
+ /**
+ * @param mixed the cancel button
+ */
+ public function setCancelButton($value)
+ {
+ $this->_cancelButton=$value;
+ }
+
+ /**
+ * @return mixed the complete button
+ */
+ public function getCompleteButton()
+ {
+ return $this->_completeButton;
+ }
+
+ /**
+ * @param mixed the complete button
+ */
+ public function setCompleteButton($value)
+ {
+ $this->_completeButton=$value;
+ }
+}
+
+
+/**
+ * TWizardNavigationEventParameter class.
+ *
+ * TWizardNavigationEventParameter represents the parameter for
+ * {@link TWizard}'s navigation events.
+ *
+ * The index of the currently active step can be obtained from
+ * {@link getCurrentStepIndex CurrentStepIndex}, while the index
+ * of the candidate new step is in {@link getNextStepIndex NextStepIndex}.
+ * By modifying {@link setNextStepIndex NextStepIndex}, the new step
+ * can be changed to another one. If there is anything wrong with
+ * the navigation and it is not wanted, set {@link setCancelNavigation CancelNavigation}
+ * to true.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardNavigationEventParameter extends TEventParameter
+{
+ private $_cancel=false;
+ private $_currentStep;
+ private $_nextStep;
+
+ /**
+ * Constructor.
+ * @param integer current step index
+ */
+ public function __construct($currentStep)
+ {
+ $this->_currentStep=$currentStep;
+ $this->_nextStep=$currentStep;
+ }
+
+ /**
+ * @return integer the zero-based index of the currently active step.
+ */
+ public function getCurrentStepIndex()
+ {
+ return $this->_currentStep;
+ }
+
+ /**
+ * @return integer the zero-based index of the next step. Default to {@link getCurrentStepIndex CurrentStepIndex}.
+ */
+ public function getNextStepIndex()
+ {
+ return $this->_nextStep;
+ }
+
+ /**
+ * @param integer the zero-based index of the next step.
+ */
+ public function setNextStepIndex($index)
+ {
+ $this->_nextStep=TPropertyValue::ensureInteger($index);
+ }
+
+ /**
+ * @return boolean whether navigation to the next step should be canceled. Default to false.
+ */
+ public function getCancelNavigation()
+ {
+ return $this->_cancel;
+ }
+
+ /**
+ * @param boolean whether navigation to the next step should be canceled.
+ */
+ public function setCancelNavigation($value)
+ {
+ $this->_cancel=TPropertyValue::ensureBoolean($value);
+ }
+}
+
+/**
+ * TWizardSideBarTemplate class.
+ * TWizardSideBarTemplate is the default template for wizard sidebar.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardSideBarTemplate extends TComponent implements ITemplate
+{
+ /**
+ * Instantiates the template.
+ * It creates a {@link TDataList} control.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $dataList=new TDataList;
+ $dataList->setID(TWizard::ID_SIDEBAR_LIST);
+ $dataList->getSelectedItemStyle()->getFont()->setBold(true);
+ $dataList->setItemTemplate(new TWizardSideBarListItemTemplate);
+ $parent->getControls()->add($dataList);
+ }
+}
+
+/**
+ * TWizardSideBarListItemTemplate class.
+ * TWizardSideBarListItemTemplate is the default template for each item in the sidebar datalist.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardSideBarListItemTemplate extends TComponent implements ITemplate
+{
+ /**
+ * Instantiates the template.
+ * It creates a {@link TLinkButton}.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $button=new TLinkButton;
+ $button->setID(TWizard::ID_SIDEBAR_BUTTON);
+ $parent->getControls()->add($button);
+ }
+}
+
+/**
+ * TWizardNavigationTemplate class.
+ * TWizardNavigationTemplate is the base class for various navigation templates.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardNavigationTemplate extends TComponent implements ITemplate
+{
+ private $_wizard;
+
+ /**
+ * Constructor.
+ * @param TWizard the wizard owning this template
+ */
+ public function __construct($wizard)
+ {
+ $this->_wizard=$wizard;
+ }
+
+ /**
+ * @return TWizard the wizard owning this template
+ */
+ public function getWizard()
+ {
+ return $this->_wizard;
+ }
+
+ /**
+ * Instantiates the template.
+ * Derived classes should override this method.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ }
+
+ /**
+ * Creates a navigation button.
+ * It creates a {@link TButton}, {@link TLinkButton}, or {@link TImageButton},
+ * depending on the given parameters.
+ * @param TWizardNavigationButtonStyle button style
+ * @param boolean whether the button should cause validation
+ * @param string command name for the button's OnCommand event
+ * @throws TInvalidDataValueException if the button type is not recognized
+ */
+ protected function createNavigationButton($buttonStyle,$causesValidation,$commandName)
+ {
+ switch($buttonStyle->getButtonType())
+ {
+ case TWizardNavigationButtonType::Button:
+ $button=new TButton;
+ break;
+ case TWizardNavigationButtonType::Link:
+ $button=new TLinkButton;
+ break;
+ case TWizardNavigationButtonType::Image:
+ $button=new TImageButton;
+ $button->setImageUrl($buttonStyle->getImageUrl());
+ break;
+ default:
+ throw new TInvalidDataValueException('wizard_buttontype_unknown',$buttonStyle->getButtonType());
+ }
+ $button->setText($buttonStyle->getButtonText());
+ $button->setCausesValidation($causesValidation);
+ $button->setCommandName($commandName);
+ return $button;
+ }
+}
+
+/**
+ * TWizardStartNavigationTemplate class.
+ * TWizardStartNavigationTemplate is the template used as default wizard start navigation panel.
+ * It consists of two buttons, Next and Cancel.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardStartNavigationTemplate extends TWizardNavigationTemplate
+{
+ /**
+ * Instantiates the template.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $nextButton=$this->createNavigationButton($this->getWizard()->getStartNextButtonStyle(),true,TWizard::CMD_NEXT);
+ $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL);
+
+ $controls=$parent->getControls();
+ $controls->add($nextButton);
+ $controls->add("\n");
+ $controls->add($cancelButton);
+
+ $parent->setNextButton($nextButton);
+ $parent->setCancelButton($cancelButton);
+ }
+}
+
+/**
+ * TWizardFinishNavigationTemplate class.
+ * TWizardFinishNavigationTemplate is the template used as default wizard finish navigation panel.
+ * It consists of three buttons, Previous, Complete and Cancel.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardFinishNavigationTemplate extends TWizardNavigationTemplate
+{
+ /**
+ * Instantiates the template.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $previousButton=$this->createNavigationButton($this->getWizard()->getFinishPreviousButtonStyle(),false,TWizard::CMD_PREVIOUS);
+ $completeButton=$this->createNavigationButton($this->getWizard()->getFinishCompleteButtonStyle(),true,TWizard::CMD_COMPLETE);
+ $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL);
+
+ $controls=$parent->getControls();
+ $controls->add($previousButton);
+ $controls->add("\n");
+ $controls->add($completeButton);
+ $controls->add("\n");
+ $controls->add($cancelButton);
+
+ $parent->setPreviousButton($previousButton);
+ $parent->setCompleteButton($completeButton);
+ $parent->setCancelButton($cancelButton);
+ }
+}
+
+/**
+ * TWizardStepNavigationTemplate class.
+ * TWizardStepNavigationTemplate is the template used as default wizard step navigation panel.
+ * It consists of three buttons, Previous, Next and Cancel.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardStepNavigationTemplate extends TWizardNavigationTemplate
+{
+ /**
+ * Instantiates the template.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $previousButton=$this->createNavigationButton($this->getWizard()->getStepPreviousButtonStyle(),false,TWizard::CMD_PREVIOUS);
+ $nextButton=$this->createNavigationButton($this->getWizard()->getStepNextButtonStyle(),true,TWizard::CMD_NEXT);
+ $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL);
+
+ $controls=$parent->getControls();
+ $controls->add($previousButton);
+ $controls->add("\n");
+ $controls->add($nextButton);
+ $controls->add("\n");
+ $controls->add($cancelButton);
+
+ $parent->setPreviousButton($previousButton);
+ $parent->setNextButton($nextButton);
+ $parent->setCancelButton($cancelButton);
+ }
+}
+
+
+/**
+ * TWizardNavigationButtonType class.
+ * TWizardNavigationButtonType defines the enumerable type for the possible types of buttons
+ * that can be used in the navigation part of a {@link TWizard}.
+ *
+ * The following enumerable values are defined:
+ * - Button: a regular click button
+ * - Image: an image button
+ * - Link: a hyperlink button
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TWizardNavigationButtonType extends TEnumerable
+{
+ const Button='Button';
+ const Image='Image';
+ const Link='Link';
+}
+
+
+/**
+ * TWizardStepType class.
+ * TWizardStepType defines the enumerable type for the possible types of {@link TWizard wizard} steps.
+ *
+ * The following enumerable values are defined:
+ * - Auto: the type is automatically determined based on the location of the wizard step in the whole step collection.
+ * - Complete: the step is the last summary step.
+ * - Start: the step is the first step
+ * - Step: the step is between the begin and the end steps.
+ * - Finish: the last step before the Complete step.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TWizardStepType extends TEnumerable
+{
+ const Auto='Auto';
+ const Complete='Complete';
+ const Start='Start';
+ const Step='Step';
+ const Finish='Finish';
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TWizardNavigationButtonStyle.php b/lib/prado/framework/Web/UI/WebControls/TWizardNavigationButtonStyle.php
new file mode 100644
index 0000000..de94fc5
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TWizardNavigationButtonStyle.php
@@ -0,0 +1,154 @@
+<?php
+/**
+ * TWizardNavigationButtonStyle class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @version $Id $
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TStyle class file
+ */
+Prado::using('System.Web.UI.WebControls.TStyle');
+
+/**
+ * TWizardNavigationButtonStyle class.
+ * TWizardNavigationButtonStyle defines the style applied to a wizard navigation button.
+ * The button type can be specified via {@link setButtonType ButtonType}, which
+ * can be 'Button', 'Image' or 'Link'.
+ * If the button is an image button, {@link setImageUrl ImageUrl} will be
+ * used to load the image for the button.
+ * Otherwise, {@link setButtonText ButtonText} will be displayed as the button caption.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardNavigationButtonStyle extends TStyle
+{
+ private $_imageUrl=null;
+ private $_buttonText=null;
+ private $_buttonType=null;
+
+ /**
+ * Sets the style attributes to default values.
+ * This method overrides the parent implementation by
+ * resetting additional TWizardNavigationButtonStyle specific attributes.
+ */
+ public function reset()
+ {
+ parent::reset();
+ $this->_imageUrl=null;
+ $this->_buttonText=null;
+ $this->_buttonType=null;
+ }
+
+ /**
+ * Copies the fields in a new style to this style.
+ * If a style field is set in the new style, the corresponding field
+ * in this style will be overwritten.
+ * @param TStyle the new style
+ */
+ public function copyFrom($style)
+ {
+ parent::copyFrom($style);
+ if($style instanceof TWizardNavigationButtonStyle)
+ {
+ if($this->_imageUrl===null && $style->_imageUrl!==null)
+ $this->_imageUrl=$style->_imageUrl;
+ if($this->_buttonText===null && $style->_buttonText!==null)
+ $this->_buttonText=$style->_buttonText;
+ if($this->_buttonType===null && $style->_buttonType!==null)
+ $this->_buttonType=$style->_buttonType;
+ }
+ }
+
+ /**
+ * Merges the style with a new one.
+ * If a style field is not set in this style, it will be overwritten by
+ * the new one.
+ * @param TStyle the new style
+ */
+ public function mergeWith($style)
+ {
+ parent::mergeWith($style);
+ if($style instanceof TWizardNavigationButtonStyle)
+ {
+ if($style->_imageUrl!==null)
+ $this->_imageUrl=$style->_imageUrl;
+ if($style->_buttonText!==null)
+ $this->_buttonText=$style->_buttonText;
+ if($style->_buttonType!==null)
+ $this->_buttonType=$style->_buttonType;
+ }
+ }
+
+ /**
+ * @return string image URL for the image button
+ */
+ public function getImageUrl()
+ {
+ return $this->_imageUrl===null?'':$this->_imageUrl;
+ }
+
+ /**
+ * @param string image URL for the image button
+ */
+ public function setImageUrl($value)
+ {
+ $this->_imageUrl=$value;
+ }
+
+ /**
+ * @return string button caption
+ */
+ public function getButtonText()
+ {
+ return $this->_buttonText===null?'':$this->_buttonText;
+ }
+
+ /**
+ * @param string button caption
+ */
+ public function setButtonText($value)
+ {
+ $this->_buttonText=$value;
+ }
+
+ /**
+ * @return TWizardNavigationButtonType button type. Default to TWizardNavigationButtonType::Button.
+ */
+ public function getButtonType()
+ {
+ return $this->_buttonType===null? TWizardNavigationButtonType::Button :$this->_buttonType;
+ }
+
+ /**
+ * @param TWizardNavigationButtonType button type.
+ */
+ public function setButtonType($value)
+ {
+ $this->_buttonType=TPropertyValue::ensureEnum($value,'TWizardNavigationButtonType');
+ }
+
+ /**
+ * Applies this style to the specified button
+ * @param mixed button to be applied with this style
+ */
+ public function apply($button)
+ {
+ if($button instanceof TImageButton)
+ {
+ if($button->getImageUrl()==='')
+ $button->setImageUrl($this->getImageUrl());
+ }
+ if($button->getText()==='')
+ $button->setText($this->getButtonText());
+ $button->getStyle()->mergeWith($this);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/TXmlTransform.php b/lib/prado/framework/Web/UI/WebControls/TXmlTransform.php
new file mode 100644
index 0000000..e3c206f
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/TXmlTransform.php
@@ -0,0 +1,193 @@
+<?php
+/**
+ * TXmlTransform class file
+ *
+ * @author Knut Urdalen <knut.urdalen@gmail.com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TXmlTransform class
+ *
+ * TXmlTransform uses the PHP's XSL extension to perform
+ * {@link http://www.w3.org/TR/xslt XSL transformations} using the
+ * {@link http://xmlsoft.org/XSLT/ libxslt library}.
+ *
+ * To associate an XML style sheet with TXmlTransform set the
+ * {@link setTransformPath TransformPath} property to the namespace or path to the style sheet
+ * or set the {@link setTransformContent TransformContent} property to the XML style sheet
+ * data as a string.
+ *
+ * To associate the XML data to be transformed set the {@link setDocumentPath DocumentPath}
+ * property to the namespace or path to the XML document or set the
+ * {@link setDocumentContent DocumentContent} property to the XML data as a string.
+ *
+ * To add additional parameters to the transformation process you can use the {@link getParameters Parameters}
+ * property.
+ *
+ * @author Knut Urdalen <knut.urdalen@gmail.com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1
+ */
+class TXmlTransform extends TControl {
+
+ const EXT_XML_FILE = '.xml';
+ const EXT_XSL_FILE = '.xsl';
+
+ /**
+ * Constructor
+ *
+ * Initializes the TXmlTransform object and ensure that the XSL extension is available
+ * @throws TConfigurationException If XSL extension is not available
+ */
+ public function __construct() {
+ if(!class_exists('XSLTProcessor', false)) {
+ throw new TConfigurationException('xmltransform_xslextension_required');
+ }
+ }
+
+ /**
+ * @return string The path to the XML style sheet.
+ */
+ public function getTransformPath() {
+ return $this->getViewState('TransformPath', '');
+ }
+
+ /**
+ * @param string The path to the XML style sheet. It must be in namespace format.
+ */
+ public function setTransformPath($value) {
+ if(!is_file($value)) {
+ $value = Prado::getPathOfNamespace($value, self::EXT_XSL_FILE);
+ if($value === null) {
+ throw new TInvalidDataValueException('xmltransform_transformpath_invalid', $value);
+ }
+ }
+ $this->setViewState('TransformPath', $value, '');
+ }
+
+ /**
+ * @return string XML style sheet as string
+ */
+ public function getTransformContent() {
+ return $this->getViewState('TransformContent', '');
+ }
+
+ /**
+ * @param string $value XML style sheet as string
+ */
+ public function setTransformContent($value) {
+ $this->setViewState('TransformContent', $value, '');
+ }
+
+ /**
+ * @return string The path to the XML document. It must be in namespace format.
+ */
+ public function getDocumentPath() {
+ return $this->getViewState('DocumentPath', '');
+ }
+
+ /**
+ * @param string Namespace or path to XML document
+ * @throws TInvalidDataValueException
+ */
+ public function setDocumentPath($value) {
+ if(!is_file($value)) {
+ $value = Prado::getPathOfNamespace($value, self::EXT_XML_FILE);
+ if($value === null) {
+ throw new TInvalidDataValueException('xmltransform_documentpath_invalid', $value);
+ }
+ }
+ $this->setViewState('DocumentPath', $value, '');
+ }
+
+ /**
+ * @return string XML data
+ */
+ public function getDocumentContent() {
+ return $this->getViewState('DocumentContent', '');
+ }
+
+ /**
+ * @param string $value XML data. If not empty, it takes precedence over {@link setDocumentPath DocumentPath}.
+ */
+ public function setDocumentContent($value) {
+ $this->setViewState('DocumentContent', $value, '');
+ }
+
+ /**
+ * Returns the list of parameters to be applied to the transform.
+ * @return TAttributeCollection the list of custom parameters
+ */
+ public function getParameters() {
+ if($params = $this->getViewState('Parameters',null)) {
+ return $params;
+ } else {
+ $params = new TAttributeCollection();
+ $this->setViewState('Parameters', $params, null);
+ return $params;
+ }
+ }
+
+ private function getTransformXmlDocument() {
+ if(($content = $this->getTransformContent()) !== '') {
+ $document = new DOMDocument();
+ $document->loadXML($content);
+ return $document;
+ } else if(($path = $this->getTransformPath()) !== '') {
+ $document = new DOMDocument();
+ $document->load($path);
+ return $document;
+ } else {
+ throw new TConfigurationException('xmltransform_transform_required');
+ }
+ }
+
+ private function getSourceXmlDocument() {
+ if(($content = $this->getDocumentContent()) !== '') {
+ $document = new DOMDocument();
+ $document->loadXML($content);
+ return $document;
+ } else if(($path = $this->getDocumentPath()) !== '') {
+ $document = new DOMDocument();
+ $document->load($path);
+ return $document;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Performs XSL transformation and render the output.
+ * @param THtmlWriter The writer used for the rendering purpose
+ */
+ public function render($writer) {
+ if(($document=$this->getSourceXmlDocument()) === null) {
+ $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter());
+ parent::render($htmlWriter);
+ $document = new DOMDocument();
+ $document->loadXML($htmlWriter->flush());
+ }
+ $stylesheet = $this->getTransformXmlDocument();
+
+ // Perform XSL transformation
+ $xslt = new XSLTProcessor();
+ $xslt->importStyleSheet($stylesheet);
+
+ // Check for parameters
+ $parameters = $this->getParameters();
+ foreach($parameters as $name => $value) {
+ $xslt->setParameter('', $name, $value);
+ }
+ $output = $xslt->transformToXML($document);
+
+ // Write output
+ $writer->write($output);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/assets/TSlider/TSlider.css b/lib/prado/framework/Web/UI/WebControls/assets/TSlider/TSlider.css
new file mode 100755
index 0000000..458467e
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/assets/TSlider/TSlider.css
@@ -0,0 +1,96 @@
+/* Base CSS Class for the slider */
+.Slider
+{
+ position: relative;
+ margin: 10px;
+ padding: 0;
+ background-color: Gainsboro;
+ border: 1px outset;
+}
+
+/* Class for horizontal slider */
+.HorizontalSlider
+{
+ width: 210px;
+ height: 14px;
+ text-align: left;
+}
+
+/* Class for vertical slider */
+.VerticalSlider
+{
+ height: 210px;
+ width: 14px;
+}
+
+/* Class for Track */
+.Track
+{
+ border-style: inset;
+ outline-color: invert;
+ outline-style: none;
+ outline-width: 1px;
+ border-width: 1px;
+ position: absolute;
+ background-color: lightBlue;
+}
+
+/* Horizontal Track */
+.HorizontalSlider .Track
+{
+
+ height: 3px;
+ top: 5px;
+ width: 97%;
+ left: 1%;
+}
+
+/* Vertical Track */
+.VerticalSlider .Track
+{
+ height: 97%;
+ width: 3px;
+ left: 5px;
+ top: 1%;
+}
+
+/* Class for the progress indicator */
+.Progress
+{
+ background-color: red;
+}
+
+/* Horizontal one, take 100% of track (parent) height*/
+.HorizontalSlider .Progress
+{
+ height: 100%;
+}
+
+/* Vertical progress indicator, take 100% of track width*/
+.VerticalSlider .Progress
+{
+ width: 100%
+}
+
+/* Class for handle */
+.Handle {
+ border: 0px none;
+ position: relative;
+ cursor: move;
+}
+
+/* Horizontal slider handle */
+.HorizontalSlider .Handle
+{
+ width: 31px;
+ height: 14px;
+ background: transparent url("TSliderHandleHorizontal.png") no-repeat scroll center;
+}
+
+/* Vertical slider handle */
+.VerticalSlider .Handle
+{
+ width: 14px;
+ height: 31px;
+ background: transparent url("TSliderHandleVertical.png") no-repeat scroll center;
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/assets/TSlider/TSliderHandleHorizontal.png b/lib/prado/framework/Web/UI/WebControls/assets/TSlider/TSliderHandleHorizontal.png
new file mode 100644
index 0000000..d9dc7ff
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/assets/TSlider/TSliderHandleHorizontal.png
Binary files differ
diff --git a/lib/prado/framework/Web/UI/WebControls/assets/TSlider/TSliderHandleVertical.png b/lib/prado/framework/Web/UI/WebControls/assets/TSlider/TSliderHandleVertical.png
new file mode 100644
index 0000000..00532fb
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/assets/TSlider/TSliderHandleVertical.png
Binary files differ
diff --git a/lib/prado/framework/Web/UI/WebControls/assets/accordion.css b/lib/prado/framework/Web/UI/WebControls/assets/accordion.css
new file mode 100644
index 0000000..842868e
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/assets/accordion.css
@@ -0,0 +1,28 @@
+
+div.accordion {
+ position: relative;
+}
+
+div.accordion-header {
+ padding: 3px;
+ z-index: 10; position: relative;
+ cursor: pointer;
+ background-color: #5577aa;
+ color: white; font-weight: bold;
+ border: 1px solid;
+}
+
+div.accordion-header-active {
+ padding: 3px;
+ z-index: 10; position: relative;
+ cursor: pointer;
+ background-color: #334477;
+ color: red; font-weight: bold;
+ border: 1px solid red;
+}
+
+div.accordion-view {
+ overflow: auto;
+ padding-left: 3px; padding-right: 3px;
+ margin-bottom: 2px;
+}
diff --git a/lib/prado/framework/Web/UI/WebControls/assets/captcha.php b/lib/prado/framework/Web/UI/WebControls/assets/captcha.php
new file mode 100644
index 0000000..bc20a57
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/assets/captcha.php
@@ -0,0 +1,223 @@
+<?php
+/**
+ * CAPTCHA generator script.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System.Web.UI.WebControls.assets
+ */
+
+define('THEME_OPAQUE_BACKGROUND',0x0001);
+define('THEME_NOISY_BACKGROUND',0x0002);
+define('THEME_HAS_GRID',0x0004);
+define('THEME_HAS_SCRIBBLE',0x0008);
+define('THEME_MORPH_BACKGROUND',0x0010);
+define('THEME_SHADOWED_TEXT',0x0020);
+
+require_once(dirname(__FILE__).'/captcha_key.php');
+
+$token='error';
+$theme=0;
+
+if(isset($_GET['options']))
+{
+ $str=base64_decode($_GET['options']);
+ if(strlen($str)>32)
+ {
+ $hash=substr($str,0,32);
+ $str=substr($str,32);
+ if(md5($privateKey.$str)===$hash)
+ {
+ $options=unserialize($str);
+ $publicKey=$options['publicKey'];
+ $tokenLength=$options['tokenLength'];
+ $caseSensitive=$options['caseSensitive'];
+ $alphabet=$options['alphabet'];
+ $fontSize=$options['fontSize'];
+ $theme=$options['theme'];
+ if(($randomSeed=$options['randomSeed'])>0)
+ srand($randomSeed);
+ else
+ srand((int)(microtime()*1000000));
+ $token=generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive);
+ }
+ }
+}
+
+displayToken($token,$fontSize,$theme);
+
+function generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive)
+{
+ $token=substr(hash2string(md5($publicKey.$privateKey),$alphabet).hash2string(md5($privateKey.$publicKey),$alphabet),0,$tokenLength);
+ return $caseSensitive?$token:strtoupper($token);
+}
+
+function hash2string($hex,$alphabet)
+{
+ if(strlen($alphabet)<2)
+ $alphabet='234578adefhijmnrtABDEFGHJLMNRT';
+ $hexLength=strlen($hex);
+ $base=strlen($alphabet);
+ $result='';
+ for($i=0;$i<$hexLength;$i+=6)
+ {
+ $number=hexdec(substr($hex,$i,6));
+ while($number)
+ {
+ $result.=$alphabet[$number%$base];
+ $number=floor($number/$base);
+ }
+ }
+ return $result;
+}
+
+function displayToken($token,$fontSize,$theme)
+{
+ if(($fontSize=(int)$fontSize)<22)
+ $fontSize=22;
+ if($fontSize>100)
+ $fontSize=100;
+ $length=strlen($token);
+ $padding=10;
+ $fontWidth=$fontSize;
+ $fontHeight=floor($fontWidth*1.5);
+ $width=$fontWidth*$length+$padding*2;
+ $height=$fontHeight;
+ $image=imagecreatetruecolor($width,$height);
+
+ addBackground
+ (
+ $image, $width, $height,
+ $theme&THEME_OPAQUE_BACKGROUND,
+ $theme&THEME_NOISY_BACKGROUND,
+ $theme&THEME_HAS_GRID,
+ $theme&THEME_HAS_SCRIBBLE,
+ $theme&THEME_MORPH_BACKGROUND
+ );
+
+ $font=dirname(__FILE__).DIRECTORY_SEPARATOR.'verase.ttf';
+
+ if(function_exists('imagefilter'))
+ imagefilter($image,IMG_FILTER_GAUSSIAN_BLUR);
+
+ $hasShadow=($theme&THEME_SHADOWED_TEXT);
+ for($i=0;$i<$length;$i++)
+ {
+ $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220));
+ $size=rand($fontWidth-10,$fontWidth);
+ $angle=rand(-30,30);
+ $x=$padding+$i*$fontWidth;
+ $y=rand($fontHeight-15,$fontHeight-10);
+ imagettftext($image,$size,$angle,$x,$y,$color,$font,$token[$i]);
+ if($hasShadow)
+ imagettftext($image,$size,$angle,$x+2,$y+2,$color,$font,$token[$i]);
+ imagecolordeallocate($image,$color);
+ }
+
+ header('Content-Type: image/png');
+ imagepng($image);
+ imagedestroy($image);
+}
+
+function addBackground($image,$width,$height,$opaque,$noisy,$hasGrid,$hasScribble,$morph)
+{
+ $background=imagecreatetruecolor($width*2,$height*2);
+ $white=imagecolorallocate($background,255,255,255);
+ imagefill($background,0,0,$white);
+
+ if($opaque)
+ imagefill($background,0,0,imagecolorallocate($background,100,100,100));
+
+ if($noisy)
+ addNoise($background,$width*2,$height*2);
+
+ if($hasGrid)
+ addGrid($background,$width*2,$height*2);
+
+ if($hasScribble)
+ addScribble($background,$width*2,$height*2);
+
+ if($morph)
+ morphImage($background,$width*2,$height*2);
+
+ imagecopy($image,$background,0,0,30,30,$width,$height);
+
+ if(!$opaque)
+ imagecolortransparent($image,$white);
+}
+
+function addNoise($image,$width,$height)
+{
+ for($x=0;$x<$width;++$x)
+ {
+ for($y=0;$y<$height;++$y)
+ {
+ if(rand(0,100)<25)
+ {
+ $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220));
+ imagesetpixel($image,$x,$y,$color);
+ imagecolordeallocate($image,$color);
+ }
+ }
+ }
+}
+
+function addGrid($image,$width,$height)
+{
+ for($i=0;$i<$width;$i+=rand(15,25))
+ {
+ imagesetthickness($image,rand(2,6));
+ $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180));
+ imageline($image,$i+rand(-10,20),0,$i+rand(-10,20),$height,$color);
+ imagecolordeallocate($image,$color);
+ }
+ for($i=0;$i<$height;$i+=rand(15,25))
+ {
+ imagesetthickness($image,rand(2,6));
+ $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180));
+ imageline($image,0,$i+rand(-10,20),$width,$i+rand(-10,20),$color);
+ imagecolordeallocate($image,$color);
+ }
+}
+
+function addScribble($image,$width,$height)
+{
+ for($i=0;$i<8;$i++)
+ {
+ $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180));
+ $points=array();
+ for($j=1;$j<rand(5,10);$j++)
+ {
+ $points[]=rand(2*(20*($i+1)),2*(50*($i+1)));
+ $points[]=rand(30,$height+30);
+ }
+ imagesetthickness($image,rand(2,6));
+ imagepolygon($image,$points,intval(sizeof($points)/2),$color);
+ imagecolordeallocate($image,$color);
+ }
+}
+
+function morphImage($image,$width,$height)
+{
+ $tempImage=imagecreatetruecolor($width,$height);
+ $chunk=rand(1,5);
+ for($x=$y=0;$x<$width;$x+=$chunk)
+ {
+ $chunk=rand(1,5);
+ $y+=rand(-1,1);
+ if($y>=$height) $y=$height-5;
+ if($y<0) $y=5;
+ imagecopy($tempImage,$image,$x,0,$x,$y,$chunk,$height);
+ }
+ for($x=$y=0;$y<$height;$y+=$chunk)
+ {
+ $chunk=rand(1,5);
+ $x+=rand(-1,1);
+ if($x>=$width) $x=$width-5;
+ if($x<0) $x=5;
+ imagecopy($image,$tempImage,$x,$y,0,$y,$width,$chunk);
+ }
+}
+
diff --git a/lib/prado/framework/Web/UI/WebControls/assets/keyboard.css b/lib/prado/framework/Web/UI/WebControls/assets/keyboard.css
new file mode 100644
index 0000000..ad88d76
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/assets/keyboard.css
@@ -0,0 +1,80 @@
+div.Keyboard
+{
+ -moz-background-clip: -moz-initial;
+ -moz-background-origin: -moz-initial;
+ -moz-background-inline-policy: -moz-initial;
+ -moz-user-select: none;
+
+ display: block;
+ position: absolute;
+ border: 1px solid #698977;
+ background-color: #DDDDDD;
+ z-index: 1000 !important;
+ visibility: hidden;
+ padding: 4px 4px 4px 4px;
+ text-align: center;
+}
+
+div.Keyboard div.Line
+{
+ width: 267px;
+ height: 18px;
+}
+
+div.Keyboard div.Key
+{
+ width: 17px;
+ height: 17px;
+ margin: 1px 0px 0px 1px;
+ overflow: hidden;
+ float: left;
+ display: inline;
+}
+
+div.Keyboard div.Key div.Key1,
+div.Keyboard div.Key div.Key2
+{
+ overflow: hidden;
+ border: 1px solid #A5A5A5;
+ background-color: #F7F7F7;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+ color: #556C5F;
+ font-weight: normal;
+ text-align: center;
+ line-height: 15px;
+ vertical-align: middle;
+ display: block;
+ cursor: pointer;
+}
+
+div.Keyboard div.Key div.Hover
+{
+ color: #E02C03;
+ border-color: #E0431D;
+}
+
+div.Keyboard div.Key div.Active
+{
+ color: #FFFFFF;
+ background-color: #E0431D;
+}
+
+div.Keyboard.Shift div.Key div.Key1,
+div.Keyboard.Caps div.L div.Key1,
+div.Keyboard.Off div.Key div.Key2
+{
+ display: none;
+}
+
+div.Keyboard.Caps div.L div.Key2
+{
+ display: block;
+}
+
+div.Keyboard div.Bksp {width: 31px;}
+div.Keyboard div.Exit {width: 33px;}
+div.Keyboard div.Caps {width: 33px;}
+div.Keyboard div.\\ {width: 24px;}
+div.Keyboard div.Del {width: 24px;}
+div.Keyboard div.Shift {width: 42px;} \ No newline at end of file
diff --git a/lib/prado/framework/Web/UI/WebControls/assets/tabpanel.css b/lib/prado/framework/Web/UI/WebControls/assets/tabpanel.css
new file mode 100644
index 0000000..43a42c6
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/assets/tabpanel.css
@@ -0,0 +1,71 @@
+.tab-panel
+{
+ position: relative;
+ float: left;
+ width: 100%;
+}
+
+.tab-normal
+{
+ font-family: Verdana, Helvetica, Arial;
+ font-size: 12px;
+ display: inline;
+ margin: 1px -5px 1px 5px;
+ float: left;
+ padding: 3px 6px 4px 6px;
+ background: rgb(234,242,255);
+ border: 1px solid;
+ border-color: rgb(120,172,255);
+ z-index: 1;
+ position: relative;
+ top: 0;
+}
+
+.tab-active
+{
+ position: relative;
+ display: inline;
+ float: left;
+
+ font-family: Verdana, Helvetica, Arial;
+ font-size: 12px;
+
+ border: 1px solid rgb(120,172,255);
+ border-bottom: 0;
+ z-index: 3;
+ padding: 2px 6px 8px 6px;
+ margin: 1px -6px -2px 0px;
+ top: -2px;
+ background: white;
+}
+
+.tab-view
+{
+ clear: both;
+ border: 1px solid rgb(120,172,255);
+ z-index: 2;
+ position: relative;
+ top: -2px;
+ padding: 10px;
+}
+
+.tab-active a
+{
+ color: black;
+ text-decoration: none;
+ font-weight: bold;
+}
+
+.tab-normal a
+{
+ color: gray;
+ text-decoration: none;
+ font-weight: bold;
+}
+
+.tab-normal a:hover, .tab-normal a:focus
+{
+ color: rgb(120,172,255);
+ text-decoration: none;
+ font-weight: bold;
+} \ No newline at end of file
diff --git a/lib/prado/framework/Web/UI/WebControls/assets/verase.ttf b/lib/prado/framework/Web/UI/WebControls/assets/verase.ttf
new file mode 100644
index 0000000..4b4ecc6
--- /dev/null
+++ b/lib/prado/framework/Web/UI/WebControls/assets/verase.ttf
Binary files differ