diff --git a/.gitignore b/.gitignore index 4b830bf..b2a87c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,17 @@ *.un~ build/test/*.xml build/build.properties +build/coverage +build/extended config.php modules/db/conf/protean-conf.php modules/db/sql/sqldb.map +modules/db/sql/schema.sql modules/list/misc/ modules/db/lib/om modules/db/lib/map build/runtime-conf.xml +build/buildtime-conf.xml build/schema-transformed.xml build/schema.xml build/tests diff --git a/build/build-dist.properties b/build/build-dist.properties index ceab86b..7df646b 100644 --- a/build/build-dist.properties +++ b/build/build-dist.properties @@ -15,7 +15,7 @@ propel.database.classname = DebugPDO propel.mysql.path = /usr/bin/mysql propel.mysql.tableType = InnoDB -propel.generator.buildpath = /usr/lib/php/data/propel_generator +propel.generator.buildpath = /usr/lib/php/pear/data/propel_generator propel.addGenericAccessors = true propel.addGenericMutators = true propel.addTimeStamp = false \ No newline at end of file diff --git a/config-dist.php b/config-dist.php index 4bd5c6c..6277a1f 100644 --- a/config-dist.php +++ b/config-dist.php @@ -18,7 +18,7 @@ // BUILD SETTINGS -define('PF_VERSION','4.0'); +define('PF_VERSION','4.1'); define('PF_ENVIRONMENT', 'development'); @@ -60,14 +60,10 @@ // TEMPLATE/FORM SETTINGS -define('PF_TEMPLATE_FORCE_RECOMPILE', true); +define('PF_TEMPLATE_FORCE_RECOMPILE', false); define('PF_FORM_FIELD_ERROR_HIGHLIGHTING', true); -// CMS SETTINGS -define('PF_CMS_ENABLED', false); - - // SESSION SETTINGS define('PF_SESSION_NAME', 'id'); define('PF_SESSION_PERSIST_NAME', 'persist'); @@ -83,12 +79,21 @@ define('PF_CACHE_ENABLED', true); define('PF_CACHE_USER_TTL', 3600); define('PF_CACHE_CONTROLLER_MAP', false); +define('PF_CACHE_TEMPLATES', false); define('PF_CACHE_MEMCACHE_SERVER_HOST_1', false); define('PF_CACHE_MEMCACHE_SERVER_HOST_2', false); define('PF_CACHE_MEMCACHE_SERVER_HOST_3', false); define('PF_CACHE_MEMCACHE_SERVER_HOST_4', false); +define('PF_CDN_URL', '%%PHING_PROTEAN_URL%%'); + + +// JOB QUEUE SETTINGS +define('PF_JOBQUEUE_HOST', '127.0.0.1'); +define('PF_JOBQUEUE_PORT', 11300); +define('PF_JOBQUEUE_CONN_TIMEOUT', null); + // MAILER SETTINGS define('PF_EMAIL_USE_SMTP', false); @@ -127,8 +132,7 @@ define('PF_SHOP_EMAIL_ADMINS', false); define('PF_SHOP_GATEWAY_DEBUG', true); -define('PF_SHOP_GATEWAY_LOG', '%%PHING_PROTEAN_BASEDIR%%/logs/pf_authnet_gateway.log'); -define('PF_SHOP_CIM_LOG', '%%PHING_PROTEAN_BASEDIR%%/logs/pf_authnet_cim.log'); +define('PF_SHOP_GATEWAY_LOG', '%%PHING_PROTEAN_BASEDIR%%/logs/pf_gateway.log'); define('PF_SHOP_GATEWAY_AUTHNET_TEST_REQUEST', true); define('PF_SHOP_GATEWAY_AUTHNET_LOGIN', 'abc'); @@ -140,6 +144,23 @@ define('PF_SHOP_GATEWAY_AUTHNET_CIM_PORT', '443'); define('PF_SHOP_GATEWAY_AUTHNET_CIM_PATH', '/xml/v1/request.api'); +define('PF_SHOP_GATEWAY_STRIPE_TEST_REQUEST', true); +define('PF_SHOP_GATEWAY_STRIPE_TEST_SECRET_KEY', 'D7bES9biF1eeGhBENJrnQO6tDVMrnt5o'); +define('PF_SHOP_GATEWAY_STRIPE_TEST_PUBLISH_KEY', 'pk_3GALjNFDV4KXTd4QPkLBibsHpXkar'); +define('PF_SHOP_GATEWAY_STRIPE_LIVE_SECRET_KEY', 'sTHNScUGnEXIhVcmiibWrSPYCevHlx1Y'); +define('PF_SHOP_GATEWAY_STRIPE_LIVE_PUBLISH_KEY', 'pk_sn1AJYs7zVjkWG6ubFBj2rpMFy9Ko'); +define('PF_SHOP_GATEWAY_STRIPE_SCRIPT', 'https://js.stripe.com/v1/'); + +define('PF_SHOP_GATEWAY_PAYPAL_TEST_REQUEST', true); +define('PF_SHOP_GATEWAY_PAYPAL_LOG', '/www/standard/www.missouriquiltco.com/logs/pf_paypal.log'); +define('PF_SHOP_GATEWAY_PAYPAL_SELLER_EMAIL', 'ericj_1354059916_biz@loopshot.com'); + +define('PF_USPS_RATECALCULATOR_USERNAME', '493MISSO0374'); + +define('PF_ES_HOST_1', 'localhost'); +define('PF_ES_HOST_2', false); +define('PF_ES_HOST_3', false); +define('PF_ES_HOST_4', false); // SITE SPECIFIC DEFINES diff --git a/crossdomain.xml b/crossdomain.xml new file mode 100755 index 0000000..0d42929 --- /dev/null +++ b/crossdomain.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/api/lib/httprequest.class.php b/modules/api/lib/httprequest.class.php new file mode 100644 index 0000000..d9dcfb8 --- /dev/null +++ b/modules/api/lib/httprequest.class.php @@ -0,0 +1,81 @@ +request('get', $url, $credentials, null, $status, $wait); + } + + public function post($url, $credentials, $data, $status=null, $wait=3) { + return $this->request('post', $url, $credentials, $data, $status, $wait); + } + + public function put($url, $credentials, $data, $status=null, $wait=3) { + return $this->request('put', $url, $credentials, $data, $status, $wait); + } + + public function delete($url, $credentials, $status=null, $wait=3) { + return $this->request('delete', $url, $credentials, null, $status, $wait); + } + + protected function request($verb, $url, $credentials, $fields=null, $status=null) { + $time = microtime(true); + + //$fields = (is_array($fields)) ? http_build_query($fields) : $fields; + printr($verb); + printr($url); + printr($credentials); + printr($fields); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $verb); + //curl_setopt($ch, CURLOPT_HEADER, TRUE); + if ($credentials) { + curl_setopt($ch, CURLOPT_USERPWD, $credentials); + } + if ($verb == 'post' || $verb == 'put') { + curl_setopt($ch, CURLOPT_POSTFIELDS, array($fields)); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json; charset=utf-8')); + } + //curl_setopt($ch, CURLOPT_NOBODY, TRUE); // remove body + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + $head = curl_exec($ch); + if (!$head) { + printr(curl_error($ch)); + return false; + } + + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + printr('CURL VERB:'); + printr($verb); + printr('CURL OUTPUT:'); + printr($head); + + if ($status === null) { + if ($httpCode < 400) { + return $head; + } else { + return false; + } + } elseif ($status == $httpCode) { + return $head; + } + + return false; + } +} +?> \ No newline at end of file diff --git a/modules/api/lib/jobqueue.class.php b/modules/api/lib/jobqueue.class.php new file mode 100644 index 0000000..9098736 --- /dev/null +++ b/modules/api/lib/jobqueue.class.php @@ -0,0 +1,63 @@ +bs = new Pheanstalk(PF_JOBQUEUE_HOST, PF_JOBQUEUE_PORT, PF_JOBQUEUE_CONN_TIMEOUT); + } + + public function put($tube, $payload) { + return $this->bs->putInTube($tube, $payload); + } + + public function reserve($tube) { + return $this->bs->reserveFromTube($tube); + } + + public function bury($job) { + return $this->bs->bury($job); + } + + public function delete($job) { + return $this->bs->delete($job); + } + + public function statsTube($tube) { + return $this->bs->statsTube($tube); + } + + public function peekReady($tube) { + return $this->bs->peekReady($tube); + } + + public function clearTube($tube) { + try { + $stats = $this->statsTube($tube); + } catch (Exception $e) { + if ($e->getMessage() == 'Server reported NOT_FOUND') { + return false; + } + } + + while ($stats->{'current-jobs-ready'} > 0) { + $this->delete($this->peekReady($tube)); + $stats = $this->statsTube($tube); + } + } +} + +?> \ No newline at end of file diff --git a/modules/api/test/unit/httprequest.class.php b/modules/api/test/unit/httprequest.class.php new file mode 100644 index 0000000..d9dcfb8 --- /dev/null +++ b/modules/api/test/unit/httprequest.class.php @@ -0,0 +1,81 @@ +request('get', $url, $credentials, null, $status, $wait); + } + + public function post($url, $credentials, $data, $status=null, $wait=3) { + return $this->request('post', $url, $credentials, $data, $status, $wait); + } + + public function put($url, $credentials, $data, $status=null, $wait=3) { + return $this->request('put', $url, $credentials, $data, $status, $wait); + } + + public function delete($url, $credentials, $status=null, $wait=3) { + return $this->request('delete', $url, $credentials, null, $status, $wait); + } + + protected function request($verb, $url, $credentials, $fields=null, $status=null) { + $time = microtime(true); + + //$fields = (is_array($fields)) ? http_build_query($fields) : $fields; + printr($verb); + printr($url); + printr($credentials); + printr($fields); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $verb); + //curl_setopt($ch, CURLOPT_HEADER, TRUE); + if ($credentials) { + curl_setopt($ch, CURLOPT_USERPWD, $credentials); + } + if ($verb == 'post' || $verb == 'put') { + curl_setopt($ch, CURLOPT_POSTFIELDS, array($fields)); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json; charset=utf-8')); + } + //curl_setopt($ch, CURLOPT_NOBODY, TRUE); // remove body + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + $head = curl_exec($ch); + if (!$head) { + printr(curl_error($ch)); + return false; + } + + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + printr('CURL VERB:'); + printr($verb); + printr('CURL OUTPUT:'); + printr($head); + + if ($status === null) { + if ($httpCode < 400) { + return $head; + } else { + return false; + } + } elseif ($status == $httpCode) { + return $head; + } + + return false; + } +} +?> \ No newline at end of file diff --git a/modules/api/test/unit/jobqueue.class.php b/modules/api/test/unit/jobqueue.class.php new file mode 100644 index 0000000..9098736 --- /dev/null +++ b/modules/api/test/unit/jobqueue.class.php @@ -0,0 +1,63 @@ +bs = new Pheanstalk(PF_JOBQUEUE_HOST, PF_JOBQUEUE_PORT, PF_JOBQUEUE_CONN_TIMEOUT); + } + + public function put($tube, $payload) { + return $this->bs->putInTube($tube, $payload); + } + + public function reserve($tube) { + return $this->bs->reserveFromTube($tube); + } + + public function bury($job) { + return $this->bs->bury($job); + } + + public function delete($job) { + return $this->bs->delete($job); + } + + public function statsTube($tube) { + return $this->bs->statsTube($tube); + } + + public function peekReady($tube) { + return $this->bs->peekReady($tube); + } + + public function clearTube($tube) { + try { + $stats = $this->statsTube($tube); + } catch (Exception $e) { + if ($e->getMessage() == 'Server reported NOT_FOUND') { + return false; + } + } + + while ($stats->{'current-jobs-ready'} > 0) { + $this->delete($this->peekReady($tube)); + $stats = $this->statsTube($tube); + } + } +} + +?> \ No newline at end of file diff --git a/modules/content/tpl/default/css/960.css b/modules/content/tpl/default/css/960.css deleted file mode 100644 index 1b17e2f..0000000 --- a/modules/content/tpl/default/css/960.css +++ /dev/null @@ -1 +0,0 @@ -.container_12,.container_16{margin-left:auto;margin-right:auto;width:960px}.grid_1,.grid_2,.grid_3,.grid_4,.grid_5,.grid_6,.grid_7,.grid_8,.grid_9,.grid_10,.grid_11,.grid_12,.grid_13,.grid_14,.grid_15,.grid_16{display:inline;float:left;margin-left:10px;margin-right:10px}.container_12 .grid_3,.container_16 .grid_4{width:220px}.container_12 .grid_6,.container_16 .grid_8{width:460px}.container_12 .grid_9,.container_16 .grid_12{width:700px}.container_12 .grid_12,.container_16 .grid_16{width:940px}.alpha{margin-left:0}.omega{margin-right:0}.container_12 .grid_1{width:60px}.container_12 .grid_2{width:140px}.container_12 .grid_4{width:300px}.container_12 .grid_5{width:380px}.container_12 .grid_7{width:540px}.container_12 .grid_8{width:620px}.container_12 .grid_10{width:780px}.container_12 .grid_11{width:860px}.container_16 .grid_1{width:40px}.container_16 .grid_2{width:100px}.container_16 .grid_3{width:160px}.container_16 .grid_5{width:280px}.container_16 .grid_6{width:340px}.container_16 .grid_7{width:400px}.container_16 .grid_9{width:520px}.container_16 .grid_10{width:580px}.container_16 .grid_11{width:640px}.container_16 .grid_13{width:760px}.container_16 .grid_14{width:820px}.container_16 .grid_15{width:880px}.container_12 .prefix_3,.container_16 .prefix_4{padding-left:240px}.container_12 .prefix_6,.container_16 .prefix_8{padding-left:480px}.container_12 .prefix_9,.container_16 .prefix_12{padding-left:720px}.container_12 .prefix_1{padding-left:80px}.container_12 .prefix_2{padding-left:160px}.container_12 .prefix_4{padding-left:320px}.container_12 .prefix_5{padding-left:400px}.container_12 .prefix_7{padding-left:560px}.container_12 .prefix_8{padding-left:640px}.container_12 .prefix_10{padding-left:800px}.container_12 .prefix_11{padding-left:880px}.container_16 .prefix_1{padding-left:60px}.container_16 .prefix_2{padding-left:120px}.container_16 .prefix_3{padding-left:180px}.container_16 .prefix_5{padding-left:300px}.container_16 .prefix_6{padding-left:360px}.container_16 .prefix_7{padding-left:420px}.container_16 .prefix_9{padding-left:540px}.container_16 .prefix_10{padding-left:600px}.container_16 .prefix_11{padding-left:660px}.container_16 .prefix_13{padding-left:780px}.container_16 .prefix_14{padding-left:840px}.container_16 .prefix_15{padding-left:900px}.container_12 .suffix_3,.container_16 .suffix_4{padding-right:240px}.container_12 .suffix_6,.container_16 .suffix_8{padding-right:480px}.container_12 .suffix_9,.container_16 .suffix_12{padding-right:720px}.container_12 .suffix_1{padding-right:80px}.container_12 .suffix_2{padding-right:160px}.container_12 .suffix_4{padding-right:320px}.container_12 .suffix_5{padding-right:400px}.container_12 .suffix_7{padding-right:560px}.container_12 .suffix_8{padding-right:640px}.container_12 .suffix_10{padding-right:800px}.container_12 .suffix_11{padding-right:880px}.container_16 .suffix_1{padding-right:60px}.container_16 .suffix_2{padding-right:120px}.container_16 .suffix_3{padding-right:180px}.container_16 .suffix_5{padding-right:300px}.container_16 .suffix_6{padding-right:360px}.container_16 .suffix_7{padding-right:420px}.container_16 .suffix_9{padding-right:540px}.container_16 .suffix_10{padding-right:600px}.container_16 .suffix_11{padding-right:660px}.container_16 .suffix_13{padding-right:780px}.container_16 .suffix_14{padding-right:840px}.container_16 .suffix_15{padding-right:900px}html body div.clear,html body span.clear{background:none;border:0;clear:both;display:block;float:none;font-size:0;margin:0;padding:0;overflow:hidden;visibility:hidden;width:0;height:0}.clearfix:after{clear:both;content:'.';display:block;visibility:hidden;height:0}.clearfix{display:inline-block}* html .clearfix{height:1%}.clearfix{display:block} \ No newline at end of file diff --git a/modules/content/tpl/default/css/protean.css b/modules/content/tpl/default/css/protean.css new file mode 100755 index 0000000..8a68fdc --- /dev/null +++ b/modules/content/tpl/default/css/protean.css @@ -0,0 +1,58 @@ +/* @group Universal Selectors */ +/* @end */ + +/* @group Element Selectors */ +/* @end */ + +/* @group Class, Attribute, and Pseudo Selectors */ +.disabled { + color: #999999; +} +.enabled { + color: #ff6f00; + font-weight: bold; +} +.yes { + color: #00ad11; +} +.no { + color: #990000; +} +.notice { + color: #968672; + font-weight: bold; + margin: 0 0 10px; +} +.error { + color: #F00; + font-weight: bold; + margin: 0 0 10px; +} +.errorfield { + background: #f3d3c7; + color: #333333; +} +.required { + color: #ff6f00; + font-weight: bold; +} +.left { + float: left; + text-align: left; +} +.right { + float: right; + text-align: right; +} +/* @end */ + +/* @group ID Selectors */ +#errorstack { + color: #F00; + font-weight: bold; + padding: 12px 40px; + position: relative; + top: 100px; + width: 880px; + background: url("../images/40-percent-opacity-black.png") repeat scroll 0 0 transparent; letter-spacing: .5px; } +/* @end */ diff --git a/modules/content/tpl/default/css/style.css b/modules/content/tpl/default/css/style.css index 75e40b2..e69de29 100644 --- a/modules/content/tpl/default/css/style.css +++ b/modules/content/tpl/default/css/style.css @@ -1,192 +0,0 @@ -/* HTML5 Boilerplate */ - -html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, -abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, -small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, figcaption, figure, footer, header, hgroup, -menu, nav, section, summary, time, mark, audio, video { - margin:0; - padding:0; - border:0; - outline:0; - font-size:100%; - vertical-align:baseline; - background:transparent; -} -article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { - display:block; -} -nav ul { list-style:none; } -blockquote, q { quotes:none; } -blockquote:before, blockquote:after, -q:before, q:after { content:''; content:none; } -a { margin:0; padding:0; font-size:100%; vertical-align:baseline; background:transparent; } -ins { background-color:#ff9; color:#000; text-decoration:none; } -mark { background-color:#ff9; color:#000; font-style:italic; font-weight:bold; } -del { text-decoration: line-through; } -abbr[title], dfn[title] { border-bottom:1px dotted; cursor:help; } -table { border-collapse:collapse; border-spacing:0; } -hr { display:block; height:1px; border:0; border-top:1px solid #333; margin:1em 0; padding:0; } -input, select { vertical-align:middle; } - - -body { font:13px/1.231 sans-serif; *font-size:small; } -select, input, textarea, button { font:99% sans-serif; } -pre, code, kbd, samp { font-family: monospace, sans-serif; } - -body, select, input, textarea { color: #444; } -h1,h2,h3,h4,h5,h6 { font-weight: bold; } -html { overflow-y: scroll; } - -a:hover, a:active { outline: none; } -a, a:active, a:visited { color: #607890; } -a:hover { color: #036; } - -ul, ol { margin: 0; } -ol { list-style-type: decimal; } - -nav ul, nav li { margin: 0; } -small { font-size: 85%; } -strong, th { font-weight: bold; } -td, td img { vertical-align: top; } -sub { vertical-align: sub; font-size: smaller; } -sup { vertical-align: super; font-size: smaller; } -pre { padding: 15px; white-space: pre; white-space: pre-wrap; white-space: pre-line; word-wrap: break-word; } -textarea { overflow: auto; } -.ie6 legend, .ie7 legend { margin-left: -7px; } -input[type="radio"] { vertical-align: text-bottom; } -input[type="checkbox"] { vertical-align: bottom; } -.ie7 input[type="checkbox"] { vertical-align: baseline; } -.ie6 input { vertical-align: text-bottom; } -input[type=button], input[type=submit], button { cursor: pointer; } -button, input, select, textarea { margin: 0; } -input:valid, textarea:valid { } -input:invalid, textarea:invalid { border-radius: 1px; -moz-box-shadow: 0px 0px 5px red; -webkit-box-shadow: 0px 0px 5px red; box-shadow: 0px 0px 5px red; } -.no-boxshadow input:invalid, -.no-boxshadow textarea:invalid { background-color: #f0dddd; } - -::-moz-selection{ background: #FF5E99; color:#fff; text-shadow: none; } -::selection { background:#FF5E99; color:#fff; text-shadow: none; } -a:link { -webkit-tap-highlight-color: #FF5E99; } - -button { width: auto; overflow: visible; } -.ie7 img { -ms-interpolation-mode: bicubic; } - -.ir { display: block; text-indent: -999em; overflow: hidden; background-repeat: no-repeat; text-align: left; direction: ltr; } -.hidden { display: none; visibility: hidden; } -.visuallyhidden { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px, 1px, 1px, 1px); } -.invisible { visibility: hidden; } -.clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; visibility: hidden; } -.clearfix:after { clear: both; } -.clearfix { zoom: 1; } - - - /* Primary Styles - Author: - */ - - - - - - - - - - - - - - -@media all and (orientation:portrait) { - -} - -@media all and (orientation:landscape) { - -} - -@media screen and (max-device-width: 480px) { - - - /* html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */ -} - -@media print { - * { background: transparent !important; color: #444 !important; text-shadow: none !important; } - a, a:visited { color: #444 !important; text-decoration: underline; } - a:after { content: " (" attr(href) ")"; } - abbr:after { content: " (" attr(title) ")"; } - .ir a:after { content: ""; } - pre, blockquote { border: 1px solid #999; page-break-inside: avoid; } - thead { display: table-header-group; } - tr, img { page-break-inside: avoid; } - @page { margin: 0.5cm; } - p, h2, h3 { orphans: 3; widows: 3; } - h2, h3{ page-break-after: avoid; } -}.container_12,.container_16{margin-left:auto;margin-right:auto;width:960px}.grid_1,.grid_2,.grid_3,.grid_4,.grid_5,.grid_6,.grid_7,.grid_8,.grid_9,.grid_10,.grid_11,.grid_12,.grid_13,.grid_14,.grid_15,.grid_16{display:inline;float:left;margin-left:10px;margin-right:10px}.container_12 .grid_3,.container_16 .grid_4{width:220px}.container_12 .grid_6,.container_16 .grid_8{width:460px}.container_12 .grid_9,.container_16 .grid_12{width:700px}.container_12 .grid_12,.container_16 .grid_16{width:940px}.alpha{margin-left:0}.omega{margin-right:0}.container_12 .grid_1{width:60px}.container_12 .grid_2{width:140px}.container_12 .grid_4{width:300px}.container_12 .grid_5{width:380px}.container_12 .grid_7{width:540px}.container_12 .grid_8{width:620px}.container_12 .grid_10{width:780px}.container_12 .grid_11{width:860px}.container_16 .grid_1{width:40px}.container_16 .grid_2{width:100px}.container_16 .grid_3{width:160px}.container_16 .grid_5{width:280px}.container_16 .grid_6{width:340px}.container_16 .grid_7{width:400px}.container_16 .grid_9{width:520px}.container_16 .grid_10{width:580px}.container_16 .grid_11{width:640px}.container_16 .grid_13{width:760px}.container_16 .grid_14{width:820px}.container_16 .grid_15{width:880px}.container_12 .prefix_3,.container_16 .prefix_4{padding-left:240px}.container_12 .prefix_6,.container_16 .prefix_8{padding-left:480px}.container_12 .prefix_9,.container_16 .prefix_12{padding-left:720px}.container_12 .prefix_1{padding-left:80px}.container_12 .prefix_2{padding-left:160px}.container_12 .prefix_4{padding-left:320px}.container_12 .prefix_5{padding-left:400px}.container_12 .prefix_7{padding-left:560px}.container_12 .prefix_8{padding-left:640px}.container_12 .prefix_10{padding-left:800px}.container_12 .prefix_11{padding-left:880px}.container_16 .prefix_1{padding-left:60px}.container_16 .prefix_2{padding-left:120px}.container_16 .prefix_3{padding-left:180px}.container_16 .prefix_5{padding-left:300px}.container_16 .prefix_6{padding-left:360px}.container_16 .prefix_7{padding-left:420px}.container_16 .prefix_9{padding-left:540px}.container_16 .prefix_10{padding-left:600px}.container_16 .prefix_11{padding-left:660px}.container_16 .prefix_13{padding-left:780px}.container_16 .prefix_14{padding-left:840px}.container_16 .prefix_15{padding-left:900px}.container_12 .suffix_3,.container_16 .suffix_4{padding-right:240px}.container_12 .suffix_6,.container_16 .suffix_8{padding-right:480px}.container_12 .suffix_9,.container_16 .suffix_12{padding-right:720px}.container_12 .suffix_1{padding-right:80px}.container_12 .suffix_2{padding-right:160px}.container_12 .suffix_4{padding-right:320px}.container_12 .suffix_5{padding-right:400px}.container_12 .suffix_7{padding-right:560px}.container_12 .suffix_8{padding-right:640px}.container_12 .suffix_10{padding-right:800px}.container_12 .suffix_11{padding-right:880px}.container_16 .suffix_1{padding-right:60px}.container_16 .suffix_2{padding-right:120px}.container_16 .suffix_3{padding-right:180px}.container_16 .suffix_5{padding-right:300px}.container_16 .suffix_6{padding-right:360px}.container_16 .suffix_7{padding-right:420px}.container_16 .suffix_9{padding-right:540px}.container_16 .suffix_10{padding-right:600px}.container_16 .suffix_11{padding-right:660px}.container_16 .suffix_13{padding-right:780px}.container_16 .suffix_14{padding-right:840px}.container_16 .suffix_15{padding-right:900px}html body div.clear,html body span.clear{background:none;border:0;clear:both;display:block;float:none;font-size:0;margin:0;padding:0;overflow:hidden;visibility:hidden;width:0;height:0}.clearfix:after{clear:both;content:'.';display:block;visibility:hidden;height:0}.clearfix{display:inline-block}* html .clearfix{height:1%}.clearfix{display:block}/* @group Universal Selectors */ -/* @end */ - -/* @group Element Selectors */ -/* @end */ - -/* @group Class, Attribute, and Pseudo Selectors */ -.disabled { - color: #999999; -} -.enabled { - color: #ff6f00; - font-weight: bold; -} -.yes { - color: #00ad11; -} -.no { - color: #990000; -} -.notice { - color: #968672; - font-weight: bold; - margin: 0 0 10px; -} -.error { - color: #F00; - font-weight: bold; - margin: 0 0 10px; -} -.errorfield { - background: #f3d3c7; - color: #333333; -} -.required { - color: #ff6f00; - font-weight: bold; -} -.left { - float: left; - text-align: left; -} -.right { - float: right; - text-align: right; -} -/* @end */ - -/* @group ID Selectors */ -#errorstack { - color: #F00; - font-weight: bold; - padding-bottom: 5px; -} -#doc { } -#hd { - padding: 10px; - background: #ebf9ff; - clear: both; -} -#ft { - padding-top: 10px; - background-color: white; -} -/* @end */ diff --git a/modules/content/tpl/default/html/ga-js.tpl b/modules/content/tpl/default/html/ga-js.tpl new file mode 100755 index 0000000..fa8398c --- /dev/null +++ b/modules/content/tpl/default/html/ga-js.tpl @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/modules/content/tpl/default/js/utilities.js b/modules/content/tpl/default/js/utilities.js new file mode 100644 index 0000000..7b840f9 --- /dev/null +++ b/modules/content/tpl/default/js/utilities.js @@ -0,0 +1,10 @@ +String.prototype.ucfirst = function() { + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); +}; + +function roundNumber(num, dec) { + var result = String(Math.round(num*Math.pow(10,dec))/Math.pow(10,dec)); + if(result.indexOf('.')<0) {result+= '.';} + while(result.length- result.indexOf('.')<=dec) {result+= '0';} + return result; +}; \ No newline at end of file diff --git a/modules/db/lib/AuthRole.php b/modules/db/lib/AuthRole.php new file mode 100644 index 0000000..97d714c --- /dev/null +++ b/modules/db/lib/AuthRole.php @@ -0,0 +1,18 @@ +helper = PFFactory::getInstance()->createObject('registration.userhelper'); + $this->userId = $this->session->get('user_id'); + $this->partyId = $this->session->get('user_party_id'); + $this->rewardsPointsHelper = PFFactory::getInstance()->createObject('shop.rewardspointshelper'); + $this->page->assign('PARTY_CURRENT_POINTS', $this->rewardsPointsHelper->getCurrentPointsForParty($this->partyId)); + + + } + + public function index(PFRequest $request) { // GET /registration/account + $this->page->assign('user', $this->helper->getUser($this->userId)); + $this->page->assign('orderhistory', $this->helper->getOrderHistoryForParty($this->partyId)); + //$this->page->assign('billingcountries', $this->helper->getAvailableBillingAddressCountries()); + //$this->page->assign('shippingcountries', $this->helper->getAvailableShippingAddressCountries()); + $this->make($request); + return self::statuses('CMD_DEFAULT'); + } + + public function make(PFRequest $request) { // GET /registration/account/make + $form = $this->initializeCreateForm($request); + $this->populateCreateForm($request, $form); + $this->page->assign('FORM_ELEMENTS', $form->renderForm()); + return $this->handleSubmittedCreateForm($request, $form); + } + + public function create(PFRequest $request) { // POST /registration/account + $form = $this->initializeCreateForm($request); + $this->page->assign('FORM_ELEMENTS', $form->renderForm()); + return $this->handleSubmittedCreateForm($request, $form); + } + + public function show(PFRequest $request, $key) { // GET /registration/account/:integer: + return self::statuses('CMD_DEFAULT'); + } + + public function edit(PFRequest $request, $key) { // GET /registration/account/:integer:/edit + return self::statuses('CMD_DEFAULT'); + } + + public function update(PFRequest $request, $key) { // PUT /registration/account/:integer: + try { + $this->helper->updateUser($this->userId, $request); + $json = PFRestHelper::makeResponse('ok', '201', 'User successfully updated'); + PFRestHelper::sendResponse(201, $json); + } catch (Exception $e) { + $e = PFException::enrich($e); + $e->handleRestException(); + } + } + + public function destroy(PFRequest $request, $key) { // DELETE /registration/account/:integer: + PFRestHelper::sendResponse(501, json_encode(array('status' => 'notimplemented')), 'application/json'); + } + + public function initializeCreateForm(PFRequest $request) { + $form = PFFactory::getInstance()->createObject('api.form', $request, 'registration.account', 'createaccount'); + $form->setAction($this->session->getURL('registration/account', true)); + + $emailRule = &patForms::createRule('Email'); + $el = &$form->getFormObject()->getElementByName('email'); + $el->addRule($emailRule, PATFORMS_RULE_AFTER_VALIDATION); + + $passwordRule = &patForms::createRule('PasswordMatch'); + $passwordRule->setPassword1('password'); + $passwordRule->setPassword2('password2'); + $form->getFormObject()->addRule($passwordRule, PATFORMS_RULE_AFTER_VALIDATION); + + $fields = array('firstname', + 'lastname', + 'email', + 'password', + 'password2' + ); + $form->applyTrimFilters($fields); + return $form; + } + + public function populateCreateForm(PFRequest $request, PFForm $form) { + $user = $this->helper->getUser($this->userId); + + $form->getFormObject()->setValues( + array( + 'firstname' => $user->getParty()->getFirstName(), + 'lastname' => $user->getParty()->getLastName(), + 'email' => $user->getParty()->getEmail() + ), + false + ); + } + + protected function handleSubmittedCreateForm(PFRequest $request, PFForm $form) { + if ($form->isSubmitted()) { + if ($form->reportErrors()) { + return self::statuses('CMD_INSUFFICIENT_DATA'); + } + + try { + $this->helper->createUser($request); + $this->helper->login($request->get('email'), $request->get('password')); + } catch (PFException $e) { + $e->handleException(); + return self::statuses('CMD_ERROR'); + } + + if ($this->session->isRegistered('pf.redirect_url')) { + $redirectUrl = '/' . str_replace('.', '/', $this->session->get('pf.redirect_url')); + $this->redirectTo($redirectUrl, true); + } else { + return self::statuses('CMD_OK'); + } + } + } +} + +?> \ No newline at end of file diff --git a/modules/registration/cmd/apilogin.class.php b/modules/registration/cmd/apilogin.class.php new file mode 100755 index 0000000..277d376 --- /dev/null +++ b/modules/registration/cmd/apilogin.class.php @@ -0,0 +1,48 @@ +notImplemented(); + } + + public function handlePost(PFRequest $request) { + $username = $request->get('login-emailaddress'); + $password = $request->get('login-password'); + $persistent = $request->get('rememberlogin'); + $redirectUrl = $this->session->retrieve('pf.session_redirect_url'); + + if (empty($username) || empty($password)) { + return PFRestHelper::sendResponse(400, '{"status":"error","code":"missinginfo","message":"Please enter both an email address and a password"}', 'application/json'); + } + $userHelper = PFFactory::getInstance()->createObject('registration.userhelper'); + + try { + $userHelper->login($username, $password, $persistent); + return PFRestHelper::sendResponse(200, '{"status":"success","code":"loginsucceeded","message":"You are successfully logged in","data":{redirectUrl: ' + $redirectUrl + '}}', 'application/json'); + } catch (Exception $e) { + return PFRestHelper::sendResponse(401, '{"status":"error","code":"loginfailed","message":"Login failed, please try again!"}', 'application/json'); + } + } + + public function handlePut(PFRequest $request) { + return $this->notImplemented(); + } + + public function handleDelete(PFRequest $request) { + return $this->notImplemented(); + } +} +?> \ No newline at end of file diff --git a/modules/registration/cmd/command.xml b/modules/registration/cmd/command.xml new file mode 100755 index 0000000..5ce0c25 --- /dev/null +++ b/modules/registration/cmd/command.xml @@ -0,0 +1,159 @@ + + + + registration.forgot + content.header + content.footer + registration.forgot + + + + registration.forgot + content.header + content.footer + registration.forgot + registration.forgot + + /registration/forgot + + + /registration/passwordresetsent + + + + + registration.static + content.header + content.footer + registration.passwordresetsent + + + + registration.resetpassword + content.header + content.footer + registration.resetpassword + + + + registration.resetpassword + content.header + content.footer + registration.resetpassword + registration.passwordreset.tpl + + /registration/forgot + + + /registration/resetpassword + + + + + registration.login + content.header + content.footer + registration.login + registration.login + + /content/default + + + + + registration.login + content.header + content.footer + registration.login + registration.login + + /content/default + + + + + registration.login + content.empty + content.empty + registration.empty + true + + admin + + registration.login + + /content/default + + + + + registration.apilogin + content.empty + content.empty + content.empty + + + + registration.logout + content.header + content.footer + registration.login + registration.login + + /content/default + + + + + registration.unshadow + content.empty + content.empty + content.empty + + + + registration.account + content.header + content.footer + registration.account + true + + /registration/login + + + /registration/account + + + + + registration.account + content.empty + content.empty + shop.empty + true + + + + registration.account + content.header + content.footer + registration.account + + + + registration.login + content.header + content.footer + registration.login + + /registration/login + + + /registration/login + + + /content/default + + + + \ No newline at end of file diff --git a/modules/registration/cmd/forgot.class.php b/modules/registration/cmd/forgot.class.php new file mode 100755 index 0000000..dad74b1 --- /dev/null +++ b/modules/registration/cmd/forgot.class.php @@ -0,0 +1,63 @@ +helper = PFFactory::getInstance()->createObject('registration.userhelper'); + + $form = $this->initializeForm($request); + $this->populateForm($request, $form); + $this->page->assign('FORM_ELEMENTS', $form->renderForm()); + return $this->handleSubmittedForm($request, $form); + } + + public function initializeForm(PFRequest $request) { + $form = PFFactory::getInstance()->createObject('api.form', $request, 'registration.forgot', 'reset'); + $form->setAction($this->session->getURL('registration/forgot')); + $fields = array('email'); + $form->applyTrimFilters($fields); + + return $form; + } + + public function populateForm(PFRequest $request, PFForm $form) { } + + public function handleSubmittedForm(PFRequest $request, PFForm $form) { + + if ($form->isSubmitted()) { + if ($form->reportErrors()) { + return self::statuses('CMD_INSUFFICIENT_DATA'); + } + + $con = Propel::getConnection(PF_DATABASE_NAME); + $con->beginTransaction(); + + try { + if (!$this->helper->doesEmailExist($request->get('email'))) { + throw new PFException('', 'The e-mail address "' . $request->get('email') . '" cannot be found. Please try again.', E_USER_WARNING); + } + $this->helper->setResetPasswordKey($request->get('email'), $con); + $con->commit(); + + } catch (PFException $e) { + $e->handleException(); + return self::statuses('CMD_ERROR'); + } + + return self::statuses('CMD_OK'); + } + } +} +?> \ No newline at end of file diff --git a/modules/registration/cmd/login.class.php b/modules/registration/cmd/login.class.php new file mode 100755 index 0000000..194cdbd --- /dev/null +++ b/modules/registration/cmd/login.class.php @@ -0,0 +1,135 @@ +initializeForms($request); + $this->populateForms($request, $forms); + $this->page->assign('LOGIN_FORM_ELEMENTS', $forms['login']->renderForm()); + $this->page->assign('CREATE_FORM_ELEMENTS', $forms['create']->renderForm()); + return $this->handleSubmittedForm($request, $forms); + } + + public function initializeForms(PFRequest $request) { + $forms = array(); + + $form = PFFactory::getInstance()->createObject('api.form', $request, 'registration.login', 'signin'); + $form->setAction($this->session->getURL('registration/login', true)); + + $fields = array('login-emailaddress', + 'login-password'); + $form->applyTrimFilters($fields); + $forms['login'] = $form; + + $form2 = PFFactory::getInstance()->createObject('api.form', $request, 'registration.account', 'createaccount'); + $form2->setAction($this->session->getURL('registration/account', true)); + + $fields2 = array('firstname', + 'lastname', + 'email', + 'password', + 'password2'); + $form2->applyTrimFilters($fields2); + $forms['create'] = $form2; + + return $forms; + } + + public function populateForms(PFRequest $request, array $forms) { } + + public function handleSubmittedForm(PFRequest $request, array $forms) { + try { + if ($request->isPropertySet('signin')) { + $this->handleSigninForm($request, $forms['login']); + } + if ($request->isPropertySet('createaccount')) { + $this->handleCreateForm($request, $forms['create']); + } + } catch (PFException $e) { + $e->handleException(); + } + } + + protected function handleSigninForm(PFRequest $request, PFForm $form) { + if ($form->getFormObject()->isSubmitted()) { + $userHelper = PFFactory::getInstance()->createObject('registration.userhelper'); + + $request->unsetProperty('signin'); + + if ($form->reportErrors()) { + return self::statuses('CMD_INSUFFICIENT_DATA'); + } + + $username = $request->get('login-emailaddress'); + $password = $request->get('login-password'); + $persistent = $request->get('rememberlogin'); + $redirectUrl = $this->session->retrieve('pf.session_redirect_url'); + + $userHelper = PFFactory::getInstance()->createObject('registration.userhelper'); + + if (PFRequestHelper::getRESTSlot(1) && $userHelper->doesCurrentUserHavePermission('admin')) { + $party = PartyQuery::create()->findPK(PFRequestHelper::getRESTSlot(1)); + if (!$party) { + return self::statuses('CMD_ERROR'); + } + $originalPartyUsername = $this->session->retrieve('user_username'); + + $userHelper->login($username, $password, $persistent, true); + $this->page->assign('CURRENTLY_LOGGED_IN', true); + $this->page->assign('CURRENTLY_LOGGED_IN_AS', $this->session->get('user_fullname')); + + $this->session->register('shadow_party_id', $party->getPartyId()); + $this->session->register('shadow_party_name', $party->getFirstName() . ' ' . $party->getLastName()); + $this->session->register('shadow_original_username', $originalPartyUsername); + + return PFRestHelper::sendResponse(200); + } else { + if (!$userHelper->login($username, $password, $persistent)) { + return self::statuses('CMD_ERROR'); + } else { + $this->page->assign('CURRENTLY_LOGGED_IN', true); + $this->page->assign('CURRENTLY_LOGGED_IN_AS', $this->session->get('user_fullname')); + + $this->redirectToSessionUrl(); + return self::statuses('CMD_OK'); + } + } + } + } + + protected function handleCreateForm(PFRequest $request, PFForm $form) { + + if ($form->isSubmitted()) { + if ($form->reportErrors()) { + return self::statuses('CMD_INSUFFICIENT_DATA'); + } + + try { + $userHelper = PFFactory::getInstance()->createObject('registration.userhelper'); + $userHelper->createUser($request); + $userHelper->login($request->get('email'), $request->get('password')); + } catch (PFException $e) { + $e->handleException(); + return self::statuses('CMD_ERROR'); + } + + if ($this->session->isRegistered('pf.redirect_url')) { + $redirectUrl = '/' . str_replace('.', '/', $this->session->get('pf.redirect_url')); + $this->redirectTo($redirectUrl, true); + } else { + return self::statuses('CMD_OK'); + } + } + } +} +?> \ No newline at end of file diff --git a/modules/registration/cmd/logout.class.php b/modules/registration/cmd/logout.class.php new file mode 100755 index 0000000..67d0ca4 --- /dev/null +++ b/modules/registration/cmd/logout.class.php @@ -0,0 +1,22 @@ +createObject('registration.userhelper'); + $user->logout(); + $this->assignDefaults($request); + return self::statuses('CMD_OK'); + } +} + +?> \ No newline at end of file diff --git a/modules/registration/cmd/resetpassword.class.php b/modules/registration/cmd/resetpassword.class.php new file mode 100755 index 0000000..1eb11cf --- /dev/null +++ b/modules/registration/cmd/resetpassword.class.php @@ -0,0 +1,88 @@ +helper = PFFactory::getInstance()->createObject('registration.userhelper'); + + if (!$this->checkURLPermission($request)) { + $request->addFeedback('', 'An invalid key was given. Please try resetting your password again.', E_USER_ERROR); + return self::statuses('CMD_ERROR'); + } + + //$this->helper->resetPassword('123', '123'); + + $form = $this->initializeForm($request); + $this->populateForm($request, $form); + $this->page->assign('FORM_ELEMENTS', $form->renderForm()); + return $this->handleSubmittedForm($request, $form); + } + + public function initializeForm(PFRequest $request) { + $form = PFFactory::getInstance()->createObject('api.form', $request, 'registration.resetpassword', 'reset'); + $form->setAction($this->session->getURL('registration/resetpassword') . '?key=' . $request->get('key')); + + $passwordRule = &patForms::createRule('PasswordMatch'); + $passwordRule->setPassword1('password'); + $passwordRule->setPassword2('password2'); + $form->getFormObject()->addRule($passwordRule, PATFORMS_RULE_AFTER_VALIDATION); + + $fields = array('password', + 'password2'); + $form->applyTrimFilters($fields); + + return $form; + } + + public function populateForm(PFRequest $request, PFForm $form) { } + + public function handleSubmittedForm(PFRequest $request, PFForm $form) { + if ($form->isSubmitted()) { + if ($form->reportErrors()) { + return self::statuses('CMD_INSUFFICIENT_DATA'); + } + + $user = $this->helper->getUserFromPasswordResetKey($request->get('key')); + + try { + $this->helper->resetPassword($request->get('password'), $request->get('key')); + } catch (PFException $e) { + $e->handleException(); + return self::statuses('CMD_ERROR'); + } + + if ($user) { + parent::assignDefaults($request); + $this->helper->login($user->getUsername(), $request->get('password')); + } + + return self::statuses('CMD_OK'); + } + } + + public function checkURLPermission($request) { + $key = urldecode($request->get('key')); + $count = AuthUserQuery::create() + ->filterByPasswordResetKey($key) + ->count(); + + if ($count == 0) { + return false; + } + return true; + } +} + +?> \ No newline at end of file diff --git a/modules/registration/cmd/signup.class.php b/modules/registration/cmd/signup.class.php new file mode 100755 index 0000000..6141294 --- /dev/null +++ b/modules/registration/cmd/signup.class.php @@ -0,0 +1,77 @@ +initializeForm($request); + $this->populateForm($request, $form); + $page = PFRegistry::getInstance()->getPage(); + $page->assign('FORM_ELEMENTS', $form->renderForm()); + return $this->handleSubmittedForm($request, $form); + } + + public function initializeForm(PFRequest $request) { + $form = PFFactory::getInstance()->createObject('api.form', $request, 'registration.signup', 'create'); + $form->setAction(PFSession::getInstance()->getURL('registration/signup')); + + $emailRule = &patForms::createRule('Email'); + $el = &$form->getFormObject()->getElementByName('username'); + $el->addRule($emailRule, PATFORMS_RULE_AFTER_VALIDATION); + + $passwordRule = &patForms::createRule('PasswordMatch'); + $passwordRule->setPassword1('password'); + $passwordRule->setPassword2('password2'); + $form->getFormObject()->addRule($passwordRule, PATFORMS_RULE_AFTER_VALIDATION); + + $fields = array('username', + 'password', + 'password2' + ); + $form->applyTrimFilters($fields); + return $form; + } + + public function populateForm(PFRequest $request, PFForm $form) { } + + public function handleSubmittedForm(PFRequest $request, PFForm $form) { + if ($form->getFormObject()->isSubmitted()) { + if ($form->reportErrors()) { + return self::statuses('CMD_INSUFFICIENT_DATA'); + } + + $user = PFFactory::getInstance()->createObject('registration.userhelper'); + + $con = Propel::getConnection(PF_DATABASE_NAME); + + try { + $con->beginTransaction(); + $timestamp = mktime(); + $user->createUser($con, $request, $timestamp); + $con->commit(); + } catch (Exception $e) { + $con->rollback(); + PFException::handleVanillaException($e->getMessage(), $e->getCode()); + return self::statuses('CMD_ERROR'); + } + + $user->login($request->getProperty('username'), $request->getProperty('password')); + + if (PFSession::getInstance()->isRegistered('pf.redirect_url')) { + $redirectUrl = '/' . str_replace('.', '/', PFSession::getInstance()->get('pf.redirect_url')); + $this->redirectTo($redirectUrl, true); + } else { + return self::statuses('CMD_OK'); + } + } + } +} +?> \ No newline at end of file diff --git a/modules/registration/cmd/static.class.php b/modules/registration/cmd/static.class.php new file mode 100644 index 0000000..741447a --- /dev/null +++ b/modules/registration/cmd/static.class.php @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/modules/registration/cmd/unshadow.class.php b/modules/registration/cmd/unshadow.class.php new file mode 100644 index 0000000..a5ad095 --- /dev/null +++ b/modules/registration/cmd/unshadow.class.php @@ -0,0 +1,29 @@ + * +* Copyright 2006-2010 Eric Jennings * +* ------------------------------------------------------------------------ * +* This program 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 of the License, or * +* (at your option) any later version. * +\**************************************************************************/ + +class PFUnshadowCommand extends PFDefaultCommand { + + public function doExecute(PFRequest $request) { + parent::doExecute($request); + + $this->session->unregister('shadow_party_id'); + $this->session->unregister('shadow_party_name'); + + $userHelper = PFFactory::getInstance()->createObject('registration.userhelper'); + $userHelper->login($this->session->retrieve('shadow_original_username'), '', false, true); + + $this->redirectTo('/shop/admin'); + } +} + +?> \ No newline at end of file diff --git a/modules/registration/lang/.placeholder b/modules/registration/lang/.placeholder new file mode 100755 index 0000000..e69de29 diff --git a/modules/registration/lang/en/global.lng b/modules/registration/lang/en/global.lng new file mode 100644 index 0000000..e312b62 --- /dev/null +++ b/modules/registration/lang/en/global.lng @@ -0,0 +1,66 @@ +// ****************** ENGLISH GLOBAL API TRANSLATION FILE ****************// + +// Navigation + +// Contentpages +MODULE_NAME=Registration Module + +// Error Messages +FORM_VALIDATION_FAILED=Form validation failed. +USERNAME_NOT_FOUND=Username not found. Please try again. +USERNAME_EXISTS=This e-mail address already exists. Please use another one. +PASSWORDS_DONT_MATCH=The passwords entered do not match. Please try again. +INVALID_PASSWORD=Invalid password. Please try again. +ACCOUNT_INACTIVE=This account has been disabled. +ACCOUNT_EXPIRED=This account has expired. +BILLING_ADDRESS_INCOMPLETE=The billing address is incomplete. +SHIPPING_ADDRESS_INCOMPLETE=The shipping address is incomplete. +INVALID_TELEPHONE=The telephone number was invalid. Please try again. +YOU_HAVE_BEEN_LOGGED_OUT=You have been logged out. +ERROR_SAVING_TO_DATABASE=Error saving %s to database. +ERROR_AUTHORIZING_CARD=There was an error authorizing your credit card. Please check your card information and try again. +ERROR_CARD_ID_NOT_FOUND=The selected credit card was not found. +ERROR_CANNOT_DELETE_ACTIVE_CARD=The currently-active card cannot be deleted. Please add a new card or activate another card first. + +ACCOUNT_ALREADY_ENABLED=This group has a current subscription and does not expire until %s. +ACCOUNT_ACTIVATION_FAILED=You provided incorrect credentials to activate your account. Please try again. +// Notice Messages +NOTICE_CARD_DELETED=The selected credit card has been deleted. +NOTICE_CARD_ACTIVATED=The selected credit card has been activated. +NOTICE_CARD_SUCCESSFULLY_ADDED=Credit card successfully added. +NOTICE_USER_ACTIVATED=The selected user has been activated. +NOTICE_USER_DEACTIVATED=The selected user has been deactivated. + +// Form Field names +__FORM=Form +USERNAME=E-mail Address +PASSWORD=Password +PASSWORD2=Confirm Password +ACCEPT_TERMS=Terms of Service +FIRSTNAME=First Name +LASTNAME=Last Name +EMAIL=E-mail Address +COMPANYNAME=Company Name +BILLING_STREET_1=Billing Address - Street Address 1 +BILLING_STREET_2=Billing Address - Street Address 2 +BILLING_CITY=Billing Address - City +BILLING_STATE=Billing Address - State +BILLING_ZIP=Billing Address - Zip Code +BILLING_TELEPHONE=Billing Address - Telephone +BILLING_FAX=Billing Address - Fax +SHIPPING_STREET_1=Shipping Address - Street Address 1 +SHIPPING_STREET_2=Shipping Address - Street Address 2 +SHIPPING_CITY=Shipping Address - City +SHIPPING_STATE=Shipping Address - State +SHIPPING_ZIP=Shipping Address - Zip Code + +APPLICATION=Application +TERM=Term +RATE=Rate +CREDIT_CARD_NAME=Name on Credit Card +CREDIT_CARD_NUMBER=Credit Card Number +CREDIT_CARD_EXPIRATION_MONTH=Credit Card Expiration Month +CREDIT_CARD_EXPIRATION_YEAR=Credit Card Expiration Year +CREDIT_CARD_CVV2=Credit Card CVV2 Number +STATES=States +AGREED=Terms and Conditions diff --git a/modules/registration/lib/.placeholder b/modules/registration/lib/.placeholder new file mode 100755 index 0000000..e69de29 diff --git a/modules/registration/lib/userhelper.class.php b/modules/registration/lib/userhelper.class.php new file mode 100755 index 0000000..c334731 --- /dev/null +++ b/modules/registration/lib/userhelper.class.php @@ -0,0 +1,567 @@ +mailer = PFFactory::getInstance()->createObject('api.mailer'); + $this->session = PFSession::getInstance() ; + PFFactory::getInstance()->initObject('api.template'); + } + + public function login($username, $password, $persistent=false, $admin=false) { + $user = AuthUserQuery::create() + ->filterByUsername(strtolower($username)) + ->joinWith('AuthUser.Party') + ->findOne(); + + if (!is_object($user)) { + throw new PFException('registration', 'USERNAME_NOT_FOUND', E_USER_WARNING); + } + + if ($admin == false) { + $hasher = new PasswordHash(PF_SESSION_PASSWORD_HASH_COST, false); + if (!$hasher->checkPassword($password, $user->getPassword())) { + // try oldschool MD5 hash password for backwards compatibility + $md5PassSalt = explode(':', $user->getMd5Password()); + $md5Pass = $md5PassSalt[0]; + $md5Salt = $md5PassSalt[1]; + + if ($md5Pass != md5($md5Salt . $password)) { + throw new PFException('registration', 'INVALID_PASSWORD', E_USER_WARNING); + } else { + $user->setPassword($hasher->hashPassword($password)); + $user->setMd5Password(null); + $user->save($con); + } + } + unset($hasher); + + if ($persistent) { + $this->session->setPersistentCookie(525600); + } + } + + $this->session->login(); + + $this->session->register('user_id', $user->getAuthUserId()); + $this->session->register('user_party_id', $user->getPartyId()); + $this->session->register('user_fullname', $user->getParty()->getFirstName() . ' ' . $user->getParty()->getLastName()); + $this->session->register('user_firstname', $user->getParty()->getFirstName()); + $this->session->register('user_lastname', $user->getParty()->getLastName()); + $this->session->register('user_username', $user->getUsername()); + $this->session->register('user_email', $user->getParty()->getEmail()); + $this->session->register('user_expires', $user->getExpires()); + $this->session->register('user_status', $user->getStatus()); + + $this->getAndStoreUserRoles($user->getAuthUserId()); + + try { + $user->setLastLogin(mktime()); + $user->setLastLoginFrom(@$_SERVER['REMOTE_ADDR']); + $user->save(); + } catch (PFException $e) { + throw new PFException('', 'Error saving login information', E_USER_WARNING); + } + + $this->assignDefaults(); + return true; + } + + public function assignDefaults() { + + $page = PFRegistry::getInstance()->getPage(); + if (!isset($page)) { + $page = PFTemplateHelper::getInstance(); + } + + $page->assign('CURRENTLY_LOGGED_IN', $this->session->isLoggedIn()); + $page->assign('CURRENTLY_LOGGED_IN_AS', $this->session->retrieve('user_firstname')); + $page->assign('IS_ADMIN', $this->doesCurrentUserHavePermission('admin')); + } + + public function logout() { + $this->session->logout(true); + $this->assignDefaults(); + } + + public function setResetPasswordKey($email, $con) { + + $user = $this->getUserFromEmail($email); + $key = sha1(time() . 'rrreeessseeett' . PF_SESSION_UNIQUE_KEY); + if ($user) { + $user->setPasswordResetKey($key); + $user->save($con); + + $this->sendResetPasswordEmail($email, $key); + } else { + throw new PFException('', 'Error resetting password key. No user exists with that email.', E_USER_WARNING); + } + } + + public function resetPassword($password, $key, $con=NULL) { + + $user = $this->getUserFromPasswordResetKey($key); + + if ($user) { + $hasher = new PasswordHash(PF_SESSION_PASSWORD_HASH_COST, false); + $user->setPassword($hasher->hashPassword($password)); + unset($hasher); + $user->setPasswordResetKey($key); + $user->setPasswordResetKey(NULL); + $user->save($con); + } + } + + public function doesUsernameExist($username) { + + $count = AuthUserQuery::create() + ->filterByUsername(strtolower($username)) + ->count(); + + if ($count > 0) { + return true; + } else { + return false; + } + } + + public function doesEmailExist($email) { + + $count = AuthUserQuery::create() + ->joinWith('AuthUser.Party') + ->usePartyQuery() + ->filterByEmail(strtolower($email)) + ->endUse() + ->count(); + + if ($count > 0) { + return true; + } else { + return false; + } + } + + public function getUser($authUserId) { + return AuthUserQuery::create() + ->joinWith('AuthUser.Party') + ->joinWith('Party.PartyLocaleLocationXref', Criteria::LEFT_JOIN) + ->joinWith('PartyLocaleLocationXref.LocaleLocation', Criteria::LEFT_JOIN) + ->joinWith('Party.ShopOrderPaymentMethod', Criteria::LEFT_JOIN) + ->filterByAuthUserId($authUserId) + ->findOne(); + } + + public function getUserFromUsername($username) { + return AuthUserQuery::create() + ->joinWith('AuthUser.Party') + ->joinWith('Party.PartyLocaleLocationXref', Criteria::LEFT_JOIN) + ->joinWith('PartyLocaleLocationXref.LocaleLocation', Criteria::LEFT_JOIN) + ->joinWith('Party.ShopOrderPaymentMethod', Criteria::LEFT_JOIN) + ->filterByUsername(strtolower($username)) + ->findOne(); + } + + public function getUserFromEmail($email) { + return AuthUserQuery::create() + ->joinWith('AuthUser.Party') + ->joinWith('Party.PartyLocaleLocationXref', Criteria::LEFT_JOIN) + ->joinWith('PartyLocaleLocationXref.LocaleLocation', Criteria::LEFT_JOIN) + ->joinWith('Party.ShopOrderPaymentMethod', Criteria::LEFT_JOIN) + ->usePartyQuery() + ->filterByEmail(strtolower($email)) + ->endUse() + ->findOne(); + } + + public function getUserFromPartyId($partyId) { + return AuthUserQuery::create() + ->joinWith('AuthUser.Party') + ->joinWith('Party.PartyLocaleLocationXref', Criteria::LEFT_JOIN) + ->joinWith('PartyLocaleLocationXref.LocaleLocation', Criteria::LEFT_JOIN) + ->joinWith('Party.ShopOrderPaymentMethod', Criteria::LEFT_JOIN) + ->filterByPartyId($partyId) + ->findOne(); + } + + public function getUserFromPasswordResetKey($key) { + return AuthUserQuery::create() + ->joinWith('AuthUser.Party') + ->joinWith('Party.PartyLocaleLocationXref', Criteria::LEFT_JOIN) + ->joinWith('PartyLocaleLocationXref.LocaleLocation', Criteria::LEFT_JOIN) + ->joinWith('Party.ShopOrderPaymentMethod', Criteria::LEFT_JOIN) + ->filterByPasswordResetKey($key) + ->findOne(); + } + + public function getAndStoreUserRoles($userID) { + $permissionRoles = array(); + + $c = new Criteria(); + $c->add(AuthUserRoleXrefPeer::AUTH_USER_ID, $userID); + $roles = AuthUserRoleXrefPeer::doSelectJoinAll($c); + + foreach($roles as $role) { + $key = $role->getAuthRole()->getRoleKey(); + $permissionRoles[$key]['name'] = $role->getAuthRole()->getName(); + $permissionRoles[$key]['status'] = $role->getAuthRole()->getStatus(); + $permissionRoles[$key]['expires'] = $role->getAuthRole()->getExpires(); + } + + $roles = AuthUserGroupRoleXrefPeer::getAllRolesForUserInGroup($userID); + + for ($i=0; $isession->register('user_roles', $permissionRoles); + $this->assignDefaults(); + } + + public function doesCurrentUserHavePermission($roles) { + + $userRoles = $this->session->get('user_roles'); + + // if no user roles, make it an empty array + if (!$userRoles) { + $userRoles = array(); + } + + // if no roles are given from the command.xml file, there are no permission locks on the page + if (empty($roles)) { + return true; + } + + // convert to array if $roles was a single item, so the foreach can loop over it + if (!is_array($roles)) { + $roles = array($roles); + } + + // printr($roles); + // printr($userRoles); + foreach ($roles as $role) { + if (array_key_exists($role, $userRoles)) { + if ($userRoles[$role]['status'] == 'A' && + ($userRoles[$role]['expires'] == '' || ($userRoles[$role]['expires'] > mktime()))) { + return true; + } + } + } + + return false; + } + + public function getOrderHistoryForParty($partyId, $limit=10) { + + return ShopOrderQuery::create() + ->filterByPartyId($partyId) + ->orderByCreatedAt(Criteria::DESC) + ->limit($limit) + ->find(); + } + + public function setStatus($userId, $status, $timestamp) { + + $user = AuthUserPeer::retrieveByPk($userId); + + if (is_object($user)) { + + $user->setStatus($status); + $user->setUpdatedAt($timestamp); + $user->save(); + + // Update session vars if this user is us + if ($userId == $this->session->retrieve('user_id')) { + $this->session->register('user_expires', $user->getExpires()); + $this->session->register('user_status', $user->getStatus()); + } + return true; + + } else { + return false; + } + } + + public function getStatus($userId) { + + $user = AuthUserPeer::retrieveByPk($userId); + + if (is_object($user)) { + return ($user->getStatus()); + } else { + return false; + } + } + + public function createUser($request) { + + $con = Propel::getConnection(PF_DATABASE_NAME); + + try { + $con->beginTransaction(); + + if ($this->doesUsernameExist($request->get('email'))) { + throw new PFException('registration', 'USERNAME_EXISTS', E_USER_WARNING); + } + + if (trim($request->get('password')) != trim($request->get('password2'))) { + throw new PFException('registration', array('PASSWORDS_DONT_MATCH'), E_USER_WARNING); + } + + $party = PFFactory::getInstance()->createPropelObject('Party'); + $user = PFFactory::getInstance()->createPropelObject('AuthUser'); + $shippingAddress = PFFactory::getInstance()->createPropelObject('LocaleLocation'); + $shippingAddressXref = PFFactory::getInstance()->createPropelObject('PartyLocaleLocationXref'); + + $party->setFirstName($request->get('firstname')); + $party->setLastName($request->get('lastname')); + $party->setEmail(strtolower($request->get('email'))); + $party->setTelephone(strtolower($request->get('telephone'))); + $party->save($con); + + $user->setUsername(strtolower($request->get('email'))); + $hasher = new PasswordHash(PF_SESSION_PASSWORD_HASH_COST, false); + $user->setPassword($hasher->hashPassword($request->get('password'))); + unset($hasher); + $user->setStatus('A'); + $user->setPartyId($party->getPartyId()); + $user->save($con); + + $shippingAddress->setName($request->get('shippingaddress-name')); + $shippingAddress->setAddress1($request->get('shippingaddress-address1')); + $shippingAddress->setAddress2($request->get('shippingaddress-address2')); + $shippingAddress->setAddress3($request->get('shippingaddress-address3')); + $shippingAddress->setCity($request->get('shippingaddress-city')); + $shippingAddress->setRegion($request->get('shippingaddress-region')); + $shippingAddress->setPostalCode($request->get('shippingaddress-postalcode')); + $shippingAddress->setLocaleCountry($request->get('shippingaddress-country')); + $shippingAddress->save($con); + + $shippingAddressXref->setPartyId($party->getPartyId()); + $shippingAddressXref->setLocaleLocationId($shippingAddress->getLocaleLocationId()); + $shippingAddressXref->setType('shipping'); + $shippingAddressXref->save($con); + + $con->commit(); + } catch (PFException $e) { + $con->rollback(); + throw $e; + } + + return $user->getAuthUserId(); + } + + public function updateUser($userId, $request) { + + $con = Propel::getConnection(PF_DATABASE_NAME); + + try { + $con->beginTransaction(); + + $user = AuthUserQuery::create() + ->joinWith('AuthUser.Party') + ->joinWith('Party.ShopOrderPaymentMethod', Criteria::LEFT_JOIN) + ->filterByAuthUserId($userId) + ->findOne($con); + if (!$user) { + throw new PFException('registration', array('ID_NOT_FOUND', $userId), E_USER_WARNING); + } + + if ($request->isPropertySet('user-emailaddress') && $this->doesUsernameExist($request->get('user-emailaddress'))) { + $otherUser = $this->getUserFromUsername($request->get('user-emailaddress')); + if ($otherUser->getAuthUserId() != $userId) { + throw new PFException('registration', 'USERNAME_EXISTS', E_USER_WARNING); + } + } + + $party = $user->getParty(); + + if ($request->isPropertySet('billingaddress-postalcode')) { + + $billingAddress = PFFactory::getInstance()->createPropelObject('LocaleLocation'); + $billingAddress->setName($request->get('billingaddress-name')); + // $billingAddress->setAddress1($request->get('billingaddress-address1')); + // $billingAddress->setAddress2($request->get('billingaddress-address2')); + // $billingAddress->setAddress3($request->get('billingaddress-address3')); + // $billingAddress->setCity($request->get('billingaddress-city')); + // $billingAddress->setRegion($request->get('billingaddress-region')); + $billingAddress->setPostalCode($request->get('billingaddress-postalcode')); + // $billingAddress->setLocaleCountryId($request->isPropertySet('billingaddress-country')?$request->get('billingaddress-country'):NULL); + if (!LocaleLocation::isBillingAddressComplete($billingAddress)) { + throw new PFException('registration', 'BILLING_ADDRESS_INCOMPLETE', E_USER_WARNING); + } + $billingAddress->save($con); + $party->setBillingAddress($billingAddress->getLocaleLocationId()); + } + + if ($request->isPropertySet('shippingaddress-address1') || + $request->isPropertySet('shippingaddress-city') || + $request->isPropertySet('shippingaddress-region') || + $request->isPropertySet('shippingaddress-postalcode')) { + + $shippingAddress = PFFactory::getInstance()->createPropelObject('LocaleLocation'); + $shippingAddress->setName($request->get('shippingaddress-name')); + $shippingAddress->setAddress1($request->get('shippingaddress-address1')); + $shippingAddress->setAddress2($request->get('shippingaddress-address2')); + $shippingAddress->setAddress3($request->get('shippingaddress-address3')); + $shippingAddress->setCity($request->get('shippingaddress-city')); + $shippingAddress->setRegion($request->get('shippingaddress-region')); + $shippingAddress->setPostalCode($request->get('shippingaddress-postalcode')); + $shippingAddress->setLocaleCountry($request->get('shippingaddress-country')); + if (!LocaleLocation::isShippingAddressComplete($shippingAddress)) { + throw new PFException('registration', 'BILLING_ADDRESS_INCOMPLETE', E_USER_WARNING); + } + $shippingAddress->save($con); + $party->setShippingAddress($shippingAddress->getLocaleLocationId()); + } + + if ($request->isPropertySet('firstname') || $request->isPropertySet('lastname')) { + $party->setFirstName($request->get('firstname')); + $party->setLastName($request->get('lastname')); + } + + if ($request->isPropertySet('user-emailaddress')) { + $party->setEmail(strtolower($request->get('user-emailaddress'))); + } + + if ($request->isPropertySet('telephone')) { + if (!$party->validateTelephone($request->get('telephone'))) { + throw new PFException('registration', array('INVALID_TELEPHONE'), E_USER_WARNING); + } + + $party->setTelephone(strtolower($request->get('telephone'))); + } + $party->save($con); + + if ($request->isPropertySet('user-password')) { + + if (trim($request->get('user-password')) != trim($request->get('user-passwordconfirm'))) { + throw new PFException('registration', array('PASSWORDS_DONT_MATCH'), E_USER_WARNING); + } + + $hasher = new PasswordHash(PF_SESSION_PASSWORD_HASH_COST, false); + $user->setPassword($hasher->hashPassword(trim($request->get('user-password')))); + unset($hasher); + } + if ($request->isPropertySet('user-emailaddress')) { + $user->setUsername(strtolower($request->get('user-emailaddress'))); + } + $user->save($con); + + /* TODO if needed for Stripe card saving + // CIM + $authNetCim = PFFactory::getInstance()->createObject('registration.authnetcim'); + $authNetCim->doCustomerProfile($party); + + if ($authNetCim->isError()) { + throw new PFException('', $authNetCim->getErrorMessage(), E_USER_WARNING); + } + + if ($authNetCim->getCustomerProfileID() && !$party->getAuthNetProfileId()) { + $party->setAuthNetProfileId($authNetCim->getCustomerProfileID()); + $party->save($con); + } + + // save regardless here, b/c AuthNet interaction + $con->commit(); + + $paymentMethod = $this->updatePaymentMethod($party, $request); + + if ($paymentMethod) { + $party->addShopOrderPaymentMethod($paymentMethod); + $authNetCim->doPaymentProfile($party); + + if ($authNetCim->isError()) { + throw new PFException('', $authNetCim->getErrorMessage(), E_USER_WARNING); + } + + if ($authNetCim->getPaymentProfileId()) { + $paymentMethod->setAuthNetPaymentProfileId($authNetCim->getPaymentProfileId()); + $paymentMethod->save(); + } + } + */ + $con->commit(); + } catch (Exception $e) { + $con->rollback(); + throw $e; + } + + return $user->getAuthUserId(); + } + + private function updatePaymentMethod($party, $request) { + $ccNum = $request->get('paymentinfo-number'); + $ccType = $request->get('paymentinfo-type'); + $ccCCV = $request->get('paymentinfo-ccv'); + $ccExpMon = $request->get('paymentinfo-expirationmonth'); + $ccExpYear = $request->get('paymentinfo-expirationyear'); + + if ($ccNum && $ccType && $ccCCV && $ccExpMon && $ccExpYear) { + $paymentMethod = $party->getFirstCreditPaymentMethod(); + if($paymentMethod === null) { + $paymentMethod = new ShopOrderPaymentMethod(); + $paymentMethod->setPartyId($party->getPartyId()); + } + $paymentMethod->setLocaleLocationIdBilling($party->getBillingAddress()->getLocaleLocationId()); + $paymentMethod->setType($ccType); + $paymentMethod->setName($party->getBillingAddress()->getName()); + $paymentMethod->setNumber($ccNum); + $paymentMethod->setCcv($ccCCV); // Note this won't actually save it's more for the auth net class, it's blanked during save() + $paymentMethod->setExpirationDate(strtotime($ccExpYear . '-' . $ccExpMon . '-01')); + $paymentMethod->setActive(true); + return $paymentMethod; + } + return false; + } + + public function sendResetPasswordEmail($email, $key) { + + $this->mailer->addAddress($email); + $this->mailer->Subject = PF_SITE_NAME . ' - Password Reset Request'; + $this->mailer->From = PF_DEFAULT_FROM_EMAIL_ADDRESS; + $this->mailer->FromName = PF_DEFAULT_FROM_EMAIL_NAME; + + $emailPage = new PFTemplate('registration'); + $emailPage->assign('key', urlencode($key)); + + //$html = $emailPage->fetch('registration', 'email-resetpassword-html.tpl'); + $plain = $emailPage->fetch('registration', 'email-resetpassword-txt.tpl'); + + //$this->mailer->Body = $html; + //$this->mailer->AltBody = $plain; + + $this->mailer->Body = $plain; + + try { + if ($this->mailer->send()) { + return true; + } + + $this->mailer->logError(); + + } catch (Exception $e) { + $e = PFException::enrich($e); + $e->handleException(); + $this->mailer->logError(); + } + } +} +?> diff --git a/modules/registration/test/fake/.placeholder b/modules/registration/test/fake/.placeholder new file mode 100755 index 0000000..e69de29 diff --git a/modules/registration/test/unit/.placeholder b/modules/registration/test/unit/.placeholder new file mode 100755 index 0000000..e69de29 diff --git a/modules/api/test/unit/ProfilerTest.class.php b/modules/registration/test/unit/UserTest.class.php old mode 100644 new mode 100755 similarity index 51% rename from modules/api/test/unit/ProfilerTest.class.php rename to modules/registration/test/unit/UserTest.class.php index 967ac53..2499bbf --- a/modules/api/test/unit/ProfilerTest.class.php +++ b/modules/registration/test/unit/UserTest.class.php @@ -2,36 +2,26 @@ /**************************************************************************\ * Protean Framework * * https://github.com/erictj/protean * -* Copyright (c) 2006-2010, Loopshot Inc. All rights reserved. * +* Copyright (c) 2006-2012, Eric Jennings. All rights reserved. * * ------------------------------------------------------------------------ * * This program is free software; you can redistribute it and/or modify it * * under the terms of the BSD License as described in license.txt. * \**************************************************************************/ require_once 'config.php'; -require_once 'PHPUnit/Framework.php'; -require_once 'modules/api/lib/profiler.class.php'; -class ProfilerTest extends PHPUnit_Framework_TestCase { +class UserTest extends PHPUnit_Framework_TestCase { - private $profiler; + protected $user; - public function setUp() { - $this->profiler = PFProfiler::getInstance(); + public function setUp() { + $this->user = PFFactory::getInstance()->createObject('registration.userhelper'); } - - public function tearDown() { - - } - - public function testTime() { - - $this->profiler->setStartTime(microtime(true)); - usleep(10000); - $var = $this->profiler->getTime(); - - $this->assertEquals(0.01, (float)$var, 'Profiler time exceeds delta.', .05); + + public function tearDown() { } + + public function testSuccessfulLogin() { + $this->assertTrue($this->user->login('ethomjen@gmail.com', '123')); } } - ?> \ No newline at end of file diff --git a/modules/registration/tpl/default/css/.placeholder b/modules/registration/tpl/default/css/.placeholder new file mode 100755 index 0000000..e69de29 diff --git a/modules/registration/tpl/default/html/.placeholder b/modules/registration/tpl/default/html/.placeholder new file mode 100755 index 0000000..e69de29 diff --git a/modules/registration/tpl/default/html/account.form.tpl b/modules/registration/tpl/default/html/account.form.tpl new file mode 100755 index 0000000..dc90adc --- /dev/null +++ b/modules/registration/tpl/default/html/account.form.tpl @@ -0,0 +1,31 @@ + + +

send me email updates

+ +
\ No newline at end of file diff --git a/modules/registration/tpl/default/html/account.tpl b/modules/registration/tpl/default/html/account.tpl new file mode 100755 index 0000000..e0b1234 --- /dev/null +++ b/modules/registration/tpl/default/html/account.tpl @@ -0,0 +1,62 @@ +{include file=$PF_HEADER} + +
+

Your Account

+
+

Account Information

+ {$FORM_ELEMENTS} +
+
+

Your Newsletters

+ +
+
+
+

You currently have {$PARTY_CURRENT_POINTS} Quilter's Cash Points

+
+
+
+
+
+

Order History

+ + + + + + + + + + + + + + + + + + {foreach $orderhistory as $order} + + + + + + + + + {/foreach} + + + + +
Order #DateTotal

+ {$order->getShopOrderId()} + + {$order->getCreatedAt('M j, Y, g:ia')} + + ${$order->getTotal()|number_format:2} +


+
+
+{include file=$PF_FOOTER} \ No newline at end of file diff --git a/modules/registration/tpl/default/html/changepassword.form.tpl b/modules/registration/tpl/default/html/changepassword.form.tpl new file mode 100755 index 0000000..43fb539 --- /dev/null +++ b/modules/registration/tpl/default/html/changepassword.form.tpl @@ -0,0 +1,14 @@ + + +
+ +
\ No newline at end of file diff --git a/modules/registration/tpl/default/html/changepassword.tpl b/modules/registration/tpl/default/html/changepassword.tpl new file mode 100755 index 0000000..e4c6ae5 --- /dev/null +++ b/modules/registration/tpl/default/html/changepassword.tpl @@ -0,0 +1,9 @@ +{include file=$PF_HEADER} + +
+

Enter a new password

+
+ {$FORM_ELEMENTS} +
+ +{include file=$PF_FOOTER} \ No newline at end of file diff --git a/modules/registration/tpl/default/html/edit-member.tpl b/modules/registration/tpl/default/html/edit-member.tpl new file mode 100644 index 0000000..3c075bc --- /dev/null +++ b/modules/registration/tpl/default/html/edit-member.tpl @@ -0,0 +1,262 @@ +
+
+
+
+ +
+
+ {$user->getParty()->getFullName()|default:'None'} + +
+
+
+
+
+ +
+
+ + +
+
+ +
+
+ +
+
+
+ + +
+
+
+ +
+
+ {$user->getParty()->getEmail()} + +
+
+
+
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+
+ +
+
+ {$user->getParty()->getTelephone()|default:"None"} + +
+
+
+
+
+ +
+
+ + +
+
+
+ +
+
+
+ +
+
+ {assign var="paymentMethod" value=$user->getParty()->getShopOrderPaymentMethods()} + {if $paymentMethod[0]} + {$paymentMethod[0]->getType()} {$paymentMethod[0]->getNumber()} + {else} + None + {/if} + +
+
+
+
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ / + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+
+ + {assign var="shippingAddress" value=$user->getParty()->getShippingAddress()} +
+
+ + {if $shippingAddress !== null && $shippingAddress->isShippingComplete()} + {$shippingAddress->getName()}
+ {$shippingAddress->getAddress1()}
+ {if $shippingAddress->getAddress2()}{$shippingAddress->getAddress2()}
{/if} + {if $shippingAddress->getAddress3()}{$shippingAddress->getAddress3()}
{/if} + {$shippingAddress->getCity()}, {$shippingAddress->getRegion()} {$shippingAddress->getPostalCode()}
+ {$shippingAddress->getLocaleCountry()} + {else} + No shipping address + {/if} +
+ +
+
+
+
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
\ No newline at end of file diff --git a/modules/registration/tpl/default/html/email-accountcreateion-html.tpl b/modules/registration/tpl/default/html/email-accountcreateion-html.tpl new file mode 100644 index 0000000..faf86b8 --- /dev/null +++ b/modules/registration/tpl/default/html/email-accountcreateion-html.tpl @@ -0,0 +1,21 @@ +Whats cookin good lookin?! + +Congratulations! With your new MSQC account youve officially been inducted into an elite squadron of quilting ninjas. Your training and preparation in the art of quilting have clearly paid off! Here is your login info: + +Login: +Password: + +Remember though, not everyone gets one of these accounts, and with great power comes great responsibility. + +With this account, you have been entrusted with a sacred duty, namely to ALWAYS login when you come to our site. Why? This is why: + +1) The only way to earn and spend Quilters Cash is to be logged in If you dont youre basically throwing away free money (to learn more about Quilters Cash, click here) +2) You can check out with lightning speed (and the stealth and grace of a true quilting ninja) +3) When logged in, you have access to our awesome Quilting Forums, QuiltsByMe.com, and Quilting Tutorials. + +Oh ya, one more duty we forgot to mention you must check the daily deal every day and talk yourself into buying it, then out of buying it because you have way too much fabric, then back into buying again. + +With this solemn commitment to the art of ninja quilting, we now knight you Sir/Siress ____ + +Respectfully, +The Board of Quilting Ninjas at the Missouri Star Quilting Company. \ No newline at end of file diff --git a/modules/registration/tpl/default/html/email-resetpassword-html.tpl b/modules/registration/tpl/default/html/email-resetpassword-html.tpl new file mode 100755 index 0000000..2d611c7 --- /dev/null +++ b/modules/registration/tpl/default/html/email-resetpassword-html.tpl @@ -0,0 +1,12 @@ +Hello! + +A password reset request has been made for your account at {$smarty.const.PF_SITE_NAME} + +If you requested your password to be reset, please click on the link below to complete your request. + +{$smarty.const.PF_URL}/registration/resetpassword?key={$key} + +If you did not request for your password to be reset, you can safely ignore this message. + +Thank you! +{$smarty.const.PF_SITE_NAME} \ No newline at end of file diff --git a/modules/registration/tpl/default/html/email-resetpassword-txt.tpl b/modules/registration/tpl/default/html/email-resetpassword-txt.tpl new file mode 100755 index 0000000..2d611c7 --- /dev/null +++ b/modules/registration/tpl/default/html/email-resetpassword-txt.tpl @@ -0,0 +1,12 @@ +Hello! + +A password reset request has been made for your account at {$smarty.const.PF_SITE_NAME} + +If you requested your password to be reset, please click on the link below to complete your request. + +{$smarty.const.PF_URL}/registration/resetpassword?key={$key} + +If you did not request for your password to be reset, you can safely ignore this message. + +Thank you! +{$smarty.const.PF_SITE_NAME} \ No newline at end of file diff --git a/modules/registration/tpl/default/html/forgot.form.tpl b/modules/registration/tpl/default/html/forgot.form.tpl new file mode 100755 index 0000000..07e0015 --- /dev/null +++ b/modules/registration/tpl/default/html/forgot.form.tpl @@ -0,0 +1,10 @@ + + +
+ +
\ No newline at end of file diff --git a/modules/registration/tpl/default/html/forgot.tpl b/modules/registration/tpl/default/html/forgot.tpl new file mode 100755 index 0000000..ad52347 --- /dev/null +++ b/modules/registration/tpl/default/html/forgot.tpl @@ -0,0 +1,12 @@ +{include file=$PF_HEADER} + +
+

Forgot your password?

+

+ No problem! Just give us the email address you used to set up your account, and we will reset your password right away! +

+
+ {$FORM_ELEMENTS} +
+ +{include file=$PF_FOOTER} \ No newline at end of file diff --git a/modules/registration/tpl/default/html/login-box.tpl b/modules/registration/tpl/default/html/login-box.tpl new file mode 100644 index 0000000..5461893 --- /dev/null +++ b/modules/registration/tpl/default/html/login-box.tpl @@ -0,0 +1,3 @@ +
+ {$LOGIN_FORM_ELEMENTS} +
\ No newline at end of file diff --git a/modules/registration/tpl/default/html/login.form.tpl b/modules/registration/tpl/default/html/login.form.tpl new file mode 100755 index 0000000..33e5efe --- /dev/null +++ b/modules/registration/tpl/default/html/login.form.tpl @@ -0,0 +1,14 @@ + + +

forgot your password?

+ +
\ No newline at end of file diff --git a/modules/registration/tpl/default/html/login.tpl b/modules/registration/tpl/default/html/login.tpl new file mode 100755 index 0000000..52695ce --- /dev/null +++ b/modules/registration/tpl/default/html/login.tpl @@ -0,0 +1,16 @@ +{include file=$PF_HEADER} + +
+

Sign In

+ +
+
+

New users, create an account and join us!

+ {$CREATE_FORM_ELEMENTS} +
+
+ +{include file=$PF_FOOTER} \ No newline at end of file diff --git a/modules/registration/tpl/default/html/passwordreset.tpl b/modules/registration/tpl/default/html/passwordreset.tpl new file mode 100644 index 0000000..1f616e2 --- /dev/null +++ b/modules/registration/tpl/default/html/passwordreset.tpl @@ -0,0 +1,14 @@ +{include file=$PF_HEADER} + +
+ + +
+ +{include file=$PF_FOOTER} \ No newline at end of file diff --git a/modules/registration/tpl/default/html/passwordresetsent.tpl b/modules/registration/tpl/default/html/passwordresetsent.tpl new file mode 100755 index 0000000..918af5c --- /dev/null +++ b/modules/registration/tpl/default/html/passwordresetsent.tpl @@ -0,0 +1,14 @@ +{include file=$PF_HEADER} + +
+ + +
+ +{include file=$PF_FOOTER} \ No newline at end of file diff --git a/modules/registration/tpl/default/html/resetpassword.form.tpl b/modules/registration/tpl/default/html/resetpassword.form.tpl new file mode 100755 index 0000000..43fb539 --- /dev/null +++ b/modules/registration/tpl/default/html/resetpassword.form.tpl @@ -0,0 +1,14 @@ + + +
+ +
\ No newline at end of file diff --git a/modules/registration/tpl/default/html/resetpassword.tpl b/modules/registration/tpl/default/html/resetpassword.tpl new file mode 100755 index 0000000..2f5588a --- /dev/null +++ b/modules/registration/tpl/default/html/resetpassword.tpl @@ -0,0 +1,11 @@ +{include file=$PF_HEADER} +
+

Enter a new password

+

+ Please choose a new password below, and you'll be all set. +

+
+ {$FORM_ELEMENTS} +
+ +{include file=$PF_FOOTER} \ No newline at end of file diff --git a/modules/registration/tpl/default/images/.placeholder b/modules/registration/tpl/default/images/.placeholder new file mode 100755 index 0000000..e69de29 diff --git a/modules/registration/tpl/default/js/.placeholder b/modules/registration/tpl/default/js/.placeholder new file mode 100755 index 0000000..e69de29 diff --git a/modules/thirdparty/elastica/LICENSE.txt b/modules/thirdparty/elastica/LICENSE.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/modules/thirdparty/elastica/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/modules/thirdparty/elastica/README.markdown b/modules/thirdparty/elastica/README.markdown new file mode 100755 index 0000000..1db2fc4 --- /dev/null +++ b/modules/thirdparty/elastica/README.markdown @@ -0,0 +1,40 @@ +Elastica: elasticsearch PHP Client +================================== + +[![Build Status](https://secure.travis-ci.org/ruflin/Elastica.png?branch=master)](http://travis-ci.org/ruflin/Elastica) + +Documentation +--------------------- +Check out the [Elastica documentation](http://ruflin.github.com/Elastica/) to find out how Elastica works. If you have questions, don't hesitate to ask them in the [Elastica google group](https://groups.google.com/group/elastica-php-client). Issues should go to the [issue tracker from github](https://github.com/ruflin/Elastica/issues). + +About +--------------------- +PHP client for the distributed search engine [elasticsearch](http://www.elasticsearch.com/) which is +based on [Lucene](http://lucene.apache.org/java/docs/index.html) and can be an alternative to [solr](http://lucene.apache.org/solr/). +The client naming and structure is consistent with [Zend Framework](http://framework.zend.com/) +and other PHP frameworks. This makes it easy to use the client in combination with Zend Framework. + +Changes +------- +For changes in the API please check the file [changes.txt](https://github.com/ruflin/Elastica/blob/master/changes.txt) + +Versions +-------- +The version numbers are consistent with elasticsearch. The version number 0.16.0.0 means it is the first release for elasticsearch version 0.16.0. The next release is called 0.16.0.1. As soon as the elasticsearch is updated and the client is updated, also the next version is called 0.16.1.0. Like this it should be always clear to which versions the Elastica client is compatible. + +Compatibility +------------- +At the moment the client should be backward compatible to PHP 5.2. That's the reason why +the client was not directly built with namespaces and other nice PHP 5.3 features. + +File indexing +------------- +File upload is supported but the mapper attachement plugin has to be installed + + ./bin/plugin install mapper-attachments + +Contributing +------------ +Help is very welcomed, but code contributions must be done in respect of [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md). + +See [Coding guidelines](https://github.com/ruflin/Elastica/wiki/Coding-guidelines) for tips on how to do so. \ No newline at end of file diff --git a/modules/thirdparty/elastica/Vagrantfile b/modules/thirdparty/elastica/Vagrantfile new file mode 100644 index 0000000..af49b02 --- /dev/null +++ b/modules/thirdparty/elastica/Vagrantfile @@ -0,0 +1,14 @@ +# Elastica debian image +# +# All passwords and username (db, ...) are root / root +# +# The image has 2GB of memory and a size of 10GB + +Vagrant::Config.run do |config| + + config.vm.box = "debian-6.0.3-64-elastica-20120115" + config.vm.box_url = "http://ruflin.com/files/vagrant/debian-6.0.3-64-elastica-20120528.box" + config.vm.network :hostonly, "10.10.10.10" + + config.vm.share_folder "project", "/project", "." +end diff --git a/modules/thirdparty/elastica/build.xml b/modules/thirdparty/elastica/build.xml new file mode 100755 index 0000000..7b2ce3f --- /dev/null +++ b/modules/thirdparty/elastica/build.xml @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/thirdparty/elastica/changes.txt b/modules/thirdparty/elastica/changes.txt new file mode 100644 index 0000000..c07db9b --- /dev/null +++ b/modules/thirdparty/elastica/changes.txt @@ -0,0 +1,262 @@ +CHANGES + +2012-07-26 +- Change Elastica_Filter_GeoDistance::__construct(), accepts geohash parameter (BC break, before: ($key, $latitude, $longitude, $distance), after: ($key, $location, $distance) where $location is array('lat' => $latitude, 'lon' => $longitude) or a geohash) + +2012-07-17 +- Changed naming for several methods to camelCase +- Enforced PSR1 code style, as per https://github.com/pmjones/fig-standards/blob/psr-1-style-guide/proposed/PSR-1-basic.md +- Added Elastica_Script::toArray +- Added Elastica_ScriptFields +- Elastica_Query::setScriptFields now takes Elastica_ScriptFields or associative array as argument, the old implementation was bogus. + +2012-06-24 +- Simplify Elastica_Type::search and Elastica_Index::search by using Elastica_Search +- Implement Elastica_Filter_Abstract::setCache and Elastica_Filter_Abstract::setCacheKey +- Add Elastica_Param::hasParam +- Remove unsupported use of minimum number should match for Boolean Filter +- Remove old style path creation through params in Elastica_Index::create and Elastica_Search::search + +2012-06-22 +- Add Elastica_Filter_Limit +- Add getters+setters for Index Setting blocks 'read', 'write' and 'metadata' +- Add Elastica_Filter_MatchAll + +2012-06-20 +- Facet scope added + +2012-06-09 +- Change $_parent to null to also support 0 for an id +- Fix Elasitca_Document->toArray() + +2012-05-01 +- Release v0.19.3.0 +- MoreLikeThis Query in Elastica_Document +- Add query param for request (allows GET params) + +2012-03-04 +- Node info call update. The receive os info and more, param is needed. By default, only basics are returned +- Release v0.19.0.0 which is compatible with ES 0.19.0 http://www.elasticsearch.org/blog/2012/03/01/0.19.0-released.html + +2012-02-21 +- Allow percolate queries in bulk requests +- Fix memory leak in curl requests + +2012-01-23 +- Packagist added http://packagist.org/ + +2012-01-15 +- Vagrantfile for vagrant environment with elasticsearch added. Run: vagrant up + +2012-01-08 +- Allow to set curl params over client config #106 #107 +- Add the possiblity to add path or url in config for a request #120 + +2012-01-04 +- Elastica_Index::exists() and Elastica_Cluster::getIndexNames() added + +2012-01-01 +- Elastica_Cluster_Settings added +- Read only feature for cluster and index added. This feature is elasticsearch >0.19.0 only. ES 0.19.0 release is not out yet + +2011-12-29 +- Elastica_Type::deleteByQuery implemented + +2011-12-20 +- Release v0.18.6.0 + +2011-12-19 +- Percolator for Type and Documents added + +2011-12-06 +- Elastica_Percolator added. See tests for more details + +2011-12-02 +- Rename Elastica_Type::getType() to Elastica_Type::getName(), getType() is now deprecated + +2011-12-01 +- Elastica_Filter_Term::addTerm renamed to setTerm, Elastica_Filter_Term::setTerm renamed to setRawTerm +- Elastica_Query_Term::addTerm renamed to setTerm, Elastica_Query_Term::setTerm renamed to setRawTerm + +2011-11-30 +- Release v0.18.5.0 + +2011-11-28 +- Elastica_Filter_Nested added + +2011-11-26 +- Elastica_Search::addIndices(), Elastica_Search::addTypes() added + +2011-11-20 +- Release v0.18.4.1 +- Elastica_Log added for logging. Has to be passed as client config to enable +- Elastica blogging introduced: http://ruflin.com/en/elastica + +2011-11-17 +- Release v0.18.4.0 +- Support for Travis CI added: http://travis-ci.org/ruflin/Elastica + +2011-11-07 +- Elastica_Index_Stats added + +2011-11-05 +- Elastica_Query_Nested added + +2011-10-29 +- TTL for document and mapping added + +2011-10-28 +- Refactored Elastica_Query_CustomScore::addCSParam to ::addParams +- Rename Elastica_Query_CustomScore::addParam to ::addCSParam +- Release v0.18.1.0 + +2011-10-20 +- Release v0.17.9.0 +- Elastica_Filter_Type added + +2011-10-19 +- Elastica_Query_CustomFilterScore added + +2011-10-15 +- API Documentation changed to DocBlox + +2011-10-10 +- Bug fixing +- Release v0.17.8.0 added + +2011-09-19 +- Release v0.17.7.0 added +- Release v0.17.6.1 added + +2011-09-18 +- Elastica_Exception_ExpectedFieldNotFound renamed to Elastica_Exception_NotFound + +2011-08-25 +- Https transport layer added + +2011-08-22 +- Typo in Terms query fixed (issue #74) + +2011-08-15 +- Refactoring HTTP connection to keep alive connection -> speed improvement during using the same client +- Release v0.17.6.0 added + +2011-08-09 +- Automatic creation of id for documents added. This was more a bug +- Release v0.17.4.0 added + +2011-08-08 +- Elastica_Query_Text added +- Params (constructor) of Elastica_Filter_GeoBoundingBox changed (array instead of single params) + +2011-08-07 +- Elastica_Query_MoreLikeThis added by @juneym. Still work under progress +- Refactoring Queries and Filters to use Elastica_Param. Adding tests + +2011-08-05 +- Elastica_Filter_Abstract enhanced for more general usage (set/get/addParam(s)) added + +2011-08-04 +- Release v0.17.3.0 added +- Elastica_Index_Settings::set/get response updated. get('...') does not require 'index.' in front anymore +- Nodes and Cluster shutdown added +- Elastica_Node::getIp() and getPort() added + +2011-07-30 +- Readd merge_factor to settings. Now working as expected. Index has to be closed first. + +2011-07-29 +- Release tag v0.17.2.0 added. Elastica is compatible with elasticsearch 0.17.2 + +2011-07-22 +- Elastica_Index_Settings::getMergePolicyMergeFactor and set removed because of enhanced merge policy implementation in ES 0.17.0 https://github.com/elasticsearch/elasticsearch/issues/998 +- Release tav v0.17.1.0 added + +2011-07-21 +- Elastica_Query_HasChild and _parent feature added by fabian +- Elastica_Filter_GeoBoundingBox added by fabian + +2011-07-20 +- Elastica_Query_Builder added by chrisdegrim + +2011-07-19 +- Release tag v0.17.0.0 added. Elastica is compatible with elasticsearch 0.17.0 + +2011-07-18 +- ResultSet::hasFacets added +- QueryString useDisMax added + +2011-07-15 +- Facet/DateHistogram and Facet/Historgram added +- Documentation pages added unter http://ruflin.github.com/Elastica +- Release tag v0.16.4.0 added + +2011-06-19 +- Add support for multiple servers to Elastica_Client (issue #39) + +2011-06-16 +- Support for multiple index, type queries and _all queries added through Elastica_Search object +- Elastica_Index::clearCache added to clean cache +- Elastica_Index::flush added + +2011-06-07 +- Elastica_Index::setNumberOfShards removed as not supported after creating index + +2011-05-11 +- Refactor client constructor. Elastica_Client::__construct(array $config) now takes a config array instead of host and port + +2011-05-08 +- Elastica_Query_QueryString::escapeTerm move to Elastica_Util::escapeTerm + +2011-04-29 +- Added getParam to Elastica_Result that more values can be retrieved from the hit array +- Elastica_Filter_Ids added http://www.elasticsearch.org/guide/reference/query-dsl/ids-filter.html +- getMergePolicyMergeFactor and getRefreshInterval to Elastica_Type_Settings added. If no value is set, default values are returned + +2011-04-28 +- Release of version 0.16.0.0 (see new version naming structure in README) + +2011-04-27 +- Refactoring of Elastica_Type::setMapping. No source parameter anymore. +- Elastica_Type_Mapping object introduced to set more fine grained mapping + +2011-04-17 +- Elastica_Filter_Exists added + +2011-04-14 +- Elastica_Type getCount replace by count() +- Count has now optional query parametere + +2011-04-01 +- Renaming of functions in Elastica_Query_Terms and Ela-stica_Query_Filter to fit new naming convention. setTerms, addTerm have different API now! + +2011-03-31 +- Deprecated code removed +- Break backward compatibility to 0.15.1 (versions introduced by wlp1979) + +2011-03-30 +- Filtered query introduced +- setRawArguments in Elastica_Query is now setParam +- open / close for index added +- Remove Elastica_Filter and Elastica_Facets because not needed anymore + +2011-03-29 +- Renaming Elastica_Filter->addQuery, addFilter to setQuery, setFilter +- Add parts of Facets API +- Add facet Terms +- Renaming Elastica_Query->addFilter to setFilter + +2011-03-24 +- Renaming of Elastica_Status_Index to Elastica_Index_Status => API Change! +- IndexSettings added for improved bulk updating http://www.elasticsearch.org/blog/2011/03/23/update-settings.html + +2011-03-21 +- Node object added +- Node_Info and Node_Stats added +- Refactoring of Cluster object + +2011-03-13 +- changes.txt introduced +- getResponse in Elastica_Response renamed to getData. getResponse now deprecated +- Index status objects added +- getIndexName in Elastica_Index renamed to getName. getIndexName is deprecated \ No newline at end of file diff --git a/modules/thirdparty/elastica/composer.json b/modules/thirdparty/elastica/composer.json new file mode 100644 index 0000000..e994d99 --- /dev/null +++ b/modules/thirdparty/elastica/composer.json @@ -0,0 +1,20 @@ +{ + "name": "ruflin/Elastica", + "description": "Elasticsearch Client", + "keywords": ["search","client"], + "homepage": "http://ruflin.github.com/Elastica/", + "type": "library", + "license": "Apache 2.0", + "authors": [ + { + "name": "Nicolas Ruflin", + "homepage": "http://ruflin.com/" + } + ], + "require": { + "php": ">=5.3.0" + }, + "autoload": { + "psr-0": {"Elastica": "lib/"} + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Client.php b/modules/thirdparty/elastica/lib/Elastica/Client.php new file mode 100755 index 0000000..351a878 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Client.php @@ -0,0 +1,413 @@ + + */ +class Elastica_Client +{ + /** + * Default elastic search port + */ + const DEFAULT_PORT = 9200; + + /** + * Default host + */ + const DEFAULT_HOST = 'localhost'; + + /** + * Default transport + * + * @var string + */ + const DEFAULT_TRANSPORT = 'Http'; + + /** + * Number of seconds after a timeout occurs for every request + * If using indexing of file large value necessary. + */ + const TIMEOUT = 300; + + /** + * Config with defaults + * + * @var array + */ + protected $_config = array( + 'host' => self::DEFAULT_HOST, + 'port' => self::DEFAULT_PORT, + 'path' => '', + 'url' => null, + 'transport' => self::DEFAULT_TRANSPORT, + 'persistent' => true, + 'timeout' => self::TIMEOUT, + 'headers' => array(), + 'servers' => array(), + 'curl' => array(), + 'roundRobin' => false, + 'log' => false, + 'retryOnConflict' => 0, + ); + + /** + * Creates a new Elastica client + * + * @param array $config OPTIONAL Additional config options + */ + public function __construct(array $config = array()) + { + $this->setConfig($config); + } + + /** + * Sets specific config values (updates and keeps default values) + * + * @param array $config Params + */ + public function setConfig(array $config) + { + foreach ($config as $key => $value) { + $this->_config[$key] = $value; + } + + return $this; + } + + /** + * Returns a specific config key or the whole + * config array if not set + * + * @param string $key Config key + * @return array|string Config value + */ + public function getConfig($key = '') + { + if (empty($key)) { + return $this->_config; + } + + if (!array_key_exists($key, $this->_config)) { + throw new Elastica_Exception_Invalid('Config key is not set: ' . $key); + } + + return $this->_config[$key]; + } + + /** + * Sets / overwrites a specific config value + * + * @param string $key Key to set + * @param mixed $value Value + * @return Elastica_Client Client object + */ + public function setConfigValue($key, $value) + { + return $this->setConfig(array($key => $value)); + } + + /** + * Returns the index for the given connection + * + * @param string $name Index name to create connection to + * @return Elastica_Index Index for the given name + */ + public function getIndex($name) + { + return new Elastica_Index($this, $name); + } + + /** + * Returns host the client connects to + * + * @return string Host + */ + public function getHost() + { + return $this->getConfig('host'); + } + + /** + * Returns connection port of this client + * + * @return int Connection port + */ + public function getPort() + { + return (int) $this->getConfig('port'); + } + + /** + * Returns transport type to user + * + * @return string Transport type + */ + public function getTransport() + { + return $this->getConfig('transport'); + } + + /** + * Adds a HTTP Header + * + * @param string $header The HTTP Header + * @param string $headerValue The HTTP Header Value + * @throws Elastica_Exception_Invalid If $header or $headerValue is not a string + */ + public function addHeader($header, $headerValue) + { + if (is_string($header) && is_string($headerValue)) { + $this->_config['headers'][$header] = $headerValue; + } else { + throw new Elastica_Exception_Invalid('Header must be a string'); + } + } + + /** + * Remove a HTTP Header + * + * @param string $header The HTTP Header to remove + * @throws Elastica_Exception_Invalid IF $header is not a string + */ + public function removeHeader($header) + { + if (is_string($header)) { + if (array_key_exists($header, $this->_config['headers'])) { + unset($this->_config['headers'][$header]); + } + } else { + throw new Elastica_Exception_Invalid('Header must be a string'); + } + } + + /** + * Uses _bulk to send documents to the server + * + * Array of Elastica_Document as input. Index and type has to be + * set inside the document, because for bulk settings documents, + * documents can belong to any type and index + * + * @param array $docs Array of Elastica_Document + * @return Elastica_Response Response object + * @throws Elastica_Exception_Invalid If docs is empty + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/bulk/ + */ + public function addDocuments(array $docs) + { + if (empty($docs)) { + throw new Elastica_Exception_Invalid('Array has to consist of at least one element'); + } + $params = array(); + + foreach ($docs as $doc) { + + $indexInfo = array( + '_index' => $doc->getIndex(), + '_type' => $doc->getType(), + '_id' => $doc->getId() + ); + + $version = $doc->getVersion(); + if (!empty($version)) { + $indexInfo['_version'] = $version; + } + + $parent = $doc->getParent(); + if (!is_null($parent)) { + $indexInfo['_parent'] = $parent; + } + + $percolate = $doc->getPercolate(); + if (!empty($percolate)) { + $indexInfo['percolate'] = $percolate; + } + + $params[] = array('index' => $indexInfo); + $params[] = $doc->getData(); + } + + return $this->bulk($params); + } + + /** + * Update document, using update script. Requires elasticsearch >= 0.19.0 + * + * @param int $id document id + * @param Elastica_Script $script script to use for update + * @param string $index index to update + * @param string $type type of index to update + * @param array $options array of query params to use for query. For possible options check es api + * @return Elastica_Response + * @link http://www.elasticsearch.org/guide/reference/api/update.html + */ + public function updateDocument($id, Elastica_Script $script, $index, $type, array $options = array()) + { + $path = $index . '/' . $type . '/' . $id . '/_update'; + if (!isset($options['retry_on_conflict'])) { + $retryOnConflict = $this->getConfig("retryOnConflict"); + $options['retry_on_conflict'] = $retryOnConflict; + } + + $data = array( + 'script' => $script->getScript(), + ); + if ($script->getLang() != null) { + $data['lang'] = $script->getLang(); + } + if ($script->getParams() != null) { + $data['params'] = $script->getParams(); + } + + return $this->request($path, Elastica_Request::POST, $data, $options); + } + + /** + * Bulk deletes documents (not implemented yet) + * + * @param array $docs Docs + * @throws Elastica_Exception + */ + public function deleteDocuments(array $docs) + { + // TODO: similar to delete ids but with type and index inside files + throw new Elastica_Exception_NotImplemented('not implemented yet'); + } + + /** + * Returns the status object for all indices + * + * @return Elastica_Status Status object + */ + public function getStatus() + { + return new Elastica_Status($this); + } + + /** + * Returns the current cluster + * + * @return Elastica_Cluster Cluster object + */ + public function getCluster() + { + return new Elastica_Cluster($this); + } + + /** + * Deletes documents with the given ids, index, type from the index + * + * @param array $ids Document ids + * @param string|Elastica_Index $index Index name + * @param string|Elastica_Type $type Type of documents + * @return Elastica_Response Response object + * @throws Elastica_Exception If ids is empty + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/bulk/ + */ + public function deleteIds(array $ids, $index, $type) + { + if (empty($ids)) { + throw new Elastica_Exception_Invalid('Array has to consist of at least one id'); + } + + if ($index instanceof Elastica_Index) { + $index = $index->getName(); + } + + if ($type instanceof Elastica_Type) { + $type = $type->getName(); + } + + $params = array(); + foreach ($ids as $id) { + $action = array( + 'delete' => array( + '_index' => $index, + '_type' => $type, + '_id' => $id, + ) + ); + + $params[] = $action; + } + + return $this->bulk($params); + } + + /** + * Bulk operation + * + * Every entry in the params array has to exactly on array + * of the bulk operation. An example param array would be: + * + * array( + * array('index' => array('_index' => 'test', '_type' => 'user', '_id' => '1')), + * array('user' => array('name' => 'hans')), + * array('delete' => array('_index' => 'test', '_type' => 'user', '_id' => '2')) + * ); + * + * @param array $params Parameter array + * @return Elastica_Response Reponse object + * @todo Test + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/bulk/ + */ + public function bulk(array $params) + { + if (empty($params)) { + throw new Elastica_Exception_Invalid('Array has to consist of at least one param'); + } + + $path = '_bulk'; + + $queryString = ''; + foreach ($params as $index => $baseArray) { + // Always newline needed + $queryString .= json_encode($baseArray) . PHP_EOL; + } + + $response = $this->request($path, Elastica_Request::PUT, $queryString); + $data = $response->getData(); + + if (isset($data['items'])) { + foreach ($data['items'] as $item) { + $params = reset($item); + if (isset($params['error'])) { + throw new Elastica_Exception_BulkResponse($response); + } + } + } + + return $response; + } + + /** + * Makes calls to the elasticsearch server based on this index + * + * It's possible to make any REST query directly over this method + * + * @param string $path Path to call + * @param string $method Rest method to use (GET, POST, DELETE, PUT) + * @param array $data OPTIONAL Arguments as array + * @param array $query OPTIONAL Query params + * @return Elastica_Response Response object + */ + public function request($path, $method, $data = array(), array $query = array()) + { + $request = new Elastica_Request($this, $path, $method, $data, $query); + + return $request->send(); + } + + /** + * Optimizes all search indices + * + * @param array $args OPTIONAL Optional arguments + * @return Elastica_Response Response object + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/indices/optimize/ + */ + public function optimizeAll($args = array()) + { + return $this->request('_optimize', Elastica_Request::POST, $args); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Cluster.php b/modules/thirdparty/elastica/lib/Elastica/Cluster.php new file mode 100755 index 0000000..a7aa915 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Cluster.php @@ -0,0 +1,160 @@ + + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/cluster + */ +class Elastica_Cluster +{ + /** + * Client + * + * @var Elastica_Client Client object + */ + protected $_client = null; + + /** + * Creates a cluster object + * + * @param Elastica_Client $client Connection client object + */ + public function __construct(Elastica_Client $client) + { + $this->_client = $client; + $this->refresh(); + } + + /** + * Refreshs all cluster information (state) + */ + public function refresh() + { + $path = '_cluster/state'; + $this->_response = $this->_client->request($path, Elastica_Request::GET); + $this->_data = $this->getResponse()->getData(); + } + + /** + * Returns the response object + * + * @return Elastica_Response Response object + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Return list of index names + * + * @return array List of index names + */ + public function getIndexNames() + { + $metaData = $this->_data['metadata']['indices']; + + $indices = array(); + foreach ($metaData as $key => $value) { + $indices[] = $key; + } + + return $indices; + } + + /** + * Returns the full state of the cluster + * + * @return array State array + * @link http://www.elasticsearch.org/guide/reference/api/admin-cluster-state.html + */ + public function getState() + { + return $this->_data; + } + + /** + * Returns a list of existing node names + * + * @return array List of node names + */ + public function getNodeNames() + { + $data = $this->getState(); + + return array_keys($data['routing_nodes']['nodes']); + } + + /** + * Returns all nodes of the cluster + * + * @return array List of Elastica_Node objects + */ + public function getNodes() + { + $nodes = array(); + foreach ($this->getNodeNames() as $name) { + $nodes[] = new Elastica_Node($name, $this->getClient()); + } + + return $nodes; + } + + /** + * Returns the client object + * + * @return Elastica_Client Client object + */ + public function getClient() + { + return $this->_client; + } + + /** + * Returns the cluster information (not implemented yet) + * + * @param array $args Additional arguemtns + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/cluster/nodes_info/ + */ + public function getInfo(array $args) + { + throw new Exception('not implemented yet'); + } + + /** + * Return Cluster health + * + * @param array $args OPTIONAL + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/cluster/health/ + */ + public function getHealth($args = array()) + { + throw new Exception('not implemented yet'); + } + + /** + * Return Cluster settings + * + * @return Elastica_Cluster_Settings + */ + public function getSettings() + { + return new Elastica_Cluster_Settings($this->getClient()); + } + + /** + * Shuts down the complete cluster + * + * @param string $delay OPTIONAL Seconds to shutdown cluster after (default = 1s) + * @return Elastica_Response + * @link http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-shutdown.html + */ + public function shutdown($delay = '1s') + { + $path = '_shutdown?delay=' . $delay; + + return $this->_client->request($path, Elastica_Request::POST); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Cluster/Settings.php b/modules/thirdparty/elastica/lib/Elastica/Cluster/Settings.php new file mode 100644 index 0000000..927bbe0 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Cluster/Settings.php @@ -0,0 +1,179 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/admin-cluster-update-settings.html + */ +class Elastica_Cluster_Settings +{ + /** + * Client + * + * @var Elastica_Client Client object + */ + protected $_client = null; + + /** + * Creates a cluster object + * + * @param Elastica_Client $client Connection client object + */ + public function __construct(Elastica_Client $client) + { + $this->_client = $client; + } + + /** + * Returns settings data + * + * @return array Settings data (persistent and transient) + */ + public function get() + { + return $this->request()->getData(); + } + + /** + * Returns the current persistent settings of the cluster + * + * If param is set, only specified setting is return. + * + * @param string $setting OPTIONAL Setting name to return + * @return array|string|null Settings data + */ + public function getPersistent($setting = '') + { + $data = $this->get(); + $settings = $data['persistent']; + + if (!empty($setting)) { + if (isset($settings[ $setting])) { + return $settings[$setting]; + } else { + return null; + } + } + + return $settings; + } + + /** + * Returns the current transient settings of the cluster + * + * If param is set, only specified setting is return. + * + * @param string $setting OPTIONAL Setting name to return + * @return array|string|null Settings data + */ + public function getTransient($setting = '') + { + $data = $this->get(); + $settings = $data['transient']; + + if (!empty($setting)) { + if (isset($settings[ $setting])) { + return $settings[$setting]; + } else { + return null; + } + } + + return $settings; + } + + /** + * Sets persistent setting + * + * @param string $key + * @param string $value + * @return Elastica_Response + */ + public function setPersistent($key, $value) + { + return $this->set( + array( + 'persistent' => array( + $key => $value + ) + ) + ); + } + + /** + * Sets transient settings + * + * @param string $key + * @param string $value + * @return Elastica_Response + */ + public function setTransient($key, $value) + { + return $this->set( + array( + 'transient' => array( + $key => $value + ) + ) + ); + } + + /** + * Sets the cluster to read only + * + * Second param can be used to set it persistent + * + * @param bool $readOnly + * @param bool $persistent + * @return Elastica_Response $response + */ + public function setReadOnly($readOnly = true, $persistent = false) + { + $key = 'cluster.blocks.read_only'; + + if ($persistent) { + $response = $this->setPersistent($key, $readOnly); + } else { + $response = $this->setTransient($key, $readOnly); + } + + return $response; + } + + /** + * Set settings for cluster + * + * @param array $settings Raw settings (including persistent or transient) + * @return Elastica_Response + */ + public function set(array $settings) + { + return $this->request($settings, Elastica_Request::PUT); + } + + /** + * Get the client + * + * @return Elastica_Client + */ + public function getClient() + { + return $this->_client; + } + + /** + * Sends settings request + * + * @param array $data OPTIONAL Data array + * @param string $method OPTIONAL Transfer method (default = Elastica_Request::GET) + * @return Elastica_Response Response object + */ + public function request(array $data = array(), $method = Elastica_Request::GET) + { + $path = '_cluster/settings'; + + return $this->getClient()->request($path, $method, $data); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Document.php b/modules/thirdparty/elastica/lib/Elastica/Document.php new file mode 100644 index 0000000..2bb13ae --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Document.php @@ -0,0 +1,390 @@ + + */ +class Elastica_Document +{ + /** + * Document id + * + * @var string|int Document id + */ + protected $_id = ''; + + /** + * Document data + * + * @var array Document data + */ + protected $_data = array(); + + /** + * Document type name + * + * @var string Document type name + */ + protected $_type = null; + + /** + * Document index name + * + * @var string Document index name + */ + protected $_index = null; + + /** + * Document version + * + * @var string Document version + */ + protected $_version = ''; + + /** + * Parent document id + * + * @var string|int Parent document id + */ + protected $_parent = null; + + /** + * Optype + * + * @var string Optype + */ + protected $_optype = ''; + + /** + * Percolate + * + * @var string Percolate + */ + protected $_percolate = ''; + + /** + * Creates a new document + * + * @param int $id OPTIONAL $id Id is create if empty + * @param array $data OPTIONAL Data array + * @param string $type OPTIONAL Type name + * @param string $index OPTIONAL Index name + */ + public function __construct($id = '', array $data = array(), $type = '', $index = '') + { + $this->_id = $id; + $this->setData($data); + $this->setType($type); + $this->setIndex($index); + } + + /** + * Returns document id + * + * @return string|int Document id + */ + public function getId() + { + return $this->_id; + } + + /** + * Adds the given key/value pair to the document + * + * @param string $key Document entry key + * @param mixed $value Document entry value + * @return Elastica_Document + */ + public function add($key, $value) + { + $this->_data[$key] = $value; + + return $this; + } + + /** + * Adds a file to the index + * + * To use this feature you have to call the following command in the + * elasticsearch directory: + * + * ./bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/1.2.0 + * + * This installs the tika file analysis plugin. More infos about supported formats + * can be found here: {@link http://tika.apache.org/0.7/formats.html} + * + * @param string $key Key to add the file to + * @param string $filepath Path to add the file + * @param string $mimeType OPTIONAL Header mime type + * @return Elastica_Document + */ + public function addFile($key, $filepath, $mimeType = '') + { + $value = base64_encode(file_get_contents($filepath)); + + if (!empty($mimeType)) { + $value = array('_content_type' => $mimeType, '_name' => $filepath, 'content' => $value,); + } + + $this->add($key, $value); + + return $this; + } + + /** + * Add file content + * + * @param string $key Document key + * @param string $content Raw file content + * @return Elastica_Document + */ + public function addFileContent($key, $content) + { + return $this->add($key, base64_encode($content)); + } + + /** + * Adds a geopoint to the document + * + * Geohashes re not yet supported + * + * @param string $key Field key + * @param float $latitude Latitud value + * @param float $longitude Longitude value + * @link http://www.elasticsearch.com/docs/elasticsearch/mapping/geo_point/ + * @return Elastica_Document + */ + public function addGeoPoint($key, $latitude, $longitude) + { + $value = array('lat' => $latitude, 'lon' => $longitude,); + + $this->add($key, $value); + + return $this; + } + + /** + * Overwrites the curent document data with the given data + * + * @param array $data Data array + * @return Elastica_Document + */ + public function setData(array $data) + { + $this->_data = $data; + + return $this; + } + + /** + * Sets lifetime of document + * + * @param string $ttl + * @return Elastica_Document + */ + public function setTtl($ttl) + { + return $this->add('_ttl', $ttl); + } + + /** + * Returns the document data + * + * @return array Document data + */ + public function getData() + { + return $this->_data; + } + + /** + * Sets the document type name + * + * @param string $type Type name + * @return Elastica_Document Current object + */ + public function setType($type) + { + $this->_type = $type; + + return $this; + } + + /** + * Return document type name + * + * @return string Document type name + * @throws Elastica_Exception_Invalid + */ + public function getType() + { + $type = $this->_type; + + if (is_null($type)) { + throw new Elastica_Exception_Invalid('Type not set'); + } + + return $type; + } + + /** + * Sets the document index name + * + * @param string $index Index name + * @return Elastica_Document Current object + */ + public function setIndex($index) + { + $this->_index = $index; + + return $this; + } + + /** + * Get the document index name + * + * @return string Index name + * @throws Elastica_Exception_Invalid + */ + public function getIndex() + { + $index = $this->_index; + + if (is_null($index)) { + throw new Elastica_Exception_Invalid('Index not set'); + } + + return $index; + } + + /** + * Sets the version of a document for use with optimistic concurrency control + * + * @param int $version Document version + * @return Elastica_Document Current object + * @link http://www.elasticsearch.org/blog/2011/02/08/versioning.html + */ + public function setVersion($version) + { + if ($version !== '') { + $this->_version = (int) $version; + } + + return $this; + } + + /** + * Returns document version + * + * @return string|int Document version + */ + public function getVersion() + { + return $this->_version; + } + + /** + * Sets parent document id + * + * @param string|int $parent Parent document id + * @return Elastica_Document Current object + * @link http://www.elasticsearch.org/guide/reference/mapping/parent-field.html + */ + public function setParent($parent) + { + $this->_parent = $parent; + + return $this; + } + + /** + * Returns the parent document id + * + * @return string|int Parent document id + */ + public function getParent() + { + return $this->_parent; + } + + /** + * Set operation type + * + * @param string $optype Only accept create + * @return Elastica_Document Current object + */ + public function setOpType($optype) + { + $this->_optype = $optype; + + return $this; + } + + /** + * Get operation type + */ + public function getOpType() + { + return $this->_optype; + } + + /** + * Set percolate query param + * + * @param string $value percolator filter + * @return Elastica_Document + */ + public function setPercolate($value = '*') + { + $this->_percolate = $value; + + return $this; + } + + /** + * Get percolate parameter + * + * @return string + */ + public function getPercolate() + { + return $this->_percolate; + } + + /** + * Returns the document as an array + * @return array + */ + public function toArray() + { + $doc = array(); + + if (!is_null($this->_index)) { + $doc['_index'] = $this->_index; + } + + if (!is_null($this->_type)) { + $doc['_type'] = $this->_type; + } + + if (!is_null($this->_index)) { + $doc['_id'] = $this->getId(); + } + + $version = $this->getVersion(); + if (!empty($version)) { + $doc['_version'] = $version; + } + + $parent = $this->getParent(); + if (!is_null($parent)) { + $doc['_parent'] = $parent; + } + + $doc['_source'] = $this->getData(); + + return $doc; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Exception/Abstract.php b/modules/thirdparty/elastica/lib/Elastica/Exception/Abstract.php new file mode 100755 index 0000000..08d28eb --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Exception/Abstract.php @@ -0,0 +1,11 @@ + + */ +abstract class Elastica_Exception_Abstract extends Exception +{ +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Exception/BulkResponse.php b/modules/thirdparty/elastica/lib/Elastica/Exception/BulkResponse.php new file mode 100644 index 0000000..873cca1 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Exception/BulkResponse.php @@ -0,0 +1,66 @@ +_response = $response; + parent::__construct('Error in one or more bulk request actions'); + } + + /** + * Returns response object + * + * @return Elastica_Response Response object + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Returns array of failed actions + * + * @return array Array of failed actions + */ + public function getFailures() + { + $data = $this->_response->getData(); + $errors = array(); + + foreach ($data['items'] as $item) { + $meta = reset($item); + $action = key($item); + if (isset($meta['error'])) { + $error = array( + 'action' => $action, + ); + foreach ($meta as $key => $value) { + $key = ltrim($key, '_'); + $error[$key] = $value; + } + + $errors[] = $error; + } + } + + return $errors; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Exception/Client.php b/modules/thirdparty/elastica/lib/Elastica/Exception/Client.php new file mode 100755 index 0000000..e8e2480 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Exception/Client.php @@ -0,0 +1,117 @@ + + */ +class Elastica_Exception_Client extends Elastica_Exception_Abstract +{ + /** + * Error code / message + * + * @var string Error code / message + */ + protected $_error = 0; + + /** + * Request + * + * @var Elastica_Request Request object + */ + protected $_request = null; + + /** + * Response + * + * @var Elastica_Response Response object + */ + protected $_response = null; + + /** + * Construct Exception + * + * @param string $error Error + * @param Elastica_Request $request + * @param Elastica_Response $response + */ + public function __construct($error, Elastica_Request $request = null, Elastica_Response $response = null) + { + $this->_error = $error; + $this->_request = $request; + $this->_response = $response; + + $message = $this->getErrorMessage($this->getError()); + parent::__construct($message); + } + + /** + * Returns the error message corresponding to the error code + * cUrl error code reference can be found here {@link http://curl.haxx.se/libcurl/c/libcurl-errors.html} + * + * @param string $error Error code + * @return string Error message + */ + public function getErrorMessage($error) + { + switch ($error) { + case CURLE_UNSUPPORTED_PROTOCOL: + $error = "Unsupported protocol"; + break; + case CURLE_FAILED_INIT: + $error = "Internal cUrl error?"; + break; + case CURLE_URL_MALFORMAT: + $error = "Malformed URL"; + break; + case CURLE_COULDNT_RESOLVE_PROXY: + $error = "Couldnt resolve proxy"; + break; + case CURLE_COULDNT_RESOLVE_HOST: + $error = "Couldnt resolve host"; + break; + case CURLE_COULDNT_CONNECT: + $error = "Couldnt connect to host, ElasticSearch down?"; + break; + case 28: + $error = "Operation timed out"; + break; + default: + $error = "Unknown error:" . $error; + break; + } + + return $error; + } + + /** + * Return Error code / message + * + * @return string Error code / message + */ + public function getError() + { + return $this->_error; + } + + /** + * Returns request object + * + * @return Elastica_Transport_Abstract Request object + */ + public function getRequest() + { + return $this->_request; + } + + /** + * Returns response object + * + * @return Elastica_Response Response object + */ + public function getResponse() + { + return $this->_response; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Exception/Invalid.php b/modules/thirdparty/elastica/lib/Elastica/Exception/Invalid.php new file mode 100755 index 0000000..eefb3fe --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Exception/Invalid.php @@ -0,0 +1,11 @@ + + */ +class Elastica_Exception_Invalid extends Elastica_Exception_Abstract +{ +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Exception/NotFound.php b/modules/thirdparty/elastica/lib/Elastica/Exception/NotFound.php new file mode 100644 index 0000000..91152c2 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Exception/NotFound.php @@ -0,0 +1,11 @@ + + */ +class Elastica_Exception_NotFound extends Elastica_Exception_Abstract +{ +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Exception/NotImplemented.php b/modules/thirdparty/elastica/lib/Elastica/Exception/NotImplemented.php new file mode 100755 index 0000000..680f6e4 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Exception/NotImplemented.php @@ -0,0 +1,13 @@ + + */ +class Elastica_Exception_NotImplemented extends Elastica_Exception_Abstract +{ +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Exception/Response.php b/modules/thirdparty/elastica/lib/Elastica/Exception/Response.php new file mode 100755 index 0000000..c2677a1 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Exception/Response.php @@ -0,0 +1,38 @@ + + */ +class Elastica_Exception_Response extends Elastica_Exception_Abstract +{ + /** + * Response + * + * @var Elastica_Response Response object + */ + protected $_response = null; + + /** + * Construct Exception + * + * @param Elastica_Response $response + */ + public function __construct(Elastica_Response $response) + { + $this->_response = $response; + parent::__construct($response->getError()); + } + + /** + * Returns reponsce object + * + * @return Elastica_Response Response object + */ + public function getResponse() + { + return $this->_response; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/Abstract.php b/modules/thirdparty/elastica/lib/Elastica/Facet/Abstract.php new file mode 100644 index 0000000..8317eee --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Facet/Abstract.php @@ -0,0 +1,134 @@ + + * @author Jasper van Wanrooy + */ +abstract class Elastica_Facet_Abstract extends Elastica_Param +{ + /** + * Holds the name of the facet. + * @var string + */ + protected $_name = ''; + + /** + * Holds all facet parameters. + * @var array + */ + protected $_facet = array(); + + /** + * Constructs a Facet object. + * + * @param string $name The name of the facet. + */ + public function __construct($name) + { + $this->setName($name); + } + + /** + * Sets the name of the facet. It is automatically set by + * the constructor. + * + * @param string $name The name of the facet. + * @throws Elastica_Exception_Invalid + * @return Elastica_Facet_Abstract + */ + public function setName($name) + { + if (empty($name)) { + throw new Elastica_Exception_Invalid('Facet name has to be set'); + } + $this->_name = $name; + + return $this; + } + + /** + * Gets the name of the facet. + * + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * Sets a filter for this facet. + * + * @param Elastica_Filter_Abstract $filter A filter to apply on the facet. + * @return Elastica_Facet_Abstract + */ + public function setFilter(Elastica_Filter_Abstract $filter) + { + return $this->_setFacetParam('facet_filter', $filter->toArray()); + } + + /** + * Sets the flag to either run the facet globally or bound to the + * current search query. When not set, it defaults to the + * ElasticSearch default value. + * + * @param bool $global Flag to either run the facet globally. + * @return Elastica_Facet_Abstract + */ + public function setGlobal($global = true) + { + return $this->_setFacetParam('global', (bool) $global); + } + + /** + * Sets the path to the nested document + * + * @param string $nestedPath Nested path + * @return Elastica_Facet_Abstract + */ + public function setNested($nestedPath) + { + return $this->_setFacetParam('nested', $nestedPath); + } + + /** + * Sets the scope + * + * @param string $scope Scope + * @return Elastica_Facet_Abstract + */ + public function setScope($scope) + { + return $this->_setFacetParam('scope', $scope); + } + + /** + * Basic definition of all specs of the facet. Each implementation + * should override this function in order to set it's specific + * settings. + * + * @return array + */ + public function toArray() + { + return $this->_facet; + } + + /** + * Sets a param for the facet. Each facet implementation needs to take + * care of handling their own params. + * + * @param string $key The key of the param to set. + * @param mixed $value The value of the param. + * @return Elastica_Facet_Abstract + */ + protected function _setFacetParam($key, $value) + { + $this->_facet[$key] = $value; + + return $this; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/DateHistogram.php b/modules/thirdparty/elastica/lib/Elastica/Facet/DateHistogram.php new file mode 100644 index 0000000..c9856b5 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Facet/DateHistogram.php @@ -0,0 +1,41 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/search/facets/date-histogram-facet.html + * @link https://github.com/elasticsearch/elasticsearch/issues/591 + */ +class Elastica_Facet_DateHistogram extends Elastica_Facet_Histogram +{ + /** + * Set the time_zone parameter + * + * @param string $tzOffset + * @return void + */ + public function setTimezone($tzOffset) + { + return $this->setParam('time_zone', $tzOffset); + } + + /** + * Creates the full facet definition, which includes the basic + * facet definition of the parent. + * + * @see Elastica_Facet_Abstract::toArray() + * @throws Elastica_Exception_Invalid When the right fields haven't been set. + * @return array + */ + public function toArray() + { + /** + * Set the range in the abstract as param. + */ + $this->_setFacetParam('date_histogram', $this->_params); + + return $this->_facet; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/Filter.php b/modules/thirdparty/elastica/lib/Elastica/Facet/Filter.php new file mode 100644 index 0000000..65356fa --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Facet/Filter.php @@ -0,0 +1,22 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/search/facets/filter-facet.html + */ +class Elastica_Facet_Filter extends Elastica_Facet_Abstract +{ + /** + * Set the filter for the facet. + * + * @param Elastica_Filter_Abstract $filter + * @return Elastica_Facet_Filter + */ + public function setFilter(Elastica_Filter_Abstract $filter) + { + return $this->_setFacetParam('filter', $filter->toArray()); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/GeoDistance.php b/modules/thirdparty/elastica/lib/Elastica/Facet/GeoDistance.php new file mode 100644 index 0000000..ec4288a --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Facet/GeoDistance.php @@ -0,0 +1,63 @@ + + * @linkhttp://www.elasticsearch.org/guide/reference/api/search/facets/geo-distance-facet.html + */ +class Elastica_Facet_GeoDistance extends Elastica_Facet_Abstract +{ + /** + * Sets the ranges for the facet all at once. + * Sample ranges: + * array ( + * array('to' => 50), + * array('from' => 20, 'to' => 70), + * array('from' => 70, 'to' => 120), + * array('from' => 150) + * ) + * + * @param array $ranges Numerical array with range definitions. + * @return Elastica_Facet_GeoDistance + */ + public function setRanges(array $ranges) + { + return $this->setParam ( 'ranges', $ranges ); + } + + /** + * Set the relative GeoPoint for the facet. + * + * @param string $typeField index type and field e.g foo.bar + * @param float $latitude + * @param float $longitude + * @return Elastica_Facet_GeoDistance + */ + public function setGeoPoint($typeField, $latitude, $longitude) + { + return $this->setParam ( $typeField, array ( + "lat" => $latitude, + "lon" => $longitude + ) ); + } + + /** + * Creates the full facet definition, which includes the basic + * facet definition of the parent. + * + * @see Elastica_Facet_Abstract::toArray() + * @throws Elastica_Exception_Invalid When the right fields haven't been set. + * @return array + */ + public function toArray() + { + /** + * Set the geo_distance in the abstract as param. + */ + $this->_setFacetParam ( 'geo_distance', $this->_params ); + + return parent::toArray (); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/Histogram.php b/modules/thirdparty/elastica/lib/Elastica/Facet/Histogram.php new file mode 100644 index 0000000..b721353 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Facet/Histogram.php @@ -0,0 +1,86 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/search/facets/histogram-facet.html + */ +class Elastica_Facet_Histogram extends Elastica_Facet_Abstract +{ + /** + * Sets the field for histogram + * + * @param string $field The name of the field for the historgram + * @return Elastica_Facet_Histogram + */ + public function setField($field) + { + return $this->setParam('field', $field); + } + + /** + * Set the value for interval + * + * @param string $interval + * @return Elastica_Facet_Range + */ + public function setInterval($interval) + { + return $this->setParam('interval', $interval); + } + + /** + * Set the fields for key_field and value_field + * + * @param string $keyField Key field + * @param string $valueField Value field + * @return Elastica_Facet_Range + */ + public function setKeyValueFields($keyField, $valueField) + { + return $this->setParam('key_field', $keyField)->setParam('value_field', $valueField); + } + + /** + * Sets the key and value for this facet by script. + * + * @param string $keyScript Script to check whether it falls into the range. + * @param string $valueScript Script to use for statistical calculations. + */ + public function setKeyValueScripts($keyScript, $valueScript) + { + return $this->setParam('key_script', $keyScript) + ->setParam('value_script', $valueScript); + } + + /** + * Set the "params" essential to the a script + * + * @param array $params Associative array (key/value pair) + * @return Elastica_Facet_Histogram Facet object + */ + public function setScriptParams(array $params) + { + return $this->setParam('params', $params); + } + + /** + * Creates the full facet definition, which includes the basic + * facet definition of the parent. + * + * @see Elastica_Facet_Abstract::toArray() + * @throws Elastica_Exception_Invalid When the right fields haven't been set. + * @return array + */ + public function toArray() + { + /** + * Set the range in the abstract as param. + */ + $this->_setFacetParam('histogram', $this->_params); + + return parent::toArray(); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/Query.php b/modules/thirdparty/elastica/lib/Elastica/Facet/Query.php new file mode 100644 index 0000000..4e49bdc --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Facet/Query.php @@ -0,0 +1,22 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/search/facets/query-facet.html + */ +class Elastica_Facet_Query extends Elastica_Facet_Abstract +{ + /** + * Set the query for the facet. + * + * @param Elastica_Query_Abstract $query + * @return Elastica_Facet_Query + */ + public function setQuery(Elastica_Query_Abstract $query) + { + return $this->_setFacetParam('query', $query->toArray()); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/Range.php b/modules/thirdparty/elastica/lib/Elastica/Facet/Range.php new file mode 100644 index 0000000..6d7a5b1 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Facet/Range.php @@ -0,0 +1,124 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/search/facets/range-facet.html + */ +class Elastica_Facet_Range extends Elastica_Facet_Abstract +{ + /** + * Sets the field for the range. + * + * @param string $field The name of the field for range. + * @return Elastica_Facet_Range + */ + public function setField($field) + { + return $this->setParam('field', $field); + } + + /** + * Sets the fields by their separate key and value fields. + * + * @param string $keyField The key_field param for the range. + * @param string $valueField The key_value param for the range. + * @return Elastica_Facet_Range + */ + public function setKeyValueFields($keyField, $valueField) + { + return $this->setParam('key_field', $keyField) + ->setParam('value_field', $valueField); + } + + /** + * Sets the key and value for this facet by script. + * + * @param string $keyScript Script to check whether it falls into the range. + * @param string $valueScript Script to use for statistical calculations. + */ + public function setKeyValueScripts($keyScript, $valueScript) + { + return $this->setParam('key_script', $keyScript) + ->setParam('value_script', $valueScript); + } + + /** + * Sets the ranges for the facet all at once. Sample ranges: + * array ( + * array('to' => 50), + * array('from' => 20, 'to' 70), + * array('from' => 70, 'to' => 120), + * array('from' => 150) + * ) + * + * @param array $ranges Numerical array with range definitions. + * @return Elastica_Facet_Range + */ + public function setRanges(array $ranges) + { + return $this->setParam('ranges', $ranges); + } + + /** + * Adds a range to the range facet. + * + * @param mixed $from The from for the range. + * @param mixed $to The to for the range. + * @return Elastica_Facet_Range + */ + public function addRange($from = null, $to = null) + { + if (!isset($this->_params['ranges']) || !is_array($this->_params['ranges'])) { + $this->_params['ranges'] = array(); + } + + $this->_params['ranges'][] = array('from' => $from, 'to' => $to); + + return $this; + } + + /** + * Creates the full facet definition, which includes the basic + * facet definition of the parent. + * + * @see Elastica_Facet_Abstract::toArray() + * @throws Elastica_Exception_Invalid When the right fields haven't been set. + * @return array + */ + public function toArray() + { + /** + * Check the facet for validity. + * There are three ways to set the key and value field for the range: + * - a single field for both key and value; or + * - separate fields for key and value; or + * - separate scripts for key and value. + */ + $fieldTypesSet = 0; + if (isset($this->_params['field'])) { + $fieldTypesSet++; + } + if (isset($this->_params['key_field'])) { + $fieldTypesSet++; + } + if (isset($this->_params['key_script'])) { + $fieldTypesSet++; + } + + if ($fieldTypesSet === 0) { + throw new Elastica_Exception_Invalid('Neither field, key_field nor key_script is set.'); + } elseif ($fieldTypesSet > 1) { + throw new Elastica_Exception_Invalid('Either field, key_field and key_value or key_script and value_script should be set.'); + } + + /** + * Set the range in the abstract as param. + */ + $this->_setFacetParam('range', $this->_params); + + return parent::toArray(); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/Statistical.php b/modules/thirdparty/elastica/lib/Elastica/Facet/Statistical.php new file mode 100644 index 0000000..b0c2787 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Facet/Statistical.php @@ -0,0 +1,58 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/search/facets/statistical-facet.html + */ +class Elastica_Facet_Statistical extends Elastica_Facet_Abstract +{ + /** + * Sets the field for the statistical query. + * + * @param string $field The field name for the statistical query. + * @return Elastica_Facet_Statistical + */ + public function setField($field) + { + return $this->setParam('field', $field); + } + + /** + * Sets multiple fields for the statistical query. + * + * @param array $fields Numerical array with the fields for the statistical query. + * @return Elastica_Facet_Statistical + */ + public function setFields(array $fields) + { + return $this->setParam('fields', $fields); + } + + /** + * Sets a script to calculate statistical information + * + * @param string $script The script to do calculations on the statistical values + * @return Elastica_Facet_Statistical + */ + public function setScript($script) + { + return $this->setParam('script', $script); + } + + /** + * Creates the full facet definition, which includes the basic + * facet definition of the parent. + * + * @see Elastica_Facet_Abstract::toArray() + * @return array + */ + public function toArray() + { + $this->_setFacetParam('statistical', $this->_params); + + return parent::toArray(); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/Terms.php b/modules/thirdparty/elastica/lib/Elastica/Facet/Terms.php new file mode 100644 index 0000000..d76d429 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Facet/Terms.php @@ -0,0 +1,107 @@ + + * @author Jasper van Wanrooy + * @link http://www.elasticsearch.org/guide/reference/api/search/facets/terms-facet.html + */ +class Elastica_Facet_Terms extends Elastica_Facet_Abstract +{ + /** + * Holds the types of ordering which are allowed + * by ElasticSearch. + * + * @var array + */ + protected $_orderTypes = array('count', 'term', 'reverse_count', 'reverse_term'); + + /** + * Sets the field for the terms. + * + * @param string $field The field name for the terms. + * @return Elastica_Facet_Terms + */ + public function setField($field) + { + return $this->setParam('field', $field); + } + + /** + * Sets multiple fields for the terms. + * + * @param array $fields Numerical array with the fields for the terms. + * @return Elastica_Facet_Terms + */ + public function setFields(array $fields) + { + return $this->setParam('fields', $fields); + } + + /** + * Sets the flag to return all available terms. When they + * don't have a hit, they have a count of zero. + * + * @param bool $allTerms Flag to fetch all terms. + * @return Elastica_Facet_Terms + */ + public function setAllTerms($allTerms) + { + return $this->setParam('all_terms', (bool) $allTerms); + } + + /** + * Sets the ordering type for this facet. ElasticSearch + * internal default is count. + * + * @param string $type The order type to set use for sorting of the terms. + * @throws Elastica_Exception_Invalid When an invalid order type was set. + * @return Elastica_Facet_Terms + */ + public function setOrder($type) + { + if (!in_array($type, $this->_orderTypes)) { + throw new Elastica_Exception_Invalid('Invalid order type: ' . $type); + } + + return $this->setParam('order', $type); + } + + /** + * Set an array with terms which are omitted in the search. + * + * @param array $exclude Numerical array which includes all terms which needs to be ignored. + * @return Elastica_Facet_Terms + */ + public function setExclude(array $exclude) + { + return $this->setParam('exclude', $exclude); + } + + /** + * Sets the amount of terms to be returned. + * + * @param int $size The amount of terms to be returned. + * @return Elastica_Facet_Terms + */ + public function setSize($size) + { + return $this->setParam('size', (int) $size); + } + + /** + * Creates the full facet definition, which includes the basic + * facet definition of the parent. + * + * @see Elastica_Facet_Abstract::toArray() + * @return array + */ + public function toArray() + { + $this->_setFacetParam('terms', $this->_params); + + return parent::toArray(); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Facet/TermsStats.php b/modules/thirdparty/elastica/lib/Elastica/Facet/TermsStats.php new file mode 100644 index 0000000..7b4f2c4 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Facet/TermsStats.php @@ -0,0 +1,60 @@ + + */ +class Elastica_Facet_TermsStats extends Elastica_Facet_Abstract +{ + + /** + * Sets the key field for the query. + * + * @param string $keyField The key field name for the query. + * @return Elastica_Facet_TermsStats + */ + public function setKeyField( $keyField ) + { + return $this->setParam( 'key_field', $keyField ); + } + + /** + * Sets a script to calculate statistical information on a per term basis + * + * @param string $valueScript The script to do calculations on the statistical values + * @return Elastica_Facet_TermsStats + */ + public function setValueScript( $valueScript ) + { + return $this->setParam( 'value_script', $valueScript ); + } + + /** + * Sets a field to compute basic statistical results on + * + * @param string $valueField The field to compute statistical values for + * @return Elastica_Facet_TermsStats + */ + public function setValueField( $valueField ) + { + return $this->setParam( 'value_field', $valueField ); + } + + /** + * Creates the full facet definition, which includes the basic + * facet definition of the parent. + * + * @see Elastica_Facet_Abstract::toArray() + * @return array + */ + public function toArray() + { + $this->_setFacetParam( 'terms_stats', $this->_params ); + + return parent::toArray(); + } + +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Abstract.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Abstract.php new file mode 100755 index 0000000..1c736b9 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Abstract.php @@ -0,0 +1,50 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/ + */ +abstract class Elastica_Filter_Abstract extends Elastica_Param +{ + /** + * Sets the filter cache + * + * @param boolean $cached Cached + * @return Elastica_Filter_Abstract + */ + public function setCached($cached = true) + { + return $this->setParam('_cache', (bool) $cached); + } + + /** + * Sets the filter cache key + * + * @param string $cacheKey Cache key + * @return Elastica_Filter_Abstract + */ + public function setCacheKey($cacheKey) + { + $cacheKey = (string) $cacheKey; + + if (empty($cacheKey)) { + throw new Elastica_Exception_Invalid('Invalid parameter. Has to be a non empty string'); + } + + return $this->setParam('_cache_key', (string) $cacheKey); + } + + /** + * Sets the filter name + * + * @param string $name Name + * @return Elastica_Filter_Abstract + */ + public function setName($name) + { + return $this->setParam('_name', $name); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Abstract/Multi.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Abstract/Multi.php new file mode 100644 index 0000000..30fb74a --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Abstract/Multi.php @@ -0,0 +1,67 @@ + + */ +abstract class Elastica_Filter_Abstract_Multi extends Elastica_Filter_Abstract +{ + /** + * Filters + * @var array + */ + protected $_filters = array(); + + /** + * Add filter + * + * @param Elastica_Filter_Abstract $filter + * @return Elastica_Filter_Abstract_Multi + */ + public function addFilter(Elastica_Filter_Abstract $filter) + { + $this->_filters[] = $filter->toArray(); + + return $this; + } + + /** + * Set filters + * + * @param array $filters + * @return Elastica_Filter_Abstract_Multi + */ + public function setFilters(array $filters) + { + $this->_filters = array(); + + foreach ($filters as $filter) { + $this->addFilter($filter); + } + + return $this; + } + + /** + * @see Elastica_Param::toArray() + */ + public function toArray() + { + $data = parent::toArray(); + $name = $this->_getBaseName(); + $filterData = $data[$name]; + + if (empty($filterData)) { + $filterData = $this->_filters; + } else { + $filterData['filters'] = $this->_filters; + } + + $data[$name] = $filterData; + + return $data; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/And.php b/modules/thirdparty/elastica/lib/Elastica/Filter/And.php new file mode 100644 index 0000000..ab226f8 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/And.php @@ -0,0 +1,13 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/and-filter.html + */ +class Elastica_Filter_And extends Elastica_Filter_Abstract_Multi +{ +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Bool.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Bool.php new file mode 100755 index 0000000..8909a33 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Bool.php @@ -0,0 +1,147 @@ + + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/bool_query/ + */ +class Elastica_Filter_Bool extends Elastica_Filter_Abstract +{ + /** + * minimum number of matches + * + * @var int minimum number of matches + */ + protected $_minimumNumberShouldMatch = 1; + + /** + * Must + * + * @var array + */ + protected $_must = array(); + + /** + * Should + * + * @var array + */ + protected $_should = array(); + + /** + * Must not + * + * @var array + */ + protected $_mustNot = array(); + + /** + * Adds should filter + * + * @param array|Elastica_Filter_Abstract $args Filter data + * @return Elastica_Filter_Bool Current object + */ + public function addShould($args) + { + return $this->_addFilter('should', $args); + } + + /** + * Adds must filter + * + * @param array|Elastica_Filter_Abstract $args Filter data + * @return Elastica_Filter_Bool Current object + */ + public function addMust($args) + { + return $this->_addFilter('must', $args); + } + + /** + * Adds mustNot filter + * + * @param array|Elastica_Filter_Abstract $args Filter data + * @return Elastica_Filter_Bool Current object + */ + public function addMustNot($args) + { + return $this->_addFilter('mustNot', $args); + } + + /** + * Adds general filter based on type + * + * @param string $type Filter type + * @param array|Elastica_Filter_Abstract $args Filter data + * @return Elastica_Filter_Bool Current object + */ + protected function _addFilter($type, $args) + { + if ($args instanceof Elastica_Filter_Abstract) { + $args = $args->toArray(); + } + + if (!is_array($args)) { + throw new Elastica_Exception_Invalid('Invalid parameter. Has to be array or instance of Elastica_Filter'); + } + + $varName = '_' . $type; + $this->{$varName}[] = $args; + + return $this; + } + + /** + * Converts bool filter to array + * + * @see Elastica_Filter_Abstract::toArray() + * @return array Filter array + */ + public function toArray() + { + $args = array(); + + if (!empty($this->_must)) { + $args['must'] = $this->_must; + } + + if (!empty($this->_should)) { + $args['should'] = $this->_should; + } + + if (!empty($this->_mustNot)) { + $args['must_not'] = $this->_mustNot; + } + + return array('bool' => $args); + } + + /** + * Sets the boost value for this filter + * + * @param float $boost Boost + * @return Elastica_Filter_Bool Current object + */ + public function setBoost($boost) + { + $this->_boost = $boost; + + return $this; + } + + /** + * Sets the minimum number that should filter have to match + * + * @param int $minimumNumberShouldMatch Number of matches + * @return Elastica_Filter_Bool Current object + */ + public function setMinimumNumberShouldMatch($minimumNumberShouldMatch) + { + $this->_minimumNumberShouldMatch = intval($minimumNumberShouldMatch); + + return $this; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Exists.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Exists.php new file mode 100644 index 0000000..12006f2 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Exists.php @@ -0,0 +1,33 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/exists-filter.html + */ +class Elastica_Filter_Exists extends Elastica_Filter_Abstract +{ + /** + * Construct exists filter + * + * @param string $field + */ + public function __construct($field) + { + $this->setField($field); + } + + /** + * Set field + * + * @param string $field + * @return Elastica_Filter_Exists + */ + public function setField($field) + { + return $this->setParam('field', $field); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/GeoBoundingBox.php b/modules/thirdparty/elastica/lib/Elastica/Filter/GeoBoundingBox.php new file mode 100755 index 0000000..9958572 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/GeoBoundingBox.php @@ -0,0 +1,46 @@ + + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/geo_bounding_box_filter/ + */ +class Elastica_Filter_GeoBoundingBox extends Elastica_Filter_Abstract +{ + /** + * Construct GeoBoundingBox filter + * + * @param string $key Key + * @param array $coordinates Array with top left coordinate as first and bottom right coordinate as second element + */ + public function __construct($key, array $coordinates) + { + $this->addCoordinates($key, $coordinates); + } + + /** + * Add coordinates + * + * @param string $key Key + * @param array $coordinates Array with top left coordinate as first and bottom right coordinate as second element + * @throws Elastica_Exception_Invalid If $coordinates doesn't have two elements + * @return Elastica_Filter_GeoBoundingBox Current object + */ + public function addCoordinates($key, array $coordinates) + { + if (!isset($coordinates[0]) || !isset($coordinates[1])) { + throw new Elastica_Exception_Invalid('expected $coordinates to be an array with two elements'); + } + + $this->setParam($key, array( + 'top_left' => $coordinates[0], + 'bottom_right' => $coordinates[1] + )); + + return $this; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/GeoDistance.php b/modules/thirdparty/elastica/lib/Elastica/Filter/GeoDistance.php new file mode 100755 index 0000000..fa2ac39 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/GeoDistance.php @@ -0,0 +1,242 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/geo-distance-filter.html + */ +class Elastica_Filter_GeoDistance extends Elastica_Filter_Abstract +{ + const DISTANCE_TYPE_ARC = 'arc'; + const DISTANCE_TYPE_PLANE = 'plane'; + + const OPTIMIZE_BBOX_MEMORY = 'memory'; + const OPTIMIZE_BBOX_INDEXED = 'indexed'; + const OPTIMIZE_BBOX_NONE = 'none'; + + /** + * Location type + * + * Decides if this filter uses latitude/longitude or geohash for the location. + * Values are "latlon" or "geohash". + * + * @var string + */ + private $_locationType = null; + + /** + * Key + * + * @var string + */ + private $_key = null; + + /** + * Latitude + * + * @var float + */ + private $_latitude = null; + + /** + * Longitude + * + * @var float + */ + private $_longitude = null; + + /** + * Geohash + * + * @var string + */ + private $_geohash = null; + + /** + * Create GeoDistance object + * + * @param string $key Key + * @param array|string $location Location as array or geohash: array('lat' => 48.86, 'lon' => 2.35) OR 'drm3btev3e86' + * @param string $distance Distance + * @throws Elastica_Exception_Invalid + */ + public function __construct($key, $location, $distance) + { + // Fix old constructor. Remove it when the old constructor is not supported anymore + if (func_num_args() === 4) { + extract($this->_oldConstruct(func_get_args())); + } + + // Key + $this->setKey($key); + + // Location + if (is_array($location)) { // Latitude/Longitude + // Latitude + if (isset($location['lat'])) { + $this->setLatitude($location['lat']); + } else { + throw new Elastica_Exception_Invalid('$location[\'lat\'] has to be set'); + } + + // Longitude + if (isset($location['lon'])) { + $this->setLongitude($location['lon']); + } else { + throw new Elastica_Exception_Invalid('$location[\'lon\'] has to be set'); + } + } elseif (is_string($location)) { // Geohash + $this->setGeohash($location); + } else { // Invalid location + throw new Elastica_Exception_Invalid('$location has to be an array (latitude/longitude) or a string (geohash)'); + } + + //Distance + $this->setDistance($distance); + } + + /** + * Convert old constructor signature to the new one + * Remove it when the old constructor is not supported + * + * @deprecated + * @param array $args old arguments + * @return array new arguments + */ + private function _oldConstruct(array $args) + { + return array( + 'key' => $args[0], + 'location' => array( + 'lat' => $args[1], + 'lon' => $args[2] + ), + 'distance' => $args[3] + ); + } + + /** + * @param string $key + * @return Elastica_Filter_GeoDistance current filter + */ + public function setKey($key) + { + $this->_key = $key; + + return $this; + } + + /** + * @param float $latitude + * @return Elastica_Filter_GeoDistance current filter + */ + public function setLatitude($latitude) + { + $this->_latitude = (float) $latitude; + $this->_locationType = 'latlon'; + + return $this; + } + + /** + * @param float $longitude + * @return Elastica_Filter_GeoDistance current filter + */ + public function setLongitude($longitude) + { + $this->_longitude = (float) $longitude; + $this->_locationType = 'latlon'; + + return $this; + } + + /** + * @param string $geohash + * @return Elastica_Filter_GeoDistance current filter + */ + public function setGeohash($geohash) + { + $this->_geohash = $geohash; + $this->_locationType = 'geohash'; + + return $this; + } + + /** + * @param string $distance + * @return Elastica_Filter_GeoDistance current filter + */ + public function setDistance($distance) + { + $this->setParam('distance', $distance); + + return $this; + } + + /** + * See DISTANCE_TYPE_* constants + * + * @param string $distanceType + * @return Elastica_Filter_GeoDistance current filter + */ + public function setDistanceType($distanceType) + { + $this->setParam('distance_type', $distanceType); + + return $this; + } + + /** + * See OPTIMIZE_BBOX_* constants + * + * @param string $optimizeBbox + * @return Elastica_Filter_GeoDistance current filter + */ + public function setOptimizeBbox($optimizeBbox) + { + $this->setParam('optimize_bbox', $optimizeBbox); + + return $this; + } + + /** + * @see Elastica_Param::toArray() + * @throws Elastica_Exception_Invalid + */ + public function toArray() + { + $data = parent::toArray(); + + // Add location to data array + $filterName = $this->_getBaseName(); + $filterData = $data[$filterName]; + + if ($this->_locationType === 'latlon') { // Latitude/longitude + $location = array(); + + if (isset($this->_latitude)) { // Latitude + $location['lat'] = $this->_latitude; + } else { + throw new Elastica_Exception_Invalid('Latitude has to be set'); + } + + if (isset($this->_longitude)) { // Geohash + $location['lon'] = $this->_longitude; + } else { + throw new Elastica_Exception_Invalid('Longitude has to be set'); + } + } elseif ($this->_locationType === 'geohash') { // Geohash + $location = $this->_geohash; + } else { // Invalid location type + throw new Elastica_Exception_Invalid('Invalid location type'); + } + + $filterData[$this->_key] = $location; + + $data[$filterName] = $filterData; + + return $data; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/GeoPolygon.php b/modules/thirdparty/elastica/lib/Elastica/Filter/GeoPolygon.php new file mode 100755 index 0000000..7a05560 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/GeoPolygon.php @@ -0,0 +1,56 @@ + + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/geo_bounding_box_filter/ + */ +class Elastica_Filter_GeoPolygon extends Elastica_Filter_Abstract +{ + /** + * Key + * + * @var string Key + */ + protected $_key = ''; + + /** + * Points making up polygon + * + * @var array Points making up polygon + */ + protected $_points = array(); + + /** + * Construct polygon filter + * + * @param string $key Key + * @param array $points Points making up polygon + */ + public function __construct($key, array $points) + { + $this->_key = $key; + $this->_points = $points; + } + + /** + * Converts filter to array + * + * @see Elastica_Filter_Abstract::toArray() + * @return array + */ + public function toArray() + { + return array( + 'geo_polygon' => array( + $this->_key => array( + 'points' => $this->_points + ), + ) + ); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/HasChild.php b/modules/thirdparty/elastica/lib/Elastica/Filter/HasChild.php new file mode 100644 index 0000000..5a10e6c --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/HasChild.php @@ -0,0 +1,50 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/has-child-filter.html + */ +class Elastica_Filter_HasChild extends Elastica_Filter_Abstract +{ + /** + * Construct HasChild filter + * + * @param string|Elastica_Query $query Query string or a Elastica_Query object + * @param string $type Parent document type + */ + public function __construct($query, $type = null) + { + $this->setQuery($query); + $this->setType($type); + } + + /** + * Sets query object + * + * @param string|Elastica_Query|Elastica_Query_Abstract $query + * @return Elastica_Filter_HasChild Current object + */ + public function setQuery($query) + { + $query = Elastica_Query::create($query); + $data = $query->toArray(); + + return $this->setParam('query', $data['query']); + } + + /** + * Set type of the parent document + * + * @param string $type Parent document type + * @return Elastica_Filter_HasChild Current object + */ + public function setType($type) + { + return $this->setParam('type', $type); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Ids.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Ids.php new file mode 100644 index 0000000..8cb511e --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Ids.php @@ -0,0 +1,88 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/ids-filter.html + */ +class Elastica_Filter_Ids extends Elastica_Filter_Abstract +{ + /** + * Creates filter object + * + * @param string|Elastica_Type $type Type to filter on + * @param array $ids List of ids + */ + public function __construct($type = null, array $ids = array()) + { + $this->setType($type); + $this->setIds($ids); + } + + /** + * Adds one more filter to the and filter + * + * @param string $id Adds id to filter + * @return Elastica_Filter_Ids Current object + */ + public function addId($id) + { + return $this->addParam('values', $id); + } + + /** + * Adds one more type to query + * + * @param string $type Adds type to query + * @return Elastica_Filter_Ids Current object + */ + public function addType($type) + { + if ($type instanceof Elastica_Type) { + $type = $type->getType(); + } elseif (empty($type) && !is_numeric($type)) { + // TODO: Shouldn't this throw an exception? + // A type can be 0, but cannot be empty + return $this; + } + + return $this->addParam('type', $type); + } + + /** + * Set type + * + * @param string|Elastica_Type $type Type name or object + * @return Elastica_Filter_Ids Current object + */ + public function setType($type) + { + if ($type instanceof Elastica_Type) { + $type = $type->getType(); + } elseif (empty($type) && !is_numeric($type)) { + // TODO: Shouldn't this throw an exception or let handling of invalid params to ES? + // A type can be 0, but cannot be empty + return $this; + } + + return $this->setParam('type', $type); + } + + /** + * Sets the ids to filter + * + * @param array|string $ids List of ids + * @return Elastica_Filter_Ids Current object + */ + public function setIds($ids) + { + if (!is_array($ids)) { + $ids = array($ids); + } + + return $this->setParam('values', $ids); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Limit.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Limit.php new file mode 100644 index 0000000..66c1100 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Limit.php @@ -0,0 +1,34 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/limit-filter.html + */ +class Elastica_Filter_Limit extends Elastica_Filter_Abstract +{ + /** + * Construct limit filter + * + * @param int $limit Limit + * @return Elastica_Filter_Limit + */ + public function __construct($limit) + { + $this->setLimit($limit); + } + + /** + * Set the limit + * + * @param int $limit Limit + * @return Elastica_Filter_Limit + */ + public function setLimit($limit) + { + return $this->setParam('value', (int) $limit); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/MatchAll.php b/modules/thirdparty/elastica/lib/Elastica/Filter/MatchAll.php new file mode 100755 index 0000000..6e3f357 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/MatchAll.php @@ -0,0 +1,19 @@ + + */ +class Elastica_Filter_MatchAll extends Elastica_Filter_Abstract +{ + /** + * Creates match all filter + */ + public function __construct() + { + $this->_params = new stdClass(); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Missing.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Missing.php new file mode 100644 index 0000000..dfc8a11 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Missing.php @@ -0,0 +1,35 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/missing-filter.html + */ +class Elastica_Filter_Missing extends Elastica_Filter_Abstract +{ + /** + * Construct missing filter + * + * @param string $field OPTIONAL + */ + public function __construct($field = '') + { + if (strlen($field)) { + $this->setField($field); + } + } + + /** + * Set field + * + * @param string $field + */ + public function setField($field) + { + return $this->setParam('field', (string) $field); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Nested.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Nested.php new file mode 100644 index 0000000..0ea060f --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Nested.php @@ -0,0 +1,45 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/nested-filter.html + */ +class Elastica_Filter_Nested extends Elastica_Filter_Abstract +{ + /** + * Adds field to mlt filter + * + * @param string $path Nested object path + * @return Elastica_Filter_Nested + */ + public function setPath($path) + { + return $this->setParam('path', $path); + } + + /** + * Sets nested query + * + * @param Elastica_Query_Abstract $query + * @return Elastica_Filter_Nested + */ + public function setQuery(Elastica_Query_Abstract $query) + { + return $this->setParam('query', $query->toArray()); + } + + /** + * Set score mode + * + * @param string $scoreMode Options: avg, total, max and none. + * @return Elastica_Filter_Nested + */ + public function setScoreMode($scoreMode) + { + return $this->setParam('score_mode', $scoreMode); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Not.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Not.php new file mode 100644 index 0000000..edbcb7a --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Not.php @@ -0,0 +1,33 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/not-filter.html + */ +class Elastica_Filter_Not extends Elastica_Filter_Abstract +{ + /** + * Creates Not filter query + * + * @param Elastica_Filter_Abstract $filter Filter object + */ + public function __construct(Elastica_Filter_Abstract $filter) + { + $this->setFilter($filter); + } + + /** + * Set filter + * + * @param Elastica_Filter_Abstract $filter + * @return Elastica_Filter_Not + */ + public function setFilter(Elastica_Filter_Abstract $filter) + { + return $this->setParam('filter', $filter->toArray()); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/NumericRange.php b/modules/thirdparty/elastica/lib/Elastica/Filter/NumericRange.php new file mode 100644 index 0000000..4c024ac --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/NumericRange.php @@ -0,0 +1,13 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/numeric-range-filter.html + */ +class Elastica_Filter_NumericRange extends Elastica_Filter_Range +{ +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Or.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Or.php new file mode 100755 index 0000000..bf4b98b --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Or.php @@ -0,0 +1,13 @@ + + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/or_filter/ + */ +class Elastica_Filter_Or extends Elastica_Filter_Abstract_Multi +{ +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Prefix.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Prefix.php new file mode 100644 index 0000000..9df7260 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Prefix.php @@ -0,0 +1,75 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/prefix-filter.html + */ +class Elastica_Filter_Prefix extends Elastica_Filter_Abstract +{ + /** + * Holds the name of the field for the prefix. + * + * @var string + */ + protected $_field = ''; + + /** + * Holds the prefix string. + * + * @var string + */ + protected $_prefix = ''; + + /** + * Creates prefix filter + * + * @param string $field Field name + * @param string $prefix Prefix string + */ + public function __construct($field = '', $prefix = '') + { + $this->setField($field); + $this->setPrefix($prefix); + } + + /** + * Sets the name of the prefix field. + * + * @param string $field Field name + */ + public function setField($field) + { + $this->_field = $field; + + return $this; + } + + /** + * Sets the prefix string. + * + * @param string $prefix Prefix string + */ + public function setPrefix($prefix) + { + $this->_prefix = $prefix; + + return $this; + } + + /** + * Convers object to an arrray + * + * @see Elastica_Filter_Abstract::toArray() + * @return array data array + */ + public function toArray() + { + $this->setParam($this->_field, $this->_prefix); + + return parent::toArray(); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Query.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Query.php new file mode 100644 index 0000000..a723aa1 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Query.php @@ -0,0 +1,85 @@ + + */ +class Elastica_Filter_Query extends Elastica_Filter_Abstract +{ + /** + * Query + * @var array + */ + protected $_query; + + /** + * Construct query filter + * + * @param array|Elastica_Query_Abstract $query + */ + public function __construct($query = null) + { + if (!is_null($query)) { + $this->setQuery($query); + } + } + + /** + * Set query + * + * @param array|Elastica_Query_Abstract $query + * @return Elastca_Filter_Query Query object + * @throws Elastica_Exception_Invalid Invalid param + */ + public function setQuery($query) + { + if (!$query instanceof Elastica_Query_Abstract && ! is_array($query)) { + throw new Elastica_Exception_Invalid('expected an array or instance of Elastica_Query_Abstract'); + } + + if ($query instanceof Elastica_Query_Abstract) { + $query = $query->toArray(); + } + + $this->_query = $query; + + return $this; + } + + /** + * @see Elastica_Param::_getBaseName() + */ + protected function _getBaseName() + { + if (empty($this->_params)) { + return parent::_getBaseName(); + } else { + return 'fquery'; + } + } + + /** + * @see Elastica_Param::toArray() + */ + public function toArray() + { + $data = parent::toArray(); + + $name = $this->_getBaseName(); + $filterData = $data[$name]; + + if (empty($filterData)) { + $filterData = $this->_query; + } else { + $filterData['query'] = $this->_query; + } + + $data[$name] = $filterData; + + return $data; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Range.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Range.php new file mode 100755 index 0000000..b368b05 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Range.php @@ -0,0 +1,60 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/range-filter.html + */ +class Elastica_Filter_Range extends Elastica_Filter_Abstract +{ + /** + * Fields + * + * @var array Fields + */ + protected $_fields = array(); + + /** + * Construct range filter + * + * @param string $fieldName Field name + * @param array $args Field arguments + * @return Elastica_Filter_Range + */ + public function __construct($fieldName = false, array $args = array()) + { + if ($fieldName) { + $this->addField($fieldName, $args); + } + } + + /** + * Ads a field with arguments to the range query + * + * @param string $fieldName Field name + * @param array $args Field arguments + * @return Elastica_Filter_Range + */ + public function addField($fieldName, array $args) + { + $this->_fields[$fieldName] = $args; + + return $this; + } + + /** + * Convers object to array + * + * @see Elastica_Filter_Abstract::toArray() + * @return array Filter array + */ + public function toArray() + { + $this->setParams($this->_fields); + + return parent::toArray(); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Script.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Script.php new file mode 100644 index 0000000..d16a453 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Script.php @@ -0,0 +1,70 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/script-filter.html + */ +class Elastica_Filter_Script extends Elastica_Filter_Abstract +{ + /** + * Query object + * + * @var array|Elastica_Query_Abstract + */ + protected $_query = null; + + /** + * Construct script filter + * + * @param array|Elastica_Query_Abstract $query OPTIONAL Query object + */ + public function __construct($query = null) + { + if (!is_null($query)) { + $this->setQuery($query); + } + } + + /** + * Sets query object + * + * @param array|Elastica_Query_Abstract $query + * @return Elastica_Filter_Script + * @throws Elastica_Exception_Invalid Invalid argument type + */ + public function setQuery($query) + { + // TODO: check if should be renamed to setScript? + if (!$query instanceof Elastica_Query_Abstract && !is_array($query)) { + throw new Elastica_Exception_Invalid('expected an array or instance of Elastica_Query_Abstract'); + } + + if ($query instanceof Elastica_Query_Abstract) { + $this->_query = $query->toArray(); + } else { + $this->_query = $query; + } + + return $this; + } + + /** + * ToArray + * + * @return array Script filter + * @see Elastica_Filter_Abstract::toArray() + */ + public function toArray() + { + return array( + 'script' => ( + $this->_query + ), + ); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Term.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Term.php new file mode 100755 index 0000000..16adb5b --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Term.php @@ -0,0 +1,45 @@ + + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/term_query/ + */ +class Elastica_Filter_Term extends Elastica_Filter_Abstract +{ + /** + * Construct term filter + * + * @param array $term Term array + */ + public function __construct(array $term = array()) + { + $this->setRawTerm($term); + } + + /** + * Sets/overwrites key and term directly + * + * @param array $term Key value pair + * @return Elastica_Filter_Term Filter object + */ + public function setRawTerm(array $term) + { + return $this->setParams($term); + } + + /** + * Adds a term to the term query + * + * @param string $key Key to query + * @param string|array $value Values(s) for the query. Boost can be set with array + * @return Elastica_Filter_Term Filter object + */ + public function setTerm($key, $value) + { + return $this->setRawTerm(array($key => $value)); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Terms.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Terms.php new file mode 100755 index 0000000..f1a294d --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Terms.php @@ -0,0 +1,87 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/terms-filter.html + */ +class Elastica_Filter_Terms extends Elastica_Filter_Abstract +{ + /** + * Terms + * + * @var array Terms + */ + protected $_terms = array(); + + /** + * Params + * + * @var array Params + */ + protected $_params = array(); + + /** + * Terms key + * + * @var string Terms key + */ + protected $_key = ''; + + /** + * Creates terms filter + * + * @param string $key Terms key + * @param array $terms Terms values + */ + public function __construct($key = '', array $terms = array()) + { + $this->setTerms($key, $terms); + } + + /** + * Sets key and terms for the filter + * + * @param string $key Terms key + * @param array $terms Terms for the query. + */ + public function setTerms($key, array $terms) + { + $this->_key = $key; + $this->_terms = array_values($terms); + + return $this; + } + + /** + * Adds an additional term to the query + * + * @param string $term Filter term + * @return Elastica_Filter_Abstract Filter object + */ + public function addTerm($term) + { + $this->_terms[] = $term; + + return $this; + } + + /** + * Convers object to an arrray + * + * @see Elastica_Filter_Abstract::toArray() + * @return array data array + */ + public function toArray() + { + if (empty($this->_key)) { + throw new Elastica_Exception_Invalid('Terms key has to be set'); + } + $this->_params[$this->_key] = $this->_terms; + + return array('terms' => $this->_params); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Filter/Type.php b/modules/thirdparty/elastica/lib/Elastica/Filter/Type.php new file mode 100755 index 0000000..49fb459 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Filter/Type.php @@ -0,0 +1,58 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/type-filter.html + */ +class Elastica_Filter_Type extends Elastica_Filter_Abstract +{ + /** + * Type + * + * @var Elastica_Type Type object + */ + protected $_type = null; + + /** + * Construct Type Filter + * + * @param string $typeName Type name + * @return Elastica_Filter_Type + */ + public function __construct($typeName = null) + { + if ($typeName) { + $this->setType($typeName); + } + } + + /** + * Ads a field with arguments to the range query + * + * @param string $typeName Type name + * @return Elastica_Filter_Type current object + */ + public function setType($typeName) + { + $this->_type = $typeName; + + return $this; + } + + /** + * Convert object to array + * + * @see Elastica_Filter_Abstract::toArray() + * @return array Filter array + */ + public function toArray() + { + return array( + 'type' => array('value' => $this->_type) + ); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Index.php b/modules/thirdparty/elastica/lib/Elastica/Index.php new file mode 100755 index 0000000..187aa24 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Index.php @@ -0,0 +1,400 @@ + + */ +class Elastica_Index implements Elastica_Searchable +{ + /** + * Index name + * + * @var string Index name + */ + protected $_name = ''; + + /** + * Client object + * + * @var Elastica_Client Client object + */ + protected $_client = null; + + /** + * Creates a new index object + * + * All the communication to and from an index goes of this object + * + * @param Elastica_Client $client Client object + * @param string $name Index name + */ + public function __construct(Elastica_Client $client, $name) + { + $this->_client = $client; + + if (!is_string($name)) { + throw new Elastica_Exception_Invalid('Index name should be of type string'); + } + $this->_name = $name; + } + + /** + * Returns a type object for the current index with the given name + * + * @param string $type Type name + * @return Elastica_Type Type object + */ + public function getType($type) + { + return new Elastica_Type($this, $type); + } + + /** + * Returns the current status of the index + * + * @return Elastica_Index_Status Index status + */ + public function getStatus() + { + return new Elastica_Index_Status($this); + } + + /** + * Return Index Stats + * + * @return ELastica_Index_Stats + */ + public function getStats() + { + return new Elastica_Index_Stats($this); + } + + /** + * Gets all the type mappings for an index. + * + * @return array + */ + public function getMapping() + { + $path = '_mapping'; + + $response = $this->request($path, Elastica_Request::GET); + + return $response->getData(); + } + + /** + * Returns the index settings object + * + * @return Elastica_Index_Settings Settings object + */ + public function getSettings() + { + return new Elastica_Index_Settings($this); + } + + /** + * Uses _bulk to send documents to the server + * + * @param array $docs Array of Elastica_Document + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/bulk/ + */ + public function addDocuments(array $docs) + { + foreach ($docs as $doc) { + $doc->setIndex($this->getName()); + } + + return $this->getClient()->addDocuments($docs); + } + + /** + * Update document, using update script. Requires elasticsearch >= 0.19.0 + * + * @param string $id document id + * @param Elastica_Script $script script to use for update + * @param string $type index type + * @param array $options options for query + * @return Elastica_Response + * @link http://www.elasticsearch.org/guide/reference/api/update.html + * @see Elastica_Client::updateDocument() + */ + public function updateDocument($id, Elastica_Script $script, $type, array $options = array()) + { + return $this->getClient()->updateDocument($id, $script, $this->getName(), $type, $options); + } + + /** + * Deletes the index + * + * @return Elastica_Response Response object + */ + public function delete() + { + $response = $this->request('', Elastica_Request::DELETE); + + return $response; + } + + /** + * Optimizes search index + * + * Detailed arguments can be found here in the link + * + * @param array $args OPTIONAL Additional arguments + * @return array Server response + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/indices/optimize/ + */ + public function optimize($args = array()) + { + // TODO: doesn't seem to work? + $this->request('_optimize', Elastica_Request::POST, $args); + } + + /** + * Refreshs the index + * + * @return Elastica_Response Response object + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/indices/refresh/ + */ + public function refresh() + { + return $this->request('_refresh', Elastica_Request::POST, array()); + } + + /** + * Creates a new index with the given arguments + * + * @param array $args OPTIONAL Arguments to use + * @param bool|array $options OPTIONAL + * bool=> Deletes index first if already exists (default = false). + * array => Associative array of options (option=>value) + * @return array Server response + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/indices/create_index/ + */ + public function create(array $args = array(), $options = null) + { + $path = ''; + $query = array(); + + if (is_bool($options)) { + if ($options) { + try { + $this->delete(); + } catch (Elastica_Exception_Response $e) { + // Table can't be deleted, because doesn't exist + } + } + } else { + if (is_array($options)) { + foreach ($options as $key => $value) { + switch ($key) { + case 'recreate' : + try { + $this->delete(); + } catch (Elastica_Exception_Response $e) { + // Table can't be deleted, because doesn't exist + } + break; + case 'routing' : + $query = array('routing' => $value); + break; + default: + throw new Elastica_Exception_Invalid('Invalid option ' . $key); + break; + } + } + } + } + + return $this->request($path, Elastica_Request::PUT, $args, $query); + } + + /** + * Checks if the given index is already created + * + * @return bool True if index exists + */ + public function exists() + { + $cluster = new Elastica_Cluster($this->getClient()); + + return in_array($this->getName(), $cluster->getIndexNames()); + } + + /** + * Searchs in this index + * + * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object + * @param int|array $options OPTIONAL Limit or associative array of options (option=>value) + * @return Elastica_ResultSet ResultSet with all results inside + * @see Elastica_Searchable::search + */ + public function search($query, $options = null) + { + $search = new Elastica_Search($this->getClient()); + $search->addIndex($this); + + return $search->search($query, $options); + } + + /** + * Counts results of query + * + * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object + * @return int number of documents matching the query + * @see Elastica_Searchable::count + */ + public function count($query = '') + { + $query = Elastica_Query::create($query); + $path = '_search'; + + $response = $this->request($path, Elastica_Request::GET, $query->toArray(), array('search_type' => 'count')); + $resultSet = new Elastica_ResultSet($response); + + return $resultSet->getTotalHits(); + } + + /** + * Opens an index + * + * @return Elastica_Response Response object + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-open-close.html + */ + public function open() + { + $this->request('_open', Elastica_Request::POST); + } + + /** + * Closes the index + * + * @return Elastica_Response Response object + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-open-close.html + */ + public function close() + { + return $this->request('_close', Elastica_Request::POST); + } + + /** + * Returns the index name + * + * @return string Index name + */ + public function getName() + { + return $this->_name; + } + + /** + * Returns index client + * + * @return Elastica_Client Index client object + */ + public function getClient() + { + return $this->_client; + } + + /** + * Adds an alias to the current index + * + * @param string $name Alias name + * @param bool $replace OPTIONAL If set, an existing alias will be replaced + * @return Elastica_Response Response + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases.html + */ + public function addAlias($name, $replace = false) + { + $path = '_aliases'; + + if ($replace) { + $status = new Elastica_Status($this->getClient()); + + foreach ($status->getIndicesWithAlias($name) as $index) { + $index->removeAlias($name); + } + } + + $data = array('actions' => array(array('add' => array('index' => $this->getName(), 'alias' => $name)))); + + return $this->getClient()->request($path, Elastica_Request::POST, $data); + } + + /** + * Removes an alias pointing to the current index + * + * @param string $name Alias name + * @return Elastica_Response Response + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases.html + */ + public function removeAlias($name) + { + $path = '_aliases'; + + $data = array('actions' => array(array('remove' => array('index' => $this->getName(), 'alias' => $name)))); + + return $this->getClient()->request($path, Elastica_Request::POST, $data); + } + + /** + * Clears the cache of an index + * + * @return Elastica_Response Reponse object + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-clearcache.html + */ + public function clearCache() + { + $path = '_cache/clear'; + // TODO: add additional cache clean arguments + return $this->request($path, Elastica_Request::POST); + } + + /** + * Flushs the index to storage + * + * @return Elastica_Response Reponse object + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-flush.html + */ + public function flush() + { + $path = '_flush'; + // TODO: Add option for refresh + return $this->request($path, Elastica_Request::POST); + } + + /** + * Can be used to change settings during runtime. One example is to use + * if for bulk updating {@link http://www.elasticsearch.org/blog/2011/03/23/update-settings.html} + * + * @param array $data Data array + * @return Elastica_Response Response object + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-update-settings.html + */ + public function setSettings(array $data) + { + return $this->request('_settings', Elastica_Request::PUT, $data); + } + + /** + * Makes calls to the elasticsearch server based on this index + * + * @param string $path Path to call + * @param string $method Rest method to use (GET, POST, DELETE, PUT) + * @param array $data OPTIONAL Arguments as array + * @param array $query OPTIONAL Query params + * @return Elastica_Response Response object + */ + public function request($path, $method, $data = array(), array $query = array()) + { + $path = $this->getName() . '/' . $path; + + return $this->getClient()->request($path, $method, $data, $query); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Index/Settings.php b/modules/thirdparty/elastica/lib/Elastica/Index/Settings.php new file mode 100644 index 0000000..d46d103 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Index/Settings.php @@ -0,0 +1,294 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-update-settings.html + * @link http://www.elasticsearch.org/guide/reference/index-modules/merge.html + */ +class Elastica_Index_Settings +{ + /** + * Response + * + * @var Elastica_Response Response object + */ + protected $_response = null; + + /** + * Stats info + * + * @var array Stats info + */ + protected $_data = array(); + + /** + * Index + * + * @var Elastica_Index Index object + */ + protected $_index = null; + + const DEFAULT_REFRESH_INTERVAL = '1s'; + + /** + * Construct + * + * @param Elastica_Index $index Index object + */ + public function __construct(Elastica_Index $index) + { + $this->_index = $index; + } + + /** + * Returns the current settings of the index + * + * If param is set, only specified setting is return. + * 'index.' is added in front of $setting. + * + * @param string $setting OPTIONAL Setting name to return + * @return array|string|null Settings data + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-update-settings.html + */ + public function get($setting = '') + { + $data = $this->request()->getData(); + $settings = $data[$this->_index->getName()]['settings']; + + if (!empty($setting)) { + if (isset($settings['index.' . $setting])) { + return $settings['index.' . $setting]; + } else { + return null; + } + } + + return $settings; + } + + /** + * Sets the number of replicas + * + * @param int $replicas Number of replicas + * @return Elastica_Response Response object + */ + public function setNumberOfReplicas($replicas) + { + $replicas = (int) $replicas; + + $data = array('number_of_replicas' => $replicas); + + return $this->set($data); + } + + /** + * Sets the index to read only + * + * @param bool $readOnly (default = true) + * @return Elastica_Response + */ + public function setReadOnly($readOnly = true) + { + return $this->set(array('blocks.read_only' => $readOnly)); + } + + /** + * @return bool + */ + public function getBlocksRead() + { + return (bool) $this->get('blocks.read'); + } + + /** + * @param bool $state OPTIONAL (default = true) + * @return Elastica_Response + */ + public function setBlocksRead($state = true) + { + $state = $state ? 1 : 0; + + return $this->set(array('blocks.read' => $state)); + } + + /** + * @return bool + */ + public function getBlocksWrite() + { + return (bool) $this->get('blocks.write'); + } + + /** + * @param bool $state OPTIONAL (default = true) + * @return Elastica_Response + */ + public function setBlocksWrite($state = true) + { + $state = $state ? 1 : 0; + + return $this->set(array('blocks.write' => (int) $state)); + } + + /** + * @return bool + */ + public function getBlocksMetadata() + { + return (bool) $this->get('blocks.metadata'); + } + + /** + * @param bool $state OPTIONAL (default = true) + * @return Elastica_Response + */ + public function setBlocksMetadata($state = true) + { + $state = $state ? 1 : 0; + + return $this->set(array('blocks.metadata' => (int) $state)); + } + + /** + * Sets the index refresh interval + * + * Value can be for example 3s for 3 seconds or + * 5m for 5 minutes. -1 refreshing is disabled. + * + * @param int $interval Number of seconds + * @return Elastica_Response Response object + */ + public function setRefreshInterval($interval) + { + return $this->set(array('refresh_interval' => $interval)); + } + + /** + * Returns the refresh interval + * + * If no interval is set, the default interval is returned + * + * @return string Refresh interval + */ + public function getRefreshInterval() + { + $interval = $this->get('refresh_interval'); + + if (empty($interval)) { + $interval = self::DEFAULT_REFRESH_INTERVAL; + } + + return $interval; + } + + /** + * Return merge policy + * + * @return string Merge policy type + */ + public function getMergePolicyType() + { + return $this->get('merge.policy.type'); + } + + /** + * Sets merge policy + * + * @param string $type Merge policy type + * @return Elastica_Response Response object + * @link http://www.elasticsearch.org/guide/reference/index-modules/merge.html + */ + public function setMergePolicyType($type) + { + $this->getIndex()->close(); + $response = $this->set(array('merge.policy.type' => $type)); + $this->getIndex()->open(); + + return $response; + } + + /** + * Sets the specific merge policies + * + * To have this changes made the index has to be closed and reopened + * + * @param string $key Merge policy key (for ex. expunge_deletes_allowed) + * @param string $value + * @return Elastica_Response + * @link http://www.elasticsearch.org/guide/reference/index-modules/merge.html + */ + public function setMergePolicy($key, $value) + { + $this->getIndex()->close(); + $response = $this->set(array('merge.policy.' . $key => $value)); + $this->getIndex()->open(); + + return $response; + } + + /** + * Returns the specific merge policy value + * + * @param string $key Merge policy key (for ex. expunge_deletes_allowed) + * @return string Refresh interval + * @link http://www.elasticsearch.org/guide/reference/index-modules/merge.html + */ + public function getMergePolicy($key) + { + return $this->get('merge.policy.' . $key); + } + + /** + * Can be used to set/update settings + * + * @param array $data Arguments + * @return Elastica_Response Response object + */ + public function set(array $data) + { + return $this->request($data, Elastica_Request::PUT); + } + + /** + * Returns the index object + * + * @return Elastica_Index Index object + */ + public function getIndex() + { + return $this->_index; + } + + /** + * Updates the given settings for the index + * + * With elasticsearch 0.16 the following settings are supported + * - index.term_index_interval + * - index.term_index_divisor + * - index.translog.flush_threshold_ops + * - index.translog.flush_threshold_size + * - index.translog.flush_threshold_period + * - index.refresh_interval + * - index.merge.policy + * - index.auto_expand_replicas + * + * @param array $data OPTIONAL Data array + * @param string $method OPTIONAL Transfer method (default = Elastica_Request::GET) + * @return Elastica_Response Response object + */ + public function request(array $data = array(), $method = Elastica_Request::GET) + { + $path = '_settings'; + + $data = array('index' => $data); + + return $this->getIndex()->request($path, $method, $data); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Index/Stats.php b/modules/thirdparty/elastica/lib/Elastica/Index/Stats.php new file mode 100644 index 0000000..34741be --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Index/Stats.php @@ -0,0 +1,104 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-stats.html + */ +class Elastica_Index_Stats +{ + /** + * Response + * + * @var Elastica_Response Response object + */ + protected $_response = null; + + /** + * Stats info + * + * @var array Stats info + */ + protected $_data = array(); + + /** + * Index + * + * @var Elastica_Index Index object + */ + protected $_index = null; + + /** + * Construct + * + * @param Elastica_Index $index Index object + */ + public function __construct(Elastica_Index $index) + { + $this->_index = $index; + $this->refresh(); + } + + /** + * Returns the raw stats info + * + * @return array Stats info + */ + public function getData() + { + return $this->_data; + } + + /** + * Returns the entry in the data array based on the params. + * Various params possible. + * + * @return mixed Data array entry or null if not found + */ + public function get() + { + $data = $this->getData(); + + foreach (func_get_args() as $arg) { + if (isset($data[$arg])) { + $data = $data[$arg]; + } else { + return null; + } + } + + return $data; + } + + /** + * Returns the index object + * + * @return Elastica_Index Index object + */ + public function getIndex() + { + return $this->_index; + } + + /** + * Returns response object + * + * @return Elastica_Response Response object + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Reloads all status data of this object + */ + public function refresh() + { + $path = '_stats'; + $this->_response = $this->getIndex()->request($path, Elastica_Request::GET); + $this->_data = $this->getResponse()->getData(); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Index/Status.php b/modules/thirdparty/elastica/lib/Elastica/Index/Status.php new file mode 100644 index 0000000..7be19d9 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Index/Status.php @@ -0,0 +1,143 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-status.html + */ +class Elastica_Index_Status +{ + /** + * Response + * + * @var Elastica_Response Response object + */ + protected $_response = null; + + /** + * Stats info + * + * @var array Stats info + */ + protected $_data = array(); + + /** + * Index + * + * @var Elastica_Index Index object + */ + protected $_index = null; + + /** + * Construct + * + * @param Elastica_Index $index Index object + */ + public function __construct(Elastica_Index $index) + { + $this->_index = $index; + $this->refresh(); + } + + /** + * Returns all status info + * + * @return array Status info + */ + public function getData() + { + return $this->_data; + } + + /** + * Returns the entry in the data array based on the params. + * Various params possible. + * + * @return mixed Data array entry or null if not found + */ + public function get() + { + $data = $this->getData(); + $data = $data['indices'][$this->getIndex()->getName()]; + + foreach (func_get_args() as $arg) { + if (isset($data[$arg])) { + $data = $data[$arg]; + } else { + return null; + } + } + + return $data; + } + + /** + * Returns all index aliases + * + * @return array Aliases + */ + public function getAliases() + { + // TODO Update as soon as new API is implmented + $cluster = new Elastica_Cluster($this->_index->getClient()); + $state = $cluster->getState(); + + return $state['metadata']['indices'][$this->_index->getName()]['aliases']; + } + + /** + * Returns all index settings + * + * @return array Index settings + */ + public function getSettings() + { + // TODO Update as soon as new API is implmented + $cluster = new Elastica_Cluster($this->_index->getClient()); + $state = $cluster->getState(); + + return $state['metadata']['indices'][$this->_index->getName()]['settings']; + } + + /** + * Checks if the index has the given alias + * + * @param string $name Alias name + */ + public function hasAlias($name) + { + return in_array($name, $this->getAliases()); + } + + /** + * Returns the index object + * + * @return Elastica_Index Index object + */ + public function getIndex() + { + return $this->_index; + } + + /** + * Returns response object + * + * @return Elastica_Response Response object + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Reloads all status data of this object + */ + public function refresh() + { + $path = '_status'; + $this->_response = $this->getIndex()->request($path, Elastica_Request::GET); + $this->_data = $this->getResponse()->getData(); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Log.php b/modules/thirdparty/elastica/lib/Elastica/Log.php new file mode 100644 index 0000000..10fc99d --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Log.php @@ -0,0 +1,109 @@ + + */ +class Elastica_Log +{ + /** + * Log path or true if enabled + * + * @var string|bool + */ + protected $_log = false; + + /** + * Last logged message + * + * @var string Last logged message + */ + protected $_lastMessage = ''; + + /** + * Inits log object. Checks if logging is enabled for the given client + * + * @param Elastica_Client $client + */ + public function __construct(Elastica_Client $client) + { + $this->setLog($client->getConfig('log')); + } + + /** + * Log a message + * + * @param string|Elastica_Request $message + */ + public function log($message) + { + if (!$this->_log) { + return; + } + + if ($message instanceof Elastica_Request) { + $message = $this->_convertRequest($message); + } + + $this->_lastMessage = $message; + + if (is_string($this->_log)) { + error_log($message . PHP_EOL, 3, $this->_log); + } else { + error_log($message); + } + + } + + /** + * Enable/disable log or set log path + * + * @param bool|string $log Enables log or sets log path + * @return Elastica_Log + */ + public function setLog($log) + { + $this->_log = $log; + + return $this; + } + + /** + * Converts a request to a log message + * + * @param Elastica_Request $request + * @return string Request log message + */ + protected function _convertRequest(Elastica_Request $request) + { + $message = 'curl -X' . strtoupper($request->getMethod()) . ' '; + $message .= '\'http://' . $request->getClient()->getHost() . ':' . $request->getClient()->getPort() . '/'; + $message .= $request->getPath(); + + $query = $request->getQuery(); + if (!empty($query)) { + $message .= '?' . http_build_query($query); + } + + $message .= '\''; + + $data = $request->getData(); + if (!empty($data)) { + $message .= ' -d \'' . json_encode($data) . '\''; + } + + return $message; + } + + /** + * Return last logged message + * + * @return string Last logged message + */ + public function getLastMessage() + { + return $this->_lastMessage; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Node.php b/modules/thirdparty/elastica/lib/Elastica/Node.php new file mode 100644 index 0000000..ff7ef92 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Node.php @@ -0,0 +1,118 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-status.html + */ +class Elastica_Node +{ + /** + * Node name + * + * @var string Node name + */ + protected $_name = ''; + + /** + * Node stats + * + * @var Elastica_Node_Stats Node Stats + */ + protected $_stats = null; + + /** + * Node info + * + * @var Elastica_Node_Info Node info + */ + protected $_info = null; + + /** + * Create a new node object + * + * @param string $name Node name + * @param Elastica_Client $client Node object + */ + public function __construct($name, Elastica_Client $client) + { + $this->_name = $name; + $this->_client = $client; + $this->refresh(); + } + + /** + * Get the name of the node + * + * @return string Node name + */ + public function getName() + { + return $this->_name; + } + + /** + * Returns the current client object + * + * @return Elastica_Client Client + */ + public function getClient() + { + return $this->_client; + } + + /** + * Return stats object of the current node + * + * @return Elastica_Node_Stats Node stats + */ + public function getStats() + { + if (!$this->_stats) { + $this->_stats = new Elastica_Node_Stats($this); + } + + return $this->_stats; + } + + /** + * Return info object of the current node + * + * @return Elastica_Node_Info Node info object + */ + public function getInfo() + { + if (!$this->_info) { + $this->_info = new Elastica_Node_Info($this); + } + + return $this->_info; + } + + /** + * Refreshs all node information + * + * This should be called after upating a node to refresh all information + */ + public function refresh() + { + $this->_stats = null; + $this->_info = null; + } + + /** + * Shuts this node down + * + * @param string $delay OPTIONAL Delay after which node is shut down (defualt = 1s) + * @return Elastica_Response + * @link http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-shutdown.html + */ + public function shutdown($delay = '1s') + { + $path = '_cluster/nodes/' . $this->getName() . '/_shutdown?delay=' . $delay; + + return $this->_client->request($path, Elastica_Request::POST); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Node/Info.php b/modules/thirdparty/elastica/lib/Elastica/Node/Info.php new file mode 100644 index 0000000..734f0a2 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Node/Info.php @@ -0,0 +1,151 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-status.html + */ +class Elastica_Node_Info +{ + /** + * Response + * + * @var Elastica_Response Response object + */ + protected $_response = null; + + /** + * Stats data + * + * @var array stats data + */ + protected $_data = array(); + + /** + * Node + * + * @var Elastica_Node Node object + */ + protected $_node = null; + + /** + * Create new info object for node + * + * @param Elastica_Node $node Node object + * @param array $params List of params to return. Can be: settings, os, process, jvm, thread_pool, network, transport, http + */ + public function __construct(Elastica_Node $node, array $params = array()) + { + $this->_node = $node; + $this->refresh($params); + } + + /** + * Returns the entry in the data array based on the params. + * Several params possible. + * + * Example 1: get('os', 'mem', 'total') returns total memory of the system the + * node is running on + * Example 2: get('os', 'mem') returns an array with all mem infos + * + * @return mixed Data array entry or null if not found + */ + public function get() + { + $data = $this->getData(); + + foreach (func_get_args() as $arg) { + if (isset($data[$arg])) { + $data = $data[$arg]; + } else { + return null; + } + } + + return $data; + } + + /** + * Return port of the node + * + * @return string Returns Node port + */ + public function getPort() + { + // Returns string in format: inet[/192.168.1.115:9201] + $data = $this->get('http_address'); + $data = substr($data, 6, strlen($data) - 7); + $data = explode(':', $data); + + return $data[1]; + } + + /** + * Return IP of the node + * + * @return string Returns Node ip address + */ + public function getIp() + { + // Returns string in format: inet[/192.168.1.115:9201] + $data = $this->get('http_address'); + $data = substr($data, 6, strlen($data) - 7); + $data = explode(':', $data); + + return $data[0]; + } + + /** + * Return all info data + * + * @return array Data array + */ + public function getData() + { + return $this->_data; + } + + /** + * Return node object + * + * @return Elastica_Node Node object + */ + public function getNode() + { + return $this->_node; + } + + /** + * Returns response object + * + * @return Elastica_Response Response object + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Reloads all nodes information. Has to be called if informations changed + * + * @param array $params Params to return (default none). Possible options: settings, os, process, jvm, thread_pool, network, transport, http + * @return Elastica_Response Response object + */ + public function refresh(array $params = array()) + { + $path = '_cluster/nodes/' . $this->getNode()->getName(); + + if (!empty($params)) { + $path .= '?'; + foreach ($params as $param) { + $path .= $param . '=true&'; + } + } + + $this->_response = $this->getNode()->getClient()->request($path, Elastica_Request::GET); + $data = $this->getResponse()->getData(); + $this->_data = reset($data['nodes']); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Node/Stats.php b/modules/thirdparty/elastica/lib/Elastica/Node/Stats.php new file mode 100644 index 0000000..3223642 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Node/Stats.php @@ -0,0 +1,109 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-status.html + */ +class Elastica_Node_Stats +{ + /** + * Response + * + * @var Elastica_Response Response object + */ + protected $_response = null; + + /** + * Stats data + * + * @var array stats data + */ + protected $_data = array(); + + /** + * Node + * + * @var Elastica_Node Node object + */ + protected $_node = null; + + /** + * Create new stats for node + * + * @param Elastica_Node $node Elastica node object + */ + public function __construct(Elastica_Node $node) + { + $this->_node = $node; + $this->refresh(); + } + + /** + * Returns all node stats as array based on the arguments + * + * Several arguments can be use + * get('index', 'test', 'example') + * + * @return array Node stats for the given field or null if not found + */ + public function get() + { + $data = $this->getData(); + + foreach (func_get_args() as $arg) { + if (isset($data[$arg])) { + $data = $data[$arg]; + } else { + return null; + } + } + + return $data; + } + + /** + * Returns all stats data + * + * @return array Data array + */ + public function getData() + { + return $this->_data; + } + + /** + * Returns node object + * + * @return Elastica_Node Node object + */ + public function getNode() + { + return $this->_node; + } + + /** + * Returns response object + * + * @return Elastica_Response Response object + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Reloads all nodes information. Has to be called if informations changed + * + * @return Elastica_Response Response object + */ + public function refresh() + { + $path = '_cluster/nodes/' . $this->getNode()->getName() . '/stats'; + $this->_response = $this->getNode()->getClient()->request($path, Elastica_Request::GET); + $data = $this->getResponse()->getData(); + $this->_data = reset($data['nodes']); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Param.php b/modules/thirdparty/elastica/lib/Elastica/Param.php new file mode 100644 index 0000000..8a6099f --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Param.php @@ -0,0 +1,156 @@ + + */ +class Elastica_Param +{ + /** + * Params + * + * @var array + */ + protected $_params = array(); + + /** + * Raw Params + * + * @var array + */ + protected $_rawParams = array(); + + /** + * Converts the params to an array. A default implementation exist to create + * the an array out of the class name (last part of the class name) + * and the params + * + * @return array Filter array + */ + public function toArray() + { + $data = array($this->_getBaseName() => $this->getParams()); + + if (!empty($this->_rawParams)) { + $data = array_merge($data, $this->_rawParams); + } + + return $data; + } + + /** + * Param's name + * Picks the last part of the class name and makes it snake_case + * You can override this method if you want to change the name + * + * @return string name + */ + protected function _getBaseName() + { + $classNameParts = explode('_', get_class($this)); + $name = Elastica_Util::toSnakeCase(array_pop($classNameParts)); + + return $name; + } + + /** + * Sets params not inside params array + * + * @param string $key + * @param mixed $value + * @return Elastica_Param + */ + protected function _setRawParam($key, $value) + { + $this->_rawParams[$key] = $value; + + return $this; + } + + /** + * Sets (overwrites) the value at the given key + * + * @param string $key Key to set + * @param mixed $value Key Value + */ + public function setParam($key, $value) + { + $this->_params[$key] = $value; + + return $this; + } + + /** + * Sets (overwrites) all params of this object + * + * @param array $params Parameter list + * @return Elastica_Param + */ + public function setParams(array $params) + { + $this->_params = $params; + + return $this; + } + + /** + * Adds a param to the list + * + * This function can be used to add an array of params + * + * @param string $key Param key + * @param mixed $value Value to set + * @return Elastica_Param + */ + public function addParam($key, $value) + { + if (!isset($this->_params[$key])) { + $this->_params[$key] = array(); + } + + $this->_params[$key][] = $value; + + return $this; + } + + /** + * Returns a specific param + * + * @param string $key Key to return + * @return mixed Key value + * @throws Elastica_Exception_Invalid If requested key is not set + */ + public function getParam($key) + { + if (!isset($this->_params[$key])) { + throw new Elastica_Exception_Invalid('Param ' . $key . ' does not exist'); + } + + return $this->_params[$key]; + } + + /** + * Test if a param is set + * + * @param string $key Key to test + * @return boolean True if the param is set, false otherwise + */ + public function hasParam($key) + { + return isset($this->_params[$key]); + } + + /** + * Returns the params array + * + * @return array Params + */ + public function getParams() + { + return $this->_params; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Percolator.php b/modules/thirdparty/elastica/lib/Elastica/Percolator.php new file mode 100644 index 0000000..e0a4420 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Percolator.php @@ -0,0 +1,83 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/percolate.html + */ +class Elastica_Percolator +{ + /** + * Index object + * + * @var Elastica_Index + */ + protected $_index = null; + + /** + * Construct new perlocator + * + * @param Elastica_Index $index + */ + public function __construct(Elastica_Index $index) + { + $this->_index = $index; + } + + /** + * Registers a percolator query + * + * @param string $name Query name + * @param string|Elastica_Query|Elastica_Query_Abstract $query Query to add + * @return Elastica_Response + */ + public function registerQuery($name, $query) + { + $path = '_percolator/' . $this->_index->getName() . '/' . $name; + $query = Elastica_Query::create($query); + + return $this->_index->getClient()->request($path, Elastica_Request::PUT, $query->toArray()); + } + + /** + * Removes a percolator query + * @param string $name query name + * @return Elastica_Response + */ + public function unregisterQuery($name) + { + $path = '_percolator/' . $this->_index->getName() . '/' . $name; + + return $this->_index->getClient()->request($path, Elastica_Request::DELETE); + } + + /** + * Match a document to percolator queries + * + * @param Elastica_Document $doc + * @param string|Elastica_Query|Elastica_Query_Abstract $query Not implemented yet + * @return Elastica_Response + */ + public function matchDoc(Elastica_Document $doc, $query = null) + { + $path = $this->_index->getName() . '/type/_percolate'; + $data = array('doc' => $doc->getData()); + + $response = $this->getIndex()->getClient()->request($path, Elastica_Request::GET, $data); + $data = $response->getData(); + + return $data['matches']; + } + + /** + * Return index object + * + * @return Elastica_Index + */ + public function getIndex() + { + return $this->_index; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query.php b/modules/thirdparty/elastica/lib/Elastica/Query.php new file mode 100755 index 0000000..462b5a2 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query.php @@ -0,0 +1,319 @@ + + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/ + */ +class Elastica_Query extends Elastica_Param +{ + /** + * Params + * + * @var array Params + */ + protected $_params = array(); + + /** + * Creates a query object + * + * @param array|Elastica_Query_Abstract $query OPTIONAL Query object (default = null) + */ + public function __construct($query = null) + { + if (is_array($query)) { + $this->setRawQuery($query); + } elseif ($query instanceof Elastica_Query_Abstract) { + $this->setQuery($query); + } + } + + /** + * Transforms a string or an array to a query object + * + * If query is empty, + * + * @param mixed $query + * @return Elastica_Query + **/ + public static function create($query) + { + switch (true) { + case $query instanceof Elastica_Query: + return $query; + case $query instanceof Elastica_Query_Abstract: + return new self($query); + case $query instanceof Elastica_Filter_Abstract: + $newQuery = new Elastica_Query(); + $newQuery->setFilter($query); + + return $newQuery; + case empty($query): + return new self(new Elastica_Query_MatchAll()); + case is_string($query): + return new self(new Elastica_Query_QueryString($query)); + + } + + // TODO: Implement queries without + throw new Elastica_Exception_NotImplemented(); + } + + /** + * Sets query as raw array. Will overwrite all already set arguments + * + * @param array $query Query array + * @return Elastica_Query Query object + */ + public function setRawQuery(array $query) + { + $this->_params = $query; + + return $this; + } + + /** + * Sets the query + * + * @param Elastica_Query_Abstract $query Query object + * @return Elastica_Query Query object + */ + public function setQuery(Elastica_Query_Abstract $query) + { + return $this->setParam('query', $query->toArray()); + } + + /** + * Gets the query array + * + * @return array + **/ + public function getQuery() + { + return $this->getParam('query'); + } + + /** + * Set Filter + * + * @param Elastica_Filter_Abstract $filter Filter object + * @return Elastica_Query Current object + */ + public function setFilter(Elastica_Filter_Abstract $filter) + { + return $this->setParam('filter', $filter->toArray()); + } + + /** + * Sets the start from which the search results should be returned + * + * @param int $from + * @return Elastica_Query Query object + */ + public function setFrom($from) + { + return $this->setParam('from', $from); + } + + /** + * Sets sort arguments for the query + * Replaces existing values + * + * @param array $sortArgs Sorting arguments + * @return Elastica_Query Query object + * @link http://www.elasticsearch.org/guide/reference/api/search/sort.html + */ + public function setSort(array $sortArgs) + { + return $this->setParam('sort', $sortArgs); + } + + /** + * Adds a sort param to the query + * + * @param mixed $sort Sort parameter + * @return Elastica_Query Query object + * @link http://www.elasticsearch.org/guide/reference/api/search/sort.html + */ + public function addSort($sort) + { + return $this->addParam('sort', $sort); + } + + /** + * Sets highlight arguments for the query + * + * @param array $highlightArgs Set all highlight arguments + * @return Elastica_Query Query object + * @link http://www.elasticsearch.org/guide/reference/api/search/highlighting.html + */ + public function setHighlight(array $highlightArgs) + { + return $this->setParam('highlight', $highlightArgs); + } + + /** + * Adds a highlight argument + * + * @param mixed $highlight Add highlight argument + * @return Elastica_Query Query object + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/highlighting/ + */ + public function addHighlight($highlight) + { + return $this->addParam('highlight', $highlight); + } + + /** + * Alias for setLimit + * + * @param int $limit OPTIONAL Maximal number of results for query (default = 10) + * @return Elastica_Query Query object + */ + public function setSize($limit = 10) + { + return $this->setLimit($limit); + } + + /** + * Sets maximum number of results for this query + * + * Setting the limit to 0, means no limit + * + * @param int $limit OPTIONAL Maximal number of results for query (default = 10) + * @return Elastica_Query Query object + */ + public function setLimit($limit = 10) + { + return $this->setParam('size', $limit); + } + + /** + * Enables explain on the query + * + * @param bool $explain OPTIONAL Enabled or disable explain (default = true) + * @return Elastica_Query Current object + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/explain/ + */ + public function setExplain($explain = true) + { + return $this->setParam('explain', $explain); + } + + /** + * Enables version on the query + * + * @param bool $version OPTIONAL Enabled or disable version (default = true) + * @return Elastica_Query Current object + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/version/ + */ + public function setVersion($version = true) + { + return $this->setParam('version', $version); + } + + /** + * Sets the fields to be returned by the search + * + * @param array $fields Fields to be returne + * @return Elastica_Query Current object + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/fields/ + */ + public function setFields(array $fields) + { + return $this->setParam('fields', $fields); + } + + /** + * Set script fields + * + * @param array|Elastica_ScriptFields $scriptFields Script fields + * @return Elastica_Query Current object + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/script_fields/ + */ + public function setScriptFields($scriptFields) + { + if (is_array($scriptFields)) { + $scriptFields = new Elastica_ScriptFields($scriptFields); + } + + return $this->setParam('script_fields', $scriptFields->toArray()); + } + + /** + * Adds a Script to the query + * + * @param Elastica_Script $script Script object + * @return Elastica_Query Query object + */ + public function addScriptField($name, Elastica_Script $script) + { + $this->_params['script_fields'][$name] = $script->toArray(); + + return $this; + } + + /** + * Sets all facets for this query object. Replaces existing facets + * + * @param array $facets List of facet objects + * @return Elastica_Query Query object + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/facets + */ + public function setFacets(array $facets) + { + $this->_params['facets'] = array(); + foreach ($facets as $facet) { + $this->addFacet($facet); + } + + return $this; + } + + /** + * Adds a Facet to the query + * + * @param Elastica_Facet_Abstract $facet Facet object + * @return Elastica_Query Query object + */ + public function addFacet(Elastica_Facet_Abstract $facet) + { + $this->_params['facets'][$facet->getName()] = $facet->toArray(); + + return $this; + } + + /** + * Converts all query params to an array + * + * @return array Query array + */ + public function toArray() + { + // If no query is set, all query is chosen by default + if (!isset($this->_params['query'])) { + $this->setQuery(new Elastica_Query_MatchAll()); + } + + return $this->_params; + } + + /** + * Allows filtering of documents based on a minimum score + * + * @param int|double $minScore Minimum score to filter documents by + * @return Elastica_Query Query object + */ + public function setMinScore($minScore) + { + if (!is_numeric($minScore)) { + throw new Elastica_Exception_Invalid('has to be numeric param'); + } + + return $this->setParam('min_score', $minScore); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Abstract.php b/modules/thirdparty/elastica/lib/Elastica/Query/Abstract.php new file mode 100755 index 0000000..760f7bf --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/Abstract.php @@ -0,0 +1,11 @@ + + */ +abstract class Elastica_Query_Abstract extends Elastica_Param +{ +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Array.php b/modules/thirdparty/elastica/lib/Elastica/Query/Array.php new file mode 100755 index 0000000..d71d296 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/Array.php @@ -0,0 +1,53 @@ + + */ +class Elastica_Query_Array extends Elastica_Query_Abstract +{ + /** + * Query + * + * @var array Query + */ + protected $_query = array(); + + /** + * Constructs a query based on an array + * + * @param array $query Query array + */ + public function __construct(array $query) + { + $this->setQuery($query); + } + + /** + * Sets new query array + * + * @param array $query Query array + * @return Elastica_Query_Array Current object + */ + public function setQuery(array $query) + { + $this->_query = $query; + + return $this; + } + + /** + * Converts query to array + * + * @return array Query array + * @see Elastica_Query_Abstract::toArray() + */ + public function toArray() + { + return $this->_query; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Bool.php b/modules/thirdparty/elastica/lib/Elastica/Query/Bool.php new file mode 100755 index 0000000..9c7562c --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/Bool.php @@ -0,0 +1,87 @@ + + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/bool_query/ + */ +class Elastica_Query_Bool extends Elastica_Query_Abstract +{ + /** + * Add should part to query + * + * @param Elastica_Query_Abstract|array $args Should query + * @return Elastica_Query_Bool Current object + */ + public function addShould($args) + { + return $this->_addQuery('should', $args); + } + + /** + * Add must part to query + * + * @param Elastica_Query_Abstract|array $args Must query + * @return Elastica_Query_Bool Current object + */ + public function addMust($args) + { + return $this->_addQuery('must', $args); + } + + /** + * Add must not part to query + * + * @param Elastica_Query_Abstract|array $args Must not query + * @return Elastica_Query_Bool Current object + */ + public function addMustNot($args) + { + return $this->_addQuery('must_not', $args); + } + + /** + * Adds a query to the current object + * + * @param string $type Query type + * @param Elastica_Query_Abstract|array $args Query + * @throws Elastica_Exception_Invalid If not valid query + */ + protected function _addQuery($type, $args) + { + if ($args instanceof Elastica_Query_Abstract) { + $args = $args->toArray(); + } + + if (!is_array($args)) { + throw new Elastica_Exception_Invalid('Invalid parameter. Has to be array or instance of Elastica_Query'); + } + + return $this->addParam($type, $args); + } + + /** + * Sets boost value of this query + * + * @param float $boost Boost value + * @return Elastica_Query_Bool Current object + */ + public function setBoost($boost) + { + return $this->setParam('boost', $boost); + } + + /** + * Set the minimum number of of should match + * + * @param int $minimumNumberShouldMatch Should match minimum + * @return Elastica_Query_Bool Current object + */ + public function setMinimumNumberShouldMatch($minimumNumberShouldMatch) + { + return $this->setParam('minimum_number_should_match', $minimumNumberShouldMatch); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Builder.php b/modules/thirdparty/elastica/lib/Elastica/Query/Builder.php new file mode 100644 index 0000000..ddb6957 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/Builder.php @@ -0,0 +1,947 @@ + + * @link http://www.elasticsearch.com/ + **/ +class Elastica_Query_Builder extends Elastica_Query_Abstract +{ + /** + * Query string. + * + * @var string + */ + private $_string = '{'; + + /** + * Factory method. + * + * @param string $string JSON encoded string to use as query. + * + * @return Elastica_Query_Builder + */ + public static function factory($string = null) + { + return new Elastica_Query_Builder($string); + } + + /** + * Constructor + * + * @param string $string JSON encoded string to use as query. + */ + public function __construct($string = null) + { + if (! $string == null) { + $this->_string .= substr($string, 1, -1); + } + } + + /** + * Output the query string. + * + * @return string + */ + public function __toString() + { + return rtrim($this->_string, ',').'}'; + } + + /** + * {@inheritdoc} + */ + public function toArray() + { + $array = json_decode($this->__toString(), true); + + if (is_null($array)) { + throw new Elastica_Exception_Invalid('The query produced is invalid'); + } + + return $array; + } + + /** + * Allow widcards (*, ?) as the first character in a query. + * + * @param boolean $bool Defaults to true. + * + * @return Elastica_Query_Builder + */ + public function allowLeadingWildcard($bool = true) + { + return $this->field('allow_leading_wildcard', (bool) $bool); + } + + /** + * Enable best effort analysis of wildcard terms. + * + * @param boolean $bool Defaults to true. + * + * @return Elastica_Query_Builder + */ + public function analyzeWildcard($bool = true) + { + return $this->field('analyze_wildcard', (bool) $bool); + } + + /** + * Set the analyzer name used to analyze the query string. + * + * @param string $analyzer Analyzer to use. + * + * @return Elastica_Query_Builder + */ + public function analyzer($analyzer) + { + return $this->field('analyzer', $analyzer); + } + + /** + * Auitogenerate phrase queries. + * + * @param boolean $bool Defaults to true. + * + * @return Elastica_Query_Builder + */ + public function autoGeneratePhraseQueries($bool = true) + { + return $this->field('auto_generate_phrase_queries', (bool) $bool); + } + + /** + * Bool Query. + * + * A query that matches documents matching boolean combinations of other queries. + * + * The bool query maps to Lucene BooleanQuery. + * + * It is built using one or more boolean clauses, each clause with a typed + * occurrence. + * + * The occurrence types are: must, should, must_not. + * + * @return Elastica_Query_Builder + */ + public function bool() + { + return $this->fieldOpen('bool'); + } + + /** + * Close a 'bool' block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function boolClose() + { + return $this->fieldClose(); + } + + /** + * Sets the boost value of the query. + * + * @param float $boost Defaults to 1.0. + * + * @return Elastica_Query_Builder + */ + public function boost($boost = 1.0) + { + return $this->field('boost', (float) $boost); + } + + /** + * Close a previously opened brace. + * + * @return Elastica_Query_Builder + */ + public function close() + { + $this->_string = rtrim($this->_string, ' ,').'},'; + + return $this; + } + + /** + * Constant Score Query. + * + * A query that wraps a filter or another query and simply returns a constant + * score equal to the query boost for every document in the filter. + * + * Maps to Lucene ConstantScoreQuery. + * + * @return Elastica_Query_Builder + */ + public function constantScore() + { + return $this->fieldOpen('constant_score'); + } + + /** + * Close a 'constant_score' block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function constantScoreClose() + { + return $this->fieldClose(); + } + + /** + * The default field for query terms if no prefix field is specified. + * + * @param string $field Defaults to _all. + * + * @return Elastica_Query_Builder + */ + public function defaultField($field = '_all') + { + return $this->field('default_field', $field); + } + + /** + * The default operator used if no explicit operator is specified. + * + * For example, with a default operator of OR, the query "capital of Hungary" + * is translated to "capital OR of OR Hungary", and with default operator of + * AND, the same query is translated to "capital AND of AND Hungary". + * + * @param string $operator Defaults to OR. + * + * @return Elastica_Query_Builder + */ + public function defaultOperator($operator = 'OR') + { + return $this->field('default_operator', $operator); + } + + /** + * Dis Max Query. + * + * A query that generates the union of documents produced by its subqueries, + * and that scores each document with the maximum score for that document as + * produced by any subquery, plus a tie breaking increment for any additional + * matching subqueries. + * + * @return Elastica_Query_Builder + */ + public function disMax() + { + return $this->fieldOpen('dis_max'); + } + + /** + * Close a 'dis_max' block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function disMaxClose() + { + return $this->fieldClose(); + } + + /** + * Enable position increments in result queries. + * + * @param boolean $bool Defaults to true. + * + * @return Elastica_Query_Builder + */ + public function enablePositionIncrements($bool = true) + { + return $this->field('enable_position_increments', (bool) $bool); + } + + /** + * Enables explanation for each hit on how its score was computed. + * + * @param boolean $value Turn on / off explain. + * + * @return Elastica_Query_Builder + */ + public function explain($value = true) + { + return $this->field('explain', $value); + } + + /** + * Open 'facets' block. + * + * Facets provide aggregated data based on a search query. + * + * In the simple case, a facet can return facet counts for various facet + * values for a specific field. + * + * ElasticSearch supports more advanced facet implementations, such as + * statistical or date histogram facets. + * + * @return Elastica_Query_Builder + */ + public function facets() + { + return $this->fieldOpen('facets'); + } + + /** + * Close a facets block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function facetsClose() + { + return $this->close(); + } + + /** + * Add a specific field / value entry. + * + * @param string $name Field to add. + * @param mixed $value Value to set. + * + * @return Elastica_Query_Builder + */ + public function field($name, $value) + { + if (is_bool($value)) { + $value = '"'. var_export($value, true) . '"'; + } elseif (is_array($value)) { + $value = '["'.implode('","', $value).'"]'; + } else { + $value = '"'.$value.'"'; + } + + $this->_string .= '"'.$name.'":'.$value.','; + + return $this; + } + + /** + * Close a field block. + * + * Alias of close() for ease of reading in source. + * Passed parameters will be ignored, however they can be useful in source for + * seeing which field is being closed. + * + * Elastica_Query_Builder::factory() + * ->query() + * ->range() + * ->fieldOpen('created') + * ->gte('2011-07-18 00:00:00') + * ->lt('2011-07-19 00:00:00') + * ->fieldClose('created') + * ->rangeClose() + * ->queryClose(); + * + * @return Elastica_Query_Builder + */ + public function fieldClose() + { + return $this->close(); + } + + /** + * Open a node for the specified name. + * + * @param string $name Field name. + * + * @return Elastica_Query_Builder + */ + public function fieldOpen($name) + { + $this->_string .= '"'.$name.'":'; + $this->open(); + + return $this; + } + + /** + * Explicitly define fields to return. + * + * @param array $fields Array of fields to return. + * + * @return Elastica_Query_Builder + */ + public function fields(array $fields) + { + $this->_string .= '"fields":['; + + foreach ($fields as $field) { + $this->_string .= '"'.$field.'",'; + } + + $this->_string = rtrim($this->_string, ',').'],'; + + return $this; + } + + /** + * Open a 'filter' block. + * + * @return Elastica_Query_Builder + */ + public function filter() + { + return $this->fieldOpen('filter'); + } + + /** + * Close a filter block. + * + * @return Elastica_Query_Builder + */ + public function filterClose() + { + return $this->close(); + } + + /** + * Query. + * + * @return Elastica_Query_Builder + */ + public function filteredQuery() + { + return $this->fieldOpen('filtered'); + } + + /** + * Close a 'filtered_query' block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function filteredQueryClose() + { + return $this->fieldClose(); + } + + /** + * Set the from parameter (offset). + * + * @param integer $value Result number to start from. + * + * @return Elastica_Query_Builder + */ + public function from($value = 0) + { + return $this->field('from', $value); + } + + /** + * Set the minimum similarity for fuzzy queries. + * + * @param float $value Defaults to 0.5. + * + * @return Elastica_Query_Builder + */ + public function fuzzyMinSim($value = 0.5) + { + return $this->field('fuzzy_min_sim', (float) $value); + } + + /** + * Set the prefix length for fuzzy queries. + * + * @param integer $value Defaults to 0. + * + * @return Elastica_Query_Builder + */ + public function fuzzyPrefixLength($value = 0) + { + return $this->field('fuzzy_prefix_length', (int) $value); + } + + /** + * Add a greater than (gt) clause. + * + * Used in range blocks. + * + * @param mixed $value Value to be gt. + * + * @return Elastica_Query_Builder + */ + public function gt($value) + { + return $this->field('gt', $value); + } + + /** + * Add a greater than or equal to (lt) clause. + * + * Used in range blocks. + * + * @param mixed $value Value to be gte to. + * + * @return Elastica_Query_Builder + */ + public function gte($value) + { + return $this->field('gte', $value); + } + + /** + * Automatically lower-case terms of wildcard, prefix, fuzzy, and range queries. + * + * @param boolean $bool Defaults to true. + * + * @return Elastica_Query_Builder + */ + public function lowercaseExpandedTerms($bool = true) + { + return $this->field('lowercase_expanded_terms', (bool) $bool); + } + + /** + * Add a less than (lt) clause. + * + * Used in range blocks. + * + * @param mixed $value Value to be lt. + * + * @return Elastica_Query_Builder + */ + public function lt($value) + { + return $this->field('lt', $value); + } + + /** + * Add a less than or equal to (lte) clause. + * + * Used in range blocks. + * + * @param mixed $value Value to be lte to. + * + * @return Elastica_Query_Builder + */ + public function lte($value) + { + return $this->field('lte', $value); + } + + /** + * Match All Query. + * + * A query that matches all documents. + * + * Maps to Lucene MatchAllDocsQuery. + * + * @param float $boost Boost to use. + * + * @return Elastica_Query_Builder + */ + public function matchAll($boost = null) + { + $this->fieldOpen('match_all'); + + if ( ! $boost == null && is_numeric($boost)) { + $this->field('boost', (float) $boost); + } + + return $this->close(); + } + + /** + * The minimum number of should clauses to match. + * + * @param integer $minimum Minimum number that should match. + * + * @return Elastica_Query_Builder + */ + public function minimumNumberShouldMatch($minimum) + { + return $this->field('minimum_number_should_match', (int) $minimum); + } + + /** + * @see minimumNumberShouldMatch() + * @deprecated + */ + public function minimumShouldMatch($minimum) + { + return $this->minimumNumberShouldMatch($minimum); + } + + /** + * The clause (query) must appear in matching documents. + * + * @return Elastica_Query_Builder + */ + public function must() + { + return $this->fieldOpen('must'); + } + + /** + * Close a 'must' block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function mustClose() + { + return $this->fieldClose(); + } + + /** + * The clause (query) must not appear in the matching documents. + * + * Note that it is not possible to search on documents that only consists of + * a must_not clauses. + * + * @return Elastica_Query_Builder + */ + public function mustNot() + { + return $this->fieldOpen('must_not'); + } + + /** + * Close a 'must_not' block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function mustNotClose() + { + return $this->fieldClose(); + } + + /** + * Add an opening brace. + * + * @return Elastica_Query_Builder + */ + public function open() + { + $this->_string .= '{'; + + return $this; + } + + /** + * Sets the default slop for phrases. + * + * If zero, then exact phrase matches are required. + * + * @param integer $value Defaults to 0. + * + * @return Elastica_Query_Builder + */ + public function phraseSlop($value = 0) + { + return $this->field('phrase_slop', (int) $value); + } + + /** + * Query. + * + * @return Elastica_Query_Builder + */ + public function prefix() + { + return $this->fieldOpen('prefix'); + } + + /** + * Close a 'prefix' block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function prefixClose() + { + return $this->fieldClose(); + } + + /** + * Queries to run within a dis_max query. + * + * @param array $queries Array of queries. + * + * @return Elastica_Query_Builder + */ + public function queries(array $queries) + { + $this->_string .= '"queries":['; + + foreach ($queries as $query) { + $this->_string .= $query.','; + } + + $this->_string = rtrim($this->_string, ' ,').'],'; + + return $this; + } + + /** + * Open a query block. + * + * @return Elastica_Query_Builder + */ + public function query() + { + return $this->fieldOpen('query'); + } + + /** + * Close a query block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function queryClose() + { + return $this->close(); + } + + /** + * Query String Query. + * + * A query that uses a query parser in order to parse its content + * + * @return Elastica_Query_Builder + */ + public function queryString() + { + return $this->fieldOpen('query_string'); + } + + /** + * Close a 'query_string' block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function queryStringClose() + { + return $this->fieldClose(); + } + + /** + * Open a range block. + * + * @return Elastica_Query_Builder + */ + public function range() + { + return $this->fieldOpen('range'); + } + + /** + * Close a range block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function rangeClose() + { + return $this->close(); + } + + /** + * The clause (query) should appear in the matching document. + * + * A boolean query with no must clauses, one or more should clauses must + * match a document. + * + * @return Elastica_Query_Builder + */ + public function should() + { + return $this->fieldOpen('should'); + } + + /** + * Close a 'should' block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function shouldClose() + { + return $this->fieldClose(); + } + + /** + * Set the size parameter (number of records to return). + * + * @param integer $value Number of records to return. + * + * @return Elastica_Query_Builder + */ + public function size($value = 10) + { + return $this->field('size', $value); + } + + /** + * Allows to add one or more sort on specific fields. + * + * @return Elastica_Query_Builder + */ + public function sort() + { + return $this->fieldOpen('sort'); + } + + /** + * Close a sort block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function sortClose() + { + return $this->close(); + } + + /** + * Add a field to sort on. + * + * @param string $name Field to sort. + * @param boolean $reverse Reverse direction. + * + * @return Elastica_Query_Builder + */ + public function sortField($name, $reverse = false) + { + return $this + ->fieldOpen('sort') + ->fieldOpen($name) + ->field('reverse', $reverse) + ->close() + ->close(); + } + + /** + * Sort on multiple fields + * + * @param array $fields Associative array where the keys are field names to sort on, and the + * values are the sort order: "asc" or "desc" + * + * @return Elastica_Query_Builder + */ + public function sortFields(array $fields) + { + $this->_string .= '"sort":['; + + foreach ($fields as $fieldName => $order) { + $this->_string .= '{"'.$fieldName.'":"'.$order.'"},'; + } + + $this->_string = rtrim($this->_string, ',') . '],'; + + return $this; + } + + /** + * Term Query. + * + * Matches documents that have fields that contain a term (not analyzed). + * + * The term query maps to Lucene TermQuery. + * + * @return Elastica_Query_Builder + */ + public function term() + { + return $this->fieldOpen('term'); + } + + /** + * Close a 'term' block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function termClose() + { + return $this->fieldClose(); + } + + /** + * Open a 'text_phrase' block. + * + * @return Elastica_Query_Builder + */ + public function textPhrase() + { + return $this->fieldOpen('text_phrase'); + } + + /** + * Close a 'text_phrase' block. + * + * @return Elastica_Query_Builder + */ + public function textPhraseClose() + { + return $this->close(); + } + + /** + * When using dis_max, the disjunction max tie breaker. + * + * @param float $multiplier Multiplier to use. + * + * @return Elastica_Query_Builder + */ + public function tieBreakerMultiplier($multiplier) + { + return $this->field('tie_breaker_multiplier', (float) $multiplier); + } + + /** + * @see tieBreakerMultiplier + * @deprecated + */ + public function tieBreaker($multiplier) + { + return $this->tieBreakerMultiplier($multiplier); + } + + /** + * Query. + * + * @return Elastica_Query_Builder + */ + public function wildcard() + { + return $this->fieldOpen('wildcard'); + } + + /** + * Close a 'wildcard' block. + * + * Alias of close() for ease of reading in source. + * + * @return Elastica_Query_Builder + */ + public function wildcardClose() + { + return $this->fieldClose(); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/ConstantScore.php b/modules/thirdparty/elastica/lib/Elastica/Query/ConstantScore.php new file mode 100644 index 0000000..b819006 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/ConstantScore.php @@ -0,0 +1,51 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/constant-score-query.html + */ +class Elastica_Query_ConstantScore extends Elastica_Query_Abstract +{ + /** + * Construct constant score query + * + * @param null|Elastica_Filter_Abstract|array $filter + */ + public function __construct($filter = null) + { + if (!is_null($filter)) { + $this->setFilter($filter); + } + } + + /** + * Set filter + * + * @param array|Elastica_Filter_Abstract $filter + * @return Elastica_Query_ConstantScore Query object + */ + public function setFilter($filter) + { + if ($filter instanceof Elastica_Filter_Abstract) { + $filter = $filter->toArray(); + } + + return $this->setParam('filter', $filter); + } + + /** + * Set boost + * + * @param float $boost + * @return Elastica_Query_ConstantScore + */ + public function setBoost($boost) + { + return $this->setParam('boost', $boost); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/CustomFiltersScore.php b/modules/thirdparty/elastica/lib/Elastica/Query/CustomFiltersScore.php new file mode 100644 index 0000000..267035d --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/CustomFiltersScore.php @@ -0,0 +1,55 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/custom-filters-score-query.html + */ +class Elastica_Query_CustomFiltersScore extends Elastica_Query_Abstract +{ + /** + * Sets a query + * + * @param Elastica_Query_Abstract $query Query object + * @return Elastica_Query_CustomFiltersScore Current object + */ + public function setQuery(Elastica_Query_Abstract $query) + { + $this->setParam('query', $query->toArray()); + + return $this; + } + + /** + * Add a filter with boost + * + * @param Elastica_Filter_Abstract $filter Filter object + * @param float $boost Boost for the filter + * @return Elastica_Query_CustomFiltersScore Current object + */ + public function addFilter(Elastica_Filter_Abstract $filter, $boost) + { + $filterParam = array('filter' => $filter->toArray(), 'boost' => $boost); + $this->addParam('filters', $filterParam); + + return $this; + } + + /** + * Add a filter with a script to calculate the score + * + * @param Elastica_Filter_Abstract $filter Filter object + * @param Elastica_Script $script Script for calculating the score + * @return Elastica_Query_CustomFiltersScore Current object + */ + public function addFilterScript(Elastica_Filter_Abstract $filter, Elastica_Script $script) + { + $filterParam = array('filter' => $filter->toArray(), 'script' => $script->getScript()); + $this->addParam('filters', $filterParam); + + return $this; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/CustomScore.php b/modules/thirdparty/elastica/lib/Elastica/Query/CustomScore.php new file mode 100644 index 0000000..e05a7ea --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/CustomScore.php @@ -0,0 +1,51 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/custom-score-query.html + */ +class Elastica_Query_CustomScore extends Elastica_Query_Abstract +{ + /** + * Sets query object + * + * @param string|Elastica_Query|Elastica_Query_Abstract $query + * @return Elastica_Query_CustomScore + */ + public function setQuery($query) + { + $query = Elastica_Query::create($query); + $data = $query->toArray(); + + return $this->setParam('query', $data['query']); + } + + /** + * Set script + * + * @param string $script + * @return Elastica_Query_CustomScore + */ + public function setScript($script) + { + return $this->setParam('script', $script); + } + + /** + * Add params + * + * @param array $params + * @return Elastica_Query_CustomScore + */ + public function addParams(array $params) + { + $this->setParam('params', $params); + + return $this; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Field.php b/modules/thirdparty/elastica/lib/Elastica/Query/Field.php new file mode 100755 index 0000000..818b931 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/Field.php @@ -0,0 +1,81 @@ + + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/field_query/ + */ +class Elastica_Query_Field extends Elastica_Query_Abstract +{ + /** + * Field for object + * + * @var string Field for object + */ + protected $_field = ''; + + /** + * Query string + * + * @var string Query string + */ + protected $_queryString = ''; + + /** + * Creates field query object. Calls setField and setQuery with argument + * + * @param string $field OPTIONAL field for object + * @param string $queryString OPTIONAL Query string for object + */ + public function __construct($field = '', $queryString = '') + { + $this->setField($field); + $this->setQueryString($queryString); + } + + /** + * Sets the field + * + * @param string $field Field + * @return Elastica_Query_Field Current object + */ + public function setField($field) + { + $this->_field = $field; + + return $this; + } + + /** + * Sets a new query string for the object + * + * @param string $queryString Query string + * @return Elastica_Query_Field Current object + */ + public function setQueryString($queryString) + { + if (!is_string($queryString)) { + throw new Elastica_Exception_Invalid('Parameter has to be a string'); + } + + $this->_queryString = $queryString; + + return $this; + } + + /** + * Converts query to array + * + * @return array Query array + * @see Elastica_Query_Abstract::toArray() + */ + public function toArray() + { + $this->setParam($this->_field, array('query' => $this->_queryString)); + + return parent::toArray(); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Filtered.php b/modules/thirdparty/elastica/lib/Elastica/Query/Filtered.php new file mode 100644 index 0000000..3d8a15b --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/Filtered.php @@ -0,0 +1,78 @@ + + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/fuzzy_query/ + */ +class Elastica_Query_Filtered extends Elastica_Query_Abstract +{ + /** + * Query + * + * @var Elastica_Query_Abstract Query object + */ + protected $_query = null; + + /** + * Filter + * + * @var Elastica_Filter_Abstract Filter object + */ + protected $_filter = null; + + /** + * Constructs a filtered query + * + * @param Elastica_Query_Abstract $query Query object + * @param Elastica_Filter_Abstract $filter Filter object + */ + public function __construct(Elastica_Query_Abstract $query, Elastica_Filter_Abstract $filter) + { + $this->setQuery($query); + $this->setFilter($filter); + } + + /** + * Sets a query + * + * @param Elastica_Query_Abstract $query Query object + * @return Elastica_Query_Filtered Current object + */ + public function setQuery(Elastica_Query_Abstract $query) + { + $this->_query = $query; + + return $this; + } + + /** + * Sets the filter + * + * @param Elastica_Filter_Abstract $filter Filter object + * @return Elastica_Query_Filtered Current object + */ + public function setFilter(Elastica_Filter_Abstract $filter) + { + $this->_filter = $filter; + + return $this; + } + + /** + * Converts query to array + * + * @return array Query array + * @see Elastica_Query_Abstract::toArray() + */ + public function toArray() + { + return array('filtered' => array( + 'query' => $this->_query->toArray(), + 'filter' => $this->_filter->toArray() + )); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Fuzzy.php b/modules/thirdparty/elastica/lib/Elastica/Query/Fuzzy.php new file mode 100755 index 0000000..a751e0e --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/Fuzzy.php @@ -0,0 +1,24 @@ + + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/fuzzy_query/ + */ +class Elastica_Query_Fuzzy extends Elastica_Query_Abstract +{ + /** + * Adds field to fuzzy query + * + * @param string $fieldName Field name + * @param array $args Data array + * @return Elastica_Query_Fuzzy Current object + */ + public function addField($fieldName, array $args) + { + return $this->setParam($fieldName, $args); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/FuzzyLikeThis.php b/modules/thirdparty/elastica/lib/Elastica/Query/FuzzyLikeThis.php new file mode 100644 index 0000000..99fe1ae --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/FuzzyLikeThis.php @@ -0,0 +1,162 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/flt-query.html + */ +class Elastica_Query_FuzzyLikeThis extends Elastica_Query_Abstract +{ + /** + * Field names + * + * @var array Field names + */ + protected $_fields = array(); + + /** + * Like text + * + * @var string Like text + */ + protected $_likeText = ''; + + /** + * Max query terms value + * + * @var int Max query terms value + */ + protected $_maxQueryTerms = 25; + + /** + * minimum similarity + * + * @var int minimum similarity + */ + protected $_minSimilarity = 0.5; + + /** + * Prefix Length + * + * @var int Prefix Length + */ + protected $_prefixLength = 0; + + /** + * Boost + * + * @var float Boost + */ + protected $_boost = 1.0; + + /** + * Adds field to flt query + * + * @param array $fields Field names + * @return Elastica_Query_FuzzyLikeThis Current object + */ + public function addFields(array $fields) + { + $this->_fields = $fields; + + return $this; + } + + /** + * Set the "like_text" value + * + * @param string $text + * @return Elastica_Query_FuzzyLikeThis This current object + */ + public function setLikeText($text) + { + $text = trim($text); + $this->_likeText = $text; + + return $this; + } + + /** + * Set the minimum similarity + * + * @param int $value + * @return Elastica_Query_FuzzyLikeThis This current object + */ + public function setMinSimilarity($value) + { + $value = (float) $value; + $this->_minSimilarity = $value; + + return $this; + } + + /** + * Set boost + * + * @param float $value Boost value + * @return Elastica_Query_FuzzyLikeThis Query object + */ + public function setBoost($value) + { + $this->_boost = (float) $value; + + return $this; + } + + /** + * Set Prefix Length + * + * @param int $value Prefix length + * @return Elastica_Query_FuzzyLikeThis + */ + public function setPrefixLength($value) + { + $this->_prefixLength = (int) $value; + + return $this; + } + + /** + * Set max_query_terms + * + * @param int $value Max query terms value + * @return Elastica_Query_FuzzyLikeThis + */ + public function setMaxQueryTerms($value) + { + $this->_maxQueryTerms = (int) $value; + + return $this; + } + + /** + * Converts fuzzy like this query to array + * + * @return array Query array + * @see Elastica_Query_Abstract::toArray() + */ + public function toArray() + { + if (!empty($this->_fields)) { + $args['fields'] = $this->_fields; + } + + if (!empty($this->_boost)) { + $args['boost'] = $this->_boost; + } + + if (!empty($this->_likeText)) { + $args['like_text'] = $this->_likeText; + } + + $args['min_similarity'] = ($this->_minSimilarity > 0) ? $this->_minSimilarity : 0; + + $args['prefix_length'] = $this->_prefixLength; + $args['max_query_terms'] = $this->_maxQueryTerms; + + return array('fuzzy_like_this' => $args); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/HasChild.php b/modules/thirdparty/elastica/lib/Elastica/Query/HasChild.php new file mode 100644 index 0000000..6bd625f --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/HasChild.php @@ -0,0 +1,50 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/has-child-query.html + */ +class Elastica_Query_HasChild extends Elastica_Query_Abstract +{ + /** + * Construct HasChild Query + * + * @param string|Elastica_Query $query Query string or a Elastica_Query object + * @param string $type Parent document type + */ + public function __construct($query, $type = null) + { + $this->setQuery($query); + $this->setType($type); + } + + /** + * Sets query object + * + * @param string|Elastica_Query|Elastica_Query_Abstract $query + * @return Elastica_Query_HasChild + */ + public function setQuery($query) + { + $query = Elastica_Query::create($query); + $data = $query->toArray(); + + return $this->setParam('query', $data['query']); + } + + /** + * Set type of the parent document + * + * @param string $type Parent document type + * @return Elastica_Query_HasChild Current object + */ + public function setType($type) + { + return $this->setParam('type', $type); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Ids.php b/modules/thirdparty/elastica/lib/Elastica/Query/Ids.php new file mode 100644 index 0000000..d6186f8 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/Ids.php @@ -0,0 +1,114 @@ + + * @author Tim Rupp + * @link http://www.elasticsearch.org/guide/reference/query-dsl/ids-query.html + */ +class Elastica_Query_Ids extends Elastica_Query_Abstract +{ + /** + * Params + * + * @var array Params + */ + protected $_params = array(); + + /** + * Creates filter object + * + * @param string|Elastica_Type $type Type to filter on + * @param array $ids List of ids + */ + public function __construct($type = null, array $ids = array()) + { + $this->setType($type); + $this->setIds($ids); + } + + /** + * Adds one more filter to the and filter + * + * @param string $id Adds id to filter + * @return Elastica_Query_Ids Current object + */ + public function addId($id) + { + $this->_params['values'][] = $id; + + return $this; + } + + /** + * Adds one more type to query + * + * @param string $type Adds type to query + * @return Elastica_Query_Ids Current object + */ + public function addType($type) + { + if ($type instanceof Elastica_Type) { + $type = $type->getType(); + } elseif (empty($type) && !is_numeric($type)) { + // A type can be 0, but cannot be empty + return $this; + } + + $this->_params['type'][] = $type; + + return $this; + } + + /** + * Set type + * + * @param string|Elastica_Type $type Type name or object + * @return Elastica_Query_Ids Current object + */ + public function setType($type) + { + if ($type instanceof Elastica_Type) { + $type = $type->getType(); + } elseif (empty($type) && !is_numeric($type)) { + // A type can be 0, but cannot be empty + return $this; + } + + $this->_params['type'] = $type; + + return $this; + } + + /** + * Sets the ids to filter + * + * @param array|string $ids List of ids + * @return Elastica_Query_Ids Current object + */ + public function setIds($ids) + { + if (is_array($ids)) { + $this->_params['values'] = $ids; + } else { + $this->_params['values'] = array($ids); + } + + return $this; + } + + /** + * Converts filter to array + * + * @see Elastica_Query_Abstract::toArray() + * @return array Query array + */ + public function toArray() + { + return array('ids' => $this->_params); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/MatchAll.php b/modules/thirdparty/elastica/lib/Elastica/Query/MatchAll.php new file mode 100755 index 0000000..ee88468 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/MatchAll.php @@ -0,0 +1,19 @@ + + */ +class Elastica_Query_MatchAll extends Elastica_Query_Abstract +{ + /** + * Creates match all query + */ + public function __construct() + { + $this->_params = new stdClass(); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/MoreLikeThis.php b/modules/thirdparty/elastica/lib/Elastica/Query/MoreLikeThis.php new file mode 100644 index 0000000..19d289c --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/MoreLikeThis.php @@ -0,0 +1,160 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/mlt-query.html + */ +class Elastica_Query_MoreLikeThis extends Elastica_Query_Abstract +{ + /** + * Adds field to mlt query + * + * @param array $fields Field names + * @return Elastica_Query_MoreLikeThis Current object + */ + public function setFields(array $fields) + { + return $this->setParam('fields', $fields); + } + + /** + * Set the "like_text" value + * + * @param string $likeText + * @return Elastica_Query_MoreLikeThis This current object + */ + public function setLikeText($likeText) + { + $likeText = trim($likeText); + + return $this->setParam('like_text', $likeText); + } + + /** + * Set boost + * + * @param float $boost Boost value + * @return Elastica_Query_MoreLikeThis Query object + */ + public function setBoost($boost) + { + return $this->setParam('boost', (float) $boost); + } + + /** + * Set max_query_terms + * + * @param int $maxQueryTerms Max query terms value + * @return Elastica_Query_MoreLikeThis + */ + public function setMaxQueryTerms($maxQueryTerms) + { + return $this->setParam('max_query_terms', (int) $maxQueryTerms); + } + + /** + * Set percent terms to match + * + * @param float $percentTermsToMatch Percentage + * @return Elastica_Query_MoreLikeThis + */ + public function setPercentTermsToMatch($percentTermsToMatch) + { + return $this->setParam('percent_terms_to_match', (float) $percentTermsToMatch); + } + + /** + * Set min term frequency + * + * @param int $minTermFreq + * @return Elastica_Query_MoreLikeThis + */ + public function setMinTermFrequency($minTermFreq) + { + return $this->setParam('min_term_freq', (int) $minTermFreq); + } + + /** + * set min document frequency + * + * @param int $minDocFreq + * @return Elastica_Query_MoreLikeThis + */ + public function setMinDocFrequency($minDocFreq) + { + return $this->setParam('min_doc_freq', (int) $minDocFreq); + } + + /** + * set max document frequency + * + * @param int $maxDocFreq + * @return Elastica_Query_MoreLikeThis + */ + public function setMaxDocFrequency($maxDocFreq) + { + return $this->setParam('max_doc_freq', (int) $maxDocFreq); + } + + /** + * Set min word length + * + * @param int $minWordLength + * @return Elastica_Query_MoreLikeThis + */ + public function setMinWordLength($minWordLength) + { + return $this->setParam('min_word_length', (int) $minWordLength); + } + + /** + * Set max word length + * + * @param int $maxWordLength + * @return Elastica_Query_MoreLikeThis + */ + public function setMaxWordLength($maxWordLength) + { + return $this->setParam('max_word_length', (int) $maxWordLength); + } + + /** + * Set boost terms + * + * @param bool $boostTerms + * @return Elastica_Query_MoreLikeThis + * @link http://www.elasticsearch.org/guide/reference/query-dsl/mlt-query.html + */ + public function setBoostTerms($boostTerms) + { + return $this->setParam('boost_terms', (bool) $boostTerms); + } + + /** + * Set analyzer + * + * @param string $analyzer + * @return Elastica_Query_MoreLikeThis + */ + public function setAnalyzer($analyzer) + { + $analyzer = trim($analyzer); + + return $this->setParam('analyzer', $analyzer); + } + + /** + * Set stopwords + * + * @param array $stopWords + * @return Elastica_Query_MoreLikeThis + */ + public function setStopWords(array $stopWords) + { + return $this->setParam('stop_words', $stopWords); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Nested.php b/modules/thirdparty/elastica/lib/Elastica/Query/Nested.php new file mode 100644 index 0000000..9f517a3 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/Nested.php @@ -0,0 +1,45 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/nested-query.html + */ +class Elastica_Query_Nested extends Elastica_Query_Abstract +{ + /** + * Adds field to mlt query + * + * @param string $path Nested object path + * @return Elastica_Query_Nested + */ + public function setPath($path) + { + return $this->setParam('path', $path); + } + + /** + * Sets nested query + * + * @param Elastica_Query_Abstract $query + * @return Elastica_Query_Nested + */ + public function setQuery(Elastica_Query_Abstract $query) + { + return $this->setParam('query', $query->toArray()); + } + + /** + * Set score method + * + * @param string $scoreMode Options: avg, total, max and none. + * @return Elastica_Query_Nested + */ + public function setScoreMode($scoreMode) + { + return $this->setParam('score_mode', $scoreMode); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/QueryString.php b/modules/thirdparty/elastica/lib/Elastica/Query/QueryString.php new file mode 100755 index 0000000..f8229e5 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/QueryString.php @@ -0,0 +1,276 @@ +, Jasper van Wanrooy + * @link http://www.elasticsearch.org/guide/reference/query-dsl/query-string-query.html + */ +class Elastica_Query_QueryString extends Elastica_Query_Abstract +{ + /** + * Query string + * + * @var string Query string + */ + protected $_queryString = ''; + + /** + * Creates query string object. Calls setQuery with argument + * + * @param string $queryString OPTIONAL Query string for object + */ + public function __construct($queryString = '') + { + $this->setQuery($queryString); + } + + /** + * Sets a new query string for the object + * + * @param string $query Query string + * @return Elastica_Query_QueryString Current object + */ + public function setQuery($query = '') + { + if (!is_string($query)) { + throw new Elastica_Exception_Invalid('Parameter has to be a string'); + } + + return $this->setParam('query', $query); + } + + /** + * Sets the default operator AND or OR + * + * If no operator is set, OR is chosen + * + * @param string $queryString Query string + * @return Elastica_Query_QueryString Current object + * @deprecated Please use setQuery instead + */ + public function setQueryString($queryString) + { + return $this->setQuery($queryString); + } + + /** + * Sets the default field + * + * If no field is set, _all is chosen + * + * @param string $field Field + * @return Elastica_Query_QueryString Current object + */ + public function setDefaultField($field) + { + return $this->setParam('default_field', $field); + } + + /** + * Sets the default operator AND or OR + * + * If no operator is set, OR is chosen + * + * @param string $operator Operator + * @return Elastica_Query_QueryString Current object + */ + public function setDefaultOperator($operator) + { + return $this->setParam('default_operator', $operator); + } + + /** + * Sets the analyzer to analyze the query with. + * + * @param string $analyzer Analyser to use + * @return Elastica_Query_QueryString Current object + */ + public function setAnalyzer($analyzer) + { + return $this->setParam('analyzer', $analyzer); + } + + /** + * Sets the parameter to allow * and ? as first characters. + * + * If not set, defaults to true. + * + * @param bool $allow + * @return Elastica_Query_QueryString Current object + */ + public function setAllowLeadingWildcard($allow = true) + { + return $this->setParam('allow_leading_wildcard', (bool) $allow); + } + + /** + * Sets the parameter to auto-lowercase terms of some queries. + * + * If not set, defaults to true. + * + * @param bool $lowercase + * @return Elastica_Query_QueryString Current object + */ + public function setLowercaseExpandedTerms($lowercase = true) + { + return $this->setParam('lowercase_expanded_terms', (bool) $lowercase); + } + + /** + * Sets the paramater to enable the position increments in result queries. + * + * If not set, defaults to true. + * + * @param bool $enabled + * @return Elastica_Query_QueryString Current object + */ + public function setEnablePositionIncrements($enabled = true) + { + return $this->setParam('enable_position_increments', (bool) $enabled); + } + + /** + * Sets the fuzzy prefix length parameter. + * + * If not set, defaults to 0. + * + * @param int $length + * @return Elastica_Query_QueryString Current object + */ + public function setFuzzyPrefixLength($length = 0) + { + return $this->setParam('fuzzy_prefix_length', (int) $length); + } + + /** + * Sets the fuzzy minimal similarity parameter. + * + * If not set, defaults to 0.5 + * + * @param float $minSim + * @return Elastica_Query_QueryString Current object + */ + public function setFuzzyMinSim($minSim = 0.5) + { + return $this->setParam('fuzzy_min_sim', (float) $minSim); + } + + /** + * Sets the phrase slop. + * + * If zero, exact phrases are required. + * If not set, defaults to zero. + * + * @param int $phraseSlop + * @return Elastica_Query_QueryString Current object + */ + public function setPhraseSlop($phraseSlop = 0) + { + return $this->setParam('phrase_slop', (int) $phraseSlop); + } + + /** + * Sets the boost value of the query. + * + * If not set, defaults to 1.0. + * + * @param float $boost + * @return Elastica_Query_QueryString Current object + */ + public function setBoost($boost = 1.0) + { + return $this->setParam('boost', (float) $boost); + } + + /** + * Allows analyzing of wildcard terms. + * + * If not set, defaults to false + * + * @param bool $analyze + * @return Elastica_Query_QueryString Current object + */ + public function setAnalyzeWildcard($analyze = true) + { + return $this->setParam('analyze_wildcard', (bool) $analyze); + } + + /** + * Sets the param to automatically generate phrase queries. + * + * If not set, defaults to false. + * + * @param bool $autoGenerate + * @return Elastica_Query_QueryString Current object + */ + public function setAutoGeneratePhraseQueries($autoGenerate = true) + { + return $this->setParam('auto_generate_phrase_queries', (bool) $autoGenerate); + } + + /** + * Sets the fields + * + * If no fields are set, _all is chosen + * + * @param array $fields Fields + * @return Elastica_Query_QueryString Current object + */ + public function setFields(array $fields) + { + if (!is_array($fields)) { + throw new Elastica_Exception_Invalid('Parameter has to be an array'); + } + + return $this->setParam('fields', $fields); + } + + /** + * Whether to use bool or dis_max quueries to internally combine results for multi field search. + * + * @param bool $value Determines whether to use + * @return Elastica_Query_QueryString Current object + */ + public function setUseDisMax($value = true) + { + return $this->setParam('use_dis_max', (bool) $value); + } + + /** + * When using dis_max, the disjunction max tie breaker. + * + * If not set, defaults to 0. + * + * @param int $tieBreaker + * @return Elastica_Query_QueryString Current object + */ + public function setTieBraker($tieBreaker = 0) + { + return $this->setParam('tie_breaker', (int) $tieBreaker); + } + + /** + * Set a re-write condition. See https://github.com/elasticsearch/elasticsearch/issues/1186 for additional information + * + * @param string $rewrite + * @return Elastica_Param + */ + public function setRewrite($rewrite = "") + { + return $this->setParam('rewrite', $rewrite); + } + + /** + * Converts query to array + * + * @see Elastica_Param::toArray() + * @return array Query array + */ + public function toArray() + { + return array('query_string' => array_merge(array('query' => $this->_queryString), $this->getParams()),); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Range.php b/modules/thirdparty/elastica/lib/Elastica/Query/Range.php new file mode 100755 index 0000000..1e5f674 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/Range.php @@ -0,0 +1,25 @@ + + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/range_query/ + */ +class Elastica_Query_Range extends Elastica_Query_Abstract +{ + /** + * Adds a range field to the query + * + * @param string $fieldName Field name + * @param array $args Field arguments + * @return Elastica_Query_Range Current object + */ + public function addField($fieldName, array $args) + { + return $this->setParam($fieldName, $args); + + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Term.php b/modules/thirdparty/elastica/lib/Elastica/Query/Term.php new file mode 100755 index 0000000..772418a --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/Term.php @@ -0,0 +1,47 @@ + + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/term_query/ + */ +class Elastica_Query_Term extends Elastica_Query_Abstract +{ + /** + * Constructs the Term query object + * + * @param array $term OPTIONAL Calls setTerm with the given $term array + */ + public function __construct(array $term = array()) + { + $this->setRawTerm($term); + } + + /** + * Set term can be used instead of addTerm if some more special + * values for a term have to be set. + * + * @param array $term Term array + * @return Elastica_Query_Term Current object + */ + public function setRawTerm(array $term) + { + return $this->setParams($term); + } + + /** + * Adds a term to the term query + * + * @param string $key Key to query + * @param string|array $value Values(s) for the query. Boost can be set with array + * @param float $boost OPTIONAL Boost value (default = 1.0) + * @return Elastica_Query_Term Current object + */ + public function setTerm($key, $value, $boost = 1.0) + { + return $this->setRawTerm(array($key => array('value' => $value, 'boost' => $boost))); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Terms.php b/modules/thirdparty/elastica/lib/Elastica/Query/Terms.php new file mode 100755 index 0000000..4577f21 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/Terms.php @@ -0,0 +1,96 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/terms-query.html + */ +class Elastica_Query_Terms extends Elastica_Query_Abstract +{ + /** + * Terms + * + * @var array Terms + */ + protected $_terms = array(); + + /** + * Params + * + * @var array Params + */ + protected $_params = array(); + + /** + * Terms key + * + * @var string Terms key + */ + protected $_key = ''; + + /** + * Construct terms query + * + * @param string $key OPTIONAL Terms key + * @param array $terms OPTIONAL Terms list + */ + public function __construct($key = '', array $terms = array()) + { + $this->setTerms($key, $terms); + } + + /** + * Sets key and terms for the query + * + * @param string $key Terms key + * @param array $terms Terms for the query. + */ + public function setTerms($key, array $terms) + { + $this->_key = $key; + $this->_terms = array_values($terms); + + return $this; + } + + /** + * Adds a single term to the list + * + * @param string $term Term + */ + public function addTerm($term) + { + $this->_terms[] = $term; + + return $this; + } + + /** + * Sets the minimum matching values + * + * @param int $minimum Minimum value + */ + public function setMinimumMatch($minimum) + { + return $this->setParam('minimum_match', (int) $minimum); + } + + /** + * Converts the terms object to an array + * + * @return array Query array + * @see Elastica_Query_Abstract::toArray() + */ + public function toArray() + { + if (empty($this->_key)) { + throw new Elastica_Exception_Invalid('Terms key has to be set'); + } + $this->setParam($this->_key, $this->_terms); + + return parent::toArray(); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Text.php b/modules/thirdparty/elastica/lib/Elastica/Query/Text.php new file mode 100644 index 0000000..a0bdc8e --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/Text.php @@ -0,0 +1,79 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/text-query.html + */ +class Elastica_Query_Text extends Elastica_Query_Abstract +{ + /** + * Sets a param for the message array + * + * @param string $field + * @param mixed $values + * @return Elastica_Query_Text + */ + public function setField($field, $values) + { + return $this->setParam($field, $values); + } + + /** + * Sets a param for the given field + * + * @param string $field + * @param string $key + * @param string $value + * @return Elastica_Query_Text + */ + public function setFieldParam($field, $key, $value) + { + if (!isset($this->_params[$field])) { + $this->_params[$field] = array(); + } + + $this->_params[$field][$key] = $value; + + return $this; + } + + /** + * Sets the query string + * + * @param string $field + * @param string $query + * @return Elastica_Query_Text + */ + public function setFieldQuery($field, $query) + { + return $this->setFieldParam($field, 'query', $query); + } + + /** + * Set field type + * + * @param string $field + * @param string $type Text query type + * @return Elastica_Query_Text + */ + public function setFieldType($field, $type) + { + return $this->setFieldParam($field, 'type', $type); + } + + /** + * Set field max expansions + * + * @param string $field + * @param int $maxExpansions + * @return Elastica_Query_Text + */ + public function setFieldMaxExpansions($field, $maxExpansions) + { + return $this->setFieldParam($field, 'max_expansions', $maxExpansions); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/TopChildren.php b/modules/thirdparty/elastica/lib/Elastica/Query/TopChildren.php new file mode 100644 index 0000000..f412064 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/TopChildren.php @@ -0,0 +1,50 @@ + + * @link http://www.elasticsearch.org/guide/reference/query-dsl/top-children-query.html + */ +class Elastica_Query_TopChildren extends Elastica_Query_Abstract +{ + /** + * Construct topChildren query + * + * @param string|Elastica_Query $query Query string or a Elastica_Query object + * @param string $type Parent document type + */ + public function __construct($query, $type = null) + { + $this->setQuery($query); + $this->setType($type); + } + + /** + * Sets query object + * + * @param string|Elastica_Query|Elastica_Query_Abstract $query + * @return Elastica_Query_TopChildren + */ + public function setQuery($query) + { + $query = Elastica_Query::create($query); + $data = $query->toArray(); + + return $this->setParam('query', $data['query']); + } + + /** + * Set type of the parent document + * + * @param string $type Parent document type + * @return Elastica_Query_TopChildren Current object + */ + public function setType($type) + { + return $this->setParam('type', $type); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Query/Wildcard.php b/modules/thirdparty/elastica/lib/Elastica/Query/Wildcard.php new file mode 100755 index 0000000..c385577 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Query/Wildcard.php @@ -0,0 +1,38 @@ + + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/query_dsl/wildcard_query + */ +class Elastica_Query_Wildcard extends Elastica_Query_Abstract +{ + /** + * Construct wildcard query + * + * @param string $key OPTIONAL Wildcard key + * @param string $value OPTIONAL Wildcard value + * @param float $boost OPTIONAL Boost value (default = 1) + */ + public function __construct($key = '', $value = null, $boost = 1.0) + { + if (!empty($key)) { + $this->setValue($key, $value, $boost); + } + } + + /** + * Sets the query expression for a key with its boost value + * + * @param string $key + * @param string $value + * @param float $boost + */ + public function setValue($key, $value, $boost = 1.0) + { + $this->setParam($key, array('value' => $value, 'boost' => $boost)); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Request.php b/modules/thirdparty/elastica/lib/Elastica/Request.php new file mode 100755 index 0000000..b654d39 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Request.php @@ -0,0 +1,244 @@ + + */ +class Elastica_Request +{ + const POST = 'POST'; + const PUT = 'PUT'; + const GET = 'GET'; + const DELETE = 'DELETE'; + + /** + * Client + * + * @var Elastica_Client Client object + */ + protected $_client; + + /** + * Request path + * + * @var string Request path + */ + protected $_path; + + /** + * Request method (use const's) + * + * @var string Request method (use const's) + */ + protected $_method; + + /** + * Data array + * + * @var array Data array + */ + protected $_data; + + /** + * Query params + * + * @var array Query params + */ + protected $_query; + + /** + * Internal id of last used server. This is used for round robin + * + * @var int Last server id + */ + protected static $_serverId = null; + + /** + * Construct + * + * @param Elastica_Client $client + * @param string $path Request path + * @param string $method Request method (use const's) + * @param array $data OPTIONAL Data array + * @param array $query OPTIONLA Query params + */ + public function __construct(Elastica_Client $client, $path, $method, $data = array(), array $query = array()) + { + $this->_client = $client; + $this->_path = $path; + $this->_method = $method; + $this->_data = $data; + $this->_query = $query; + } + + /** + * Sets the request method. Use one of the for consts + * + * @param string $method Request method + * @return Elastica_Request Current object + */ + public function setMethod($method) + { + $this->_method = $method; + + return $this; + } + + /** + * Get request method + * + * @return string Request method + */ + public function getMethod() + { + return $this->_method; + } + + /** + * Sets the request data + * + * @param array $data Request data + */ + public function setData($data) + { + $this->_data = $data; + + return $this; + } + + /** + * Return request data + * + * @return array Request data + */ + public function getData() + { + return $this->_data; + } + + /** + * Sets the request path + * + * @param string $path Request path + * @return Elastica_Request Current object + */ + public function setPath($path) + { + $this->_path = $path; + + return $this; + } + + /** + * Return request path + * + * @return string Request path + */ + public function getPath() + { + return $this->_path; + } + + /** + * Return query params + * + * @return array Query params + */ + public function getQuery() + { + return $this->_query; + } + + /** + * Return Client Object + * + * @return Elastica_Client + */ + public function getClient() + { + return $this->_client; + } + + /** + * Returns a specific config key or the whole + * config array if not set + * + * @param string $key Config key + * @return array|string Config value + */ + public function getConfig($key = '') + { + return $this->getClient()->getConfig($key); + } + + /** + * Returns an instance of the transport type + * + * @return Elastica_Transport_Abstract Transport object + * @throws Elastica_Exception_Invalid If invalid transport type + */ + public function getTransport() + { + $className = 'Elastica_Transport_' . $this->_client->getConfig('transport'); + if (!class_exists($className)) { + throw new Elastica_Exception_Invalid('Invalid transport'); + } + + return new $className($this); + } + + /** + * Sends request to server + * + * @return Elastica_Response Response object + */ + public function send() + { + $log = new Elastica_Log($this->getClient()); + $log->log($this); + + $transport = $this->getTransport(); + + $servers = $this->getClient()->getConfig('servers'); + + /* + + // Integration of temp file + $dir = sys_get_temp_dir(); + $name = 'elasticaServers.json'; + $file = $dir . DIRECTORY_SEPARATOR . $name; + + if (!file_exists($file)) { + file_put_contents($file, 'hh'); + error_log(print_r($this->getClient()->getCluster(), true)); + } + + */ + + if (empty($servers)) { + $params = array( + 'url' => $this->getClient()->getConfig('url'), + 'host' => $this->getClient()->getHost(), + 'port' => $this->getClient()->getPort(), + 'path' => $this->getClient()->getConfig('path'), + ); + $response = $transport->exec($params); + } else { + + // Set server id for first request (round robin by default) + if (is_null(self::$_serverId)) { + self::$_serverId = rand(0, count($servers) - 1); + } else { + self::$_serverId = (self::$_serverId + 1) % count($servers); + } + + $server = $servers[self::$_serverId]; + + $response = $transport->exec($server); + } + + return $response; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Response.php b/modules/thirdparty/elastica/lib/Elastica/Response.php new file mode 100755 index 0000000..80071d9 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Response.php @@ -0,0 +1,215 @@ + is given to resultset, returned by ... + * + * @category Xodoa + * @package Elastica + * @author Nicolas Ruflin + */ +class Elastica_Response +{ + /** + * Query time + * + * @var float Query time + */ + protected $_queryTime = null; + + /** + * Response string (json) + * + * @var string Response + */ + protected $_responseString = ''; + + /** + * Error + * + * @var boolean Error + */ + protected $_error = false; + + /** + * Transfer info + * + * @var array transfer info + */ + protected $_transferInfo = array(); + + /** + * Response + * + * @var Elastica_Response Response object + */ + protected $_response = null; + + /** + * Construct + * + * @param string $responseString Response string (json) + */ + public function __construct($responseString) + { + $this->_responseString = $responseString; + } + + /** + * Error message + * + * @return string Error message + */ + public function getError() + { + $message = ''; + $response = $this->getData(); + + if (isset($response['error'])) { + $message = $response['error']; + } + + return $message; + } + + /** + * True if response has error + * + * @return bool True if response has error + */ + public function hasError() + { + $response = $this->getData(); + + if (isset($response['error'])) { + return true; + } + + return false; + } + + /** + * Checks if the query returned ok + * + * @return bool True if ok + */ + public function isOk() + { + $data = $this->getData(); + + return (isset($data['ok']) && $data['ok']); + } + + /** + * Response data array + * + * @return array Response data array + */ + public function getData() + { + if ($this->_response == null) { + $response = $this->_responseString; + if ($response === false) { + $this->_error = true; + } else { + + $tempResponse = json_decode($response, true); + // If error is returned, json_decod makes empty string of string + if (!empty($tempResponse)) { + $response = $tempResponse; + } + } + + if (empty($response)) { + $response = array(); + } + + if (is_string($response)) { + $response = array('message' => $response); + } + + $this->_response = $response; + } + + return $this->_response; + } + + /** + * Gets the transfer information if in DEBUG mode. + * + * @return array Information about the curl request. + */ + public function getTransferInfo() + { + return $this->_transferInfo; + } + + /** + * Sets the transfer info of the curl request. This function is called + * from the Elastica_Client::_callService only in debug mode. + * + * @param array $transferInfo The curl transfer information. + * @return Elastica_Response Current object + */ + public function setTransferInfo(array $transferInfo) + { + $this->_transferInfo = $transferInfo; + + return $this; + } + + /** + * This is only available if DEBUG constant is set to true + * + * @return float Query time + */ + public function getQueryTime() + { + return $this->_queryTime; + } + + /** + * Sets the query time + * + * @param float $queryTime Query time + * @return Elastica_Response Current object + */ + public function setQueryTime($queryTime) + { + $this->_queryTime = $queryTime; + + return $this; + } + + /** + * Time request took + * + * @return int Time request took + */ + public function getEngineTime() + { + $data = $this->getData(); + + if (!isset($data['took'])) { + throw new Elastica_Exception_NotFound("Unable to find the field [took]from the response"); + } + + return $data['took']; + } + + /** + * Get the _shard statistics for the response + * + * @return array + */ + public function getShardsStatistics() + { + $data = $this->getData(); + + if (!isset($data['_shards'])) { + throw new Elastica_Exception_NotFound("Unable to find the field [_shards] from the response"); + } + + return $data['_shards']; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Result.php b/modules/thirdparty/elastica/lib/Elastica/Result.php new file mode 100644 index 0000000..12cf4ca --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Result.php @@ -0,0 +1,179 @@ + + */ +class Elastica_Result +{ + /** + * Hit array + * + * @var array Hit array + */ + protected $_hit = array(); + + /** + * Constructs a single results object + * + * @param array $hit Hit data + */ + public function __construct(array $hit) + { + $this->_hit = $hit; + } + + /** + * Returns a param from the result hit array + * + * This function can be used to retrieve all data for which a specific + * function doesn't exist. + * If the param does not exist, an empty array is retured + * + * @param string $name Param name + * @return array Result data + */ + public function getParam($name) + { + if (isset($this->_hit[$name])) { + return $this->_hit[$name]; + } else { + return array(); + } + } + + /** + * Returns the hit id + * + * @return string Hit id + */ + public function getId() + { + return $this->getParam('_id'); + } + + /** + * Returns the type of the result + * + * @return string Result type + */ + public function getType() + { + return $this->getParam('_type'); + } + + /** + * Returns list of fields + * + * @return array Fields list + */ + public function getFields() + { + return $this->getParam('fields'); + } + + /** + * Returns the index name of the result + * + * @return string Index name + */ + public function getIndex() + { + return $this->getParam('_index'); + } + + /** + * Returns the score of the result + * + * @return float Result score + */ + public function getScore() + { + return $this->getParam('_score'); + } + + /** + * Returns the raw hit array + * + * @return array Hit array + */ + public function getHit() + { + return $this->_hit; + } + + /** + * Returns the version information from the hit + * + * @return string|int Document version + */ + public function getVersion() + { + return $this->getParam('_version'); + } + + /** + * Returns result data + * + * Checks for partial result data with getFields, falls back to getSource + * + * @return array Result data array + */ + public function getData() + { + if (isset($this->_hit['fields']) && !isset($this->_hit['_source'])) { + return $this->getFields(); + } else { + return $this->getSource(); + } + } + + /** + * Returns the result source + * + * @return array Source data array + */ + public function getSource() + { + return $this->getParam('_source'); + } + + /** + * Returns result data + * + * @return array Result data array + */ + public function getHighlights() + { + return $this->getParam('highlight'); + } + + /** + * Returns explanation on how its score was computed. + * + * @return array explanations + */ + public function getExplanation() + { + return $this->getParam('_explanation'); + } + + /** + * Magic function to directly access keys inside the result + * + * Returns null if key does not exist + * + * @param string $key Key name + * @return mixed Key value + */ + public function __get($key) + { + $source = $this->getData(); + + return array_key_exists($key, $source) ? $source[$key] : null; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/ResultSet.php b/modules/thirdparty/elastica/lib/Elastica/ResultSet.php new file mode 100755 index 0000000..873beb3 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/ResultSet.php @@ -0,0 +1,189 @@ + + */ +class Elastica_ResultSet implements Iterator, Countable +{ + /** + * Results + * + * @var array Results + */ + protected $_results = array(); + + /** + * Current position + * + * @var int Current position + */ + protected $_position = 0; + + /** + * Response + * + * @var Elastica_Response Response object + */ + protected $_response = null; + protected $_took = 0; + /** + * Constructs ResultSet object + * + * @param Elastica_Response $response Response object + */ + public function __construct(Elastica_Response $response) + { + $this->rewind(); + $this->_init($response); + } + + /** + * Loads all data into the results object (initalisation) + * + * @param Elastica_Response $response Response object + */ + protected function _init(Elastica_Response $response) + { + $this->_response = $response; + $result = $response->getData(); + $this->_totalHits = $result['hits']['total']; + $this->_took = isset($result['took']) ? $result['took'] : 0; + if (isset($result['hits']['hits'])) { + foreach ($result['hits']['hits'] as $hit) { + $this->_results[] = new Elastica_Result($hit); + } + } + } + + /** + * Returns all results + * + * @return array Results + */ + public function getResults() + { + return $this->_results; + } + + /** + * Returns whether facets exist + * + * @return boolean Facet existence + */ + public function hasFacets() + { + $data = $this->_response->getData(); + + return isset($data['facets']); + } + + /** + * Returns all facets results + * + * @return array Facet results + */ + public function getFacets() + { + $data = $this->_response->getData(); + + return isset($data['facets']) ? $data['facets'] : array(); + } + + /** + * Returns the total number of found hits + * + * @return int Total hits + */ + public function getTotalHits() + { + return (int) $this->_totalHits; + } + + /** + * Returns the total number of ms for this search to complete + * + * @return int Total time + */ + public function getTotalTime() + { + return (int) $this->_took; + } + + /** + * Returns response object + * + * @return Elastica_Response Response object + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Returns size of current set + * + * @return int Size of set + */ + public function count() + { + return sizeof($this->_results); + } + + /** + * Returns the current object of the set + * + * @return Elastica_Result|bool Set object or false if not valid (no more entries) + */ + public function current() + { + if ($this->valid()) { + return $this->_results[$this->key()]; + } else { + return false; + } + } + + /** + * Sets pointer (current) to the next item of the set + */ + public function next() + { + $this->_position++; + + return $this->current(); + } + + /** + * Returns the position of the current entry + * + * @return int Current position + */ + public function key() + { + return $this->_position; + } + + /** + * Check if an object exists at the current position + * + * @return bool True if object exists + */ + public function valid() + { + return isset($this->_results[$this->key()]); + } + + /** + * Resets position to 0, restarts iterator + */ + public function rewind() + { + $this->_position = 0; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Script.php b/modules/thirdparty/elastica/lib/Elastica/Script.php new file mode 100644 index 0000000..21d9c7f --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Script.php @@ -0,0 +1,99 @@ + + * @link http://www.elasticsearch.org/guide/reference/modules/scripting.html + */ +class Elastica_Script +{ + /** + * @var string + */ + private $_script; + /** + * @var string + */ + private $_lang; + /** + * @var array + */ + private $_params; + + /** + * @param string $script + * @param array|null $params + * @param string|null $lang + */ + public function __construct($script, array $params = null, $lang = null) + { + $this->_script = $script; + $this->_params = $params; + $this->_lang = $lang; + } + + /** + * @param string $lang + */ + public function setLang($lang) + { + $this->_lang = $lang; + } + + /** + * @return string + */ + public function getLang() + { + return $this->_lang; + } + + /** + * @param array $params + */ + public function setParams($params) + { + $this->_params = $params; + } + + /** + * @return array + */ + public function getParams() + { + return $this->_params; + } + + /** + * @param string $script + */ + public function setScript($script) + { + $this->_script = $script; + } + + /** + * @return string + */ + public function getScript() + { + return $this->_script; + } + + public function toArray() + { + $array = array( + 'script' => $this->_script, + ); + if ($this->_params) { + $array['params'] = $this->_params; + } + if ($this->_lang) { + $array['lang'] = $this->_lang; + } + + return $array; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/ScriptFields.php b/modules/thirdparty/elastica/lib/Elastica/ScriptFields.php new file mode 100644 index 0000000..87ba224 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/ScriptFields.php @@ -0,0 +1,55 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/search/script-fields.html + */ +class Elastica_ScriptFields extends Elastica_Param +{ + /** + * @param array $scripts OPTIONAL + */ + public function __construct(array $scripts = array()) + { + if ($scripts) { + $this->setScripts($scripts); + } + } + + /** + * @param string $name Name of the Script field + * @param Elastica_Script $script + * @return Elastica_ScriptFields + */ + public function addScript($name, Elastica_Script $script) + { + if (!is_string($name) || !strlen($name)) { + throw new Elastica_Exception_Invalid('The name of a Script is required and must be a string'); + } + $this->setParam($name, $script->toArray()); + + return $this; + } + + /** + * @param array $script Associative array of string => Elastica_Script + * @return Elastica_ScriptFields + */ + public function setScripts(array $scripts) + { + $this->_params = array(); + foreach ($scripts as $name => $script) { + $this->addScript($name, $script); + } + + return $this; + } + + public function toArray() + { + return $this->_params; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Search.php b/modules/thirdparty/elastica/lib/Elastica/Search.php new file mode 100644 index 0000000..3721ef9 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Search.php @@ -0,0 +1,225 @@ + + */ +class Elastica_Search +{ + /** + * Array of indices + * + * @var array + */ + protected $_indices = array(); + + /** + * Array of types + * + * @var array + */ + protected $_types = array(); + + /** + * Client object + * + * @var Elastica_Client + */ + protected $_client; + + /** + * Constructs search object + * + * @param Elastica_Client $client Client object + */ + public function __construct(Elastica_Client $client) + { + $this->_client = $client; + } + + /** + * Adds a index to the list + * + * @param Elastica_Index|string $index Index object or string + * @return Elastica_Search Current object + */ + public function addIndex($index) + { + if ($index instanceof Elastica_Index) { + $index = $index->getName(); + } + + if (!is_string($index)) { + throw new Elastica_Exception_Invalid('Invalid param type'); + } + + $this->_indices[] = $index; + + return $this; + } + + /** + * Add array of indices at once + * + * @param array $indices + * @return Elastica_Search + */ + public function addIndices(array $indices = array()) + { + foreach ($indices as $index) { + $this->addIndex($index); + } + + return $this; + } + + /** + * Adds a type to the current search + * + * @param Elastica_Type|string $type Type name or object + * @return Elastica_Search Search object + * @throws Elastica_Exception_Invalid + */ + public function addType($type) + { + if ($type instanceof Elastica_Type) { + $type = $type->getName(); + } + + if (!is_string($type)) { + throw new Elastica_Exception_Invalid('Invalid type type'); + } + + $this->_types[] = $type; + + return $this; + } + + /** + * Add array of types + * + * @param array $types + * @return Elastica_Search + */ + public function addTypes(array $types = array()) + { + foreach ($types as $type) { + $this->addType($type); + } + + return $this; + } + + /** + * Return client object + * + * @return Elastica_Client Client object + */ + public function getClient() + { + return $this->_client; + } + + /** + * Return array of indices + * + * @return array List of index names + */ + public function getIndices() + { + return $this->_indices; + } + + /** + * Return array of types + * + * @return array List of types + */ + public function getTypes() + { + return $this->_types; + } + + /** + * Creates new search object + * + * @param Elastica_Searchable $searchObject + */ + public static function create(Elastica_Searchable $searchObject) + { + throw new Elastica_Exception_NotImplemented(); + // Set index + // set type + // set client + } + + /** + * Combines indices and types to the search request path + * + * @return string Search path + */ + public function getPath() + { + $indices = $this->getIndices(); + + $path = ''; + + if (empty($indices)) { + $path .= '_all'; + } else { + $path .= implode(',', $indices); + } + + $types = $this->getTypes(); + + if (!empty($types)) { + $path .= '/' . implode(',', $types); + } + + // Add full path based on indices and types -> could be all + return $path . '/_search'; + } + + /** + * Search in the set indices, types + * + * @param mixed $query + * @param int|array $options OPTIONAL Limit or associative array of options (option=>value) + * @return Elastica_ResultSet + */ + public function search($query, $options = null) + { + $query = Elastica_Query::create($query); + $path = $this->getPath(); + $params = array(); + + if (is_int($options)) { + $query->setLimit($options); + } else { + if (is_array($options)) { + foreach ($options as $key => $value) { + switch ($key) { + case 'limit' : + $query->setLimit($value); + break; + case 'routing' : + $params['routing'] = $value; + break; + case 'search_type': + $params['search_type'] = $value; + break; + default: + throw new Elastica_Exception_Invalid('Invalid option ' . $key); + break; + } + } + } + } + + $response = $this->getClient()->request($path, Elastica_Request::GET, $query->toArray(), $params); + + return new Elastica_ResultSet($response); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Searchable.php b/modules/thirdparty/elastica/lib/Elastica/Searchable.php new file mode 100644 index 0000000..65eee4e --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Searchable.php @@ -0,0 +1,43 @@ + + */ +interface Elastica_Searchable +{ + /** + * Searches results for a query + * + * TODO: Improve sample code + * { + * "from" : 0, + * "size" : 10, + * "sort" : { + * "postDate" : {"reverse" : true}, + * "user" : { }, + * "_score" : { } + * }, + * "query" : { + * "term" : { "user" : "kimchy" } + * } + * } + * + * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object + * @return Elastica_ResultSet ResultSet with all results inside + */ + public function search($query); + + /** + * Counts results for a query + * + * If no query is set, matchall query is created + * + * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object + * @return int number of documents matching the query + */ + public function count($query = ''); +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Status.php b/modules/thirdparty/elastica/lib/Elastica/Status.php new file mode 100644 index 0000000..c4d9dca --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Status.php @@ -0,0 +1,171 @@ + + * @link http://www.elasticsearch.org/guide/reference/api/admin-indices-status.html + */ +class Elastica_Status +{ + /** + * Contains all status infos + * + * @var Elastica_Response Response object + */ + protected $_response = null; + + /** + * Data + * + * @var array Data + */ + protected $_data = array(); + + /** + * Client object + * + * @var Elastica_Client Client object + */ + protected $_client = null; + + /** + * Constructs Status object + * + * @param Elastica_Client $client Client object + */ + public function __construct(Elastica_Client $client) + { + $this->_client = $client; + $this->refresh(); + } + + /** + * Returns status data + * + * @return array Status data + */ + public function getData() + { + return $this->_data; + } + + /** + * Returns status objects of all indices + * + * @return array List of Elastica_Client_Index objects + */ + public function getIndexStatuses() + { + $statuses = array(); + foreach ($this->getIndexNames() as $name) { + $index = new Elastica_Index($this->_client, $name); + $statuses[] = new Elastica_Index_Status($index); + } + + return $statuses; + } + + /** + * Returns a list of the existing index names + * + * @return array Index names list + */ + public function getIndexNames() + { + $names = array(); + foreach ($this->_data['indices'] as $name => $data) { + $names[] = $name; + } + + return $names; + } + + /** + * Checks if the given index exists + * + * @param string $name Index name to check + * @return bool True if index exists + */ + public function indexExists($name) + { + return in_array($name, $this->getIndexNames()); + } + + /** + * Checks if the given alias exists + * + * @param string $name Alias name + * @return bool True if alias exists + */ + public function aliasExists($name) + { + foreach ($this->getIndexStatuses() as $status) { + if ($status->hasAlias($name)) { + return true; + } + } + + return false; + } + + /** + * Returns an array with all indices that the given alias name points to + * + * @param string $name Alias name + * @return array List of Elastica_Index + */ + public function getIndicesWithAlias($name) + { + $indices = array(); + foreach ($this->getIndexStatuses() as $status) { + if ($status->hasAlias($name)) { + $indices[] = $status->getIndex(); + } + } + + return $indices; + } + + /** + * Returns response object + * + * @return Elastica_Response Response object + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Return shards info + * + * @return array Shards info + */ + public function getShards() + { + return $this->_data['shards']; + } + + /** + * Refresh status object + */ + public function refresh() + { + $path = '_status'; + $this->_response = $this->_client->request($path, Elastica_Request::GET); + $this->_data = $this->getResponse()->getData(); + } + + /** + * Refresh serverStatus object + */ + public function getServerStatus() + { + $path = ''; + $response = $this->_client->request($path, Elastica_Request::GET); + + return $response->getData(); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Transport/Abstract.php b/modules/thirdparty/elastica/lib/Elastica/Transport/Abstract.php new file mode 100644 index 0000000..fece61c --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Transport/Abstract.php @@ -0,0 +1,67 @@ + + */ +abstract class Elastica_Transport_Abstract +{ + /** + * Path + * + * @var string path + */ + protected $_path; + + /** + * Method + * + * @var string method + * @todo set default method? + */ + protected $_method; + + /** + * Data + * + * @var array Data + */ + protected $_data; + + /** + * Config + * + * @var array config + */ + protected $_config; + + /** + * Construc transport + * + * @param Elastica_Request $request Request object + */ + public function __construct(Elastica_Request $request) + { + $this->_request = $request; + } + + /** + * Returns the request object + * + * @return Elastica_Request Request object + */ + public function getRequest() + { + return $this->_request; + } + + /** + * Executes the transport request + * + * @param array $params Hostname, port, path, ... + * @return Elastica_Response Response object + */ + abstract public function exec(array $params); +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Transport/Http.php b/modules/thirdparty/elastica/lib/Elastica/Transport/Http.php new file mode 100644 index 0000000..737bd82 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Transport/Http.php @@ -0,0 +1,149 @@ + + */ +class Elastica_Transport_Http extends Elastica_Transport_Abstract +{ + /** + * Http scheme + * + * @var string Http scheme + */ + protected $_scheme = 'http'; + + /** + * Curl resource to reuse + * + * @var resource Curl resource to reuse + */ + protected static $_connection = null; + + /** + * Makes calls to the elasticsearch server + * + * All calls that are made to the server are done through this function + * + * @param array $params Host, Port, ... + * @return Elastica_Response Response object + */ + public function exec(array $params) + { + $request = $this->getRequest(); + + $conn = $this->_getConnection($request->getConfig('persistent')); + + // If url is set, url is taken. Otherwise port, host and path + if (!empty($params['url'])) { + $baseUri = $params['url']; + } else { + if (!isset($params['host']) || !isset($params['port'])) { + throw new Elastica_Exception_Invalid('host and port have to be set'); + } + + $path = isset($params['path']) ? $params['path'] : ''; + + $baseUri = $this->_scheme . '://' . $params['host'] . ':' . $params['port'] . '/' . $path; + } + + $baseUri .= $request->getPath(); + + $query = $request->getQuery(); + + if (!empty($query)) { + $baseUri .= '?' . http_build_query($query); + } + + curl_setopt($conn, CURLOPT_URL, $baseUri); + curl_setopt($conn, CURLOPT_TIMEOUT, $request->getConfig('timeout')); + curl_setopt($conn, CURLOPT_CUSTOMREQUEST, $request->getMethod()); + curl_setopt($conn, CURLOPT_FORBID_REUSE, 0); + + $this->_setupCurl($conn); + + $headersConfig = $request->getConfig('headers'); + if (!empty($headersConfig)) { + $headers = array(); + while (list($header, $headerValue) = each($headersConfig)) { + array_push($headers, $header . ': ' . $headerValue); + } + + curl_setopt($conn, CURLOPT_HTTPHEADER, $headers); + } + + // TODO: REFACTOR + $data = $request->getData(); + + if (isset($data) && !empty($data)) { + if (is_array($data)) { + $content = json_encode($data); + } else { + $content = $data; + } + + // Escaping of / not necessary. Causes problems in base64 encoding of files + $content = str_replace('\/', '/', $content); + + curl_setopt($conn, CURLOPT_POSTFIELDS, $content); + } + + $start = microtime(true); + + // cURL opt returntransfer leaks memory, therefore OB instead. + ob_start(); + curl_exec($conn); + $responseString = ob_get_clean(); + + $end = microtime(true); + + // Checks if error exists + $errorNumber = curl_errno($conn); + + $response = new Elastica_Response($responseString); + + if (defined('DEBUG') && DEBUG) { + $response->setQueryTime($end - $start); + $response->setTransferInfo(curl_getinfo($conn)); + } + + if ($response->hasError()) { + throw new Elastica_Exception_Response($response); + } + + if ($errorNumber > 0) { + throw new Elastica_Exception_Client($errorNumber, $request, $response); + } + + return $response; + } + + /** + * Called to add additional curl params + * + * @param resource $connection Curl connection + */ + protected function _setupCurl($connection) + { + foreach ($this->_request->getClient()->getConfig('curl') as $key => $param) { + curl_setopt($connection, $key, $param); + } + } + + /** + * Return Curl ressource + * + * @param bool $persistent False if not persistent connection + * @return resource Connection resource + */ + protected function _getConnection($persistent = true) + { + if (!$persistent || !self::$_connection) { + self::$_connection = curl_init(); + } + + return self::$_connection; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Transport/Https.php b/modules/thirdparty/elastica/lib/Elastica/Transport/Https.php new file mode 100644 index 0000000..83070dd --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Transport/Https.php @@ -0,0 +1,27 @@ + + */ +class Elastica_Transport_Https extends Elastica_Transport_Http +{ + /** + * Https scheme + * + * @var string https scheme + */ + protected $_scheme = 'https'; + + /** + * Overloads setupCurl to set SSL params + * + * @param resource $connection Curl connection resource + */ + protected function _setupCurl($connection) + { + parent::_setupCurl($connection); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Transport/Memcache.php b/modules/thirdparty/elastica/lib/Elastica/Transport/Memcache.php new file mode 100644 index 0000000..03e9fdb --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Transport/Memcache.php @@ -0,0 +1,73 @@ + + */ +class Elastica_Transport_Memcache extends Elastica_Transport_Abstract +{ + /** + * Makes calls to the elasticsearch server + * + * @param array $params Host, Port, ... + * @return Elastica_Response Response object + */ + public function exec(array $params) + { + $request = $this->getRequest(); + + $memcache = new Memcache(); + $memcache->connect($params['host'], $params['port']); + + // Finds right function name + $function = strtolower($request->getMethod()); + + $data = $request->getData(); + + $content = ''; + + if (!empty($data)) { + if (is_array($data)) { + $content = json_encode($data); + } else { + $content = $data; + } + + // Escaping of / not necessary. Causes problems in base64 encoding of files + $content = str_replace('\/', '/', $content); + } + + $responseString = ''; + + switch ($function) { + case 'post': + case 'put': + $memcache->set($request->getPath(), $content); + break; + case 'get': + $responseString = $memcache->get($request->getPath() . '?source=' . $content); + echo $responseString . PHP_EOL; + break; + case 'delete': + break; + default: + throw new Elastica_Exception_Invalid('Method ' . $function . ' is not supported in memcache transport'); + + } + + $response = new Elastica_Response($responseString); + + if (defined('DEBUG') && DEBUG) { + $response->setQueryTime($end - $start); + $response->setTransferInfo(curl_getinfo($conn)); + } + + if ($response->hasError()) { + throw new Elastica_Exception_Response($response); + } + + return $response; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Type.php b/modules/thirdparty/elastica/lib/Elastica/Type.php new file mode 100644 index 0000000..093a612 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Type.php @@ -0,0 +1,320 @@ + index -> type -> document + * + * Search over different indices and types is not supported yet {@link http://www.elasticsearch.com/docs/elasticsearch/rest_api/search/indices_types/} + * + * @category Xodoa + * @package Elastica + * @author Nicolas Ruflin + */ +class Elastica_Type implements Elastica_Searchable +{ + /** + * Index + * + * @var Elastica_Index Index object + */ + protected $_index = null; + + /** + * Type name + * + * @var string Type name + */ + protected $_name = ''; + + /** + * Creates a new type object inside the given index + * + * @param Elastica_Index $index Index Object + * @param string $name Type name + */ + public function __construct(Elastica_Index $index, $name) + { + $this->_index = $index; + $this->_name = $name; + } + + /** + * Adds the given document to the search index + * + * @param Elastica_Document $doc Document with data + * @return Elastica_Response + */ + public function addDocument(Elastica_Document $doc) + { + $path = $doc->getId(); + + $query = array(); + + if ($doc->getVersion() > 0) { + $query['version'] = $doc->getVersion(); + } + + if (!is_null($doc->getParent())) { + $query['parent'] = $doc->getParent(); + } + + if ($doc->getOpType()) { + $query['op_type'] = $doc->getOpType(); + } + + if ($doc->getPercolate()) { + $query['percolate'] = $doc->getPercolate(); + } + + $type = Elastica_Request::PUT; + + // If id is empty, POST has to be used to automatically create id + if (empty($path)) { + $type = Elastica_Request::POST; + } + + return $this->request($path, $type, $doc->getData(), $query); + } + + /** + * Update document, using update script. Requires elasticsearch >= 0.19.0 + * + * @param string $id Document id + * @param Elastica_Script $script script to use for update + * @param array $options options for query + * @return Elastica_Response + * @see Elastica_Client::updateDocument() + * @link http://www.elasticsearch.org/guide/reference/api/update.html + */ + public function updateDocument($id, Elastica_Script $script, array $options = array()) + { + return $this->getIndex()->updateDocument($id, $script, $this->getName(), $options); + } + + /** + * Uses _bulk to send documents to the server + * + * @param array $docs Array of Elastica_Document + * @link http://www.elasticsearch.com/docs/elasticsearch/rest_api/bulk/ + */ + public function addDocuments(array $docs) + { + foreach ($docs as $doc) { + $doc->setType($this->getName()); + } + + return $this->getIndex()->addDocuments($docs); + } + + /** + * Get the document from search index + * + * @param string $id Document id + * @return Elastica_Document + */ + public function getDocument($id) + { + $path = $id; + + try { + $result = $this->request($path, Elastica_Request::GET)->getData(); + } catch (Elastica_Exception_Response $e) { + throw new Elastica_Exception_NotFound('doc id ' . $id . ' not found'); + } + + if (empty($result['exists'])) { + throw new Elastica_Exception_NotFound('doc id ' . $id . ' not found'); + } + + $data = isset($result['_source']) ? $result['_source'] : array(); + $document = new Elastica_Document($id, $data, $this->getName(), $this->getIndex()); + $document->setVersion($result['_version']); + + return $document; + } + + /** + * Returns the type name + * + * @return string Type + * @deprecated Use getName instead + */ + public function getType() + { + return $this->getName(); + } + + /** + * Returns the type name + * + * @return string Type name + */ + public function getName() + { + return $this->_name; + } + + /** + * Sets value type mapping for this type + * + * @param Elastica_Type_Mapping|array $mapping Elastica_Type_Mapping object or property array with all mappings + */ + public function setMapping($mapping) + { + $mapping = Elastica_Type_Mapping::create($mapping); + $mapping->setType($this); + + return $mapping->send(); + } + + /** + * Returns current mapping for the given type + * + * @return array Current mapping + */ + public function getMapping() + { + $path = '_mapping'; + + $response = $this->request($path, Elastica_Request::GET); + + return $response->getData(); + } + + /** + * Do a search on this type + * + * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object + * @param int|array $options OPTIONAL Limit or associative array of options (option=>value) + * @return Elastica_ResultSet ResultSet with all results inside + * @see Elastica_Searchable::search + */ + public function search($query, $options = null) + { + $search = new Elastica_Search($this->getIndex()->getClient()); + $search->addIndex($this->getIndex()); + $search->addType($this); + + return $search->search($query, $options); + } + + /** + * Count docs by query + * + * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object + * @return int number of documents matching the query + * @see Elastica_Searchable::count + */ + public function count($query = '') + { + $query = Elastica_Query::create($query); + $path = '_search'; + + $response = $this->request($path, Elastica_Request::GET, $query->toArray(), array('search_type' => 'count')); + $resultSet = new Elastica_ResultSet($response); + + return $resultSet->getTotalHits(); + } + + /** + * Returns index client + * + * @return Elastica_Index Index object + */ + public function getIndex() + { + return $this->_index; + } + + /** + * Deletes an entry by its unique identifier + * + * @param int|string $id Document id + * @return Elastica_Response Response object + * @link http://www.elasticsearch.org/guide/reference/api/delete.html + */ + public function deleteById($id) + { + if (empty($id) || !trim($id)) { + throw new InvalidArgumentException(); + } + + return $this->request($id, Elastica_Request::DELETE); + } + + /** + * Deletes the given list of ids from this type + * + * @param array $ids + * @return Elastica_Response Response object + */ + public function deleteIds(array $ids) + { + return $this->getIndex()->getClient()->deleteIds($ids, $this->getIndex(), $this); + } + + /** + * Deletes entries in the db based on a query + * + * @param Elastica_Query|string $query Query object + * @link http://www.elasticsearch.org/guide/reference/api/delete-by-query.html + */ + public function deleteByQuery($query) + { + $query = Elastica_Query::create($query); + + return $this->request('_query', Elastica_Request::DELETE, $query->getQuery()); + } + + /** + * Deletes the index type. + * + * @return Elastica_Response + */ + public function delete() + { + $response = $this->request('', Elastica_Request::DELETE); + + return $response; + } + + /** + * More like this query based on the given object + * + * The id in the given object has to be set + * + * @param Elastica_Document $doc Document to query for similar objects + * @param array $params OPTIONAL Additional arguments for the query + * @param Elastica_Query $query OPTIONAL Query to filter the moreLikeThis results + * @return Elastica_ResultSet ResultSet with all results inside + * @link http://www.elasticsearch.org/guide/reference/api/more-like-this.html + */ + public function moreLikeThis(Elastica_Document $doc, $params = array(), $query = array()) + { + $path = $doc->getId() . '/_mlt'; + + $query = Elastica_Query::create($query); + + $response = $this->request($path, Elastica_Request::GET, $query->toArray(), $params); + + return new Elastica_ResultSet($response); + } + + /** + * Makes calls to the elasticsearch server based on this type + * + * @param string $path Path to call + * @param string $method Rest method to use (GET, POST, DELETE, PUT) + * @param array $data OPTIONAL Arguments as array + * @param array $query OPTIONAL Query params + * @return Elastica_Response Response object + */ + public function request($path, $method, $data = array(), array $query = array()) + { + $path = $this->getName() . '/' . $path; + + return $this->getIndex()->request($path, $method, $data, $query); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Type/Abstract.php b/modules/thirdparty/elastica/lib/Elastica/Type/Abstract.php new file mode 100755 index 0000000..f8e5798 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Type/Abstract.php @@ -0,0 +1,179 @@ + + */ +abstract class Elastica_Type_Abstract implements Elastica_Searchable +{ + const MAX_DOCS_PER_REQUEST = 1000; + + /** + * Index name + * + * @var string Index name + */ + protected $_indexName = ''; + + /** + * Index name + * + * @var string Index name + */ + protected $_typeName = ''; + + /** + * Client + * + * @var Elastica_Client Client object + */ + protected $_client = null; + + /** + * Index + * + * @var Elastica_Index Index object + */ + protected $_index = null; + + /** + * Type + * + * @var Elastica_Type Type object + */ + protected $_type = null; + + /** + * Mapping + * + * @var array Mapping + */ + protected $_mapping = array(); + + /** + * Index params + * + * @var array Index params + */ + protected $_indexParams = array(); + + /** + * Source + * + * @var boolean Source + */ + protected $_source = true; + + /** + * Creates index object with client connection + * + * Reads index and type name from protected vars _indexName and _typeName. + * Has to be set in child class + * + * @param Elastica_Client $client OPTIONAL Client object + */ + public function __construct(Elastica_Client $client = null) + { + if (!$client) { + $client = new Elastica_Client(); + } + + if (empty($this->_indexName)) { + throw new Elastica_Exception_Invalid('Index name has to be set'); + } + + if (empty($this->_typeName)) { + throw new Elastica_Exception_Invalid('Type name has to be set'); + } + + $this->_client = $client; + $this->_index = new Elastica_Index($this->_client, $this->_indexName); + $this->_type = new Elastica_Type($this->_index, $this->_typeName); + } + + /** + * Creates the index and sets the mapping for this type + * + * @param bool $recreate OPTIONAL Recreates the index if true (default = false) + */ + public function create($recreate = false) + { + $this->getIndex()->create($this->_indexParams, $recreate); + + $mapping = new Elastica_Type_Mapping($this->getType()); + $mapping->setProperties($this->_mapping); + $mapping->setSource(array('enabled' => $this->_source)); + $mapping->send(); + } + + /** + * Search on the type + * + * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object + * @return Elastica_ResultSet ResultSet with all results inside + * @see Elastica_Searchable::search + */ + public function search($query) + { + return $this->getType()->search($query); + } + + /** + * Count docs in the type based on query + * + * @param string|array|Elastica_Query $query Array with all query data inside or a Elastica_Query object + * @return int number of documents matching the query + * @see Elastica_Searchable::count + */ + public function count($query = '') + { + return $this->getType()->count($query); + } + + /** + * Returns the search index + * + * @return Elastica_Index Index object + */ + public function getIndex() + { + return $this->_index; + } + + /** + * Returns type object + * + * @return Elastica_Type Type object + */ + public function getType() + { + return $this->_type; + } + + /** + * Converts given time to format: 1995-12-31T23:59:59Z + * + * This is the lucene date format + * + * @param int $date Date input (could be string etc.) -> must be supported by strtotime + * @return string Converted date string + */ + public function convertDate($date) + { + return Elastica_Util::convertDate($date); + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Type/Mapping.php b/modules/thirdparty/elastica/lib/Elastica/Type/Mapping.php new file mode 100644 index 0000000..19a5c8c --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Type/Mapping.php @@ -0,0 +1,206 @@ + + * @link http://www.elasticsearch.org/guide/reference/mapping/ + */ +class Elastica_Type_Mapping +{ + /** + * Mapping + * + * @var array Mapping + */ + protected $_mapping = array(); + + /** + * Type + * + * @var Elastica_Type Type object + */ + protected $_type = null; + + /** + * Construct Mapping + * + * @param Elastica_Type $type OPTIONAL Type object + * @param array $properties OPTIONAL Properties + */ + public function __construct(Elastica_Type $type = null, array $properties = array()) + { + if ($type) { + $this->setType($type); + } + + if (!empty($properties)) { + $this->setProperties($properties); + } + } + + /** + * Sets the mapping type + * Enter description here ... + * @param Elastica_Type $type Type object + * @return Elastica_Type_Mapping Current object + */ + public function setType(Elastica_Type $type) + { + $this->_type = $type; + + return $this; + } + + /** + * Sets the mapping properites + * + * @param array $properties Prpoerties + * @return Elastica_Type_Mapping Mapping object + */ + public function setProperties(array $properties) + { + return $this->setParam('properties', $properties); + } + + /** + * Returns mapping type + * + * @return Elastica_Type Type + */ + public function getType() + { + return $this->_type; + } + + /** + * Sets source values + * + * To disable source, argument is + * array('enabled' => false) + * + * @param array $source Source array + * @return Elastica_Type_Mapping Current object + * @link http://www.elasticsearch.org/guide/reference/mapping/source-field.html + */ + public function setSource(array $source) + { + return $this->setParam('_source', $source); + } + + /** + * Disables the source in the index + * + * Param can be set to true to enable again + * + * @param bool $enabled OPTIONAL (default = false) + * @return Elastica_Type_Mapping Current object + */ + public function disableSource($enabled = false) + { + return $this->setSource(array('enabled' => $enabled)); + } + + /** + * Sets raw parameters + * + * Possible options: + * _uid + * _id + * _type + * _source + * _all + * _analyzer + * _boost + * _parent + * _routing + * _index + * _size + * properties + * + * @param string $key Key name + * @param mixed $value Key value + * @return Elastica_Type_Mapping Current object + */ + public function setParam($key, $value) + { + $this->_mapping[$key] = $value; + + return $this; + } + + /** + * Set TTL + * + * @param array $params TTL Params (enabled, default, ...) + * @return Elastica_Type_Mapping + */ + public function setTtl(array $params) + { + return $this->setParam('_ttl', $params); + + } + + /** + * Enables TTL for all documens in this type + * + * @param bool $enabled OPTIONAL (default = true) + * @return Elastica_Type_Mapping + */ + public function enableTtl($enabled = true) + { + return $this->setTTL(array('enabled' => $enabled)); + } + + /** + * Converts the mapping to an array + * + * @return array Mapping as array + */ + public function toArray() + { + $type = $this->getType(); + + if (empty($type)) { + throw new Elastica_Exception_Invalid('Type has to be set'); + } + + return array($type->getType() => $this->_mapping); + } + + /** + * Submits the mapping and sends it to the server + * + * @return Elastica_Response Response object + */ + public function send() + { + $path = '_mapping'; + + return $this->getType()->request($path, Elastica_Request::PUT, $this->toArray()); + } + + /** + * Creates a mapping object + * + * @param array|Elastica_Type_Mapping $mapping Mapping object or properties array + * @return Elastica_Type_Mapping Mapping object + * @throws Elastica_Exception_Invalid If invalid type + */ + public static function create($mapping) + { + if (is_array($mapping)) { + $mappingObject = new Elastica_Type_Mapping(); + $mappingObject->setProperties($mapping); + } else { + $mappingObject = $mapping; + } + + if (!$mappingObject instanceof Elastica_Type_Mapping) { + throw new Elastica_Exception_Invalid('Invalid object type'); + } + + return $mappingObject; + } +} diff --git a/modules/thirdparty/elastica/lib/Elastica/Util.php b/modules/thirdparty/elastica/lib/Elastica/Util.php new file mode 100644 index 0000000..acf8fc5 --- /dev/null +++ b/modules/thirdparty/elastica/lib/Elastica/Util.php @@ -0,0 +1,116 @@ + + * @author Thibault Duplessis + * @author Oleg Zinchenko + */ +class Elastica_Util +{ + /** + * Replace the following reserved words: AND OR NOT + * and + * escapes the following terms: + - && || ! ( ) { } [ ] ^ " ~ * ? : \ + * + * @param string $term Query term to replare and escape + * @return string Replaced and escaped query term + * @link http://lucene.apache.org/java/2_4_0/queryparsersyntax.html#Boolean%20operators + * @link http://lucene.apache.org/java/2_4_0/queryparsersyntax.html#Escaping%20Special%20Characters + */ + public static function replaceBooleanWordsAndEscapeTerm($term) + { + $result = $term; + $result = self::replaceBooleanWords($result); + $result = self::escapeTerm($result); + + return $result; + } + + /** + * Escapes the following terms (because part of the query language) + * + - && || ! ( ) { } [ ] ^ " ~ * ? : \ + * + * @param string $term Query term to escape + * @return string Escaped query term + * @link http://lucene.apache.org/java/2_4_0/queryparsersyntax.html#Escaping%20Special%20Characters + */ + public static function escapeTerm($term) + { + $result = $term; + // \ escaping has to be first, otherwise escaped later once again + $chars = array('\\', '+', '-', '&&', '||', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':'); + + foreach ($chars as $char) { + $result = str_replace($char, '\\' . $char, $result); + } + + return $result; + } + + /** + * Replace the following reserved words (because part of the query language) + * AND OR NOT + * + * @param string $term Query term to replace + * @return string Replaced query term + * @link http://lucene.apache.org/java/2_4_0/queryparsersyntax.html#Boolean%20operators + */ + public static function replaceBooleanWords($term) + { + $replacementMap = array('AND'=>'&&', 'OR'=>'||', 'NOT'=>'!'); + $result = strtr($term, $replacementMap); + + return $result; + } + + /** + * Converts a snake_case string to CamelCase + * + * For example: hello_world to HelloWorld + * + * @param string $string snake_case string + * @return string CamelCase string + */ + public static function toCamelCase($string) + { + return str_replace(" ", "", ucwords(str_replace("_", " ", $string))); + } + + /** + * Converts a CamelCase string to snake_case + * + * For Example HelloWorld to hello_world + * + * @param string $string CamelCase String to Convert + * @return string SnakeCase string + */ + public static function toSnakeCase($string) + { + $string = preg_replace('/([A-Z])/', '_$1', $string); + + return strtolower(substr($string,1)); + } + + /** + * Converts given time to format: 1995-12-31T23:59:59Z + * + * This is the lucene date format + * + * @param int $date Date input (could be string etc.) -> must be supported by strtotime + * @return string Converted date string + */ + public static function convertDate($date) + { + if (is_int($date)) { + $timestamp = $date; + } else { + $timestamp = strtotime($date); + } + $string = date('Y-m-d\TH:i:s\Z', $timestamp); + + return $string; + } +} diff --git a/modules/thirdparty/elastica/phpdoc.dist.xml b/modules/thirdparty/elastica/phpdoc.dist.xml new file mode 100644 index 0000000..73d161f --- /dev/null +++ b/modules/thirdparty/elastica/phpdoc.dist.xml @@ -0,0 +1,13 @@ + + + Elastica + + ./build/api + + + ./build/api + + + ./lib + + diff --git a/modules/thirdparty/elastica/test/benchmark/BulkMemoryUsageTest.php b/modules/thirdparty/elastica/test/benchmark/BulkMemoryUsageTest.php new file mode 100644 index 0000000..d2f021a --- /dev/null +++ b/modules/thirdparty/elastica/test/benchmark/BulkMemoryUsageTest.php @@ -0,0 +1,44 @@ +getIndex('test'); + $index->create(array(), true); + $type = $index->getType('test'); + + $data = array( + 'text1' => 'Very long text for a string', + 'text2' => 'But this is not very long', + 'text3' => 'random or not random?', + ); + + $startMemory = memory_get_usage(); + + for ($n = 1; $n < 10; $n++) { + $docs = array(); + + for ($i = 1; $i <= 3000; $i++) { + $docs[] = new Elastica_Document(uniqid(), $data); + } + + $type->addDocuments($docs); + $docs = array(); + } + + unset($docs); + + $endMemory = memory_get_usage(); + + $this->assertLessThan(1.1, $endMemory/$startMemory); + } +} diff --git a/modules/thirdparty/elastica/test/benchmark/ClientTest.php b/modules/thirdparty/elastica/test/benchmark/ClientTest.php new file mode 100644 index 0000000..3221beb --- /dev/null +++ b/modules/thirdparty/elastica/test/benchmark/ClientTest.php @@ -0,0 +1,29 @@ +getIndex('test'); + $index->create(array(), true); + $type = $index->getType('test'); + + $start = microtime(true); + + for ($i = 1; $i <= 10000; $i++) { + $doc = new Elastica_Document($i, array('test' => 1)); + $type->addDocument($doc); + } + + // Refresh index + $index->refresh(); + + $end = microtime(true); + + //echo $end - $start; + + } +} diff --git a/modules/thirdparty/elastica/test/bin/install_php_memcache.sh b/modules/thirdparty/elastica/test/bin/install_php_memcache.sh new file mode 100755 index 0000000..da9288e --- /dev/null +++ b/modules/thirdparty/elastica/test/bin/install_php_memcache.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Build and install PHP Memcache extension +wget http://pecl.php.net/get/memcache-2.2.6.tgz +tar -xzf memcache-2.2.6.tgz +sh -c "cd memcache-2.2.6 && phpize && ./configure --enable-memcache && make && sudo make install" +echo "extension=memcache.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` diff --git a/modules/thirdparty/elastica/test/bin/run_elasticsearch.sh b/modules/thirdparty/elastica/test/bin/run_elasticsearch.sh new file mode 100755 index 0000000..0d25946 --- /dev/null +++ b/modules/thirdparty/elastica/test/bin/run_elasticsearch.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +wget https://github.com/downloads/elasticsearch/elasticsearch/elasticsearch-0.19.3.tar.gz +tar -xzf elasticsearch-0.19.3.tar.gz +sed 's/# index.number_of_shards: 1/index.number_of_shards: 2/' elasticsearch-0.19.3/config/elasticsearch.yml > elasticsearch-0.19.3/config/elasticsearch.yml +sed 's/# index.number_of_replicas: 0/index.number_of_replicas: 0/' elasticsearch-0.19.3/config/elasticsearch.yml > elasticsearch-0.19.3/config/elasticsearch.yml +sed 's/# discovery.zen.ping.multicast.enabled: false/discovery.zen.ping.multicast.enabled: false/' elasticsearch-0.19.3/config/elasticsearch.yml > elasticsearch-0.19.3/config/elasticsearch.yml +elasticsearch-0.19.3/bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/1.4.0 + +export JAVA_OPTS="-server" +elasticsearch-0.19.3/bin/elasticsearch & + +echo "Waiting until elasticsearch is ready on port 9200" +while [[ -z `curl -s 'http://localhost:9200' ` ]] +do + echo -n "." + sleep 2s +done + +echo "elasticsearch is up" diff --git a/modules/thirdparty/elastica/test/bootstrap.php b/modules/thirdparty/elastica/test/bootstrap.php new file mode 100755 index 0000000..ea56496 --- /dev/null +++ b/modules/thirdparty/elastica/test/bootstrap.php @@ -0,0 +1,20 @@ + $host, 'port' => $port)); + + $this->assertEquals($host, $client->getHost()); + $this->assertEquals($port, $client->getPort()); + } + + public function testDefaults() + { + $client = new Elastica_Client(); + + $this->assertEquals(Elastica_Client::DEFAULT_HOST, 'localhost'); + $this->assertEquals(Elastica_Client::DEFAULT_PORT, 9200); + $this->assertEquals(Elastica_Client::DEFAULT_TRANSPORT, 'Http'); + + $this->assertEquals(Elastica_Client::DEFAULT_HOST, $client->getHost()); + $this->assertEquals(Elastica_Client::DEFAULT_PORT, $client->getPort()); + $this->assertEquals(Elastica_Client::DEFAULT_TRANSPORT, $client->getTransport()); + } + + public function testServersArray() + { + // Creates a new index 'xodoa' and a type 'user' inside this index + $client = new Elastica_Client(array('servers' => array(array('host' => 'localhost', 'port' => 9200)))); + $index = $client->getIndex('elastica_test1'); + $index->create(array(), true); + + $type = $index->getType('user'); + + // Adds 1 document to the index + $doc1 = new Elastica_Document(1, + array('username' => 'hans', 'test' => array('2', '3', '5')) + ); + $type->addDocument($doc1); + + // Adds a list of documents with _bulk upload to the index + $docs = array(); + $docs[] = new Elastica_Document(2, + array('username' => 'john', 'test' => array('1', '3', '6')) + ); + $docs[] = new Elastica_Document(3, + array('username' => 'rolf', 'test' => array('2', '3', '7')) + ); + $type->addDocuments($docs); + + // Refresh index + $index->refresh(); + + $resultSet = $type->search('rolf'); + } + + public function testTwoServersSame() + { + // Creates a new index 'xodoa' and a type 'user' inside this index + $client = new Elastica_Client(array('servers' => array( + array('host' => 'localhost', 'port' => 9200), + array('host' => 'localhost', 'port' => 9200), + ))); + $index = $client->getIndex('elastica_test1'); + $index->create(array(), true); + + $type = $index->getType('user'); + + // Adds 1 document to the index + $doc1 = new Elastica_Document(1, + array('username' => 'hans', 'test' => array('2', '3', '5')) + ); + $type->addDocument($doc1); + + // Adds a list of documents with _bulk upload to the index + $docs = array(); + $docs[] = new Elastica_Document(2, + array('username' => 'john', 'test' => array('1', '3', '6')) + ); + $docs[] = new Elastica_Document(3, + array('username' => 'rolf', 'test' => array('2', '3', '7')) + ); + $type->addDocuments($docs); + + // Refresh index + $index->refresh(); + + $resultSet = $type->search('rolf'); + } + + public function testBulk() + { + $client = new Elastica_Client(); + + $params = array( + array('index' => array('_index' => 'test', '_type' => 'user', '_id' => '1')), + array('user' => array('name' => 'hans')), + array('index' => array('_index' => 'test', '_type' => 'user', '_id' => '2')), + array('user' => array('name' => 'peter')), + ); + + $client->bulk($params); + } + + public function testOptimizeAll() + { + $client = new Elastica_Client(); + $response = $client->optimizeAll(); + + $this->assertFalse($response->hasError()); + } + + public function testAddDocumentsEmpty() + { + $client = new Elastica_Client(); + try { + $client->addDocuments(array()); + $this->fail('Should throw exception'); + } catch (Elastica_Exception_Invalid $e) { + $this->assertTrue(true); + } + } + + /** + * Test deleteIds method using string parameters + * + * This test ensures that the deleteIds method of + * the Elastica_Client can properly accept and use + * an $index parameter and $type parameter that are + * strings + * + * This test is a bit more verbose than just sending the + * values to deleteIds and checking for exceptions or + * warnings. + * + * It will add a document, search for it, then delete it + * using the parameter types we are interested in, and then + * re-search to verify that they have been deleted + */ + public function testDeleteIdsIdxStringTypeString() + { + $data = array('username' => 'hans'); + $userSearch = 'username:hans'; + + $index = $this->_createIndex(); + + // Create the index, deleting it first if it already exists + $index->create(array(), true); + $type = $index->getType('user'); + + // Adds 1 document to the index + $doc = new Elastica_Document(null, $data); + $result = $type->addDocument($doc); + + // Refresh index + $index->refresh(); + + $resultData = $result->getData(); + $ids = array($resultData['_id']); + + // Check to make sure the document is in the index + $resultSet = $type->search($userSearch); + $totalHits = $resultSet->getTotalHits(); + $this->assertEquals(1, $totalHits); + + // And verify that the variables we are doing to send to + // deleteIds are the type we are testing for + $idxString = $index->getName(); + $typeString = $type->getName(); + $this->assertEquals(true, is_string($idxString)); + $this->assertEquals(true, is_string($typeString)); + + // Using the existing $index and $type variables which + // are Elastica_Index and Elastica_Type objects respectively + $resp = $index->getClient()->deleteIds($ids, $index, $type); + + // Refresh the index to clear out deleted ID information + $index->refresh(); + + // Research the index to verify that the items have been deleted + $resultSet = $type->search($userSearch); + $totalHits = $resultSet->getTotalHits(); + $this->assertEquals(0, $totalHits); + } + + /** + * Test deleteIds method using string parameter for $index + * and object parameter for $type + * + * This test ensures that the deleteIds method of + * the Elastica_Client can properly accept and use + * an $index parameter that is a string and a $type + * parameter that is of type Elastica_Type + * + * This test is a bit more verbose than just sending the + * values to deleteIds and checking for exceptions or + * warnings. + * + * It will add a document, search for it, then delete it + * using the parameter types we are interested in, and then + * re-search to verify that they have been deleted + */ + public function testDeleteIdsIdxStringTypeObject() + { + $data = array('username' => 'hans'); + $userSearch = 'username:hans'; + + $index = $this->_createIndex(); + + // Create the index, deleting it first if it already exists + $index->create(array(), true); + $type = $index->getType('user'); + + // Adds 1 document to the index + $doc = new Elastica_Document(null, $data); + $result = $type->addDocument($doc); + + // Refresh index + $index->refresh(); + + $resultData = $result->getData(); + $ids = array($resultData['_id']); + + // Check to make sure the document is in the index + $resultSet = $type->search($userSearch); + $totalHits = $resultSet->getTotalHits(); + $this->assertEquals(1, $totalHits); + + // And verify that the variables we are doing to send to + // deleteIds are the type we are testing for + $idxString = $index->getName(); + $this->assertEquals(true, is_string($idxString)); + $this->assertEquals(true, ($type instanceof Elastica_Type)); + + // Using the existing $index and $type variables which + // are Elastica_Index and Elastica_Type objects respectively + $resp = $index->getClient()->deleteIds($ids, $index, $type); + + // Refresh the index to clear out deleted ID information + $index->refresh(); + + // Research the index to verify that the items have been deleted + $resultSet = $type->search($userSearch); + $totalHits = $resultSet->getTotalHits(); + $this->assertEquals(0, $totalHits); + } + + /** + * Test deleteIds method using object parameter for $index + * and string parameter for $type + * + * This test ensures that the deleteIds method of + * the Elastica_Client can properly accept and use + * an $index parameter that is of type Elasitca_Index + * and a $type parameter that is a string + * + * This test is a bit more verbose than just sending the + * values to deleteIds and checking for exceptions or + * warnings. + * + * It will add a document, search for it, then delete it + * using the parameter types we are interested in, and then + * re-search to verify that they have been deleted + */ + public function testDeleteIdsIdxObjectTypeString() + { + $data = array('username' => 'hans'); + $userSearch = 'username:hans'; + + $index = $this->_createIndex(); + + // Create the index, deleting it first if it already exists + $index->create(array(), true); + $type = $index->getType('user'); + + // Adds 1 document to the index + $doc = new Elastica_Document(null, $data); + $result = $type->addDocument($doc); + + // Refresh index + $index->refresh(); + + $resultData = $result->getData(); + $ids = array($resultData['_id']); + + // Check to make sure the document is in the index + $resultSet = $type->search($userSearch); + $totalHits = $resultSet->getTotalHits(); + $this->assertEquals(1, $totalHits); + + // And verify that the variables we are doing to send to + // deleteIds are the type we are testing for + $typeString = $type->getName(); + $this->assertEquals(true, ($index instanceof Elastica_Index)); + $this->assertEquals(true, is_string($typeString)); + + // Using the existing $index and $type variables which + // are Elastica_Index and Elastica_Type objects respectively + $resp = $index->getClient()->deleteIds($ids, $index, $type); + + // Refresh the index to clear out deleted ID information + $index->refresh(); + + // Research the index to verify that the items have been deleted + $resultSet = $type->search($userSearch); + $totalHits = $resultSet->getTotalHits(); + $this->assertEquals(0, $totalHits); + } + + /** + * Test deleteIds method using object parameter for $index + * and object parameter for $type + * + * This test ensures that the deleteIds method of + * the Elastica_Client can properly accept and use + * an $index parameter that is an object and a $type + * parameter that is of type Elastica_Type + * + * This test is a bit more verbose than just sending the + * values to deleteIds and checking for exceptions or + * warnings. + * + * It will add a document, search for it, then delete it + * using the parameter types we are interested in, and then + * re-search to verify that they have been deleted + */ + public function testDeleteIdsIdxObjectTypeObject() + { + $data = array('username' => 'hans'); + $userSearch = 'username:hans'; + + $index = $this->_createIndex(); + + // Create the index, deleting it first if it already exists + $index->create(array(), true); + $type = $index->getType('user'); + + // Adds 1 document to the index + $doc = new Elastica_Document(null, $data); + $result = $type->addDocument($doc); + + // Refresh index + $index->refresh(); + + $resultData = $result->getData(); + $ids = array($resultData['_id']); + + // Check to make sure the document is in the index + $resultSet = $type->search($userSearch); + $totalHits = $resultSet->getTotalHits(); + $this->assertEquals(1, $totalHits); + + // And verify that the variables we are doing to send to + // deleteIds are the type we are testing for + $this->assertEquals(true, ($index instanceof Elastica_Index)); + $this->assertEquals(true, ($type instanceof Elastica_Type)); + + // Using the existing $index and $type variables which + // are Elastica_Index and Elastica_Type objects respectively + $resp = $index->getClient()->deleteIds($ids, $index, $type); + + // Refresh the index to clear out deleted ID information + $index->refresh(); + + // Research the index to verify that the items have been deleted + $resultSet = $type->search($userSearch); + $totalHits = $resultSet->getTotalHits(); + $this->assertEquals(0, $totalHits); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Cluster/SettingsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Cluster/SettingsTest.php new file mode 100644 index 0000000..96152c5 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Cluster/SettingsTest.php @@ -0,0 +1,88 @@ +_createIndex(); + $settings = new Elastica_Cluster_Settings($index->getClient()); + + $settings->setTransient('discovery.zen.minimum_master_nodes', 2); + $data = $settings->get(); + $this->assertEquals(2, $data['transient']['discovery.zen.minimum_master_nodes']); + + $settings->setTransient('discovery.zen.minimum_master_nodes', 1); + $data = $settings->get(); + $this->assertEquals(1, $data['transient']['discovery.zen.minimum_master_nodes']); + } + + public function testSetPersistent() + { + $index = $this->_createIndex(); + $settings = new Elastica_Cluster_Settings($index->getClient()); + + $settings->setPersistent('discovery.zen.minimum_master_nodes', 2); + $data = $settings->get(); + $this->assertEquals(2, $data['persistent']['discovery.zen.minimum_master_nodes']); + + $settings->setPersistent('discovery.zen.minimum_master_nodes', 1); + $data = $settings->get(); + $this->assertEquals(1, $data['persistent']['discovery.zen.minimum_master_nodes']); + } + + public function testSetReadOnly() + { + // Create two indices to check that the complete cluster is read only + $index1 = $this->_createIndex('test1'); + $index2 = $this->_createIndex('test2'); + + $settings = new Elastica_Cluster_Settings($index1->getClient()); + + $doc = new Elastica_Document(null, array('hello' => 'world')); + + // Check that adding documents work + $index1->getType('test')->addDocument($doc); + $index2->getType('test')->addDocument($doc); + + $response = $settings->setReadOnly(true); + $this->assertFalse($response->hasError()); + $setting = $settings->getTransient('cluster.blocks.read_only'); + $this->assertEquals('true', $setting); + + // Make sure both index are read only + try { + $index1->getType('test')->addDocument($doc); + $this->fail('should throw read only exception'); + } catch (Elastica_Exception_Response $e) { + $message = $e->getMessage(); + $this->assertContains('ClusterBlockException', $message); + $this->assertContains('cluster read-only', $message); + } + + try { + $index2->getType('test')->addDocument($doc); + $this->fail('should throw read only exception'); + } catch (Elastica_Exception_Response $e) { + $message = $e->getMessage(); + $this->assertContains('ClusterBlockException', $message); + $this->assertContains('cluster read-only', $message); + } + + $response = $settings->setReadOnly(false); + $this->assertFalse($response->hasError()); + $setting = $settings->getTransient('cluster.blocks.read_only'); + $this->assertEquals('false', $setting); + + // Check that adding documents works again + $index1->getType('test')->addDocument($doc); + $index2->getType('test')->addDocument($doc); + + $index1->refresh(); + $index2->refresh(); + + // 2 docs should be in each index + $this->assertEquals(2, $index1->count()); + $this->assertEquals(2, $index2->count()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/ClusterTest.php b/modules/thirdparty/elastica/test/lib/Elastica/ClusterTest.php new file mode 100644 index 0000000..304e6da --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/ClusterTest.php @@ -0,0 +1,80 @@ +getNodeNames(); + + $this->assertInternalType('array', $names); + $this->assertGreaterThan(0, count($names)); + } + + public function testGetNodes() + { + $client = new Elastica_Client(); + $cluster = $client->getCluster(); + + $nodes = $cluster->getNodes(); + + foreach ($nodes as $node) { + $this->assertInstanceOf('Elastica_Node', $node); + } + + $this->assertGreaterThan(0, count($nodes)); + } + + public function testGetState() + { + $client = new Elastica_Client(); + $cluster = $client->getCluster(); + $state = $cluster->getState(); + $this->assertInternalType('array', $state); + } + + public function testShutdown() + { + $this->markTestSkipped('This test shuts down the cluster which means the following tests would not work'); + $client = new Elastica_Client(); + $cluster = $client->getCluster(); + + $cluster->shutdown('2s'); + + sleep(5); + + try { + $client->getStatus(); + $this->fail('Should throw exception because cluster is shut down'); + } catch (Elastica_Exception_Client $e) { + $this->assertTrue(true); + } + } + + public function testGetIndexNames() + { + $client = new Elastica_Client(); + $cluster = $client->getCluster(); + + $indexName = 'elastica_test999'; + $index = $this->_createIndex($indexName); + $index->delete(); + $cluster->refresh(); + + // Checks that index does not exist + $indexNames = $cluster->getIndexNames(); + $this->assertNotContains($index->getName(), $indexNames); + + $index = $this->_createIndex($indexName); + $cluster->refresh(); + + // Now index should exist + $indexNames = $cluster->getIndexNames(); + $this->assertContains($index->getname(), $indexNames); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/DocumentTest.php b/modules/thirdparty/elastica/test/lib/Elastica/DocumentTest.php new file mode 100644 index 0000000..aa195ea --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/DocumentTest.php @@ -0,0 +1,49 @@ +add('key', 'value'); + $data = $doc->getData(); + $this->assertArrayHasKey('key', $data); + $this->assertEquals('value', $data['key']); + $this->assertInstanceOf('Elastica_Document', $returnValue); + } + + public function testAddFile() + { + $doc = new Elastica_Document(); + $returnValue = $doc->addFile('key', '/dev/null'); + $this->assertInstanceOf('Elastica_Document', $returnValue); + } + + public function testAddGeoPoint() + { + $doc = new Elastica_Document(); + $returnValue = $doc->addGeoPoint('point', 38.89859, -77.035971); + $this->assertInstanceOf('Elastica_Document', $returnValue); + } + + public function testSetData() + { + $doc = new Elastica_Document(); + $returnValue = $doc->setData(array('data')); + $this->assertInstanceOf('Elastica_Document', $returnValue); + } + + public function testToArray() + { + $id = 17; + $data = array('hello' => 'world'); + $type = 'testtype'; + $index = 'textindex'; + + $doc = new Elastica_Document($id, $data, $type, $index); + + $result = array('_index' => $index, '_type' => $type, '_id' => $id, '_source' => $data); + $this->assertEquals($result, $doc->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/ExampleTest.php b/modules/thirdparty/elastica/test/lib/Elastica/ExampleTest.php new file mode 100755 index 0000000..fb4742a --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/ExampleTest.php @@ -0,0 +1,39 @@ +getIndex('elastica_test'); + $index->create(array(), true); + + $type = $index->getType('user'); + + // Adds 1 document to the index + $doc1 = new Elastica_Document(1, + array('username' => 'hans', 'test' => array('2', '3', '5')) + ); + $type->addDocument($doc1); + + // Adds a list of documents with _bulk upload to the index + $docs = array(); + $docs[] = new Elastica_Document(2, + array('username' => 'john', 'test' => array('1', '3', '6')) + ); + $docs[] = new Elastica_Document(3, + array('username' => 'rolf', 'test' => array('2', '3', '7')) + ); + $type->addDocuments($docs); + + // Refresh index + $index->refresh(); + + $resultSet = $type->search('rolf'); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Exception/NotImplementedTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Exception/NotImplementedTest.php new file mode 100644 index 0000000..a88236c --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Exception/NotImplementedTest.php @@ -0,0 +1,20 @@ +assertInstanceOf('Elastica_Exception_NotImplemented', $exception); + $this->assertInstanceOf('Elastica_Exception_Abstract', $exception); + $this->assertInstanceOf('Exception', $exception); + + $this->assertEquals($message, $exception->getMessage()); + $this->assertEquals($code, $exception->getCode()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Facet/DateHistogramTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Facet/DateHistogramTest.php new file mode 100644 index 0000000..9e2fa16 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Facet/DateHistogramTest.php @@ -0,0 +1,52 @@ +assertInstanceOf('Elastica_Facet_Histogram', $facet); + $this->assertInstanceOf('Elastica_Facet_Abstract', $facet); + unset($facet); + } + + public function testTest() + { + $client = new Elastica_Client(); + $index = $client->getIndex('test'); + $index->create(array(), true); + $type = $index->getType('helloworld'); + + $mapping = new Elastica_Type_Mapping($type, array( + 'name' => array('type' => 'string', 'store' => 'no'), + 'dtmPosted' => array('type' => 'date', 'store' => 'no', 'format' => 'yyyy-MM-dd HH:mm:ss') + )); + $type->setMapping($mapping); + + $doc = new Elastica_Document(1, array('name' => 'nicolas ruflin', 'dtmPosted' => "2011-06-23 21:53:00")); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('name' => 'raul martinez jr', 'dtmPosted' => "2011-06-23 09:53:00")); + $type->addDocument($doc); + $doc = new Elastica_Document(3, array('name' => 'rachelle clemente', 'dtmPosted' => "2011-07-08 08:53:00")); + $type->addDocument($doc); + $doc = new Elastica_Document(4, array('name' => 'elastica search', 'dtmPosted' => "2011-07-08 01:53:00")); + $type->addDocument($doc); + + $facet = new Elastica_Facet_DateHistogram('dateHist1'); + $facet->setInterval("day"); + $facet->setField("dtmPosted"); + + $query = new Elastica_Query(); + $query->addFacet($facet); + $query->setQuery(new Elastica_Query_MatchAll()); + $index->refresh(); + + $response = $type->search($query); + $facets = $response->getFacets(); + + $this->assertEquals(4, $response->getTotalHits()); + $this->assertEquals(2, count($facets['dateHist1']['entries'])); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Facet/FilterTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Facet/FilterTest.php new file mode 100644 index 0000000..a163c05 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Facet/FilterTest.php @@ -0,0 +1,34 @@ +getIndex('test'); + $index->create(array(), true); + $type = $index->getType('helloworld'); + + $type->addDocument(new Elastica_Document(1, array('color' => 'red'))); + $type->addDocument(new Elastica_Document(2, array('color' => 'green'))); + $type->addDocument(new Elastica_Document(3, array('color' => 'blue'))); + + $index->refresh(); + + $filter = new Elastica_Filter_Term(array('color' => 'red')); + + $facet = new Elastica_Facet_Filter('test'); + $facet->setFilter($filter); + + $query = new Elastica_Query(); + $query->addFacet($facet); + + $resultSet = $type->search($query); + + $facets = $resultSet->getFacets(); + + $this->assertEquals(1, $facets['test']['count']); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Facet/QueryTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Facet/QueryTest.php new file mode 100644 index 0000000..06b8610 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Facet/QueryTest.php @@ -0,0 +1,34 @@ +getIndex('test'); + $index->create(array(), true); + $type = $index->getType('helloworld'); + + $type->addDocument(new Elastica_Document(1, array('color' => 'red'))); + $type->addDocument(new Elastica_Document(2, array('color' => 'green'))); + $type->addDocument(new Elastica_Document(3, array('color' => 'blue'))); + + $index->refresh(); + + $termQuery = new Elastica_Query_Term(array('color' => 'red')); + + $facet = new Elastica_Facet_Query('test'); + $facet->setQuery($termQuery); + + $query = new Elastica_Query(); + $query->addFacet($facet); + + $resultSet = $type->search($query); + + $facets = $resultSet->getFacets(); + + $this->assertEquals(1, $facets['test']['count']); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Facet/StatisticalTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Facet/StatisticalTest.php new file mode 100644 index 0000000..2679fd0 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Facet/StatisticalTest.php @@ -0,0 +1,73 @@ +getIndex('test'); + $index->create(array(), true); + $type = $index->getType('helloworld'); + + $doc = new Elastica_Document(1, array('price' => 10)); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('price' => 35)); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('price' => 45)); + $type->addDocument($doc); + + $facet = new Elastica_Facet_Statistical('stats'); + $facet->setField('price'); + + $query = new Elastica_Query(); + $query->addFacet($facet); + $query->setQuery(new Elastica_Query_MatchAll()); + + $index->refresh(); + + $response = $type->search($query); + $facets = $response->getFacets(); + + $this->assertEquals(55, $facets['stats']['total']); + $this->assertEquals(10, $facets['stats']['min']); + $this->assertEquals(45, $facets['stats']['max']); + } + + public function testStatisticalWithSetFields() + { + $client = new Elastica_Client(); + $index = $client->getIndex('test'); + $index->create(array(), true); + $type = $index->getType('helloworld'); + + $doc = new Elastica_Document(1, array('price' => 10, 'price2' => 20)); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('price' => 35, 'price2' => 70)); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('price' => 45, 'price2' => 90)); + $type->addDocument($doc); + + $facet = new Elastica_Facet_Statistical('stats'); + $facet->setFields(array('price','price2')); + + $query = new Elastica_Query(); + $query->addFacet($facet); + $query->setQuery(new Elastica_Query_MatchAll()); + + $index->refresh(); + + $response = $type->search($query); + $facets = $response->getFacets(); + + $this->assertEquals(165, $facets['stats']['total']); + $this->assertEquals(10, $facets['stats']['min']); + $this->assertEquals(90, $facets['stats']['max']); + } + + public function testStatisticalWithSetScript() + { + $this->markTestIncomplete('Test for setting the script value'); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Facet/TermsStatsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Facet/TermsStatsTest.php new file mode 100644 index 0000000..ce7bd5e --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Facet/TermsStatsTest.php @@ -0,0 +1,63 @@ +getIndex( 'test' ); + $index->create( array( ), true ); + $type = $index->getType( 'helloworld' ); + + $doc = new Elastica_Document( 1, array( 'name' => 'tom', 'paid' => 7 ) ); + $type->addDocument( $doc ); + $doc = new Elastica_Document( 2, array( 'name' => 'tom', 'paid' => 2 ) ); + $type->addDocument( $doc ); + $doc = new Elastica_Document( 3, array( 'name' => 'tom', 'paid' => 5 ) ); + $type->addDocument( $doc ); + $doc = new Elastica_Document( 4, array( 'name' => 'mike', 'paid' => 13 ) ); + $type->addDocument( $doc ); + $doc = new Elastica_Document( 5, array( 'name' => 'mike', 'paid' => 1 ) ); + $type->addDocument( $doc ); + $doc = new Elastica_Document( 6, array( 'name' => 'mike', 'paid' => 15 ) ); + $type->addDocument( $doc ); + + $facet = new Elastica_Facet_TermsStats( 'test' ); + $facet->setKeyField( 'name' ); + $facet->setValueField( 'paid' ); + + $query = new Elastica_Query(); + $query->addFacet( $facet ); + $query->setQuery( new Elastica_Query_MatchAll() ); + + $index->refresh(); + + $response = $type->search( $query ); + $facets = $response->getFacets(); + + $this->assertEquals( 2, count( $facets[ 'test' ][ 'terms' ] ) ); + foreach ($facets[ 'test' ][ 'terms' ] as $facet) { + if ($facet[ 'term' ] === 'tom') { + $this->assertEquals( 14, $facet[ 'total' ] ); + } + if ($facet[ 'term' ] === 'mike') { + $this->assertEquals( 29, $facet[ 'total' ] ); + } + } + } + +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Facet/TermsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Facet/TermsTest.php new file mode 100644 index 0000000..2d820ee --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Facet/TermsTest.php @@ -0,0 +1,35 @@ +getIndex('test'); + $index->create(array(), true); + $type = $index->getType('helloworld'); + + $doc = new Elastica_Document(1, array('name' => 'nicolas ruflin')); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('name' => 'ruflin test')); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('name' => 'nicolas helloworld')); + $type->addDocument($doc); + + $facet = new Elastica_Facet_Terms('test'); + $facet->setField('name'); + + $query = new Elastica_Query(); + $query->addFacet($facet); + $query->setQuery(new Elastica_Query_MatchAll()); + + $index->refresh(); + + $response = $type->search($query); + $facets = $response->getFacets(); + + $this->assertEquals(3, count($facets['test']['terms'])); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/Abstract/MultiTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/Abstract/MultiTest.php new file mode 100644 index 0000000..f7b1604 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/Abstract/MultiTest.php @@ -0,0 +1,96 @@ +getStub(); + + $this->assertEmpty($stub->getFilters()); + } + + public function testAddFilter() + { + $stub = $this->getStub(); + + $filter = new Elastica_Filter_MatchAll(); + $stub->addFilter($filter); + + $expected = array( + $filter->toArray() + ); + + $this->assertEquals($expected, $stub->getFilters()); + } + + public function testSetFilters() + { + $stub = $this->getStub(); + + $filter = new Elastica_Filter_MatchAll(); + $stub->setFilters(array($filter)); + + $expected = array( + $filter->toArray() + ); + + $this->assertEquals($expected, $stub->getFilters()); + } + + public function testToArray() + { + $stub = $this->getStub(); + + $filter = new Elastica_Filter_MatchAll(); + $stub->addFilter($filter); + + $expected = array( + $stub->getBaseName() => array( + $filter->toArray() + ) + ); + + $this->assertEquals($expected, $stub->toArray()); + } + + public function testToArrayWithParam() + { + $stub = $this->getStub(); + + $stub->setCached(true); + + $filter = new Elastica_Filter_MatchAll(); + $stub->addFilter($filter); + + $expected = array( + $stub->getBaseName() => array( + '_cache' => true, + 'filters' => array( + $filter->toArray() + ) + ) + ); + + $this->assertEquals($expected, $stub->toArray()); + } + + private function getStub() + { + return $this->getMockForAbstractClass('Elastica_Filter_Abstract_MultiDebug'); + } +} + +abstract class Elastica_Filter_Abstract_MultiDebug extends Elastica_Filter_Abstract_Multi +{ + public function getFilters() + { + return $this->_filters; + } + + public function getBaseName() + { + return parent::_getBaseName(); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/AbstractTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/AbstractTest.php new file mode 100644 index 0000000..b150b85 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/AbstractTest.php @@ -0,0 +1,67 @@ +getStub(); + + $stubFilter->setCached(true); + $arrayFilter = current($stubFilter->toArray()); + $this->assertTrue($arrayFilter['_cache']); + + $stubFilter->setCached(false); + $arrayFilter = current($stubFilter->toArray()); + $this->assertFalse($arrayFilter['_cache']); + } + + public function testSetCachedDefaultValue() + { + $stubFilter = $this->getStub(); + + $stubFilter->setCached(); + $arrayFilter = current($stubFilter->toArray()); + $this->assertTrue($arrayFilter['_cache']); + } + + public function testSetCacheKey() + { + $stubFilter = $this->getStub(); + + $cacheKey = 'myCacheKey'; + + $stubFilter->setCacheKey($cacheKey); + $arrayFilter = current($stubFilter->toArray()); + $this->assertEquals($cacheKey, $arrayFilter['_cache_key']); + } + + /** + * @expectedException Elastica_Exception_Invalid + */ + public function testSetCacheKeyEmptyKey() + { + $stubFilter = $this->getStub(); + + $cacheKey = ''; + + $stubFilter->setCacheKey($cacheKey); + } + + public function testSetName() + { + $stubFilter = $this->getStub(); + + $name = 'myFilter'; + + $stubFilter->setName($name); + $arrayFilter = current($stubFilter->toArray()); + $this->assertEquals($name, $arrayFilter['_name']); + } + + private function getStub() + { + return $this->getMockForAbstractClass('Elastica_Filter_Abstract'); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/AndTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/AndTest.php new file mode 100644 index 0000000..6027743 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/AndTest.php @@ -0,0 +1,60 @@ +assertEquals(array('and' => array()), $and->toArray()); + + $idsFilter = new Elastica_Filter_Ids(); + $idsFilter->setIds(12); + + $and->addFilter($idsFilter); + $and->addFilter($idsFilter); + + $expectedArray = array( + 'and' => array( + $idsFilter->toArray(), + $idsFilter->toArray() + ) + ); + + $this->assertEquals($expectedArray, $and->toArray()); + } + + public function testSetCache() + { + $client = new Elastica_Client(); + $index = $client->getIndex('test'); + $index->create(array(), true); + $type = $index->getType('test'); + + $doc = new Elastica_Document(1, array('name' => 'hello world')); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('name' => 'nicolas ruflin')); + $type->addDocument($doc); + $doc = new Elastica_Document(3, array('name' => 'ruflin')); + $type->addDocument($doc); + + $and = new Elastica_Filter_And(); + + $idsFilter1 = new Elastica_Filter_Ids(); + $idsFilter1->setIds(1); + + $idsFilter2 = new Elastica_Filter_Ids(); + $idsFilter2->setIds(1); + + $and->addFilter($idsFilter1); + $and->addFilter($idsFilter2); + + $index->refresh(); + $and->setCached(true); + + $resultSet = $type->search($and); + + $this->assertEquals(1, $resultSet->count()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/ExistsTests.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/ExistsTests.php new file mode 100644 index 0000000..dc35b20 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/ExistsTests.php @@ -0,0 +1,28 @@ + array('field' => $field)); + $this->assertEquals($expectedArray, $filter->toArray()); + } + + public function testSetField() + { + $field = 'test'; + $filter = new Elastica_Filter_Exists($field); + + $this->assertEquals($field, $filter->getParam('field')); + + $newField = 'hello world'; + $this->assertInstanceOf('Elastica_Filter_Exists', $filter->setField($newField)); + + $this->assertEquals($newField, $filter->getParam('field')); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/GeoDistanceTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/GeoDistanceTest.php new file mode 100755 index 0000000..8af5a22 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/GeoDistanceTest.php @@ -0,0 +1,147 @@ +getIndex('test'); + $index->create(array(), true); + + $type = $index->getType('test'); + + // Set mapping + $type->setMapping(array('point' => array('type' => 'geo_point'))); + + // Add doc 1 + $doc1 = new Elastica_Document(1, + array( + 'name' => 'ruflin', + ) + ); + + $doc1->addGeoPoint('point', 17, 19); + $type->addDocument($doc1); + + // Add doc 2 + $doc2 = new Elastica_Document(2, + array( + 'name' => 'ruflin', + ) + ); + + $doc2->addGeoPoint('point', 30, 40); + $type->addDocument($doc2); + + $index->optimize(); + $index->refresh(); + + // Only one point should be in radius + $query = new Elastica_Query(); + $geoFilter = new Elastica_Filter_GeoDistance('point', array('lat' => 30, 'lon' => 40), '1km'); + + $query = new Elastica_Query(new Elastica_Query_MatchAll()); + $query->setFilter($geoFilter); + $this->assertEquals(1, $type->search($query)->count()); + + // Both points should be inside + $query = new Elastica_Query(); + $geoFilter = new Elastica_Filter_GeoDistance('point', array('lat' => 30, 'lon' => 40), '40000km'); + $query = new Elastica_Query(new Elastica_Query_MatchAll()); + $query->setFilter($geoFilter); + $index->refresh(); + + $this->assertEquals(2, $type->search($query)->count()); + } + + public function testConstructLatlon() + { + $key = 'location'; + $location = array( + 'lat' => 48.86, + 'lon' => 2.35 + ); + $distance = '10km'; + + $filter = new Elastica_Filter_GeoDistance($key, $location, $distance); + + $expected = array( + 'geo_distance' => array( + $key => $location, + 'distance' => $distance + ) + ); + + $data = $filter->toArray(); + + $this->assertEquals($expected, $data); + } + + public function testConstructGeohash() + { + $key = 'location'; + $location = 'u09tvqx'; + $distance = '10km'; + + $filter = new Elastica_Filter_GeoDistance($key, $location, $distance); + + $expected = array( + 'geo_distance' => array( + $key => $location, + 'distance' => $distance + ) + ); + + $data = $filter->toArray(); + + $this->assertEquals($expected, $data); + } + + public function testConstructOldSignature() + { + $key = 'location'; + $latitude = 48.86; + $longitude = 2.35; + $distance = '10km'; + + $filter = new Elastica_Filter_GeoDistance($key, $latitude, $longitude, $distance); + + $expected = array( + 'geo_distance' => array( + $key => array( + 'lat' => $latitude, + 'lon' => $longitude + ), + 'distance' => $distance + ) + ); + + $data = $filter->toArray(); + + $this->assertEquals($expected, $data); + } + + public function testSetDistanceType() + { + $filter = new Elastica_Filter_GeoDistance('location', array('lat' => 48.86, 'lon' => 2.35), '10km'); + $distanceType = Elastica_Filter_GeoDistance::DISTANCE_TYPE_ARC; + $filter->setDistanceType($distanceType); + + $data = $filter->toArray(); + + $this->assertEquals($distanceType, $data['geo_distance']['distance_type']); + } + + public function testSetOptimizeBbox() + { + $filter = new Elastica_Filter_GeoDistance('location', array('lat' => 48.86, 'lon' => 2.35), '10km'); + $optimizeBbox = Elastica_Filter_GeoDistance::OPTIMIZE_BBOX_MEMORY; + $filter->setOptimizeBbox($optimizeBbox); + + $data = $filter->toArray(); + + $this->assertEquals($optimizeBbox, $data['geo_distance']['optimize_bbox']); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/GeoPolygonTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/GeoPolygonTest.php new file mode 100755 index 0000000..de4babc --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/GeoPolygonTest.php @@ -0,0 +1,59 @@ +getIndex('test'); + $index->create(array(), true); + + $type = $index->getType('test'); + + // Set mapping + $type->setMapping(array('point' => array('type' => 'geo_point'))); + + // Add doc 1 + $doc1 = new Elastica_Document(1, + array( + 'name' => 'ruflin', + ) + ); + + $doc1->addGeoPoint('point', 17, 19); + $type->addDocument($doc1); + + // Add doc 2 + $doc2 = new Elastica_Document(2, + array( + 'name' => 'ruflin', + ) + ); + + $doc2->addGeoPoint('point', 30, 40); + $type->addDocument($doc2); + + $index->refresh(); + + // Only one point should be in polygon + $query = new Elastica_Query(); + $points = array(array(16, 16), array(16, 20), array(20, 20), array(20, 16), array(16, 16)); + $geoFilter = new Elastica_Filter_GeoPolygon('point', compact('points')); + + $query = new Elastica_Query(new Elastica_Query_MatchAll()); + $query->setFilter($geoFilter); + $this->assertEquals(1, $type->search($query)->count()); + + // Both points should be inside + $query = new Elastica_Query(); + $points = array(array(16, 16), array(16, 40), array(40, 40), array(40, 16), array(16, 16)); + $geoFilter = new Elastica_Filter_GeoPolygon('point', compact('points')); + + $query = new Elastica_Query(new Elastica_Query_MatchAll()); + $query->setFilter($geoFilter); + + $this->assertEquals(2, $type->search($query)->count()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/IdsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/IdsTest.php new file mode 100644 index 0000000..1777298 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/IdsTest.php @@ -0,0 +1,185 @@ +getIndex('test'); + $index->create(array(), true); + + $type1 = $index->getType('helloworld1'); + $type2 = $index->getType('helloworld2'); + + // Add documents to first type + for ($i = 1; $i < 100; $i++) { + $doc = new Elastica_Document($i, array('name' => 'ruflin')); + $type1->addDocument($doc); + } + + // Add documents to second type + for ($i = 1; $i < 100; $i++) { + $doc = new Elastica_Document($i, array('name' => 'ruflin')); + $type2->addDocument($doc); + } + + // This is a special id that will only be in the second type + $doc = new Elastica_Document('101', array('name' => 'ruflin')); + $type2->addDocument($doc); + + $index->optimize(); + $index->refresh(); + + $this->_type = $type1; + $this->_index = $index; + } + + public function tearDown() + { + $client = new Elastica_Client(); + $index = $client->getIndex('test'); + $index->delete(); + } + + public function testSetIdsSearchSingle() + { + $filter = new Elastica_Filter_Ids(); + $filter->setIds('1'); + + $query = Elastica_Query::create($filter); + $resultSet = $this->_type->search($query); + + $this->assertEquals(1, $resultSet->count()); + } + + public function testSetIdsSearchArray() + { + $filter = new Elastica_Filter_Ids(); + $filter->setIds(array(1, 7, 13)); + + $query = Elastica_Query::create($filter); + $resultSet = $this->_type->search($query); + + $this->assertEquals(3, $resultSet->count()); + } + + public function testAddIdsSearchSingle() + { + $filter = new Elastica_Filter_Ids(); + $filter->addId('39'); + + $query = Elastica_Query::create($filter); + $resultSet = $this->_type->search($query); + + $this->assertEquals(1, $resultSet->count()); + } + + public function testAddIdsSearchSingleNotInType() + { + $filter = new Elastica_Filter_Ids(); + $filter->addId('39'); + + // Add an ID that is not in the index + $filter->addId(104); + + $query = Elastica_Query::create($filter); + $resultSet = $this->_type->search($query); + + $this->assertEquals(1, $resultSet->count()); + } + + public function testComboIdsSearchArray() + { + $filter = new Elastica_Filter_Ids(); + $filter->setIds(array(1, 7, 13)); + $filter->addId('39'); + + $query = Elastica_Query::create($filter); + $resultSet = $this->_type->search($query); + + $this->assertEquals(4, $resultSet->count()); + } + + public function testSetTypeSingleSearchSingle() + { + $filter = new Elastica_Filter_Ids(); + $filter->setIds('1'); + $filter->setType('helloworld1'); + + $query = Elastica_Query::create($filter); + $resultSet = $this->_index->search($query); + + $this->assertEquals(1, $resultSet->count()); + } + + public function testSetTypeSingleSearchArray() + { + $filter = new Elastica_Filter_Ids(); + $filter->setIds(array('1', '2')); + $filter->setType('helloworld1'); + + $query = Elastica_Query::create($filter); + $resultSet = $this->_index->search($query); + + $this->assertEquals(2, $resultSet->count()); + } + + public function testSetTypeSingleSearchSingleDocInOtherType() + { + $filter = new Elastica_Filter_Ids(); + + // Doc 4 is in the second type... + $filter->setIds('101'); + $filter->setType('helloworld1'); + + $query = Elastica_Query::create($filter); + $resultSet = $this->_type->search($query); + + // ...therefore 0 results should be returned + $this->assertEquals(0, $resultSet->count()); + } + + public function testSetTypeSingleSearchArrayDocInOtherType() + { + $filter = new Elastica_Filter_Ids(); + + // Doc 4 is in the second type... + $filter->setIds(array('1', '101')); + $filter->setType('helloworld1'); + + $query = Elastica_Query::create($filter); + $resultSet = $this->_type->search($query); + + // ...therefore only 1 result should be returned + $this->assertEquals(1, $resultSet->count()); + } + + public function testSetTypeArraySearchArray() + { + $filter = new Elastica_Filter_Ids(); + $filter->setIds(array('1', '4')); + $filter->setType(array('helloworld1', 'helloworld2')); + + $query = Elastica_Query::create($filter); + $resultSet = $this->_index->search($query); + + $this->assertEquals(4, $resultSet->count()); + } + + public function testSetTypeArraySearchSingle() + { + $filter = new Elastica_Filter_Ids(); + $filter->setIds('4'); + $filter->setType(array('helloworld1', 'helloworld2')); + + $query = Elastica_Query::create($filter); + $resultSet = $this->_index->search($query); + + $this->assertEquals(2, $resultSet->count()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/MatchAllTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/MatchAllTest.php new file mode 100644 index 0000000..7cc5bce --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/MatchAllTest.php @@ -0,0 +1,14 @@ + new stdClass()); + + $this->assertEquals($expectedArray, $filter->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/NestedTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/NestedTest.php new file mode 100644 index 0000000..01cf88b --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/NestedTest.php @@ -0,0 +1,114 @@ +getIndex('elastica_test_filter_nested'); + $index->create(array(), true); + $type = $index->getType('user'); + $mapping = new Elastica_Type_Mapping(); + $mapping->setProperties( + array( + 'firstname' => array('type' => 'string', 'store' => 'yes'), + // default is store => no expected + 'lastname' => array('type' => 'string'), + 'hobbies' => array( + 'type' => 'nested', + 'include_in_parent' => true, + 'properties' => array('hobby' => array('type' => 'string')) + ) + ) + ); + $type->setMapping($mapping); + + // Adds a list of documents with _bulk upload to the index + $docs = array(); + $docs[] = new Elastica_Document(1, + array( + 'firstname' => 'Nicolas', + 'lastname' => 'Ruflin', + 'hobbies' => array( + array('hobby' => 'opensource') + ) + ) + ); + $docs[] = new Elastica_Document(2, + array( + 'firstname' => 'Nicolas', + 'lastname' => 'Ippolito', + 'hobbies' => array( + array('hobby' => 'opensource'), + array('hobby' => 'guitar'), + ) + ) + ); + $response = $type->addDocuments($docs); + + // Refresh index + $index->refresh(); + } + + public function tearDown() + { + $client = new Elastica_Client(); + $index = $client->getIndex('elastica_test_filter_nested'); + $index->delete(); + } + + public function testToArray() + { + $f = new Elastica_Filter_Nested(); + $this->assertEquals(array('nested' => array()), $f->toArray()); + $q = new Elastica_Query_Terms(); + $q->setTerms('hobby', array('guitar')); + $f->setPath('hobbies'); + $f->setQuery($q); + + $expectedArray = array( + 'nested' => array( + 'path' => 'hobbies', + 'query' => array('terms' => array( + 'hobby' => array('guitar') + )) + ) + ); + + $this->assertEquals($expectedArray, $f->toArray()); + } + + public function testShouldReturnTheRightNumberOfResult() + { + $f = new Elastica_Filter_Nested(); + $this->assertEquals(array('nested' => array()), $f->toArray()); + $q = new Elastica_Query_Terms(); + $q->setTerms('hobby', array('guitar')); + $f->setPath('hobbies'); + $f->setQuery($q); + + $c = new Elastica_Client(); + $s = new Elastica_Search($c); + $i = $c->getIndex('elastica_test_filter_nested'); + $s->addIndex($i); + $r = $s->search($f); + + $this->assertEquals(1, $r->getTotalHits()); + + $f = new Elastica_Filter_Nested(); + $this->assertEquals(array('nested' => array()), $f->toArray()); + $q = new Elastica_Query_Terms(); + $q->setTerms('hobby', array('opensource')); + $f->setPath('hobbies'); + $f->setQuery($q); + + $c = new Elastica_Client(); + $s = new Elastica_Search($c); + $i = $c->getIndex('elastica_test_filter_nested'); + $s->addIndex($i); + $r = $s->search($f); + $this->assertEquals(2, $r->getTotalHits()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/NotTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/NotTest.php new file mode 100644 index 0000000..63765f2 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/NotTest.php @@ -0,0 +1,21 @@ +setIds(12); + $filter = new Elastica_Filter_Not($idsFilter); + + $expectedArray = array( + 'not' => array( + 'filter' => $idsFilter->toArray() + ) + ); + + $this->assertEquals($expectedArray, $filter->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/NumericRangeTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/NumericRangeTest.php new file mode 100644 index 0000000..93961a1 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/NumericRangeTest.php @@ -0,0 +1,29 @@ +addField('fieldName', array('to' => 'value')); + $this->assertInstanceOf('Elastica_Filter_NumericRange', $returnValue); + } + + public function testToArray() + { + $filter = new Elastica_Filter_NumericRange(); + + $fromTo = array('from' => 'ra', 'to' => 'ru'); + $filter->addField('name', $fromTo); + + $expectedArray = array( + 'numeric_range' => array( + 'name' => $fromTo + ) + ); + + $this->assertEquals($expectedArray, $filter->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/OrTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/OrTest.php new file mode 100644 index 0000000..f6b687b --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/OrTest.php @@ -0,0 +1,37 @@ +getMockForAbstractClass('Elastica_Filter_Abstract'); + $orFilter = new Elastica_Filter_Or(); + $returnValue = $orFilter->addFilter($filter); + $this->assertInstanceOf('Elastica_Filter_Or', $returnValue); + } + + public function testToArray() + { + $orFilter = new Elastica_Filter_Or(); + + $filter1 = new Elastica_Filter_Ids(); + $filter1->setIds('1'); + + $filter2 = new Elastica_Filter_Ids(); + $filter2->setIds('2'); + + $orFilter->addFilter($filter1); + $orFilter->addFilter($filter2); + + $expectedArray = array( + 'or' => array( + $filter1->toArray(), + $filter2->toArray() + ) + ); + + $this->assertEquals($expectedArray, $orFilter->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/PrefixTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/PrefixTest.php new file mode 100644 index 0000000..cebc54c --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/PrefixTest.php @@ -0,0 +1,144 @@ + array( + $field => $prefix + ) + ); + + $this->assertequals($expectedArray, $filter->toArray()); + } + + public function testDifferentPrefixes() + { + $client = new Elastica_Client(); + $index = $client->getIndex('test'); + + /*$indexParams = array( + 'analysis' => array( + 'analyzer' => array( + 'lw' => array( + 'type' => 'custom', + 'tokenizer' => 'keyword', + 'filter' => array('lowercase') + ) + ), + ) + );*/ + + $index->create(array(), true); + $type = $index->getType('test'); + + $mapping = new Elastica_Type_Mapping($type, array( + 'name' => array('type' => 'string', 'store' => 'no', 'index' => 'not_analyzed'), + ) + ); + $type->setMapping($mapping); + + $doc = new Elastica_Document(1, array('name' => 'Basel-Stadt')); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('name' => 'New York')); + $type->addDocument($doc); + $doc = new Elastica_Document(3, array('name' => 'Baden')); + $type->addDocument($doc); + $doc = new Elastica_Document(4, array('name' => 'Baden Baden')); + $type->addDocument($doc); + $doc = new Elastica_Document(5, array('name' => 'New Orleans')); + $type->addDocument($doc); + + $index->refresh(); + + $query = new Elastica_Filter_Prefix('name', 'Ba'); + $resultSet = $index->search($query); + $this->assertEquals(3, $resultSet->count()); + + // Lower case should not return a result + $query = new Elastica_Filter_Prefix('name', 'ba'); + $resultSet = $index->search($query); + $this->assertEquals(0, $resultSet->count()); + + $query = new Elastica_Filter_Prefix('name', 'Baden'); + $resultSet = $index->search($query); + $this->assertEquals(2, $resultSet->count()); + + $query = new Elastica_Filter_Prefix('name', 'Baden B'); + $resultSet = $index->search($query); + $this->assertEquals(1, $resultSet->count()); + + $query = new Elastica_Filter_Prefix('name', 'Baden Bas'); + $resultSet = $index->search($query); + $this->assertEquals(0, $resultSet->count()); + } + + public function testDifferentPrefixesLowercase() + { + $client = new Elastica_Client(); + $index = $client->getIndex('test'); + + $indexParams = array( + 'analysis' => array( + 'analyzer' => array( + 'lw' => array( + 'type' => 'custom', + 'tokenizer' => 'keyword', + 'filter' => array('lowercase') + ) + ), + ) + ); + + $index->create($indexParams, true); + $type = $index->getType('test'); + + $mapping = new Elastica_Type_Mapping($type, array( + 'name' => array('type' => 'string', 'store' => 'no', 'analyzer' => 'lw'), + ) + ); + $type->setMapping($mapping); + + $doc = new Elastica_Document(1, array('name' => 'Basel-Stadt')); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('name' => 'New York')); + $type->addDocument($doc); + $doc = new Elastica_Document(3, array('name' => 'Baden')); + $type->addDocument($doc); + $doc = new Elastica_Document(4, array('name' => 'Baden Baden')); + $type->addDocument($doc); + $doc = new Elastica_Document(5, array('name' => 'New Orleans')); + $type->addDocument($doc); + + $index->refresh(); + + $query = new Elastica_Filter_Prefix('name', 'ba'); + $resultSet = $index->search($query); + $this->assertEquals(3, $resultSet->count()); + + // Upper case should not return a result + $query = new Elastica_Filter_Prefix('name', 'Ba'); + $resultSet = $index->search($query); + $this->assertEquals(0, $resultSet->count()); + + $query = new Elastica_Filter_Prefix('name', 'baden'); + $resultSet = $index->search($query); + $this->assertEquals(2, $resultSet->count()); + + $query = new Elastica_Filter_Prefix('name', 'baden b'); + $resultSet = $index->search($query); + $this->assertEquals(1, $resultSet->count()); + + $query = new Elastica_Filter_Prefix('name', 'baden bas'); + $resultSet = $index->search($query); + $this->assertEquals(0, $resultSet->count()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/QueryTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/QueryTest.php new file mode 100644 index 0000000..a832ef9 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/QueryTest.php @@ -0,0 +1,41 @@ + array( + 'query_string' => array( + 'query' => 'foo bar', + ) + ) + ); + + $this->assertEquals($expected, $filter->toArray()); + } + + public function testExtended() + { + $query = new Elastica_Query_QueryString('foo bar'); + $filter = new Elastica_Filter_Query($query); + $filter->setCached(true); + + $expected = array( + 'fquery' => array( + 'query' => array( + 'query_string' => array( + 'query' => 'foo bar', + ), + ), + '_cache' => true + ) + ); + + $this->assertEquals($expected, $filter->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/RangeTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/RangeTest.php new file mode 100644 index 0000000..ffc0e75 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/RangeTest.php @@ -0,0 +1,29 @@ +addField('fieldName', array('to' => 'value')); + $this->assertInstanceOf('Elastica_Filter_Range', $returnValue); + } + + public function testToArray() + { + $filter = new Elastica_Filter_Range(); + + $fromTo = array('from' => 'ra', 'to' => 'ru'); + $filter->addField('name', $fromTo); + + $expectedArray = array( + 'range' => array( + 'name' => $fromTo + ) + ); + + $this->assertEquals($expectedArray, $filter->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/TermTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/TermTest.php new file mode 100644 index 0000000..faf0ede --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/TermTest.php @@ -0,0 +1,20 @@ +setTerm($key, $value, $boost); + + $data = $query->toArray(); + + $this->assertInternalType('array', $data['term']); + $this->assertEquals(array($key => $value), $data['term']); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Filter/TypeTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Filter/TypeTest.php new file mode 100644 index 0000000..092d528 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Filter/TypeTest.php @@ -0,0 +1,24 @@ +setType('type_name'); + $this->assertInstanceOf('Elastica_Filter_Type', $returnValue); + } + + public function testToArray() + { + $typeFilter = new Elastica_Filter_Type('type_name'); + + $expectedArray = array( + 'type' => array('value' => 'type_name') + ); + + $this->assertEquals($expectedArray, $typeFilter->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Index/SettingsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Index/SettingsTest.php new file mode 100644 index 0000000..97fc904 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Index/SettingsTest.php @@ -0,0 +1,239 @@ +getIndex($indexName); + $index->create(array(), true); + $index->refresh(); + $settings = $index->getSettings(); + + $this->assertInternalType('array', $settings->get()); + $this->assertNotNull($settings->get('number_of_replicas')); + $this->assertNotNull($settings->get('number_of_shards')); + $this->assertNull($settings->get('kjqwerjlqwer')); + } + + public function testSetNumberOfReplicas() + { + $indexName = 'test'; + + $client = new Elastica_Client(); + $index = $client->getIndex($indexName); + $index->create(array(), true); + $settings = $index->getSettings(); + + $settings->setNumberOfReplicas(2); + $index->refresh(); + $this->assertEquals(2, $settings->get('number_of_replicas')); + + $settings->setNumberOfReplicas(3); + $index->refresh(); + $this->assertEquals(3, $settings->get('number_of_replicas')); + } + + public function testSetRefreshInterval() + { + $indexName = 'test'; + + $client = new Elastica_Client(); + $index = $client->getIndex($indexName); + $index->create(array(), true); + + $settings = $index->getSettings(); + + $settings->setRefreshInterval('2s'); + $index->refresh(); + $this->assertEquals('2s', $settings->get('refresh_interval')); + + $settings->setRefreshInterval('5s'); + $index->refresh(); + $this->assertEquals('5s', $settings->get('refresh_interval')); + } + + public function testGetRefreshInterval() + { + $indexName = 'test'; + + $client = new Elastica_Client(); + $index = $client->getIndex($indexName); + $index->create(array(), true); + + $settings = $index->getSettings(); + + $this->assertEquals(Elastica_Index_Settings::DEFAULT_REFRESH_INTERVAL, $settings->getRefreshInterval()); + + $interval = '2s'; + $settings->setRefreshInterval($interval); + $index->refresh(); + $this->assertEquals($interval, $settings->getRefreshInterval()); + $this->assertEquals($interval, $settings->get('refresh_interval')); + } + + public function testSetMergePolicy() + { + $indexName = 'test'; + + $client = new Elastica_Client(); + $index = $client->getIndex($indexName); + $index->create(array(), true); + + $settings = $index->getSettings(); + + $settings->setMergePolicy('expunge_deletes_allowed', 15); + $this->assertEquals(15, $settings->getMergePolicy('expunge_deletes_allowed')); + + $settings->setMergePolicy('expunge_deletes_allowed', 10); + $this->assertEquals(10, $settings->getMergePolicy('expunge_deletes_allowed')); + } + + public function testSetMergeFactor() + { + $indexName = 'test'; + + $client = new Elastica_Client(); + $index = $client->getIndex($indexName); + $index->create(array(), true); + + $settings = $index->getSettings(); + + $response = $settings->setMergePolicy('merge_factor', 15); + $this->assertEquals(15, $settings->getMergePolicy('merge_factor')); + $this->assertInstanceOf('Elastica_Response', $response); + $data = $response->getData(); + $this->assertTrue($data['ok']); + + $settings->setMergePolicy('merge_factor', 10); + $this->assertEquals(10, $settings->getMergePolicy('merge_factor')); + } + + public function testSetMergePolicyType() + { + $indexName = 'test'; + + $client = new Elastica_Client(); + $index = $client->getIndex($indexName); + $index->create(array(), true); + + $settings = $index->getSettings(); + + //$response = $settings->setMergePolicyType('LogByteSizeMergePolicyProvider'); + $response = $settings->setMergePolicyType('log_byte_size'); + $this->assertEquals('log_byte_size', $settings->getMergePolicyType()); + + $response = $settings->setMergePolicy('merge_factor', 15); + $this->assertEquals(15, $settings->getMergePolicy('merge_factor')); + $this->assertInstanceOf('Elastica_Response', $response); + $data = $response->getData(); + $this->assertTrue($data['ok']); + } + + public function testSetReadOnly() + { + $client = new Elastica_Client(); + $index = new Elastica_Index($client, 'elastica_test'); + $index->getSettings()->setReadOnly(false); + + $index = $this->_createIndex(); + + // Add document to normal index + $doc = new Elastica_Document(null, array('hello' => 'world')); + $type = $index->getType('test'); + $type->addDocument($doc); + $this->assertFalse((bool) $index->getSettings()->get('blocks.read_only')); + + // Try to add doc to read only index + $index->getSettings()->setReadOnly(true); + $this->assertTrue((bool) $index->getSettings()->get('blocks.read_only')); + + try { + $type->addDocument($doc); + $this->fail('Should throw exception because of read only'); + } catch (Elastica_Exception_Response $e) { + $message = $e->getMessage(); + $this->assertContains('ClusterBlockException', $message); + $this->assertContains('index read-only', $message); + } + + // Remove read only, add document + $response = $index->getSettings()->setReadOnly(false); + $this->assertTrue($response->isOk()); + + $type->addDocument($doc); + $index->refresh(); + + $this->assertEquals(2, $type->count()); + } + + public function testGetSetBlocksRead() + { + $client = new Elastica_Client(); + $index = $client->getIndex('elastica-test'); + $index->create(); + $index->refresh(); + $settings = $index->getSettings(); + + $this->assertFalse($settings->getBlocksRead()); + + $settings->setBlocksRead(true); + $this->assertTrue($settings->getBlocksRead()); + + $settings->setBlocksRead(false); + $this->assertFalse($settings->getBlocksRead()); + + $settings->setBlocksRead(); + $this->assertTrue($settings->getBlocksRead()); + + $index->delete(); + } + + public function testGetSetBlocksWrite() + { + $client = new Elastica_Client(); + $index = $client->getIndex('elastica-test'); + $index->create(); + $index->refresh(); + $settings = $index->getSettings(); + + $this->assertFalse($settings->getBlocksWrite()); + + $settings->setBlocksWrite(true); + $this->assertTrue($settings->getBlocksWrite()); + + $settings->setBlocksWrite(false); + $this->assertFalse($settings->getBlocksWrite()); + + $settings->setBlocksWrite(); + $this->assertTrue($settings->getBlocksWrite()); + + $index->delete(); + } + + public function testGetSetBlocksMetadata() + { + $client = new Elastica_Client(); + $index = $client->getIndex('elastica-test'); + $index->create(); + $index->refresh(); + $settings = $index->getSettings(); + + $this->assertFalse($settings->getBlocksMetadata()); + + $settings->setBlocksMetadata(true); + $this->assertTrue($settings->getBlocksMetadata()); + + $settings->setBlocksMetadata(false); + $this->assertFalse($settings->getBlocksMetadata()); + + $settings->setBlocksMetadata(); + $this->assertTrue($settings->getBlocksMetadata()); + + $settings->setBlocksMetadata(false); // Cannot delete index otherwise + $index->delete(); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Index/StatsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Index/StatsTest.php new file mode 100644 index 0000000..a619ee8 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Index/StatsTest.php @@ -0,0 +1,20 @@ +getIndex($indexName); + $index->create(array(), true); + $stats = $index->getStats(); + $this->assertInstanceOf('Elastica_Index_Stats', $stats); + + $this->assertTrue($stats->get('ok')); + $this->assertEquals(0, $stats->get('_all', 'indices', 'test', 'primaries', 'docs', 'count')); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Index/StatusTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Index/StatusTest.php new file mode 100644 index 0000000..d2657ff --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Index/StatusTest.php @@ -0,0 +1,62 @@ +getIndex($indexName); + $index->create(array(), true); + + $status = new Elastica_Index_Status($index); + + $aliases = $status->getAliases(); + + $this->assertTrue(empty($aliases)); + $this->assertInternalType('array', $aliases); + + $index->addAlias($aliasName); + $status->refresh(); + + $aliases = $status->getAliases(); + + $this->assertTrue(in_array($aliasName, $aliases)); + } + + public function testHasAlias() + { + $indexName = 'test'; + $aliasName = 'test-alias'; + + $client = new Elastica_Client(); + $index = $client->getIndex($indexName); + $index->create(array(), true); + + $status = new Elastica_Index_Status($index); + + $this->assertFalse($status->hasAlias($aliasName)); + + $index->addAlias($aliasName); + $status->refresh(); + + $this->assertTrue($status->hasAlias($aliasName)); + } + + public function testGetSettings() + { + $indexName = 'test'; + + $client = new Elastica_Client(); + $index = $client->getIndex($indexName); + $index->create(array(), true); + $status = $index->getStatus(); + + $settings = $status->getSettings(); + $this->assertInternalType('array', $settings); + $this->assertTrue(isset($settings['index.number_of_shards'])); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/IndexTest.php b/modules/thirdparty/elastica/test/lib/Elastica/IndexTest.php new file mode 100755 index 0000000..66decde --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/IndexTest.php @@ -0,0 +1,497 @@ +_createIndex(); + $doc = new Elastica_Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'hanswurst', 'test' => array('2', '3', '5'))); + + $type = $index->getType('test'); + + $mapping = array('id' => array('type' => 'integer', 'store' => 'yes'), 'email' => array('type' => 'string', 'store' => 'no'), + 'username' => array('type' => 'string', 'store' => 'no'), 'test' => array('type' => 'integer', 'store' => 'no'),); + $type->setMapping($mapping); + + $type->addDocument($doc); + $index->optimize(); + + $storedMapping = $type->getMapping('test'); + + $this->assertEquals($storedMapping['test']['properties']['id']['type'], 'integer'); + $this->assertEquals($storedMapping['test']['properties']['id']['store'], 'yes'); + $this->assertEquals($storedMapping['test']['properties']['email']['type'], 'string'); + $this->assertEquals($storedMapping['test']['properties']['username']['type'], 'string'); + $this->assertEquals($storedMapping['test']['properties']['test']['type'], 'integer'); + + $result = $type->search('hanswurst'); + } + + public function testParent() + { + $index = $this->_createIndex(); + + $typeBlog = new Elastica_Type($index, 'blog'); + + $typeComment = new Elastica_Type($index, 'comment'); + + $mapping = new Elastica_Type_Mapping(); + $mapping->setParam('_parent', array('type' => 'blog')); + $typeComment->setMapping($mapping); + + $entry1 = new Elastica_Document(1); + $entry1->add('title', 'Hello world'); + $typeBlog->addDocument($entry1); + + $entry2 = new Elastica_Document(2); + $entry2->add('title', 'Foo bar'); + $typeBlog->addDocument($entry2); + + $entry3 = new Elastica_Document(3); + $entry3->add('title', 'Till dawn'); + $typeBlog->addDocument($entry3); + + $comment = new Elastica_Document(1); + $comment->add('author', 'Max'); + $comment->setParent(2); // Entry Foo bar + $typeComment->addDocument($comment); + + $index->optimize(); + + $query = new Elastica_Query_HasChild('Max', 'comment'); + $resultSet = $typeBlog->search($query); + $this->assertEquals(1, $resultSet->count()); + $this->assertEquals(array('title' => 'Foo bar'), $resultSet->current()->getData()); + } + + public function testAddPdfFile() + { + $indexMapping = array('file' => array('type' => 'attachment', 'store' => 'no'), 'text' => array('type' => 'string', 'store' => 'no'),); + + $indexParams = array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0),); + + $index = $this->_createIndex(); + $type = new Elastica_Type($index, 'test'); + + $index->create($indexParams, true); + $type->setMapping($indexMapping); + + $doc1 = new Elastica_Document(1); + $doc1->addFile('file', BASE_PATH . '/data/test.pdf'); + $doc1->add('text', 'basel world'); + $type->addDocument($doc1); + + $doc2 = new Elastica_Document(2); + $doc2->add('text', 'running in basel'); + $type->addDocument($doc2); + + $index->optimize(); + + $resultSet = $type->search('xodoa'); + $this->assertEquals(1, $resultSet->count()); + + $resultSet = $type->search('basel'); + $this->assertEquals(2, $resultSet->count()); + + // Author is ruflin + $resultSet = $type->search('ruflin'); + $this->assertEquals(1, $resultSet->count()); + + // String does not exist in file + $resultSet = $type->search('guschti'); + $this->assertEquals(0, $resultSet->count()); + } + + public function testAddPdfFileContent() + { + $indexMapping = array('file' => array('type' => 'attachment', 'store' => 'no'), 'text' => array('type' => 'string', 'store' => 'no'),); + + $indexParams = array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0),); + + $index = $this->_createIndex(); + $type = new Elastica_Type($index, 'test'); + + $index->create($indexParams, true); + $type->setMapping($indexMapping); + + $doc1 = new Elastica_Document(1); + $doc1->addFileContent('file', file_get_contents(BASE_PATH . '/data/test.pdf')); + $doc1->add('text', 'basel world'); + $type->addDocument($doc1); + + $doc2 = new Elastica_Document(2); + $doc2->add('text', 'running in basel'); + $type->addDocument($doc2); + + $index->optimize(); + + $resultSet = $type->search('xodoa'); + $this->assertEquals(1, $resultSet->count()); + + $resultSet = $type->search('basel'); + $this->assertEquals(2, $resultSet->count()); + + // Author is ruflin + $resultSet = $type->search('ruflin'); + $this->assertEquals(1, $resultSet->count()); + + // String does not exist in file + $resultSet = $type->search('guschti'); + $this->assertEquals(0, $resultSet->count()); + } + + public function testAddWordxFile() + { + $indexMapping = array('file' => array('type' => 'attachment'), 'text' => array('type' => 'string', 'store' => 'no'),); + + $indexParams = array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0),); + + $index = $this->_createIndex(); + $type = new Elastica_Type($index, 'content'); + + $index->create($indexParams, true); + $type->setMapping($indexMapping); + + $doc1 = new Elastica_Document(1); + $doc1->addFile('file', BASE_PATH . '/data/test.docx'); + $doc1->add('text', 'basel world'); + $type->addDocument($doc1); + + $doc2 = new Elastica_Document(2); + $doc2->add('text', 'running in basel'); + $type->addDocument($doc2); + + $index->optimize(); + + $resultSet = $type->search('xodoa'); + $this->assertEquals(1, $resultSet->count()); + + $resultSet = $type->search('basel'); + $this->assertEquals(2, $resultSet->count()); + + $resultSet = $type->search('ruflin'); + $this->assertEquals(0, $resultSet->count()); + } + + public function testExcludeFileSource() + { + $indexMapping = array('file' => array('type' => 'attachment', 'store' => 'yes'), 'text' => array('type' => 'string', 'store' => 'yes'), + 'title' => array('type' => 'string', 'store' => 'yes'),); + + $indexParams = array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0),); + + $index = $this->_createIndex(); + $type = new Elastica_Type($index, 'content'); + + $mapping = Elastica_Type_Mapping::create($indexMapping); + $mapping->setSource(array('excludes' => array('file'))); + + $mapping->setType($type); + + $index->create($indexParams, true); + $type->setMapping($mapping); + + $docId = 1; + $text = 'Basel World'; + $title = 'No Title'; + + $doc1 = new Elastica_Document($docId); + $doc1->addFile('file', BASE_PATH . '/data/test.docx'); + $doc1->add('text', $text); + $doc1->add('title', $title); + $type->addDocument($doc1); + + // Optimization necessary, as otherwise source still in realtime get + $index->optimize(); + + $data = $type->getDocument($docId)->getData(); + $this->assertEquals($data['title'], $title); + $this->assertEquals($data['text'], $text); + $this->assertFalse(isset($data['file'])); + } + + public function testAddRemoveAlias() + { + $client = new Elastica_Client(); + + $indexName1 = 'test1'; + $aliasName = 'test-alias'; + $typeName = 'test'; + + $index = $client->getIndex($indexName1); + $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true); + + $doc = new Elastica_Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'ruflin')); + + $type = $index->getType($typeName); + $type->addDocument($doc); + $index->refresh(); + + $resultSet = $type->search('ruflin'); + + $this->assertEquals(1, $resultSet->count()); + + $data = $index->addAlias($aliasName, true)->getData(); + $this->assertTrue($data['ok']); + + $index2 = $client->getIndex($aliasName); + $type2 = $index2->getType($typeName); + + $resultSet2 = $type2->search('ruflin'); + $this->assertEquals(1, $resultSet2->count()); + + $response = $index->removeAlias($aliasName)->getData(); + $this->assertTrue($response['ok']); + + try { + $client->getIndex($aliasName)->getType($typeName)->search('ruflin'); + $this->fail('Should throw no index exception'); + } catch (Elastica_Exception_Response $e) { + $this->assertTrue(true); + } + } + + public function testDeleteIndexDeleteAlias() + { + $indexName = 'test'; + $aliasName = 'test-aliase'; + + $client = new Elastica_Client(); + $index = $client->getIndex($indexName); + + $index->create(array(), true); + $index->addAlias($aliasName); + + $status = new Elastica_Status($client); + $this->assertTrue($status->indexExists($indexName)); + $this->assertTrue($status->aliasExists($aliasName)); + + // Deleting index should also remove alias + $index->delete(); + + $status->refresh(); + $this->assertFalse($status->indexExists($indexName)); + $this->assertFalse($status->aliasExists($aliasName)); + } + + public function testAddAliasTwoIndices() + { + $indexName1 = 'test1'; + $indexName2 = 'test2'; + $aliasName = 'test-alias'; + + $client = new Elastica_Client(); + $index1 = $client->getIndex($indexName1); + $index2 = $client->getIndex($indexName2); + + $index1->create(array(), true); + $index1->addAlias($aliasName); + $index2->create(array(), true); + + $status = new Elastica_Status($client); + $this->assertTrue($status->indexExists($indexName1)); + $this->assertTrue($status->indexExists($indexName2)); + $this->assertTrue($status->aliasExists($aliasName)); + $this->assertTrue($index1->getStatus()->hasAlias($aliasName)); + $this->assertFalse($index2->getStatus()->hasAlias($aliasName)); + + $index2->addAlias($aliasName); + $this->assertTrue($index1->getStatus()->hasAlias($aliasName)); + $this->assertTrue($index2->getStatus()->hasAlias($aliasName)); + } + + public function testReplaceAlias() + { + $indexName1 = 'test1'; + $indexName2 = 'test2'; + $aliasName = 'test-alias'; + + $client = new Elastica_Client(); + $index1 = $client->getIndex($indexName1); + $index2 = $client->getIndex($indexName2); + + $index1->create(array(), true); + $index1->addAlias($aliasName); + $index2->create(array(), true); + + $status = new Elastica_Status($client); + $this->assertTrue($status->indexExists($indexName1)); + $this->assertTrue($status->indexExists($indexName2)); + $this->assertTrue($status->aliasExists($aliasName)); + $this->assertTrue($index1->getStatus()->hasAlias($aliasName)); + $this->assertFalse($index2->getStatus()->hasAlias($aliasName)); + + $index2->addAlias($aliasName, true); + $this->assertFalse($index1->getStatus()->hasAlias($aliasName)); + $this->assertTrue($index2->getStatus()->hasAlias($aliasName)); + } + + public function testAddDocumentVersion() + { + $client = new Elastica_Client(); + $index = $client->getIndex('test'); + $index->create(array(), true); + $type = new Elastica_Type($index, 'test'); + + $doc1 = new Elastica_Document(1); + $doc1->add('title', 'Hello world'); + + $return = $type->addDocument($doc1); + $data = $return->getData(); + $this->assertEquals(1, $data['_version']); + + $return = $type->addDocument($doc1); + $data = $return->getData(); + $this->assertEquals(2, $data['_version']); + } + + public function testClearCache() + { + $client = new Elastica_Client(); + $index1 = $client->getIndex('test1'); + + $response = $index1->clearCache(); + $this->assertFalse($response->hasError()); + } + + public function testFlush() + { + $client = new Elastica_Client(); + $index = $client->getIndex('test1'); + + $response = $index->flush(); + $this->assertFalse($response->hasError()); + } + + public function testExists() + { + $index = $this->_createIndex(); + + $this->assertTrue($index->exists()); + + $index->delete(); + + $this->assertFalse($index->exists()); + } + + /** + * Test $index->delete() return value for unknown index + * + * Tests if deleting an index that does not exist in Elasticsearch, + * correctly returns a boolean true from the hasError() method of + * the Elastica_Response object + */ + public function testDeleteMissingIndexHasError() + { + $client = new Elastica_Client(); + $index = $client->getIndex('index_does_not_exist'); + + try { + $index->delete(); + $this->fail('This should never be reached. Deleting an unknown index will throw an exception'); + } catch (Elastica_Exception_Response $error) { + $response = $error->getResponse(); + $this->assertTrue($response->hasError()); + } + } + + /** + * Tests to see if the test type mapping exists when calling $index->getMapping() + */ + public function testIndexGetMapping() + { + $index = $this->_createIndex(); + $type = $index->getType('test'); + + $mapping = array('id' => array('type' => 'integer', 'store' => 'yes'), 'email' => array('type' => 'string', 'store' => 'no'), + 'username' => array('type' => 'string', 'store' => 'no'), 'test' => array('type' => 'integer', 'store' => 'no'),); + + $type->setMapping($mapping); + $indexMappings = $index->getMapping(); + + $this->assertEquals($indexMappings['elastica_test']['test']['properties']['id']['type'], 'integer'); + $this->assertEquals($indexMappings['elastica_test']['test']['properties']['id']['store'], 'yes'); + $this->assertEquals($indexMappings['elastica_test']['test']['properties']['email']['type'], 'string'); + $this->assertEquals($indexMappings['elastica_test']['test']['properties']['username']['type'], 'string'); + $this->assertEquals($indexMappings['elastica_test']['test']['properties']['test']['type'], 'integer'); + } + + /** + * Tests to see if the index is empty when there are no types set. + */ + public function testEmptyIndexGetMapping() + { + $index = $this->_createIndex(); + $indexMappings = $index->getMapping(); + + $this->assertTrue(empty($indexMappings['elastica_test'])); + } + + /** + * Test to see if search Default Limit works + */ + public function testLimitDefaultIndex() + { + $client = new Elastica_Client(); + $index = $client->getIndex('zero'); + $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true); + + $docs = array(); + + $docs[] = new Elastica_Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(2, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(3, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(4, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(5, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(6, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(7, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(8, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(9, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(10, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(11, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + + $type = $index->getType('zeroType'); + $type->addDocuments($docs); + $index->refresh(); + + // default limit results (default limit is 10) + $resultSet = $index->search('farrelley'); + $this->assertEquals(10, $resultSet->count()); + + // limit = 1 + $resultSet = $index->search('farrelley', 1); + $this->assertEquals(1, $resultSet->count()); + } + + public function testCreateArray() + { + $client = new Elastica_Client(); + $indexName = 'test'; + $aliasName = 'test-aliase'; + + //Testing recreate (backward compatibility) + $index = $client->getIndex($indexName); + $index->create(array(), true); + $status = new Elastica_Status($client); + $this->assertTrue($status->indexExists($indexName)); + + //Testing create index with array options + $opts = array('recreate' => true, 'routing' => 'r1,r2'); + $index->create(array(), $opts); + $status = new Elastica_Status($client); + $this->assertTrue($status->indexExists($indexName)); + + //Testing invalid options + try { + $opts = array('recreate' => true, 'routing' => 'r1,r2', 'testing_invalid_option' => true); + $index->create(array(), $opts); + $status = new Elastica_Status($client); + $this->assertTrue($status->indexExists($indexName)); + $this->fail('Should throw Elastica_Exception_Invalid'); + } catch (Exception $ex) { + $this->assertTrue($ex instanceof Elastica_Exception_Invalid); + } + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/LogTest.php b/modules/thirdparty/elastica/test/lib/Elastica/LogTest.php new file mode 100644 index 0000000..c7ba7c0 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/LogTest.php @@ -0,0 +1,64 @@ + $logPath)); + $this->assertEquals($logPath, $client->getConfig('log')); + } + + public function testSetLogConfigEnable() + { + $client = new Elastica_Client(array('log' => true)); + $this->assertTrue($client->getConfig('log')); + } + + public function testEmptyLogConfig() + { + $client = new Elastica_Client(); + $this->assertEmpty($client->getConfig('log')); + } + + public function testDisabledLog() + { + $client = new Elastica_Client(); + $log = new Elastica_Log($client); + + $log->log('hello world'); + + $this->assertEmpty($log->getLastMessage()); + } + + public function testGetLastMessage() + { + $client = new Elastica_Client(array('log' => '/tmp/php.log')); + $log = new Elastica_Log($client); + $message = 'hello world'; + + $log->log($message); + + $this->assertEquals($message, $log->getLastMessage()); + } + + public function testGetLastMessage2() + { + $client = new Elastica_Client(array('log' => true)); + $log = new Elastica_Log($client); + + // Set log path temp path as otherwise test fails with output + $errorLog = ini_get('error_log'); + ini_set('error_log', sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'php.log'); + + $message = 'hello world'; + + $log->log($message); + + ini_set('error_log', $errorLog); + + $this->assertEquals($message, $log->getLastMessage()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Node/InfoTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Node/InfoTest.php new file mode 100644 index 0000000..d087747 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Node/InfoTest.php @@ -0,0 +1,25 @@ +getCluster()->getNodeNames(); + $name = reset($names); + + $node = new Elastica_Node($name, $client); + $info = new Elastica_Node_Info($node); + + $this->assertNull($info->get('os', 'mem', 'total')); + + // Load os infos + $info = new Elastica_Node_Info($node, array('os')); + + $this->assertInternalType('string', $info->get('os', 'mem', 'total')); + $this->assertInternalType('array', $info->get('os', 'mem')); + $this->assertNull($info->get('test', 'notest', 'notexist')); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/NodeTest.php b/modules/thirdparty/elastica/test/lib/Elastica/NodeTest.php new file mode 100644 index 0000000..a4e6ddb --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/NodeTest.php @@ -0,0 +1,65 @@ +getCluster()->getNodeNames(); + $name = reset($names); + + $node = new Elastica_Node($name, $client); + $this->assertInstanceOf('Elastica_Node', $node); + } + + public function testGetInfo() + { + $client = new Elastica_Client(); + $names = $client->getCluster()->getNodeNames(); + $name = reset($names); + + $node = new Elastica_Node($name, $client); + + $info = $node->getInfo(); + + $this->assertInstanceOf('Elastica_Node_Info', $info); + } + + public function testGetStats() + { + $client = new Elastica_Client(); + $names = $client->getCluster()->getNodeNames(); + $name = reset($names); + + $node = new Elastica_Node($name, $client); + + $stats = $node->getStats(); + + $this->assertInstanceOf('Elastica_Node_Stats', $stats); + } + + public function testShutdown() + { + $client = new Elastica_Client(); + $nodes = $client->getCluster()->getNodes(); + + $count = count($nodes); + if ($count < 2) { + $this->markTestSkipped('At least two nodes have to be running, because 1 node is shutdown'); + } + + // Stores node info for later + $info = $nodes[1]->getInfo(); + $nodes[0]->shutdown('2s'); + + sleep(5); + + $client = new Elastica_Client(array('host' => $info->getIp(), 'port' => $info->getPort())); + $names = $client->getCluster()->getNodeNames(); + + // One node less ... + $this->assertEquals($count - 1, count($names)); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/ParamTest.php b/modules/thirdparty/elastica/test/lib/Elastica/ParamTest.php new file mode 100644 index 0000000..01afbd9 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/ParamTest.php @@ -0,0 +1,110 @@ +getMock('Elastica_Param', null, array(), $className); + + $this->assertInstanceOf('Elastica_Param', $param); + $this->assertEquals(array('param_abstract' => array()), $param->toArray()); + } + + public function testToArrayEmpty() + { + $param = new Elastica_Param(); + $this->assertInstanceOf('Elastica_Param', $param); + $this->assertEquals(array($this->_getFilterName($param) => array()), $param->toArray()); + } + + public function testSetParams() + { + $param = new Elastica_Param(); + $params = array('hello' => 'word', 'nicolas' => 'ruflin'); + $param->setParams($params); + + $this->assertInstanceOf('Elastica_Param', $param); + $this->assertEquals(array($this->_getFilterName($param) => $params), $param->toArray()); + } + + public function testSetGetParam() + { + $param = new Elastica_Param(); + + $key = 'name'; + $value = 'nicolas ruflin'; + + $params = array($key => $value); + $param->setParam($key, $value); + + $this->assertEquals($params, $param->getParams()); + $this->assertEquals($value, $param->getParam($key)); + } + + public function testAddParam() + { + $param = new Elastica_Param(); + + $key = 'name'; + $value = 'nicolas ruflin'; + + $param->addParam($key, $value); + + $this->assertEquals(array($key => array($value)), $param->getParams()); + $this->assertEquals(array($value), $param->getParam($key)); + } + + public function testAddParam2() + { + $param = new Elastica_Param(); + + $key = 'name'; + $value1 = 'nicolas'; + $value2 = 'ruflin'; + + $param->addParam($key, $value1); + $param->addParam($key, $value2); + + $this->assertEquals(array($key => array($value1, $value2)), $param->getParams()); + $this->assertEquals(array($value1, $value2), $param->getParam($key)); + } + + public function testGetParamInvalid() + { + $param = new Elastica_Param(); + + try { + $param->getParam('notest'); + $this->fail('Should throw exception'); + } catch (Elastica_Exception_Invalid $e) { + $this->assertTrue(true); + } + } + + public function testHasParam() + { + $param = new Elastica_Param(); + + $key = 'name'; + $value = 'nicolas ruflin'; + + $this->assertFalse($param->hasParam($key)); + + $param->setParam($key, $value); + $this->assertTrue($param->hasParam($key)); + } + + protected function _getFilterName($filter) + { + // Picks the last part of the class name and makes it snake_case + $classNameParts = explode('_', get_class($filter)); + + return Elastica_Util::toSnakeCase(array_pop($classNameParts)); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/PercolatorTest.php b/modules/thirdparty/elastica/test/lib/Elastica/PercolatorTest.php new file mode 100644 index 0000000..2b3badb --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/PercolatorTest.php @@ -0,0 +1,62 @@ +_createIndex($percolatorName); + $percolator = new Elastica_Percolator($index); + + $query = new Elastica_Query_Term(array('field1' => 'value1')); + $response = $percolator->registerQuery($percolatorName, $query); + + $data = $response->getData(); + + $expectedArray = array( + 'ok' => true, + '_type' => $index->getName(), + '_index' => '_percolator', + '_id' => $percolatorName, + '_version' => 1 + ); + + $this->assertEquals($expectedArray, $data); + } + + public function testMatchDoc() + { + $client = new Elastica_Client(array('persistent' => false)); + $index = $client->getIndex('elastica_test'); + $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true); + + $percolator = new Elastica_Percolator($index); + + $percolatorName = 'percotest'; + + $query = new Elastica_Query_Term(array('name' => 'ruflin')); + $response = $percolator->registerQuery($percolatorName, $query); + + $this->assertTrue($response->isOk()); + $this->assertFalse($response->hasError()); + + $doc1 = new Elastica_Document(); + $doc1->add('name', 'ruflin'); + + $doc2 = new Elastica_Document(); + $doc2->add('name', 'nicolas'); + + $index = new Elastica_Index($index->getClient(), '_percolator'); + $index->refresh(); + + $matches1 = $percolator->matchDoc($doc1); + + $this->assertTrue(in_array($percolatorName, $matches1)); + $this->assertEquals(1, count($matches1)); + + $matches2 = $percolator->matchDoc($doc2); + $this->assertEmpty($matches2); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/ArrayTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/ArrayTest.php new file mode 100644 index 0000000..595fae6 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/ArrayTest.php @@ -0,0 +1,13 @@ + array('world'), 'name' => 'ruflin'); + $query = new Elastica_Query_Array($testQuery); + + $this->assertEquals($testQuery, $query->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/BoolTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/BoolTest.php new file mode 100755 index 0000000..ed2b1f0 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/BoolTest.php @@ -0,0 +1,105 @@ +setIds(1); + + $idsQuery2 = new Elastica_Query_Ids(); + $idsQuery2->setIds(2); + + $idsQuery3 = new Elastica_Query_Ids(); + $idsQuery3->setIds(3); + + $boost = 1.2; + $minMatch = 2; + + $query->setBoost($boost); + $query->setMinimumNumberShouldMatch($minMatch); + $query->addMust($idsQuery1); + $query->addMustNot($idsQuery2); + $query->addShould($idsQuery3->toArray()); + + $expectedArray = array( + 'bool' => array( + 'must' => array($idsQuery1->toArray()), + 'should' => array($idsQuery3->toArray()), + 'minimum_number_should_match' => $minMatch, + 'must_not' => array($idsQuery2->toArray()), + 'boost' => $boost, + ) + ); + + $this->assertEquals($expectedArray, $query->toArray()); + } + + /** + * Test to resolve the following issue + * + * https://groups.google.com/forum/?fromgroups#!topic/elastica-php-client/zK_W_hClfvU + */ + public function testToArrayStructure() + { + $boolQuery = new Elastica_Query_Bool(); + + $term1 = new Elastica_Query_Term(); + $term1->setParam('interests', 84); + + $term2 = new Elastica_Query_Term(); + $term2->setParam('interests', 92); + + $boolQuery->addShould($term1)->addShould($term2); + + $jsonString = '{"bool":{"should":[{"term":{"interests":84}},{"term":{"interests":92}}]}}'; + $this->assertEquals($jsonString, json_encode($boolQuery->toArray())); + } + + public function testSearch() + { + $client = new Elastica_Client(); + $index = new Elastica_Index($client, 'test'); + $index->create(array(), true); + + $type = new Elastica_Type($index, 'helloworld'); + + $doc = new Elastica_Document(1, array('id' => 1, 'email' => 'hans@test.com', 'username' => 'hans', 'test' => array('2', '3', '5'))); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('id' => 2, 'email' => 'emil@test.com', 'username' => 'emil', 'test' => array('1', '3', '6'))); + $type->addDocument($doc); + $doc = new Elastica_Document(3, array('id' => 3, 'email' => 'ruth@test.com', 'username' => 'ruth', 'test' => array('2', '3', '7'))); + $type->addDocument($doc); + + // Refresh index + $index->refresh(); + + $boolQuery = new Elastica_Query_Bool(); + $termQuery1 = new Elastica_Query_Term(array('test' => '2')); + $boolQuery->addMust($termQuery1); + $resultSet = $type->search($boolQuery); + + $this->assertEquals(2, $resultSet->count()); + + $termQuery2 = new Elastica_Query_Term(array('test' => '5')); + $boolQuery->addMust($termQuery2); + $resultSet = $type->search($boolQuery); + + $this->assertEquals(1, $resultSet->count()); + + $termQuery3 = new Elastica_Query_Term(array('username' => 'hans')); + $boolQuery->addMust($termQuery3); + $resultSet = $type->search($boolQuery); + + $this->assertEquals(1, $resultSet->count()); + + $termQuery4 = new Elastica_Query_Term(array('username' => 'emil')); + $boolQuery->addMust($termQuery4); + $resultSet = $type->search($boolQuery); + + $this->assertEquals(0, $resultSet->count()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/BuilderTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/BuilderTest.php new file mode 100644 index 0000000..a5eabe4 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/BuilderTest.php @@ -0,0 +1,270 @@ +builder = new Elastica_Query_Builder(); + } + + public function tearDown() + { + $this->builder = null; + } + + /** + * @covers Elastica_Query_Builder::factory + * @covers Elastica_Query_Builder::__construct + */ + public function testFactory() + { + $this->assertInstanceOf( + 'Elastica_Query_Builder', + Elastica_Query_Builder::factory('some string') + ); + } + + public function getQueryData() + { + return array( + array('allowLeadingWildcard', false, '{"allow_leading_wildcard":"false"}'), + array('allowLeadingWildcard', true, '{"allow_leading_wildcard":"true"}'), + array('analyzeWildcard', false, '{"analyze_wildcard":"false"}'), + array('analyzeWildcard', true, '{"analyze_wildcard":"true"}'), + array('analyzer', 'someAnalyzer', '{"analyzer":"someAnalyzer"}'), + array('autoGeneratePhraseQueries', true, '{"auto_generate_phrase_queries":"true"}'), + array('autoGeneratePhraseQueries', false, '{"auto_generate_phrase_queries":"false"}'), + array('boost', 2, '{"boost":"2"}'), + array('boost', 4.2, '{"boost":"4.2"}'), + array('defaultField', 'fieldName', '{"default_field":"fieldName"}'), + array('defaultOperator', 'OR', '{"default_operator":"OR"}'), + array('defaultOperator', 'AND', '{"default_operator":"AND"}'), + array('enablePositionIncrements', true, '{"enable_position_increments":"true"}'), + array('enablePositionIncrements', false, '{"enable_position_increments":"false"}'), + array('explain', true, '{"explain":"true"}'), + array('explain', false, '{"explain":"false"}'), + array('from', 42, '{"from":"42"}'), + array('fuzzyMinSim', 4.2, '{"fuzzy_min_sim":"4.2"}'), + array('fuzzyPrefixLength', 2, '{"fuzzy_prefix_length":"2"}'), + array('gt', 10, '{"gt":"10"}'), + array('gte', 11, '{"gte":"11"}'), + array('lowercaseExpandedTerms', true, '{"lowercase_expanded_terms":"true"}'), + array('lt', 10, '{"lt":"10"}'), + array('lte', 11, '{"lte":"11"}'), + array('minimumNumberShouldMatch', 21, '{"minimum_number_should_match":"21"}'), + array('minimumShouldMatch', 21, '{"minimum_number_should_match":"21"}'), + array('phraseSlop', 6, '{"phrase_slop":"6"}'), + array('size', 7, '{"size":"7"}'), + array('tieBreakerMultiplier', 7, '{"tie_breaker_multiplier":"7"}'), + array('tieBreaker', 7, '{"tie_breaker_multiplier":"7"}'), + array('matchAll', 1.1, '{"match_all":{"boost":"1.1"}}'), + array('fields', array("age", "sex", "location"), '{"fields":["age","sex","location"]}'), + ); + } + + /** + * @dataProvider getQueryData + * @covers Elastica_Query_Builder::__toString + * @covers Elastica_Query_Builder::allowLeadingWildcard + * @covers Elastica_Query_Builder::analyzeWildcard + * @covers Elastica_Query_Builder::analyzer + * @covers Elastica_Query_Builder::autoGeneratePhraseQueries + * @covers Elastica_Query_Builder::boost + * @covers Elastica_Query_Builder::defaultField + * @covers Elastica_Query_Builder::defaultOperator + * @covers Elastica_Query_Builder::enablePositionIncrements + * @covers Elastica_Query_Builder::explain + * @covers Elastica_Query_Builder::from + * @covers Elastica_Query_Builder::fuzzyMinSim + * @covers Elastica_Query_Builder::fuzzyPrefixLength + * @covers Elastica_Query_Builder::gt + * @covers Elastica_Query_Builder::gte + * @covers Elastica_Query_Builder::lowercaseExpandedTerms + * @covers Elastica_Query_Builder::lt + * @covers Elastica_Query_Builder::lte + * @covers Elastica_Query_Builder::minimumNumberShouldMatch + * @covers Elastica_Query_Builder::minimumShouldMatch + * @covers Elastica_Query_Builder::phraseSlop + * @covers Elastica_Query_Builder::size + * @covers Elastica_Query_Builder::tieBreakerMultiplier + * @covers Elastica_Query_Builder::tieBreaker + * @covers Elastica_Query_Builder::matchAll + * @covers Elastica_Query_Builder::fields + */ + public function testAllowLeadingWildcard($method, $argument, $result) + { + $this->assertSame($this->builder, $this->builder->$method($argument)); + $this->assertSame($result, (string) $this->builder); + } + + public function getQueryTypes() + { + return array( + array('bool', 'bool'), + array('constantScore', 'constant_score'), + array('disMax', 'dis_max'), + array('facets', 'facets'), + array('filter', 'filter'), + array('filteredQuery', 'filtered'), + array('must', 'must'), + array('mustNot', 'must_not'), + array('prefix', 'prefix'), + array('query', 'query'), + array('queryString', 'query_string'), + array('range', 'range'), + array('should', 'should'), + array('sort', 'sort'), + array('term', 'term'), + array('textPhrase', 'text_phrase'), + array('wildcard', 'wildcard'), + ); + } + + /** + * @dataProvider getQueryTypes + * + * @covers Elastica_Query_Builder::fieldClose + * @covers Elastica_Query_Builder::close + * + * @covers Elastica_Query_Builder::bool + * @covers Elastica_Query_Builder::boolClose + * @covers Elastica_Query_Builder::constantScore + * @covers Elastica_Query_Builder::constantScoreClose + * @covers Elastica_Query_Builder::disMax + * @covers Elastica_Query_Builder::disMaxClose + * @covers Elastica_Query_Builder::facets + * @covers Elastica_Query_Builder::facetsClose + * @covers Elastica_Query_Builder::filter + * @covers Elastica_Query_Builder::filterClose + * @covers Elastica_Query_Builder::filteredQuery + * @covers Elastica_Query_Builder::filteredQueryClose + * @covers Elastica_Query_Builder::must + * @covers Elastica_Query_Builder::mustClose + * @covers Elastica_Query_Builder::mustNot + * @covers Elastica_Query_Builder::mustNotClose + * @covers Elastica_Query_Builder::prefix + * @covers Elastica_Query_Builder::prefixClose + * @covers Elastica_Query_Builder::query + * @covers Elastica_Query_Builder::queryClose + * @covers Elastica_Query_Builder::queryString + * @covers Elastica_Query_Builder::queryStringClose + * @covers Elastica_Query_Builder::range + * @covers Elastica_Query_Builder::rangeClose + * @covers Elastica_Query_Builder::should + * @covers Elastica_Query_Builder::shouldClose + * @covers Elastica_Query_Builder::sort + * @covers Elastica_Query_Builder::sortClose + * @covers Elastica_Query_Builder::term + * @covers Elastica_Query_Builder::termClose + * @covers Elastica_Query_Builder::textPhrase + * @covers Elastica_Query_Builder::textPhraseClose + * @covers Elastica_Query_Builder::wildcard + * @covers Elastica_Query_Builder::wildcardClose + */ + public function testQueryTypes($method, $queryType) + { + $this->assertSame($this->builder, $this->builder->$method()); // open + $this->assertSame($this->builder, $this->builder->{$method."Close"}()); // close + $this->assertSame('{"' . $queryType . '":{}}', (string) $this->builder); + } + + /** + * @covers Elastica_Query_Builder::fieldOpen + * @covers Elastica_Query_Builder::fieldClose + * @covers Elastica_Query_Builder::open + * @covers Elastica_Query_Builder::close + */ + public function testFieldOpenAndClose() + { + $this->assertSame($this->builder, $this->builder->fieldOpen('someField')); + $this->assertSame($this->builder, $this->builder->fieldClose()); + $this->assertSame('{"someField":{}}', (string) $this->builder); + } + + /** + * @covers Elastica_Query_Builder::sortField + */ + public function testSortField() + { + $this->assertSame($this->builder, $this->builder->sortField('name', true)); + $this->assertSame('{"sort":{"name":{"reverse":"true"}}}', (string) $this->builder); + } + + /** + * @covers Elastica_Query_Builder::sortFields + */ + public function testSortFields() + { + $this->assertSame($this->builder, $this->builder->sortFields(array('field1' => 'asc', 'field2' => 'desc', 'field3' => 'asc'))); + $this->assertSame('{"sort":[{"field1":"asc"},{"field2":"desc"},{"field3":"asc"}]}', (string) $this->builder); + } + + /** + * @covers Elastica_Query_Builder::queries + */ + public function testQueries() + { + $queries = array(); + + $b1 = clone $this->builder; + $b2 = clone $this->builder; + + $queries[] = $b1->term()->field('age', 34)->termClose(); + $queries[] = $b2->term()->field('name', 'christer')->termClose(); + + $this->assertSame($this->builder, $this->builder->queries($queries)); + $this->assertSame('{"queries":[{"term":{"age":"34"}},{"term":{"name":"christer"}}]}', (string) $this->builder); + } + + public function getFieldData() + { + return array( + array('name', 'value', '{"name":"value"}'), + array('name', true, '{"name":"true"}'), + array('name', false, '{"name":"false"}'), + array('name', array(1, 2, 3), '{"name":["1","2","3"]}'), + array('name', array('foo', 'bar', 'baz'), '{"name":["foo","bar","baz"]}'), + ); + } + + /** + * @dataProvider getFieldData + * @covers Elastica_Query_Builder::field + */ + public function testField($name, $value, $result) + { + $this->assertSame($this->builder, $this->builder->field($name, $value)); + $this->assertSame($result, (string) $this->builder); + } + + /** + * @expectedException Elastica_Exception_Invalid + * @covers Elastica_Query_Builder::toArray + */ + public function testToArrayWithInvalidData() + { + $this->builder->open('foo'); + $this->builder->toArray(); + } + + /** + * @covers Elastica_Query_Builder::toArray + */ + public function testToArray() + { + $this->builder->query()->term()->field('category.id', array(1, 2, 3))->termClose()->queryClose(); + $this->assertEquals(array( + 'query' => array( + 'term' => array( + 'category.id' => array(1, 2, 3) + ) + ) + ), $this->builder->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/ConstantScoreTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/ConstantScoreTest.php new file mode 100644 index 0000000..88b0c01 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/ConstantScoreTest.php @@ -0,0 +1,105 @@ + array( + 'filter' => array( + 'term' => array( + 'foo', + 'bar', + ), + ), + ), + ), + ), + array( + array( + 'and' => array( + array( + 'query' => array( + 'query_string' => array( + 'query' => 'foo', + 'default_field' => 'something', + ), + ), + ), + array( + 'query' => array( + 'query_string' => array( + 'query' => 'bar', + 'default_field' => 'something', + ), + ), + ), + ), + ), + '{"constant_score":{"filter":{"and":[{"query":{"query_string":{"query":"foo","default_field":"something"}}},{"query":{"query_string":{"query":"bar","default_field":"something"}}}]}}}', + ), + ); + } + /** + * @dataProvider dataProviderSampleQueries + */ + public function testSimple($filter, $expected) + { + $query = new Elastica_Query_ConstantScore(); + $query->setFilter($filter); + if (is_string($expected)) { + $expected = json_decode($expected, true); + } + $this->assertEquals($expected, $query->toArray()); + } + + public function testToArray() + { + $query = new Elastica_Query_ConstantScore(); + + $boost = 1.2; + $filter = new Elastica_Filter_Ids(); + $filter->setIds(array(1)); + + $query->setFilter($filter); + $query->setBoost($boost); + + $expectedArray = array( + 'constant_score' => array( + 'filter' => $filter->toArray(), + 'boost' => $boost + ) + ); + + $this->assertEquals($expectedArray, $query->toArray()); + } + + public function testConstruct() + { + $filter = new Elastica_Filter_Ids(); + $filter->setIds(array(1)); + + $query = new Elastica_Query_ConstantScore($filter); + + $expectedArray = array( + 'constant_score' => array( + 'filter' => $filter->toArray(), + ) + ); + + $this->assertEquals($expectedArray, $query->toArray()); + + } + + public function testConstructEmpty() + { + $query = new Elastica_Query_ConstantScore(); + $expectedArray = array('constant_score' => array()); + + $this->assertEquals($expectedArray, $query->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/CustomScoreTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/CustomScoreTest.php new file mode 100644 index 0000000..0aa2030 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/CustomScoreTest.php @@ -0,0 +1,19 @@ +setQuery($query); + $customscore_query->setScript("doc['hits'].value * (param1 + param2)"); + $customscore_query->addParams(array('param1' => 1123, 'param2' => 2001)); + + $experted = '{"custom_score":{"query":{"match_all":{}},"script":"doc[\'hits\'].value * (param1 + param2)","params":{"param1":1123,"param2":2001}}}'; + + $this->assertEquals($experted, json_encode($customscore_query->toArray())); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/FieldTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/FieldTest.php new file mode 100644 index 0000000..0945511 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/FieldTest.php @@ -0,0 +1,43 @@ +getIndex('test'); + $index->create(array(), true); + $type = $index->getType('test'); + + $doc = new Elastica_Document(1, array('name' => 'Basel-Stadt')); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('name' => 'New York')); + $type->addDocument($doc); + $doc = new Elastica_Document(3, array('name' => 'Baden')); + $type->addDocument($doc); + $doc = new Elastica_Document(4, array('name' => 'Baden Baden')); + $type->addDocument($doc); + + $index->refresh(); + + $type = 'text_phrase'; + $field = 'name'; + + $query = new Elastica_Query_Field(); + $query->setField('name'); + $query->setQueryString('"Baden Baden"'); + + $resultSet = $index->search($query); + + $this->assertEquals(1, $resultSet->count()); + } + + public function testToArray() + { + $query = new Elastica_Query_Field('user', 'jack'); + $expected = array('field' => array('user' => array('query' => 'jack'))); + + $this->assertSame($expected, $query->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/FilteredTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/FilteredTest.php new file mode 100644 index 0000000..3061adb --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/FilteredTest.php @@ -0,0 +1,39 @@ +getIndex('test'); + $index->create(array(), true); + $type = $index->getType('helloworld'); + + $doc = new Elastica_Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'hanswurst', 'test' => array('2', '3', '5'))); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('id' => 2, 'email' => 'test@test.com', 'username' => 'peter', 'test' => array('2', '3', '5'))); + $type->addDocument($doc); + + $queryString = new Elastica_Query_QueryString('test*'); + + $filter1 = new Elastica_Filter_Term(); + $filter1->setTerm('username', 'peter'); + + $filter2 = new Elastica_Filter_Term(); + $filter2->setTerm('username', 'qwerqwer'); + + $query1 = new Elastica_Query_Filtered($queryString, $filter1); + $query2 = new Elastica_Query_Filtered($queryString, $filter2); + $index->refresh(); + + $resultSet = $type->search($queryString); + $this->assertEquals(2, $resultSet->count()); + + $resultSet = $type->search($query1); + $this->assertEquals(1, $resultSet->count()); + + $resultSet = $type->search($query2); + $this->assertEquals(0, $resultSet->count()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/FuzzyLikeThisTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/FuzzyLikeThisTest.php new file mode 100644 index 0000000..41e981d --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/FuzzyLikeThisTest.php @@ -0,0 +1,97 @@ +create(array(), true); + $index->getSettings()->setNumberOfReplicas(0); + //$index->getSettings()->setNumberOfShards(1); + + $type = new Elastica_Type($index, 'helloworldfuzzy'); + $mapping = new Elastica_Type_Mapping($type , array( + 'email' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'), + 'content' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'), + )); + + $mapping->setSource(array('enabled' => false)); + $type->setMapping($mapping); + + $doc = new Elastica_Document(1000, array('email' => 'testemail@gmail.com', 'content' => 'This is a sample post. Hello World Fuzzy Like This!')); + $type->addDocument($doc); + + // Refresh index + $index->refresh(); + + $fltQuery = new Elastica_Query_FuzzyLikeThis(); + $fltQuery->setLikeText("sample gmail"); + $fltQuery->addFields(array("email","content")); + $fltQuery->setMinSimilarity(0.3); + $fltQuery->setMaxQueryTerms(3); + $resultSet = $type->search($fltQuery); + $this->assertEquals(1, $resultSet->count()); + } + + public function testSetPrefixLength() + { + $query = new Elastica_Query_FuzzyLikeThis(); + + $length = 3; + $query->setPrefixLength($length); + + $data = $query->toArray(); + + $this->assertEquals($length, $data['fuzzy_like_this']['prefix_length']); + } + + public function testAddFields() + { + $query = new Elastica_Query_FuzzyLikeThis(); + + $fields = array('test1', 'test2'); + $query->addFields($fields); + + $data = $query->toArray(); + + $this->assertEquals($fields, $data['fuzzy_like_this']['fields']); + } + + public function testSetLikeText() + { + $query = new Elastica_Query_FuzzyLikeThis(); + + $text = ' hello world'; + $query->setLikeText($text); + + $data = $query->toArray(); + + $this->assertEquals(trim($text), $data['fuzzy_like_this']['like_text']); + } + + public function testSetMinSimilarity() + { + $query = new Elastica_Query_FuzzyLikeThis(); + + $similarity = 2; + $query->setMinSimilarity($similarity); + + $data = $query->toArray(); + + $this->assertEquals($similarity, $data['fuzzy_like_this']['min_similarity']); + } + + public function testSetBoost() + { + $query = new Elastica_Query_FuzzyLikeThis(); + + $boost = 2.2; + $query->setBoost($boost); + + $data = $query->toArray(); + + $this->assertEquals($boost, $data['fuzzy_like_this']['boost']); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/FuzzyTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/FuzzyTest.php new file mode 100644 index 0000000..8bba2cf --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/FuzzyTest.php @@ -0,0 +1,52 @@ +addField('user', array('value' => 'Nicolas', 'boost' => 1.0)); + + $expectedArray = array( + 'fuzzy' => array( + 'user' => array( + 'value' => 'Nicolas', + 'boost' => 1.0 + ) + ) + ); + + $this->assertEquals($expectedArray, $fuzzy->toArray()); + } + + public function testQuery() + { + $client = new Elastica_Client(); + $index = $client->getIndex('test'); + $index->create(array(), true); + $type = $index->getType('test'); + + $doc = new Elastica_Document(1, array('name' => 'Basel-Stadt')); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('name' => 'New York')); + $type->addDocument($doc); + $doc = new Elastica_Document(3, array('name' => 'Baden')); + $type->addDocument($doc); + $doc = new Elastica_Document(4, array('name' => 'Baden Baden')); + $type->addDocument($doc); + + $index->refresh(); + + $type = 'text_phrase'; + $field = 'name'; + + $query = new Elastica_Query_Fuzzy(); + $query->addField('name', array('value' => 'Baden')); + + $resultSet = $index->search($query); + + $this->assertEquals(2, $resultSet->count()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/HasChildTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/HasChildTest.php new file mode 100644 index 0000000..1e9cca5 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/HasChildTest.php @@ -0,0 +1,25 @@ +setIds(12); + + $type = 'test'; + + $query = new Elastica_Query_HasChild($ids, $type); + $query->setType($type); + + $expectedArray = array( + 'has_child' => array( + 'type' => $type, + 'query' => $ids->toArray(), + ) + ); + + $this->assertEquals($expectedArray, $query->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/HighlightTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/HighlightTest.php new file mode 100644 index 0000000..a27043c --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/HighlightTest.php @@ -0,0 +1,43 @@ +getIndex('test'); + $index->create(array(), true); + $type = $index->getType('helloworld'); + + $phrase = 'My name is ruflin'; + + $doc = new Elastica_Document(1, array('id' => 1, 'phrase' => $phrase, 'username' => 'hanswurst', 'test' => array('2', '3', '5'))); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('id' => 2, 'phrase' => $phrase, 'username' => 'peter', 'test' => array('2', '3', '5'))); + $type->addDocument($doc); + + $queryString = new Elastica_Query_QueryString('rufl*'); + $query = new Elastica_Query($queryString); + $query->setHighlight(array( + 'pre_tags' => array(''), + 'post_tags' => array(''), + 'fields' => array( + 'phrase' => array( + 'fragment_size' => 200, + 'number_of_fragments' => 1, + ), + ), + )); + + $index->refresh(); + + $resultSet = $type->search($query); + foreach ($resultSet as $result) { + $highlight = $result->getHighlights(); + $this->assertEquals(array('phrase' => array(0 => 'My name is ruflin')), $highlight); + } + $this->assertEquals(2, $resultSet->count()); + + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/IdsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/IdsTest.php new file mode 100644 index 0000000..052c0e4 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/IdsTest.php @@ -0,0 +1,160 @@ +getIndex('test'); + $index->create(array(), true); + + $type1 = $index->getType('helloworld1'); + $type2 = $index->getType('helloworld2'); + + $doc = new Elastica_Document(1, array('name' => 'hello world')); + $type1->addDocument($doc); + + $doc = new Elastica_Document(2, array('name' => 'nicolas ruflin')); + $type1->addDocument($doc); + + $doc = new Elastica_Document(3, array('name' => 'ruflin')); + $type1->addDocument($doc); + + $doc = new Elastica_Document(4, array('name' => 'hello world again')); + $type2->addDocument($doc); + + $index->refresh(); + + $this->_type = $type1; + $this->_index = $index; + } + + public function tearDown() + { + $client = new Elastica_Client(); + $index = $client->getIndex('test'); + $index->delete(); + } + + public function testSetIdsSearchSingle() + { + $query = new Elastica_Query_Ids(); + $query->setIds('1'); + + $resultSet = $this->_type->search($query); + + $this->assertEquals(1, $resultSet->count()); + } + + public function testSetIdsSearchArray() + { + $query = new Elastica_Query_Ids(); + $query->setIds(array('1', '2')); + + $resultSet = $this->_type->search($query); + + $this->assertEquals(2, $resultSet->count()); + } + + public function testAddIdsSearchSingle() + { + $query = new Elastica_Query_Ids(); + $query->addId('3'); + + $resultSet = $this->_type->search($query); + + $this->assertEquals(1, $resultSet->count()); + } + + public function testComboIdsSearchArray() + { + $query = new Elastica_Query_Ids(); + + $query->setIds(array('1', '2')); + $query->addId('3'); + + $resultSet = $this->_type->search($query); + + $this->assertEquals(3, $resultSet->count()); + } + + public function testSetTypeSingleSearchSingle() + { + $query = new Elastica_Query_Ids(); + + $query->setIds('1'); + $query->setType('helloworld1'); + + $resultSet = $this->_index->search($query); + + $this->assertEquals(1, $resultSet->count()); + } + + public function testSetTypeSingleSearchArray() + { + $query = new Elastica_Query_Ids(); + + $query->setIds(array('1', '2')); + $query->setType('helloworld1'); + + $resultSet = $this->_index->search($query); + + $this->assertEquals(2, $resultSet->count()); + } + + public function testSetTypeSingleSearchSingleDocInOtherType() + { + $query = new Elastica_Query_Ids(); + + // Doc 4 is in the second type... + $query->setIds('4'); + $query->setType('helloworld1'); + + $resultSet = $this->_index->search($query); + + // ...therefore 0 results should be returned + $this->assertEquals(0, $resultSet->count()); + } + + public function testSetTypeSingleSearchArrayDocInOtherType() + { + $query = new Elastica_Query_Ids(); + + // Doc 4 is in the second type... + $query->setIds(array('1', '4')); + $query->setType('helloworld1'); + + $resultSet = $this->_index->search($query); + + // ...therefore only 1 result should be returned + $this->assertEquals(1, $resultSet->count()); + } + + public function testSetTypeArraySearchArray() + { + $query = new Elastica_Query_Ids(); + + $query->setIds(array('1', '4')); + $query->setType(array('helloworld1', 'helloworld2')); + + $resultSet = $this->_index->search($query); + + $this->assertEquals(2, $resultSet->count()); + } + + public function testSetTypeArraySearchSingle() + { + $query = new Elastica_Query_Ids(); + + $query->setIds('4'); + $query->setType(array('helloworld1', 'helloworld2')); + + $resultSet = $this->_index->search($query); + + $this->assertEquals(1, $resultSet->count()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/MatchAllTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/MatchAllTest.php new file mode 100644 index 0000000..e28be57 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/MatchAllTest.php @@ -0,0 +1,14 @@ + new stdClass()); + + $this->assertEquals($expectedArray, $query->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/MoreLikeThisTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/MoreLikeThisTest.php new file mode 100644 index 0000000..2a92dd9 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/MoreLikeThisTest.php @@ -0,0 +1,167 @@ +create(array(), true); + $index->getSettings()->setNumberOfReplicas(0); + //$index->getSettings()->setNumberOfShards(1); + + $type = new Elastica_Type($index, 'helloworldmlt'); + $mapping = new Elastica_Type_Mapping($type , array( + 'email' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'), + 'content' => array('store' => 'yes', 'type' => 'string', 'index' => 'analyzed'), + )); + + $mapping->setSource(array('enabled' => false)); + $type->setMapping($mapping); + + $doc = new Elastica_Document(1000, array('email' => 'testemail@gmail.com', 'content' => 'This is a sample post. Hello World Fuzzy Like This!')); + $type->addDocument($doc); + + $doc = new Elastica_Document(1001, array('email' => 'nospam@gmail.com', 'content' => 'This is a fake nospam email address for gmail')); + $type->addDocument($doc); + + // Refresh index + $index->refresh(); + + $mltQuery = new Elastica_Query_MoreLikeThis(); + $mltQuery->setLikeText('fake gmail sample'); + $mltQuery->setFields(array('email','content')); + $mltQuery->setMaxQueryTerms(1); + $mltQuery->setMinDocFrequency(1); + $mltQuery->setMinTermFrequency(1); + + $query = new Elastica_Query(); + $query->setFields(array('email', 'content')); + $query->setQuery($mltQuery); + + $resultSet = $type->search($query); + $resultSet->getResponse()->getData(); + $this->assertEquals(2, $resultSet->count()); + } + + public function testSetFields() + { + $query = new Elastica_Query_MoreLikeThis(); + + $fields = array('firstname', 'lastname'); + $query->setFields($fields); + + $data = $query->toArray(); + $this->assertEquals($fields, $data['more_like_this']['fields']); + } + + public function testSetLikeText() + { + $query = new Elastica_Query_MoreLikeThis(); + $query->setLikeText(' hello world'); + + $data = $query->toArray(); + $this->assertEquals('hello world', $data['more_like_this']['like_text']); + } + + public function testSetBoost() + { + $query = new Elastica_Query_MoreLikeThis(); + + $boost = 1.3; + $query->setBoost($boost); + + $this->assertEquals($boost, $query->getParam('boost')); + } + + public function testSetMaxQueryTerms() + { + $query = new Elastica_Query_MoreLikeThis(); + + $max = 3; + $query->setMaxQueryTerms($max); + + $this->assertEquals($max, $query->getParam('max_query_terms')); + } + + public function testSetPercentTermsToMatch() + { + $query = new Elastica_Query_MoreLikeThis(); + + $match = 0.8; + $query->setPercentTermsToMatch($match); + + $this->assertEquals($match, $query->getParam('percent_terms_to_match')); + } + + public function testSetMinDocFrequency() + { + $query = new Elastica_Query_MoreLikeThis(); + + $freq = 2; + $query->setMinDocFrequency($freq); + + $this->assertEquals($freq, $query->getParam('min_doc_freq')); + } + + public function testSetMaxDocFrequency() + { + $query = new Elastica_Query_MoreLikeThis(); + + $freq = 2; + $query->setMaxDocFrequency($freq); + + $this->assertEquals($freq, $query->getParam('max_doc_freq')); + } + + public function testSetMinWordLength() + { + $query = new Elastica_Query_MoreLikeThis(); + + $length = 4; + $query->setMinWordLength($length); + + $this->assertEquals($length, $query->getParam('min_word_length')); + } + + public function testSetMaxWordLength() + { + $query = new Elastica_Query_MoreLikeThis(); + + $length = 5; + $query->setMaxWordLength($length); + + $this->assertEquals($length, $query->getParam('max_word_length')); + } + + public function testSetBoostTerms() + { + $query = new Elastica_Query_MoreLikeThis(); + + $boost = false; + $query->setBoostTerms($boost); + + $this->assertEquals($boost, $query->getParam('boost_terms')); + } + + public function testSetAnalyzer() + { + $query = new Elastica_Query_MoreLikeThis(); + + $analyzer = 'UpperCase'; + $query->setAnalyzer($analyzer); + + $this->assertEquals($analyzer, $query->getParam('analyzer')); + } + + public function testSetStopWords() + { + $query = new Elastica_Query_MoreLikeThis(); + + $stopWords = array('no', 'yes', 'test'); + $query->setStopWords($stopWords); + + $this->assertEquals($stopWords, $query->getParam('stop_words')); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/NestedTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/NestedTest.php new file mode 100644 index 0000000..f7f43d5 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/NestedTest.php @@ -0,0 +1,23 @@ +assertInstanceOf('Elastica_Query_Nested', $nested->setQuery($queryString)); + $this->assertInstanceOf('Elastica_Query_Nested', $nested->setPath($path)); + $expected = array( + 'nested' => array( + 'query' => $queryString->toArray(), + 'path' => $path, + ) + ); + + $this->assertEquals($expected, $nested->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/QueryStringTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/QueryStringTest.php new file mode 100755 index 0000000..e06029c --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/QueryStringTest.php @@ -0,0 +1,100 @@ + $str + ); + + $this->assertEquals(array('query_string' => $expected), $query->toArray()); + + $fields = array(); + $max = rand() % 10 + 1; + for ($i = 0; $i < $max; $i++) { + $fields[] = md5(rand()); + } + + $query->setFields($fields); + $expected['fields'] = $fields; + $this->assertEquals(array('query_string' => $expected), $query->toArray()); + + foreach (array(false, true) as $val) { + $query->setUseDisMax($val); + $expected['use_dis_max'] = $val; + + $this->assertEquals(array('query_string' => $expected), $query->toArray()); + } + } + + public function testSearch() + { + $client = new Elastica_Client(); + $index = new Elastica_Index($client, 'test'); + $index->create(array(), true); + $index->getSettings()->setNumberOfReplicas(0); + //$index->getSettings()->setNumberOfShards(1); + + $type = new Elastica_Type($index, 'helloworld'); + + $doc = new Elastica_Document(1, array('email' => 'test@test.com', 'username' => 'hanswurst', 'test' => array('2', '3', '5'))); + $type->addDocument($doc); + + // Refresh index + $index->refresh(); + + $queryString = new Elastica_Query_QueryString('test*'); + $resultSet = $type->search($queryString); + + $this->assertEquals(1, $resultSet->count()); + } + + public function testSetDefaultOperator() + { + $operator = 'AND'; + $query = new Elastica_Query_QueryString('test'); + $query->setDefaultOperator($operator); + + $data = $query->toArray(); + + $this->assertEquals($data['query_string']['default_operator'], $operator); + } + + public function testSetDefaultField() + { + $default = 'field1'; + $query = new Elastica_Query_QueryString('test'); + $query->setDefaultField($default); + + $data = $query->toArray(); + + $this->assertEquals($data['query_string']['default_field'], $default); + } + + public function testSetRewrite() + { + $rewrite = 'scoring_boolean'; + $query = new Elastica_Query_QueryString('test'); + $query->setRewrite($rewrite); + + $data = $query->toArray(); + + $this->assertEquals($data['query_string']['rewrite'], $rewrite); + } + + public function testSetQueryStringInvalid() + { + $query = new Elastica_Query_QueryString(); + try { + $query->setQueryString(array()); + $this->fail('should throw exception because no string'); + } catch (Elastica_Exception_Invalid $e) { + $this->assertTrue(true); + } + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/RangeTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/RangeTest.php new file mode 100644 index 0000000..6771245 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/RangeTest.php @@ -0,0 +1,21 @@ + 20, 'to' => 40); + $range->addField('age', $field); + + $expectedArray = array( + 'range' => array( + 'age' => $field, + ) + ); + + $this->assertEquals($expectedArray, $range->toArray()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/TermTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/TermTest.php new file mode 100644 index 0000000..a16a0f5 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/TermTest.php @@ -0,0 +1,22 @@ +setTerm($key, $value, $boost); + + $data = $query->toArray(); + + $this->assertInternalType('array', $data['term']); + $this->assertInternalType('array', $data['term'][$key]); + $this->assertEquals($data['term'][$key]['value'], $value); + $this->assertEquals($data['term'][$key]['boost'], $boost); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/TermsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/TermsTest.php new file mode 100644 index 0000000..f9399d2 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/TermsTest.php @@ -0,0 +1,60 @@ +getIndex('test'); + $index->create(array(), true); + $type = $index->getType('helloworld'); + + $doc = new Elastica_Document(1, array('name' => 'hello world')); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('name' => 'nicolas ruflin')); + $type->addDocument($doc); + $doc = new Elastica_Document(3, array('name' => 'ruflin')); + $type->addDocument($doc); + + $query = new Elastica_Query_Terms(); + $query->setTerms('name', array('nicolas', 'hello')); + + $index->refresh(); + + $resultSet = $type->search($query); + + $this->assertEquals(2, $resultSet->count()); + + $query->addTerm('ruflin'); + $resultSet = $type->search($query); + + $this->assertEquals(3, $resultSet->count()); + } + + public function testSetMinimum() + { + $key = 'name'; + $terms = array('nicolas', 'ruflin'); + $minimum = 2; + + $query = new Elastica_Query_Terms($key, $terms); + $query->setMinimumMatch($minimum); + + $data = $query->toArray(); + $this->assertEquals($minimum, $data['terms']['minimum_match']); + } + + public function testInvalidParams() + { + $query = new Elastica_Query_Terms(); + + try { + $query->toArray(); + $this->fail('Should throw exception because no key'); + } catch (Elastica_Exception_Invalid $e) { + $this->assertTrue(true); + } + + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/TextTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/TextTest.php new file mode 100644 index 0000000..b87e12c --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/TextTest.php @@ -0,0 +1,64 @@ +setFieldQuery($field, $queryText); + $query->setFieldType($field, $type); + $query->setFieldParam($field, 'analyzer', $analyzer); + $query->setFieldMaxExpansions($field, $maxExpansions); + + $expectedArray = array( + 'text' => array( + $field => array( + 'query' => $queryText, + 'type' => $type, + 'analyzer' => $analyzer, + 'max_expansions' => $maxExpansions, + ) + ) + ); + + $this->assertEquals($expectedArray, $query->toArray()); + } + + public function testTextPhrase() + { + $client = new Elastica_Client(); + $index = $client->getIndex('test'); + $index->create(array(), true); + $type = $index->getType('test'); + + $doc = new Elastica_Document(1, array('name' => 'Basel-Stadt')); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('name' => 'New York')); + $type->addDocument($doc); + $doc = new Elastica_Document(3, array('name' => 'New Hampshire')); + $type->addDocument($doc); + $doc = new Elastica_Document(4, array('name' => 'Basel Land')); + $type->addDocument($doc); + + $index->refresh(); + + $type = 'text_phrase'; + $field = 'name'; + + $query = new Elastica_Query_Text(); + $query->setFieldQuery($field, 'Basel New'); + $query->setField('operator', 'OR'); + $query->setFieldType($field, $type); + + $resultSet = $index->search($query); + + $this->assertEquals(4, $resultSet->count()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Query/WildcardTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Query/WildcardTest.php new file mode 100644 index 0000000..13ea562 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Query/WildcardTest.php @@ -0,0 +1,95 @@ +assertEmpty($wildcard->getParams()); + } + + public function testToArray() + { + $key = 'name'; + $value = 'Ru*lin'; + $boost = 2.0; + + $wildcard = new Elastica_Query_Wildcard($key, $value, $boost); + + $expectedArray = array( + 'wildcard' => array( + $key => array( + 'value' => $value, + 'boost' => $boost + ) + ) + ); + + $this->assertEquals($expectedArray, $wildcard->toArray()); + } + + public function testSearchWithAnalyzer() + { + $client = new Elastica_Client(); + $index = $client->getIndex('test'); + + $indexParams = array( + 'analysis' => array( + 'analyzer' => array( + 'lw' => array( + 'type' => 'custom', + 'tokenizer' => 'keyword', + 'filter' => array('lowercase') + ) + ), + ) + ); + + $index->create($indexParams, true); + $type = $index->getType('test'); + + $mapping = new Elastica_Type_Mapping($type, array( + 'name' => array('type' => 'string', 'store' => 'no', 'analyzer' => 'lw'), + ) + ); + $type->setMapping($mapping); + + $doc = new Elastica_Document(1, array('name' => 'Basel-Stadt')); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('name' => 'New York')); + $type->addDocument($doc); + $doc = new Elastica_Document(3, array('name' => 'Baden')); + $type->addDocument($doc); + $doc = new Elastica_Document(4, array('name' => 'Baden Baden')); + $type->addDocument($doc); + $doc = new Elastica_Document(5, array('name' => 'New Orleans')); + $type->addDocument($doc); + + $index->refresh(); + + $query = new Elastica_Query_Wildcard(); + $query->setValue('name', 'ba*'); + $resultSet = $index->search($query); + + $this->assertEquals(3, $resultSet->count()); + + $query = new Elastica_Query_Wildcard(); + $query->setValue('name', 'baden*'); + $resultSet = $index->search($query); + + $this->assertEquals(2, $resultSet->count()); + + $query = new Elastica_Query_Wildcard(); + $query->setValue('name', 'baden b*'); + $resultSet = $index->search($query); + + $this->assertEquals(1, $resultSet->count()); + + $query = new Elastica_Query_Wildcard(); + $query->setValue('name', 'baden bas*'); + $resultSet = $index->search($query); + + $this->assertEquals(0, $resultSet->count()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/QueryTest.php b/modules/thirdparty/elastica/test/lib/Elastica/QueryTest.php new file mode 100644 index 0000000..f613a5a --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/QueryTest.php @@ -0,0 +1,150 @@ +toArray(); + + $this->assertInternalType('array', $queryArray); + + $this->assertEquals('2011-07-18 00:00:00', $queryArray['query']['filtered']['filter']['range']['due']['gte']); + } + + public function testRawQuery() + { + $textQuery = new Elastica_Query_Text(); + $textQuery->setField('title', 'test'); + + $query1 = Elastica_Query::create($textQuery); + + $query2 = new Elastica_Query(); + $query2->setRawQuery(array('query' => array('text' => array('title' => 'test')))); + + $this->assertEquals($query1->toArray(), $query2->toArray()); + } + + public function testSetSort() + { + $index = $this->_createIndex(); + $type = $index->getType('test'); + + $doc = new Elastica_Document(1, array('name' => 'hello world')); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('firstname' => 'guschti', 'lastname' => 'ruflin')); + $type->addDocument($doc); + $doc = new Elastica_Document(3, array('firstname' => 'nicolas', 'lastname' => 'ruflin')); + $type->addDocument($doc); + + $queryTerm = new Elastica_Query_Term(); + $queryTerm->setTerm('lastname', 'ruflin'); + + $index->refresh(); + + $query = Elastica_Query::create($queryTerm); + + // ASC order + $query->setSort(array(array('firstname' => array('order' => 'asc')))); + $resultSet = $type->search($query); + $this->assertEquals(2, $resultSet->count()); + + $first = $resultSet->current()->getData(); + $second = $resultSet->next()->getData(); + + $this->assertEquals('guschti', $first['firstname']); + $this->assertEquals('nicolas', $second['firstname']); + + // DESC order + $query->setSort(array('firstname' => array('order' => 'desc'))); + $resultSet = $type->search($query); + $this->assertEquals(2, $resultSet->count()); + + $first = $resultSet->current()->getData(); + $second = $resultSet->next()->getData(); + + $this->assertEquals('nicolas', $first['firstname']); + $this->assertEquals('guschti', $second['firstname']); + } + + public function testAddSort() + { + $query = new Elastica_Query(); + $sortParam = array('firstname' => array('order' => 'asc')); + $query->addSort($sortParam); + + $this->assertEquals($query->getParam('sort'), array($sortParam)); + } + + public function testSetRawQuery() + { + $query = new Elastica_Query(); + + $params = array('query' => 'test'); + $query->setRawQuery($params); + + $this->assertEquals($params, $query->toArray()); + } + + public function testSetFields() + { + $query = new Elastica_Query(); + + $params = array('query' => 'test'); + + $query->setFields(array('firstname', 'lastname')); + + $data = $query->toArray(); + + $this->assertContains('firstname', $data['fields']); + $this->assertContains('lastname', $data['fields']); + $this->assertEquals(2, count($data['fields'])); + } + + public function testGetQuery() + { + $query = new Elastica_Query(); + + try { + $query->getQuery(); + $this->fail('should throw exception because query does not exist'); + } catch (Elastica_Exception_Invalid $e) { + $this->assertTrue(true); + } + + $termQuery = new Elastica_Query_Term(); + $termQuery->setTerm('text', 'value'); + $query->setQuery($termQuery); + + $this->assertEquals($termQuery->toArray(), $query->getQuery()); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/ResponseTest.php b/modules/thirdparty/elastica/test/lib/Elastica/ResponseTest.php new file mode 100644 index 0000000..4e773b4 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/ResponseTest.php @@ -0,0 +1,48 @@ +assertInstanceOf('Elastica_Facet_Histogram', $facet); + $this->assertInstanceOf('Elastica_Facet_Abstract', $facet); + unset($facet); + } + + public function testResponse() + { + $index = $this->_createIndex(); + $type = $index->getType('helloworld'); + + $mapping = new Elastica_Type_Mapping($type, array( + 'name' => array('type' => 'string', 'store' => 'no'), + 'dtmPosted' => array('type' => 'date', 'store' => 'no', 'format' => 'yyyy-MM-dd HH:mm:ss') + )); + $type->setMapping($mapping); + + $doc = new Elastica_Document(1, array('name' => 'nicolas ruflin', 'dtmPosted' => "2011-06-23 21:53:00")); + $type->addDocument($doc); + $doc = new Elastica_Document(2, array('name' => 'raul martinez jr', 'dtmPosted' => "2011-06-23 09:53:00")); + $type->addDocument($doc); + $doc = new Elastica_Document(3, array('name' => 'rachelle clemente', 'dtmPosted' => "2011-07-08 08:53:00")); + $type->addDocument($doc); + $doc = new Elastica_Document(4, array('name' => 'elastica search', 'dtmPosted' => "2011-07-08 01:53:00")); + $type->addDocument($doc); + + $query = new Elastica_Query(); + $query->setQuery(new Elastica_Query_MatchAll()); + $index->refresh(); + + $resultSet = $type->search($query); + + $engineTime = $resultSet->getResponse()->getEngineTime(); + $shardsStats = $resultSet->getResponse()->getShardsStatistics(); + + $this->assertInternalType('int', $engineTime); + $this->assertTrue(is_array($shardsStats)); + $this->assertArrayHasKey('total', $shardsStats); + $this->assertArrayHasKey('successful', $shardsStats); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/ResultTest.php b/modules/thirdparty/elastica/test/lib/Elastica/ResultTest.php new file mode 100755 index 0000000..2cdfdcf --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/ResultTest.php @@ -0,0 +1,97 @@ +_createIndex(); + $type = $index->getType($typeName); + + // Adds 1 document to the index + $docId = 3; + $doc1 = new Elastica_Document($docId, array('username' => 'hans')); + $type->addDocument($doc1); + + // Refreshes index + $index->refresh(); + + $resultSet = $type->search('hans'); + + $this->assertEquals(1, $resultSet->count()); + + $result = $resultSet->current(); + + $this->assertInstanceOf('Elastica_Result', $result); + $this->assertEquals($index->getName(), $result->getIndex()); + $this->assertEquals($typeName, $result->getType()); + $this->assertEquals($docId, $result->getId()); + $this->assertGreaterThan(0, $result->getScore()); + $this->assertInternalType('array', $result->getData()); + } + + public function testGetIdNoSource() + { + // Creates a new index 'xodoa' and a type 'user' inside this index + $indexName = 'xodoa'; + $typeName = 'user'; + + $client = new Elastica_Client(); + $index = $client->getIndex($indexName); + $index->create(array(), true); + $type = $index->getType($typeName); + + $mapping = new Elastica_Type_Mapping($type); + $mapping->disableSource(); + $mapping->send(); + + // Adds 1 document to the index + $docId = 3; + $doc1 = new Elastica_Document($docId, array('username' => 'hans')); + $type->addDocument($doc1); + + // Refreshes index + $index->refresh(); + + $resultSet = $type->search('hans'); + + $this->assertEquals(1, $resultSet->count()); + + $result = $resultSet->current(); + + $this->assertEquals(array(), $result->getSource()); + $this->assertInstanceOf('Elastica_Result', $result); + $this->assertEquals($indexName, $result->getIndex()); + $this->assertEquals($typeName, $result->getType()); + $this->assertEquals($docId, $result->getId()); + $this->assertGreaterThan(0, $result->getScore()); + $this->assertInternalType('array', $result->getData()); + } + + public function testGetTotalTimeReturnsExpectedResults() + { + $typeName = 'user'; + $index = $this->_createIndex(); + $type = $index->getType($typeName); + + // Adds 1 document to the index + $docId = 3; + $doc1 = new Elastica_Document($docId, array('username' => 'hans')); + $type->addDocument($doc1); + + // Refreshes index + $index->refresh(); + + $resultSet = $type->search('hans'); + + $this->assertNotNull($resultSet->getTotalTime(), 'Get Total Time should never be a null value'); + $this->assertEquals( + 'integer', + getType($resultSet->getTotalTime()), + 'Total Time should be an integer' + ); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/ScriptFieldsTest.php b/modules/thirdparty/elastica/test/lib/Elastica/ScriptFieldsTest.php new file mode 100644 index 0000000..f0ea5be --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/ScriptFieldsTest.php @@ -0,0 +1,87 @@ +index = $this->_createIndex(); + } + + public function tearDown() + { + $this->index->delete(); + } + + public function testNewScriptFields() + { + $script = new Elastica_Script('1 + 2'); + + // addScript + $scriptFields = new Elastica_ScriptFields; + $scriptFields->addScript('test', $script); + $this->assertEquals($scriptFields->getParam('test'), $script->toArray()); + + // setScripts + $scriptFields = new Elastica_ScriptFields; + $scriptFields->setScripts(array( + 'test' => $script + )); + $this->assertEquals($scriptFields->getParam('test'), $script->toArray()); + + // Constructor + $scriptFields = new Elastica_ScriptFields(array( + 'test' => $script + )); + $this->assertEquals($scriptFields->getParam('test'), $script->toArray()); + } + + public function testSetScriptFields() + { + $query = new Elastica_Query; + $script = new Elastica_Script('1 + 2'); + + $scriptFields = new Elastica_ScriptFields(array( + 'test' => $script + )); + $query->setScriptFields($scriptFields); + $this->assertEquals($query->getParam('script_fields'), $scriptFields->toArray()); + + $query->setScriptFields(array( + 'test' => $script + )); + $this->assertEquals($query->getParam('script_fields'), $scriptFields->toArray()); + } + + public function testNameException() + { + $this->setExpectedException('Elastica_Exception_Invalid'); + + $script = new Elastica_Script('1 + 2'); + $scriptFields = new Elastica_ScriptFields(array($script)); + } + + public function testQuery() + { + $type = $this->index->getType('test'); + + $doc = new Elastica_Document(1, array('firstname' => 'guschti', 'lastname' => 'ruflin')); + $type->addDocument($doc); + $this->index->refresh(); + + $query = new Elastica_Query(); + $script = new Elastica_Script('1 + 2'); + $scriptFields = new Elastica_ScriptFields(array( + 'test' => $script + )); + $query->setScriptFields($scriptFields); + + $resultSet = $type->search($query); + $first = $resultSet->current()->getData(); + + // 1 + 2 + $this->assertEquals(3, $first['test']); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/SearchTest.php b/modules/thirdparty/elastica/test/lib/Elastica/SearchTest.php new file mode 100644 index 0000000..e44e19d --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/SearchTest.php @@ -0,0 +1,287 @@ +assertInstanceOf('Elastica_Search', $search); + $this->assertSame($client, $search->getClient()); + } + + public function testAddIndex() + { + $client = new Elastica_Client(); + $search = new Elastica_Search($client); + + $index1 = $this->_createIndex('test1'); + $index2 = $this->_createIndex('test2'); + + $search->addIndex($index1); + $indices = $search->getIndices(); + + $this->assertEquals(1, count($indices)); + + $search->addIndex($index2); + $indices = $search->getIndices(); + + $this->assertEquals(2, count($indices)); + + $this->assertTrue(in_array($index1->getName(), $indices)); + $this->assertTrue(in_array($index2->getName(), $indices)); + + // Add string + $search->addIndex('test3'); + $indices = $search->getIndices(); + + $this->assertEquals(3, count($indices)); + $this->assertTrue(in_array('test3', $indices)); + } + + public function testAddIndices() + { + $client = new Elastica_Client(); + $search = new Elastica_Search($client); + + $indices = array(); + $indices[] = $client->getIndex('elastica_test1'); + $indices[] = $client->getIndex('elastica_test2'); + + $search->addIndices($indices); + + $this->assertEquals(2, count($search->getIndices())); + } + + public function testAddType() + { + $client = new Elastica_Client(); + $search = new Elastica_Search($client); + + $index = $this->_createIndex(); + + $type1 = $index->getType('type1'); + $type2 = $index->getType('type2'); + + $this->assertEquals(array(), $search->getTypes()); + + $search->addType($type1); + $types = $search->getTypes(); + + $this->assertEquals(1, count($types)); + + $search->addType($type2); + $types = $search->getTypes(); + + $this->assertEquals(2, count($types)); + + $this->assertTrue(in_array($type1->getName(), $types)); + $this->assertTrue(in_array($type2->getName(), $types)); + + // Add string + $search->addType('test3'); + $types = $search->getTypes(); + + $this->assertEquals(3, count($types)); + $this->assertTrue(in_array('test3', $types)); + } + + public function testAddTypes() + { + $client = new Elastica_Client(); + $search = new Elastica_Search($client); + + $index = $this->_createIndex(); + + $types = array(); + $types[] = $index->getType('type1'); + $types[] = $index->getType('type2'); + + $search->addTypes($types); + + $this->assertEquals(2, count($search->getTypes())); + } + + public function testAddTypeInvalid() + { + $client = new Elastica_Client(); + $search = new Elastica_Search($client); + + try { + $search->addType(new stdClass()); + $this->fail('Should throw invalid exception'); + } catch (Elastica_Exception_Invalid $e) { + $this->assertTrue(true); + } + } + + public function testAddIndexInvalid() + { + $client = new Elastica_Client(); + $search = new Elastica_Search($client); + + try { + $search->addIndex(new stdClass()); + $this->fail('Should throw invalid exception'); + } catch (Elastica_Exception_Invalid $e) { + $this->assertTrue(true); + } + } + + public function testGetPath() + { + $client = new Elastica_Client(); + $search1 = new Elastica_Search($client); + $search2 = new Elastica_Search($client); + + $index1 = $this->_createIndex('test1'); + $index2 = $this->_createIndex('test2'); + + $type1 = $index1->getType('type1'); + $type2 = $index1->getType('type2'); + + // No index + $this->assertEquals('_all/_search', $search1->getPath()); + + // Only index + $search1->addIndex($index1); + $this->assertEquals($index1->getName() . '/_search', $search1->getPath()); + + // MUltiple index, no types + $search1->addIndex($index2); + $this->assertEquals($index1->getName() . ',' . $index2->getName() . '/_search', $search1->getPath()); + + // Single type, no index + $search2->addType($type1); + $this->assertEquals('_all/' . $type1->getName() . '/_search', $search2->getPath()); + + // Multiple types + $search2->addType($type2); + $this->assertEquals('_all/' . $type1->getName() . ',' . $type2->getName() . '/_search', $search2->getPath()); + + // Combine index and types + $search2->addIndex($index1); + $this->assertEquals($index1->getName() . '/' . $type1->getName() . ',' . $type2->getName() . '/_search', $search2->getPath()); + } + + public function testSearchRequest() + { + $client = new Elastica_Client(); + $search1 = new Elastica_Search($client); + + $index1 = $this->_createIndex('test1'); + $index2 = $this->_createIndex('test2'); + + $type1 = $index1->getType('hello1'); + + $result = $search1->search(array()); + $this->assertFalse($result->getResponse()->hasError()); + + $search1->addIndex($index1); + + $result = $search1->search(array()); + $this->assertFalse($result->getResponse()->hasError()); + + $search1->addIndex($index2); + + $result = $search1->search(array()); + $this->assertFalse($result->getResponse()->hasError()); + + $search1->addType($type1); + + $result = $search1->search(array()); + $this->assertFalse($result->getResponse()->hasError()); + } + + /** + * Default Limit tests for Elastica_Search + */ + public function testLimitDefaultSearch() + { + $client = new Elastica_Client(); + $search = new Elastica_Search($client); + + $index = $client->getIndex('zero'); + $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true); + + $docs = array(); + $docs[] = new Elastica_Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(2, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(3, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(4, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(5, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(6, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(7, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(8, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(9, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(10, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(11, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $type = $index->getType('zeroType'); + $type->addDocuments($docs); + $index->refresh(); + + $search->addIndex($index)->addType($type); + + // default limit results (default limit is 10) + $resultSet = $search->search('farrelley'); + $this->assertEquals(10, $resultSet->count()); + + // limit = 1 + $resultSet = $search->search('farrelley', 1); + $this->assertEquals(1, $resultSet->count()); + } + + public function testArrayConfigSearch() + { + $client = new Elastica_Client(); + $search = new Elastica_Search($client); + + $index = $client->getIndex('zero'); + $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true); + + $docs = array(); + for ($i = 0; $i < 11; $i++) { + $docs[] = new Elastica_Document($i, array('id' => 1, 'email' => 'test@test.com', 'username' => 'test')); + } + + $type = $index->getType('zeroType'); + $type->addDocuments($docs); + $index->refresh(); + + $search->addIndex($index)->addType($type); + //Backward compatibility, integer => limit + // default limit results (default limit is 10) + $resultSet = $search->search('test'); + $this->assertEquals(10, $resultSet->count()); + + // limit = 1 + $resultSet = $search->search('test', 1); + $this->assertEquals(1, $resultSet->count()); + + //Array with limit + $resultSet = $search->search('test', array('limit' => 2)); + $this->assertEquals(2, $resultSet->count()); + + //Array with routing + $resultSet = $search->search('test', array('routing' => 'r1,r2')); + $this->assertEquals(10, $resultSet->count()); + + //Array with limit and routing + $resultSet = $search->search('test', array('limit' => 5, 'routing' => 'r1,r2')); + $this->assertEquals(5, $resultSet->count()); + + //Search types + $resultSet = $search->search('test', array('limit' => 5, 'search_type' => 'count')); + $this->assertTrue(($resultSet->count() === 0) && $resultSet->getTotalHits() === 11); + + //Invalid option + try { + $resultSet = $search->search('test', array('invalid_option' => 'invalid_option_value')); + $this->fail('Should throw Elastica_Exception_Invalid'); + } catch (Exception $ex) { + $this->assertTrue($ex instanceof Elastica_Exception_Invalid); + } + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/StatusTest.php b/modules/thirdparty/elastica/test/lib/Elastica/StatusTest.php new file mode 100644 index 0000000..57dff49 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/StatusTest.php @@ -0,0 +1,103 @@ +_createIndex(); + $status = new Elastica_Status($index->getClient()); + $this->assertInstanceOf('Elastica_Response', $status->getResponse()); + } + + public function testGetIndexStatuses() + { + $index = $this->_createIndex(); + + $status = new Elastica_Status($index->getClient()); + $statuses = $status->getIndexStatuses(); + + $this->assertInternalType('array', $statuses); + + foreach ($statuses as $indexStatus) { + $this->assertInstanceOf('Elastica_Index_Status', $indexStatus); + } + } + + public function testGetIndexNames() + { + $indexName = 'test'; + $client = new Elastica_Client(); + $index = $client->getIndex($indexName); + $index->create(array(), true); + $index = $this->_createIndex(); + + $status = new Elastica_Status($index->getClient()); + $names = $status->getIndexNames(); + + $this->assertInternalType('array', $names); + $this->assertTrue(in_array($index->getName(), $names)); + + foreach ($names as $name) { + $this->assertInternalType('string', $name); + } + } + + public function testIndexExists() + { + $indexName = 'elastica_test'; + $aliasName = 'elastica_test-alias'; + + $client = new Elastica_Client(); + $index = $client->getIndex($indexName); + + try { + // Make sure index is deleted first + $index->delete(); + } catch (Elastica_Exception_Response $e) { + } + + $status = new Elastica_Status($client); + $this->assertFalse($status->indexExists($indexName)); + $index->create(); + + $status->refresh(); + $this->assertTrue($status->indexExists($indexName)); + } + + public function testAliasExists() + { + $indexName = 'test'; + $aliasName = 'elastica_test-alias'; + + $index1 = $this->_createIndex(); + + $status = new Elastica_Status($index1->getClient()); + + foreach ($status->getIndicesWithAlias($aliasName) as $tmpIndex) { + $tmpIndex->removeAlias($aliasName); + } + + $this->assertFalse($status->aliasExists($aliasName)); + + $index1->addAlias($aliasName); + $status->refresh(); + $this->assertTrue($status->aliasExists($aliasName)); + } + + public function testServerStatus() + { + $client = new Elastica_Client(); + $status = $client->getStatus(); + $serverStatus = $status->getServerStatus(); + + $this->assertTrue(!empty($serverStatus) ); + $this->assertTrue('array' == gettype($serverStatus)); + $this->assertArrayHasKey('ok', $serverStatus); + $this->assertTrue($serverStatus['ok']); + $this->assertArrayHasKey('version', $serverStatus); + + $versionInfo = $serverStatus['version']; + $this->assertArrayHasKey('number', $versionInfo); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Test.php b/modules/thirdparty/elastica/test/lib/Elastica/Test.php new file mode 100644 index 0000000..ee63d19 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Test.php @@ -0,0 +1,23 @@ +_getClient(); + $index = $client->getIndex('elastica_' . $name); + $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true); + + return $index; + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Transport/MemcacheTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Transport/MemcacheTest.php new file mode 100644 index 0000000..c3f9a1c --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Transport/MemcacheTest.php @@ -0,0 +1,56 @@ +markTestSkipped('pecl/memcache must be installed to run this test case'); + } + } + + public function testConstruct() + { + $host = 'localhost'; + $port = 11211; + $client = new Elastica_Client(array('host' => $host, 'port' => $port, 'transport' => 'Memcache')); + + $this->assertEquals($host, $client->getHost()); + $this->assertEquals($port, $client->getPort()); + } + + public function testExample() + { + // Creates a new index 'xodoa' and a type 'user' inside this index + $host = 'localhost'; + $port = 11211; + $client = new Elastica_Client(array('host' => $host, 'port' => $port, 'transport' => 'Memcache')); + + $index = $client->getIndex('elastica_test1'); + $index->create(array(), true); + + $type = $index->getType('user'); + + // Adds 1 document to the index + $doc1 = new Elastica_Document(1, + array('username' => 'hans', 'test' => array('2', '3', '5')) + ); + $type->addDocument($doc1); + + // Adds a list of documents with _bulk upload to the index + $docs = array(); + $docs[] = new Elastica_Document(2, + array('username' => 'john', 'test' => array('1', '3', '6')) + ); + $docs[] = new Elastica_Document(3, + array('username' => 'rolf', 'test' => array('2', '3', '7')) + ); + $type->addDocuments($docs); + + // Refresh index + $index->refresh(); + $this->markTestSkipped('Memcache implementation is not finished yet'); + $resultSet = $type->search('rolf'); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/Type/MappingTest.php b/modules/thirdparty/elastica/test/lib/Elastica/Type/MappingTest.php new file mode 100644 index 0000000..ef55cc5 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/Type/MappingTest.php @@ -0,0 +1,171 @@ +getIndex('test'); + + $index->create(array(), true); + $type = $index->getType('test'); + + $mapping = new Elastica_Type_Mapping($type, + array( + 'firstname' => array('type' => 'string', 'store' => 'yes'), + // default is store => no expected + 'lastname' => array('type' => 'string'), + ) + ); + $mapping->disableSource(); + + $type->setMapping($mapping); + + $firstname = 'Nicolas'; + $doc = new Elastica_Document(1, + array( + 'firstname' => $firstname, + 'lastname' => 'Ruflin' + ) + ); + + $type->addDocument($doc); + + $index->refresh(); + $queryString = new Elastica_Query_QueryString('ruflin'); + $query = Elastica_Query::create($queryString); + $query->setFields(array('*')); + + $resultSet = $type->search($query); + $result = $resultSet->current(); + $fields = $result->getFields(); + + $this->assertEquals($firstname, $fields['firstname']); + $this->assertArrayNotHasKey('lastname', $fields); + $this->assertEquals(1, count($fields)); + + $index->flush(); + $document = $type->getDocument(1); + + $this->assertEmpty($document->getData()); + } + + public function testEnableTtl() + { + $client = new Elastica_Client(); + $index = $client->getIndex('test'); + + $index->create(array(), true); + $type = $index->getType('test'); + + $mapping = new Elastica_Type_Mapping($type, array()); + + $mapping->enableTtl(); + + $data = $mapping->toArray(); + $this->assertTrue($data[$type->getName()]['_ttl']['enabled']); + } + + public function testNestedMapping() + { + $client = new Elastica_Client(); + $index = $client->getIndex('test'); + + $index->create(array(), true); + $type = $index->getType('test'); + + $this->markTestIncomplete('nested mapping is not set right yet'); + $mapping = new Elastica_Type_Mapping($type, + array( + 'test' => array( + 'type' => 'object', 'store' => 'yes', 'properties' => array( + 'user' => array( + 'properties' => array( + 'firstname' => array('type' => 'string', 'store' => 'yes'), + 'lastname' => array('type' => 'string', 'store' => 'yes'), + 'age' => array('type' => 'integer', 'store' => 'yes'), + ) + ), + ), + ), + ) + ); + + $type->setMapping($mapping); + + $doc = new Elastica_Document(1, array( + 'user' => array( + 'firstname' => 'Nicolas', + 'lastname' => 'Ruflin', + 'age' => 9 + ), + )); + + //print_r($type->getMapping()); + //exit(); + $type->addDocument($doc); + + $index->refresh(); + $resultSet = $type->search('ruflin'); + //print_r($resultSet); + } + + public function testParentMapping() + { + $index = $this->_createIndex(); + $parenttype = new Elastica_Type($index, 'parenttype'); + $parentmapping = new Elastica_Type_Mapping($parenttype, + array( + 'name' => array('type' => 'string', 'store' => 'yes') + ) + ); + + $parenttype->setMapping($parentmapping); + + $childtype = new Elastica_Type($index, 'childtype'); + $childmapping = new Elastica_Type_Mapping($childtype, + array( + 'name' => array('type' => 'string', 'store' => 'yes'), + ) + ); + $childmapping->setParam('_parent', array('type' => 'parenttype')); + + $childtype->setMapping($childmapping); + } + + public function testMappingExample() + { + $index = $this->_createIndex(); + $type = $index->getType('notes'); + + $mapping = new Elastica_Type_Mapping($type, + array( + 'note' => array( + 'store' => 'yes', 'properties' => array( + 'titulo' => array('type' => 'string', 'store' => 'no', 'include_in_all' => true, 'boost' => 1.0), + 'contenido' => array('type' => 'string', 'store' => 'no', 'include_in_all' => true, 'boost' => 1.0) + ) + ) + ) + ); + + $type->setMapping($mapping); + + $doc = new Elastica_Document(1, array( + 'note' => array( + array( + 'titulo' => 'nota1', + 'contenido' => 'contenido1' + ), + array( + 'titulo' => 'nota2', + 'contenido' => 'contenido2' + ) + ) + ) + ); + + $type->addDocument($doc); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/TypeTest.php b/modules/thirdparty/elastica/test/lib/Elastica/TypeTest.php new file mode 100755 index 0000000..54866a0 --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/TypeTest.php @@ -0,0 +1,301 @@ +_createIndex(); + + $type = new Elastica_Type($index, 'user'); + + // Adds 1 document to the index + $doc1 = new Elastica_Document(1, + array('username' => 'hans', 'test' => array('2', '3', '5')) + ); + $type->addDocument($doc1); + + // Adds a list of documents with _bulk upload to the index + $docs = array(); + $docs[] = new Elastica_Document(2, + array('username' => 'john', 'test' => array('1', '3', '6')) + ); + $docs[] = new Elastica_Document(3, + array('username' => 'rolf', 'test' => array('2', '3', '7')) + ); + $type->addDocuments($docs); + $index->refresh(); + + $resultSet = $type->search('rolf'); + $this->assertEquals(1, $resultSet->count()); + + // Test if source is returned + $result = $resultSet->current(); + $this->assertEquals(3, $result->getId()); + $data = $result->getData(); + $this->assertEquals('rolf', $data['username']); + } + + public function testNoSource() + { + $index = $this->_createIndex(); + + $type = new Elastica_Type($index, 'user'); + $mapping = new Elastica_Type_Mapping($type, array( + 'id' => array('type' => 'integer', 'store' => 'yes'), + 'username' => array('type' => 'string', 'store' => 'no'), + )); + $mapping->setSource(array('enabled' => false)); + $type->setMapping($mapping); + + // Adds 1 document to the index + $doc1 = new Elastica_Document(1, + array('username' => 'hans', 'test' => array('2', '3', '5')) + ); + $type->addDocument($doc1); + + // Adds a list of documents with _bulk upload to the index + $docs = array(); + $docs[] = new Elastica_Document(2, + array('username' => 'john', 'test' => array('1', '3', '6')) + ); + $docs[] = new Elastica_Document(3, + array('username' => 'rolf', 'test' => array('2', '3', '7')) + ); + $type->addDocuments($docs); + + // To update index + $index->refresh(); + + $resultSet = $type->search('rolf'); + + $this->assertEquals(1, $resultSet->count()); + + // Tests if no source is in response except id + $result = $resultSet->current(); + $this->assertEquals(3, $result->getId()); + $this->assertEmpty($result->getData()); + } + + public function testDeleteDocument() + { + $index = $this->_createIndex(); + $type = new Elastica_Type($index, 'user'); + + // Adds hans, john and rolf to the index + $docs = array( + new Elastica_Document(1, array('username' => 'hans', 'test' => array('2', '3', '5'))), + new Elastica_Document(2, array('username' => 'john', 'test' => array('1', '3', '6'))), + new Elastica_Document(3, array('username' => 'rolf', 'test' => array('2', '3', '7'))), + ); + $type->addDocuments($docs); + $index->refresh(); + + // sanity check for rolf + $resultSet = $type->search('rolf'); + $this->assertEquals(1, $resultSet->count()); + $data = $resultSet->current()->getData(); + $this->assertEquals('rolf', $data['username']); + + // delete rolf + $type->deleteById(3); + $index->refresh(); + + // rolf should no longer be there + $resultSet = $type->search('rolf'); + $this->assertEquals(0, $resultSet->count()); + + // it should not be possible to delete the entire type with this method + try { + $type->deleteById(' '); + } catch (Exception $e) { + /* ignore */ + } + + try { + $type->deleteById(null); + } catch (Exception $e) { + /* ignore */ + } + + try { + $type->deleteById(array()); + } catch (Exception $e) { + /* ignore */ + } + + try { + $type->deleteById('*'); + } catch (Exception $e) { + /* ignore */ + } + + try { + $type->deleteById('*:*'); + } catch (Exception $e) { + /* ignore */ + } + + try { + $type->deleteById('!'); + } catch (Exception $e) { + /* ignore */ + } + + $index->refresh(); + + // rolf should no longer be there + $resultSet = $type->search('john'); + $this->assertEquals(1, $resultSet->count()); + } + + public function testGetDocumentNotExist() + { + $index = $this->_createIndex(); + $type = new Elastica_Type($index, 'test'); + $type->addDocument(new Elastica_Document(1, array('name' => 'ruflin'))); + $index->refresh(); + + $type->getDocument(1); + + try { + $type->getDocument(2); + $this->fail('Should throw exceptoin as doc does not exist'); + } catch (Elastica_Exception_NotFound $e) { + $this->assertTrue(true); + } + } + + public function testDeleteByQuery() + { + $index = $this->_createIndex(); + $type = new Elastica_Type($index, 'test'); + $type->addDocument(new Elastica_Document(1, array('name' => 'ruflin nicolas'))); + $type->addDocument(new Elastica_Document(2, array('name' => 'ruflin'))); + $index->refresh(); + + $response = $index->search('ruflin*'); + $this->assertEquals(2, $response->count()); + + $response = $index->search('nicolas'); + $this->assertEquals(1, $response->count()); + + // Delete first document + $response = $type->deleteByQuery('nicolas'); + $this->assertTrue($response->isOk()); + + $index->refresh(); + + // Makes sure, document is deleted + $response = $index->search('ruflin*'); + $this->assertEquals(1, $response->count()); + + $response = $index->search('nicolas'); + $this->assertEquals(0, $response->count()); + } + + /** + * Test to see if search Default Limit works + */ + public function testLimitDefaultType() + { + $client = new Elastica_Client(); + $index = $client->getIndex('zero'); + $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true); + + $docs = array(); + $docs[] = new Elastica_Document(1, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(2, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(3, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(4, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(5, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(6, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(7, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(8, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(9, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(10, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + $docs[] = new Elastica_Document(11, array('id' => 1, 'email' => 'test@test.com', 'username' => 'farrelley')); + + $type = $index->getType('zeroType'); + $type->addDocuments($docs); + $index->refresh(); + + // default results (limit default is 10) + $resultSet = $type->search('farrelley'); + $this->assertEquals(10, $resultSet->count()); + + // limit = 1 + $resultSet = $type->search('farrelley', 1); + $this->assertEquals(1, $resultSet->count()); + } + + /** + * Test Delete of index type. After delete will check for type mapping. + */ + public function testDeleteType() + { + $index = $this->_createIndex(); + $type = new Elastica_Type($index, 'test'); + $type->addDocument(new Elastica_Document(1, array('name' => 'ruflin nicolas'))); + $type->addDocument(new Elastica_Document(2, array('name' => 'ruflin'))); + $index->refresh(); + + $type->delete(); + try { + $type->getMapping(); + } catch (Elastica_Exception_Response $expected) { + $this->assertEquals("TypeMissingException[[elastica_test] type[test] missing]", $expected->getMessage()); + + return; + } + + $this->fail('Mapping for type[test] in [elastica_test] still exists'); + } + + public function testMoreLikeThisApi() + { + $client = new Elastica_Client(array('persistent' => false)); + $index = $client->getIndex('elastica_test'); + $index->create(array('index' => array('number_of_shards' => 1, 'number_of_replicas' => 0)), true); + + $type = new Elastica_Type($index, 'mlt_test'); + $type->addDocument(new Elastica_Document(1, array('visible' => true, 'name' => 'bruce wayne batman'))); + $type->addDocument(new Elastica_Document(2, array('visible' => true, 'name' => 'bruce wayne'))); + $type->addDocument(new Elastica_Document(3, array('visible' => false, 'name' => 'bruce wayne'))); + $type->addDocument(new Elastica_Document(4, array('visible' => true, 'name' => 'batman'))); + $type->addDocument(new Elastica_Document(5, array('visible' => false, 'name' => 'batman'))); + $type->addDocument(new Elastica_Document(6, array('visible' => true, 'name' => 'superman'))); + $type->addDocument(new Elastica_Document(7, array('visible' => true, 'name' => 'spiderman'))); + + $index->refresh(); + + $document = $type->getDocument(1); + + // Return all similar + $resultSet = $type->moreLikeThis($document, array('min_term_freq' => '1', 'min_doc_freq' => '1')); + $this->assertEquals(4, $resultSet->count()); + + // Return just the visible similar + $query = new Elastica_Query(); + $filterTerm = new Elastica_Filter_Term(); + $filterTerm->setTerm('visible', true); + $query->setFilter($filterTerm); + + $resultSet = $type->moreLikeThis($document, array('min_term_freq' => '1', 'min_doc_freq' => '1'), $query); + $this->assertEquals(2, $resultSet->count()); + } + + public function testUpdateDocument() + { + $client = new Elastica_Client(); + $index = $client->getIndex('elastica_test'); + $type = $index->getType('update_type'); + $id = 1; + $type->addDocument(new Elastica_Document($id, array('name' => 'bruce wayne batman'))); + $newName = 'batman'; + $update = new Elastica_Script("ctx._source.name = name", array('name' => $newName)); + $type->updateDocument($id, $update, array('refresh' => true)); + $updatedDoc = $type->getDocument($id)->getData(); + $this->assertEquals($newName, $updatedDoc['name'], "Name was not updated"); + } +} diff --git a/modules/thirdparty/elastica/test/lib/Elastica/UtilTest.php b/modules/thirdparty/elastica/test/lib/Elastica/UtilTest.php new file mode 100644 index 0000000..a67a3ff --- /dev/null +++ b/modules/thirdparty/elastica/test/lib/Elastica/UtilTest.php @@ -0,0 +1,51 @@ +assertEquals($escaped, Elastica_Util::escapeTerm($unescaped)); + } + + public function getEscapeTermPairs() + { + return array( + array('', ''), + array('pragmatic banana', 'pragmatic banana'), + array('oh yeah!', 'oh yeah\\!'), + // Seperate test below because phpunit seems to have some problems + //array('\\+-&&||!(){}[]^"~*?:', '\\\\\\+\\-\\&&\\||\\!\\(\\)\\{\\}\\[\\]\\^\\"\\~\\*\\?\\:'), + array('some signs, can stay.', 'some signs, can stay.') + ); + } + + public function testEscapeTermSpecialCharacters() + { + $before = '\\+-&&||!(){}[]^"~*?:'; + $after = '\\\\\\+\\-\\&&\\||\\!\\(\\)\\{\\}\\[\\]\\^\\"\\~\\*\\?\\:'; + + $this->assertEquals(Elastica_Util::escapeTerm($before), $after); + } + + public function testToCamelCase() + { + $string = 'hello_world'; + $this->assertEquals('HelloWorld', Elastica_Util::toCamelCase($string)); + + $string = 'how_are_you_today'; + $this->assertEquals('HowAreYouToday', Elastica_Util::toCamelCase($string)); + } + + public function testToSnakeCase() + { + $string = 'HelloWorld'; + $this->assertEquals('hello_world', Elastica_Util::toSnakeCase($string)); + + $string = 'HowAreYouToday'; + $this->assertEquals('how_are_you_today', Elastica_Util::toSnakeCase($string)); + } +} diff --git a/modules/thirdparty/elastica/test/phpunit.xml.dist b/modules/thirdparty/elastica/test/phpunit.xml.dist new file mode 100755 index 0000000..f80641f --- /dev/null +++ b/modules/thirdparty/elastica/test/phpunit.xml.dist @@ -0,0 +1,33 @@ + + + + + ./lib/Elastica/ + + + + + ../lib/ + + + + + + + + \ No newline at end of file diff --git a/modules/thirdparty/ipnlistener/LICENSE b/modules/thirdparty/ipnlistener/LICENSE new file mode 100755 index 0000000..bad71e3 --- /dev/null +++ b/modules/thirdparty/ipnlistener/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012, Micah Carrick +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of Quixotix, LLC nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/modules/thirdparty/ipnlistener/README.md b/modules/thirdparty/ipnlistener/README.md new file mode 100755 index 0000000..a4afa9d --- /dev/null +++ b/modules/thirdparty/ipnlistener/README.md @@ -0,0 +1,179 @@ +PHP-PayPal-IPN +============== + +A PayPal Instant Payment Notification (IPN) class for PHP 5. + +Use the `IpnListener` class in your PHP IPN script to handle the encoding +of POST data, post back to PayPal, and parsing of the response from PayPal. + + +Features +-------- + +* Switch between live and sandbox by setting the `use_sandbox` property. +* Supports both secure SSL and plain HTTP transactions by setting the `use_ssl` + property (SSL is recommended). +* Supports both cURL and fsockopen network libraries by setting the `use_curl` + property (cURL is recommended). +* Verifies an HTTP "200" response status code from the PayPal server. +* Get detailed plain text reports of the entire IPN using the `getTextReport()` + method for use in emails and logs to administrators. +* Throws various exceptions to differentiate between common errors in code or + server configuration versus invalid IPN responses. + + +Getting Started +--------------- + +This code is intended for web developers. You should understand how the IPN +process works conceptually and you should understand when and why you would be +using IPN. Reading the [PayPal Instant Payment Notification Guide][1] is a good +place to start. + +You should also have a [PayPal Sandbox Account][2] with a test buyer account and +a test seller account. When logged into your sandbox account there is an IPN +simulator under the 'Test Tools' menu which you can used to test your IPN +listener. + +[1]: https://cms.paypal.com/cms_content/US/en_US/files/developer/IPNGuide.pdf +[2]: https://developer.paypal.com + +Once you have your sandbox account setup, you simply create a PHP script that +will be your IPN listener. In that script, use the `IpnListener()` class as shown +below. For a more thoroughly documented example, take a look at the +`example/ipn.php` script in the source code. + + use_sandbox = true; + + try { + $verified = $listener->processIpn(); + } catch (Exception $e) { + // fatal error trying to process IPN. + exit(0); + } + + if ($verified) { + // IPN response was "VERIFIED" + } else { + // IPN response was "INVALID" + } + + ?> + + +Documentation +------------- + +Documentation has not been generated yet, but, there are phpDocumentor style +docstrings (comments) throughout `ipnlistener.php` which explain the important +public properties and methods. + +I have also written a more in-depth IPN tutorial on my blog: [PayPal IPN with PHP][3] + +[3]: http://www.micahcarrick.com/paypal-ipn-with-php.html + + +Known Issues +------------ + +__Problem__ + +The `processIpn()` method throws the following exception: + + cURL error: [52] GnuTLS recv error (-9): A TLS packet with unexpected length was received. + +__Solution__ + +When cURL is compiled with GnuTLS the call to PayPal will fail if the SSL version +is not explicitly set as a cURL option. Set the `force_ssl_v3` property to force +SSL 3: + + $listener = new IpnListener(); + $listener->force_ssl_v3 = true; + +_Note: force_ssl_v3 is now true by default_ + + + +__Problem__ + + PHP Warning: curl_setopt() [function.curl-setopt]: CURLOPT_FOLLOWLOCATION + cannot be activated when in safe_mode or an open_basedir is set in ... + +__Solution__ + +If you need PHP safe mode, you can disable CURLOPT_FOLLOWLOCATION using the +`follow_location` property. + + $listener = new IpnListener(); + $listener->follow_location = false; + +_Note: follow_location is now false enabled by default_ + + +Example Report +-------------- + +Here is an example of a report returned by the `getTextReport()` method. Create +your own reports by extending the `IpnListener()` class or by accessing the data +directly in your ipn script. + + -------------------------------------------------------------------------------- + [09/09/2011 8:35 AM] - https://www.sandbox.paypal.com/cgi-bin/webscr (curl) + -------------------------------------------------------------------------------- + HTTP/1.1 200 OK + Date: Fri, 09 Sep 2011 13:35:39 GMT + Server: Apache + X-Frame-Options: SAMEORIGIN + Set-Cookie: c9MWDuvPtT9GIMyPc3jwol1VSlO=Ch-NORlHUjlmbEm__KG9LupR4mfMfQTkx1QQ6hHDyc0RImWr88NY_ILeICENiwtVX3iw4jEnT1-1gccYjQafWrQCkDmiykNT8TeDUg7R7L0D9bQm47PTG8MafmrpyrUAxQfst0%7c_jG1ZL6CffJgwrC-stQeqni04tKaYSIZqyqhFU7tKnV520wiYOw0hwk5Ehrh3hLDvBxkpm%7cYTFdl0w0YpEqxu0D1jDTVTlEGXlmLs4wob2Glu9htpZkFV9O2aCyfQ4CvA2kLJmlI6YiXm%7c1315575340; domain=.paypal.com; path=/; Secure; HttpOnly + Set-Cookie: cookie_check=yes; expires=Mon, 06-Sep-2021 13:35:40 GMT; domain=.paypal.com; path=/; Secure; HttpOnly + Set-Cookie: navcmd=_notify-validate; domain=.paypal.com; path=/; Secure; HttpOnly + Set-Cookie: navlns=0.0; expires=Thu, 04-Sep-2031 13:35:40 GMT; domain=.paypal.com; path=/; Secure; HttpOnly + Set-Cookie: Apache=10.72.109.11.1315575339707456; path=/; expires=Sun, 01-Sep-41 13:35:39 GMT + X-Cnection: close + Transfer-Encoding: chunked + Content-Type: text/html; charset=UTF-8 + + VERIFIED + -------------------------------------------------------------------------------- + test_ipn 1 + payment_type instant + payment_date 06:34:51 Sep 09, 2011 PDT + payment_status Completed + address_status confirmed + payer_status verified + first_name John + last_name Smith + payer_email buyer@paypalsandbox.com + payer_id TESTBUYERID01 + address_name John Smith + address_country United States + address_country_code US + address_zip 95131 + address_state CA + address_city San Jose + address_street 123, any street + business seller@paypalsandbox.com + receiver_email seller@paypalsandbox.com + receiver_id TESTSELLERID1 + residence_country US + item_name something + item_number AK-1234 + quantity 1 + shipping 3.04 + tax 2.02 + mc_currency USD + mc_fee 0.44 + mc_gross 12.34 + mc_gross_1 9.34 + txn_type web_accept + txn_id 51991334 + notify_version 2.1 + custom xyz123 + charset windows-1252 + verify_sign Ah5rOpfPGo5g6FNg95DMPybP51J5AUEdXS1hqyRAP6WYYwaixKNDgQRR diff --git a/modules/thirdparty/ipnlistener/cert/api_cert_chain.crt b/modules/thirdparty/ipnlistener/cert/api_cert_chain.crt new file mode 100755 index 0000000..347f0eb --- /dev/null +++ b/modules/thirdparty/ipnlistener/cert/api_cert_chain.crt @@ -0,0 +1,54 @@ +-----BEGIN CERTIFICATE----- +MIIDgzCCAuygAwIBAgIQJUuKhThCzONY+MXdriJupDANBgkqhkiG9w0BAQUFADBf +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT +LkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw +HhcNOTcwNDE3MDAwMDAwWhcNMTExMDI0MjM1OTU5WjCBujEfMB0GA1UEChMWVmVy +aVNpZ24gVHJ1c3QgTmV0d29yazEXMBUGA1UECxMOVmVyaVNpZ24sIEluYy4xMzAx +BgNVBAsTKlZlcmlTaWduIEludGVybmF0aW9uYWwgU2VydmVyIENBIC0gQ2xhc3Mg +MzFJMEcGA1UECxNAd3d3LnZlcmlzaWduLmNvbS9DUFMgSW5jb3JwLmJ5IFJlZi4g +TElBQklMSVRZIExURC4oYyk5NyBWZXJpU2lnbjCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEA2IKA6NYZAn0fhRg5JaJlK+G/1AXTvOY2O6rwTGxbtueqPHNFVbLx +veqXQu2aNAoV1Klc9UAl3dkHwTKydWzEyruj/lYncUOqY/UwPpMo5frxCTvzt01O +OfdcSVq4wR3Tsor+cDCVQsv+K1GLWjw6+SJPkLICp1OcTzTnqwSye28CAwEAAaOB +4zCB4DAPBgNVHRMECDAGAQH/AgEAMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQEw +KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL0NQUzA0BgNV +HSUELTArBggrBgEFBQcDAQYIKwYBBQUHAwIGCWCGSAGG+EIEAQYKYIZIAYb4RQEI +ATALBgNVHQ8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgEGMDEGA1UdHwQqMCgwJqAk +oCKGIGh0dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMuY3JsMA0GCSqGSIb3DQEB +BQUAA4GBAAgB7ORolANC8XPxI6I63unx2sZUxCM+hurPajozq+qcBBQHNgYL+Yhv +1RPuKSvD5HKNRO3RrCAJLeH24RkFOLA9D59/+J4C3IYChmFOJl9en5IeDCSk9dBw +E88mw0M9SR2egi5SX7w+xmYpAY5Okiy8RnUDgqxz6dl+C2fvVFIa +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz +cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 +MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV +BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN +ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE +BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is +I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G +CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do +lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc +AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh +c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy +MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp +emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X +DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw +FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg +UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo +YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 +MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 +pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 +13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID +AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk +U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i +F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY +oJ2daZH9 +-----END CERTIFICATE----- diff --git a/modules/thirdparty/ipnlistener/example/ipn.php b/modules/thirdparty/ipnlistener/example/ipn.php new file mode 100755 index 0000000..4e66cd6 --- /dev/null +++ b/modules/thirdparty/ipnlistener/example/ipn.php @@ -0,0 +1,111 @@ +use_sandbox = true; + +/* +By default the IpnListener object is going going to post the data back to PayPal +using cURL over a secure SSL connection. This is the recommended way to post +the data back, however, some people may have connections problems using this +method. + +To post over standard HTTP connection, use: +$listener->use_ssl = false; + +To post using the fsockopen() function rather than cURL, use: +$listener->use_curl = false; +*/ + +/* +The processIpn() method will encode the POST variables sent by PayPal and then +POST them back to the PayPal server. An exception will be thrown if there is +a fatal error (cannot connect, your server is not configured properly, etc.). +Use a try/catch block to catch these fatal errors and log to the ipn_errors.log +file we setup at the top of this file. + +The processIpn() method will send the raw data on 'php://input' to PayPal. You +can optionally pass the data to processIpn() yourself: +$verified = $listener->processIpn($my_post_data); +*/ +try { + $listener->requirePostMethod(); + $verified = $listener->processIpn(); +} catch (Exception $e) { + error_log($e->getMessage()); + exit(0); +} + + +/* +The processIpn() method returned true if the IPN was "VERIFIED" and false if it +was "INVALID". +*/ +if ($verified) { + /* + Once you have a verified IPN you need to do a few more checks on the POST + fields--typically against data you stored in your database during when the + end user made a purchase (such as in the "success" page on a web payments + standard button). The fields PayPal recommends checking are: + + 1. Check the $_POST['payment_status'] is "Completed" + 2. Check that $_POST['txn_id'] has not been previously processed + 3. Check that $_POST['receiver_email'] is your Primary PayPal email + 4. Check that $_POST['payment_amount'] and $_POST['payment_currency'] + are correct + + Since implementations on this varies, I will leave these checks out of this + example and just send an email using the getTextReport() method to get all + of the details about the IPN. + */ + mail('YOUR EMAIL ADDRESS', 'Verified IPN', $listener->getTextReport()); + +} else { + /* + An Invalid IPN *may* be caused by a fraudulent transaction attempt. It's + a good idea to have a developer or sys admin manually investigate any + invalid IPN. + */ + mail('YOUR EMAIL ADDRESS', 'Invalid IPN', $listener->getTextReport()); +} + +?> diff --git a/modules/thirdparty/ipnlistener/example/ipn_errors.log b/modules/thirdparty/ipnlistener/example/ipn_errors.log new file mode 100755 index 0000000..e69de29 diff --git a/modules/thirdparty/ipnlistener/ipnlistener.php b/modules/thirdparty/ipnlistener/ipnlistener.php new file mode 100755 index 0000000..bb8c93d --- /dev/null +++ b/modules/thirdparty/ipnlistener/ipnlistener.php @@ -0,0 +1,312 @@ +use_ssl) { + $uri = 'https://'.$this->getPaypalHost().'/cgi-bin/webscr'; + $this->post_uri = $uri; + } else { + $uri = 'http://'.$this->getPaypalHost().'/cgi-bin/webscr'; + $this->post_uri = $uri; + } + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); + curl_setopt($ch, CURLOPT_CAINFO, + dirname(__FILE__)."/cert/api_cert_chain.crt"); + curl_setopt($ch, CURLOPT_URL, $uri); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded_data); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $this->follow_location); + curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HEADER, true); + + if ($this->force_ssl_v3) { + curl_setopt($ch, CURLOPT_SSLVERSION, 3); + } + + $this->response = curl_exec($ch); + $this->response_status = strval(curl_getinfo($ch, CURLINFO_HTTP_CODE)); + + if ($this->response === false || $this->response_status == '0') { + $errno = curl_errno($ch); + $errstr = curl_error($ch); + throw new Exception("cURL error: [$errno] $errstr"); + } + } + + /** + * Post Back Using fsockopen() + * + * Sends the post back to PayPal using the fsockopen() function. Called by + * the processIpn() method if the use_curl property is false. Throws an + * exception if the post fails. Populates the response, response_status, + * and post_uri properties on success. + * + * @param string The post data as a URL encoded string + */ + protected function fsockPost($encoded_data) { + + if ($this->use_ssl) { + $uri = 'ssl://'.$this->getPaypalHost(); + $port = '443'; + $this->post_uri = $uri.'/cgi-bin/webscr'; + } else { + $uri = $this->getPaypalHost(); // no "http://" in call to fsockopen() + $port = '80'; + $this->post_uri = 'http://'.$uri.'/cgi-bin/webscr'; + } + + $fp = fsockopen($uri, $port, $errno, $errstr, $this->timeout); + + if (!$fp) { + // fsockopen error + throw new Exception("fsockopen error: [$errno] $errstr"); + } + + $header = "POST /cgi-bin/webscr HTTP/1.1\r\n"; + $header .= "Host: ".$this->getPaypalHost()."\r\n"; + $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; + $header .= "Content-Length: ".strlen($encoded_data)."\r\n"; + $header .= "Connection: Close\r\n\r\n"; + + fputs($fp, $header.$encoded_data."\r\n\r\n"); + + while(!feof($fp)) { + if (empty($this->response)) { + // extract HTTP status from first line + $this->response .= $status = fgets($fp, 1024); + $this->response_status = trim(substr($status, 9, 4)); + } else { + $this->response .= fgets($fp, 1024); + } + } + + fclose($fp); + } + + private function getPaypalHost() { + if ($this->use_sandbox) return self::SANDBOX_HOST; + else return self::PAYPAL_HOST; + } + + /** + * Get POST URI + * + * Returns the URI that was used to send the post back to PayPal. This can + * be useful for troubleshooting connection problems. The default URI + * would be "ssl://www.sandbox.paypal.com:443/cgi-bin/webscr" + * + * @return string + */ + public function getPostUri() { + return $this->post_uri; + } + + /** + * Get Response + * + * Returns the entire response from PayPal as a string including all the + * HTTP headers. + * + * @return string + */ + public function getResponse() { + return $this->response; + } + + /** + * Get Response Status + * + * Returns the HTTP response status code from PayPal. This should be "200" + * if the post back was successful. + * + * @return string + */ + public function getResponseStatus() { + return $this->response_status; + } + + /** + * Get Text Report + * + * Returns a report of the IPN transaction in plain text format. This is + * useful in emails to order processors and system administrators. Override + * this method in your own class to customize the report. + * + * @return string + */ + public function getTextReport() { + + $r = ''; + + // date and POST url + for ($i=0; $i<80; $i++) { $r .= '-'; } + $r .= "\n[".date('m/d/Y g:i A').'] - '.$this->getPostUri(); + if ($this->use_curl) $r .= " (curl)\n"; + else $r .= " (fsockopen)\n"; + + // HTTP Response + for ($i=0; $i<80; $i++) { $r .= '-'; } + $r .= "\n{$this->getResponse()}\n"; + + // POST vars + for ($i=0; $i<80; $i++) { $r .= '-'; } + $r .= "\n"; + + foreach ($this->post_data as $key => $value) { + $r .= str_pad($key, 25)."$value\n"; + } + $r .= "\n\n"; + + return $r; + } + + /** + * Process IPN + * + * Handles the IPN post back to PayPal and parsing the response. Call this + * method from your IPN listener script. Returns true if the response came + * back as "VERIFIED", false if the response came back "INVALID", and + * throws an exception if there is an error. + * + * @param array + * + * @return boolean + */ + public function processIpn($post_data=null) { + + $encoded_data = 'cmd=_notify-validate'; + + if ($post_data === null) { + // use raw POST data + if (!empty($_POST)) { + $this->post_data = $_POST; + $encoded_data .= '&'.file_get_contents('php://input'); + } else { + throw new Exception("No POST data found."); + } + } else { + // use provided data array + $this->post_data = $post_data; + + foreach ($this->post_data as $key => $value) { + $encoded_data .= "&$key=".urlencode($value); + } + } + + if ($this->use_curl) $this->curlPost($encoded_data); + else $this->fsockPost($encoded_data); + + if (strpos($this->response_status, '200') === false) { + throw new Exception("Invalid response status: ".$this->response_status); + } + + if (strpos($this->response, "VERIFIED") !== false) { + return true; + } elseif (strpos($this->response, "INVALID") !== false) { + return false; + } else { + throw new Exception("Unexpected response from PayPal."); + } + } + + /** + * Require Post Method + * + * Throws an exception and sets a HTTP 405 response header if the request + * method was not POST. + */ + public function requirePostMethod() { + // require POST requests + if ($_SERVER['REQUEST_METHOD'] && $_SERVER['REQUEST_METHOD'] != 'POST') { + header('Allow: POST', true, 405); + throw new Exception("Invalid HTTP request method."); + } + } +} + diff --git a/modules/thirdparty/jquery/barcode/jquery.barcode.min.js b/modules/thirdparty/jquery/barcode/jquery.barcode.min.js new file mode 100644 index 0000000..55e37e3 --- /dev/null +++ b/modules/thirdparty/jquery/barcode/jquery.barcode.min.js @@ -0,0 +1,16 @@ +/* + * BarCode Coder Library (BCC Library) + * BCCL Version 2.0 + * + * Porting : jQuery barcode plugin + * Version : 2.0.2 + * + * Date : March 01, 2011 + * Author : DEMONTE Jean-Baptiste + * HOUREZ Jonathan + * + * Web site: http://barcode-coder.com/ + * dual licence : http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html + * http://www.gnu.org/licenses/gpl.html + */ +(function(b){var a={settings:{barWidth:1,barHeight:50,moduleSize:5,showHRI:true,addQuietZone:true,marginHRI:5,bgColor:"#FFFFFF",color:"#000000",fontSize:10,output:"css",posX:0,posY:0},intval:function(d){var c=typeof(d);if(c=="string"){d=d.replace(/[^0-9-.]/g,"");d=parseInt(d*1,10);return isNaN(d)||!isFinite(d)?0:d}return c=="number"&&isFinite(d)?Math.floor(d):0},i25:{encoding:["NNWWN","WNNNW","NWNNW","WWNNN","NNWNW","WNWNN","NWWNN","NNNWW","WNNWN","NWNWN"],compute:function(g,j,f){if(!j){if(g.length%2!=0){g="0"+g}}else{if((f=="int25")&&(g.length%2==0)){g="0"+g}var h=true,c,e=0;for(var d=g.length-1;d>-1;d--){c=a.intval(g.charAt(d));if(isNaN(c)){return("")}e+=h?3*c:c;h=!h}g+=((10-e%10)%10).toString()}return(g)},getDigit:function(k,l,h){k=this.compute(k,l,h);if(k==""){return("")}result="";var f,d;if(h=="int25"){result+="1010";var g,e;for(f=0;f"9")){return("")}}h=this.compute(h,g);var j="101";if(g=="ean8"){for(var f=0;f<4;f++){j+=this.encoding[a.intval(h.charAt(f))][0]}j+="01010";for(var f=4;f<8;f++){j+=this.encoding[a.intval(h.charAt(f))][2]}}else{var e=this.first[a.intval(h.charAt(0))];for(var f=1;f<7;f++){j+=this.encoding[a.intval(h.charAt(f))][a.intval(e.charAt(f-1))]}j+="01010";for(var f=7;f<13;f++){j+=this.encoding[a.intval(h.charAt(f))][2]}}j+="101";return(j)},compute:function(f,e){var c=e=="ean13"?12:7;f=f.substring(0,c);var d=0,g=true;for(i=f.length-1;i>-1;i--){d+=(g?3:1)*a.intval(f.charAt(i));g=!g}return(f+((10-d%10)%10).toString())}},msi:{encoding:["100100100100","100100100110","100100110100","100100110110","100110100100","100110100110","100110110100","100110110110","110100100100","110100100110"],compute:function(c,d){if(typeof(d)=="object"){if(d.crc1=="mod10"){c=this.computeMod10(c)}else{if(d.crc1=="mod11"){c=this.computeMod11(c)}}if(d.crc2=="mod10"){c=this.computeMod10(c)}else{if(d.crc2=="mod11"){c=this.computeMod11(c)}}}else{if(typeof(d)=="boolean"){if(d){c=this.computeMod10(c)}}}return(c)},computeMod10:function(h){var d,g=h.length%2;var f=0,e=0;for(d=0;d=0;d--){e+=c*a.intval(f.charAt(d));c=c==7?2:c+1}return(f+((11-e%11)%11).toString())},getDigit:function(e,g){var d="0123456789";var c=0;var f="";e=this.compute(e,false);f="110";for(i=0;i=0;g--){p=p==10?1:p+1;j=j==10?1:j+1;l=q.indexOf(d.charAt(g));e+=p*l;m+=j*l}var n=e%11;m+=n;var f=m%11;o+=this.encoding[n]+h;if(d.length>=10){o+=this.encoding[f]+h}o+="1011001";return(o)}},code39:{encoding:["101001101101","110100101011","101100101011","110110010101","101001101011","110100110101","101100110101","101001011011","110100101101","101100101101","110101001011","101101001011","110110100101","101011001011","110101100101","101101100101","101010011011","110101001101","101101001101","101011001101","110101010011","101101010011","110110101001","101011010011","110101101001","101101101001","101010110011","110101011001","101101011001","101011011001","110010101011","100110101011","110011010101","100101101011","110010110101","100110110101","100101011011","110010101101","100110101101","100100100101","100100101001","100101001001","101001001001","100101101101"],getDigit:function(f){var e="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%*";var d,c,h="",g="0";if(f.indexOf("*")>=0){return("")}f=("*"+f+"*").toUpperCase();for(d=0;d0){h+=g}h+=this.encoding[c]}return(h)}},code93:{encoding:["100010100","101001000","101000100","101000010","100101000","100100100","100100010","101010000","100010010","100001010","110101000","110100100","110100010","110010100","110010010","110001010","101101000","101100100","101100010","100110100","100011010","101011000","101001100","101000110","100101100","100010110","110110100","110110010","110101100","110100110","110010110","110011010","101101100","101100110","100110110","100111010","100101110","111010100","111010010","111001010","101101110","101110110","110101110","100100110","111011010","111010110","100110010","101011110"],getDigit:function(d,h){var o="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%____*",l,m="";if(d.indexOf("*")>=0){return("")}d=d.toUpperCase();m+=this.encoding[47];for(i=0;i=0;i--){n=n==20?1:n+1;g=g==15?1:g+1;index=o.indexOf(d.charAt(i));e+=n*index;j+=g*index}var l=e%47;j+=l;var f=j%47;m+=this.encoding[l];m+=this.encoding[f]}m+=this.encoding[47];m+="1";return(m)}},code128:{encoding:["11011001100","11001101100","11001100110","10010011000","10010001100","10001001100","10011001000","10011000100","10001100100","11001001000","11001000100","11000100100","10110011100","10011011100","10011001110","10111001100","10011101100","10011100110","11001110010","11001011100","11001001110","11011100100","11001110100","11101101110","11101001100","11100101100","11100100110","11101100100","11100110100","11100110010","11011011000","11011000110","11000110110","10100011000","10001011000","10001000110","10110001000","10001101000","10001100010","11010001000","11000101000","11000100010","10110111000","10110001110","10001101110","10111011000","10111000110","10001110110","11101110110","11010001110","11000101110","11011101000","11011100010","11011101110","11101011000","11101000110","11100010110","11101101000","11101100010","11100011010","11101111010","11001000010","11110001010","10100110000","10100001100","10010110000","10010000110","10000101100","10000100110","10110010000","10110000100","10011010000","10011000010","10000110100","10000110010","11000010010","11001010000","11110111010","11000010100","10001111010","10100111100","10010111100","10010011110","10111100100","10011110100","10011110010","11110100100","11110010100","11110010010","11011011110","11011110110","11110110110","10101111000","10100011110","10001011110","10111101000","10111100010","11110101000","11110100010","10111011110","10111101110","11101011110","11110101110","11010000100","11010010000","11010011100","11000111010"],getDigit:function(d){var m=" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";var n="";var k=0;var e=0;var h=0;var g=0;var o=0;for(h=0;h1;var l="";for(h=0;h<3&&h="0"&&l<="9"}k=f?105:104;n=this.encoding[k];h=0;while(h="0")&&(d.charAt(h+g)<="9")){g++}f=(g>5)||((h+g-1==d.length)&&(g>3));if(f){n+=this.encoding[99];k+=++e*99}}else{if((h==d.length)||(d.charAt(h)<"0")||(d.charAt(h)>"9")||(d.charAt(h+1)<"0")||(d.charAt(h+1)>"9")){f=false;n+=this.encoding[100];k+=++e*100}}if(f){o=a.intval(d.charAt(h)+d.charAt(h+1));h+=2}else{o=m.indexOf(d.charAt(h));h+=1}n+=this.encoding[o];k+=++e*o}n+=this.encoding[k%103];n+=this.encoding[106];n+="11";return(n)}},codabar:{encoding:["101010011","101011001","101001011","110010101","101101001","110101001","100101011","100101101","100110101","110100101","101001101","101100101","1101011011","1101101011","1101101101","1011011011","1011001001","1010010011","1001001011","1010011001"],getDigit:function(f){var e="0123456789-$:/.+";var d,c,h="",g="0";h+=this.encoding[16]+g;for(d=0;d1558)&&!d){return -1}if((c<1||c>49)&&d){return -1}var e=0;if(d){e=24}while(this.dataCWCount[e]127){e[h]=235;g=g-127;h++}else{if((g>=48&&g<=57)&&(d+1=48&&f.charCodeAt(d+1)<=57)){g=((g-48)*10)+((f.charCodeAt(d+1))-48);g+=130;d++}else{g++}}e[h]=g;h++}return e},addPadCW:function(d,g,f){if(g>=f){return}d[g]=129;var e,c;for(c=g+1;c=0;d--){f[d]=this.champGaloisDoub(f[d],e);if(d>0){f[d]=this.champGaloisSum(f[d],f[d-1])}}}return f},addReedSolomonCW:function(c,g,l,m,h){var o=0;var n=c/h;var p=new Array();var f,e,d;for(d=0;d=0;e--){if(!o){p[e]=0}else{p[e]=this.champGaloisMult(o,g[e])}if(e>0){p[e]=this.champGaloisSum(p[e-1],p[e])}}}e=l+d;for(f=n-1;f>=0;f--){m[e]=p[f];e=e+h}}return m},getBits:function(d){var e=new Array();for(var c=0;c<8;c++){e[c]=d&(128>>c)?1:0}return e},next:function(h,k,d,j,g,c){var f=0;var l=4;var e=0;do{if((l==k)&&(e==0)){this.patternShapeSpecial1(g,c,j[f],k,d);f++}else{if((h<3)&&(l==k-2)&&(e==0)&&(d%4!=0)){this.patternShapeSpecial2(g,c,j[f],k,d);f++}else{if((l==k-2)&&(e==0)&&(d%8==4)){this.patternShapeSpecial3(g,c,j[f],k,d);f++}else{if((l==k+4)&&(e==2)&&(d%8==0)){this.patternShapeSpecial4(g,c,j[f],k,d);f++}}}}do{if((l=0)&&(c[l][e]!=1)){this.patternShapeStandard(g,c,j[f],l,e,k,d);f++}l-=2;e+=2}while((l>=0)&&(e=0)&&(e=0));l+=3;e+=1}while((l>8}return d},cRgb:function(e,d,c){return String.fromCharCode(c)+String.fromCharCode(d)+String.fromCharCode(e)},cHexColor:function(h){var d=parseInt("0x"+h.substr(1));var c=d&255;d=d>>8;var f=d&255;var e=d>>8;return(this.cRgb(e,f,c))}},hexToRGB:function(h){var d=parseInt("0x"+h.substr(1));var c=d&255;d=d>>8;var f=d&255;var e=d>>8;return({r:e,g:f,b:c})},isHexColor:function(d){var c=new RegExp("#[0-91-F]","gi");return d.match(c)},base64Encode:function(o){var c="",h,f,e,n,m,l,j;var d="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var g=0;while(g>2;m=((h&3)<<4)|(f>>4);l=((f&15)<<2)|(e>>6);j=e&63;if(isNaN(f)){l=j=64}else{if(isNaN(e)){j=64}}c+=d.charAt(n)+d.charAt(m)+d.charAt(l)+d.charAt(j)}return c},bitStringTo2DArray:function(f){var e=[];e[0]=[];for(var c=0;c=0;h--){var l="";for(var j=0;j';var l='
';var f,h;for(var k=0;k0){j+=(h=="0"?o:l).replace("&W",f*p)}}if(d.showHRI){j+='
'+e+"
"}this.resize(q,p*c).html(j)},digitToCss:function(g,f,j,d){var c=a.intval(f.barWidth);var e=a.intval(f.barHeight);this.digitToCssRenderer(g,f,this.bitStringTo2DArray(j),d,c,e)},digitToCss2D:function(f,e,g,c){var d=a.intval(e.moduleSize);this.digitToCssRenderer(f,e,g,c,d,d)},digitToSvgRenderer:function(q,s,n,f,l,t){var d=n.length;var e=n[0].length;var o=l*e;var u=t*d;if(s.showHRI){var g=a.intval(s.fontSize);u+=a.intval(s.marginHRI)+g}var m='';m+='';var c='';var r,p;for(var h=0;h0)&&(p=="1")){m+=c.replace("&W",r*l).replace("&X",(e-r)*l).replace("&Y",h*t)}}if(s.showHRI){m+='';m+=''+f+"";m+=""}m+="";var k=document.createElement("object");k.setAttribute("type","image/svg+xml");k.setAttribute("data","data:image/svg+xml,"+m);this.resize(q,o).append(k)},digitToSvg:function(g,f,j,d){var c=a.intval(f.barWidth);var e=a.intval(f.barHeight);this.digitToSvgRenderer(g,f,this.bitStringTo2DArray(j),d,c,e)},digitToSvg2D:function(f,e,g,c){var d=a.intval(e.moduleSize);this.digitToSvgRenderer(f,e,g,c,d,d)},digitToCanvasRenderer:function(s,d,o,f,m,e,q,k){var j=s.get(0);if(!j||!j.getContext){return}var t=o.length;var c=o[0].length;var r=j.getContext("2d");r.lineWidth=1;r.lineCap="butt";r.fillStyle=d.bgColor;r.fillRect(m,e,c*q,t*k);r.fillStyle=d.color;for(var n=0;n0)&&(l=="1")){r.fillRect(m+(c-h)*q,e+n*k,q*h,k)}}if(d.showHRI){var g=r.measureText(f);r.fillText(f,m+Math.floor((c*q-g.width)/2),e+t*k+d.fontSize+d.marginHRI)}},digitToCanvas:function(j,g,l,e){var d=a.intval(g.barWidth);var f=a.intval(g.barHeight);var c=a.intval(g.posX);var k=a.intval(g.posY);this.digitToCanvasRenderer(j,g,this.bitStringTo2DArray(l),e,c,k,d,f)},digitToCanvas2D:function(g,f,j,d){var e=a.intval(f.moduleSize);var c=a.intval(f.posX);var h=a.intval(f.posY);this.digitToCanvasRenderer(g,f,j,d,c,h,e,e)}};b.fn.extend({barcode:function(h,m,f){var o="",g="",d="",k=true,n=false,j=false;if(typeof(h)=="string"){d=h}else{if(typeof(h)=="object"){d=typeof(h.code)=="string"?h.code:"";k=typeof(h.crc)!="undefined"?h.crc:true;n=typeof(h.rect)!="undefined"?h.rect:false}}if(d==""){return(false)}if(typeof(f)=="undefined"){f=[]}for(var c in a.settings){if(f[c]==undefined){f[c]=a.settings[c]}}switch(m){case"std25":case"int25":o=a.i25.getDigit(d,k,m);g=a.i25.compute(d,k,m);break;case"ean8":case"ean13":o=a.ean.getDigit(d,m);g=a.ean.compute(d,m);break;case"code11":o=a.code11.getDigit(d);g=d;break;case"code39":o=a.code39.getDigit(d);g=d;break;case"code93":o=a.code93.getDigit(d,k);g=d;break;case"code128":o=a.code128.getDigit(d);g=d;break;case"codabar":o=a.codabar.getDigit(d);g=d;break;case"msi":o=a.msi.getDigit(d,k);g=a.msi.compute(d,k);break;case"datamatrix":o=a.datamatrix.getDigit(d,n);g=d;j=true;break}if(o.length==0){return(b(this))}if(!j&&f.addQuietZone){o="0000000000"+o+"0000000000"}var l=b(this);var e="digitTo"+f.output.charAt(0).toUpperCase()+f.output.substr(1)+(j?"2D":"");if(typeof(a[e])=="function"){a[e](l,f,o,g)}return(l)}})}(jQuery)); \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/css/jquery.dataTables.css b/modules/thirdparty/jquery/datatables/css/jquery.dataTables.css new file mode 100644 index 0000000..7da7fae --- /dev/null +++ b/modules/thirdparty/jquery/datatables/css/jquery.dataTables.css @@ -0,0 +1,221 @@ + +/* + * Table + */ +table.dataTable { + margin: 0 auto; + clear: both; + width: 100%; +} + +table.dataTable thead th { + padding: 3px 18px 3px 10px; + border-bottom: 1px solid black; + font-weight: bold; + cursor: pointer; + *cursor: hand; +} + +table.dataTable tfoot th { + padding: 3px 18px 3px 10px; + border-top: 1px solid black; + font-weight: bold; +} + +table.dataTable td { + padding: 3px 10px; +} + +table.dataTable td.center, +table.dataTable td.dataTables_empty { + text-align: center; +} + +table.dataTable tr.odd { background-color: #E2E4FF; } +table.dataTable tr.even { background-color: white; } + +table.dataTable tr.odd td.sorting_1 { background-color: #D3D6FF; } +table.dataTable tr.odd td.sorting_2 { background-color: #DADCFF; } +table.dataTable tr.odd td.sorting_3 { background-color: #E0E2FF; } +table.dataTable tr.even td.sorting_1 { background-color: #EAEBFF; } +table.dataTable tr.even td.sorting_2 { background-color: #F2F3FF; } +table.dataTable tr.even td.sorting_3 { background-color: #F9F9FF; } + + +/* + * Table wrapper + */ +.dataTables_wrapper { + position: relative; + clear: both; + *zoom: 1; +} + + +/* + * Page length menu + */ +.dataTables_length { + float: left; +} + + +/* + * Filter + */ +.dataTables_filter { + float: right; + text-align: right; +} + + +/* + * Table information + */ +.dataTables_info { + clear: both; + float: left; +} + + +/* + * Pagination + */ +.dataTables_paginate { + float: right; + text-align: right; +} + +/* Two button pagination - previous / next */ +.paginate_disabled_previous, +.paginate_enabled_previous, +.paginate_disabled_next, +.paginate_enabled_next { + height: 19px; + float: left; + cursor: pointer; + *cursor: hand; + color: #111 !important; +} +.paginate_disabled_previous:hover, +.paginate_enabled_previous:hover, +.paginate_disabled_next:hover, +.paginate_enabled_next:hover { + text-decoration: none !important; +} +.paginate_disabled_previous:active, +.paginate_enabled_previous:active, +.paginate_disabled_next:active, +.paginate_enabled_next:active { + outline: none; +} + +.paginate_disabled_previous, +.paginate_disabled_next { + color: #666 !important; +} +.paginate_disabled_previous, +.paginate_enabled_previous { + padding-left: 23px; +} +.paginate_disabled_next, +.paginate_enabled_next { + padding-right: 23px; + margin-left: 10px; +} + +.paginate_enabled_previous { background: url('../images/back_enabled.png') no-repeat top left; } +.paginate_enabled_previous:hover { background: url('../images/back_enabled_hover.png') no-repeat top left; } +.paginate_disabled_previous { background: url('../images/back_disabled.png') no-repeat top left; } + +.paginate_enabled_next { background: url('../images/forward_enabled.png') no-repeat top right; } +.paginate_enabled_next:hover { background: url('../images/forward_enabled_hover.png') no-repeat top right; } +.paginate_disabled_next { background: url('../images/forward_disabled.png') no-repeat top right; } + +/* Full number pagination */ +.paging_full_numbers { + height: 22px; + line-height: 22px; +} +.paging_full_numbers a:active { + outline: none +} +.paging_full_numbers a:hover { + text-decoration: none; +} + +.paging_full_numbers a.paginate_button, +.paging_full_numbers a.paginate_active { + border: 1px solid #aaa; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + padding: 2px 5px; + margin: 0 3px; + cursor: pointer; + *cursor: hand; + color: #333 !important; +} + +.paging_full_numbers a.paginate_button { + background-color: #ddd; +} + +.paging_full_numbers a.paginate_button:hover { + background-color: #ccc; + text-decoration: none !important; +} + +.paging_full_numbers a.paginate_active { + background-color: #99B3FF; +} + + +/* + * Processing indicator + */ +.dataTables_processing { + position: absolute; + top: 50%; + left: 50%; + width: 250px; + height: 30px; + margin-left: -125px; + margin-top: -15px; + padding: 14px 0 2px 0; + border: 1px solid #ddd; + text-align: center; + color: #999; + font-size: 14px; + background-color: white; +} + + +/* + * Sorting + */ +.sorting { background: url('../images/sort_both.png') no-repeat center right; } +.sorting_asc { background: url('../images/sort_asc.png') no-repeat center right; } +.sorting_desc { background: url('../images/sort_desc.png') no-repeat center right; } + +.sorting_asc_disabled { background: url('../images/sort_asc_disabled.png') no-repeat center right; } +.sorting_desc_disabled { background: url('../images/sort_desc_disabled.png') no-repeat center right; } + +table.dataTable thead th:active, +table.dataTable thead td:active { + outline: none; +} + + +/* + * Scrolling + */ +.dataTables_scroll { + clear: both; +} + +.dataTables_scrollBody { + *margin-top: -1px; + -webkit-overflow-scrolling: touch; +} + diff --git a/modules/thirdparty/jquery/datatables/css/jquery.dataTables_themeroller.css b/modules/thirdparty/jquery/datatables/css/jquery.dataTables_themeroller.css new file mode 100644 index 0000000..cf1d4ed --- /dev/null +++ b/modules/thirdparty/jquery/datatables/css/jquery.dataTables_themeroller.css @@ -0,0 +1,244 @@ + + +/* + * Table + */ +table.dataTable { + margin: 0 auto; + clear: both; + width: 100%; + border-collapse: collapse; +} + +table.dataTable thead th { + padding: 3px 0px 3px 10px; + cursor: pointer; + *cursor: hand; +} + +table.dataTable tfoot th { + padding: 3px 10px; +} + +table.dataTable td { + padding: 3px 10px; +} + +table.dataTable td.center, +table.dataTable td.dataTables_empty { + text-align: center; +} + +table.dataTable tr.odd { background-color: #E2E4FF; } +table.dataTable tr.even { background-color: white; } + +table.dataTable tr.odd td.sorting_1 { background-color: #D3D6FF; } +table.dataTable tr.odd td.sorting_2 { background-color: #DADCFF; } +table.dataTable tr.odd td.sorting_3 { background-color: #E0E2FF; } +table.dataTable tr.even td.sorting_1 { background-color: #EAEBFF; } +table.dataTable tr.even td.sorting_2 { background-color: #F2F3FF; } +table.dataTable tr.even td.sorting_3 { background-color: #F9F9FF; } + + +/* + * Table wrapper + */ +.dataTables_wrapper { + position: relative; + clear: both; + *zoom: 1; +} +.dataTables_wrapper .ui-widget-header { + font-weight: normal; +} +.dataTables_wrapper .ui-toolbar { + padding: 5px; +} + + +/* + * Page length menu + */ +.dataTables_length { + float: left; +} + + +/* + * Filter + */ +.dataTables_filter { + float: right; + text-align: right; +} + + +/* + * Table information + */ +.dataTables_info { + padding-top: 3px; + clear: both; + float: left; +} + + +/* + * Pagination + */ +.dataTables_paginate { + float: right; + text-align: right; +} + +.dataTables_paginate .ui-button { + margin-right: -0.1em !important; +} + +.paging_two_button .ui-button { + float: left; + cursor: pointer; + * cursor: hand; +} + +.paging_full_numbers .ui-button { + padding: 2px 6px; + margin: 0; + cursor: pointer; + * cursor: hand; + color: #333 !important; +} + +/* Two button pagination - previous / next */ +.paginate_disabled_previous, +.paginate_enabled_previous, +.paginate_disabled_next, +.paginate_enabled_next { + height: 19px; + float: left; + cursor: pointer; + *cursor: hand; + color: #111 !important; +} +.paginate_disabled_previous:hover, +.paginate_enabled_previous:hover, +.paginate_disabled_next:hover, +.paginate_enabled_next:hover { + text-decoration: none !important; +} +.paginate_disabled_previous:active, +.paginate_enabled_previous:active, +.paginate_disabled_next:active, +.paginate_enabled_next:active { + outline: none; +} + +.paginate_disabled_previous, +.paginate_disabled_next { + color: #666 !important; +} +.paginate_disabled_previous, +.paginate_enabled_previous { + padding-left: 23px; +} +.paginate_disabled_next, +.paginate_enabled_next { + padding-right: 23px; + margin-left: 10px; +} + +.paginate_enabled_previous { background: url('../images/back_enabled.png') no-repeat top left; } +.paginate_enabled_previous:hover { background: url('../images/back_enabled_hover.png') no-repeat top left; } +.paginate_disabled_previous { background: url('../images/back_disabled.png') no-repeat top left; } + +.paginate_enabled_next { background: url('../images/forward_enabled.png') no-repeat top right; } +.paginate_enabled_next:hover { background: url('../images/forward_enabled_hover.png') no-repeat top right; } +.paginate_disabled_next { background: url('../images/forward_disabled.png') no-repeat top right; } + +/* Full number pagination */ +.paging_full_numbers a:active { + outline: none +} +.paging_full_numbers a:hover { + text-decoration: none; +} + +.paging_full_numbers a.paginate_button, +.paging_full_numbers a.paginate_active { + border: 1px solid #aaa; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + padding: 2px 5px; + margin: 0 3px; + cursor: pointer; + *cursor: hand; + color: #333 !important; +} + +.paging_full_numbers a.paginate_button { + background-color: #ddd; +} + +.paging_full_numbers a.paginate_button:hover { + background-color: #ccc; + text-decoration: none !important; +} + +.paging_full_numbers a.paginate_active { + background-color: #99B3FF; +} + + +/* + * Processing indicator + */ +.dataTables_processing { + position: absolute; + top: 50%; + left: 50%; + width: 250px; + height: 30px; + margin-left: -125px; + margin-top: -15px; + padding: 14px 0 2px 0; + border: 1px solid #ddd; + text-align: center; + color: #999; + font-size: 14px; + background-color: white; +} + + +/* + * Sorting + */ +table.dataTable thead th div.DataTables_sort_wrapper { + position: relative; + padding-right: 20px; +} + +table.dataTable thead th div.DataTables_sort_wrapper span { + position: absolute; + top: 50%; + margin-top: -8px; + right: 0; +} + +table.dataTable th:active { + outline: none; +} + + +/* + * Scrolling + */ +.dataTables_scroll { + clear: both; +} + +.dataTables_scrollBody { + *margin-top: -1px; + -webkit-overflow-scrolling: touch; +} + diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/callbacks.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/callbacks.html new file mode 100755 index 0000000..b276593 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/callbacks.html @@ -0,0 +1,552 @@ + + + + + + + AutoFill example + + + + + + + +
+
+ AutoFill example +
+ +

Preamble

+

+ AutoFill provides a number of customisable callback functions so you can tailor it's + actions to exactly what you need. This specific example shows fnCallback, which is fired when the mouse is released. Further documentation is below. +

+ +
    +
  • + fnRead - Called when a cell is read for it's value. This allows you to override the default of reading the HTML value (or 'input' elements value if there is one present). For example reading the value from a select list. +
      +
    • Parameter 1: Node - TD element to be read from
    • +
    • Returns: String - read value
    • +
    +
  • +
  • + fnWrite - Called when a cell is to read to. This allows you to write in a specific format, or perhaps to an element within the cell. +
      +
    • Parameter 1: Node - TD element to be written to
    • +
    • Parameter 2: String - Value to write
    • +
    • Parameter 3: Boolean - Last cell to be written (useful for speeding up DataTables' fnUpdate)
    • +
    • Returns: void
    • +
    +
  • +
  • + fnStep - Called to calculate the new value to give to a cell +
      +
    • Parameter 1: Node - TD element to be written to
    • +
    • Parameter 2: String - Statement with a token to be replace with the calculated value
    • +
    • Parameter 3: Int - Step counter
    • +
    • Parameter 4: Boolean - increment (true), or decrement (false)
    • +
    • Parameter 5: String - Token to replace
    • +
    • Returns: String - string to write into the cell
    • +
    +
  • +
  • + fnCallback - Called when the AutoFill is complete, with information about the fill. This can be useful for updating a server database for example. +
      +
    • Parameter 1: Array - An array of objects with information about each cell that was written to. Object parameters are: "td", "newValue" and "oldValue".
    • +
    • Returns: void
    • +
    +
  • +
+ + +

Live example

+
+
+ Information about each update will appear here.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable();
+	new AutoFill( oTable, {
+		"aoColumnDefs": [ {
+			"fnCallback": function ( ao ) {
+				var n = document.getElementById('output');
+				for ( var i=0, iLen=ao.length ; i<iLen ; i++ ) {
+					n.innerHTML += "Update: old value: {"+
+						ao[i].oldValue+"} - new value: {"+ao[i].newValue+"}<br>";
+				}
+				n.scrollTop = n.scrollHeight;
+			},
+			"aTargets": [ "_all" ]
+		} ]
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/columns.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/columns.html new file mode 100755 index 0000000..2d7ad1d --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/columns.html @@ -0,0 +1,503 @@ + + + + + + + AutoFill example + + + + + + + +
+
+ AutoFill example with column selection options +
+ +

Preamble

+

+ Columns can be enabled (default) and disabled from providing the end user the AutoFill option + by using either aoColumns or aoColumnDefs and the bEnable option. These two arrays work in + exactly the same way has for DataTables. +

+

+ This example shows how disabling columns counting from the right hand side of the table + can be achieved. In this case, the last three columns. +

+ + +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable();
+	new AutoFill( oTable, {
+		"aoColumnDefs": [ {
+			"bEnable": false,
+			"aTargets": [ -1, -2, -3 ]
+		} ]
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/index.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/index.html new file mode 100755 index 0000000..c9e9557 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/index.html @@ -0,0 +1,489 @@ + + + + + + + AutoFill example + + + + + + + +
+
+ AutoFill example +
+ +

Preamble

+

+ AutoFill gives an Excel like option to a DataTable to click and drag over multiple + cells, filling in information over the selected cells and incrementing numbers as needed. +

+

Thanks to Phoniax AS for their sponsorship of this plug-in for DataTables.

+ + + +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable();
+	new AutoFill( oTable );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/inputs.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/inputs.html new file mode 100755 index 0000000..bdb9140 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/inputs.html @@ -0,0 +1,519 @@ + + + + + + + AutoFill example + + + + + + + +
+
+ AutoFill example with input elements +
+ +

Preamble

+

+ AutoFill works with Input elements and Select elements, as well as plain HTML cells. This + example shows all inputs cells, combined with DataTables' DOM sorting plug-in. You can + even combine input and plain HTML cells if you wanted (useful from something like jEditable). +

+ + + +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$.fn.dataTableExt.afnSortData['dom-text'] = function ( oSettings, iColumn )
+{
+	var aData = [];
+	$( 'td:eq('+iColumn+') input', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
+		aData.push( this.value );
+	} );
+	return aData;
+}
+
+$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"aoColumnDefs": [
+			{ "sSortDataType": "dom-text", "aTargets": [ "_all" ] },
+			{ "sType": "numeric", "aTargets": [ -2 ] }
+		]
+	} );
+	new AutoFill( oTable );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/css/AutoFill.css b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/css/AutoFill.css new file mode 100644 index 0000000..cab59b3 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/css/AutoFill.css @@ -0,0 +1,24 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * AutoFill styles + */ + +div.AutoFill_filler { + display: none; + position: absolute; + height: 14px; + width: 14px; + background: url(../images/filler.png) no-repeat center center; + z-index: 1002; +} + +div.AutoFill_border { + display: none; + position: absolute; + background-color: #0063dc; + z-index: 1001; + + box-shadow: 0px 0px 5px #76b4ff; + -moz-box-shadow: 0px 0px 5px #76b4ff; + -webkit-box-shadow: 0px 0px 5px #76b4ff; +} + diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/02ff627f40.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/02ff627f40.html new file mode 100644 index 0000000..53c0f08 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/02ff627f40.html @@ -0,0 +1,75 @@ + + + + + Namespace: Store for live information for the current drag - documentation + + + + + + + + + +
+ + +
+

Namespace: Store for live information for the current drag

+ +
+ +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/36456bf45f.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/36456bf45f.html new file mode 100644 index 0000000..c300cc7 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/36456bf45f.html @@ -0,0 +1,75 @@ + + + + + Namespace: Settings object which contains customisable information for AutoFill instance - documentation + + + + + + + + + +
+ + +
+

Namespace: Settings object which contains customisable information for AutoFill instance

+ +
+ +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/47cac4f141.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/47cac4f141.html new file mode 100644 index 0000000..6281931 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/47cac4f141.html @@ -0,0 +1,75 @@ + + + + + Namespace: Cached information about the border display - documentation + + + + + + + + + +
+ + +
+

Namespace: Cached information about the border display

+ +
+ +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/5a72546831.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/5a72546831.html new file mode 100644 index 0000000..64d1cee --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/5a72546831.html @@ -0,0 +1,77 @@ + + + + + Namespace: Data cache for the position of the DataTables scrolling element (when scrolling + is enabled) - documentation + + + + + + + + + +
+ + +
+

Namespace: Data cache for the position of the DataTables scrolling element (when scrolling + is enabled)

+ +
+ +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/8ee4007a12.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/8ee4007a12.html new file mode 100644 index 0000000..effbccd --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/8ee4007a12.html @@ -0,0 +1,77 @@ + + + + + Namespace: Data cache for information that we need for scrolling the screen when we near + the edges - documentation + + + + + + + + + +
+ + +
+

Namespace: Data cache for information that we need for scrolling the screen when we near + the edges

+ +
+ +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/AutoFill.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/AutoFill.html new file mode 100644 index 0000000..760bb2d --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/AutoFill.html @@ -0,0 +1,93 @@ + + + + + Class: AutoFill - documentation + + + + + + + + + +
+ + +
+

Class: AutoFill

+

AutoFill

+
+ +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
new AutoFill(DataTables, Configuration)

AutoFill provides Excel like auto fill features for a DataTable

Constructor

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
DataTablesobject

settings object

2
Configurationobject

object for AutoFill

+
+
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/a69b02bcf2.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/a69b02bcf2.html new file mode 100644 index 0000000..194635b --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/a69b02bcf2.html @@ -0,0 +1,75 @@ + + + + + Namespace: Common and useful DOM elements for the class instance - documentation + + + + + + + + + +
+ + +
+

Namespace: Common and useful DOM elements for the class instance

+ +
+ +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/b44bd4821a.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/b44bd4821a.html new file mode 100644 index 0000000..723c61f --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/b44bd4821a.html @@ -0,0 +1,75 @@ + + + + + Namespace: An array of objects - documentation + + + + + + + + + +
+ + +
+

Namespace: An array of objects

+ +
+ +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/c6945fdb4a.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/c6945fdb4a.html new file mode 100644 index 0000000..ce19cba --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/c6945fdb4a.html @@ -0,0 +1,75 @@ + + + + + Namespace: Cached information about the little dragging icon - documentation + + + + + + + + + +
+ + +
+

Namespace: Cached information about the little dragging icon

+ the filler +
+ +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/global.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/global.html new file mode 100644 index 0000000..841bcfd --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/global.html @@ -0,0 +1,371 @@ + + + + + Global - documentation + + + + + + + + + +
+ + +
+

Global

+ +
+ +
+
+ + + +
+

Navigation

+ +
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +

Summary

+ +

Classes

+
+
AutoFill

AutoFill provides Excel like auto fill features for a DataTable

+

Properties - instance

+ +
+
<constant> CLASS :String

Name of this class

<constant> VERSION :String

AutoFill version

+

Methods - instance

+ +
+
fnSettings() → {object}

Retreieve the settings object from an instance

_fnFillerDisplay(e)

Display the drag handle on mouse over cell

_fnFillerDragMove(e)

Mouse move event handler for during a move. See if we want to update the display based on the +new cursor position

_fnFillerDragStart(e)

Mouse down event handler for starting a drag

_fnFillerFinish(e)

Mouse release handler - end the drag and take action to update the cells with the needed values

_fnFillerPosition(nTd)

Position the filler icon over a cell

_fnInit(oDT, oConfig)

Initialisation

_fnPrep(sStr) → {Object}

Chunk a string such that it can be filled in by the stepper function

_fnReadCell(nTd) → {String}

Read informaiton from a cell, possibly using live DOM elements if suitable

_fnStep(nTd, oPrepped, iDiff, bIncrement, sToken) → {String}

Render a string for it's position in the table after the drag (incrememt numbers)

_fnTargetCoords(nTd) → {Object}

Find out the coordinates of a given TD cell in a table

_fnUpdateBorder(nStart, nEnd)

Display the border around one or more cells (from start to end)

_fnWriteCell(nTd, sVal, bLast)

Write informaiton to a cell, possibly using live DOM elements if suitable

+
+
+
+ + + + +
+ +

Details

+

Properties - instance

+
+
<constant> CLASS :String

Name of this class

+ +
+
<constant> VERSION :String

AutoFill version

+ +
+
+

Methods - instance

+
+
fnSettings() → {object}

Retreieve the settings object from an instance

+ +
+
Returns:

AutoFill settings object

+
_fnFillerDisplay(e)

Display the drag handle on mouse over cell

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
eObject

Event object

Returns:

void

+
_fnFillerDragMove(e)

Mouse move event handler for during a move. See if we want to update the display based on the +new cursor position

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
eObject

Event object

Returns:

void

+
_fnFillerDragStart(e)

Mouse down event handler for starting a drag

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
eObject

Event object

Returns:

void

+
_fnFillerFinish(e)

Mouse release handler - end the drag and take action to update the cells with the needed values

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
eObject

Event object

Returns:

void

+
_fnFillerPosition(nTd)

Position the filler icon over a cell

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
nTdNode

Cell to position filler icon over

Returns:

void

+
_fnInit(oDT, oConfig)

Initialisation

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
oDTobject

DataTables settings object

2
oConfigobject

Configuration object for AutoFill

Returns:

void

+
_fnPrep(sStr) → {Object}

Chunk a string such that it can be filled in by the stepper function

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
sStrString

String to prep

Returns:

with parameters, iStart, sStr and sPostFix

+
_fnReadCell(nTd) → {String}

Read informaiton from a cell, possibly using live DOM elements if suitable

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
nTdNode

Cell to read

Returns:

Read value

+
_fnStep(nTd, oPrepped, iDiff, bIncrement, sToken) → {String}

Render a string for it's position in the table after the drag (incrememt numbers)

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
nTdNode

Cell being written to

2
oPreppedObject

Prepared object for the stepper (from _fnPrep)

3
iDiffInt

Step difference

4
bIncrementBoolean

Increment (true) or decriment (false)

5
sTokenString

Token to replace

Returns:

Rendered information

+
_fnTargetCoords(nTd) → {Object}

Find out the coordinates of a given TD cell in a table

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
nTdNodeundefined
Returns:

x and y properties, for the position of the cell in the tables DOM

+
_fnUpdateBorder(nStart, nEnd)

Display the border around one or more cells (from start to end)

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
nStartNode

Starting cell

2
nEndNode

Ending cell

Returns:

void

+
_fnWriteCell(nTd, sVal, bLast)

Write informaiton to a cell, possibly using live DOM elements if suitable

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
nTdNode

Cell to write

2
sValString

Value to write

3
bLastBoolean

Flag to show if this is that last update

Returns:

void

+ +
+
+
+ +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/index.html b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/index.html new file mode 100644 index 0000000..cffc291 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/index.html @@ -0,0 +1,40 @@ + + + + + Table of Contents - documentation + + + + + + + + + +
+ +
+
+ +
+

Table of Contents

+
+
AutoFill

AutoFill provides Excel like auto fill features for a DataTable

+
+
+
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/doc.css b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/doc.css new file mode 100644 index 0000000..a239329 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/doc.css @@ -0,0 +1,393 @@ +/* +Copyright (c) 2006, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 0.12.0 +*/ +body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;} +table{border-collapse:collapse;border-spacing:0;} +fieldset,img{border:0;} +address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;} +ol,ul {list-style:none;} +caption,th {text-align:left;} +h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;} +q:before,q:after{content:'';} +abbr,acronym {border:0;} + + +html, body { + margin: 0; + padding: 0; + width: 100%; + font: 14px/1.45em "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; + color: #111; +} + +div.fw_container { + width: 980px; + padding-top: 2em; + margin: 0 auto; +} + +div.fw_header { + position: relative; +} + +div.fw_content { + padding-top: 2em; +} + +div.fw_footer { + padding-top: 4em; + font-size: 75%; + text-align: center; +} + + + + +.type-attr .type-signature { + background-color: #ccc; + color: white; + border-radius: 3px; + display: inline-block; + padding: 0 3px; + font-size: 0.9em; +} + +.type-attr { + float: right; + color: #999; +} + +.type-name { + font-weight: bold; +} + +.type-sig { + color: #999; +} + +.type-param { + color: #D32929; +} + +.type-return { + color: #FF8080; +} + +.type-brace { + color: #111; +} + +.example-code { + margin-left: 30px; +} +.example-code td.code { + border-top: 1px solid #4E6CA3 !important; +} + +.type-augmented { + position: absolute; + left: 8px; + top: 0; +} + +dt, dd { + padding: 0.4em 10px; +} + +dt { + padding-bottom: 0 !important; +} + +dd { + position: relative; + padding-top: 0 !important; + padding-left: 3em; +} + +dt.even, dd.even { + background-color: white; +} + +dt.odd, dd.odd { + background-color: #F2F2F2; +} + +div.doc_overview dd, div.doc_overview dt { + padding-left: 0 !important; +} + + + +.right_border div { + width: 20px; + padding: 2px 0.5em 2px 1em; + text-align: right; +} +.right_border { + border-right: 3px solid #4E6CA3; +} +.bottom_border { + border-bottom: 1px solid #4E6CA3; +} + + +a { + text-decoration: none; + color: #4E6CA3; +} + +a:hover { + text-decoration: underline; + cursor: pointer; + *cursor: hand; +} + +div.fw_content ul { + list-style-image: url('../images/arrow.png'); + padding: 0 0 0 2em; +} + +/* +h2 { + font-size: 1.4em; + margin-top: 2em; + border-bottom: 3px solid #829ac6; + padding-left: 5px; +} + +h3 { + font-size: 1.2em; + margin-top: 1em; + border-bottom: 1px solid #A4B5D5; + padding-left: 5px; +} +*/ + +h1 { + font-size: 2em; +} + +h2 { + font-size: 1.6em; + padding-top: 5px; +} + +h2.ancestors { + font-size: 14px; + margin: 0; +} + +h3 { + font-size: 1.3em; + padding-top: 5px; + margin-bottom: 5px; +} + +h5 { + padding-top: 6px; + font-weight: bold; + font-size: 0.9em; + border-bottom: 1px solid #cad4e6; + margin-bottom: 1em; +} + +div.doc_summary, div.doc_details { + margin-top: 2em; + clear: both; +} + +div.doc_group { + margin-top: 1em; + border-top: 1px solid #A4B5D5; + border-left: 1px solid #A4B5D5; + padding-left: 10px; +} + +div.extended { + margin-left: 30px; +} + +table.params { + margin-left: 30px; + width: 97%; +} + +table.params th, +table.params td { + padding: 3px; +} + +tr.odd { + background-color: white; +} + +tr.even { + background-color: #F8F8F8; +} + +th.name, +td.name { + padding-left: 13px; +} + +td.number { + background-color: white; + color: #5C5C5C; +} + +dd.odd td.number { + background-color: #F2F2F2; +} + +p { + margin: 1em 0; +} + +p:first-child { + margin-top: 0; +} + +p:last-child { + margin-bottom: 0; +} + +p.returns { + margin-left: 5%; +} + +div.page-info { + position: absolute; + top: 0; + right: 0; +} + + +.private { + display: none; +} + + +code { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + padding: 2px 4px !important; + white-space: pre; + font-size: 0.9em; + + color: #D14; + background-color: #F7F7F9; + + border: 1px solid #E1E1E8; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +pre { + background-color: #f8f8f8; + border: 1px solid #ccc; + border-radius: 3px; + padding: 6px 10px; +} + +pre>code { + background-color: transparent; + border: none; + color: #111; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +ol { + list-style-type: decimal; + list-style-position: outside; + padding-left: 30px; +} + + + +div.fw_nav { + position: fixed; + top: 25px; + right: 30px; + width: 250px; + border: 1px solid #A4B5D5; + background-color: white; + padding: 10px; + z-index: 1001; + font-size: 12px; + overflow: hidden; +} + +div.fw_nav h2 { + margin: -10px 0 10px -10px; + width: 250px; + padding: 5px 10px; + background-color: #A4B5D5; + font-size: 12px; + cursor: pointer; + *cursor: hand; +} + +div.fw_nav ul>li>div { + padding: 0 0 0 1em; +} + +div.nav_blocker { + float: right; +} + +div.fw_nav td { + color: #999; +} + +div.fw_nav li { + margin-bottom: 5px; +} + +div.fw_nav li>a { + font-weight: bold; +} + + + + + + + +.css_clear { + clear: both; + height: 0; + line-height: 0; + visibility: hidden; +} + +.css_right { + text-align: right; +} + +.css_center { + text-align: center; +} + +.css_spacing { + margin-top: 1.5em; +} + +.css_small { + font-size: 75%; + line-height: 1.45em; +} + +.css_vsmall { + font-size: 65%; + line-height: 1.45em; +} diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/shCore.css b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/shCore.css new file mode 100644 index 0000000..b0c4520 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/shCore.css @@ -0,0 +1,226 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter a, +.syntaxhighlighter div, +.syntaxhighlighter code, +.syntaxhighlighter table, +.syntaxhighlighter table td, +.syntaxhighlighter table tr, +.syntaxhighlighter table tbody, +.syntaxhighlighter table thead, +.syntaxhighlighter table caption, +.syntaxhighlighter textarea { + -moz-border-radius: 0 0 0 0 !important; + -webkit-border-radius: 0 0 0 0 !important; + background: none !important; + border: 0 !important; + bottom: auto !important; + float: none !important; + height: auto !important; + left: auto !important; + line-height: 1.1em !important; + margin: 0 !important; + outline: 0 !important; + overflow: visible !important; + padding: 0 !important; + position: static !important; + right: auto !important; + text-align: left !important; + top: auto !important; + vertical-align: baseline !important; + width: auto !important; + box-sizing: content-box !important; + font-family: "Consolas","Monaco","Bitstream Vera Sans Mono","Courier New",Courier,monospace !important; + font-weight: normal !important; + font-style: normal !important; + font-size: 1em !important; + min-height: inherit !important; + min-height: auto !important; +} + +.syntaxhighlighter { + width: 100% !important; + margin: 1em 0 1em 0 !important; + position: relative !important; + overflow: auto !important; + font-size: 1em !important; +} +.syntaxhighlighter.source { + overflow: hidden !important; +} +.syntaxhighlighter .bold { + font-weight: bold !important; +} +.syntaxhighlighter .italic { + font-style: italic !important; +} +.syntaxhighlighter .line { + white-space: pre !important; +} +.syntaxhighlighter table { + width: 100% !important; +} +.syntaxhighlighter table caption { + text-align: left !important; + padding: .5em 0 0.5em 1em !important; +} +.syntaxhighlighter table td.code { + width: 100% !important; +} +.syntaxhighlighter table td.code .container { + position: relative !important; +} +.syntaxhighlighter table td.code .container textarea { + box-sizing: border-box !important; + position: absolute !important; + left: 0 !important; + top: 0 !important; + width: 100% !important; + height: 100% !important; + border: none !important; + background: white !important; + padding-left: 1em !important; + overflow: hidden !important; + white-space: pre !important; +} +.syntaxhighlighter table td.gutter .line { + text-align: right !important; + padding: 2px 0.5em 2px 1em !important; +} +.syntaxhighlighter table td.code .line { + padding: 2px 1em !important; +} +.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { + padding-left: 0em !important; +} +.syntaxhighlighter.show { + display: block !important; +} +.syntaxhighlighter.collapsed table { + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar { + padding: 0.1em 0.8em 0em 0.8em !important; + font-size: 1em !important; + position: static !important; + width: auto !important; + height: auto !important; +} +.syntaxhighlighter.collapsed .toolbar span { + display: inline !important; + margin-right: 1em !important; +} +.syntaxhighlighter.collapsed .toolbar span a { + padding: 0 !important; + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar span a.expandSource { + display: inline !important; +} +.syntaxhighlighter .toolbar { + position: absolute !important; + right: 1px !important; + top: 1px !important; + width: 11px !important; + height: 11px !important; + font-size: 10px !important; + z-index: 10 !important; +} +.syntaxhighlighter .toolbar span.title { + display: inline !important; +} +.syntaxhighlighter .toolbar a { + display: block !important; + text-align: center !important; + text-decoration: none !important; + padding-top: 1px !important; +} +.syntaxhighlighter .toolbar a.expandSource { + display: none !important; +} +.syntaxhighlighter.ie { + font-size: .9em !important; + padding: 1px 0 1px 0 !important; +} +.syntaxhighlighter.ie .toolbar { + line-height: 8px !important; +} +.syntaxhighlighter.ie .toolbar a { + padding-top: 0px !important; +} +.syntaxhighlighter.printing .line.alt1 .content, +.syntaxhighlighter.printing .line.alt2 .content, +.syntaxhighlighter.printing .line.highlighted .number, +.syntaxhighlighter.printing .line.highlighted.alt1 .content, +.syntaxhighlighter.printing .line.highlighted.alt2 .content { + background: none !important; +} +.syntaxhighlighter.printing .line .number { + color: #bbbbbb !important; +} +.syntaxhighlighter.printing .line .content { + color: black !important; +} +.syntaxhighlighter.printing .toolbar { + display: none !important; +} +.syntaxhighlighter.printing a { + text-decoration: none !important; +} +.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { + color: black !important; +} +.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { + color: #008200 !important; +} +.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { + color: blue !important; +} +.syntaxhighlighter.printing .keyword { + color: #006699 !important; + font-weight: bold !important; +} +.syntaxhighlighter.printing .preprocessor { + color: gray !important; +} +.syntaxhighlighter.printing .variable { + color: #aa7700 !important; +} +.syntaxhighlighter.printing .value { + color: #009900 !important; +} +.syntaxhighlighter.printing .functions { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .constants { + color: #0066cc !important; +} +.syntaxhighlighter.printing .script { + font-weight: bold !important; +} +.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { + color: gray !important; +} +.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { + color: red !important; +} +.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { + color: black !important; +} diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/shThemeDataTables.css b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/shThemeDataTables.css new file mode 100644 index 0000000..7e9790a --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/css/shThemeDataTables.css @@ -0,0 +1,128 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter { + background-color: white !important; + font-size: 14px !important; + overflow: visible !important; +} +.syntaxhighlighter .line.alt1 { + background-color: white !important; +} +.syntaxhighlighter .line.alt2 { + background-color: #F8F8F8 !important; +} +.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { + background-color: #e0e0e0 !important; +} +.syntaxhighlighter .line.highlighted.number { + color: black !important; +} +.syntaxhighlighter table caption { + color: black !important; +} +.syntaxhighlighter .gutter { +} +.syntaxhighlighter .gutter div { + color: #5C5C5C !important; + width: 20px !important; +} +.syntaxhighlighter .gutter .line.alt1, .syntaxhighlighter .gutter .line.alt2 { + background-color: white !important; +} +.odd .syntaxhighlighter .gutter .line.alt1, .odd .syntaxhighlighter .gutter .line.alt2 { + background-color: #F2F2F2 !important; +} +.syntaxhighlighter .gutter .line { + border-right: 3px solid #4E6CA3 !important; +} +.syntaxhighlighter .gutter .line.highlighted { + background-color: #4E6CA3 !important; + color: white !important; +} +.syntaxhighlighter.printing .line .content { + border: none !important; +} +.syntaxhighlighter.collapsed { + overflow: visible !important; +} +.syntaxhighlighter.collapsed .toolbar { + color: blue !important; + background: white !important; + border: 1px solid #4E6CA3 !important; +} +.syntaxhighlighter.collapsed .toolbar a { + color: blue !important; +} +.syntaxhighlighter.collapsed .toolbar a:hover { + color: red !important; +} +.syntaxhighlighter .toolbar { + color: white !important; + background: #4E6CA3 !important; + border: none !important; +} +.syntaxhighlighter .toolbar a { + color: white !important; +} +.syntaxhighlighter .toolbar a:hover { + color: black !important; +} +.syntaxhighlighter .plain, .syntaxhighlighter .plain a { + color: black !important; +} +.syntaxhighlighter .comments, .syntaxhighlighter .comments a { + color: #008200 !important; +} +.syntaxhighlighter .string, .syntaxhighlighter .string a { + color: blue !important; +} +.syntaxhighlighter .keyword { + color: #006699 !important; +} +.syntaxhighlighter .preprocessor { + color: gray !important; +} +.syntaxhighlighter .variable { + color: #aa7700 !important; +} +.syntaxhighlighter .value { + color: #009900 !important; +} +.syntaxhighlighter .functions { + color: #ff1493 !important; +} +.syntaxhighlighter .constants { + color: #0066cc !important; +} +.syntaxhighlighter .script { + font-weight: bold !important; + color: #006699 !important; + background-color: none !important; +} +.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { + color: gray !important; +} +.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { + color: red !important; +} + +.syntaxhighlighter .keyword { + font-weight: bold !important; +} diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/arrow.jpg b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/arrow.jpg new file mode 100644 index 0000000..eba85ea Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/arrow.jpg differ diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/arrow.png b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/arrow.png new file mode 100644 index 0000000..08dbbb1 Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/arrow.png differ diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/extended.png b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/extended.png new file mode 100644 index 0000000..5dd01bf Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/images/extended.png differ diff --git a/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/js/doc.js b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/js/doc.js new file mode 100644 index 0000000..932d7cf --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/AutoFill/media/docs/media/js/doc.js @@ -0,0 +1,121 @@ + +(function() { + +var showingNav = true; + +$(document).ready( function () { + var jqNav = $('div.fw_nav'); + jqNav.css('right', ($(window).width() - $('div.fw_container').width()) /2); + + var n = $('div.nav_blocker')[0]; + n.style.height = $(jqNav).outerHeight()+"px"; + n.style.width = ($(jqNav).outerWidth()+20)+"px"; + + SyntaxHighlighter.highlight(); + + $('#private_toggle').click( function () { + if ( $('input[name=show_private]').val() == 0 ) { + $('input[name=show_private]').val( 1 ); + $('#private_label').html('Showing'); + $('.private').css('display', 'block'); + } else { + $('input[name=show_private]').val( 0 ); + $('#private_label').html('Hiding'); + $('.private').css('display', 'none'); + } + fnWriteCookie(); + return false; + } ); + + $('#extended_toggle').click( function () { + if ( $('input[name=show_extended]').val() == 0 ) { + $('input[name=show_extended]').val( 1 ); + $('#extended_label').html('Showing'); + $('.augmented').css('display', 'block'); + } else { + $('input[name=show_extended]').val( 0 ); + $('#extended_label').html('Hiding'); + $('.augmented').css('display', 'none'); + } + fnWriteCookie(); + return false; + } ); + + var savedHeight = $(jqNav).height(); + $('div.fw_nav h2').click( function () { + if ( showingNav ) { + $('div.fw_nav').animate( { + "height": 10, + "opacity": 0.3 + } ); + showingNav = false; + } else { + $('div.fw_nav').animate( { + "height": savedHeight, + "opacity": 1 + } ); + showingNav = true; + } + fnWriteCookie(); + } ); + + var cookie = fnReadCookie( 'SpryMedia_JSDoc' ); + if ( cookie != null ) { + var a = cookie.split('-'); + if ( a[0] == 1 ) { + $('#private_toggle').click(); + } + if ( a[1] == 0 ) { + $('#extended_toggle').click(); + } + if ( a[2] == 'false' ) { + $('div.fw_nav').css('height', 10).css('opacity', 0.3); + showingNav = false; + } + } +} ); + + +function fnWriteCookie() +{ + var sVal = + $('input[name=show_private]').val()+'-'+ + $('input[name=show_extended]').val()+'-'+ + showingNav; + + fnCreateCookie( 'SpryMedia_JSDoc', sVal ); +} + + +function fnCreateCookie( sName, sValue ) +{ + var iDays = 365; + var date = new Date(); + date.setTime( date.getTime()+(iDays*24*60*60*1000) ); + var sExpires = "; expires="+date.toGMTString(); + + document.cookie = sName+"="+sValue+sExpires+"; path=/"; +} + + +function fnReadCookie( sName ) +{ + var sNameEQ = sName + "="; + var sCookieContents = document.cookie.split(';'); + + for( var i=0 ; i)[^>]*$|#([\w\-]+)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Check for digits + rdigit = /\d/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // Has the ready events already been bound? + readyBound = false, + + // The deferred used on DOM ready + readyList, + + // Promise methods + promiseMethods = "then done fail isResolved isRejected promise".split( " " ), + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = "body"; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = (context ? context.ownerDocument || context : document); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; + } + + return jQuery.merge( this, selector ); + + // 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: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if (selector.selector !== undefined) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.5.1", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // 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 + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + (this.selector ? " " : "") + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // 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 ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.done( fn ); + + return this; + }, + + eq: function( i ) { + return i === -1 ? + this.slice( i ) : + this.slice( i, +i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + 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: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // 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 ( length === i ) { + 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({ + noConflict: function( deep ) { + window.$ = _$; + + if ( deep ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // 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, + + // Handle when the DOM is ready + ready: function( wait ) { + // A third-party is pushing the ready event forwards + if ( wait === true ) { + jQuery.readyWait--; + } + + // Make sure that the DOM is not already loaded + if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // 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" ).unbind( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyBound ) { + return; + } + + readyBound = true; + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent("onreadystatechange", DOMContentLoaded); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // 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"; + }, + + // A crude way of determining if an object is a window + isWindow: function( obj ) { + return obj && typeof obj === "object" && "setInterval" in obj; + }, + + isNaN: function( obj ) { + return obj == null || !rdigit.test( obj ) || isNaN( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // 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; + } + + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw msg; + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test(data.replace(rvalidescape, "@") + .replace(rvalidtokens, "]") + .replace(rvalidbraces, "")) ) { + + // Try to use the native JSON parser first + return window.JSON && window.JSON.parse ? + window.JSON.parse( data ) : + (new Function("return " + data))(); + + } else { + jQuery.error( "Invalid JSON: " + data ); + } + }, + + // Cross-browser xml parsing + // (xml & tmp used internally) + parseXML: function( data , xml , tmp ) { + + 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 ); + } + + tmp = xml.documentElement; + + if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) { + jQuery.error( "Invalid XML: " + data ); + } + + return xml; + }, + + noop: function() {}, + + // Evalulates a script in a global context + globalEval: function( data ) { + if ( data && rnotwhite.test(data) ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement, + script = document.createElement( "script" ); + + if ( jQuery.support.scriptEval() ) { + script.appendChild( document.createTextNode( data ) ); + } else { + script.text = data; + } + + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709). + head.insertBefore( script, head.firstChild ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction(object); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( var value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // The extra typeof function check is to prevent crashes + // in Safari 2 (See: #3039) + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type(array); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var ret = [], value; + + // Go through the array, translating each of the items to their + // new value (or values). + for ( var i = 0, length = elems.length; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + proxy: function( fn, proxy, thisObject ) { + if ( arguments.length === 2 ) { + if ( typeof proxy === "string" ) { + thisObject = fn; + fn = thisObject[ proxy ]; + proxy = undefined; + + } else if ( proxy && !jQuery.isFunction( proxy ) ) { + thisObject = proxy; + proxy = undefined; + } + } + + if ( !proxy && fn ) { + proxy = function() { + return fn.apply( thisObject || this, arguments ); + }; + } + + // Set the guid of unique handler to the same of original handler, so it can be removed + if ( fn ) { + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + } + + // So proxy can be declared as an argument + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can be optionally by executed if its a function + access: function( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + jQuery.access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : undefined; + }, + + now: function() { + return (new Date()).getTime(); + }, + + // Create a simple deferred (one callbacks list) + _Deferred: function() { + var // callbacks list + callbacks = [], + // stored [ context , args ] + fired, + // to avoid firing when already doing so + firing, + // flag to know if the deferred has been cancelled + cancelled, + // the deferred itself + deferred = { + + // done( f1, f2, ...) + done: function() { + if ( !cancelled ) { + var args = arguments, + i, + length, + elem, + type, + _fired; + if ( fired ) { + _fired = fired; + fired = 0; + } + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + deferred.done.apply( deferred, elem ); + } else if ( type === "function" ) { + callbacks.push( elem ); + } + } + if ( _fired ) { + deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); + } + } + return this; + }, + + // resolve with given context and args + resolveWith: function( context, args ) { + if ( !cancelled && !fired && !firing ) { + firing = 1; + try { + while( callbacks[ 0 ] ) { + callbacks.shift().apply( context, args ); + } + } + // We have to add a catch block for + // IE prior to 8 or else the finally + // block will never get executed + catch (e) { + throw e; + } + finally { + fired = [ context, args ]; + firing = 0; + } + } + return this; + }, + + // resolve with this as context and given arguments + resolve: function() { + deferred.resolveWith( jQuery.isFunction( this.promise ) ? this.promise() : this, arguments ); + return this; + }, + + // Has this deferred been resolved? + isResolved: function() { + return !!( firing || fired ); + }, + + // Cancel + cancel: function() { + cancelled = 1; + callbacks = []; + return this; + } + }; + + return deferred; + }, + + // Full fledged deferred (two callbacks list) + Deferred: function( func ) { + var deferred = jQuery._Deferred(), + failDeferred = jQuery._Deferred(), + promise; + // Add errorDeferred methods, then and promise + jQuery.extend( deferred, { + then: function( doneCallbacks, failCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ); + return this; + }, + fail: failDeferred.done, + rejectWith: failDeferred.resolveWith, + reject: failDeferred.resolve, + isRejected: failDeferred.isResolved, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + if ( promise ) { + return promise; + } + promise = obj = {}; + } + var i = promiseMethods.length; + while( i-- ) { + obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; + } + return obj; + } + } ); + // Make sure only one callback list will be used + deferred.done( failDeferred.cancel ).fail( deferred.cancel ); + // Unexpose cancel + delete deferred.cancel; + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + return deferred; + }, + + // Deferred helper + when: function( object ) { + var lastIndex = arguments.length, + deferred = lastIndex <= 1 && object && jQuery.isFunction( object.promise ) ? + object : + jQuery.Deferred(), + promise = deferred.promise(); + + if ( lastIndex > 1 ) { + var array = slice.call( arguments, 0 ), + count = lastIndex, + iCallback = function( index ) { + return function( value ) { + array[ index ] = arguments.length > 1 ? slice.call( arguments, 0 ) : value; + if ( !( --count ) ) { + deferred.resolveWith( promise, array ); + } + }; + }; + while( ( lastIndex-- ) ) { + object = array[ lastIndex ]; + if ( object && jQuery.isFunction( object.promise ) ) { + object.promise().then( iCallback(lastIndex), deferred.reject ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( promise, array ); + } + } else if ( deferred !== object ) { + deferred.resolve( object ); + } + return promise; + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySubclass( selector, context ) { + return new jQuerySubclass.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySubclass, this ); + jQuerySubclass.superclass = this; + jQuerySubclass.fn = jQuerySubclass.prototype = this(); + jQuerySubclass.fn.constructor = jQuerySubclass; + jQuerySubclass.subclass = this.subclass; + jQuerySubclass.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySubclass) ) { + context = jQuerySubclass(context); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass ); + }; + jQuerySubclass.fn.init.prototype = jQuerySubclass.fn; + var rootjQuerySubclass = jQuerySubclass(document); + return jQuerySubclass; + }, + + browser: {} +}); + +// Create readyList deferred +readyList = jQuery._Deferred(); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +if ( indexOf ) { + jQuery.inArray = function( elem, array ) { + return indexOf.call( array, elem ); + }; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +// Expose jQuery to the global object +return jQuery; + +})(); + + +(function() { + + jQuery.support = {}; + + var div = document.createElement("div"); + + div.style.display = "none"; + div.innerHTML = "
a"; + + var all = div.getElementsByTagName("*"), + a = div.getElementsByTagName("a")[0], + select = document.createElement("select"), + opt = select.appendChild( document.createElement("option") ), + input = div.getElementsByTagName("input")[0]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return; + } + + jQuery.support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: div.firstChild.nodeType === 3, + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText insted) + style: /red/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: a.getAttribute("href") === "/a", + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55$/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: input.value === "on", + + // 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) + optSelected: opt.selected, + + // Will be defined later + deleteExpando: true, + optDisabled: false, + checkClone: false, + noCloneEvent: true, + noCloneChecked: true, + boxModel: null, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableHiddenOffsets: true + }; + + input.checked = true; + jQuery.support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as diabled) + select.disabled = true; + jQuery.support.optDisabled = !opt.disabled; + + var _scriptEval = null; + jQuery.support.scriptEval = function() { + if ( _scriptEval === null ) { + var root = document.documentElement, + script = document.createElement("script"), + id = "script" + jQuery.now(); + + try { + script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); + } catch(e) {} + + root.insertBefore( script, root.firstChild ); + + // Make sure that the execution of code works by injecting a script + // tag with appendChild/createTextNode + // (IE doesn't support this, fails, and uses .text instead) + if ( window[ id ] ) { + _scriptEval = true; + delete window[ id ]; + } else { + _scriptEval = false; + } + + root.removeChild( script ); + // release memory in IE + root = script = id = null; + } + + return _scriptEval; + }; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + + } catch(e) { + jQuery.support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent("onclick", function click() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + jQuery.support.noCloneEvent = false; + div.detachEvent("onclick", click); + }); + div.cloneNode(true).fireEvent("onclick"); + } + + div = document.createElement("div"); + div.innerHTML = ""; + + var fragment = document.createDocumentFragment(); + fragment.appendChild( div.firstChild ); + + // WebKit doesn't clone checked state correctly in fragments + jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; + + // Figure out if the W3C box model works as expected + // document.body must exist before we can do this + jQuery(function() { + var div = document.createElement("div"), + body = document.getElementsByTagName("body")[0]; + + // Frameset documents with no body should not run this code + if ( !body ) { + return; + } + + div.style.width = div.style.paddingLeft = "1px"; + body.appendChild( div ); + jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; + + if ( "zoom" in div.style ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2; + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
"; + jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2; + } + + div.innerHTML = "
t
"; + var tds = div.getElementsByTagName("td"); + + // 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). + // (only IE 8 fails this test) + jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0; + + tds[0].style.display = ""; + tds[1].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE < 8 fail this test) + jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0; + div.innerHTML = ""; + + body.removeChild( div ).style.display = "none"; + div = tds = null; + }); + + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + var eventSupported = function( eventName ) { + var el = document.createElement("div"); + eventName = "on" + eventName; + + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( !el.attachEvent ) { + return true; + } + + var isSupported = (eventName in el); + if ( !isSupported ) { + el.setAttribute(eventName, "return;"); + isSupported = typeof el[eventName] === "function"; + } + el = null; + + return isSupported; + }; + + jQuery.support.submitBubbles = eventSupported("submit"); + jQuery.support.changeBubbles = eventSupported("change"); + + // release memory in IE + div = all = a = null; +})(); + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache, + + // 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[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; + + // 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 || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) { + 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 ) { + elem[ jQuery.expando ] = id = ++jQuery.uuid; + } else { + id = jQuery.expando; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].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 ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); + } else { + cache[ id ] = jQuery.extend(cache[ id ], name); + } + } + + thisCache = cache[ id ]; + + // Internal jQuery data is stored in a separate object inside the object's data + // cache in order to avoid key collisions between internal data and user-defined + // data + if ( pvt ) { + if ( !thisCache[ internalKey ] ) { + thisCache[ internalKey ] = {}; + } + + thisCache = thisCache[ internalKey ]; + } + + if ( data !== undefined ) { + thisCache[ name ] = data; + } + + // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should + // not attempt to inspect the internal events object using jQuery.data, as this + // internal data object is undocumented and subject to change. + if ( name === "events" && !thisCache[name] ) { + return thisCache[ internalKey ] && thisCache[ internalKey ].events; + } + + return getByName ? thisCache[ name ] : thisCache; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + 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 ) { + var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; + + if ( thisCache ) { + delete thisCache[ name ]; + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !isEmptyDataObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( pvt ) { + delete cache[ id ][ internalKey ]; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + var internalCache = cache[ id ][ internalKey ]; + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + if ( jQuery.support.deleteExpando || cache != window ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the entire user cache at once because it's faster than + // iterating through each key, but we need to continue to persist internal + // data if it existed + if ( internalCache ) { + cache[ id ] = {}; + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + + cache[ id ][ internalKey ] = internalCache; + + // Otherwise, we need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + } else if ( isNode ) { + // 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 ( jQuery.support.deleteExpando ) { + delete elem[ jQuery.expando ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( jQuery.expando ); + } else { + elem[ jQuery.expando ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var data = null; + + if ( typeof key === "undefined" ) { + if ( this.length ) { + data = jQuery.data( this[0] ); + + if ( this[0].nodeType === 1 ) { + var attr = this[0].attributes, name; + for ( var i = 0, l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = name.substr( 5 ); + dataAttr( this[0], name, data[ name ] ); + } + } + } + } + + return data; + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + // Try to fetch any internally stored data first + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + data = dataAttr( this[0], key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + + } else { + return this.each(function() { + var $this = jQuery( this ), + args = [ parts[0], value ]; + + $this.triggerHandler( "setData" + parts[1] + "!", args ); + jQuery.data( this, key, value ); + $this.triggerHandler( "changeData" + parts[1] + "!", args ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +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 ) { + data = elem.getAttribute( "data-" + key ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + !jQuery.isNaN( data ) ? parseFloat( 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; +} + +// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON +// property to be considered empty objects; this property always exists in +// order to make sure JSON.stringify does not expose internal metadata +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +jQuery.extend({ + queue: function( elem, type, data ) { + if ( !elem ) { + return; + } + + type = (type || "fx") + "queue"; + var q = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( !data ) { + return q || []; + } + + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + + } else { + q.push( data ); + } + + return q; + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(); + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift("inprogress"); + } + + fn.call(elem, function() { + jQuery.dequeue(elem, type); + }); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue", true ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function( i ) { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + type = type || "fx"; + + return this.queue( type, function() { + var elem = this; + setTimeout(function() { + jQuery.dequeue( elem, type ); + }, time ); + }); + }, + + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspaces = /\s+/, + rreturn = /\r/g, + rspecialurl = /^(?:href|src|style)$/, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rradiocheck = /^(?:radio|checkbox)$/i; + +jQuery.props = { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" +}; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name, fn ) { + return this.each(function(){ + jQuery.attr( this, name, "" ); + if ( this.nodeType === 1 ) { + this.removeAttribute( name ); + } + }); + }, + + addClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.addClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( value && typeof value === "string" ) { + var classNames = (value || "").split( rspaces ); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className ) { + elem.className = value; + + } else { + var className = " " + elem.className + " ", + setClass = elem.className; + + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { + setClass += " " + classNames[c]; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.removeClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + var classNames = (value || "").split( rspaces ); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + var className = (" " + elem.className + " ").replace(rclass, " "); + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[c] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this); + self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspaces ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " "; + for ( var i = 0, l = this.length; i < l; i++ ) { + if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + if ( !arguments.length ) { + var elem = this[0]; + + if ( elem ) { + if ( jQuery.nodeName( elem, "option" ) ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.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 ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + } + + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { + return elem.getAttribute("value") === null ? "on" : elem.value; + } + + // Everything else, we just grab the value + return (elem.value || "").replace(rreturn, ""); + + } + + return undefined; + } + + var isFunction = jQuery.isFunction(value); + + return this.each(function(i) { + var self = jQuery(this), val = value; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call(this, i, self.val()); + } + + // 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 + ""; + }); + } + + if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { + this.checked = jQuery.inArray( self.val(), val ) >= 0; + + } else if ( jQuery.nodeName( this, "select" ) ) { + var values = jQuery.makeArray(val); + + jQuery( "option", this ).each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + this.selectedIndex = -1; + } + + } else { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) { + return undefined; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery(elem)[name](value); + } + + var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), + // Whether we are setting (or getting) + set = value !== undefined; + + // Try to normalize/fix the name + name = notxml && jQuery.props[ name ] || name; + + // Only do all the following if this is a node (faster for style) + if ( elem.nodeType === 1 ) { + // These attributes require special treatment + var special = rspecialurl.test( name ); + + // Safari mis-reports the default selected property of an option + // Accessing the parent's selectedIndex property fixes it + if ( name === "selected" && !jQuery.support.optSelected ) { + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + + // If applicable, access the attribute via the DOM 0 way + // 'in' checks fail in Blackberry 4.7 #6931 + if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) { + if ( set ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } + + if ( value === null ) { + if ( elem.nodeType === 1 ) { + elem.removeAttribute( name ); + } + + } else { + elem[ name ] = value; + } + } + + // browsers index elements by id/name on forms, give priority to attributes. + if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { + return elem.getAttributeNode( name ).nodeValue; + } + + // 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/ + if ( name === "tabIndex" ) { + var attributeNode = elem.getAttributeNode( "tabIndex" ); + + return attributeNode && attributeNode.specified ? + attributeNode.value : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + + return elem[ name ]; + } + + if ( !jQuery.support.style && notxml && name === "style" ) { + if ( set ) { + elem.style.cssText = "" + value; + } + + return elem.style.cssText; + } + + if ( set ) { + // convert the value to a string (all browsers do this but IE) see #1070 + elem.setAttribute( name, "" + value ); + } + + // Ensure that missing attributes return undefined + // Blackberry 4.7 returns "" from getAttribute #6938 + if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) { + return undefined; + } + + var attr = !jQuery.support.hrefNormalized && notxml && special ? + // Some attributes require a special call on IE + elem.getAttribute( name, 2 ) : + elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return attr === null ? undefined : attr; + } + // Handle everything which isn't a DOM element node + if ( set ) { + elem[ name ] = value; + } + return elem[ name ]; + } +}); + + + + +var rnamespaces = /\.(.*)$/, + rformElems = /^(?:textarea|input|select)$/i, + rperiod = /\./g, + rspace = / /g, + rescape = /[^\w\s.|`]/g, + fcleanup = function( nm ) { + return nm.replace(rescape, "\\$&"); + }; + +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code originated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + add: function( elem, types, handler, data ) { + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // TODO :: Use a try/catch until it's safe to pull this out (likely 1.6) + // Minor release fix for bug #8018 + try { + // For whatever reason, IE has trouble passing the window object + // around, causing it to be cloned in the process + if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) { + elem = window; + } + } + catch ( e ) {} + + if ( handler === false ) { + handler = returnFalse; + } else if ( !handler ) { + // Fixes bug #7229. Fix recommended by jdalton + return; + } + + var handleObjIn, handleObj; + + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure + var elemData = jQuery._data( elem ); + + // If no elemData is found then we must be trying to bind to one of the + // banned noData elements + if ( !elemData ) { + return; + } + + var events = elemData.events, + eventHandle = elemData.handle; + + if ( !events ) { + elemData.events = events = {}; + } + + if ( !eventHandle ) { + elemData.handle = eventHandle = function() { + // Handle the second event of a trigger and when + // an event is called after a page has unloaded + return typeof jQuery !== "undefined" && !jQuery.event.triggered ? + jQuery.event.handle.apply( eventHandle.elem, arguments ) : + undefined; + }; + } + + // Add elem as a property of the handle function + // This is to prevent a memory leak with non-native events in IE. + eventHandle.elem = elem; + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = types.split(" "); + + var type, i = 0, namespaces; + + while ( (type = types[ i++ ]) ) { + handleObj = handleObjIn ? + jQuery.extend({}, handleObjIn) : + { handler: handler, data: data }; + + // Namespaced event handlers + if ( type.indexOf(".") > -1 ) { + namespaces = type.split("."); + type = namespaces.shift(); + handleObj.namespace = namespaces.slice(0).sort().join("."); + + } else { + namespaces = []; + handleObj.namespace = ""; + } + + handleObj.type = type; + if ( !handleObj.guid ) { + handleObj.guid = handler.guid; + } + + // Get the current list of functions bound to this event + var handlers = events[ type ], + special = jQuery.event.special[ type ] || {}; + + // Init the event handler queue + if ( !handlers ) { + handlers = events[ type ] = []; + + // Check for a special event handler + // 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 the function to the element's handler list + handlers.push( handleObj ); + + // Keep track of which events have been used, for global triggering + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, pos ) { + // don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + if ( handler === false ) { + handler = returnFalse; + } + + var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + events = elemData && elemData.events; + + if ( !elemData || !events ) { + return; + } + + // types is actually an event object here + if ( types && types.type ) { + handler = types.handler; + types = types.type; + } + + // Unbind all events for the element + if ( !types || typeof types === "string" && types.charAt(0) === "." ) { + types = types || ""; + + for ( type in events ) { + jQuery.event.remove( elem, type + types ); + } + + return; + } + + // Handle multiple events separated by a space + // jQuery(...).unbind("mouseover mouseout", fn); + types = types.split(" "); + + while ( (type = types[ i++ ]) ) { + origType = type; + handleObj = null; + all = type.indexOf(".") < 0; + namespaces = []; + + if ( !all ) { + // Namespaced event handlers + namespaces = type.split("."); + type = namespaces.shift(); + + namespace = new RegExp("(^|\\.)" + + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + eventType = events[ type ]; + + if ( !eventType ) { + continue; + } + + if ( !handler ) { + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( all || namespace.test( handleObj.namespace ) ) { + jQuery.event.remove( elem, origType, handleObj.handler, j ); + eventType.splice( j--, 1 ); + } + } + + continue; + } + + special = jQuery.event.special[ type ] || {}; + + for ( j = pos || 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( handler.guid === handleObj.guid ) { + // remove the given handler for the given type + if ( all || namespace.test( handleObj.namespace ) ) { + if ( pos == null ) { + eventType.splice( j--, 1 ); + } + + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + + if ( pos != null ) { + break; + } + } + } + + // remove generic event handler if no more handlers exist + if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + ret = null; + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + var handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + delete elemData.events; + delete elemData.handle; + + if ( jQuery.isEmptyObject( elemData ) ) { + jQuery.removeData( elem, undefined, true ); + } + } + }, + + // bubbling is internal + trigger: function( event, data, elem /*, bubbling */ ) { + // Event object or event type + var type = event.type || event, + bubbling = arguments[3]; + + if ( !bubbling ) { + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + jQuery.extend( jQuery.Event(type), event ) : + // Just the event type (string) + jQuery.Event(type); + + if ( type.indexOf("!") >= 0 ) { + event.type = type = type.slice(0, -1); + event.exclusive = true; + } + + // Handle a global trigger + if ( !elem ) { + // Don't bubble custom events when global (to avoid too much overhead) + event.stopPropagation(); + + // Only trigger if we've ever bound an event for it + if ( jQuery.event.global[ type ] ) { + // XXX This code smells terrible. event.js should not be directly + // inspecting the data cache + jQuery.each( jQuery.cache, function() { + // internalKey variable is just used to make it easier to find + // and potentially change this stuff later; currently it just + // points to jQuery.expando + var internalKey = jQuery.expando, + internalCache = this[ internalKey ]; + if ( internalCache && internalCache.events && internalCache.events[ type ] ) { + jQuery.event.trigger( event, data, internalCache.handle.elem ); + } + }); + } + } + + // Handle triggering a single element + + // don't do events on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { + return undefined; + } + + // Clean up in case it is reused + event.result = undefined; + event.target = elem; + + // Clone the incoming data, if any + data = jQuery.makeArray( data ); + data.unshift( event ); + } + + event.currentTarget = elem; + + // Trigger the event, it is assumed that "handle" is a function + var handle = jQuery._data( elem, "handle" ); + + if ( handle ) { + handle.apply( elem, data ); + } + + var parent = elem.parentNode || elem.ownerDocument; + + // Trigger an inline bound script + try { + if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { + if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { + event.result = false; + event.preventDefault(); + } + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (inlineError) {} + + if ( !event.isPropagationStopped() && parent ) { + jQuery.event.trigger( event, data, parent, true ); + + } else if ( !event.isDefaultPrevented() ) { + var old, + target = event.target, + targetType = type.replace( rnamespaces, "" ), + isClick = jQuery.nodeName( target, "a" ) && targetType === "click", + special = jQuery.event.special[ targetType ] || {}; + + if ( (!special._default || special._default.call( elem, event ) === false) && + !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { + + try { + if ( target[ targetType ] ) { + // Make sure that we don't accidentally re-trigger the onFOO events + old = target[ "on" + targetType ]; + + if ( old ) { + target[ "on" + targetType ] = null; + } + + jQuery.event.triggered = true; + target[ targetType ](); + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (triggerError) {} + + if ( old ) { + target[ "on" + targetType ] = old; + } + + jQuery.event.triggered = false; + } + } + }, + + handle: function( event ) { + var all, handlers, namespaces, namespace_re, events, + namespace_sort = [], + args = jQuery.makeArray( arguments ); + + event = args[0] = jQuery.event.fix( event || window.event ); + event.currentTarget = this; + + // Namespaced event handlers + all = event.type.indexOf(".") < 0 && !event.exclusive; + + if ( !all ) { + namespaces = event.type.split("."); + event.type = namespaces.shift(); + namespace_sort = namespaces.slice(0).sort(); + namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + event.namespace = event.namespace || namespace_sort.join("."); + + events = jQuery._data(this, "events"); + + handlers = (events || {})[ event.type ]; + + if ( events && handlers ) { + // Clone the handlers to prevent manipulation + handlers = handlers.slice(0); + + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; + + // Filter the functions by class + if ( all || namespace_re.test( handleObj.namespace ) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handleObj.handler; + event.data = handleObj.data; + event.handleObj = handleObj; + + var ret = handleObj.handler.apply( this, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + } + + return event.result; + }, + + props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // store a copy of the original event object + // and "clone" to set read-only properties + var originalEvent = event; + event = jQuery.Event( originalEvent ); + + for ( var i = this.props.length, prop; i; ) { + prop = this.props[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary + if ( !event.target ) { + // Fixes #1925 where srcElement might not be defined either + event.target = event.srcElement || document; + } + + // check if target is a textnode (safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) { + event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; + } + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var doc = document.documentElement, + body = document.body; + + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); + } + + // Add which for key events + if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { + event.which = event.charCode != null ? event.charCode : event.keyCode; + } + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) { + event.metaKey = event.ctrlKey; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button !== undefined ) { + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + } + + return event; + }, + + // Deprecated, use jQuery.guid instead + guid: 1E8, + + // Deprecated, use jQuery.proxy instead + proxy: jQuery.proxy, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady, + teardown: jQuery.noop + }, + + live: { + add: function( handleObj ) { + jQuery.event.add( this, + liveConvert( handleObj.origType, handleObj.selector ), + jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); + }, + + remove: function( handleObj ) { + jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); + } + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src ) { + // Allow instantiation without the 'new' keyword + if ( !this.preventDefault ) { + return new jQuery.Event( src ); + } + + // 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.returnValue === false || + src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // timeStamp is buggy for some events on Firefox(#3843) + // So we won't rely on the native value + this.timeStamp = jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return 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 = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Checks if an event happened on an element within another element +// Used in jQuery.event.special.mouseenter and mouseleave handlers +var withinElement = function( event ) { + // Check if mouse(over|out) are still within the same parent element + var parent = event.relatedTarget; + + // Firefox sometimes assigns relatedTarget a XUL element + // which we cannot access the parentNode property of + try { + + // Chrome does something similar, the parentNode property + // can be accessed but is null. + if ( parent !== document && !parent.parentNode ) { + return; + } + // Traverse up the tree + while ( parent && parent !== this ) { + parent = parent.parentNode; + } + + if ( parent !== this ) { + // set the correct event type + event.type = event.data; + + // handle event if we actually just moused on to a non sub-element + jQuery.event.handle.apply( this, arguments ); + } + + // assuming we've left the element since we most likely mousedover a xul element + } catch(e) { } +}, + +// In case of event delegation, we only need to rename the event.type, +// liveHandler will take care of the rest. +delegate = function( event ) { + event.type = event.data; + jQuery.event.handle.apply( this, arguments ); +}; + +// Create mouseenter and mouseleave events +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + setup: function( data ) { + jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); + }, + teardown: function( data ) { + jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + } + }; +}); + +// submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function( data, namespaces ) { + if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) { + jQuery.event.add(this, "click.specialSubmit", function( e ) { + var elem = e.target, + type = elem.type; + + if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { + trigger( "submit", this, arguments ); + } + }); + + jQuery.event.add(this, "keypress.specialSubmit", function( e ) { + var elem = e.target, + type = elem.type; + + if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { + trigger( "submit", this, arguments ); + } + }); + + } else { + return false; + } + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialSubmit" ); + } + }; + +} + +// change delegation, happens here so we have bind. +if ( !jQuery.support.changeBubbles ) { + + var changeFilters, + + getVal = function( elem ) { + var type = elem.type, val = elem.value; + + if ( type === "radio" || type === "checkbox" ) { + val = elem.checked; + + } else if ( type === "select-multiple" ) { + val = elem.selectedIndex > -1 ? + jQuery.map( elem.options, function( elem ) { + return elem.selected; + }).join("-") : + ""; + + } else if ( elem.nodeName.toLowerCase() === "select" ) { + val = elem.selectedIndex; + } + + return val; + }, + + testChange = function testChange( e ) { + var elem = e.target, data, val; + + if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { + return; + } + + data = jQuery._data( elem, "_change_data" ); + val = getVal(elem); + + // the current data will be also retrieved by beforeactivate + if ( e.type !== "focusout" || elem.type !== "radio" ) { + jQuery._data( elem, "_change_data", val ); + } + + if ( data === undefined || val === data ) { + return; + } + + if ( data != null || val ) { + e.type = "change"; + e.liveFired = undefined; + jQuery.event.trigger( e, arguments[1], elem ); + } + }; + + jQuery.event.special.change = { + filters: { + focusout: testChange, + + beforedeactivate: testChange, + + click: function( e ) { + var elem = e.target, type = elem.type; + + if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { + testChange.call( this, e ); + } + }, + + // Change has to be called before submit + // Keydown will be called before keypress, which is used in submit-event delegation + keydown: function( e ) { + var elem = e.target, type = elem.type; + + if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || + (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || + type === "select-multiple" ) { + testChange.call( this, e ); + } + }, + + // Beforeactivate happens also before the previous element is blurred + // with this event you can't trigger a change event, but you can store + // information + beforeactivate: function( e ) { + var elem = e.target; + jQuery._data( elem, "_change_data", getVal(elem) ); + } + }, + + setup: function( data, namespaces ) { + if ( this.type === "file" ) { + return false; + } + + for ( var type in changeFilters ) { + jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); + } + + return rformElems.test( this.nodeName ); + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialChange" ); + + return rformElems.test( this.nodeName ); + } + }; + + changeFilters = jQuery.event.special.change.filters; + + // Handle when the input is .focus()'d + changeFilters.focus = changeFilters.beforeactivate; +} + +function trigger( type, elem, args ) { + // 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. + // Don't pass args or remember liveFired; they apply to the donor event. + var event = jQuery.extend( {}, args[ 0 ] ); + event.type = type; + event.originalEvent = {}; + event.liveFired = undefined; + jQuery.event.handle.call( elem, event ); + if ( event.isDefaultPrevented() ) { + args[ 0 ].preventDefault(); + } +} + +// Create "bubbling" focus and blur events +if ( document.addEventListener ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + jQuery.event.special[ fix ] = { + setup: function() { + this.addEventListener( orig, handler, true ); + }, + teardown: function() { + this.removeEventListener( orig, handler, true ); + } + }; + + function handler( e ) { + e = jQuery.event.fix( e ); + e.type = fix; + return jQuery.event.handle.call( this, e ); + } + }); +} + +jQuery.each(["bind", "one"], function( i, name ) { + jQuery.fn[ name ] = function( type, data, fn ) { + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this[ name ](key, data, type[key], fn); + } + return this; + } + + if ( jQuery.isFunction( data ) || data === false ) { + fn = data; + data = undefined; + } + + var handler = name === "one" ? jQuery.proxy( fn, function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }) : fn; + + if ( type === "unload" && name !== "one" ) { + this.one( type, data, fn ); + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.add( this[i], type, handler, data ); + } + } + + return this; + }; +}); + +jQuery.fn.extend({ + unbind: function( type, fn ) { + // Handle object literals + if ( typeof type === "object" && !type.preventDefault ) { + for ( var key in type ) { + this.unbind(key, type[key]); + } + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.remove( this[i], type, fn ); + } + } + + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.live( types, data, fn, selector ); + }, + + undelegate: function( selector, types, fn ) { + if ( arguments.length === 0 ) { + return this.unbind( "live" ); + + } else { + return this.die( types, null, fn, selector ); + } + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + + triggerHandler: function( type, data ) { + if ( this[0] ) { + var event = jQuery.Event( type ); + event.preventDefault(); + event.stopPropagation(); + jQuery.event.trigger( event, data, this[0] ); + return event.result; + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + i = 1; + + // link all the functions, so any of them can unbind this click handler + while ( i < args.length ) { + jQuery.proxy( fn, args[ i++ ] ); + } + + return this.click( jQuery.proxy( fn, function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + })); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +var liveMap = { + focus: "focusin", + blur: "focusout", + mouseenter: "mouseover", + mouseleave: "mouseout" +}; + +jQuery.each(["live", "die"], function( i, name ) { + jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { + var type, i = 0, match, namespaces, preType, + selector = origSelector || this.selector, + context = origSelector ? this : jQuery( this.context ); + + if ( typeof types === "object" && !types.preventDefault ) { + for ( var key in types ) { + context[ name ]( key, data, types[key], selector ); + } + + return this; + } + + if ( jQuery.isFunction( data ) ) { + fn = data; + data = undefined; + } + + types = (types || "").split(" "); + + while ( (type = types[ i++ ]) != null ) { + match = rnamespaces.exec( type ); + namespaces = ""; + + if ( match ) { + namespaces = match[0]; + type = type.replace( rnamespaces, "" ); + } + + if ( type === "hover" ) { + types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); + continue; + } + + preType = type; + + if ( type === "focus" || type === "blur" ) { + types.push( liveMap[ type ] + namespaces ); + type = type + namespaces; + + } else { + type = (liveMap[ type ] || type) + namespaces; + } + + if ( name === "live" ) { + // bind live handler + for ( var j = 0, l = context.length; j < l; j++ ) { + jQuery.event.add( context[j], "live." + liveConvert( type, selector ), + { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); + } + + } else { + // unbind live handler + context.unbind( "live." + liveConvert( type, selector ), fn ); + } + } + + return this; + }; +}); + +function liveHandler( event ) { + var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, + elems = [], + selectors = [], + events = jQuery._data( this, "events" ); + + // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) + if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { + return; + } + + if ( event.namespace ) { + namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + event.liveFired = this; + + var live = events.live.slice(0); + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { + selectors.push( handleObj.selector ); + + } else { + live.splice( j--, 1 ); + } + } + + match = jQuery( event.target ).closest( selectors, event.currentTarget ); + + for ( i = 0, l = match.length; i < l; i++ ) { + close = match[i]; + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { + elem = close.elem; + related = null; + + // Those two events require additional checking + if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { + event.type = handleObj.preType; + related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; + } + + if ( !related || related !== elem ) { + elems.push({ elem: elem, handleObj: handleObj, level: close.level }); + } + } + } + } + + for ( i = 0, l = elems.length; i < l; i++ ) { + match = elems[i]; + + if ( maxLevel && match.level > maxLevel ) { + break; + } + + event.currentTarget = match.elem; + event.data = match.handleObj.data; + event.handleObj = match.handleObj; + + ret = match.handleObj.origHandler.apply( match.elem, arguments ); + + if ( ret === false || event.isPropagationStopped() ) { + maxLevel = match.level; + + if ( ret === false ) { + stop = false; + } + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + + return stop; +} + +function liveConvert( type, selector ) { + return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&"); +} + +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").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.bind( name, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } +}); + + +/*! + * 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/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[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; + + // Reset the position of the chunker regexp (start from head) + 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 { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + 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; + } + } + } + + // Improper expression + 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]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + 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, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + 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]; + } + + // Handle if an un-quoted value was used + 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 we're dealing with a complex expression, or a simple one + 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 ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + 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 ) { + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return "text" === elem.getAttribute( 'type' ); + }, + radio: function( elem ) { + return "radio" === elem.type; + }, + + checkbox: function( elem ) { + return "checkbox" === elem.type; + }, + + file: function( elem ) { + return "file" === elem.type; + }, + password: function( elem ) { + return "password" === elem.type; + }, + + submit: function( elem ) { + return "submit" === elem.type; + }, + + image: function( elem ) { + return "image" === elem.type; + }, + + reset: function( elem ) { + return "reset" === elem.type; + }, + + button: function( elem ) { + return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + } + }, + 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; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} 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 ) { + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // If the nodes are siblings (or identical) we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + 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; + }; +} + +// Utility function for retreiving the text value of an array of DOM nodes +Sizzle.getText = function( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += Sizzle.getText( elem.childNodes ); + } + } + + return ret; +}; + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + 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 ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + 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; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

"; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // 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[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // 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 + } 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 ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector, + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + if ( matches ) { + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + return matches.call( node, expr ); + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
"; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + 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]); + } + }; + + // release memory in IE + 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 ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + 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; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + 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 ); +}; + +// EXPOSE +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.POS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var ret = this.pushStack( "", "find", selector ), + length = 0; + + for ( var i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( var n = length; n < ret.length; n++ ) { + for ( var r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && jQuery.filter( selector, this ).length > 0; + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + if ( jQuery.isArray( selectors ) ) { + var match, selector, + matches = {}, + level = 1; + + if ( cur && selectors.length ) { + for ( i = 0, l = selectors.length; i < l; i++ ) { + selector = selectors[i]; + + if ( !matches[selector] ) { + matches[selector] = jQuery.expr.match.POS.test( selector ) ? + jQuery( selector, context || this.context ) : + selector; + } + } + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( selector in matches ) { + match = matches[selector]; + + if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { + ret.push({ selector: selector, elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + } + + return ret; + } + + var pos = POS.test( selectors ) ? + jQuery( selectors, context || this.context ) : null; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique(ret) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + if ( !elem || typeof elem === "string" ) { + return jQuery.inArray( this[0], + // If it receives a string, the selector is used + // If it receives nothing, the siblings are used + elem ? jQuery( elem ) : this.parent().children() ); + } + // 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 ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +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 jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "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.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ), + // The variable 'args' was introduced in + // https://github.com/jquery/jquery/commit/52a0238 + // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. + // http://code.google.com/p/v8/issues/detail?id=1050 + args = slice.call(arguments); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, args.join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + 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; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return (elem === qualifier) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + }); +} + + + + +var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /", "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and + + + + + +
+
+ AutoFill example with scrolling +
+ +

Preamble

+

+ When dragging an AutoFill handle, the table (if DataTables scrolling is enabled) or the window will be automatically scrolled, as you approach the edge of the scrolling component. The example below shows the effect with DataTables scrolling (and also window if needed). +

+ + + +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable({
+		"sScrollY": 200,
+		"bScrollCollapse": true,
+		"bPaginate": false
+	});
+	new AutoFill( oTable );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/alt_insert.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/alt_insert.html new file mode 100755 index 0000000..4f04fa4 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/alt_insert.html @@ -0,0 +1,495 @@ + + + + + + + ColReorder example + + + + + + + +
+
+ ColReorder example with alternative insert styling +
+ +

Preamble

+

Using CSS it is relatively easy to modify the insert bar to suit your web-site. This + example shows how an arrow can be used to show the insert point rather than the straight + bar used in the other examples.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sDom": 'Rlfrtip'
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/col_filter.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/col_filter.html new file mode 100755 index 0000000..eec910c --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/col_filter.html @@ -0,0 +1,588 @@ + + + + + + + ColReorder example + + + + + + + + +
+
+ ColReorder example with individual column filtering +
+ +

Preamble

+

This example of how to use ColReorder shows quite a number of different interesting + properties. Firstly, there is integration with ColVis, then there is the fact that there + is more than one row in the table header with the second being used for the input + elements, and finally of course the filtering itself. Note that it is important to use + the _fnVisibleToColumnIndex() internal function to calculate which column index should + be given to fnFilter (or you could employ your own methods).

+

Please note that this demo requires DataTables 1.8 or later.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready(function() {
+	var oTable;
+	
+	/* Add the events etc before DataTables hides a column */
+	$("thead input").keyup( function () {
+		/* Filter on the column (the index) of this element */
+		oTable.fnFilter( this.value, oTable.oApi._fnVisibleToColumnIndex( 
+			oTable.fnSettings(), $("thead input").index(this) ) );
+	} );
+	
+	/*
+	 * Support functions to provide a little bit of 'user friendlyness' to the textboxes
+	 */
+	$("thead input").each( function (i) {
+		this.initVal = this.value;
+	} );
+	
+	$("thead input").focus( function () {
+		if ( this.className == "search_init" )
+		{
+			this.className = "";
+			this.value = "";
+		}
+	} );
+	
+	$("thead input").blur( function (i) {
+		if ( this.value == "" )
+		{
+			this.className = "search_init";
+			this.value = this.initVal;
+		}
+	} );
+	
+	oTable = $('#example').dataTable( {
+		"sDom": 'RC<"clear">lfrtip',
+		"aoColumnDefs": [
+			{ "bVisible": false, "aTargets": [ 2 ] }
+		],
+		"oLanguage": {
+			"sSearch": "Search all columns:"
+		},
+		"bSortCellsTop": true
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/colvis.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/colvis.html new file mode 100755 index 0000000..b7b15e6 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/colvis.html @@ -0,0 +1,503 @@ + + + + + + + ColReorder example + + + + + + + + +
+
+ ColReorder example with ColVis +
+ +

Preamble

+

The ColReorder plug-in interacts with the ColVis plug-in for DataTables by updating the + order of the list of columns whenever a reorder is done. This is shown in the example + below, where one column has been hidden by default to add extra emphasis to ColVis.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sDom": 'RC<"clear">lfrtip',
+		"aoColumnDefs": [
+			{ "bVisible": false, "aTargets": [ 1 ] }
+		]
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/fixedcolumns.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/fixedcolumns.html new file mode 100755 index 0000000..bd993f6 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/fixedcolumns.html @@ -0,0 +1,603 @@ + + + + + + + ColReorder example + + + + + + + + +
+
+ ColReorder example with FixedColumns +
+ +

Preamble

+

While ColReorder works great with scrolling in DataTables (and thus FixedColumns), + it also presents an additional option called 'iFixedColumns' which allows you to not + let the user reorder certain columns (specific the number given, counting left to + right). So in the case of FixedColumns this is useful because you typically won't want + to let your fixed column be reordered. This is shown below in the FixedColumns index column + example.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 Rendering engineBrowserPlatform(s)Engine versionCSS grade
1TridentInternet + Explorer 4.0Win 95+4X
2TridentInternet + Explorer 5.0Win 95+5C
3TridentInternet + Explorer 5.5Win 95+5.5A
4TridentInternet + Explorer 6Win 98+6A
5TridentInternet Explorer 7Win XP SP2+7A
6TridentAOL browser (AOL desktop)Win XP6A
7GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
8GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
9GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
10GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
11GeckoCamino 1.0OSX.2+1.8A
12GeckoCamino 1.5OSX.3+1.8A
13GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
14GeckoNetscape Browser 8Win 98SE+1.7A
15GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
16GeckoMozilla 1.0Win 95+ / OSX.1+1A
17GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
18GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
19GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
20GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
21GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
22GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
23GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
24GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
25GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
26GeckoEpiphany 2.20Gnome1.8A
27WebkitSafari 1.2OSX.3125.5A
28WebkitSafari 1.3OSX.3312.8A
29WebkitSafari 2.0OSX.4+419.3A
30WebkitSafari 3.0OSX.4+522.1A
31WebkitOmniWeb 5.5OSX.4+420A
32WebkitiPod Touch / iPhoneiPod420.1A
33WebkitS60S60413A
34PrestoOpera 7.0Win 95+ / OSX.1+-A
35PrestoOpera 7.5Win 95+ / OSX.2+-A
36PrestoOpera 8.0Win 95+ / OSX.2+-A
37PrestoOpera 8.5Win 95+ / OSX.2+-A
38PrestoOpera 9.0Win 95+ / OSX.3+-A
39PrestoOpera 9.2Win 88+ / OSX.3+-A
40PrestoOpera 9.5Win 88+ / OSX.3+-A
41PrestoOpera for WiiWii-A
42PrestoNokia N800N800-A
43PrestoNintendo DS browserNintendo DS8.5C/A1
44KHTMLKonqureror 3.1KDE 3.13.1C
45KHTMLKonqureror 3.3KDE 3.33.3A
46KHTMLKonqureror 3.5KDE 3.53.5A
47TasmanInternet Explorer 4.5Mac OS 8-9-X
48TasmanInternet Explorer 5.1Mac OS 7.6-91C
49TasmanInternet Explorer 5.2Mac OS 8-X1C
50MiscNetFront 3.1Embedded devices-C
51MiscNetFront 3.4Embedded devices-A
52MiscDillo 0.8Embedded devices-X
53MiscLinksText only-X
54MiscLynxText only-X
55MiscIE MobileWindows Mobile 6-C
56MiscPSP browserPSP-C
57Other browsersAll others--U
 Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sDom": 'Rlfrtip',
+		"sScrollX": "100%",
+		"sScrollXInner": "150%",
+		"bScrollCollapse": true,
+		"fnDrawCallback": function ( oSettings ) {
+			/* Need to redo the counters if filtered or sorted */
+			if ( oSettings.bSorted || oSettings.bFiltered ) {
+				for ( var i=0, iLen=oSettings.aiDisplay.length ; i<iLen ; i++ ) {
+					$('td:eq(0)', oSettings.aoData[ oSettings.aiDisplay[i] ].nTr ).html( i+1 );
+				}
+			}
+		},
+		"aoColumnDefs": [
+			{ "bSortable": false, "sClass": "index", "aTargets": [ 0 ] }
+		],
+		"aaSorting": [[ 1, 'asc' ]],
+		"oColReorder": {
+			"iFixedColumns": 1
+		}
+	} );
+	new FixedColumns( oTable );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/fixedheader.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/fixedheader.html new file mode 100755 index 0000000..6e172c8 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/fixedheader.html @@ -0,0 +1,499 @@ + + + + + + + ColReorder example + + + + + + + + +
+
+ ColReorder example with FixedHeader +
+ +

Preamble

+

FixedHeader is a particularly useful plug-in for DataTables, allowing a table header + to float at the top of a scrolling window. ColReorder works well with FixedHeader, allowing + you to reorder columns even using the floating header, as shown in the example below.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		 "sDom": 'RC<"clear">lfrtip'
+	} );
+	new FixedHeader( oTable );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/index.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/index.html new file mode 100755 index 0000000..7b67205 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/index.html @@ -0,0 +1,496 @@ + + + + + + + ColReorder example + + + + + + + +
+
+ ColReorder example +
+ +

Preamble

+

This example shows the basic use case of the ColReorder plug-in. With ColReorder enabled + for a table, the user has the ability to click and drag any table header cell, and drop + it where they wish the column to be inserted. The insert point is shown visually, and + the column reordering is done as soon as the mouse button is released.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sDom": 'Rlfrtip'
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/media/css/ColReorder.css b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/css/ColReorder.css new file mode 100644 index 0000000..9c597e3 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/css/ColReorder.css @@ -0,0 +1,21 @@ +/* + * Namespace DTCR - "DataTables ColReorder" plug-in + */ + +table.DTCR_clonedTable { + background-color: white; + z-index: 202; +} + +div.DTCR_pointer { + width: 1px; + background-color: #0259C4; + z-index: 201; +} + +body.alt div.DTCR_pointer { + margin-top: -15px; + margin-left: -9px; + width: 18px; + background: url('../images/insert.png') no-repeat top left; +} \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/46848f6f3b.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/46848f6f3b.html new file mode 100644 index 0000000..f50b47c --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/46848f6f3b.html @@ -0,0 +1,75 @@ + + + + + Namespace: Settings object which contains customisable information for ColReorder instance - documentation + + + + + + + + + +
+ + +
+

Namespace: Settings object which contains customisable information for ColReorder instance

+ +
+ +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/4f1246032c.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/4f1246032c.html new file mode 100644 index 0000000..6aadb9f --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/4f1246032c.html @@ -0,0 +1,75 @@ + + + + + Namespace: Information used for the mouse drag - documentation + + + + + + + + + +
+ + +
+

Namespace: Information used for the mouse drag

+ +
+ +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/ColReorder.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/ColReorder.html new file mode 100644 index 0000000..06f434a --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/ColReorder.html @@ -0,0 +1,163 @@ + + + + + Class: ColReorder - documentation + + + + + + + + + +
+ + +
+

Class: ColReorder

+

ColReorder

+
+ +
+
+ + + +
+

Navigation

+ +
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
new ColReorder(DataTables, ColReorder)

ColReorder provides column visiblity control for DataTables

Constructor

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
DataTablesobject

settings object

2
ColReorderobject

options

+
+
+ + +
+ +

Summary

+ +

Properties - static

+ +
+
<static> aoInstances :array

Array of all ColReorder instances for later reference

+

Methods - static

+ +
+
<static> fnReset(object)

Reset the column ordering for a DataTables instance

+
+
+
+ + + + +
+ +

Details

+

Properties - static

+
+
<static> aoInstances :array

Array of all ColReorder instances for later reference

+ +
+
Properties:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
ColReorder.aoInstances
+

Methods - static

+
+
<static> fnReset(object)

Reset the column ordering for a DataTables instance

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
object

oTable DataTables instance to consider

Returns:

void

+ +
+
+
+ +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/a69b02bcf2.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/a69b02bcf2.html new file mode 100644 index 0000000..4219e5d --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/a69b02bcf2.html @@ -0,0 +1,75 @@ + + + + + Namespace: Common and useful DOM elements for the class instance - documentation + + + + + + + + + +
+ + +
+

Namespace: Common and useful DOM elements for the class instance

+ +
+ +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/global.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/global.html new file mode 100644 index 0000000..bf9de5f --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/global.html @@ -0,0 +1,180 @@ + + + + + Global - documentation + + + + + + + + + +
+ + +
+

Global

+ +
+ +
+
+ + + +
+

Navigation

+ +
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +

Summary

+ +

Classes

+
+
ColReorder

ColReorder provides column visiblity control for DataTables

+

Properties - instance

+ +
+
<constant> CLASS :String

Name of this class

<constant> VERSION :String

ColReorder version

+

Methods - instance

+ +
+
fnArraySwitch(array, int, int)

Modify an array by switching the position of two elements

fnDomSwitch(string, int, int)

Switch the positions of nodes in a parent node (note this is specifically designed for +table rows). Note this function considers all element nodes under the parent!

fnInvertKeyValues(array)

Switch the key value pairing of an index array to be value key (i.e. the old value is now the +key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ].

+
+
+
+ + + + +
+ +

Details

+

Properties - instance

+
+
<constant> CLASS :String

Name of this class

+ +
+
<constant> VERSION :String

ColReorder version

+ +
+
+

Methods - instance

+
+
fnArraySwitch(array, int, int)

Modify an array by switching the position of two elements

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
array

aArray Array to consider, will be modified by reference (i.e. no return)

2
int

iFrom From point

3
int

iTo Insert point

Returns:

void

+
fnDomSwitch(string, int, int)

Switch the positions of nodes in a parent node (note this is specifically designed for +table rows). Note this function considers all element nodes under the parent!

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
string

sTag Tag to consider

2
int

iFrom Element to move

3
int

Point to element the element to (before this point), can be null for append

Returns:

void

+
fnInvertKeyValues(array)

Switch the key value pairing of an index array to be value key (i.e. the old value is now the +key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ].

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
array

aIn Array to switch around

Returns:

array

+ +
+
+
+ +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/index.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/index.html new file mode 100644 index 0000000..f2f647e --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/index.html @@ -0,0 +1,40 @@ + + + + + Table of Contents - documentation + + + + + + + + + +
+ +
+
+ +
+

Table of Contents

+
+
ColReorder

ColReorder provides column visiblity control for DataTables

+
+
+
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/css/doc.css b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/css/doc.css new file mode 100644 index 0000000..a239329 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/css/doc.css @@ -0,0 +1,393 @@ +/* +Copyright (c) 2006, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 0.12.0 +*/ +body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;} +table{border-collapse:collapse;border-spacing:0;} +fieldset,img{border:0;} +address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;} +ol,ul {list-style:none;} +caption,th {text-align:left;} +h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;} +q:before,q:after{content:'';} +abbr,acronym {border:0;} + + +html, body { + margin: 0; + padding: 0; + width: 100%; + font: 14px/1.45em "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; + color: #111; +} + +div.fw_container { + width: 980px; + padding-top: 2em; + margin: 0 auto; +} + +div.fw_header { + position: relative; +} + +div.fw_content { + padding-top: 2em; +} + +div.fw_footer { + padding-top: 4em; + font-size: 75%; + text-align: center; +} + + + + +.type-attr .type-signature { + background-color: #ccc; + color: white; + border-radius: 3px; + display: inline-block; + padding: 0 3px; + font-size: 0.9em; +} + +.type-attr { + float: right; + color: #999; +} + +.type-name { + font-weight: bold; +} + +.type-sig { + color: #999; +} + +.type-param { + color: #D32929; +} + +.type-return { + color: #FF8080; +} + +.type-brace { + color: #111; +} + +.example-code { + margin-left: 30px; +} +.example-code td.code { + border-top: 1px solid #4E6CA3 !important; +} + +.type-augmented { + position: absolute; + left: 8px; + top: 0; +} + +dt, dd { + padding: 0.4em 10px; +} + +dt { + padding-bottom: 0 !important; +} + +dd { + position: relative; + padding-top: 0 !important; + padding-left: 3em; +} + +dt.even, dd.even { + background-color: white; +} + +dt.odd, dd.odd { + background-color: #F2F2F2; +} + +div.doc_overview dd, div.doc_overview dt { + padding-left: 0 !important; +} + + + +.right_border div { + width: 20px; + padding: 2px 0.5em 2px 1em; + text-align: right; +} +.right_border { + border-right: 3px solid #4E6CA3; +} +.bottom_border { + border-bottom: 1px solid #4E6CA3; +} + + +a { + text-decoration: none; + color: #4E6CA3; +} + +a:hover { + text-decoration: underline; + cursor: pointer; + *cursor: hand; +} + +div.fw_content ul { + list-style-image: url('../images/arrow.png'); + padding: 0 0 0 2em; +} + +/* +h2 { + font-size: 1.4em; + margin-top: 2em; + border-bottom: 3px solid #829ac6; + padding-left: 5px; +} + +h3 { + font-size: 1.2em; + margin-top: 1em; + border-bottom: 1px solid #A4B5D5; + padding-left: 5px; +} +*/ + +h1 { + font-size: 2em; +} + +h2 { + font-size: 1.6em; + padding-top: 5px; +} + +h2.ancestors { + font-size: 14px; + margin: 0; +} + +h3 { + font-size: 1.3em; + padding-top: 5px; + margin-bottom: 5px; +} + +h5 { + padding-top: 6px; + font-weight: bold; + font-size: 0.9em; + border-bottom: 1px solid #cad4e6; + margin-bottom: 1em; +} + +div.doc_summary, div.doc_details { + margin-top: 2em; + clear: both; +} + +div.doc_group { + margin-top: 1em; + border-top: 1px solid #A4B5D5; + border-left: 1px solid #A4B5D5; + padding-left: 10px; +} + +div.extended { + margin-left: 30px; +} + +table.params { + margin-left: 30px; + width: 97%; +} + +table.params th, +table.params td { + padding: 3px; +} + +tr.odd { + background-color: white; +} + +tr.even { + background-color: #F8F8F8; +} + +th.name, +td.name { + padding-left: 13px; +} + +td.number { + background-color: white; + color: #5C5C5C; +} + +dd.odd td.number { + background-color: #F2F2F2; +} + +p { + margin: 1em 0; +} + +p:first-child { + margin-top: 0; +} + +p:last-child { + margin-bottom: 0; +} + +p.returns { + margin-left: 5%; +} + +div.page-info { + position: absolute; + top: 0; + right: 0; +} + + +.private { + display: none; +} + + +code { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + padding: 2px 4px !important; + white-space: pre; + font-size: 0.9em; + + color: #D14; + background-color: #F7F7F9; + + border: 1px solid #E1E1E8; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +pre { + background-color: #f8f8f8; + border: 1px solid #ccc; + border-radius: 3px; + padding: 6px 10px; +} + +pre>code { + background-color: transparent; + border: none; + color: #111; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +ol { + list-style-type: decimal; + list-style-position: outside; + padding-left: 30px; +} + + + +div.fw_nav { + position: fixed; + top: 25px; + right: 30px; + width: 250px; + border: 1px solid #A4B5D5; + background-color: white; + padding: 10px; + z-index: 1001; + font-size: 12px; + overflow: hidden; +} + +div.fw_nav h2 { + margin: -10px 0 10px -10px; + width: 250px; + padding: 5px 10px; + background-color: #A4B5D5; + font-size: 12px; + cursor: pointer; + *cursor: hand; +} + +div.fw_nav ul>li>div { + padding: 0 0 0 1em; +} + +div.nav_blocker { + float: right; +} + +div.fw_nav td { + color: #999; +} + +div.fw_nav li { + margin-bottom: 5px; +} + +div.fw_nav li>a { + font-weight: bold; +} + + + + + + + +.css_clear { + clear: both; + height: 0; + line-height: 0; + visibility: hidden; +} + +.css_right { + text-align: right; +} + +.css_center { + text-align: center; +} + +.css_spacing { + margin-top: 1.5em; +} + +.css_small { + font-size: 75%; + line-height: 1.45em; +} + +.css_vsmall { + font-size: 65%; + line-height: 1.45em; +} diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/css/shCore.css b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/css/shCore.css new file mode 100644 index 0000000..b0c4520 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/css/shCore.css @@ -0,0 +1,226 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter a, +.syntaxhighlighter div, +.syntaxhighlighter code, +.syntaxhighlighter table, +.syntaxhighlighter table td, +.syntaxhighlighter table tr, +.syntaxhighlighter table tbody, +.syntaxhighlighter table thead, +.syntaxhighlighter table caption, +.syntaxhighlighter textarea { + -moz-border-radius: 0 0 0 0 !important; + -webkit-border-radius: 0 0 0 0 !important; + background: none !important; + border: 0 !important; + bottom: auto !important; + float: none !important; + height: auto !important; + left: auto !important; + line-height: 1.1em !important; + margin: 0 !important; + outline: 0 !important; + overflow: visible !important; + padding: 0 !important; + position: static !important; + right: auto !important; + text-align: left !important; + top: auto !important; + vertical-align: baseline !important; + width: auto !important; + box-sizing: content-box !important; + font-family: "Consolas","Monaco","Bitstream Vera Sans Mono","Courier New",Courier,monospace !important; + font-weight: normal !important; + font-style: normal !important; + font-size: 1em !important; + min-height: inherit !important; + min-height: auto !important; +} + +.syntaxhighlighter { + width: 100% !important; + margin: 1em 0 1em 0 !important; + position: relative !important; + overflow: auto !important; + font-size: 1em !important; +} +.syntaxhighlighter.source { + overflow: hidden !important; +} +.syntaxhighlighter .bold { + font-weight: bold !important; +} +.syntaxhighlighter .italic { + font-style: italic !important; +} +.syntaxhighlighter .line { + white-space: pre !important; +} +.syntaxhighlighter table { + width: 100% !important; +} +.syntaxhighlighter table caption { + text-align: left !important; + padding: .5em 0 0.5em 1em !important; +} +.syntaxhighlighter table td.code { + width: 100% !important; +} +.syntaxhighlighter table td.code .container { + position: relative !important; +} +.syntaxhighlighter table td.code .container textarea { + box-sizing: border-box !important; + position: absolute !important; + left: 0 !important; + top: 0 !important; + width: 100% !important; + height: 100% !important; + border: none !important; + background: white !important; + padding-left: 1em !important; + overflow: hidden !important; + white-space: pre !important; +} +.syntaxhighlighter table td.gutter .line { + text-align: right !important; + padding: 2px 0.5em 2px 1em !important; +} +.syntaxhighlighter table td.code .line { + padding: 2px 1em !important; +} +.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { + padding-left: 0em !important; +} +.syntaxhighlighter.show { + display: block !important; +} +.syntaxhighlighter.collapsed table { + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar { + padding: 0.1em 0.8em 0em 0.8em !important; + font-size: 1em !important; + position: static !important; + width: auto !important; + height: auto !important; +} +.syntaxhighlighter.collapsed .toolbar span { + display: inline !important; + margin-right: 1em !important; +} +.syntaxhighlighter.collapsed .toolbar span a { + padding: 0 !important; + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar span a.expandSource { + display: inline !important; +} +.syntaxhighlighter .toolbar { + position: absolute !important; + right: 1px !important; + top: 1px !important; + width: 11px !important; + height: 11px !important; + font-size: 10px !important; + z-index: 10 !important; +} +.syntaxhighlighter .toolbar span.title { + display: inline !important; +} +.syntaxhighlighter .toolbar a { + display: block !important; + text-align: center !important; + text-decoration: none !important; + padding-top: 1px !important; +} +.syntaxhighlighter .toolbar a.expandSource { + display: none !important; +} +.syntaxhighlighter.ie { + font-size: .9em !important; + padding: 1px 0 1px 0 !important; +} +.syntaxhighlighter.ie .toolbar { + line-height: 8px !important; +} +.syntaxhighlighter.ie .toolbar a { + padding-top: 0px !important; +} +.syntaxhighlighter.printing .line.alt1 .content, +.syntaxhighlighter.printing .line.alt2 .content, +.syntaxhighlighter.printing .line.highlighted .number, +.syntaxhighlighter.printing .line.highlighted.alt1 .content, +.syntaxhighlighter.printing .line.highlighted.alt2 .content { + background: none !important; +} +.syntaxhighlighter.printing .line .number { + color: #bbbbbb !important; +} +.syntaxhighlighter.printing .line .content { + color: black !important; +} +.syntaxhighlighter.printing .toolbar { + display: none !important; +} +.syntaxhighlighter.printing a { + text-decoration: none !important; +} +.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { + color: black !important; +} +.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { + color: #008200 !important; +} +.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { + color: blue !important; +} +.syntaxhighlighter.printing .keyword { + color: #006699 !important; + font-weight: bold !important; +} +.syntaxhighlighter.printing .preprocessor { + color: gray !important; +} +.syntaxhighlighter.printing .variable { + color: #aa7700 !important; +} +.syntaxhighlighter.printing .value { + color: #009900 !important; +} +.syntaxhighlighter.printing .functions { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .constants { + color: #0066cc !important; +} +.syntaxhighlighter.printing .script { + font-weight: bold !important; +} +.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { + color: gray !important; +} +.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { + color: red !important; +} +.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { + color: black !important; +} diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/css/shThemeDataTables.css b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/css/shThemeDataTables.css new file mode 100644 index 0000000..7e9790a --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/css/shThemeDataTables.css @@ -0,0 +1,128 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter { + background-color: white !important; + font-size: 14px !important; + overflow: visible !important; +} +.syntaxhighlighter .line.alt1 { + background-color: white !important; +} +.syntaxhighlighter .line.alt2 { + background-color: #F8F8F8 !important; +} +.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { + background-color: #e0e0e0 !important; +} +.syntaxhighlighter .line.highlighted.number { + color: black !important; +} +.syntaxhighlighter table caption { + color: black !important; +} +.syntaxhighlighter .gutter { +} +.syntaxhighlighter .gutter div { + color: #5C5C5C !important; + width: 20px !important; +} +.syntaxhighlighter .gutter .line.alt1, .syntaxhighlighter .gutter .line.alt2 { + background-color: white !important; +} +.odd .syntaxhighlighter .gutter .line.alt1, .odd .syntaxhighlighter .gutter .line.alt2 { + background-color: #F2F2F2 !important; +} +.syntaxhighlighter .gutter .line { + border-right: 3px solid #4E6CA3 !important; +} +.syntaxhighlighter .gutter .line.highlighted { + background-color: #4E6CA3 !important; + color: white !important; +} +.syntaxhighlighter.printing .line .content { + border: none !important; +} +.syntaxhighlighter.collapsed { + overflow: visible !important; +} +.syntaxhighlighter.collapsed .toolbar { + color: blue !important; + background: white !important; + border: 1px solid #4E6CA3 !important; +} +.syntaxhighlighter.collapsed .toolbar a { + color: blue !important; +} +.syntaxhighlighter.collapsed .toolbar a:hover { + color: red !important; +} +.syntaxhighlighter .toolbar { + color: white !important; + background: #4E6CA3 !important; + border: none !important; +} +.syntaxhighlighter .toolbar a { + color: white !important; +} +.syntaxhighlighter .toolbar a:hover { + color: black !important; +} +.syntaxhighlighter .plain, .syntaxhighlighter .plain a { + color: black !important; +} +.syntaxhighlighter .comments, .syntaxhighlighter .comments a { + color: #008200 !important; +} +.syntaxhighlighter .string, .syntaxhighlighter .string a { + color: blue !important; +} +.syntaxhighlighter .keyword { + color: #006699 !important; +} +.syntaxhighlighter .preprocessor { + color: gray !important; +} +.syntaxhighlighter .variable { + color: #aa7700 !important; +} +.syntaxhighlighter .value { + color: #009900 !important; +} +.syntaxhighlighter .functions { + color: #ff1493 !important; +} +.syntaxhighlighter .constants { + color: #0066cc !important; +} +.syntaxhighlighter .script { + font-weight: bold !important; + color: #006699 !important; + background-color: none !important; +} +.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { + color: gray !important; +} +.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { + color: red !important; +} + +.syntaxhighlighter .keyword { + font-weight: bold !important; +} diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/images/arrow.jpg b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/images/arrow.jpg new file mode 100644 index 0000000..eba85ea Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/images/arrow.jpg differ diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/images/arrow.png b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/images/arrow.png new file mode 100644 index 0000000..08dbbb1 Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/images/arrow.png differ diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/images/extended.png b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/images/extended.png new file mode 100644 index 0000000..5dd01bf Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/images/extended.png differ diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/js/doc.js b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/js/doc.js new file mode 100644 index 0000000..932d7cf --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/media/docs/media/js/doc.js @@ -0,0 +1,121 @@ + +(function() { + +var showingNav = true; + +$(document).ready( function () { + var jqNav = $('div.fw_nav'); + jqNav.css('right', ($(window).width() - $('div.fw_container').width()) /2); + + var n = $('div.nav_blocker')[0]; + n.style.height = $(jqNav).outerHeight()+"px"; + n.style.width = ($(jqNav).outerWidth()+20)+"px"; + + SyntaxHighlighter.highlight(); + + $('#private_toggle').click( function () { + if ( $('input[name=show_private]').val() == 0 ) { + $('input[name=show_private]').val( 1 ); + $('#private_label').html('Showing'); + $('.private').css('display', 'block'); + } else { + $('input[name=show_private]').val( 0 ); + $('#private_label').html('Hiding'); + $('.private').css('display', 'none'); + } + fnWriteCookie(); + return false; + } ); + + $('#extended_toggle').click( function () { + if ( $('input[name=show_extended]').val() == 0 ) { + $('input[name=show_extended]').val( 1 ); + $('#extended_label').html('Showing'); + $('.augmented').css('display', 'block'); + } else { + $('input[name=show_extended]').val( 0 ); + $('#extended_label').html('Hiding'); + $('.augmented').css('display', 'none'); + } + fnWriteCookie(); + return false; + } ); + + var savedHeight = $(jqNav).height(); + $('div.fw_nav h2').click( function () { + if ( showingNav ) { + $('div.fw_nav').animate( { + "height": 10, + "opacity": 0.3 + } ); + showingNav = false; + } else { + $('div.fw_nav').animate( { + "height": savedHeight, + "opacity": 1 + } ); + showingNav = true; + } + fnWriteCookie(); + } ); + + var cookie = fnReadCookie( 'SpryMedia_JSDoc' ); + if ( cookie != null ) { + var a = cookie.split('-'); + if ( a[0] == 1 ) { + $('#private_toggle').click(); + } + if ( a[1] == 0 ) { + $('#extended_toggle').click(); + } + if ( a[2] == 'false' ) { + $('div.fw_nav').css('height', 10).css('opacity', 0.3); + showingNav = false; + } + } +} ); + + +function fnWriteCookie() +{ + var sVal = + $('input[name=show_private]').val()+'-'+ + $('input[name=show_extended]').val()+'-'+ + showingNav; + + fnCreateCookie( 'SpryMedia_JSDoc', sVal ); +} + + +function fnCreateCookie( sName, sValue ) +{ + var iDays = 365; + var date = new Date(); + date.setTime( date.getTime()+(iDays*24*60*60*1000) ); + var sExpires = "; expires="+date.toGMTString(); + + document.cookie = sName+"="+sValue+sExpires+"; path=/"; +} + + +function fnReadCookie( sName ) +{ + var sNameEQ = sName + "="; + var sCookieContents = document.cookie.split(';'); + + for( var i=0 ; i)[^>]*$|#([\w\-]+)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Check for digits + rdigit = /\d/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // Has the ready events already been bound? + readyBound = false, + + // The deferred used on DOM ready + readyList, + + // Promise methods + promiseMethods = "then done fail isResolved isRejected promise".split( " " ), + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = "body"; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = (context ? context.ownerDocument || context : document); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; + } + + return jQuery.merge( this, selector ); + + // 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: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if (selector.selector !== undefined) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.5.1", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // 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 + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + (this.selector ? " " : "") + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // 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 ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.done( fn ); + + return this; + }, + + eq: function( i ) { + return i === -1 ? + this.slice( i ) : + this.slice( i, +i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + 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: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // 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 ( length === i ) { + 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({ + noConflict: function( deep ) { + window.$ = _$; + + if ( deep ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // 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, + + // Handle when the DOM is ready + ready: function( wait ) { + // A third-party is pushing the ready event forwards + if ( wait === true ) { + jQuery.readyWait--; + } + + // Make sure that the DOM is not already loaded + if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // 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" ).unbind( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyBound ) { + return; + } + + readyBound = true; + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent("onreadystatechange", DOMContentLoaded); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // 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"; + }, + + // A crude way of determining if an object is a window + isWindow: function( obj ) { + return obj && typeof obj === "object" && "setInterval" in obj; + }, + + isNaN: function( obj ) { + return obj == null || !rdigit.test( obj ) || isNaN( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // 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; + } + + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw msg; + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test(data.replace(rvalidescape, "@") + .replace(rvalidtokens, "]") + .replace(rvalidbraces, "")) ) { + + // Try to use the native JSON parser first + return window.JSON && window.JSON.parse ? + window.JSON.parse( data ) : + (new Function("return " + data))(); + + } else { + jQuery.error( "Invalid JSON: " + data ); + } + }, + + // Cross-browser xml parsing + // (xml & tmp used internally) + parseXML: function( data , xml , tmp ) { + + 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 ); + } + + tmp = xml.documentElement; + + if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) { + jQuery.error( "Invalid XML: " + data ); + } + + return xml; + }, + + noop: function() {}, + + // Evalulates a script in a global context + globalEval: function( data ) { + if ( data && rnotwhite.test(data) ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement, + script = document.createElement( "script" ); + + if ( jQuery.support.scriptEval() ) { + script.appendChild( document.createTextNode( data ) ); + } else { + script.text = data; + } + + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709). + head.insertBefore( script, head.firstChild ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction(object); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( var value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // The extra typeof function check is to prevent crashes + // in Safari 2 (See: #3039) + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type(array); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var ret = [], value; + + // Go through the array, translating each of the items to their + // new value (or values). + for ( var i = 0, length = elems.length; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + proxy: function( fn, proxy, thisObject ) { + if ( arguments.length === 2 ) { + if ( typeof proxy === "string" ) { + thisObject = fn; + fn = thisObject[ proxy ]; + proxy = undefined; + + } else if ( proxy && !jQuery.isFunction( proxy ) ) { + thisObject = proxy; + proxy = undefined; + } + } + + if ( !proxy && fn ) { + proxy = function() { + return fn.apply( thisObject || this, arguments ); + }; + } + + // Set the guid of unique handler to the same of original handler, so it can be removed + if ( fn ) { + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + } + + // So proxy can be declared as an argument + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can be optionally by executed if its a function + access: function( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + jQuery.access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : undefined; + }, + + now: function() { + return (new Date()).getTime(); + }, + + // Create a simple deferred (one callbacks list) + _Deferred: function() { + var // callbacks list + callbacks = [], + // stored [ context , args ] + fired, + // to avoid firing when already doing so + firing, + // flag to know if the deferred has been cancelled + cancelled, + // the deferred itself + deferred = { + + // done( f1, f2, ...) + done: function() { + if ( !cancelled ) { + var args = arguments, + i, + length, + elem, + type, + _fired; + if ( fired ) { + _fired = fired; + fired = 0; + } + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + deferred.done.apply( deferred, elem ); + } else if ( type === "function" ) { + callbacks.push( elem ); + } + } + if ( _fired ) { + deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); + } + } + return this; + }, + + // resolve with given context and args + resolveWith: function( context, args ) { + if ( !cancelled && !fired && !firing ) { + firing = 1; + try { + while( callbacks[ 0 ] ) { + callbacks.shift().apply( context, args ); + } + } + // We have to add a catch block for + // IE prior to 8 or else the finally + // block will never get executed + catch (e) { + throw e; + } + finally { + fired = [ context, args ]; + firing = 0; + } + } + return this; + }, + + // resolve with this as context and given arguments + resolve: function() { + deferred.resolveWith( jQuery.isFunction( this.promise ) ? this.promise() : this, arguments ); + return this; + }, + + // Has this deferred been resolved? + isResolved: function() { + return !!( firing || fired ); + }, + + // Cancel + cancel: function() { + cancelled = 1; + callbacks = []; + return this; + } + }; + + return deferred; + }, + + // Full fledged deferred (two callbacks list) + Deferred: function( func ) { + var deferred = jQuery._Deferred(), + failDeferred = jQuery._Deferred(), + promise; + // Add errorDeferred methods, then and promise + jQuery.extend( deferred, { + then: function( doneCallbacks, failCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ); + return this; + }, + fail: failDeferred.done, + rejectWith: failDeferred.resolveWith, + reject: failDeferred.resolve, + isRejected: failDeferred.isResolved, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + if ( promise ) { + return promise; + } + promise = obj = {}; + } + var i = promiseMethods.length; + while( i-- ) { + obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; + } + return obj; + } + } ); + // Make sure only one callback list will be used + deferred.done( failDeferred.cancel ).fail( deferred.cancel ); + // Unexpose cancel + delete deferred.cancel; + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + return deferred; + }, + + // Deferred helper + when: function( object ) { + var lastIndex = arguments.length, + deferred = lastIndex <= 1 && object && jQuery.isFunction( object.promise ) ? + object : + jQuery.Deferred(), + promise = deferred.promise(); + + if ( lastIndex > 1 ) { + var array = slice.call( arguments, 0 ), + count = lastIndex, + iCallback = function( index ) { + return function( value ) { + array[ index ] = arguments.length > 1 ? slice.call( arguments, 0 ) : value; + if ( !( --count ) ) { + deferred.resolveWith( promise, array ); + } + }; + }; + while( ( lastIndex-- ) ) { + object = array[ lastIndex ]; + if ( object && jQuery.isFunction( object.promise ) ) { + object.promise().then( iCallback(lastIndex), deferred.reject ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( promise, array ); + } + } else if ( deferred !== object ) { + deferred.resolve( object ); + } + return promise; + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySubclass( selector, context ) { + return new jQuerySubclass.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySubclass, this ); + jQuerySubclass.superclass = this; + jQuerySubclass.fn = jQuerySubclass.prototype = this(); + jQuerySubclass.fn.constructor = jQuerySubclass; + jQuerySubclass.subclass = this.subclass; + jQuerySubclass.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySubclass) ) { + context = jQuerySubclass(context); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass ); + }; + jQuerySubclass.fn.init.prototype = jQuerySubclass.fn; + var rootjQuerySubclass = jQuerySubclass(document); + return jQuerySubclass; + }, + + browser: {} +}); + +// Create readyList deferred +readyList = jQuery._Deferred(); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +if ( indexOf ) { + jQuery.inArray = function( elem, array ) { + return indexOf.call( array, elem ); + }; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +// Expose jQuery to the global object +return jQuery; + +})(); + + +(function() { + + jQuery.support = {}; + + var div = document.createElement("div"); + + div.style.display = "none"; + div.innerHTML = "
a"; + + var all = div.getElementsByTagName("*"), + a = div.getElementsByTagName("a")[0], + select = document.createElement("select"), + opt = select.appendChild( document.createElement("option") ), + input = div.getElementsByTagName("input")[0]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return; + } + + jQuery.support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: div.firstChild.nodeType === 3, + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText insted) + style: /red/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: a.getAttribute("href") === "/a", + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55$/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: input.value === "on", + + // 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) + optSelected: opt.selected, + + // Will be defined later + deleteExpando: true, + optDisabled: false, + checkClone: false, + noCloneEvent: true, + noCloneChecked: true, + boxModel: null, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableHiddenOffsets: true + }; + + input.checked = true; + jQuery.support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as diabled) + select.disabled = true; + jQuery.support.optDisabled = !opt.disabled; + + var _scriptEval = null; + jQuery.support.scriptEval = function() { + if ( _scriptEval === null ) { + var root = document.documentElement, + script = document.createElement("script"), + id = "script" + jQuery.now(); + + try { + script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); + } catch(e) {} + + root.insertBefore( script, root.firstChild ); + + // Make sure that the execution of code works by injecting a script + // tag with appendChild/createTextNode + // (IE doesn't support this, fails, and uses .text instead) + if ( window[ id ] ) { + _scriptEval = true; + delete window[ id ]; + } else { + _scriptEval = false; + } + + root.removeChild( script ); + // release memory in IE + root = script = id = null; + } + + return _scriptEval; + }; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + + } catch(e) { + jQuery.support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent("onclick", function click() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + jQuery.support.noCloneEvent = false; + div.detachEvent("onclick", click); + }); + div.cloneNode(true).fireEvent("onclick"); + } + + div = document.createElement("div"); + div.innerHTML = ""; + + var fragment = document.createDocumentFragment(); + fragment.appendChild( div.firstChild ); + + // WebKit doesn't clone checked state correctly in fragments + jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; + + // Figure out if the W3C box model works as expected + // document.body must exist before we can do this + jQuery(function() { + var div = document.createElement("div"), + body = document.getElementsByTagName("body")[0]; + + // Frameset documents with no body should not run this code + if ( !body ) { + return; + } + + div.style.width = div.style.paddingLeft = "1px"; + body.appendChild( div ); + jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; + + if ( "zoom" in div.style ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2; + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
"; + jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2; + } + + div.innerHTML = "
t
"; + var tds = div.getElementsByTagName("td"); + + // 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). + // (only IE 8 fails this test) + jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0; + + tds[0].style.display = ""; + tds[1].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE < 8 fail this test) + jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0; + div.innerHTML = ""; + + body.removeChild( div ).style.display = "none"; + div = tds = null; + }); + + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + var eventSupported = function( eventName ) { + var el = document.createElement("div"); + eventName = "on" + eventName; + + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( !el.attachEvent ) { + return true; + } + + var isSupported = (eventName in el); + if ( !isSupported ) { + el.setAttribute(eventName, "return;"); + isSupported = typeof el[eventName] === "function"; + } + el = null; + + return isSupported; + }; + + jQuery.support.submitBubbles = eventSupported("submit"); + jQuery.support.changeBubbles = eventSupported("change"); + + // release memory in IE + div = all = a = null; +})(); + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache, + + // 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[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; + + // 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 || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) { + 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 ) { + elem[ jQuery.expando ] = id = ++jQuery.uuid; + } else { + id = jQuery.expando; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].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 ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); + } else { + cache[ id ] = jQuery.extend(cache[ id ], name); + } + } + + thisCache = cache[ id ]; + + // Internal jQuery data is stored in a separate object inside the object's data + // cache in order to avoid key collisions between internal data and user-defined + // data + if ( pvt ) { + if ( !thisCache[ internalKey ] ) { + thisCache[ internalKey ] = {}; + } + + thisCache = thisCache[ internalKey ]; + } + + if ( data !== undefined ) { + thisCache[ name ] = data; + } + + // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should + // not attempt to inspect the internal events object using jQuery.data, as this + // internal data object is undocumented and subject to change. + if ( name === "events" && !thisCache[name] ) { + return thisCache[ internalKey ] && thisCache[ internalKey ].events; + } + + return getByName ? thisCache[ name ] : thisCache; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + 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 ) { + var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; + + if ( thisCache ) { + delete thisCache[ name ]; + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !isEmptyDataObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( pvt ) { + delete cache[ id ][ internalKey ]; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + var internalCache = cache[ id ][ internalKey ]; + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + if ( jQuery.support.deleteExpando || cache != window ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the entire user cache at once because it's faster than + // iterating through each key, but we need to continue to persist internal + // data if it existed + if ( internalCache ) { + cache[ id ] = {}; + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + + cache[ id ][ internalKey ] = internalCache; + + // Otherwise, we need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + } else if ( isNode ) { + // 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 ( jQuery.support.deleteExpando ) { + delete elem[ jQuery.expando ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( jQuery.expando ); + } else { + elem[ jQuery.expando ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var data = null; + + if ( typeof key === "undefined" ) { + if ( this.length ) { + data = jQuery.data( this[0] ); + + if ( this[0].nodeType === 1 ) { + var attr = this[0].attributes, name; + for ( var i = 0, l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = name.substr( 5 ); + dataAttr( this[0], name, data[ name ] ); + } + } + } + } + + return data; + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + // Try to fetch any internally stored data first + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + data = dataAttr( this[0], key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + + } else { + return this.each(function() { + var $this = jQuery( this ), + args = [ parts[0], value ]; + + $this.triggerHandler( "setData" + parts[1] + "!", args ); + jQuery.data( this, key, value ); + $this.triggerHandler( "changeData" + parts[1] + "!", args ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +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 ) { + data = elem.getAttribute( "data-" + key ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + !jQuery.isNaN( data ) ? parseFloat( 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; +} + +// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON +// property to be considered empty objects; this property always exists in +// order to make sure JSON.stringify does not expose internal metadata +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +jQuery.extend({ + queue: function( elem, type, data ) { + if ( !elem ) { + return; + } + + type = (type || "fx") + "queue"; + var q = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( !data ) { + return q || []; + } + + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + + } else { + q.push( data ); + } + + return q; + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(); + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift("inprogress"); + } + + fn.call(elem, function() { + jQuery.dequeue(elem, type); + }); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue", true ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function( i ) { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + type = type || "fx"; + + return this.queue( type, function() { + var elem = this; + setTimeout(function() { + jQuery.dequeue( elem, type ); + }, time ); + }); + }, + + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspaces = /\s+/, + rreturn = /\r/g, + rspecialurl = /^(?:href|src|style)$/, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rradiocheck = /^(?:radio|checkbox)$/i; + +jQuery.props = { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" +}; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name, fn ) { + return this.each(function(){ + jQuery.attr( this, name, "" ); + if ( this.nodeType === 1 ) { + this.removeAttribute( name ); + } + }); + }, + + addClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.addClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( value && typeof value === "string" ) { + var classNames = (value || "").split( rspaces ); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className ) { + elem.className = value; + + } else { + var className = " " + elem.className + " ", + setClass = elem.className; + + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { + setClass += " " + classNames[c]; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.removeClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + var classNames = (value || "").split( rspaces ); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + var className = (" " + elem.className + " ").replace(rclass, " "); + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[c] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this); + self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspaces ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " "; + for ( var i = 0, l = this.length; i < l; i++ ) { + if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + if ( !arguments.length ) { + var elem = this[0]; + + if ( elem ) { + if ( jQuery.nodeName( elem, "option" ) ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.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 ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + } + + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { + return elem.getAttribute("value") === null ? "on" : elem.value; + } + + // Everything else, we just grab the value + return (elem.value || "").replace(rreturn, ""); + + } + + return undefined; + } + + var isFunction = jQuery.isFunction(value); + + return this.each(function(i) { + var self = jQuery(this), val = value; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call(this, i, self.val()); + } + + // 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 + ""; + }); + } + + if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { + this.checked = jQuery.inArray( self.val(), val ) >= 0; + + } else if ( jQuery.nodeName( this, "select" ) ) { + var values = jQuery.makeArray(val); + + jQuery( "option", this ).each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + this.selectedIndex = -1; + } + + } else { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) { + return undefined; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery(elem)[name](value); + } + + var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), + // Whether we are setting (or getting) + set = value !== undefined; + + // Try to normalize/fix the name + name = notxml && jQuery.props[ name ] || name; + + // Only do all the following if this is a node (faster for style) + if ( elem.nodeType === 1 ) { + // These attributes require special treatment + var special = rspecialurl.test( name ); + + // Safari mis-reports the default selected property of an option + // Accessing the parent's selectedIndex property fixes it + if ( name === "selected" && !jQuery.support.optSelected ) { + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + + // If applicable, access the attribute via the DOM 0 way + // 'in' checks fail in Blackberry 4.7 #6931 + if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) { + if ( set ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } + + if ( value === null ) { + if ( elem.nodeType === 1 ) { + elem.removeAttribute( name ); + } + + } else { + elem[ name ] = value; + } + } + + // browsers index elements by id/name on forms, give priority to attributes. + if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { + return elem.getAttributeNode( name ).nodeValue; + } + + // 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/ + if ( name === "tabIndex" ) { + var attributeNode = elem.getAttributeNode( "tabIndex" ); + + return attributeNode && attributeNode.specified ? + attributeNode.value : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + + return elem[ name ]; + } + + if ( !jQuery.support.style && notxml && name === "style" ) { + if ( set ) { + elem.style.cssText = "" + value; + } + + return elem.style.cssText; + } + + if ( set ) { + // convert the value to a string (all browsers do this but IE) see #1070 + elem.setAttribute( name, "" + value ); + } + + // Ensure that missing attributes return undefined + // Blackberry 4.7 returns "" from getAttribute #6938 + if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) { + return undefined; + } + + var attr = !jQuery.support.hrefNormalized && notxml && special ? + // Some attributes require a special call on IE + elem.getAttribute( name, 2 ) : + elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return attr === null ? undefined : attr; + } + // Handle everything which isn't a DOM element node + if ( set ) { + elem[ name ] = value; + } + return elem[ name ]; + } +}); + + + + +var rnamespaces = /\.(.*)$/, + rformElems = /^(?:textarea|input|select)$/i, + rperiod = /\./g, + rspace = / /g, + rescape = /[^\w\s.|`]/g, + fcleanup = function( nm ) { + return nm.replace(rescape, "\\$&"); + }; + +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code originated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + add: function( elem, types, handler, data ) { + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // TODO :: Use a try/catch until it's safe to pull this out (likely 1.6) + // Minor release fix for bug #8018 + try { + // For whatever reason, IE has trouble passing the window object + // around, causing it to be cloned in the process + if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) { + elem = window; + } + } + catch ( e ) {} + + if ( handler === false ) { + handler = returnFalse; + } else if ( !handler ) { + // Fixes bug #7229. Fix recommended by jdalton + return; + } + + var handleObjIn, handleObj; + + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure + var elemData = jQuery._data( elem ); + + // If no elemData is found then we must be trying to bind to one of the + // banned noData elements + if ( !elemData ) { + return; + } + + var events = elemData.events, + eventHandle = elemData.handle; + + if ( !events ) { + elemData.events = events = {}; + } + + if ( !eventHandle ) { + elemData.handle = eventHandle = function() { + // Handle the second event of a trigger and when + // an event is called after a page has unloaded + return typeof jQuery !== "undefined" && !jQuery.event.triggered ? + jQuery.event.handle.apply( eventHandle.elem, arguments ) : + undefined; + }; + } + + // Add elem as a property of the handle function + // This is to prevent a memory leak with non-native events in IE. + eventHandle.elem = elem; + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = types.split(" "); + + var type, i = 0, namespaces; + + while ( (type = types[ i++ ]) ) { + handleObj = handleObjIn ? + jQuery.extend({}, handleObjIn) : + { handler: handler, data: data }; + + // Namespaced event handlers + if ( type.indexOf(".") > -1 ) { + namespaces = type.split("."); + type = namespaces.shift(); + handleObj.namespace = namespaces.slice(0).sort().join("."); + + } else { + namespaces = []; + handleObj.namespace = ""; + } + + handleObj.type = type; + if ( !handleObj.guid ) { + handleObj.guid = handler.guid; + } + + // Get the current list of functions bound to this event + var handlers = events[ type ], + special = jQuery.event.special[ type ] || {}; + + // Init the event handler queue + if ( !handlers ) { + handlers = events[ type ] = []; + + // Check for a special event handler + // 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 the function to the element's handler list + handlers.push( handleObj ); + + // Keep track of which events have been used, for global triggering + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, pos ) { + // don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + if ( handler === false ) { + handler = returnFalse; + } + + var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + events = elemData && elemData.events; + + if ( !elemData || !events ) { + return; + } + + // types is actually an event object here + if ( types && types.type ) { + handler = types.handler; + types = types.type; + } + + // Unbind all events for the element + if ( !types || typeof types === "string" && types.charAt(0) === "." ) { + types = types || ""; + + for ( type in events ) { + jQuery.event.remove( elem, type + types ); + } + + return; + } + + // Handle multiple events separated by a space + // jQuery(...).unbind("mouseover mouseout", fn); + types = types.split(" "); + + while ( (type = types[ i++ ]) ) { + origType = type; + handleObj = null; + all = type.indexOf(".") < 0; + namespaces = []; + + if ( !all ) { + // Namespaced event handlers + namespaces = type.split("."); + type = namespaces.shift(); + + namespace = new RegExp("(^|\\.)" + + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + eventType = events[ type ]; + + if ( !eventType ) { + continue; + } + + if ( !handler ) { + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( all || namespace.test( handleObj.namespace ) ) { + jQuery.event.remove( elem, origType, handleObj.handler, j ); + eventType.splice( j--, 1 ); + } + } + + continue; + } + + special = jQuery.event.special[ type ] || {}; + + for ( j = pos || 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( handler.guid === handleObj.guid ) { + // remove the given handler for the given type + if ( all || namespace.test( handleObj.namespace ) ) { + if ( pos == null ) { + eventType.splice( j--, 1 ); + } + + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + + if ( pos != null ) { + break; + } + } + } + + // remove generic event handler if no more handlers exist + if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + ret = null; + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + var handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + delete elemData.events; + delete elemData.handle; + + if ( jQuery.isEmptyObject( elemData ) ) { + jQuery.removeData( elem, undefined, true ); + } + } + }, + + // bubbling is internal + trigger: function( event, data, elem /*, bubbling */ ) { + // Event object or event type + var type = event.type || event, + bubbling = arguments[3]; + + if ( !bubbling ) { + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + jQuery.extend( jQuery.Event(type), event ) : + // Just the event type (string) + jQuery.Event(type); + + if ( type.indexOf("!") >= 0 ) { + event.type = type = type.slice(0, -1); + event.exclusive = true; + } + + // Handle a global trigger + if ( !elem ) { + // Don't bubble custom events when global (to avoid too much overhead) + event.stopPropagation(); + + // Only trigger if we've ever bound an event for it + if ( jQuery.event.global[ type ] ) { + // XXX This code smells terrible. event.js should not be directly + // inspecting the data cache + jQuery.each( jQuery.cache, function() { + // internalKey variable is just used to make it easier to find + // and potentially change this stuff later; currently it just + // points to jQuery.expando + var internalKey = jQuery.expando, + internalCache = this[ internalKey ]; + if ( internalCache && internalCache.events && internalCache.events[ type ] ) { + jQuery.event.trigger( event, data, internalCache.handle.elem ); + } + }); + } + } + + // Handle triggering a single element + + // don't do events on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { + return undefined; + } + + // Clean up in case it is reused + event.result = undefined; + event.target = elem; + + // Clone the incoming data, if any + data = jQuery.makeArray( data ); + data.unshift( event ); + } + + event.currentTarget = elem; + + // Trigger the event, it is assumed that "handle" is a function + var handle = jQuery._data( elem, "handle" ); + + if ( handle ) { + handle.apply( elem, data ); + } + + var parent = elem.parentNode || elem.ownerDocument; + + // Trigger an inline bound script + try { + if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { + if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { + event.result = false; + event.preventDefault(); + } + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (inlineError) {} + + if ( !event.isPropagationStopped() && parent ) { + jQuery.event.trigger( event, data, parent, true ); + + } else if ( !event.isDefaultPrevented() ) { + var old, + target = event.target, + targetType = type.replace( rnamespaces, "" ), + isClick = jQuery.nodeName( target, "a" ) && targetType === "click", + special = jQuery.event.special[ targetType ] || {}; + + if ( (!special._default || special._default.call( elem, event ) === false) && + !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { + + try { + if ( target[ targetType ] ) { + // Make sure that we don't accidentally re-trigger the onFOO events + old = target[ "on" + targetType ]; + + if ( old ) { + target[ "on" + targetType ] = null; + } + + jQuery.event.triggered = true; + target[ targetType ](); + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (triggerError) {} + + if ( old ) { + target[ "on" + targetType ] = old; + } + + jQuery.event.triggered = false; + } + } + }, + + handle: function( event ) { + var all, handlers, namespaces, namespace_re, events, + namespace_sort = [], + args = jQuery.makeArray( arguments ); + + event = args[0] = jQuery.event.fix( event || window.event ); + event.currentTarget = this; + + // Namespaced event handlers + all = event.type.indexOf(".") < 0 && !event.exclusive; + + if ( !all ) { + namespaces = event.type.split("."); + event.type = namespaces.shift(); + namespace_sort = namespaces.slice(0).sort(); + namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + event.namespace = event.namespace || namespace_sort.join("."); + + events = jQuery._data(this, "events"); + + handlers = (events || {})[ event.type ]; + + if ( events && handlers ) { + // Clone the handlers to prevent manipulation + handlers = handlers.slice(0); + + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; + + // Filter the functions by class + if ( all || namespace_re.test( handleObj.namespace ) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handleObj.handler; + event.data = handleObj.data; + event.handleObj = handleObj; + + var ret = handleObj.handler.apply( this, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + } + + return event.result; + }, + + props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // store a copy of the original event object + // and "clone" to set read-only properties + var originalEvent = event; + event = jQuery.Event( originalEvent ); + + for ( var i = this.props.length, prop; i; ) { + prop = this.props[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary + if ( !event.target ) { + // Fixes #1925 where srcElement might not be defined either + event.target = event.srcElement || document; + } + + // check if target is a textnode (safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) { + event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; + } + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var doc = document.documentElement, + body = document.body; + + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); + } + + // Add which for key events + if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { + event.which = event.charCode != null ? event.charCode : event.keyCode; + } + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) { + event.metaKey = event.ctrlKey; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button !== undefined ) { + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + } + + return event; + }, + + // Deprecated, use jQuery.guid instead + guid: 1E8, + + // Deprecated, use jQuery.proxy instead + proxy: jQuery.proxy, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady, + teardown: jQuery.noop + }, + + live: { + add: function( handleObj ) { + jQuery.event.add( this, + liveConvert( handleObj.origType, handleObj.selector ), + jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); + }, + + remove: function( handleObj ) { + jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); + } + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src ) { + // Allow instantiation without the 'new' keyword + if ( !this.preventDefault ) { + return new jQuery.Event( src ); + } + + // 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.returnValue === false || + src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // timeStamp is buggy for some events on Firefox(#3843) + // So we won't rely on the native value + this.timeStamp = jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return 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 = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Checks if an event happened on an element within another element +// Used in jQuery.event.special.mouseenter and mouseleave handlers +var withinElement = function( event ) { + // Check if mouse(over|out) are still within the same parent element + var parent = event.relatedTarget; + + // Firefox sometimes assigns relatedTarget a XUL element + // which we cannot access the parentNode property of + try { + + // Chrome does something similar, the parentNode property + // can be accessed but is null. + if ( parent !== document && !parent.parentNode ) { + return; + } + // Traverse up the tree + while ( parent && parent !== this ) { + parent = parent.parentNode; + } + + if ( parent !== this ) { + // set the correct event type + event.type = event.data; + + // handle event if we actually just moused on to a non sub-element + jQuery.event.handle.apply( this, arguments ); + } + + // assuming we've left the element since we most likely mousedover a xul element + } catch(e) { } +}, + +// In case of event delegation, we only need to rename the event.type, +// liveHandler will take care of the rest. +delegate = function( event ) { + event.type = event.data; + jQuery.event.handle.apply( this, arguments ); +}; + +// Create mouseenter and mouseleave events +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + setup: function( data ) { + jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); + }, + teardown: function( data ) { + jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + } + }; +}); + +// submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function( data, namespaces ) { + if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) { + jQuery.event.add(this, "click.specialSubmit", function( e ) { + var elem = e.target, + type = elem.type; + + if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { + trigger( "submit", this, arguments ); + } + }); + + jQuery.event.add(this, "keypress.specialSubmit", function( e ) { + var elem = e.target, + type = elem.type; + + if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { + trigger( "submit", this, arguments ); + } + }); + + } else { + return false; + } + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialSubmit" ); + } + }; + +} + +// change delegation, happens here so we have bind. +if ( !jQuery.support.changeBubbles ) { + + var changeFilters, + + getVal = function( elem ) { + var type = elem.type, val = elem.value; + + if ( type === "radio" || type === "checkbox" ) { + val = elem.checked; + + } else if ( type === "select-multiple" ) { + val = elem.selectedIndex > -1 ? + jQuery.map( elem.options, function( elem ) { + return elem.selected; + }).join("-") : + ""; + + } else if ( elem.nodeName.toLowerCase() === "select" ) { + val = elem.selectedIndex; + } + + return val; + }, + + testChange = function testChange( e ) { + var elem = e.target, data, val; + + if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { + return; + } + + data = jQuery._data( elem, "_change_data" ); + val = getVal(elem); + + // the current data will be also retrieved by beforeactivate + if ( e.type !== "focusout" || elem.type !== "radio" ) { + jQuery._data( elem, "_change_data", val ); + } + + if ( data === undefined || val === data ) { + return; + } + + if ( data != null || val ) { + e.type = "change"; + e.liveFired = undefined; + jQuery.event.trigger( e, arguments[1], elem ); + } + }; + + jQuery.event.special.change = { + filters: { + focusout: testChange, + + beforedeactivate: testChange, + + click: function( e ) { + var elem = e.target, type = elem.type; + + if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { + testChange.call( this, e ); + } + }, + + // Change has to be called before submit + // Keydown will be called before keypress, which is used in submit-event delegation + keydown: function( e ) { + var elem = e.target, type = elem.type; + + if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || + (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || + type === "select-multiple" ) { + testChange.call( this, e ); + } + }, + + // Beforeactivate happens also before the previous element is blurred + // with this event you can't trigger a change event, but you can store + // information + beforeactivate: function( e ) { + var elem = e.target; + jQuery._data( elem, "_change_data", getVal(elem) ); + } + }, + + setup: function( data, namespaces ) { + if ( this.type === "file" ) { + return false; + } + + for ( var type in changeFilters ) { + jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); + } + + return rformElems.test( this.nodeName ); + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialChange" ); + + return rformElems.test( this.nodeName ); + } + }; + + changeFilters = jQuery.event.special.change.filters; + + // Handle when the input is .focus()'d + changeFilters.focus = changeFilters.beforeactivate; +} + +function trigger( type, elem, args ) { + // 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. + // Don't pass args or remember liveFired; they apply to the donor event. + var event = jQuery.extend( {}, args[ 0 ] ); + event.type = type; + event.originalEvent = {}; + event.liveFired = undefined; + jQuery.event.handle.call( elem, event ); + if ( event.isDefaultPrevented() ) { + args[ 0 ].preventDefault(); + } +} + +// Create "bubbling" focus and blur events +if ( document.addEventListener ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + jQuery.event.special[ fix ] = { + setup: function() { + this.addEventListener( orig, handler, true ); + }, + teardown: function() { + this.removeEventListener( orig, handler, true ); + } + }; + + function handler( e ) { + e = jQuery.event.fix( e ); + e.type = fix; + return jQuery.event.handle.call( this, e ); + } + }); +} + +jQuery.each(["bind", "one"], function( i, name ) { + jQuery.fn[ name ] = function( type, data, fn ) { + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this[ name ](key, data, type[key], fn); + } + return this; + } + + if ( jQuery.isFunction( data ) || data === false ) { + fn = data; + data = undefined; + } + + var handler = name === "one" ? jQuery.proxy( fn, function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }) : fn; + + if ( type === "unload" && name !== "one" ) { + this.one( type, data, fn ); + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.add( this[i], type, handler, data ); + } + } + + return this; + }; +}); + +jQuery.fn.extend({ + unbind: function( type, fn ) { + // Handle object literals + if ( typeof type === "object" && !type.preventDefault ) { + for ( var key in type ) { + this.unbind(key, type[key]); + } + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.remove( this[i], type, fn ); + } + } + + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.live( types, data, fn, selector ); + }, + + undelegate: function( selector, types, fn ) { + if ( arguments.length === 0 ) { + return this.unbind( "live" ); + + } else { + return this.die( types, null, fn, selector ); + } + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + + triggerHandler: function( type, data ) { + if ( this[0] ) { + var event = jQuery.Event( type ); + event.preventDefault(); + event.stopPropagation(); + jQuery.event.trigger( event, data, this[0] ); + return event.result; + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + i = 1; + + // link all the functions, so any of them can unbind this click handler + while ( i < args.length ) { + jQuery.proxy( fn, args[ i++ ] ); + } + + return this.click( jQuery.proxy( fn, function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + })); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +var liveMap = { + focus: "focusin", + blur: "focusout", + mouseenter: "mouseover", + mouseleave: "mouseout" +}; + +jQuery.each(["live", "die"], function( i, name ) { + jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { + var type, i = 0, match, namespaces, preType, + selector = origSelector || this.selector, + context = origSelector ? this : jQuery( this.context ); + + if ( typeof types === "object" && !types.preventDefault ) { + for ( var key in types ) { + context[ name ]( key, data, types[key], selector ); + } + + return this; + } + + if ( jQuery.isFunction( data ) ) { + fn = data; + data = undefined; + } + + types = (types || "").split(" "); + + while ( (type = types[ i++ ]) != null ) { + match = rnamespaces.exec( type ); + namespaces = ""; + + if ( match ) { + namespaces = match[0]; + type = type.replace( rnamespaces, "" ); + } + + if ( type === "hover" ) { + types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); + continue; + } + + preType = type; + + if ( type === "focus" || type === "blur" ) { + types.push( liveMap[ type ] + namespaces ); + type = type + namespaces; + + } else { + type = (liveMap[ type ] || type) + namespaces; + } + + if ( name === "live" ) { + // bind live handler + for ( var j = 0, l = context.length; j < l; j++ ) { + jQuery.event.add( context[j], "live." + liveConvert( type, selector ), + { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); + } + + } else { + // unbind live handler + context.unbind( "live." + liveConvert( type, selector ), fn ); + } + } + + return this; + }; +}); + +function liveHandler( event ) { + var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, + elems = [], + selectors = [], + events = jQuery._data( this, "events" ); + + // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) + if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { + return; + } + + if ( event.namespace ) { + namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + event.liveFired = this; + + var live = events.live.slice(0); + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { + selectors.push( handleObj.selector ); + + } else { + live.splice( j--, 1 ); + } + } + + match = jQuery( event.target ).closest( selectors, event.currentTarget ); + + for ( i = 0, l = match.length; i < l; i++ ) { + close = match[i]; + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { + elem = close.elem; + related = null; + + // Those two events require additional checking + if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { + event.type = handleObj.preType; + related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; + } + + if ( !related || related !== elem ) { + elems.push({ elem: elem, handleObj: handleObj, level: close.level }); + } + } + } + } + + for ( i = 0, l = elems.length; i < l; i++ ) { + match = elems[i]; + + if ( maxLevel && match.level > maxLevel ) { + break; + } + + event.currentTarget = match.elem; + event.data = match.handleObj.data; + event.handleObj = match.handleObj; + + ret = match.handleObj.origHandler.apply( match.elem, arguments ); + + if ( ret === false || event.isPropagationStopped() ) { + maxLevel = match.level; + + if ( ret === false ) { + stop = false; + } + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + + return stop; +} + +function liveConvert( type, selector ) { + return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&"); +} + +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").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.bind( name, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } +}); + + +/*! + * 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/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[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; + + // Reset the position of the chunker regexp (start from head) + 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 { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + 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; + } + } + } + + // Improper expression + 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]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + 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, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + 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]; + } + + // Handle if an un-quoted value was used + 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 we're dealing with a complex expression, or a simple one + 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 ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + 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 ) { + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return "text" === elem.getAttribute( 'type' ); + }, + radio: function( elem ) { + return "radio" === elem.type; + }, + + checkbox: function( elem ) { + return "checkbox" === elem.type; + }, + + file: function( elem ) { + return "file" === elem.type; + }, + password: function( elem ) { + return "password" === elem.type; + }, + + submit: function( elem ) { + return "submit" === elem.type; + }, + + image: function( elem ) { + return "image" === elem.type; + }, + + reset: function( elem ) { + return "reset" === elem.type; + }, + + button: function( elem ) { + return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + } + }, + 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; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} 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 ) { + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // If the nodes are siblings (or identical) we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + 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; + }; +} + +// Utility function for retreiving the text value of an array of DOM nodes +Sizzle.getText = function( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += Sizzle.getText( elem.childNodes ); + } + } + + return ret; +}; + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + 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 ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + 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; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

"; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // 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[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // 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 + } 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 ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector, + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + if ( matches ) { + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + return matches.call( node, expr ); + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
"; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + 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]); + } + }; + + // release memory in IE + 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 ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + 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; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + 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 ); +}; + +// EXPOSE +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.POS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var ret = this.pushStack( "", "find", selector ), + length = 0; + + for ( var i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( var n = length; n < ret.length; n++ ) { + for ( var r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && jQuery.filter( selector, this ).length > 0; + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + if ( jQuery.isArray( selectors ) ) { + var match, selector, + matches = {}, + level = 1; + + if ( cur && selectors.length ) { + for ( i = 0, l = selectors.length; i < l; i++ ) { + selector = selectors[i]; + + if ( !matches[selector] ) { + matches[selector] = jQuery.expr.match.POS.test( selector ) ? + jQuery( selector, context || this.context ) : + selector; + } + } + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( selector in matches ) { + match = matches[selector]; + + if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { + ret.push({ selector: selector, elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + } + + return ret; + } + + var pos = POS.test( selectors ) ? + jQuery( selectors, context || this.context ) : null; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique(ret) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + if ( !elem || typeof elem === "string" ) { + return jQuery.inArray( this[0], + // If it receives a string, the selector is used + // If it receives nothing, the siblings are used + elem ? jQuery( elem ) : this.parent().children() ); + } + // 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 ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +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 jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "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.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ), + // The variable 'args' was introduced in + // https://github.com/jquery/jquery/commit/52a0238 + // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. + // http://code.google.com/p/v8/issues/detail?id=1050 + args = slice.call(arguments); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, args.join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + 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; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return (elem === qualifier) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + }); +} + + + + +var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /", "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and + + + + + +
+
+ ColReorder example with predefined column ordering +
+ +

Preamble

+

ColReorder provides the ability to specify a column ordering which is not that of the + HTML (which typically you will want) through the parameter oColReorder.aiOrder. This is + an array of integers with the column ordering you want.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sDom": 'Rlfrtip',
+		"oColReorder": {
+			"aiOrder": [ 4, 3, 2, 1, 0 ]
+		}
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/reset.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/reset.html new file mode 100755 index 0000000..60dca5d --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/reset.html @@ -0,0 +1,533 @@ + + + + + + + ColReorder example + + + + + + + +
+
+ ColReorder example with the ability to reset the ordering +
+ +

Preamble

+

One useful control option to present the end user when using ColReorder is the ability + to reset the column ordering to that which was found in the HTML. This can be done by + calling the fnReset API function. While ColReorder does not provide a visual element for + this itself (in order to provide maximum flexibility) it is easy to hook to an event + handler, as shown in this example.

+ +

Live example

+
+
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sDom": 'Rlfrtip',
+		"oColReorder": {
+			"aiOrder": [ 4, 3, 2, 1, 0 ]
+		}
+	} );
+	
+	$('#reset').click( function () {
+		ColReorder.fnReset( oTable );
+		return false;
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/scrolling.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/scrolling.html new file mode 100755 index 0000000..b91577a --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/scrolling.html @@ -0,0 +1,497 @@ + + + + + + + ColReorder example + + + + + + + +
+
+ ColReorder example with scrolling +
+ +

Preamble

+

This is a simple example to show ColReorder working with DataTables scrolling.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sDom": 'Rlfrtip',
+		"sScrollY": "200px",
+		"bPaginate": false
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/server_side.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/server_side.html new file mode 100755 index 0000000..8347736 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/server_side.html @@ -0,0 +1,150 @@ + + + + + + + ColReorder example + + + + + + + +
+
+ ColReorder example with server-side processing +
+ +

Preamble

+

Server-side processing can be exceptionally useful in DataTables when dealing with + massive data sets, and ColReorder works with this as would be expected. There must be + special consideration for the column ordering on the server-side script since the + columns can be in an unexpected order. For this you can either choose to use the + sName parameter for each column and take this into account in the server-side + script (the parameter 'sColumns' is a comma separated string of these sName parameters).

+ +

Alternatively use the more flexible mDataProp + option for each column. This allows you to use JSON objects which DataTables, so order doesn't + matter like it would do in an array. Again the server-side script must take this into account + through the mDataProp_{i} which is sent for each column (so the server knows which + column is to be sorted on).

+ + +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sDom": 'Rlfrtip',
+		"bProcessing": true,
+		"bServerSide": true,
+		"sAjaxSource": "../../examples/server_side/scripts/objects.php",
+		"aoColumns": [
+			{ "mDataProp": "engine" },
+			{ "mDataProp": "browser" },
+			{ "mDataProp": "platform" },
+			{ "mDataProp": "version" },
+			{ "mDataProp": "grade" }
+		]
+	} );
+} );
+ +

Example JSON return from the server

+
{
+"sEcho": 1,
+"iTotalRecords": "57",
+"iTotalDisplayRecords": "57",
+"aaData": [
+    {
+        "engine": "Gecko",
+        "browser": "Firefox 1.0",
+        "platform": "Win 98+ / OSX.2+",
+        "version": "1.7",
+        "grade": "A"
+    },
+    {
+        "engine": "Gecko",
+        "browser": "Firefox 1.5",
+        "platform": "Win 98+ / OSX.2+",
+        "version": "1.8",
+        "grade": "A"
+    },
+    ...
+  ]
+}
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/state_save.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/state_save.html new file mode 100755 index 0000000..bbfb425 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/state_save.html @@ -0,0 +1,498 @@ + + + + + + + ColReorder example + + + + + + + +
+
+ ColReorder example with state saving +
+ +

Preamble

+

A useful interaction pattern to use in DataTables is state saving, so when the end user + reloads or revisits a page its previous state is retained. ColReorder works seamlessly + with state saving in DataTables, remembering and restoring the column positions, as well + as everything else such as sorting and filtering.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sDom": 'Rlfrtip',
+		"bStateSave": true
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColReorder/theme.html b/modules/thirdparty/jquery/datatables/extras/ColReorder/theme.html new file mode 100755 index 0000000..56749a0 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColReorder/theme.html @@ -0,0 +1,500 @@ + + + + + + + ColReorder example + + + + + + + +
+
+ ColReorder example with jQuery UI theming +
+ +

Preamble

+

This example shows how the jQuery UI ThemeRoller option in DataTables can be used + with ColReorder. The important thing to node here is how sDom is set up in order to + include the required classes and elements.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sDom": 'R<"H"lfr>t<"F"ip>',
+		"bJQueryUI": true,
+		"sPaginationType": "full_numbers"
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/exclude_columns.html b/modules/thirdparty/jquery/datatables/extras/ColVis/exclude_columns.html new file mode 100755 index 0000000..bf6756c --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/exclude_columns.html @@ -0,0 +1,500 @@ + + + + + + + ColVis example + + + + + + + +
+
+ ColVis example - exclude columns from list +
+ +

Preamble

+

It can at times be useful to exclude columns from being in the 'show / hide' list (for + example if you have hidden information that the end user shouldn't be able to make + visible. This can be done by the oColVis.aiExclude initialisation parameter when creating + the DataTable. This is simply an array of integers, indicating which columns should + be excluded. This example shows the first column being excluded.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	$('#example').dataTable( {
+		"sDom": 'C<"clear">lfrtip',
+		"oColVis": {
+			"aiExclude": [ 0 ]
+		}
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/index.html b/modules/thirdparty/jquery/datatables/extras/ColVis/index.html new file mode 100755 index 0000000..7d3107c --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/index.html @@ -0,0 +1,490 @@ + + + + + + + ColVis example + + + + + + + +
+
+ ColVis example +
+ +

Preamble

+

ColVis is a plug-in for DataTables which presents a list of all columns to a user and allows them to select which ones they wish to be visible. Click the 'Show / hide columns' button to be presented with a list of columns in the table, and click the buttons to show and hide them as you wish.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	$('#example').dataTable( {
+		"sDom": 'C<"clear">lfrtip'
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/media/css/ColVis.css b/modules/thirdparty/jquery/datatables/extras/ColVis/media/css/ColVis.css new file mode 100755 index 0000000..a3bf8e2 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/media/css/ColVis.css @@ -0,0 +1,76 @@ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * ColVis styles + */ +.ColVis { + float: right; + margin-bottom: 1em; +} + +.ColVis_Button { + position: relative; + float: left; + margin-right: 3px; + padding: 3px 5px; + height: 30px; + background-color: #fff; + border: 1px solid #d0d0d0; + cursor: pointer; + *cursor: hand; +} + +button.ColVis_Button::-moz-focus-inner { + border: none !important; + padding: 0; +} + +.ColVis_text_hover { + border: 1px solid #999; + background-color: #f0f0f0; +} + +div.ColVis_collectionBackground { + background-color: black; + z-index: 1100; +} + +div.ColVis_collection { + position: relative; + width: 150px; + background-color: #f3f3f3; + padding: 3px; + border: 1px solid #ccc; + z-index: 1102; +} + +div.ColVis_collection button.ColVis_Button { + background-color: white; + width: 100%; + float: none; + margin-bottom: 2px; +} + +div.ColVis_catcher { + position: absolute; + z-index: 1101; +} + +.disabled { + color: #999; +} + + + +button.ColVis_Button { + text-align: left; +} + +div.ColVis_collection button.ColVis_Button:hover { + border: 1px solid #999; + background-color: #f0f0f0; +} + +span.ColVis_radio { + display: inline-block; + width: 20px; +} diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/media/css/ColVisAlt.css b/modules/thirdparty/jquery/datatables/extras/ColVis/media/css/ColVisAlt.css new file mode 100755 index 0000000..93f35b6 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/media/css/ColVisAlt.css @@ -0,0 +1,104 @@ +/* + * An alternative styling for ColVis + * Note you will likely have to change the path for the background image used by jQuery UI theming: + * ../../../../examples/examples_support/themes/smoothness + */ + +.ColVis { + position: absolute; + right: 0; + top: 0; + width: 15px; + height: 30px; +} + +.ColVis_MasterButton { + height: 100%; + width: 100%; + border-left-width: 0; + cursor: pointer; + *cursor: hand; + background: url('../images/button.png') no-repeat top left; +} + +button.ColVis_Button::-moz-focus-inner { + border: none !important; + padding: 0; +} + +.ColVis_text_hover { + border: 1px solid #999; + background-color: #f0f0f0; +} + +div.ColVis_collectionBackground { + background-color: black; + z-index: 1100; +} + +div.ColVis_collection { + position: relative; + width: 150px; + background-color: #f9f9f9; + padding: 3px; + border: 1px solid #ccc; + z-index: 1102; +} + +div.ColVis_collection button.ColVis_Button { + height: 30px; + width: 100%; + margin-right: 3px; + margin-bottom: 2px; + padding: 3px 5px; + cursor: pointer; + *cursor: hand; + text-align: left; +} + +div.ColVis_collection button.ColVis_Button:hover { + border: 1px solid #999; + background-color: #f0f0f0; +} + +div.ColVis_catcher { + position: absolute; + z-index: 1101; +} + +span.ColVis_radio { + display: inline-block; + width: 20px; +} + +button.ColVis_Restore { + margin-top: 15px; +} + +button.ColVis_Restore span { + display: inline-block; + padding-left: 10px; + text-align: left; +} + +.disabled { + color: #999; +} + + + +/* + * Styles needed for DataTables scrolling + */ +div.dataTables_scrollHead { + position: relative; + overflow: hidden; +} + +div.dataTables_scrollBody { + overflow-y: scroll; +} + +div.dataTables_scrollFoot { + overflow: hidden; +} diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/ColVis.html b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/ColVis.html new file mode 100644 index 0000000..58f441b --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/ColVis.html @@ -0,0 +1,176 @@ + + + + + Class: ColVis - documentation + + + + + + + + + +
+ + +
+

Class: ColVis

+

ColVis

+
+ +
+
+ + + +
+

Navigation

+ +
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
new ColVis(DataTables)

ColVis provides column visiblity control for DataTables

Constructor

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
DataTablesobject

settings object

+
+
+ + +
+ +

Summary

+ +

Properties - static

+ +
+
<static> aInstances :Array

Collection of all ColVis instances

+

Methods - instance

+ +
+
_fnAdjustOpenRows()

Alter the colspan on any fnOpen rows

+
+

Methods - static

+ +
+
<static> fnRebuild(object)

Rebuild the collection for a given table, or all tables if no parameter given

+
+
+
+ + + + +
+ +

Details

+

Properties - static

+
+
<static> aInstances :Array

Collection of all ColVis instances

+ +
+
Properties:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
ColVis.aInstances
+

Methods - instance

+
+
_fnAdjustOpenRows()

Alter the colspan on any fnOpen rows

+ +
+
+ +
+

Methods - static

+
+
<static> fnRebuild(object)

Rebuild the collection for a given table, or all tables if no parameter given

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
object

oTable DataTable instance to consider - optional

Returns:

void

+ +
+
+
+ +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/a69b02bcf2.html b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/a69b02bcf2.html new file mode 100644 index 0000000..194635b --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/a69b02bcf2.html @@ -0,0 +1,75 @@ + + + + + Namespace: Common and useful DOM elements for the class instance - documentation + + + + + + + + + +
+ + +
+

Namespace: Common and useful DOM elements for the class instance

+ +
+ +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/ccb5a49865.html b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/ccb5a49865.html new file mode 100644 index 0000000..a0c0f29 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/ccb5a49865.html @@ -0,0 +1,75 @@ + + + + + Namespace: Settings object which contains customisable information for ColVis instance - documentation + + + + + + + + + +
+ + +
+

Namespace: Settings object which contains customisable information for ColVis instance

+ +
+ +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/global.html b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/global.html new file mode 100644 index 0000000..a2969a9 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/global.html @@ -0,0 +1,117 @@ + + + + + Global - documentation + + + + + + + + + +
+ + +
+

Global

+ +
+ +
+
+ + + +
+

Navigation

+ +
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +

Summary

+ +

Classes

+
+
ColVis

ColVis provides column visiblity control for DataTables

+

Properties - instance

+ +
+
<constant> CLASS :String

Name of this class

<constant> VERSION :String

ColVis version

+

Methods - instance

+ +
+
fnRebuild()

Rebuild the list of buttons for this instance (i.e. if there is a column header update)

+
+
+
+ + + + +
+ +

Details

+

Properties - instance

+
+
<constant> CLASS :String

Name of this class

+ +
+
<constant> VERSION :String

ColVis version

+ +
+
+

Methods - instance

+
+
fnRebuild()

Rebuild the list of buttons for this instance (i.e. if there is a column header update)

+ +
+
Returns:

void

+ +
+
+
+ +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/index.html b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/index.html new file mode 100644 index 0000000..5d1c69d --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/index.html @@ -0,0 +1,40 @@ + + + + + Table of Contents - documentation + + + + + + + + + +
+ +
+
+ +
+

Table of Contents

+
+
ColVis

ColVis provides column visiblity control for DataTables

+
+
+
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/css/doc.css b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/css/doc.css new file mode 100644 index 0000000..a239329 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/css/doc.css @@ -0,0 +1,393 @@ +/* +Copyright (c) 2006, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 0.12.0 +*/ +body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;} +table{border-collapse:collapse;border-spacing:0;} +fieldset,img{border:0;} +address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;} +ol,ul {list-style:none;} +caption,th {text-align:left;} +h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;} +q:before,q:after{content:'';} +abbr,acronym {border:0;} + + +html, body { + margin: 0; + padding: 0; + width: 100%; + font: 14px/1.45em "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; + color: #111; +} + +div.fw_container { + width: 980px; + padding-top: 2em; + margin: 0 auto; +} + +div.fw_header { + position: relative; +} + +div.fw_content { + padding-top: 2em; +} + +div.fw_footer { + padding-top: 4em; + font-size: 75%; + text-align: center; +} + + + + +.type-attr .type-signature { + background-color: #ccc; + color: white; + border-radius: 3px; + display: inline-block; + padding: 0 3px; + font-size: 0.9em; +} + +.type-attr { + float: right; + color: #999; +} + +.type-name { + font-weight: bold; +} + +.type-sig { + color: #999; +} + +.type-param { + color: #D32929; +} + +.type-return { + color: #FF8080; +} + +.type-brace { + color: #111; +} + +.example-code { + margin-left: 30px; +} +.example-code td.code { + border-top: 1px solid #4E6CA3 !important; +} + +.type-augmented { + position: absolute; + left: 8px; + top: 0; +} + +dt, dd { + padding: 0.4em 10px; +} + +dt { + padding-bottom: 0 !important; +} + +dd { + position: relative; + padding-top: 0 !important; + padding-left: 3em; +} + +dt.even, dd.even { + background-color: white; +} + +dt.odd, dd.odd { + background-color: #F2F2F2; +} + +div.doc_overview dd, div.doc_overview dt { + padding-left: 0 !important; +} + + + +.right_border div { + width: 20px; + padding: 2px 0.5em 2px 1em; + text-align: right; +} +.right_border { + border-right: 3px solid #4E6CA3; +} +.bottom_border { + border-bottom: 1px solid #4E6CA3; +} + + +a { + text-decoration: none; + color: #4E6CA3; +} + +a:hover { + text-decoration: underline; + cursor: pointer; + *cursor: hand; +} + +div.fw_content ul { + list-style-image: url('../images/arrow.png'); + padding: 0 0 0 2em; +} + +/* +h2 { + font-size: 1.4em; + margin-top: 2em; + border-bottom: 3px solid #829ac6; + padding-left: 5px; +} + +h3 { + font-size: 1.2em; + margin-top: 1em; + border-bottom: 1px solid #A4B5D5; + padding-left: 5px; +} +*/ + +h1 { + font-size: 2em; +} + +h2 { + font-size: 1.6em; + padding-top: 5px; +} + +h2.ancestors { + font-size: 14px; + margin: 0; +} + +h3 { + font-size: 1.3em; + padding-top: 5px; + margin-bottom: 5px; +} + +h5 { + padding-top: 6px; + font-weight: bold; + font-size: 0.9em; + border-bottom: 1px solid #cad4e6; + margin-bottom: 1em; +} + +div.doc_summary, div.doc_details { + margin-top: 2em; + clear: both; +} + +div.doc_group { + margin-top: 1em; + border-top: 1px solid #A4B5D5; + border-left: 1px solid #A4B5D5; + padding-left: 10px; +} + +div.extended { + margin-left: 30px; +} + +table.params { + margin-left: 30px; + width: 97%; +} + +table.params th, +table.params td { + padding: 3px; +} + +tr.odd { + background-color: white; +} + +tr.even { + background-color: #F8F8F8; +} + +th.name, +td.name { + padding-left: 13px; +} + +td.number { + background-color: white; + color: #5C5C5C; +} + +dd.odd td.number { + background-color: #F2F2F2; +} + +p { + margin: 1em 0; +} + +p:first-child { + margin-top: 0; +} + +p:last-child { + margin-bottom: 0; +} + +p.returns { + margin-left: 5%; +} + +div.page-info { + position: absolute; + top: 0; + right: 0; +} + + +.private { + display: none; +} + + +code { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + padding: 2px 4px !important; + white-space: pre; + font-size: 0.9em; + + color: #D14; + background-color: #F7F7F9; + + border: 1px solid #E1E1E8; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +pre { + background-color: #f8f8f8; + border: 1px solid #ccc; + border-radius: 3px; + padding: 6px 10px; +} + +pre>code { + background-color: transparent; + border: none; + color: #111; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +ol { + list-style-type: decimal; + list-style-position: outside; + padding-left: 30px; +} + + + +div.fw_nav { + position: fixed; + top: 25px; + right: 30px; + width: 250px; + border: 1px solid #A4B5D5; + background-color: white; + padding: 10px; + z-index: 1001; + font-size: 12px; + overflow: hidden; +} + +div.fw_nav h2 { + margin: -10px 0 10px -10px; + width: 250px; + padding: 5px 10px; + background-color: #A4B5D5; + font-size: 12px; + cursor: pointer; + *cursor: hand; +} + +div.fw_nav ul>li>div { + padding: 0 0 0 1em; +} + +div.nav_blocker { + float: right; +} + +div.fw_nav td { + color: #999; +} + +div.fw_nav li { + margin-bottom: 5px; +} + +div.fw_nav li>a { + font-weight: bold; +} + + + + + + + +.css_clear { + clear: both; + height: 0; + line-height: 0; + visibility: hidden; +} + +.css_right { + text-align: right; +} + +.css_center { + text-align: center; +} + +.css_spacing { + margin-top: 1.5em; +} + +.css_small { + font-size: 75%; + line-height: 1.45em; +} + +.css_vsmall { + font-size: 65%; + line-height: 1.45em; +} diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/css/shCore.css b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/css/shCore.css new file mode 100644 index 0000000..b0c4520 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/css/shCore.css @@ -0,0 +1,226 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter a, +.syntaxhighlighter div, +.syntaxhighlighter code, +.syntaxhighlighter table, +.syntaxhighlighter table td, +.syntaxhighlighter table tr, +.syntaxhighlighter table tbody, +.syntaxhighlighter table thead, +.syntaxhighlighter table caption, +.syntaxhighlighter textarea { + -moz-border-radius: 0 0 0 0 !important; + -webkit-border-radius: 0 0 0 0 !important; + background: none !important; + border: 0 !important; + bottom: auto !important; + float: none !important; + height: auto !important; + left: auto !important; + line-height: 1.1em !important; + margin: 0 !important; + outline: 0 !important; + overflow: visible !important; + padding: 0 !important; + position: static !important; + right: auto !important; + text-align: left !important; + top: auto !important; + vertical-align: baseline !important; + width: auto !important; + box-sizing: content-box !important; + font-family: "Consolas","Monaco","Bitstream Vera Sans Mono","Courier New",Courier,monospace !important; + font-weight: normal !important; + font-style: normal !important; + font-size: 1em !important; + min-height: inherit !important; + min-height: auto !important; +} + +.syntaxhighlighter { + width: 100% !important; + margin: 1em 0 1em 0 !important; + position: relative !important; + overflow: auto !important; + font-size: 1em !important; +} +.syntaxhighlighter.source { + overflow: hidden !important; +} +.syntaxhighlighter .bold { + font-weight: bold !important; +} +.syntaxhighlighter .italic { + font-style: italic !important; +} +.syntaxhighlighter .line { + white-space: pre !important; +} +.syntaxhighlighter table { + width: 100% !important; +} +.syntaxhighlighter table caption { + text-align: left !important; + padding: .5em 0 0.5em 1em !important; +} +.syntaxhighlighter table td.code { + width: 100% !important; +} +.syntaxhighlighter table td.code .container { + position: relative !important; +} +.syntaxhighlighter table td.code .container textarea { + box-sizing: border-box !important; + position: absolute !important; + left: 0 !important; + top: 0 !important; + width: 100% !important; + height: 100% !important; + border: none !important; + background: white !important; + padding-left: 1em !important; + overflow: hidden !important; + white-space: pre !important; +} +.syntaxhighlighter table td.gutter .line { + text-align: right !important; + padding: 2px 0.5em 2px 1em !important; +} +.syntaxhighlighter table td.code .line { + padding: 2px 1em !important; +} +.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { + padding-left: 0em !important; +} +.syntaxhighlighter.show { + display: block !important; +} +.syntaxhighlighter.collapsed table { + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar { + padding: 0.1em 0.8em 0em 0.8em !important; + font-size: 1em !important; + position: static !important; + width: auto !important; + height: auto !important; +} +.syntaxhighlighter.collapsed .toolbar span { + display: inline !important; + margin-right: 1em !important; +} +.syntaxhighlighter.collapsed .toolbar span a { + padding: 0 !important; + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar span a.expandSource { + display: inline !important; +} +.syntaxhighlighter .toolbar { + position: absolute !important; + right: 1px !important; + top: 1px !important; + width: 11px !important; + height: 11px !important; + font-size: 10px !important; + z-index: 10 !important; +} +.syntaxhighlighter .toolbar span.title { + display: inline !important; +} +.syntaxhighlighter .toolbar a { + display: block !important; + text-align: center !important; + text-decoration: none !important; + padding-top: 1px !important; +} +.syntaxhighlighter .toolbar a.expandSource { + display: none !important; +} +.syntaxhighlighter.ie { + font-size: .9em !important; + padding: 1px 0 1px 0 !important; +} +.syntaxhighlighter.ie .toolbar { + line-height: 8px !important; +} +.syntaxhighlighter.ie .toolbar a { + padding-top: 0px !important; +} +.syntaxhighlighter.printing .line.alt1 .content, +.syntaxhighlighter.printing .line.alt2 .content, +.syntaxhighlighter.printing .line.highlighted .number, +.syntaxhighlighter.printing .line.highlighted.alt1 .content, +.syntaxhighlighter.printing .line.highlighted.alt2 .content { + background: none !important; +} +.syntaxhighlighter.printing .line .number { + color: #bbbbbb !important; +} +.syntaxhighlighter.printing .line .content { + color: black !important; +} +.syntaxhighlighter.printing .toolbar { + display: none !important; +} +.syntaxhighlighter.printing a { + text-decoration: none !important; +} +.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { + color: black !important; +} +.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { + color: #008200 !important; +} +.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { + color: blue !important; +} +.syntaxhighlighter.printing .keyword { + color: #006699 !important; + font-weight: bold !important; +} +.syntaxhighlighter.printing .preprocessor { + color: gray !important; +} +.syntaxhighlighter.printing .variable { + color: #aa7700 !important; +} +.syntaxhighlighter.printing .value { + color: #009900 !important; +} +.syntaxhighlighter.printing .functions { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .constants { + color: #0066cc !important; +} +.syntaxhighlighter.printing .script { + font-weight: bold !important; +} +.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { + color: gray !important; +} +.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { + color: red !important; +} +.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { + color: black !important; +} diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/css/shThemeDataTables.css b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/css/shThemeDataTables.css new file mode 100644 index 0000000..7e9790a --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/css/shThemeDataTables.css @@ -0,0 +1,128 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter { + background-color: white !important; + font-size: 14px !important; + overflow: visible !important; +} +.syntaxhighlighter .line.alt1 { + background-color: white !important; +} +.syntaxhighlighter .line.alt2 { + background-color: #F8F8F8 !important; +} +.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { + background-color: #e0e0e0 !important; +} +.syntaxhighlighter .line.highlighted.number { + color: black !important; +} +.syntaxhighlighter table caption { + color: black !important; +} +.syntaxhighlighter .gutter { +} +.syntaxhighlighter .gutter div { + color: #5C5C5C !important; + width: 20px !important; +} +.syntaxhighlighter .gutter .line.alt1, .syntaxhighlighter .gutter .line.alt2 { + background-color: white !important; +} +.odd .syntaxhighlighter .gutter .line.alt1, .odd .syntaxhighlighter .gutter .line.alt2 { + background-color: #F2F2F2 !important; +} +.syntaxhighlighter .gutter .line { + border-right: 3px solid #4E6CA3 !important; +} +.syntaxhighlighter .gutter .line.highlighted { + background-color: #4E6CA3 !important; + color: white !important; +} +.syntaxhighlighter.printing .line .content { + border: none !important; +} +.syntaxhighlighter.collapsed { + overflow: visible !important; +} +.syntaxhighlighter.collapsed .toolbar { + color: blue !important; + background: white !important; + border: 1px solid #4E6CA3 !important; +} +.syntaxhighlighter.collapsed .toolbar a { + color: blue !important; +} +.syntaxhighlighter.collapsed .toolbar a:hover { + color: red !important; +} +.syntaxhighlighter .toolbar { + color: white !important; + background: #4E6CA3 !important; + border: none !important; +} +.syntaxhighlighter .toolbar a { + color: white !important; +} +.syntaxhighlighter .toolbar a:hover { + color: black !important; +} +.syntaxhighlighter .plain, .syntaxhighlighter .plain a { + color: black !important; +} +.syntaxhighlighter .comments, .syntaxhighlighter .comments a { + color: #008200 !important; +} +.syntaxhighlighter .string, .syntaxhighlighter .string a { + color: blue !important; +} +.syntaxhighlighter .keyword { + color: #006699 !important; +} +.syntaxhighlighter .preprocessor { + color: gray !important; +} +.syntaxhighlighter .variable { + color: #aa7700 !important; +} +.syntaxhighlighter .value { + color: #009900 !important; +} +.syntaxhighlighter .functions { + color: #ff1493 !important; +} +.syntaxhighlighter .constants { + color: #0066cc !important; +} +.syntaxhighlighter .script { + font-weight: bold !important; + color: #006699 !important; + background-color: none !important; +} +.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { + color: gray !important; +} +.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { + color: red !important; +} + +.syntaxhighlighter .keyword { + font-weight: bold !important; +} diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/images/arrow.jpg b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/images/arrow.jpg new file mode 100644 index 0000000..eba85ea Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/images/arrow.jpg differ diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/images/arrow.png b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/images/arrow.png new file mode 100644 index 0000000..08dbbb1 Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/images/arrow.png differ diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/images/extended.png b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/images/extended.png new file mode 100644 index 0000000..5dd01bf Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/images/extended.png differ diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/js/doc.js b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/js/doc.js new file mode 100644 index 0000000..932d7cf --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/media/docs/media/js/doc.js @@ -0,0 +1,121 @@ + +(function() { + +var showingNav = true; + +$(document).ready( function () { + var jqNav = $('div.fw_nav'); + jqNav.css('right', ($(window).width() - $('div.fw_container').width()) /2); + + var n = $('div.nav_blocker')[0]; + n.style.height = $(jqNav).outerHeight()+"px"; + n.style.width = ($(jqNav).outerWidth()+20)+"px"; + + SyntaxHighlighter.highlight(); + + $('#private_toggle').click( function () { + if ( $('input[name=show_private]').val() == 0 ) { + $('input[name=show_private]').val( 1 ); + $('#private_label').html('Showing'); + $('.private').css('display', 'block'); + } else { + $('input[name=show_private]').val( 0 ); + $('#private_label').html('Hiding'); + $('.private').css('display', 'none'); + } + fnWriteCookie(); + return false; + } ); + + $('#extended_toggle').click( function () { + if ( $('input[name=show_extended]').val() == 0 ) { + $('input[name=show_extended]').val( 1 ); + $('#extended_label').html('Showing'); + $('.augmented').css('display', 'block'); + } else { + $('input[name=show_extended]').val( 0 ); + $('#extended_label').html('Hiding'); + $('.augmented').css('display', 'none'); + } + fnWriteCookie(); + return false; + } ); + + var savedHeight = $(jqNav).height(); + $('div.fw_nav h2').click( function () { + if ( showingNav ) { + $('div.fw_nav').animate( { + "height": 10, + "opacity": 0.3 + } ); + showingNav = false; + } else { + $('div.fw_nav').animate( { + "height": savedHeight, + "opacity": 1 + } ); + showingNav = true; + } + fnWriteCookie(); + } ); + + var cookie = fnReadCookie( 'SpryMedia_JSDoc' ); + if ( cookie != null ) { + var a = cookie.split('-'); + if ( a[0] == 1 ) { + $('#private_toggle').click(); + } + if ( a[1] == 0 ) { + $('#extended_toggle').click(); + } + if ( a[2] == 'false' ) { + $('div.fw_nav').css('height', 10).css('opacity', 0.3); + showingNav = false; + } + } +} ); + + +function fnWriteCookie() +{ + var sVal = + $('input[name=show_private]').val()+'-'+ + $('input[name=show_extended]').val()+'-'+ + showingNav; + + fnCreateCookie( 'SpryMedia_JSDoc', sVal ); +} + + +function fnCreateCookie( sName, sValue ) +{ + var iDays = 365; + var date = new Date(); + date.setTime( date.getTime()+(iDays*24*60*60*1000) ); + var sExpires = "; expires="+date.toGMTString(); + + document.cookie = sName+"="+sValue+sExpires+"; path=/"; +} + + +function fnReadCookie( sName ) +{ + var sNameEQ = sName + "="; + var sCookieContents = document.cookie.split(';'); + + for( var i=0 ; i)[^>]*$|#([\w\-]+)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Check for digits + rdigit = /\d/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // Has the ready events already been bound? + readyBound = false, + + // The deferred used on DOM ready + readyList, + + // Promise methods + promiseMethods = "then done fail isResolved isRejected promise".split( " " ), + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = "body"; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = (context ? context.ownerDocument || context : document); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; + } + + return jQuery.merge( this, selector ); + + // 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: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if (selector.selector !== undefined) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.5.1", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // 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 + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + (this.selector ? " " : "") + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // 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 ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.done( fn ); + + return this; + }, + + eq: function( i ) { + return i === -1 ? + this.slice( i ) : + this.slice( i, +i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + 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: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // 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 ( length === i ) { + 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({ + noConflict: function( deep ) { + window.$ = _$; + + if ( deep ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // 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, + + // Handle when the DOM is ready + ready: function( wait ) { + // A third-party is pushing the ready event forwards + if ( wait === true ) { + jQuery.readyWait--; + } + + // Make sure that the DOM is not already loaded + if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // 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" ).unbind( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyBound ) { + return; + } + + readyBound = true; + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent("onreadystatechange", DOMContentLoaded); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // 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"; + }, + + // A crude way of determining if an object is a window + isWindow: function( obj ) { + return obj && typeof obj === "object" && "setInterval" in obj; + }, + + isNaN: function( obj ) { + return obj == null || !rdigit.test( obj ) || isNaN( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // 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; + } + + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw msg; + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test(data.replace(rvalidescape, "@") + .replace(rvalidtokens, "]") + .replace(rvalidbraces, "")) ) { + + // Try to use the native JSON parser first + return window.JSON && window.JSON.parse ? + window.JSON.parse( data ) : + (new Function("return " + data))(); + + } else { + jQuery.error( "Invalid JSON: " + data ); + } + }, + + // Cross-browser xml parsing + // (xml & tmp used internally) + parseXML: function( data , xml , tmp ) { + + 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 ); + } + + tmp = xml.documentElement; + + if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) { + jQuery.error( "Invalid XML: " + data ); + } + + return xml; + }, + + noop: function() {}, + + // Evalulates a script in a global context + globalEval: function( data ) { + if ( data && rnotwhite.test(data) ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement, + script = document.createElement( "script" ); + + if ( jQuery.support.scriptEval() ) { + script.appendChild( document.createTextNode( data ) ); + } else { + script.text = data; + } + + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709). + head.insertBefore( script, head.firstChild ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction(object); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( var value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // The extra typeof function check is to prevent crashes + // in Safari 2 (See: #3039) + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type(array); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var ret = [], value; + + // Go through the array, translating each of the items to their + // new value (or values). + for ( var i = 0, length = elems.length; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + proxy: function( fn, proxy, thisObject ) { + if ( arguments.length === 2 ) { + if ( typeof proxy === "string" ) { + thisObject = fn; + fn = thisObject[ proxy ]; + proxy = undefined; + + } else if ( proxy && !jQuery.isFunction( proxy ) ) { + thisObject = proxy; + proxy = undefined; + } + } + + if ( !proxy && fn ) { + proxy = function() { + return fn.apply( thisObject || this, arguments ); + }; + } + + // Set the guid of unique handler to the same of original handler, so it can be removed + if ( fn ) { + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + } + + // So proxy can be declared as an argument + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can be optionally by executed if its a function + access: function( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + jQuery.access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : undefined; + }, + + now: function() { + return (new Date()).getTime(); + }, + + // Create a simple deferred (one callbacks list) + _Deferred: function() { + var // callbacks list + callbacks = [], + // stored [ context , args ] + fired, + // to avoid firing when already doing so + firing, + // flag to know if the deferred has been cancelled + cancelled, + // the deferred itself + deferred = { + + // done( f1, f2, ...) + done: function() { + if ( !cancelled ) { + var args = arguments, + i, + length, + elem, + type, + _fired; + if ( fired ) { + _fired = fired; + fired = 0; + } + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + deferred.done.apply( deferred, elem ); + } else if ( type === "function" ) { + callbacks.push( elem ); + } + } + if ( _fired ) { + deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); + } + } + return this; + }, + + // resolve with given context and args + resolveWith: function( context, args ) { + if ( !cancelled && !fired && !firing ) { + firing = 1; + try { + while( callbacks[ 0 ] ) { + callbacks.shift().apply( context, args ); + } + } + // We have to add a catch block for + // IE prior to 8 or else the finally + // block will never get executed + catch (e) { + throw e; + } + finally { + fired = [ context, args ]; + firing = 0; + } + } + return this; + }, + + // resolve with this as context and given arguments + resolve: function() { + deferred.resolveWith( jQuery.isFunction( this.promise ) ? this.promise() : this, arguments ); + return this; + }, + + // Has this deferred been resolved? + isResolved: function() { + return !!( firing || fired ); + }, + + // Cancel + cancel: function() { + cancelled = 1; + callbacks = []; + return this; + } + }; + + return deferred; + }, + + // Full fledged deferred (two callbacks list) + Deferred: function( func ) { + var deferred = jQuery._Deferred(), + failDeferred = jQuery._Deferred(), + promise; + // Add errorDeferred methods, then and promise + jQuery.extend( deferred, { + then: function( doneCallbacks, failCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ); + return this; + }, + fail: failDeferred.done, + rejectWith: failDeferred.resolveWith, + reject: failDeferred.resolve, + isRejected: failDeferred.isResolved, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + if ( promise ) { + return promise; + } + promise = obj = {}; + } + var i = promiseMethods.length; + while( i-- ) { + obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; + } + return obj; + } + } ); + // Make sure only one callback list will be used + deferred.done( failDeferred.cancel ).fail( deferred.cancel ); + // Unexpose cancel + delete deferred.cancel; + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + return deferred; + }, + + // Deferred helper + when: function( object ) { + var lastIndex = arguments.length, + deferred = lastIndex <= 1 && object && jQuery.isFunction( object.promise ) ? + object : + jQuery.Deferred(), + promise = deferred.promise(); + + if ( lastIndex > 1 ) { + var array = slice.call( arguments, 0 ), + count = lastIndex, + iCallback = function( index ) { + return function( value ) { + array[ index ] = arguments.length > 1 ? slice.call( arguments, 0 ) : value; + if ( !( --count ) ) { + deferred.resolveWith( promise, array ); + } + }; + }; + while( ( lastIndex-- ) ) { + object = array[ lastIndex ]; + if ( object && jQuery.isFunction( object.promise ) ) { + object.promise().then( iCallback(lastIndex), deferred.reject ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( promise, array ); + } + } else if ( deferred !== object ) { + deferred.resolve( object ); + } + return promise; + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySubclass( selector, context ) { + return new jQuerySubclass.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySubclass, this ); + jQuerySubclass.superclass = this; + jQuerySubclass.fn = jQuerySubclass.prototype = this(); + jQuerySubclass.fn.constructor = jQuerySubclass; + jQuerySubclass.subclass = this.subclass; + jQuerySubclass.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySubclass) ) { + context = jQuerySubclass(context); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass ); + }; + jQuerySubclass.fn.init.prototype = jQuerySubclass.fn; + var rootjQuerySubclass = jQuerySubclass(document); + return jQuerySubclass; + }, + + browser: {} +}); + +// Create readyList deferred +readyList = jQuery._Deferred(); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +if ( indexOf ) { + jQuery.inArray = function( elem, array ) { + return indexOf.call( array, elem ); + }; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +// Expose jQuery to the global object +return jQuery; + +})(); + + +(function() { + + jQuery.support = {}; + + var div = document.createElement("div"); + + div.style.display = "none"; + div.innerHTML = "
a"; + + var all = div.getElementsByTagName("*"), + a = div.getElementsByTagName("a")[0], + select = document.createElement("select"), + opt = select.appendChild( document.createElement("option") ), + input = div.getElementsByTagName("input")[0]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return; + } + + jQuery.support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: div.firstChild.nodeType === 3, + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText insted) + style: /red/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: a.getAttribute("href") === "/a", + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55$/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: input.value === "on", + + // 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) + optSelected: opt.selected, + + // Will be defined later + deleteExpando: true, + optDisabled: false, + checkClone: false, + noCloneEvent: true, + noCloneChecked: true, + boxModel: null, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableHiddenOffsets: true + }; + + input.checked = true; + jQuery.support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as diabled) + select.disabled = true; + jQuery.support.optDisabled = !opt.disabled; + + var _scriptEval = null; + jQuery.support.scriptEval = function() { + if ( _scriptEval === null ) { + var root = document.documentElement, + script = document.createElement("script"), + id = "script" + jQuery.now(); + + try { + script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); + } catch(e) {} + + root.insertBefore( script, root.firstChild ); + + // Make sure that the execution of code works by injecting a script + // tag with appendChild/createTextNode + // (IE doesn't support this, fails, and uses .text instead) + if ( window[ id ] ) { + _scriptEval = true; + delete window[ id ]; + } else { + _scriptEval = false; + } + + root.removeChild( script ); + // release memory in IE + root = script = id = null; + } + + return _scriptEval; + }; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + + } catch(e) { + jQuery.support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent("onclick", function click() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + jQuery.support.noCloneEvent = false; + div.detachEvent("onclick", click); + }); + div.cloneNode(true).fireEvent("onclick"); + } + + div = document.createElement("div"); + div.innerHTML = ""; + + var fragment = document.createDocumentFragment(); + fragment.appendChild( div.firstChild ); + + // WebKit doesn't clone checked state correctly in fragments + jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; + + // Figure out if the W3C box model works as expected + // document.body must exist before we can do this + jQuery(function() { + var div = document.createElement("div"), + body = document.getElementsByTagName("body")[0]; + + // Frameset documents with no body should not run this code + if ( !body ) { + return; + } + + div.style.width = div.style.paddingLeft = "1px"; + body.appendChild( div ); + jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; + + if ( "zoom" in div.style ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2; + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
"; + jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2; + } + + div.innerHTML = "
t
"; + var tds = div.getElementsByTagName("td"); + + // 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). + // (only IE 8 fails this test) + jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0; + + tds[0].style.display = ""; + tds[1].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE < 8 fail this test) + jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0; + div.innerHTML = ""; + + body.removeChild( div ).style.display = "none"; + div = tds = null; + }); + + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + var eventSupported = function( eventName ) { + var el = document.createElement("div"); + eventName = "on" + eventName; + + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( !el.attachEvent ) { + return true; + } + + var isSupported = (eventName in el); + if ( !isSupported ) { + el.setAttribute(eventName, "return;"); + isSupported = typeof el[eventName] === "function"; + } + el = null; + + return isSupported; + }; + + jQuery.support.submitBubbles = eventSupported("submit"); + jQuery.support.changeBubbles = eventSupported("change"); + + // release memory in IE + div = all = a = null; +})(); + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache, + + // 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[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; + + // 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 || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) { + 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 ) { + elem[ jQuery.expando ] = id = ++jQuery.uuid; + } else { + id = jQuery.expando; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].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 ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); + } else { + cache[ id ] = jQuery.extend(cache[ id ], name); + } + } + + thisCache = cache[ id ]; + + // Internal jQuery data is stored in a separate object inside the object's data + // cache in order to avoid key collisions between internal data and user-defined + // data + if ( pvt ) { + if ( !thisCache[ internalKey ] ) { + thisCache[ internalKey ] = {}; + } + + thisCache = thisCache[ internalKey ]; + } + + if ( data !== undefined ) { + thisCache[ name ] = data; + } + + // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should + // not attempt to inspect the internal events object using jQuery.data, as this + // internal data object is undocumented and subject to change. + if ( name === "events" && !thisCache[name] ) { + return thisCache[ internalKey ] && thisCache[ internalKey ].events; + } + + return getByName ? thisCache[ name ] : thisCache; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + 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 ) { + var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; + + if ( thisCache ) { + delete thisCache[ name ]; + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !isEmptyDataObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( pvt ) { + delete cache[ id ][ internalKey ]; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + var internalCache = cache[ id ][ internalKey ]; + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + if ( jQuery.support.deleteExpando || cache != window ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the entire user cache at once because it's faster than + // iterating through each key, but we need to continue to persist internal + // data if it existed + if ( internalCache ) { + cache[ id ] = {}; + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + + cache[ id ][ internalKey ] = internalCache; + + // Otherwise, we need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + } else if ( isNode ) { + // 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 ( jQuery.support.deleteExpando ) { + delete elem[ jQuery.expando ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( jQuery.expando ); + } else { + elem[ jQuery.expando ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var data = null; + + if ( typeof key === "undefined" ) { + if ( this.length ) { + data = jQuery.data( this[0] ); + + if ( this[0].nodeType === 1 ) { + var attr = this[0].attributes, name; + for ( var i = 0, l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = name.substr( 5 ); + dataAttr( this[0], name, data[ name ] ); + } + } + } + } + + return data; + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + // Try to fetch any internally stored data first + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + data = dataAttr( this[0], key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + + } else { + return this.each(function() { + var $this = jQuery( this ), + args = [ parts[0], value ]; + + $this.triggerHandler( "setData" + parts[1] + "!", args ); + jQuery.data( this, key, value ); + $this.triggerHandler( "changeData" + parts[1] + "!", args ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +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 ) { + data = elem.getAttribute( "data-" + key ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + !jQuery.isNaN( data ) ? parseFloat( 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; +} + +// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON +// property to be considered empty objects; this property always exists in +// order to make sure JSON.stringify does not expose internal metadata +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +jQuery.extend({ + queue: function( elem, type, data ) { + if ( !elem ) { + return; + } + + type = (type || "fx") + "queue"; + var q = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( !data ) { + return q || []; + } + + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + + } else { + q.push( data ); + } + + return q; + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(); + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift("inprogress"); + } + + fn.call(elem, function() { + jQuery.dequeue(elem, type); + }); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue", true ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function( i ) { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + type = type || "fx"; + + return this.queue( type, function() { + var elem = this; + setTimeout(function() { + jQuery.dequeue( elem, type ); + }, time ); + }); + }, + + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspaces = /\s+/, + rreturn = /\r/g, + rspecialurl = /^(?:href|src|style)$/, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rradiocheck = /^(?:radio|checkbox)$/i; + +jQuery.props = { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" +}; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name, fn ) { + return this.each(function(){ + jQuery.attr( this, name, "" ); + if ( this.nodeType === 1 ) { + this.removeAttribute( name ); + } + }); + }, + + addClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.addClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( value && typeof value === "string" ) { + var classNames = (value || "").split( rspaces ); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className ) { + elem.className = value; + + } else { + var className = " " + elem.className + " ", + setClass = elem.className; + + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { + setClass += " " + classNames[c]; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.removeClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + var classNames = (value || "").split( rspaces ); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + var className = (" " + elem.className + " ").replace(rclass, " "); + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[c] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this); + self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspaces ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " "; + for ( var i = 0, l = this.length; i < l; i++ ) { + if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + if ( !arguments.length ) { + var elem = this[0]; + + if ( elem ) { + if ( jQuery.nodeName( elem, "option" ) ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.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 ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + } + + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { + return elem.getAttribute("value") === null ? "on" : elem.value; + } + + // Everything else, we just grab the value + return (elem.value || "").replace(rreturn, ""); + + } + + return undefined; + } + + var isFunction = jQuery.isFunction(value); + + return this.each(function(i) { + var self = jQuery(this), val = value; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call(this, i, self.val()); + } + + // 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 + ""; + }); + } + + if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { + this.checked = jQuery.inArray( self.val(), val ) >= 0; + + } else if ( jQuery.nodeName( this, "select" ) ) { + var values = jQuery.makeArray(val); + + jQuery( "option", this ).each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + this.selectedIndex = -1; + } + + } else { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) { + return undefined; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery(elem)[name](value); + } + + var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), + // Whether we are setting (or getting) + set = value !== undefined; + + // Try to normalize/fix the name + name = notxml && jQuery.props[ name ] || name; + + // Only do all the following if this is a node (faster for style) + if ( elem.nodeType === 1 ) { + // These attributes require special treatment + var special = rspecialurl.test( name ); + + // Safari mis-reports the default selected property of an option + // Accessing the parent's selectedIndex property fixes it + if ( name === "selected" && !jQuery.support.optSelected ) { + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + + // If applicable, access the attribute via the DOM 0 way + // 'in' checks fail in Blackberry 4.7 #6931 + if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) { + if ( set ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } + + if ( value === null ) { + if ( elem.nodeType === 1 ) { + elem.removeAttribute( name ); + } + + } else { + elem[ name ] = value; + } + } + + // browsers index elements by id/name on forms, give priority to attributes. + if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { + return elem.getAttributeNode( name ).nodeValue; + } + + // 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/ + if ( name === "tabIndex" ) { + var attributeNode = elem.getAttributeNode( "tabIndex" ); + + return attributeNode && attributeNode.specified ? + attributeNode.value : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + + return elem[ name ]; + } + + if ( !jQuery.support.style && notxml && name === "style" ) { + if ( set ) { + elem.style.cssText = "" + value; + } + + return elem.style.cssText; + } + + if ( set ) { + // convert the value to a string (all browsers do this but IE) see #1070 + elem.setAttribute( name, "" + value ); + } + + // Ensure that missing attributes return undefined + // Blackberry 4.7 returns "" from getAttribute #6938 + if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) { + return undefined; + } + + var attr = !jQuery.support.hrefNormalized && notxml && special ? + // Some attributes require a special call on IE + elem.getAttribute( name, 2 ) : + elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return attr === null ? undefined : attr; + } + // Handle everything which isn't a DOM element node + if ( set ) { + elem[ name ] = value; + } + return elem[ name ]; + } +}); + + + + +var rnamespaces = /\.(.*)$/, + rformElems = /^(?:textarea|input|select)$/i, + rperiod = /\./g, + rspace = / /g, + rescape = /[^\w\s.|`]/g, + fcleanup = function( nm ) { + return nm.replace(rescape, "\\$&"); + }; + +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code originated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + add: function( elem, types, handler, data ) { + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // TODO :: Use a try/catch until it's safe to pull this out (likely 1.6) + // Minor release fix for bug #8018 + try { + // For whatever reason, IE has trouble passing the window object + // around, causing it to be cloned in the process + if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) { + elem = window; + } + } + catch ( e ) {} + + if ( handler === false ) { + handler = returnFalse; + } else if ( !handler ) { + // Fixes bug #7229. Fix recommended by jdalton + return; + } + + var handleObjIn, handleObj; + + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure + var elemData = jQuery._data( elem ); + + // If no elemData is found then we must be trying to bind to one of the + // banned noData elements + if ( !elemData ) { + return; + } + + var events = elemData.events, + eventHandle = elemData.handle; + + if ( !events ) { + elemData.events = events = {}; + } + + if ( !eventHandle ) { + elemData.handle = eventHandle = function() { + // Handle the second event of a trigger and when + // an event is called after a page has unloaded + return typeof jQuery !== "undefined" && !jQuery.event.triggered ? + jQuery.event.handle.apply( eventHandle.elem, arguments ) : + undefined; + }; + } + + // Add elem as a property of the handle function + // This is to prevent a memory leak with non-native events in IE. + eventHandle.elem = elem; + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = types.split(" "); + + var type, i = 0, namespaces; + + while ( (type = types[ i++ ]) ) { + handleObj = handleObjIn ? + jQuery.extend({}, handleObjIn) : + { handler: handler, data: data }; + + // Namespaced event handlers + if ( type.indexOf(".") > -1 ) { + namespaces = type.split("."); + type = namespaces.shift(); + handleObj.namespace = namespaces.slice(0).sort().join("."); + + } else { + namespaces = []; + handleObj.namespace = ""; + } + + handleObj.type = type; + if ( !handleObj.guid ) { + handleObj.guid = handler.guid; + } + + // Get the current list of functions bound to this event + var handlers = events[ type ], + special = jQuery.event.special[ type ] || {}; + + // Init the event handler queue + if ( !handlers ) { + handlers = events[ type ] = []; + + // Check for a special event handler + // 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 the function to the element's handler list + handlers.push( handleObj ); + + // Keep track of which events have been used, for global triggering + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, pos ) { + // don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + if ( handler === false ) { + handler = returnFalse; + } + + var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + events = elemData && elemData.events; + + if ( !elemData || !events ) { + return; + } + + // types is actually an event object here + if ( types && types.type ) { + handler = types.handler; + types = types.type; + } + + // Unbind all events for the element + if ( !types || typeof types === "string" && types.charAt(0) === "." ) { + types = types || ""; + + for ( type in events ) { + jQuery.event.remove( elem, type + types ); + } + + return; + } + + // Handle multiple events separated by a space + // jQuery(...).unbind("mouseover mouseout", fn); + types = types.split(" "); + + while ( (type = types[ i++ ]) ) { + origType = type; + handleObj = null; + all = type.indexOf(".") < 0; + namespaces = []; + + if ( !all ) { + // Namespaced event handlers + namespaces = type.split("."); + type = namespaces.shift(); + + namespace = new RegExp("(^|\\.)" + + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + eventType = events[ type ]; + + if ( !eventType ) { + continue; + } + + if ( !handler ) { + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( all || namespace.test( handleObj.namespace ) ) { + jQuery.event.remove( elem, origType, handleObj.handler, j ); + eventType.splice( j--, 1 ); + } + } + + continue; + } + + special = jQuery.event.special[ type ] || {}; + + for ( j = pos || 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( handler.guid === handleObj.guid ) { + // remove the given handler for the given type + if ( all || namespace.test( handleObj.namespace ) ) { + if ( pos == null ) { + eventType.splice( j--, 1 ); + } + + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + + if ( pos != null ) { + break; + } + } + } + + // remove generic event handler if no more handlers exist + if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + ret = null; + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + var handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + delete elemData.events; + delete elemData.handle; + + if ( jQuery.isEmptyObject( elemData ) ) { + jQuery.removeData( elem, undefined, true ); + } + } + }, + + // bubbling is internal + trigger: function( event, data, elem /*, bubbling */ ) { + // Event object or event type + var type = event.type || event, + bubbling = arguments[3]; + + if ( !bubbling ) { + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + jQuery.extend( jQuery.Event(type), event ) : + // Just the event type (string) + jQuery.Event(type); + + if ( type.indexOf("!") >= 0 ) { + event.type = type = type.slice(0, -1); + event.exclusive = true; + } + + // Handle a global trigger + if ( !elem ) { + // Don't bubble custom events when global (to avoid too much overhead) + event.stopPropagation(); + + // Only trigger if we've ever bound an event for it + if ( jQuery.event.global[ type ] ) { + // XXX This code smells terrible. event.js should not be directly + // inspecting the data cache + jQuery.each( jQuery.cache, function() { + // internalKey variable is just used to make it easier to find + // and potentially change this stuff later; currently it just + // points to jQuery.expando + var internalKey = jQuery.expando, + internalCache = this[ internalKey ]; + if ( internalCache && internalCache.events && internalCache.events[ type ] ) { + jQuery.event.trigger( event, data, internalCache.handle.elem ); + } + }); + } + } + + // Handle triggering a single element + + // don't do events on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { + return undefined; + } + + // Clean up in case it is reused + event.result = undefined; + event.target = elem; + + // Clone the incoming data, if any + data = jQuery.makeArray( data ); + data.unshift( event ); + } + + event.currentTarget = elem; + + // Trigger the event, it is assumed that "handle" is a function + var handle = jQuery._data( elem, "handle" ); + + if ( handle ) { + handle.apply( elem, data ); + } + + var parent = elem.parentNode || elem.ownerDocument; + + // Trigger an inline bound script + try { + if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { + if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { + event.result = false; + event.preventDefault(); + } + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (inlineError) {} + + if ( !event.isPropagationStopped() && parent ) { + jQuery.event.trigger( event, data, parent, true ); + + } else if ( !event.isDefaultPrevented() ) { + var old, + target = event.target, + targetType = type.replace( rnamespaces, "" ), + isClick = jQuery.nodeName( target, "a" ) && targetType === "click", + special = jQuery.event.special[ targetType ] || {}; + + if ( (!special._default || special._default.call( elem, event ) === false) && + !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { + + try { + if ( target[ targetType ] ) { + // Make sure that we don't accidentally re-trigger the onFOO events + old = target[ "on" + targetType ]; + + if ( old ) { + target[ "on" + targetType ] = null; + } + + jQuery.event.triggered = true; + target[ targetType ](); + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (triggerError) {} + + if ( old ) { + target[ "on" + targetType ] = old; + } + + jQuery.event.triggered = false; + } + } + }, + + handle: function( event ) { + var all, handlers, namespaces, namespace_re, events, + namespace_sort = [], + args = jQuery.makeArray( arguments ); + + event = args[0] = jQuery.event.fix( event || window.event ); + event.currentTarget = this; + + // Namespaced event handlers + all = event.type.indexOf(".") < 0 && !event.exclusive; + + if ( !all ) { + namespaces = event.type.split("."); + event.type = namespaces.shift(); + namespace_sort = namespaces.slice(0).sort(); + namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + event.namespace = event.namespace || namespace_sort.join("."); + + events = jQuery._data(this, "events"); + + handlers = (events || {})[ event.type ]; + + if ( events && handlers ) { + // Clone the handlers to prevent manipulation + handlers = handlers.slice(0); + + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; + + // Filter the functions by class + if ( all || namespace_re.test( handleObj.namespace ) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handleObj.handler; + event.data = handleObj.data; + event.handleObj = handleObj; + + var ret = handleObj.handler.apply( this, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + } + + return event.result; + }, + + props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // store a copy of the original event object + // and "clone" to set read-only properties + var originalEvent = event; + event = jQuery.Event( originalEvent ); + + for ( var i = this.props.length, prop; i; ) { + prop = this.props[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary + if ( !event.target ) { + // Fixes #1925 where srcElement might not be defined either + event.target = event.srcElement || document; + } + + // check if target is a textnode (safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) { + event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; + } + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var doc = document.documentElement, + body = document.body; + + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); + } + + // Add which for key events + if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { + event.which = event.charCode != null ? event.charCode : event.keyCode; + } + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) { + event.metaKey = event.ctrlKey; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button !== undefined ) { + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + } + + return event; + }, + + // Deprecated, use jQuery.guid instead + guid: 1E8, + + // Deprecated, use jQuery.proxy instead + proxy: jQuery.proxy, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady, + teardown: jQuery.noop + }, + + live: { + add: function( handleObj ) { + jQuery.event.add( this, + liveConvert( handleObj.origType, handleObj.selector ), + jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); + }, + + remove: function( handleObj ) { + jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); + } + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src ) { + // Allow instantiation without the 'new' keyword + if ( !this.preventDefault ) { + return new jQuery.Event( src ); + } + + // 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.returnValue === false || + src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // timeStamp is buggy for some events on Firefox(#3843) + // So we won't rely on the native value + this.timeStamp = jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return 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 = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Checks if an event happened on an element within another element +// Used in jQuery.event.special.mouseenter and mouseleave handlers +var withinElement = function( event ) { + // Check if mouse(over|out) are still within the same parent element + var parent = event.relatedTarget; + + // Firefox sometimes assigns relatedTarget a XUL element + // which we cannot access the parentNode property of + try { + + // Chrome does something similar, the parentNode property + // can be accessed but is null. + if ( parent !== document && !parent.parentNode ) { + return; + } + // Traverse up the tree + while ( parent && parent !== this ) { + parent = parent.parentNode; + } + + if ( parent !== this ) { + // set the correct event type + event.type = event.data; + + // handle event if we actually just moused on to a non sub-element + jQuery.event.handle.apply( this, arguments ); + } + + // assuming we've left the element since we most likely mousedover a xul element + } catch(e) { } +}, + +// In case of event delegation, we only need to rename the event.type, +// liveHandler will take care of the rest. +delegate = function( event ) { + event.type = event.data; + jQuery.event.handle.apply( this, arguments ); +}; + +// Create mouseenter and mouseleave events +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + setup: function( data ) { + jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); + }, + teardown: function( data ) { + jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + } + }; +}); + +// submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function( data, namespaces ) { + if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) { + jQuery.event.add(this, "click.specialSubmit", function( e ) { + var elem = e.target, + type = elem.type; + + if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { + trigger( "submit", this, arguments ); + } + }); + + jQuery.event.add(this, "keypress.specialSubmit", function( e ) { + var elem = e.target, + type = elem.type; + + if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { + trigger( "submit", this, arguments ); + } + }); + + } else { + return false; + } + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialSubmit" ); + } + }; + +} + +// change delegation, happens here so we have bind. +if ( !jQuery.support.changeBubbles ) { + + var changeFilters, + + getVal = function( elem ) { + var type = elem.type, val = elem.value; + + if ( type === "radio" || type === "checkbox" ) { + val = elem.checked; + + } else if ( type === "select-multiple" ) { + val = elem.selectedIndex > -1 ? + jQuery.map( elem.options, function( elem ) { + return elem.selected; + }).join("-") : + ""; + + } else if ( elem.nodeName.toLowerCase() === "select" ) { + val = elem.selectedIndex; + } + + return val; + }, + + testChange = function testChange( e ) { + var elem = e.target, data, val; + + if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { + return; + } + + data = jQuery._data( elem, "_change_data" ); + val = getVal(elem); + + // the current data will be also retrieved by beforeactivate + if ( e.type !== "focusout" || elem.type !== "radio" ) { + jQuery._data( elem, "_change_data", val ); + } + + if ( data === undefined || val === data ) { + return; + } + + if ( data != null || val ) { + e.type = "change"; + e.liveFired = undefined; + jQuery.event.trigger( e, arguments[1], elem ); + } + }; + + jQuery.event.special.change = { + filters: { + focusout: testChange, + + beforedeactivate: testChange, + + click: function( e ) { + var elem = e.target, type = elem.type; + + if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { + testChange.call( this, e ); + } + }, + + // Change has to be called before submit + // Keydown will be called before keypress, which is used in submit-event delegation + keydown: function( e ) { + var elem = e.target, type = elem.type; + + if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || + (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || + type === "select-multiple" ) { + testChange.call( this, e ); + } + }, + + // Beforeactivate happens also before the previous element is blurred + // with this event you can't trigger a change event, but you can store + // information + beforeactivate: function( e ) { + var elem = e.target; + jQuery._data( elem, "_change_data", getVal(elem) ); + } + }, + + setup: function( data, namespaces ) { + if ( this.type === "file" ) { + return false; + } + + for ( var type in changeFilters ) { + jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); + } + + return rformElems.test( this.nodeName ); + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialChange" ); + + return rformElems.test( this.nodeName ); + } + }; + + changeFilters = jQuery.event.special.change.filters; + + // Handle when the input is .focus()'d + changeFilters.focus = changeFilters.beforeactivate; +} + +function trigger( type, elem, args ) { + // 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. + // Don't pass args or remember liveFired; they apply to the donor event. + var event = jQuery.extend( {}, args[ 0 ] ); + event.type = type; + event.originalEvent = {}; + event.liveFired = undefined; + jQuery.event.handle.call( elem, event ); + if ( event.isDefaultPrevented() ) { + args[ 0 ].preventDefault(); + } +} + +// Create "bubbling" focus and blur events +if ( document.addEventListener ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + jQuery.event.special[ fix ] = { + setup: function() { + this.addEventListener( orig, handler, true ); + }, + teardown: function() { + this.removeEventListener( orig, handler, true ); + } + }; + + function handler( e ) { + e = jQuery.event.fix( e ); + e.type = fix; + return jQuery.event.handle.call( this, e ); + } + }); +} + +jQuery.each(["bind", "one"], function( i, name ) { + jQuery.fn[ name ] = function( type, data, fn ) { + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this[ name ](key, data, type[key], fn); + } + return this; + } + + if ( jQuery.isFunction( data ) || data === false ) { + fn = data; + data = undefined; + } + + var handler = name === "one" ? jQuery.proxy( fn, function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }) : fn; + + if ( type === "unload" && name !== "one" ) { + this.one( type, data, fn ); + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.add( this[i], type, handler, data ); + } + } + + return this; + }; +}); + +jQuery.fn.extend({ + unbind: function( type, fn ) { + // Handle object literals + if ( typeof type === "object" && !type.preventDefault ) { + for ( var key in type ) { + this.unbind(key, type[key]); + } + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.remove( this[i], type, fn ); + } + } + + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.live( types, data, fn, selector ); + }, + + undelegate: function( selector, types, fn ) { + if ( arguments.length === 0 ) { + return this.unbind( "live" ); + + } else { + return this.die( types, null, fn, selector ); + } + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + + triggerHandler: function( type, data ) { + if ( this[0] ) { + var event = jQuery.Event( type ); + event.preventDefault(); + event.stopPropagation(); + jQuery.event.trigger( event, data, this[0] ); + return event.result; + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + i = 1; + + // link all the functions, so any of them can unbind this click handler + while ( i < args.length ) { + jQuery.proxy( fn, args[ i++ ] ); + } + + return this.click( jQuery.proxy( fn, function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + })); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +var liveMap = { + focus: "focusin", + blur: "focusout", + mouseenter: "mouseover", + mouseleave: "mouseout" +}; + +jQuery.each(["live", "die"], function( i, name ) { + jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { + var type, i = 0, match, namespaces, preType, + selector = origSelector || this.selector, + context = origSelector ? this : jQuery( this.context ); + + if ( typeof types === "object" && !types.preventDefault ) { + for ( var key in types ) { + context[ name ]( key, data, types[key], selector ); + } + + return this; + } + + if ( jQuery.isFunction( data ) ) { + fn = data; + data = undefined; + } + + types = (types || "").split(" "); + + while ( (type = types[ i++ ]) != null ) { + match = rnamespaces.exec( type ); + namespaces = ""; + + if ( match ) { + namespaces = match[0]; + type = type.replace( rnamespaces, "" ); + } + + if ( type === "hover" ) { + types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); + continue; + } + + preType = type; + + if ( type === "focus" || type === "blur" ) { + types.push( liveMap[ type ] + namespaces ); + type = type + namespaces; + + } else { + type = (liveMap[ type ] || type) + namespaces; + } + + if ( name === "live" ) { + // bind live handler + for ( var j = 0, l = context.length; j < l; j++ ) { + jQuery.event.add( context[j], "live." + liveConvert( type, selector ), + { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); + } + + } else { + // unbind live handler + context.unbind( "live." + liveConvert( type, selector ), fn ); + } + } + + return this; + }; +}); + +function liveHandler( event ) { + var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, + elems = [], + selectors = [], + events = jQuery._data( this, "events" ); + + // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) + if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { + return; + } + + if ( event.namespace ) { + namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + event.liveFired = this; + + var live = events.live.slice(0); + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { + selectors.push( handleObj.selector ); + + } else { + live.splice( j--, 1 ); + } + } + + match = jQuery( event.target ).closest( selectors, event.currentTarget ); + + for ( i = 0, l = match.length; i < l; i++ ) { + close = match[i]; + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { + elem = close.elem; + related = null; + + // Those two events require additional checking + if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { + event.type = handleObj.preType; + related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; + } + + if ( !related || related !== elem ) { + elems.push({ elem: elem, handleObj: handleObj, level: close.level }); + } + } + } + } + + for ( i = 0, l = elems.length; i < l; i++ ) { + match = elems[i]; + + if ( maxLevel && match.level > maxLevel ) { + break; + } + + event.currentTarget = match.elem; + event.data = match.handleObj.data; + event.handleObj = match.handleObj; + + ret = match.handleObj.origHandler.apply( match.elem, arguments ); + + if ( ret === false || event.isPropagationStopped() ) { + maxLevel = match.level; + + if ( ret === false ) { + stop = false; + } + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + + return stop; +} + +function liveConvert( type, selector ) { + return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&"); +} + +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").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.bind( name, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } +}); + + +/*! + * 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/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[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; + + // Reset the position of the chunker regexp (start from head) + 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 { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + 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; + } + } + } + + // Improper expression + 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]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + 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, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + 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]; + } + + // Handle if an un-quoted value was used + 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 we're dealing with a complex expression, or a simple one + 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 ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + 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 ) { + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return "text" === elem.getAttribute( 'type' ); + }, + radio: function( elem ) { + return "radio" === elem.type; + }, + + checkbox: function( elem ) { + return "checkbox" === elem.type; + }, + + file: function( elem ) { + return "file" === elem.type; + }, + password: function( elem ) { + return "password" === elem.type; + }, + + submit: function( elem ) { + return "submit" === elem.type; + }, + + image: function( elem ) { + return "image" === elem.type; + }, + + reset: function( elem ) { + return "reset" === elem.type; + }, + + button: function( elem ) { + return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + } + }, + 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; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} 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 ) { + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // If the nodes are siblings (or identical) we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + 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; + }; +} + +// Utility function for retreiving the text value of an array of DOM nodes +Sizzle.getText = function( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += Sizzle.getText( elem.childNodes ); + } + } + + return ret; +}; + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + 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 ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + 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; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

"; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // 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[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // 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 + } 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 ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector, + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + if ( matches ) { + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + return matches.call( node, expr ); + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
"; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + 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]); + } + }; + + // release memory in IE + 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 ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + 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; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + 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 ); +}; + +// EXPOSE +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.POS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var ret = this.pushStack( "", "find", selector ), + length = 0; + + for ( var i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( var n = length; n < ret.length; n++ ) { + for ( var r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && jQuery.filter( selector, this ).length > 0; + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + if ( jQuery.isArray( selectors ) ) { + var match, selector, + matches = {}, + level = 1; + + if ( cur && selectors.length ) { + for ( i = 0, l = selectors.length; i < l; i++ ) { + selector = selectors[i]; + + if ( !matches[selector] ) { + matches[selector] = jQuery.expr.match.POS.test( selector ) ? + jQuery( selector, context || this.context ) : + selector; + } + } + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( selector in matches ) { + match = matches[selector]; + + if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { + ret.push({ selector: selector, elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + } + + return ret; + } + + var pos = POS.test( selectors ) ? + jQuery( selectors, context || this.context ) : null; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique(ret) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + if ( !elem || typeof elem === "string" ) { + return jQuery.inArray( this[0], + // If it receives a string, the selector is used + // If it receives nothing, the siblings are used + elem ? jQuery( elem ) : this.parent().children() ); + } + // 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 ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +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 jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "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.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ), + // The variable 'args' was introduced in + // https://github.com/jquery/jquery/commit/52a0238 + // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. + // http://code.google.com/p/v8/issues/detail?id=1050 + args = slice.call(arguments); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, args.join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + 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; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return (elem === qualifier) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + }); +} + + + + +var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /", "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and + + + + + +
+
+ ColVis example - mouse over activation +
+ +

Preamble

+

The default activation (showing the columns list) for ColVis is for the user to click + the button. This can be altered to a 'mouseover' activation by making use of the + oColVis.activate DataTables initialisation value and setting it to "mouseover". This is + shown in the example below.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	$('#example').dataTable( {
+		"sDom": 'C<"clear">lfrtip',
+		"oColVis": {
+			"activate": "mouseover"
+		}
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/style.html b/modules/thirdparty/jquery/datatables/extras/ColVis/style.html new file mode 100755 index 0000000..b7cfa88 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/style.html @@ -0,0 +1,532 @@ + + + + + + + ColVis example + + + + + + + +
+
+ ColVis example with alternative styling +
+ +

Preamble

+

This demo of ColVis shows a number of different features of the plug-in. Firstly, it shows alternative styling of the plug-in with the button nested just above the scrollbar in the DataTable. Secondly there is a "Restore" button in the ColVis drop down, which will restore the original visibility settings when the table was initialised (this is controlled by using the "bRestore" option). Finally it shows that the drop down can be set to align on the right of the button, rather than the left.

+

Note that this demo requires DataTables 1.7.5 or later.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	$('#example').dataTable( {
+		"sDom": '<"H"fr>tC<"F"ip>',
+		"bJQueryUI": true,
+		"bPaginate": false,
+		"sScrollY": "200px",
+		"bScrollCollapse": true,
+		"bScrollAutoCss": false,
+		"aoColumnDefs": [
+			{ "bVisible": false, "aTargets": [ 2 ] }
+		],
+		"oColVis": {
+			"buttonText": "&nbsp;",
+			"bRestore": true,
+			"sAlign": "left"
+		},
+		"fnDrawCallback": function (o) {
+			/* Position the ColVis button as needed */
+			var nColVis = $('div.ColVis', o.nTableWrapper)[0];
+			nColVis.style.width = o.oScroll.iBarWidth+"px";
+			nColVis.style.top = ($('div.dataTables_scroll', o.nTableWrapper).position().top)+"px";
+			nColVis.style.height = ($('div.dataTables_scrollHead table', o.nTableWrapper).height())+"px";
+		}
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/text.html b/modules/thirdparty/jquery/datatables/extras/ColVis/text.html new file mode 100755 index 0000000..2167b4f --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/text.html @@ -0,0 +1,497 @@ + + + + + + + ColVis example + + + + + + + +
+
+ ColVis example - custom text +
+ +

Preamble

+

You may wish to use your own text in the ColVis button - this is done by making use of + the oColVis.buttonText DataTables initialisation parameter, as shown in this example.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	$('#example').dataTable( {
+		"sDom": 'C<"clear">lfrtip',
+		"oColVis": {
+			"buttonText": "Change columns"
+		}
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/theme.html b/modules/thirdparty/jquery/datatables/extras/ColVis/theme.html new file mode 100755 index 0000000..754a25f --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/theme.html @@ -0,0 +1,503 @@ + + + + + + + ColVis example + + + + + + + +
+
+ ColVis example with jQuery theming +
+ +

Preamble

+

ColVis will automatically add the classes required for theming with jQuery UI ThemeRoller + when enabled in DataTables. This example also shows a slightly altered position for the + ColVis button from the other example, in that it is included in the table toolbar. This + is achieved by simply moving the 'C' character in sDom.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	$('#example').dataTable( {
+		"sDom": '<"H"Cfr>t<"F"ip>',
+		"bJQueryUI": true
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/title_callback.html b/modules/thirdparty/jquery/datatables/extras/ColVis/title_callback.html new file mode 100755 index 0000000..7042ea4 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/title_callback.html @@ -0,0 +1,500 @@ + + + + + + + ColVis example + + + + + + + +
+
+ ColVis example +
+ +

Preamble

+

By default ColVis will use the information in the TH cell for each column as the button name to use in ColVis, which might not always be what you want (for example you might has HTML in the cell that you don't want in the button). The fnLabel callback provides the ability to customise the label used for the button. In this example the column index is prefixed to the column title.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	$('#example').dataTable( {
+		"sDom": 'C<"clear">lfrtip',
+		"oColVis": {
+		  "fnLabel": function ( index, title, th ) {
+		    return (index+1) +'. '+ title;
+		  }
+		}
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/two_tables.html b/modules/thirdparty/jquery/datatables/extras/ColVis/two_tables.html new file mode 100755 index 0000000..e6386bd --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/two_tables.html @@ -0,0 +1,296 @@ + + + + + + + ColVis example + + + + + + + +
+
+ ColVis example - two tables with individual controls +
+ +

Preamble

+

It can be useful to have DataTables initialise more than one table with a single call can for them to each have individual ColVis controllers. All this requires is a suitable jQuery selector to be used, and DataTables and ColVis will take care of the rest - as shown in this example.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	$('table').dataTable( {
+		"sDom": 'C<"clear">lfrtip'
+	} );
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/ColVis/two_tables_identical.html b/modules/thirdparty/jquery/datatables/extras/ColVis/two_tables_identical.html new file mode 100755 index 0000000..33031a2 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/ColVis/two_tables_identical.html @@ -0,0 +1,322 @@ + + + + + + + ColVis example + + + + + + + +
+
+ ColVis example - two tables with shared control +
+ +

Preamble

+

This example shows how the API that ColVis presents can be used to control the column visibility of two tables with a single instance of ColVis. The result is that changing a button state will effect all tables on the page. This can be useful when looking at multiple tables which have the same column structure.

+ +

Live example

+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
+
+
+
+ + +

Examples

+ + + +

Initialisation code

+
$(document).ready( function () {
+	var oTables = $('table').dataTable( {
+		"sDom": 'lfrtip'
+	} );
+	
+	var oColVis = new ColVis( oTables.fnSettings() );
+	$(oColVis).bind('stateChange', function (e, data) {
+		var jqTables = $('table:not(#example)');
+		for ( var i=0, iLen=jqTables.length ; i<iLen ; i++ ) {
+			$(jqTables[i]).dataTable().fnSetColumnVis( data.iColumn, data.bVisible );
+		}
+	} );
+	
+	document.getElementById('buttonInsert').appendChild(oColVis.dom.wrapper);
+	oColVis.fnRebuild();
+} );
+ + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/col_filter.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/col_filter.html new file mode 100755 index 0000000..9c06924 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/col_filter.html @@ -0,0 +1,613 @@ + + + + + + + ColReorder example + + + + + + + +
+
+ FixedColumns example - individual column filtering +
+ +

Preamble

+

This example shows a fairly complex example of FixedColumns in action. Primarily it shows + how multiple rows can be used in the THEAD or TFOOT element of the table such that you can + provide extra information. In this case it shows how a column filter could be implemented.

+ +

Live example

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+ (Entity: &)4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
Gecko (UTF-8: $¢€)Firefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+
+ + +

Initialisation code

+
$(document).ready(function() {
+	var oTable;
+	
+	/* Use the elements to store their own index */
+	$("thead input").each( function (i) {
+		this.visibleIndex = i;
+	} );
+	
+	$("thead input").keyup( function () {
+		/* If there is no visible index then we are in the cloned node */
+		var visIndex = typeof this.visibleIndex == 'undefined' ? 0 : this.visibleIndex;
+		
+		/* Filter on the column (the index) of this element */
+		oTable.fnFilter( this.value, visIndex );
+	} );
+	
+	/*
+	 * Support functions to provide a little bit of 'user friendlyness' to the textboxes
+	 */
+	$("thead input").each( function (i) {
+		this.initVal = this.value;
+	} );
+	
+	$("thead input").focus( function () {
+		if ( this.className == "search_init" )
+		{
+			this.className = "";
+			this.value = "";
+		}
+	} );
+	
+	$("thead input").blur( function (i) {
+		if ( this.value == "" )
+		{
+			this.className = "search_init";
+			this.value = this.initVal;
+		}
+	} );
+	
+	oTable = $('#example').dataTable( {
+		"sScrollX": "100%",
+		"sScrollXInner": "150%",
+		"bScrollCollapse": true,
+		"sDom": 'C<"clear">lfrtip',
+		"aoColumnDefs": [
+			{ "bVisible": false, "aTargets": [ 2 ] }
+		],
+		"oLanguage": {
+			"sSearch": "Search all columns:"
+		}
+	} );
+	new FixedColumns( oTable );
+} );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/css_size.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/css_size.html new file mode 100644 index 0000000..c47c2e2 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/css_size.html @@ -0,0 +1,528 @@ + + + + + + + FixedColumns example + + + + + + + +
+
+ FixedColumns example - CSS row sizing +
+ +

Preamble

+

Because of the method FixedColumns uses to display the fixed columns, an important consideration is the alignment of the rows due to different heights in the individual rows of the table. There are two different algorithms in FixedColumns which can be used, or you can switch off automatic row sizing all together. This is controlled through the sHeightMatch parameter. If can take the following values:

+ +
    +
  • "none" - no automatic row height matching is performed. CSS can be used in this case and is useful when speed is of primary importance.
  • +
  • "semiauto" (default) - the height calculation will be performed once, and the result cached to be used again (fnRecalculateHeight can be used to force recalculation)
  • +
  • "auto" - height matching is performed on every draw (slowest but must accurate)
  • +
+ +

This example shows row height matching switched off but there is a CSS statement of tr { height: 50px } to force all rows to the same height.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox
1.5
Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sScrollX": "100%",
+		"sScrollXInner": "150%",
+		"bScrollCollapse": true
+	} );
+	new FixedColumns( oTable );
+} );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/070023b890.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/070023b890.html new file mode 100644 index 0000000..f120317 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/070023b890.html @@ -0,0 +1,75 @@ + + + + + Namespace: left - documentation + + + + + + + + + +
+ + +
+

Namespace: left

+

Ancestry: FixedColumns » #dom » .grid. » left

+
+ FixedColumns v2.0.3 documentation +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +

Left fixed column grid components

+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/526f872207.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/526f872207.html new file mode 100644 index 0000000..c15ec83 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/526f872207.html @@ -0,0 +1,108 @@ + + + + + Namespace: grid - documentation + + + + + + + + + +
+ + +
+

Namespace: grid

+

Ancestry: FixedColumns » #dom. » grid

+
+ FixedColumns v2.0.3 documentation +
+
+ + + +
+

Navigation

+ +
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +

Display grid elements

+ +
+ +
+ + +
+ +

Summary

+ +

Namespaces

+
+
left

Left fixed column grid components

right

Right fixed column grid components

+

Properties - static

+ +
+
<static> dt :node

DataTables scrolling element. This element is the DataTables +component in the display grid (making up the main table - i.e. +not the fixed columns).

<static> wrapper :node

Grid wrapper. This is the container element for the 3x3 grid

+
+
+ + + + +
+ +

Details

+

Properties - static

+
+
<static> dt :node

DataTables scrolling element. This element is the DataTables +component in the display grid (making up the main table - i.e. +not the fixed columns).

+ +
+
<static> wrapper :node

Grid wrapper. This is the container element for the 3x3 grid

+ +
+
+
+
+ +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/73098af57c.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/73098af57c.html new file mode 100644 index 0000000..d9e1487 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/73098af57c.html @@ -0,0 +1,75 @@ + + + + + Namespace: right - documentation + + + + + + + + + +
+ + +
+

Namespace: right

+

Ancestry: FixedColumns » #dom » .grid. » right

+
+ FixedColumns v2.0.3 documentation +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (0)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +

Right fixed column grid components

+ +
+ +
+ + + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/889588ec06.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/889588ec06.html new file mode 100644 index 0000000..9ead206 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/889588ec06.html @@ -0,0 +1,104 @@ + + + + + Namespace: left - documentation + + + + + + + + + +
+ + +
+

Namespace: left

+

Ancestry: FixedColumns » #dom » .clone. » left

+
+ FixedColumns v2.0.3 documentation +
+
+ + + +
+

Navigation

+ +
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +

Left column cloned table nodes

+ +
+ +
+ + +
+ +

Summary

+ +

Properties - static

+ +
+
<static> body :node

Cloned body table

<static> footer :node

Cloned footer table

<static> header :node

Cloned header table

+
+
+ + + + +
+ +

Details

+

Properties - static

+
+
<static> body :node

Cloned body table

+ +
+
<static> footer :node

Cloned footer table

+ +
+
<static> header :node

Cloned header table

+ +
+
+
+
+ +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/91bce7c4ad.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/91bce7c4ad.html new file mode 100644 index 0000000..1d6f973 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/91bce7c4ad.html @@ -0,0 +1,113 @@ + + + + + Namespace: s - documentation + + + + + + + + + +
+ + +
+

Namespace: s

+

Ancestry: FixedColumns# » s

+
+ FixedColumns v2.0.3 documentation +
+
+ + + +
+

Navigation

+ +
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +

Settings object which contains customisable information for FixedColumns instance

+ +
+

Extends

+ + +
+ + +
+ +

Summary

+ +

Properties - static

+ +
+
<static> aiWidths :array.<int>

Original widths of the columns as rendered by DataTables

<static, readonly> bOldIE :boolean

Flag to indicate if we are dealing with IE6/7 as these browsers need a little hack +in the odd place

<static> dt :object

DataTables settings objects

<static> iTableColumns :int

Number of columns in the DataTable - stored for quick access

+
+
+ + + + +
+ +

Details

+

Properties - static

+
+
<static> aiWidths :array.<int>

Original widths of the columns as rendered by DataTables

+ +
+
<static, readonly> bOldIE :boolean

Flag to indicate if we are dealing with IE6/7 as these browsers need a little hack +in the odd place

+ +
+
<static> dt :object

DataTables settings objects

+ +
+
<static> iTableColumns :int

Number of columns in the DataTable - stored for quick access

+ +
+
+
+
+ +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/FixedColumns.defaults.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/FixedColumns.defaults.html new file mode 100644 index 0000000..07f3c50 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/FixedColumns.defaults.html @@ -0,0 +1,219 @@ + + + + + Namespace: defaults - documentation + + + + + + + + + +
+ + +
+

Namespace: defaults

+

Ancestry: FixedColumns. » defaults

+
+ FixedColumns v2.0.3 documentation +
+
+ + + +
+

Navigation

+ +
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +

FixedColumns default settings for initialisation

+ +
+ +
+ + +
+ +

Summary

+ +

Properties - static

+ +
+
<static> fnDrawCallback :function(object, object):void

Draw callback function which is called when FixedColumns has redrawn the fixed assets

<static> iLeftColumns :int

Number of left hand columns to fix in position

<static> iLeftWidth :int

Width to set for the width of the left fixed column(s) - note that the behaviour of this +property is directly effected by the sLeftWidth property. If not defined then this property +is calculated automatically from what has been assigned by DataTables.

<static> iRightColumns :int

Number of right hand columns to fix in position

<static> iRightWidth :int

Width to set for the width of the right fixed column(s) - note that the behaviour of this +property is directly effected by the sRightWidth property. If not defined then this property +is calculated automatically from what has been assigned by DataTables.

<static> sHeightMatch :string

Height matching algorthim to use. This can be "none" which will result in no height +matching being applied by FixedColumns (height matching could be forced by CSS in this +case), "semiauto" whereby the height calculation will be performed once, and the result +cached to be used again (fnRecalculateHeight can be used to force recalculation), or +"auto" when height matching is performed on every draw (slowest but must accurate)

<static> sLeftWidth :string

Type of left column size calculation. Can take the values of "fixed", whereby the iLeftWidth +value will be treated as a pixel value, or "relative" for which case iLeftWidth will be +treated as a percentage value.

<static> sRightWidth :string

Type of right column size calculation. Can take the values of "fixed", whereby the +iRightWidth value will be treated as a pixel value, or "relative" for which case +iRightWidth will be treated as a percentage value.

+
+
+ + + + +
+ +

Details

+

Properties - static

+
+
<static> fnDrawCallback :function(object, object):void

Draw callback function which is called when FixedColumns has redrawn the fixed assets

+ +
+
Example
+
+
 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%"
+ 	} );
+ 	new FixedColumns( oTable, {
+ 		"fnDrawCallback": function () {
+				alert( "FixedColumns redraw" );
+			}
+ 	} );
+
+
<static> iLeftColumns :int

Number of left hand columns to fix in position

+ +
+
Example
+
+
 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%"
+ 	} );
+ 	new FixedColumns( oTable, {
+ 		"iLeftColumns": 2
+ 	} );
+
+
<static> iLeftWidth :int

Width to set for the width of the left fixed column(s) - note that the behaviour of this +property is directly effected by the sLeftWidth property. If not defined then this property +is calculated automatically from what has been assigned by DataTables.

+ +
+
Example
+
+
 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%"
+ 	} );
+ 	new FixedColumns( oTable, {
+ 		"iLeftWidth": 100 // pixels
+ 	} );
+
+
<static> iRightColumns :int

Number of right hand columns to fix in position

+ +
+
Example
+
+
 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%"
+ 	} );
+ 	new FixedColumns( oTable, {
+ 		"iRightColumns": 1
+ 	} );
+
+
<static> iRightWidth :int

Width to set for the width of the right fixed column(s) - note that the behaviour of this +property is directly effected by the sRightWidth property. If not defined then this property +is calculated automatically from what has been assigned by DataTables.

+ +
+
Example
+
+
 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%"
+ 	} );
+ 	new FixedColumns( oTable, {
+ 		"iRightWidth": 200 // pixels
+ 	} );
+
+
<static> sHeightMatch :string

Height matching algorthim to use. This can be "none" which will result in no height +matching being applied by FixedColumns (height matching could be forced by CSS in this +case), "semiauto" whereby the height calculation will be performed once, and the result +cached to be used again (fnRecalculateHeight can be used to force recalculation), or +"auto" when height matching is performed on every draw (slowest but must accurate)

+ +
+
Example
+
+
 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%"
+ 	} );
+ 	new FixedColumns( oTable, {
+ 		"sHeightMatch": "auto"
+ 	} );
+
+
<static> sLeftWidth :string

Type of left column size calculation. Can take the values of "fixed", whereby the iLeftWidth +value will be treated as a pixel value, or "relative" for which case iLeftWidth will be +treated as a percentage value.

+ +
+
Example
+
+
 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%"
+ 	} );
+ 	new FixedColumns( oTable, {
+ 		"sLeftWidth": "relative",
+ 		"iLeftWidth": 10 // percentage
+ 	} );
+
+
<static> sRightWidth :string

Type of right column size calculation. Can take the values of "fixed", whereby the +iRightWidth value will be treated as a pixel value, or "relative" for which case +iRightWidth will be treated as a percentage value.

+ +
+
Example
+
+
 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%"
+ 	} );
+ 	new FixedColumns( oTable, {
+ 		"sRightWidth": "relative",
+ 		"iRightWidth": 10 // percentage
+ 	} );
+
+
+
+
+ +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/FixedColumns.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/FixedColumns.html new file mode 100644 index 0000000..68c28ba --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/FixedColumns.html @@ -0,0 +1,282 @@ + + + + + Class: FixedColumns - documentation + + + + + + + + + +
+ + +
+

Class: FixedColumns

+ +
+ FixedColumns v2.0.3 documentation +
+
+ + + +
+

Navigation

+ +
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
new FixedColumns(oDT, oInit)

When making use of DataTables' x-axis scrolling feature, you may wish to +fix the left most column in place. This plug-in for DataTables provides +exactly this option (note for non-scrolling tables, please use the
+FixedHeader plug-in, which can fix headers, footers and columns). Key +features include: +

    +
  • Freezes the left or right most columns to the side of the table
  • +
  • Option to freeze two or more columns
  • +
  • Full integration with DataTables' scrolling options
  • +
  • Speed - FixedColumns is fast in its operation
  • +

Constructor

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
oDTobject

DataTables instance

2
oInitobjectOptional{}

Configuration object for FixedColumns. Options are defined by FixedColumns.defaults

Example:
+
+
 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%"
+ 	} );
+ 	new FixedColumns( oTable );
+
+
+

Requires

+
    +
  • module:jQuery
  • module:DataTables
  • +
+ +
+ + +
+ +

Summary

+ +

Namespaces

+
+
defaults

FixedColumns default settings for initialisation

dom

DOM elements used by the class instance

s

Settings object which contains customisable information for FixedColumns instance

+

Properties - static

+ +
+
<static, constant> VERSION :String

FixedColumns version

+

Methods - instance

+ +
+
fnRecalculateHeight(nTr) → {void}

Mark a row such that it's height should be recalculated when using 'semiauto' row +height matching. This function will have no effect when 'none' or 'auto' row height +matching is used.

fnRedrawLayout() → {void}

Recalculate the resizes of the 3x3 grid that FixedColumns uses for display of the table. +This is useful if you update the width of the table container. Note that FixedColumns will +perform this function automatically when the window.resize event is fired.

fnSetRowHeight(nTarget, iHeight) → {void}

Set the height of a given row - provides cross browser compatibility

fnUpdate() → {void}

Update the fixed columns - including headers and footers. Note that FixedColumns will +automatically update the display whenever the host DataTable redraws.

+
+

Events

+
+
draw

Event fired whenever FixedColumns redraws the fixed columns (i.e. clones the table elements from the main DataTable). This will occur whenever the DataTable that the FixedColumns instance is attached does its own draw.

+ +
+
+ + + + +
+ +

Details

+

Properties - static

+
+
<static, constant> VERSION :String

FixedColumns version

+ +
+
+

Methods - instance

+
+
fnRecalculateHeight(nTr) → {void}

Mark a row such that it's height should be recalculated when using 'semiauto' row +height matching. This function will have no effect when 'none' or 'auto' row height +matching is used.

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
nTrNode

TR element that should have it's height recalculated

Example:
+
+
 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%"
+ 	} );
+ 	var oFC = new FixedColumns( oTable );
+ 	
+ 	// manipulate the table - mark the row as needing an update then update the table
+ 	// this allows the redraw performed by DataTables fnUpdate to recalculate the row
+ 	// height
+ 	oFC.fnRecalculateHeight();
+ 	oTable.fnUpdate( $('#example tbody tr:eq(0)')[0], ["insert date", 1, 2, 3 ... ]);
+
+
+
fnRedrawLayout() → {void}

Recalculate the resizes of the 3x3 grid that FixedColumns uses for display of the table. +This is useful if you update the width of the table container. Note that FixedColumns will +perform this function automatically when the window.resize event is fired.

+ +
+
Example:
+
+
 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%"
+ 	} );
+ 	var oFC = new FixedColumns( oTable );
+ 	
+ 	// Resize the table container and then have FixedColumns adjust its layout....
+     $('#content').width( 1200 );
+ 	oFC.fnRedrawLayout();
+
+
+
fnSetRowHeight(nTarget, iHeight) → {void}

Set the height of a given row - provides cross browser compatibility

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
nTargetNode

TR element that should have it's height recalculated

2
iHeightint

Height in pixels to set

Example:
+
+
 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%"
+ 	} );
+ 	var oFC = new FixedColumns( oTable );
+ 	
+ 	// You may want to do this after manipulating a row in the fixed column
+ 	oFC.fnSetRowHeight( $('#example tbody tr:eq(0)')[0], 50 );
+
+
+
fnUpdate() → {void}

Update the fixed columns - including headers and footers. Note that FixedColumns will +automatically update the display whenever the host DataTable redraws.

+ +
+
Example:
+
+
 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%"
+ 	} );
+ 	var oFC = new FixedColumns( oTable );
+ 	
+ 	// at some later point when the table has been manipulated....
+ 	oFC.fnUpdate();
+
+
+ +
+

Events

+
+
draw

Event fired whenever FixedColumns redraws the fixed columns (i.e. clones the table elements from the main DataTable). This will occur whenever the DataTable that the FixedColumns instance is attached does its own draw.

+ +
+
Parameters:
+ + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
1
eevent

jQuery event object

2
oobject

Event parameters from FixedColumns

o.leftCloneobject

Instance's object dom.clone.left for easy reference. This object contains references to the left fixed clumn column's nodes

o.rightCloneobject

Instance's object dom.clone.right for easy reference. This object contains references to the right fixed clumn column's nodes

+ +
+
+
+ +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/a6bd52f587.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/a6bd52f587.html new file mode 100644 index 0000000..6230a17 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/a6bd52f587.html @@ -0,0 +1,104 @@ + + + + + Namespace: right - documentation + + + + + + + + + +
+ + +
+

Namespace: right

+

Ancestry: FixedColumns » #dom » .clone. » right

+
+ FixedColumns v2.0.3 documentation +
+
+ + + +
+

Navigation

+ +
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +

Right column cloned table nodes

+ +
+ +
+ + +
+ +

Summary

+ +

Properties - static

+ +
+
<static> body :node

Cloned body table

<static> footer :node

Cloned footer table

<static> header :node

Cloned header table

+
+
+ + + + +
+ +

Details

+

Properties - static

+
+
<static> body :node

Cloned body table

+ +
+
<static> footer :node

Cloned footer table

+ +
+
<static> header :node

Cloned header table

+ +
+
+
+
+ +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/d3890ba7c4.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/d3890ba7c4.html new file mode 100644 index 0000000..7b12888 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/d3890ba7c4.html @@ -0,0 +1,110 @@ + + + + + Namespace: dom - documentation + + + + + + + + + +
+ + +
+

Namespace: dom

+

Ancestry: FixedColumns# » dom

+
+ FixedColumns v2.0.3 documentation +
+
+ + + +
+

Navigation

+ +
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +

DOM elements used by the class instance

+ +
+ +
+ + +
+ +

Summary

+ +

Namespaces

+
+
clone

Cloned table nodes

grid

Display grid elements

+

Properties - static

+ +
+
<static> body :node

DataTables body table

<static> footer :node

DataTables footer table

<static> header :node

DataTables header table

<static> scroller :node

DataTables scrolling element

+
+
+ + + + +
+ +

Details

+

Properties - static

+
+
<static> body :node

DataTables body table

+ +
+
<static> footer :node

DataTables footer table

+ +
+
<static> header :node

DataTables header table

+ +
+
<static> scroller :node

DataTables scrolling element

+ +
+
+
+
+ +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/e20106c59a.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/e20106c59a.html new file mode 100644 index 0000000..e82ddb5 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/e20106c59a.html @@ -0,0 +1,85 @@ + + + + + Namespace: clone - documentation + + + + + + + + + +
+ + +
+

Namespace: clone

+

Ancestry: FixedColumns » #dom. » clone

+
+ FixedColumns v2.0.3 documentation +
+
+ + + +
+

Navigation

+
    +
  • Overview
  • +
  • Summary
    Classes (0)Namespaces (2)
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
  • Details
    Properties (0)Static properties (0)
    Methods (0)Static methods (0)
    Events (0)
+
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +

Cloned table nodes

+ +
+ +
+ + +
+ +

Summary

+ +

Namespaces

+
+
left

Left column cloned table nodes

right

Right column cloned table nodes

+
+
+ + + + +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/global.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/global.html new file mode 100644 index 0000000..401a0c6 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/global.html @@ -0,0 +1,111 @@ + + + + + Global - documentation + + + + + + + + + +
+ + +
+

Global

+ +
+ FixedColumns v2.0.3 documentation +
+
+ + + +
+

Navigation

+ +
+ + Hiding private elements + (toggle) + +
+
+ + Showing extended elements + (toggle) + +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +

Summary

+ +

Classes

+
+
FixedColumns

When making use of DataTables' x-axis scrolling feature, you may wish to +fix the left most column in place. This plug-in for DataTables provides +exactly this option (note for non-scrolling tables, please use the
+FixedHeader plug-in, which can fix headers, footers and columns). Key +features include: +

    +
  • Freezes the left or right most columns to the side of the table
  • +
  • Option to freeze two or more columns
  • +
  • Full integration with DataTables' scrolling options
  • +
  • Speed - FixedColumns is fast in its operation
  • +

+

Properties - instance

+ +
+
<constant> CLASS :String

Name of this class

+
+
+ + + + +
+ +

Details

+

Properties - instance

+
+
<constant> CLASS :String

Name of this class

+ +
+
+
+
+ +
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/index.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/index.html new file mode 100644 index 0000000..97aba4d --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/index.html @@ -0,0 +1,50 @@ + + + + + Table of Contents - documentation + + + + + + + + + +
+ +
+
+ +
+

Table of Contents

+
+
FixedColumns

When making use of DataTables' x-axis scrolling feature, you may wish to +fix the left most column in place. This plug-in for DataTables provides +exactly this option (note for non-scrolling tables, please use the
+FixedHeader plug-in, which can fix headers, footers and columns). Key +features include: +

    +
  • Freezes the left or right most columns to the side of the table
  • +
  • Option to freeze two or more columns
  • +
  • Full integration with DataTables' scrolling options
  • +
  • Speed - FixedColumns is fast in its operation
  • +

+
+
+
+ + + + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/css/doc.css b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/css/doc.css new file mode 100644 index 0000000..a239329 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/css/doc.css @@ -0,0 +1,393 @@ +/* +Copyright (c) 2006, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 0.12.0 +*/ +body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;} +table{border-collapse:collapse;border-spacing:0;} +fieldset,img{border:0;} +address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;} +ol,ul {list-style:none;} +caption,th {text-align:left;} +h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;} +q:before,q:after{content:'';} +abbr,acronym {border:0;} + + +html, body { + margin: 0; + padding: 0; + width: 100%; + font: 14px/1.45em "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; + color: #111; +} + +div.fw_container { + width: 980px; + padding-top: 2em; + margin: 0 auto; +} + +div.fw_header { + position: relative; +} + +div.fw_content { + padding-top: 2em; +} + +div.fw_footer { + padding-top: 4em; + font-size: 75%; + text-align: center; +} + + + + +.type-attr .type-signature { + background-color: #ccc; + color: white; + border-radius: 3px; + display: inline-block; + padding: 0 3px; + font-size: 0.9em; +} + +.type-attr { + float: right; + color: #999; +} + +.type-name { + font-weight: bold; +} + +.type-sig { + color: #999; +} + +.type-param { + color: #D32929; +} + +.type-return { + color: #FF8080; +} + +.type-brace { + color: #111; +} + +.example-code { + margin-left: 30px; +} +.example-code td.code { + border-top: 1px solid #4E6CA3 !important; +} + +.type-augmented { + position: absolute; + left: 8px; + top: 0; +} + +dt, dd { + padding: 0.4em 10px; +} + +dt { + padding-bottom: 0 !important; +} + +dd { + position: relative; + padding-top: 0 !important; + padding-left: 3em; +} + +dt.even, dd.even { + background-color: white; +} + +dt.odd, dd.odd { + background-color: #F2F2F2; +} + +div.doc_overview dd, div.doc_overview dt { + padding-left: 0 !important; +} + + + +.right_border div { + width: 20px; + padding: 2px 0.5em 2px 1em; + text-align: right; +} +.right_border { + border-right: 3px solid #4E6CA3; +} +.bottom_border { + border-bottom: 1px solid #4E6CA3; +} + + +a { + text-decoration: none; + color: #4E6CA3; +} + +a:hover { + text-decoration: underline; + cursor: pointer; + *cursor: hand; +} + +div.fw_content ul { + list-style-image: url('../images/arrow.png'); + padding: 0 0 0 2em; +} + +/* +h2 { + font-size: 1.4em; + margin-top: 2em; + border-bottom: 3px solid #829ac6; + padding-left: 5px; +} + +h3 { + font-size: 1.2em; + margin-top: 1em; + border-bottom: 1px solid #A4B5D5; + padding-left: 5px; +} +*/ + +h1 { + font-size: 2em; +} + +h2 { + font-size: 1.6em; + padding-top: 5px; +} + +h2.ancestors { + font-size: 14px; + margin: 0; +} + +h3 { + font-size: 1.3em; + padding-top: 5px; + margin-bottom: 5px; +} + +h5 { + padding-top: 6px; + font-weight: bold; + font-size: 0.9em; + border-bottom: 1px solid #cad4e6; + margin-bottom: 1em; +} + +div.doc_summary, div.doc_details { + margin-top: 2em; + clear: both; +} + +div.doc_group { + margin-top: 1em; + border-top: 1px solid #A4B5D5; + border-left: 1px solid #A4B5D5; + padding-left: 10px; +} + +div.extended { + margin-left: 30px; +} + +table.params { + margin-left: 30px; + width: 97%; +} + +table.params th, +table.params td { + padding: 3px; +} + +tr.odd { + background-color: white; +} + +tr.even { + background-color: #F8F8F8; +} + +th.name, +td.name { + padding-left: 13px; +} + +td.number { + background-color: white; + color: #5C5C5C; +} + +dd.odd td.number { + background-color: #F2F2F2; +} + +p { + margin: 1em 0; +} + +p:first-child { + margin-top: 0; +} + +p:last-child { + margin-bottom: 0; +} + +p.returns { + margin-left: 5%; +} + +div.page-info { + position: absolute; + top: 0; + right: 0; +} + + +.private { + display: none; +} + + +code { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + padding: 2px 4px !important; + white-space: pre; + font-size: 0.9em; + + color: #D14; + background-color: #F7F7F9; + + border: 1px solid #E1E1E8; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +pre { + background-color: #f8f8f8; + border: 1px solid #ccc; + border-radius: 3px; + padding: 6px 10px; +} + +pre>code { + background-color: transparent; + border: none; + color: #111; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +ol { + list-style-type: decimal; + list-style-position: outside; + padding-left: 30px; +} + + + +div.fw_nav { + position: fixed; + top: 25px; + right: 30px; + width: 250px; + border: 1px solid #A4B5D5; + background-color: white; + padding: 10px; + z-index: 1001; + font-size: 12px; + overflow: hidden; +} + +div.fw_nav h2 { + margin: -10px 0 10px -10px; + width: 250px; + padding: 5px 10px; + background-color: #A4B5D5; + font-size: 12px; + cursor: pointer; + *cursor: hand; +} + +div.fw_nav ul>li>div { + padding: 0 0 0 1em; +} + +div.nav_blocker { + float: right; +} + +div.fw_nav td { + color: #999; +} + +div.fw_nav li { + margin-bottom: 5px; +} + +div.fw_nav li>a { + font-weight: bold; +} + + + + + + + +.css_clear { + clear: both; + height: 0; + line-height: 0; + visibility: hidden; +} + +.css_right { + text-align: right; +} + +.css_center { + text-align: center; +} + +.css_spacing { + margin-top: 1.5em; +} + +.css_small { + font-size: 75%; + line-height: 1.45em; +} + +.css_vsmall { + font-size: 65%; + line-height: 1.45em; +} diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/css/shCore.css b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/css/shCore.css new file mode 100644 index 0000000..b0c4520 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/css/shCore.css @@ -0,0 +1,226 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter a, +.syntaxhighlighter div, +.syntaxhighlighter code, +.syntaxhighlighter table, +.syntaxhighlighter table td, +.syntaxhighlighter table tr, +.syntaxhighlighter table tbody, +.syntaxhighlighter table thead, +.syntaxhighlighter table caption, +.syntaxhighlighter textarea { + -moz-border-radius: 0 0 0 0 !important; + -webkit-border-radius: 0 0 0 0 !important; + background: none !important; + border: 0 !important; + bottom: auto !important; + float: none !important; + height: auto !important; + left: auto !important; + line-height: 1.1em !important; + margin: 0 !important; + outline: 0 !important; + overflow: visible !important; + padding: 0 !important; + position: static !important; + right: auto !important; + text-align: left !important; + top: auto !important; + vertical-align: baseline !important; + width: auto !important; + box-sizing: content-box !important; + font-family: "Consolas","Monaco","Bitstream Vera Sans Mono","Courier New",Courier,monospace !important; + font-weight: normal !important; + font-style: normal !important; + font-size: 1em !important; + min-height: inherit !important; + min-height: auto !important; +} + +.syntaxhighlighter { + width: 100% !important; + margin: 1em 0 1em 0 !important; + position: relative !important; + overflow: auto !important; + font-size: 1em !important; +} +.syntaxhighlighter.source { + overflow: hidden !important; +} +.syntaxhighlighter .bold { + font-weight: bold !important; +} +.syntaxhighlighter .italic { + font-style: italic !important; +} +.syntaxhighlighter .line { + white-space: pre !important; +} +.syntaxhighlighter table { + width: 100% !important; +} +.syntaxhighlighter table caption { + text-align: left !important; + padding: .5em 0 0.5em 1em !important; +} +.syntaxhighlighter table td.code { + width: 100% !important; +} +.syntaxhighlighter table td.code .container { + position: relative !important; +} +.syntaxhighlighter table td.code .container textarea { + box-sizing: border-box !important; + position: absolute !important; + left: 0 !important; + top: 0 !important; + width: 100% !important; + height: 100% !important; + border: none !important; + background: white !important; + padding-left: 1em !important; + overflow: hidden !important; + white-space: pre !important; +} +.syntaxhighlighter table td.gutter .line { + text-align: right !important; + padding: 2px 0.5em 2px 1em !important; +} +.syntaxhighlighter table td.code .line { + padding: 2px 1em !important; +} +.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { + padding-left: 0em !important; +} +.syntaxhighlighter.show { + display: block !important; +} +.syntaxhighlighter.collapsed table { + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar { + padding: 0.1em 0.8em 0em 0.8em !important; + font-size: 1em !important; + position: static !important; + width: auto !important; + height: auto !important; +} +.syntaxhighlighter.collapsed .toolbar span { + display: inline !important; + margin-right: 1em !important; +} +.syntaxhighlighter.collapsed .toolbar span a { + padding: 0 !important; + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar span a.expandSource { + display: inline !important; +} +.syntaxhighlighter .toolbar { + position: absolute !important; + right: 1px !important; + top: 1px !important; + width: 11px !important; + height: 11px !important; + font-size: 10px !important; + z-index: 10 !important; +} +.syntaxhighlighter .toolbar span.title { + display: inline !important; +} +.syntaxhighlighter .toolbar a { + display: block !important; + text-align: center !important; + text-decoration: none !important; + padding-top: 1px !important; +} +.syntaxhighlighter .toolbar a.expandSource { + display: none !important; +} +.syntaxhighlighter.ie { + font-size: .9em !important; + padding: 1px 0 1px 0 !important; +} +.syntaxhighlighter.ie .toolbar { + line-height: 8px !important; +} +.syntaxhighlighter.ie .toolbar a { + padding-top: 0px !important; +} +.syntaxhighlighter.printing .line.alt1 .content, +.syntaxhighlighter.printing .line.alt2 .content, +.syntaxhighlighter.printing .line.highlighted .number, +.syntaxhighlighter.printing .line.highlighted.alt1 .content, +.syntaxhighlighter.printing .line.highlighted.alt2 .content { + background: none !important; +} +.syntaxhighlighter.printing .line .number { + color: #bbbbbb !important; +} +.syntaxhighlighter.printing .line .content { + color: black !important; +} +.syntaxhighlighter.printing .toolbar { + display: none !important; +} +.syntaxhighlighter.printing a { + text-decoration: none !important; +} +.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { + color: black !important; +} +.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { + color: #008200 !important; +} +.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { + color: blue !important; +} +.syntaxhighlighter.printing .keyword { + color: #006699 !important; + font-weight: bold !important; +} +.syntaxhighlighter.printing .preprocessor { + color: gray !important; +} +.syntaxhighlighter.printing .variable { + color: #aa7700 !important; +} +.syntaxhighlighter.printing .value { + color: #009900 !important; +} +.syntaxhighlighter.printing .functions { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .constants { + color: #0066cc !important; +} +.syntaxhighlighter.printing .script { + font-weight: bold !important; +} +.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { + color: gray !important; +} +.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { + color: red !important; +} +.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { + color: black !important; +} diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/css/shThemeDataTables.css b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/css/shThemeDataTables.css new file mode 100644 index 0000000..7e9790a --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/css/shThemeDataTables.css @@ -0,0 +1,128 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter { + background-color: white !important; + font-size: 14px !important; + overflow: visible !important; +} +.syntaxhighlighter .line.alt1 { + background-color: white !important; +} +.syntaxhighlighter .line.alt2 { + background-color: #F8F8F8 !important; +} +.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { + background-color: #e0e0e0 !important; +} +.syntaxhighlighter .line.highlighted.number { + color: black !important; +} +.syntaxhighlighter table caption { + color: black !important; +} +.syntaxhighlighter .gutter { +} +.syntaxhighlighter .gutter div { + color: #5C5C5C !important; + width: 20px !important; +} +.syntaxhighlighter .gutter .line.alt1, .syntaxhighlighter .gutter .line.alt2 { + background-color: white !important; +} +.odd .syntaxhighlighter .gutter .line.alt1, .odd .syntaxhighlighter .gutter .line.alt2 { + background-color: #F2F2F2 !important; +} +.syntaxhighlighter .gutter .line { + border-right: 3px solid #4E6CA3 !important; +} +.syntaxhighlighter .gutter .line.highlighted { + background-color: #4E6CA3 !important; + color: white !important; +} +.syntaxhighlighter.printing .line .content { + border: none !important; +} +.syntaxhighlighter.collapsed { + overflow: visible !important; +} +.syntaxhighlighter.collapsed .toolbar { + color: blue !important; + background: white !important; + border: 1px solid #4E6CA3 !important; +} +.syntaxhighlighter.collapsed .toolbar a { + color: blue !important; +} +.syntaxhighlighter.collapsed .toolbar a:hover { + color: red !important; +} +.syntaxhighlighter .toolbar { + color: white !important; + background: #4E6CA3 !important; + border: none !important; +} +.syntaxhighlighter .toolbar a { + color: white !important; +} +.syntaxhighlighter .toolbar a:hover { + color: black !important; +} +.syntaxhighlighter .plain, .syntaxhighlighter .plain a { + color: black !important; +} +.syntaxhighlighter .comments, .syntaxhighlighter .comments a { + color: #008200 !important; +} +.syntaxhighlighter .string, .syntaxhighlighter .string a { + color: blue !important; +} +.syntaxhighlighter .keyword { + color: #006699 !important; +} +.syntaxhighlighter .preprocessor { + color: gray !important; +} +.syntaxhighlighter .variable { + color: #aa7700 !important; +} +.syntaxhighlighter .value { + color: #009900 !important; +} +.syntaxhighlighter .functions { + color: #ff1493 !important; +} +.syntaxhighlighter .constants { + color: #0066cc !important; +} +.syntaxhighlighter .script { + font-weight: bold !important; + color: #006699 !important; + background-color: none !important; +} +.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { + color: gray !important; +} +.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { + color: red !important; +} + +.syntaxhighlighter .keyword { + font-weight: bold !important; +} diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/images/arrow.jpg b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/images/arrow.jpg new file mode 100644 index 0000000..eba85ea Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/images/arrow.jpg differ diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/images/arrow.png b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/images/arrow.png new file mode 100644 index 0000000..08dbbb1 Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/images/arrow.png differ diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/images/extended.png b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/images/extended.png new file mode 100644 index 0000000..5dd01bf Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/images/extended.png differ diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/js/doc.js b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/js/doc.js new file mode 100644 index 0000000..932d7cf --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/docs/media/js/doc.js @@ -0,0 +1,121 @@ + +(function() { + +var showingNav = true; + +$(document).ready( function () { + var jqNav = $('div.fw_nav'); + jqNav.css('right', ($(window).width() - $('div.fw_container').width()) /2); + + var n = $('div.nav_blocker')[0]; + n.style.height = $(jqNav).outerHeight()+"px"; + n.style.width = ($(jqNav).outerWidth()+20)+"px"; + + SyntaxHighlighter.highlight(); + + $('#private_toggle').click( function () { + if ( $('input[name=show_private]').val() == 0 ) { + $('input[name=show_private]').val( 1 ); + $('#private_label').html('Showing'); + $('.private').css('display', 'block'); + } else { + $('input[name=show_private]').val( 0 ); + $('#private_label').html('Hiding'); + $('.private').css('display', 'none'); + } + fnWriteCookie(); + return false; + } ); + + $('#extended_toggle').click( function () { + if ( $('input[name=show_extended]').val() == 0 ) { + $('input[name=show_extended]').val( 1 ); + $('#extended_label').html('Showing'); + $('.augmented').css('display', 'block'); + } else { + $('input[name=show_extended]').val( 0 ); + $('#extended_label').html('Hiding'); + $('.augmented').css('display', 'none'); + } + fnWriteCookie(); + return false; + } ); + + var savedHeight = $(jqNav).height(); + $('div.fw_nav h2').click( function () { + if ( showingNav ) { + $('div.fw_nav').animate( { + "height": 10, + "opacity": 0.3 + } ); + showingNav = false; + } else { + $('div.fw_nav').animate( { + "height": savedHeight, + "opacity": 1 + } ); + showingNav = true; + } + fnWriteCookie(); + } ); + + var cookie = fnReadCookie( 'SpryMedia_JSDoc' ); + if ( cookie != null ) { + var a = cookie.split('-'); + if ( a[0] == 1 ) { + $('#private_toggle').click(); + } + if ( a[1] == 0 ) { + $('#extended_toggle').click(); + } + if ( a[2] == 'false' ) { + $('div.fw_nav').css('height', 10).css('opacity', 0.3); + showingNav = false; + } + } +} ); + + +function fnWriteCookie() +{ + var sVal = + $('input[name=show_private]').val()+'-'+ + $('input[name=show_extended]').val()+'-'+ + showingNav; + + fnCreateCookie( 'SpryMedia_JSDoc', sVal ); +} + + +function fnCreateCookie( sName, sValue ) +{ + var iDays = 365; + var date = new Date(); + date.setTime( date.getTime()+(iDays*24*60*60*1000) ); + var sExpires = "; expires="+date.toGMTString(); + + document.cookie = sName+"="+sValue+sExpires+"; path=/"; +} + + +function fnReadCookie( sName ) +{ + var sNameEQ = sName + "="; + var sCookieContents = document.cookie.split(';'); + + for( var i=0 ; i)[^>]*$|#([\w\-]+)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Check for digits + rdigit = /\d/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // Has the ready events already been bound? + readyBound = false, + + // The deferred used on DOM ready + readyList, + + // Promise methods + promiseMethods = "then done fail isResolved isRejected promise".split( " " ), + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = "body"; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = (context ? context.ownerDocument || context : document); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; + } + + return jQuery.merge( this, selector ); + + // 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: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if (selector.selector !== undefined) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.5.1", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // 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 + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + (this.selector ? " " : "") + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // 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 ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.done( fn ); + + return this; + }, + + eq: function( i ) { + return i === -1 ? + this.slice( i ) : + this.slice( i, +i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + 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: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // 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 ( length === i ) { + 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({ + noConflict: function( deep ) { + window.$ = _$; + + if ( deep ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // 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, + + // Handle when the DOM is ready + ready: function( wait ) { + // A third-party is pushing the ready event forwards + if ( wait === true ) { + jQuery.readyWait--; + } + + // Make sure that the DOM is not already loaded + if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // 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" ).unbind( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyBound ) { + return; + } + + readyBound = true; + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent("onreadystatechange", DOMContentLoaded); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // 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"; + }, + + // A crude way of determining if an object is a window + isWindow: function( obj ) { + return obj && typeof obj === "object" && "setInterval" in obj; + }, + + isNaN: function( obj ) { + return obj == null || !rdigit.test( obj ) || isNaN( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // 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; + } + + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw msg; + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test(data.replace(rvalidescape, "@") + .replace(rvalidtokens, "]") + .replace(rvalidbraces, "")) ) { + + // Try to use the native JSON parser first + return window.JSON && window.JSON.parse ? + window.JSON.parse( data ) : + (new Function("return " + data))(); + + } else { + jQuery.error( "Invalid JSON: " + data ); + } + }, + + // Cross-browser xml parsing + // (xml & tmp used internally) + parseXML: function( data , xml , tmp ) { + + 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 ); + } + + tmp = xml.documentElement; + + if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) { + jQuery.error( "Invalid XML: " + data ); + } + + return xml; + }, + + noop: function() {}, + + // Evalulates a script in a global context + globalEval: function( data ) { + if ( data && rnotwhite.test(data) ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement, + script = document.createElement( "script" ); + + if ( jQuery.support.scriptEval() ) { + script.appendChild( document.createTextNode( data ) ); + } else { + script.text = data; + } + + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709). + head.insertBefore( script, head.firstChild ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction(object); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( var value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // The extra typeof function check is to prevent crashes + // in Safari 2 (See: #3039) + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type(array); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var ret = [], value; + + // Go through the array, translating each of the items to their + // new value (or values). + for ( var i = 0, length = elems.length; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + proxy: function( fn, proxy, thisObject ) { + if ( arguments.length === 2 ) { + if ( typeof proxy === "string" ) { + thisObject = fn; + fn = thisObject[ proxy ]; + proxy = undefined; + + } else if ( proxy && !jQuery.isFunction( proxy ) ) { + thisObject = proxy; + proxy = undefined; + } + } + + if ( !proxy && fn ) { + proxy = function() { + return fn.apply( thisObject || this, arguments ); + }; + } + + // Set the guid of unique handler to the same of original handler, so it can be removed + if ( fn ) { + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + } + + // So proxy can be declared as an argument + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can be optionally by executed if its a function + access: function( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + jQuery.access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : undefined; + }, + + now: function() { + return (new Date()).getTime(); + }, + + // Create a simple deferred (one callbacks list) + _Deferred: function() { + var // callbacks list + callbacks = [], + // stored [ context , args ] + fired, + // to avoid firing when already doing so + firing, + // flag to know if the deferred has been cancelled + cancelled, + // the deferred itself + deferred = { + + // done( f1, f2, ...) + done: function() { + if ( !cancelled ) { + var args = arguments, + i, + length, + elem, + type, + _fired; + if ( fired ) { + _fired = fired; + fired = 0; + } + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + deferred.done.apply( deferred, elem ); + } else if ( type === "function" ) { + callbacks.push( elem ); + } + } + if ( _fired ) { + deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); + } + } + return this; + }, + + // resolve with given context and args + resolveWith: function( context, args ) { + if ( !cancelled && !fired && !firing ) { + firing = 1; + try { + while( callbacks[ 0 ] ) { + callbacks.shift().apply( context, args ); + } + } + // We have to add a catch block for + // IE prior to 8 or else the finally + // block will never get executed + catch (e) { + throw e; + } + finally { + fired = [ context, args ]; + firing = 0; + } + } + return this; + }, + + // resolve with this as context and given arguments + resolve: function() { + deferred.resolveWith( jQuery.isFunction( this.promise ) ? this.promise() : this, arguments ); + return this; + }, + + // Has this deferred been resolved? + isResolved: function() { + return !!( firing || fired ); + }, + + // Cancel + cancel: function() { + cancelled = 1; + callbacks = []; + return this; + } + }; + + return deferred; + }, + + // Full fledged deferred (two callbacks list) + Deferred: function( func ) { + var deferred = jQuery._Deferred(), + failDeferred = jQuery._Deferred(), + promise; + // Add errorDeferred methods, then and promise + jQuery.extend( deferred, { + then: function( doneCallbacks, failCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ); + return this; + }, + fail: failDeferred.done, + rejectWith: failDeferred.resolveWith, + reject: failDeferred.resolve, + isRejected: failDeferred.isResolved, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + if ( promise ) { + return promise; + } + promise = obj = {}; + } + var i = promiseMethods.length; + while( i-- ) { + obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; + } + return obj; + } + } ); + // Make sure only one callback list will be used + deferred.done( failDeferred.cancel ).fail( deferred.cancel ); + // Unexpose cancel + delete deferred.cancel; + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + return deferred; + }, + + // Deferred helper + when: function( object ) { + var lastIndex = arguments.length, + deferred = lastIndex <= 1 && object && jQuery.isFunction( object.promise ) ? + object : + jQuery.Deferred(), + promise = deferred.promise(); + + if ( lastIndex > 1 ) { + var array = slice.call( arguments, 0 ), + count = lastIndex, + iCallback = function( index ) { + return function( value ) { + array[ index ] = arguments.length > 1 ? slice.call( arguments, 0 ) : value; + if ( !( --count ) ) { + deferred.resolveWith( promise, array ); + } + }; + }; + while( ( lastIndex-- ) ) { + object = array[ lastIndex ]; + if ( object && jQuery.isFunction( object.promise ) ) { + object.promise().then( iCallback(lastIndex), deferred.reject ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( promise, array ); + } + } else if ( deferred !== object ) { + deferred.resolve( object ); + } + return promise; + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySubclass( selector, context ) { + return new jQuerySubclass.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySubclass, this ); + jQuerySubclass.superclass = this; + jQuerySubclass.fn = jQuerySubclass.prototype = this(); + jQuerySubclass.fn.constructor = jQuerySubclass; + jQuerySubclass.subclass = this.subclass; + jQuerySubclass.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySubclass) ) { + context = jQuerySubclass(context); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass ); + }; + jQuerySubclass.fn.init.prototype = jQuerySubclass.fn; + var rootjQuerySubclass = jQuerySubclass(document); + return jQuerySubclass; + }, + + browser: {} +}); + +// Create readyList deferred +readyList = jQuery._Deferred(); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +if ( indexOf ) { + jQuery.inArray = function( elem, array ) { + return indexOf.call( array, elem ); + }; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +// Expose jQuery to the global object +return jQuery; + +})(); + + +(function() { + + jQuery.support = {}; + + var div = document.createElement("div"); + + div.style.display = "none"; + div.innerHTML = "
a"; + + var all = div.getElementsByTagName("*"), + a = div.getElementsByTagName("a")[0], + select = document.createElement("select"), + opt = select.appendChild( document.createElement("option") ), + input = div.getElementsByTagName("input")[0]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return; + } + + jQuery.support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: div.firstChild.nodeType === 3, + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText insted) + style: /red/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: a.getAttribute("href") === "/a", + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55$/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: input.value === "on", + + // 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) + optSelected: opt.selected, + + // Will be defined later + deleteExpando: true, + optDisabled: false, + checkClone: false, + noCloneEvent: true, + noCloneChecked: true, + boxModel: null, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableHiddenOffsets: true + }; + + input.checked = true; + jQuery.support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as diabled) + select.disabled = true; + jQuery.support.optDisabled = !opt.disabled; + + var _scriptEval = null; + jQuery.support.scriptEval = function() { + if ( _scriptEval === null ) { + var root = document.documentElement, + script = document.createElement("script"), + id = "script" + jQuery.now(); + + try { + script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); + } catch(e) {} + + root.insertBefore( script, root.firstChild ); + + // Make sure that the execution of code works by injecting a script + // tag with appendChild/createTextNode + // (IE doesn't support this, fails, and uses .text instead) + if ( window[ id ] ) { + _scriptEval = true; + delete window[ id ]; + } else { + _scriptEval = false; + } + + root.removeChild( script ); + // release memory in IE + root = script = id = null; + } + + return _scriptEval; + }; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + + } catch(e) { + jQuery.support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent("onclick", function click() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + jQuery.support.noCloneEvent = false; + div.detachEvent("onclick", click); + }); + div.cloneNode(true).fireEvent("onclick"); + } + + div = document.createElement("div"); + div.innerHTML = ""; + + var fragment = document.createDocumentFragment(); + fragment.appendChild( div.firstChild ); + + // WebKit doesn't clone checked state correctly in fragments + jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; + + // Figure out if the W3C box model works as expected + // document.body must exist before we can do this + jQuery(function() { + var div = document.createElement("div"), + body = document.getElementsByTagName("body")[0]; + + // Frameset documents with no body should not run this code + if ( !body ) { + return; + } + + div.style.width = div.style.paddingLeft = "1px"; + body.appendChild( div ); + jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; + + if ( "zoom" in div.style ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2; + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
"; + jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2; + } + + div.innerHTML = "
t
"; + var tds = div.getElementsByTagName("td"); + + // 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). + // (only IE 8 fails this test) + jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0; + + tds[0].style.display = ""; + tds[1].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE < 8 fail this test) + jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0; + div.innerHTML = ""; + + body.removeChild( div ).style.display = "none"; + div = tds = null; + }); + + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + var eventSupported = function( eventName ) { + var el = document.createElement("div"); + eventName = "on" + eventName; + + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( !el.attachEvent ) { + return true; + } + + var isSupported = (eventName in el); + if ( !isSupported ) { + el.setAttribute(eventName, "return;"); + isSupported = typeof el[eventName] === "function"; + } + el = null; + + return isSupported; + }; + + jQuery.support.submitBubbles = eventSupported("submit"); + jQuery.support.changeBubbles = eventSupported("change"); + + // release memory in IE + div = all = a = null; +})(); + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache, + + // 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[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; + + // 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 || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) { + 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 ) { + elem[ jQuery.expando ] = id = ++jQuery.uuid; + } else { + id = jQuery.expando; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].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 ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); + } else { + cache[ id ] = jQuery.extend(cache[ id ], name); + } + } + + thisCache = cache[ id ]; + + // Internal jQuery data is stored in a separate object inside the object's data + // cache in order to avoid key collisions between internal data and user-defined + // data + if ( pvt ) { + if ( !thisCache[ internalKey ] ) { + thisCache[ internalKey ] = {}; + } + + thisCache = thisCache[ internalKey ]; + } + + if ( data !== undefined ) { + thisCache[ name ] = data; + } + + // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should + // not attempt to inspect the internal events object using jQuery.data, as this + // internal data object is undocumented and subject to change. + if ( name === "events" && !thisCache[name] ) { + return thisCache[ internalKey ] && thisCache[ internalKey ].events; + } + + return getByName ? thisCache[ name ] : thisCache; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + 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 ) { + var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; + + if ( thisCache ) { + delete thisCache[ name ]; + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !isEmptyDataObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( pvt ) { + delete cache[ id ][ internalKey ]; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + var internalCache = cache[ id ][ internalKey ]; + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + if ( jQuery.support.deleteExpando || cache != window ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the entire user cache at once because it's faster than + // iterating through each key, but we need to continue to persist internal + // data if it existed + if ( internalCache ) { + cache[ id ] = {}; + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + + cache[ id ][ internalKey ] = internalCache; + + // Otherwise, we need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + } else if ( isNode ) { + // 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 ( jQuery.support.deleteExpando ) { + delete elem[ jQuery.expando ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( jQuery.expando ); + } else { + elem[ jQuery.expando ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var data = null; + + if ( typeof key === "undefined" ) { + if ( this.length ) { + data = jQuery.data( this[0] ); + + if ( this[0].nodeType === 1 ) { + var attr = this[0].attributes, name; + for ( var i = 0, l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = name.substr( 5 ); + dataAttr( this[0], name, data[ name ] ); + } + } + } + } + + return data; + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + // Try to fetch any internally stored data first + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + data = dataAttr( this[0], key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + + } else { + return this.each(function() { + var $this = jQuery( this ), + args = [ parts[0], value ]; + + $this.triggerHandler( "setData" + parts[1] + "!", args ); + jQuery.data( this, key, value ); + $this.triggerHandler( "changeData" + parts[1] + "!", args ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +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 ) { + data = elem.getAttribute( "data-" + key ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + !jQuery.isNaN( data ) ? parseFloat( 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; +} + +// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON +// property to be considered empty objects; this property always exists in +// order to make sure JSON.stringify does not expose internal metadata +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +jQuery.extend({ + queue: function( elem, type, data ) { + if ( !elem ) { + return; + } + + type = (type || "fx") + "queue"; + var q = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( !data ) { + return q || []; + } + + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + + } else { + q.push( data ); + } + + return q; + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(); + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift("inprogress"); + } + + fn.call(elem, function() { + jQuery.dequeue(elem, type); + }); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue", true ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function( i ) { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + type = type || "fx"; + + return this.queue( type, function() { + var elem = this; + setTimeout(function() { + jQuery.dequeue( elem, type ); + }, time ); + }); + }, + + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspaces = /\s+/, + rreturn = /\r/g, + rspecialurl = /^(?:href|src|style)$/, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rradiocheck = /^(?:radio|checkbox)$/i; + +jQuery.props = { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" +}; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name, fn ) { + return this.each(function(){ + jQuery.attr( this, name, "" ); + if ( this.nodeType === 1 ) { + this.removeAttribute( name ); + } + }); + }, + + addClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.addClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( value && typeof value === "string" ) { + var classNames = (value || "").split( rspaces ); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className ) { + elem.className = value; + + } else { + var className = " " + elem.className + " ", + setClass = elem.className; + + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { + setClass += " " + classNames[c]; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.removeClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + var classNames = (value || "").split( rspaces ); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + var className = (" " + elem.className + " ").replace(rclass, " "); + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[c] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this); + self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspaces ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " "; + for ( var i = 0, l = this.length; i < l; i++ ) { + if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + if ( !arguments.length ) { + var elem = this[0]; + + if ( elem ) { + if ( jQuery.nodeName( elem, "option" ) ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.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 ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + } + + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { + return elem.getAttribute("value") === null ? "on" : elem.value; + } + + // Everything else, we just grab the value + return (elem.value || "").replace(rreturn, ""); + + } + + return undefined; + } + + var isFunction = jQuery.isFunction(value); + + return this.each(function(i) { + var self = jQuery(this), val = value; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call(this, i, self.val()); + } + + // 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 + ""; + }); + } + + if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { + this.checked = jQuery.inArray( self.val(), val ) >= 0; + + } else if ( jQuery.nodeName( this, "select" ) ) { + var values = jQuery.makeArray(val); + + jQuery( "option", this ).each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + this.selectedIndex = -1; + } + + } else { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) { + return undefined; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery(elem)[name](value); + } + + var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), + // Whether we are setting (or getting) + set = value !== undefined; + + // Try to normalize/fix the name + name = notxml && jQuery.props[ name ] || name; + + // Only do all the following if this is a node (faster for style) + if ( elem.nodeType === 1 ) { + // These attributes require special treatment + var special = rspecialurl.test( name ); + + // Safari mis-reports the default selected property of an option + // Accessing the parent's selectedIndex property fixes it + if ( name === "selected" && !jQuery.support.optSelected ) { + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + + // If applicable, access the attribute via the DOM 0 way + // 'in' checks fail in Blackberry 4.7 #6931 + if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) { + if ( set ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } + + if ( value === null ) { + if ( elem.nodeType === 1 ) { + elem.removeAttribute( name ); + } + + } else { + elem[ name ] = value; + } + } + + // browsers index elements by id/name on forms, give priority to attributes. + if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { + return elem.getAttributeNode( name ).nodeValue; + } + + // 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/ + if ( name === "tabIndex" ) { + var attributeNode = elem.getAttributeNode( "tabIndex" ); + + return attributeNode && attributeNode.specified ? + attributeNode.value : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + + return elem[ name ]; + } + + if ( !jQuery.support.style && notxml && name === "style" ) { + if ( set ) { + elem.style.cssText = "" + value; + } + + return elem.style.cssText; + } + + if ( set ) { + // convert the value to a string (all browsers do this but IE) see #1070 + elem.setAttribute( name, "" + value ); + } + + // Ensure that missing attributes return undefined + // Blackberry 4.7 returns "" from getAttribute #6938 + if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) { + return undefined; + } + + var attr = !jQuery.support.hrefNormalized && notxml && special ? + // Some attributes require a special call on IE + elem.getAttribute( name, 2 ) : + elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return attr === null ? undefined : attr; + } + // Handle everything which isn't a DOM element node + if ( set ) { + elem[ name ] = value; + } + return elem[ name ]; + } +}); + + + + +var rnamespaces = /\.(.*)$/, + rformElems = /^(?:textarea|input|select)$/i, + rperiod = /\./g, + rspace = / /g, + rescape = /[^\w\s.|`]/g, + fcleanup = function( nm ) { + return nm.replace(rescape, "\\$&"); + }; + +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code originated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + add: function( elem, types, handler, data ) { + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // TODO :: Use a try/catch until it's safe to pull this out (likely 1.6) + // Minor release fix for bug #8018 + try { + // For whatever reason, IE has trouble passing the window object + // around, causing it to be cloned in the process + if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) { + elem = window; + } + } + catch ( e ) {} + + if ( handler === false ) { + handler = returnFalse; + } else if ( !handler ) { + // Fixes bug #7229. Fix recommended by jdalton + return; + } + + var handleObjIn, handleObj; + + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure + var elemData = jQuery._data( elem ); + + // If no elemData is found then we must be trying to bind to one of the + // banned noData elements + if ( !elemData ) { + return; + } + + var events = elemData.events, + eventHandle = elemData.handle; + + if ( !events ) { + elemData.events = events = {}; + } + + if ( !eventHandle ) { + elemData.handle = eventHandle = function() { + // Handle the second event of a trigger and when + // an event is called after a page has unloaded + return typeof jQuery !== "undefined" && !jQuery.event.triggered ? + jQuery.event.handle.apply( eventHandle.elem, arguments ) : + undefined; + }; + } + + // Add elem as a property of the handle function + // This is to prevent a memory leak with non-native events in IE. + eventHandle.elem = elem; + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = types.split(" "); + + var type, i = 0, namespaces; + + while ( (type = types[ i++ ]) ) { + handleObj = handleObjIn ? + jQuery.extend({}, handleObjIn) : + { handler: handler, data: data }; + + // Namespaced event handlers + if ( type.indexOf(".") > -1 ) { + namespaces = type.split("."); + type = namespaces.shift(); + handleObj.namespace = namespaces.slice(0).sort().join("."); + + } else { + namespaces = []; + handleObj.namespace = ""; + } + + handleObj.type = type; + if ( !handleObj.guid ) { + handleObj.guid = handler.guid; + } + + // Get the current list of functions bound to this event + var handlers = events[ type ], + special = jQuery.event.special[ type ] || {}; + + // Init the event handler queue + if ( !handlers ) { + handlers = events[ type ] = []; + + // Check for a special event handler + // 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 the function to the element's handler list + handlers.push( handleObj ); + + // Keep track of which events have been used, for global triggering + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, pos ) { + // don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + if ( handler === false ) { + handler = returnFalse; + } + + var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + events = elemData && elemData.events; + + if ( !elemData || !events ) { + return; + } + + // types is actually an event object here + if ( types && types.type ) { + handler = types.handler; + types = types.type; + } + + // Unbind all events for the element + if ( !types || typeof types === "string" && types.charAt(0) === "." ) { + types = types || ""; + + for ( type in events ) { + jQuery.event.remove( elem, type + types ); + } + + return; + } + + // Handle multiple events separated by a space + // jQuery(...).unbind("mouseover mouseout", fn); + types = types.split(" "); + + while ( (type = types[ i++ ]) ) { + origType = type; + handleObj = null; + all = type.indexOf(".") < 0; + namespaces = []; + + if ( !all ) { + // Namespaced event handlers + namespaces = type.split("."); + type = namespaces.shift(); + + namespace = new RegExp("(^|\\.)" + + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + eventType = events[ type ]; + + if ( !eventType ) { + continue; + } + + if ( !handler ) { + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( all || namespace.test( handleObj.namespace ) ) { + jQuery.event.remove( elem, origType, handleObj.handler, j ); + eventType.splice( j--, 1 ); + } + } + + continue; + } + + special = jQuery.event.special[ type ] || {}; + + for ( j = pos || 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( handler.guid === handleObj.guid ) { + // remove the given handler for the given type + if ( all || namespace.test( handleObj.namespace ) ) { + if ( pos == null ) { + eventType.splice( j--, 1 ); + } + + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + + if ( pos != null ) { + break; + } + } + } + + // remove generic event handler if no more handlers exist + if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + ret = null; + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + var handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + delete elemData.events; + delete elemData.handle; + + if ( jQuery.isEmptyObject( elemData ) ) { + jQuery.removeData( elem, undefined, true ); + } + } + }, + + // bubbling is internal + trigger: function( event, data, elem /*, bubbling */ ) { + // Event object or event type + var type = event.type || event, + bubbling = arguments[3]; + + if ( !bubbling ) { + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + jQuery.extend( jQuery.Event(type), event ) : + // Just the event type (string) + jQuery.Event(type); + + if ( type.indexOf("!") >= 0 ) { + event.type = type = type.slice(0, -1); + event.exclusive = true; + } + + // Handle a global trigger + if ( !elem ) { + // Don't bubble custom events when global (to avoid too much overhead) + event.stopPropagation(); + + // Only trigger if we've ever bound an event for it + if ( jQuery.event.global[ type ] ) { + // XXX This code smells terrible. event.js should not be directly + // inspecting the data cache + jQuery.each( jQuery.cache, function() { + // internalKey variable is just used to make it easier to find + // and potentially change this stuff later; currently it just + // points to jQuery.expando + var internalKey = jQuery.expando, + internalCache = this[ internalKey ]; + if ( internalCache && internalCache.events && internalCache.events[ type ] ) { + jQuery.event.trigger( event, data, internalCache.handle.elem ); + } + }); + } + } + + // Handle triggering a single element + + // don't do events on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { + return undefined; + } + + // Clean up in case it is reused + event.result = undefined; + event.target = elem; + + // Clone the incoming data, if any + data = jQuery.makeArray( data ); + data.unshift( event ); + } + + event.currentTarget = elem; + + // Trigger the event, it is assumed that "handle" is a function + var handle = jQuery._data( elem, "handle" ); + + if ( handle ) { + handle.apply( elem, data ); + } + + var parent = elem.parentNode || elem.ownerDocument; + + // Trigger an inline bound script + try { + if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { + if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { + event.result = false; + event.preventDefault(); + } + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (inlineError) {} + + if ( !event.isPropagationStopped() && parent ) { + jQuery.event.trigger( event, data, parent, true ); + + } else if ( !event.isDefaultPrevented() ) { + var old, + target = event.target, + targetType = type.replace( rnamespaces, "" ), + isClick = jQuery.nodeName( target, "a" ) && targetType === "click", + special = jQuery.event.special[ targetType ] || {}; + + if ( (!special._default || special._default.call( elem, event ) === false) && + !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { + + try { + if ( target[ targetType ] ) { + // Make sure that we don't accidentally re-trigger the onFOO events + old = target[ "on" + targetType ]; + + if ( old ) { + target[ "on" + targetType ] = null; + } + + jQuery.event.triggered = true; + target[ targetType ](); + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (triggerError) {} + + if ( old ) { + target[ "on" + targetType ] = old; + } + + jQuery.event.triggered = false; + } + } + }, + + handle: function( event ) { + var all, handlers, namespaces, namespace_re, events, + namespace_sort = [], + args = jQuery.makeArray( arguments ); + + event = args[0] = jQuery.event.fix( event || window.event ); + event.currentTarget = this; + + // Namespaced event handlers + all = event.type.indexOf(".") < 0 && !event.exclusive; + + if ( !all ) { + namespaces = event.type.split("."); + event.type = namespaces.shift(); + namespace_sort = namespaces.slice(0).sort(); + namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + event.namespace = event.namespace || namespace_sort.join("."); + + events = jQuery._data(this, "events"); + + handlers = (events || {})[ event.type ]; + + if ( events && handlers ) { + // Clone the handlers to prevent manipulation + handlers = handlers.slice(0); + + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; + + // Filter the functions by class + if ( all || namespace_re.test( handleObj.namespace ) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handleObj.handler; + event.data = handleObj.data; + event.handleObj = handleObj; + + var ret = handleObj.handler.apply( this, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + } + + return event.result; + }, + + props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // store a copy of the original event object + // and "clone" to set read-only properties + var originalEvent = event; + event = jQuery.Event( originalEvent ); + + for ( var i = this.props.length, prop; i; ) { + prop = this.props[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary + if ( !event.target ) { + // Fixes #1925 where srcElement might not be defined either + event.target = event.srcElement || document; + } + + // check if target is a textnode (safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) { + event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; + } + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var doc = document.documentElement, + body = document.body; + + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); + } + + // Add which for key events + if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { + event.which = event.charCode != null ? event.charCode : event.keyCode; + } + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) { + event.metaKey = event.ctrlKey; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button !== undefined ) { + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + } + + return event; + }, + + // Deprecated, use jQuery.guid instead + guid: 1E8, + + // Deprecated, use jQuery.proxy instead + proxy: jQuery.proxy, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady, + teardown: jQuery.noop + }, + + live: { + add: function( handleObj ) { + jQuery.event.add( this, + liveConvert( handleObj.origType, handleObj.selector ), + jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); + }, + + remove: function( handleObj ) { + jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); + } + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src ) { + // Allow instantiation without the 'new' keyword + if ( !this.preventDefault ) { + return new jQuery.Event( src ); + } + + // 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.returnValue === false || + src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // timeStamp is buggy for some events on Firefox(#3843) + // So we won't rely on the native value + this.timeStamp = jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return 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 = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Checks if an event happened on an element within another element +// Used in jQuery.event.special.mouseenter and mouseleave handlers +var withinElement = function( event ) { + // Check if mouse(over|out) are still within the same parent element + var parent = event.relatedTarget; + + // Firefox sometimes assigns relatedTarget a XUL element + // which we cannot access the parentNode property of + try { + + // Chrome does something similar, the parentNode property + // can be accessed but is null. + if ( parent !== document && !parent.parentNode ) { + return; + } + // Traverse up the tree + while ( parent && parent !== this ) { + parent = parent.parentNode; + } + + if ( parent !== this ) { + // set the correct event type + event.type = event.data; + + // handle event if we actually just moused on to a non sub-element + jQuery.event.handle.apply( this, arguments ); + } + + // assuming we've left the element since we most likely mousedover a xul element + } catch(e) { } +}, + +// In case of event delegation, we only need to rename the event.type, +// liveHandler will take care of the rest. +delegate = function( event ) { + event.type = event.data; + jQuery.event.handle.apply( this, arguments ); +}; + +// Create mouseenter and mouseleave events +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + setup: function( data ) { + jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); + }, + teardown: function( data ) { + jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + } + }; +}); + +// submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function( data, namespaces ) { + if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) { + jQuery.event.add(this, "click.specialSubmit", function( e ) { + var elem = e.target, + type = elem.type; + + if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { + trigger( "submit", this, arguments ); + } + }); + + jQuery.event.add(this, "keypress.specialSubmit", function( e ) { + var elem = e.target, + type = elem.type; + + if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { + trigger( "submit", this, arguments ); + } + }); + + } else { + return false; + } + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialSubmit" ); + } + }; + +} + +// change delegation, happens here so we have bind. +if ( !jQuery.support.changeBubbles ) { + + var changeFilters, + + getVal = function( elem ) { + var type = elem.type, val = elem.value; + + if ( type === "radio" || type === "checkbox" ) { + val = elem.checked; + + } else if ( type === "select-multiple" ) { + val = elem.selectedIndex > -1 ? + jQuery.map( elem.options, function( elem ) { + return elem.selected; + }).join("-") : + ""; + + } else if ( elem.nodeName.toLowerCase() === "select" ) { + val = elem.selectedIndex; + } + + return val; + }, + + testChange = function testChange( e ) { + var elem = e.target, data, val; + + if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { + return; + } + + data = jQuery._data( elem, "_change_data" ); + val = getVal(elem); + + // the current data will be also retrieved by beforeactivate + if ( e.type !== "focusout" || elem.type !== "radio" ) { + jQuery._data( elem, "_change_data", val ); + } + + if ( data === undefined || val === data ) { + return; + } + + if ( data != null || val ) { + e.type = "change"; + e.liveFired = undefined; + jQuery.event.trigger( e, arguments[1], elem ); + } + }; + + jQuery.event.special.change = { + filters: { + focusout: testChange, + + beforedeactivate: testChange, + + click: function( e ) { + var elem = e.target, type = elem.type; + + if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { + testChange.call( this, e ); + } + }, + + // Change has to be called before submit + // Keydown will be called before keypress, which is used in submit-event delegation + keydown: function( e ) { + var elem = e.target, type = elem.type; + + if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || + (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || + type === "select-multiple" ) { + testChange.call( this, e ); + } + }, + + // Beforeactivate happens also before the previous element is blurred + // with this event you can't trigger a change event, but you can store + // information + beforeactivate: function( e ) { + var elem = e.target; + jQuery._data( elem, "_change_data", getVal(elem) ); + } + }, + + setup: function( data, namespaces ) { + if ( this.type === "file" ) { + return false; + } + + for ( var type in changeFilters ) { + jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); + } + + return rformElems.test( this.nodeName ); + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialChange" ); + + return rformElems.test( this.nodeName ); + } + }; + + changeFilters = jQuery.event.special.change.filters; + + // Handle when the input is .focus()'d + changeFilters.focus = changeFilters.beforeactivate; +} + +function trigger( type, elem, args ) { + // 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. + // Don't pass args or remember liveFired; they apply to the donor event. + var event = jQuery.extend( {}, args[ 0 ] ); + event.type = type; + event.originalEvent = {}; + event.liveFired = undefined; + jQuery.event.handle.call( elem, event ); + if ( event.isDefaultPrevented() ) { + args[ 0 ].preventDefault(); + } +} + +// Create "bubbling" focus and blur events +if ( document.addEventListener ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + jQuery.event.special[ fix ] = { + setup: function() { + this.addEventListener( orig, handler, true ); + }, + teardown: function() { + this.removeEventListener( orig, handler, true ); + } + }; + + function handler( e ) { + e = jQuery.event.fix( e ); + e.type = fix; + return jQuery.event.handle.call( this, e ); + } + }); +} + +jQuery.each(["bind", "one"], function( i, name ) { + jQuery.fn[ name ] = function( type, data, fn ) { + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this[ name ](key, data, type[key], fn); + } + return this; + } + + if ( jQuery.isFunction( data ) || data === false ) { + fn = data; + data = undefined; + } + + var handler = name === "one" ? jQuery.proxy( fn, function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }) : fn; + + if ( type === "unload" && name !== "one" ) { + this.one( type, data, fn ); + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.add( this[i], type, handler, data ); + } + } + + return this; + }; +}); + +jQuery.fn.extend({ + unbind: function( type, fn ) { + // Handle object literals + if ( typeof type === "object" && !type.preventDefault ) { + for ( var key in type ) { + this.unbind(key, type[key]); + } + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.remove( this[i], type, fn ); + } + } + + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.live( types, data, fn, selector ); + }, + + undelegate: function( selector, types, fn ) { + if ( arguments.length === 0 ) { + return this.unbind( "live" ); + + } else { + return this.die( types, null, fn, selector ); + } + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + + triggerHandler: function( type, data ) { + if ( this[0] ) { + var event = jQuery.Event( type ); + event.preventDefault(); + event.stopPropagation(); + jQuery.event.trigger( event, data, this[0] ); + return event.result; + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + i = 1; + + // link all the functions, so any of them can unbind this click handler + while ( i < args.length ) { + jQuery.proxy( fn, args[ i++ ] ); + } + + return this.click( jQuery.proxy( fn, function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + })); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +var liveMap = { + focus: "focusin", + blur: "focusout", + mouseenter: "mouseover", + mouseleave: "mouseout" +}; + +jQuery.each(["live", "die"], function( i, name ) { + jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { + var type, i = 0, match, namespaces, preType, + selector = origSelector || this.selector, + context = origSelector ? this : jQuery( this.context ); + + if ( typeof types === "object" && !types.preventDefault ) { + for ( var key in types ) { + context[ name ]( key, data, types[key], selector ); + } + + return this; + } + + if ( jQuery.isFunction( data ) ) { + fn = data; + data = undefined; + } + + types = (types || "").split(" "); + + while ( (type = types[ i++ ]) != null ) { + match = rnamespaces.exec( type ); + namespaces = ""; + + if ( match ) { + namespaces = match[0]; + type = type.replace( rnamespaces, "" ); + } + + if ( type === "hover" ) { + types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); + continue; + } + + preType = type; + + if ( type === "focus" || type === "blur" ) { + types.push( liveMap[ type ] + namespaces ); + type = type + namespaces; + + } else { + type = (liveMap[ type ] || type) + namespaces; + } + + if ( name === "live" ) { + // bind live handler + for ( var j = 0, l = context.length; j < l; j++ ) { + jQuery.event.add( context[j], "live." + liveConvert( type, selector ), + { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); + } + + } else { + // unbind live handler + context.unbind( "live." + liveConvert( type, selector ), fn ); + } + } + + return this; + }; +}); + +function liveHandler( event ) { + var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, + elems = [], + selectors = [], + events = jQuery._data( this, "events" ); + + // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) + if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { + return; + } + + if ( event.namespace ) { + namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + event.liveFired = this; + + var live = events.live.slice(0); + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { + selectors.push( handleObj.selector ); + + } else { + live.splice( j--, 1 ); + } + } + + match = jQuery( event.target ).closest( selectors, event.currentTarget ); + + for ( i = 0, l = match.length; i < l; i++ ) { + close = match[i]; + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { + elem = close.elem; + related = null; + + // Those two events require additional checking + if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { + event.type = handleObj.preType; + related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; + } + + if ( !related || related !== elem ) { + elems.push({ elem: elem, handleObj: handleObj, level: close.level }); + } + } + } + } + + for ( i = 0, l = elems.length; i < l; i++ ) { + match = elems[i]; + + if ( maxLevel && match.level > maxLevel ) { + break; + } + + event.currentTarget = match.elem; + event.data = match.handleObj.data; + event.handleObj = match.handleObj; + + ret = match.handleObj.origHandler.apply( match.elem, arguments ); + + if ( ret === false || event.isPropagationStopped() ) { + maxLevel = match.level; + + if ( ret === false ) { + stop = false; + } + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + + return stop; +} + +function liveConvert( type, selector ) { + return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&"); +} + +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").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.bind( name, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } +}); + + +/*! + * 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/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[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; + + // Reset the position of the chunker regexp (start from head) + 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 { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + 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; + } + } + } + + // Improper expression + 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]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + 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, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + 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]; + } + + // Handle if an un-quoted value was used + 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 we're dealing with a complex expression, or a simple one + 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 ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + 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 ) { + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return "text" === elem.getAttribute( 'type' ); + }, + radio: function( elem ) { + return "radio" === elem.type; + }, + + checkbox: function( elem ) { + return "checkbox" === elem.type; + }, + + file: function( elem ) { + return "file" === elem.type; + }, + password: function( elem ) { + return "password" === elem.type; + }, + + submit: function( elem ) { + return "submit" === elem.type; + }, + + image: function( elem ) { + return "image" === elem.type; + }, + + reset: function( elem ) { + return "reset" === elem.type; + }, + + button: function( elem ) { + return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + } + }, + 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; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} 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 ) { + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // If the nodes are siblings (or identical) we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + 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; + }; +} + +// Utility function for retreiving the text value of an array of DOM nodes +Sizzle.getText = function( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += Sizzle.getText( elem.childNodes ); + } + } + + return ret; +}; + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + 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 ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + 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; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

"; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // 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[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // 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 + } 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 ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector, + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + if ( matches ) { + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + return matches.call( node, expr ); + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
"; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + 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]); + } + }; + + // release memory in IE + 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 ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + 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; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + 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 ); +}; + +// EXPOSE +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.POS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var ret = this.pushStack( "", "find", selector ), + length = 0; + + for ( var i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( var n = length; n < ret.length; n++ ) { + for ( var r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && jQuery.filter( selector, this ).length > 0; + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + if ( jQuery.isArray( selectors ) ) { + var match, selector, + matches = {}, + level = 1; + + if ( cur && selectors.length ) { + for ( i = 0, l = selectors.length; i < l; i++ ) { + selector = selectors[i]; + + if ( !matches[selector] ) { + matches[selector] = jQuery.expr.match.POS.test( selector ) ? + jQuery( selector, context || this.context ) : + selector; + } + } + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( selector in matches ) { + match = matches[selector]; + + if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { + ret.push({ selector: selector, elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + } + + return ret; + } + + var pos = POS.test( selectors ) ? + jQuery( selectors, context || this.context ) : null; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique(ret) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + if ( !elem || typeof elem === "string" ) { + return jQuery.inArray( this[0], + // If it receives a string, the selector is used + // If it receives nothing, the siblings are used + elem ? jQuery( elem ) : this.parent().children() ); + } + // 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 ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +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 jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "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.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ), + // The variable 'args' was introduced in + // https://github.com/jquery/jquery/commit/52a0238 + // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. + // http://code.google.com/p/v8/issues/detail?id=1050 + args = slice.call(arguments); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, args.join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + 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; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return (elem === qualifier) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + }); +} + + + + +var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /", "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and + + + + + +
+
+ FixedColumns example - basic initialisation +
+ +

Preamble

+

When displaying a table which scrolls along the x-axis, it can sometimes be useful to the end user for the left most column to be fixed in place, if it shows grouping, index or similar information. This is basically the same idea as 'freeze columns' in Excel. This can be achieved with the FixedColumns plug-in for DataTables, as shown below.

+

Note that FixedColumns is suitable only for use with the scrolling features in DataTables. If you want to achieve a similar effect without scrolling enabled, please checkout FixedHeader, also for DataTables.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox
1.5
Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sScrollX": "100%",
+		"sScrollXInner": "150%",
+		"bScrollCollapse": true
+	} );
+	new FixedColumns( oTable );
+} );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/index_column.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/index_column.html new file mode 100644 index 0000000..92976d8 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/index_column.html @@ -0,0 +1,600 @@ + + + + + + + FixedColumns example + + + + + + + +
+
+ FixedColumns example - index column +
+ +

Preamble

+

A typical interaction to want to perform with a fixed column, is an index column. A method for how this can be achieved with FixedColumns is shown in this example, building on the index column example for DataTables. Also shown in this example is how the fixed column can be styled with CSS to show it more prominently.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 Rendering engineBrowserPlatform(s)Engine versionCSS grade
1TridentInternet + Explorer 4.0Win 95+4X
2TridentInternet + Explorer 5.0Win 95+5C
3TridentInternet + Explorer 5.5Win 95+5.5A
4TridentInternet + Explorer 6Win 98+6A
5TridentInternet Explorer 7Win XP SP2+7A
6TridentAOL browser (AOL desktop)Win XP6A
7GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
8GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
9GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
10GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
11GeckoCamino 1.0OSX.2+1.8A
12GeckoCamino 1.5OSX.3+1.8A
13GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
14GeckoNetscape Browser 8Win 98SE+1.7A
15GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
16GeckoMozilla 1.0Win 95+ / OSX.1+1A
17GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
18GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
19GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
20GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
21GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
22GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
23GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
24GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
25GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
26GeckoEpiphany 2.20Gnome1.8A
27WebkitSafari 1.2OSX.3125.5A
28WebkitSafari 1.3OSX.3312.8A
29WebkitSafari 2.0OSX.4+419.3A
30WebkitSafari 3.0OSX.4+522.1A
31WebkitOmniWeb 5.5OSX.4+420A
32WebkitiPod Touch / iPhoneiPod420.1A
33WebkitS60S60413A
34PrestoOpera 7.0Win 95+ / OSX.1+-A
35PrestoOpera 7.5Win 95+ / OSX.2+-A
36PrestoOpera 8.0Win 95+ / OSX.2+-A
37PrestoOpera 8.5Win 95+ / OSX.2+-A
38PrestoOpera 9.0Win 95+ / OSX.3+-A
39PrestoOpera 9.2Win 88+ / OSX.3+-A
40PrestoOpera 9.5Win 88+ / OSX.3+-A
41PrestoOpera for WiiWii-A
42PrestoNokia N800N800-A
43PrestoNintendo DS browserNintendo DS8.5C/A
44KHTMLKonqureror 3.1KDE 3.13.1C
45KHTMLKonqureror 3.3KDE 3.33.3A
46KHTMLKonqureror 3.5KDE 3.53.5A
47TasmanInternet Explorer 4.5Mac OS 8-9-X
48TasmanInternet Explorer 5.1Mac OS 7.6-91C
49TasmanInternet Explorer 5.2Mac OS 8-X1C
50MiscNetFront 3.1Embedded devices-C
51MiscNetFront 3.4Embedded devices-A
52MiscDillo 0.8Embedded devices-X
53MiscLinksText only-X
54MiscLynxText only-X
55MiscIE MobileWindows Mobile 6-C
56MiscPSP browserPSP-C
57Other browsersAll others--U
 Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sScrollX": "100%",
+		"sScrollXInner": "150%",
+		"bScrollCollapse": true,
+		"fnDrawCallback": function ( oSettings ) {
+			/* Need to redo the counters if filtered or sorted */
+			if ( oSettings.bSorted || oSettings.bFiltered ) {
+				for ( var i=0, iLen=oSettings.aiDisplay.length ; i<iLen ; i++ ) {
+					this.fnUpdate( i+1, oSettings.aiDisplay[i], 0, false, false );
+				}
+			}
+		},
+		"aoColumnDefs": [
+			{ "bSortable": false, "sClass": "index", "aTargets": [ 0 ] }
+		],
+		"aaSorting": [[ 1, 'asc' ]]
+	} );
+	new FixedColumns( oTable );
+} );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/left_right_columns.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/left_right_columns.html new file mode 100644 index 0000000..df92ec7 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/left_right_columns.html @@ -0,0 +1,678 @@ + + + + + + + FixedColumns example + + + + + + + +
+
+ FixedColumns example - left and right columns fixed +
+ +

Preamble

+

FixedColumns allows columns to be fixed from both the left and right hand sides of the table. Fixing right hand-side columns is done by using the iRightColumns initialisation parameter, which works just the same as iLeftColumns does for the left side of the table. This example shows both the left and right columns being fixed in place, and a bit of initialisation of DataTables to provide index columns.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 Rendering engineBrowserPlatform(s)Engine versionCSS grade 
 Rendering engineBrowserPlatform(s)Engine versionCSS grade 
1TridentInternet + Explorer 4.0Win 95+4X1
2TridentInternet + Explorer 5.0Win 95+5C2
3TridentInternet + Explorer 5.5Win 95+5.5A3
4TridentInternet + Explorer 6Win 98+6A4
5TridentInternet Explorer 7Win XP SP2+7A5
6TridentAOL browser (AOL desktop)Win XP6A6
7GeckoFirefox 1.0Win 98+ / OSX.2+1.7A7
8GeckoFirefox 1.5Win 98+ / OSX.2+1.8A8
9GeckoFirefox 2.0Win 98+ / OSX.2+1.8A9
10GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A10
11GeckoCamino 1.0OSX.2+1.8A11
12GeckoCamino 1.5OSX.3+1.8A12
13GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A13
14GeckoNetscape Browser 8Win 98SE+1.7A14
15GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A15
16GeckoMozilla 1.0Win 95+ / OSX.1+1A16
17GeckoMozilla 1.1Win 95+ / OSX.1+1.1A17
18GeckoMozilla 1.2Win 95+ / OSX.1+1.2A18
19GeckoMozilla 1.3Win 95+ / OSX.1+1.3A19
20GeckoMozilla 1.4Win 95+ / OSX.1+1.4A20
21GeckoMozilla 1.5Win 95+ / OSX.1+1.5A21
22GeckoMozilla 1.6Win 95+ / OSX.1+1.6A22
23GeckoMozilla 1.7Win 98+ / OSX.1+1.7A23
24GeckoMozilla 1.8Win 98+ / OSX.1+1.8A24
25GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A25
26GeckoEpiphany 2.20Gnome1.8A26
27WebkitSafari 1.2OSX.3125.5A27
28WebkitSafari 1.3OSX.3312.8A28
29WebkitSafari 2.0OSX.4+419.3A29
30WebkitSafari 3.0OSX.4+522.1A30
31WebkitOmniWeb 5.5OSX.4+420A31
32WebkitiPod Touch / iPhoneiPod420.1A32
33WebkitS60S60413A33
34PrestoOpera 7.0Win 95+ / OSX.1+-A34
35PrestoOpera 7.5Win 95+ / OSX.2+-A35
36PrestoOpera 8.0Win 95+ / OSX.2+-A36
37PrestoOpera 8.5Win 95+ / OSX.2+-A37
38PrestoOpera 9.0Win 95+ / OSX.3+-A38
39PrestoOpera 9.2Win 88+ / OSX.3+-A39
40PrestoOpera 9.5Win 88+ / OSX.3+-A40
41PrestoOpera for WiiWii-A41
42PrestoNokia N800N800-A42
43PrestoNintendo DS browserNintendo DS8.5C/A43
44KHTMLKonqureror 3.1KDE 3.13.1C44
45KHTMLKonqureror 3.3KDE 3.33.3A45
46KHTMLKonqureror 3.5KDE 3.53.5A46
47TasmanInternet Explorer 4.5Mac OS 8-9-X47
48TasmanInternet Explorer 5.1Mac OS 7.6-91C48
49TasmanInternet Explorer 5.2Mac OS 8-X1C49
50MiscNetFront 3.1Embedded devices-C50
51MiscNetFront 3.4Embedded devices-A51
52MiscDillo 0.8Embedded devices-X52
53MiscLinksText only-X53
54MiscLynxText only-X54
55MiscIE MobileWindows Mobile 6-C55
56MiscPSP browserPSP-C56
57Other browsersAll others--U57
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sScrollX": "100%",
+		"sScrollXInner": "150%",
+		"bScrollCollapse": true,
+		"fnDrawCallback": function ( oSettings ) {
+			/* Need to redo the counters if filtered or sorted */
+			if ( oSettings.bSorted || oSettings.bFiltered ) {
+				for ( var i=0, iLen=oSettings.aiDisplay.length ; i<iLen ; i++ ) {
+					this.fnUpdate( i+1, oSettings.aiDisplay[i], 0, false, false );
+					this.fnUpdate( i+1, oSettings.aiDisplay[i], 6, false, false );
+				}
+			}
+		},
+		"aoColumnDefs": [
+			{ "bSortable": false, "sClass": "indexLeft", "aTargets": [ 0 ] },
+			{ "bSortable": false, "sClass": "indexRight", "aTargets": [ -1 ] }
+		],
+		"aaSorting": [[ 1, 'asc' ]]
+	} );
+	
+	new FixedColumns( oTable, {
+		"iLeftColumns": 1,
+		"iRightColumns": 1
+	} );
+} );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/media/js/FixedColumns.js b/modules/thirdparty/jquery/datatables/extras/FixedColumns/media/js/FixedColumns.js new file mode 100644 index 0000000..5321745 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/media/js/FixedColumns.js @@ -0,0 +1,1226 @@ +/** + * @summary FixedColumns + * @description Freeze columns in place on a scrolling DataTable + * @file FixedColumns.js + * @version 2.0.3 + * @author Allan Jardine (www.sprymedia.co.uk) + * @license GPL v2 or BSD 3 point style + * @contact www.sprymedia.co.uk/contact + * + * @copyright Copyright 2010-2011 Allan Jardine, all rights reserved. + * + * This source file is free software, under either the GPL v2 license or a + * BSD style license, available at: + * http://datatables.net/license_gpl2 + * http://datatables.net/license_bsd + */ + + +/* Global scope for FixedColumns */ +var FixedColumns; + +(function($, window, document) { + + +/** + * When making use of DataTables' x-axis scrolling feature, you may wish to + * fix the left most column in place. This plug-in for DataTables provides + * exactly this option (note for non-scrolling tables, please use the + * FixedHeader plug-in, which can fix headers, footers and columns). Key + * features include: + *
    + *
  • Freezes the left or right most columns to the side of the table
  • + *
  • Option to freeze two or more columns
  • + *
  • Full integration with DataTables' scrolling options
  • + *
  • Speed - FixedColumns is fast in its operation
  • + *
+ * + * @class + * @constructor + * @param {object} oDT DataTables instance + * @param {object} [oInit={}] Configuration object for FixedColumns. Options are defined by {@link FixedColumns.defaults} + * + * @requires jQuery 1.3+ + * @requires DataTables 1.8.0+ + * + * @example + * var oTable = $('#example').dataTable( { + * "sScrollX": "100%" + * } ); + * new FixedColumns( oTable ); + */ +FixedColumns = function ( oDT, oInit ) { + /* Sanity check - you just know it will happen */ + if ( ! this instanceof FixedColumns ) + { + alert( "FixedColumns warning: FixedColumns must be initialised with the 'new' keyword." ); + return; + } + + if ( typeof oInit == 'undefined' ) + { + oInit = {}; + } + + /** + * Settings object which contains customisable information for FixedColumns instance + * @namespace + * @extends FixedColumns.defaults + */ + this.s = { + /** + * DataTables settings objects + * @type object + * @default Obtained from DataTables instance + */ + "dt": oDT.fnSettings(), + + /** + * Number of columns in the DataTable - stored for quick access + * @type int + * @default Obtained from DataTables instance + */ + "iTableColumns": oDT.fnSettings().aoColumns.length, + + /** + * Original widths of the columns as rendered by DataTables + * @type array. + * @default [] + */ + "aiWidths": [], + + /** + * Flag to indicate if we are dealing with IE6/7 as these browsers need a little hack + * in the odd place + * @type boolean + * @default Automatically calculated + * @readonly + */ + "bOldIE": ($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0")) + }; + + + /** + * DOM elements used by the class instance + * @namespace + * + */ + this.dom = { + /** + * DataTables scrolling element + * @type node + * @default null + */ + "scroller": null, + + /** + * DataTables header table + * @type node + * @default null + */ + "header": null, + + /** + * DataTables body table + * @type node + * @default null + */ + "body": null, + + /** + * DataTables footer table + * @type node + * @default null + */ + "footer": null, + + /** + * Display grid elements + * @namespace + */ + "grid": { + /** + * Grid wrapper. This is the container element for the 3x3 grid + * @type node + * @default null + */ + "wrapper": null, + + /** + * DataTables scrolling element. This element is the DataTables + * component in the display grid (making up the main table - i.e. + * not the fixed columns). + * @type node + * @default null + */ + "dt": null, + + /** + * Left fixed column grid components + * @namespace + */ + "left": { + "wrapper": null, + "head": null, + "body": null, + "foot": null + }, + + /** + * Right fixed column grid components + * @namespace + */ + "right": { + "wrapper": null, + "head": null, + "body": null, + "foot": null + } + }, + + /** + * Cloned table nodes + * @namespace + */ + "clone": { + /** + * Left column cloned table nodes + * @namespace + */ + "left": { + /** + * Cloned header table + * @type node + * @default null + */ + "header": null, + + /** + * Cloned body table + * @type node + * @default null + */ + "body": null, + + /** + * Cloned footer table + * @type node + * @default null + */ + "footer": null + }, + + /** + * Right column cloned table nodes + * @namespace + */ + "right": { + /** + * Cloned header table + * @type node + * @default null + */ + "header": null, + + /** + * Cloned body table + * @type node + * @default null + */ + "body": null, + + /** + * Cloned footer table + * @type node + * @default null + */ + "footer": null + } + } + }; + + /* Attach the instance to the DataTables instance so it can be accessed easily */ + this.s.dt.oFixedColumns = this; + + /* Let's do it */ + this._fnConstruct( oInit ); +}; + + + +FixedColumns.prototype = { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Public methods + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** + * Update the fixed columns - including headers and footers. Note that FixedColumns will + * automatically update the display whenever the host DataTable redraws. + * @returns {void} + * @example + * var oTable = $('#example').dataTable( { + * "sScrollX": "100%" + * } ); + * var oFC = new FixedColumns( oTable ); + * + * // at some later point when the table has been manipulated.... + * oFC.fnUpdate(); + */ + "fnUpdate": function () + { + this._fnDraw( true ); + }, + + + /** + * Recalculate the resizes of the 3x3 grid that FixedColumns uses for display of the table. + * This is useful if you update the width of the table container. Note that FixedColumns will + * perform this function automatically when the window.resize event is fired. + * @returns {void} + * @example + * var oTable = $('#example').dataTable( { + * "sScrollX": "100%" + * } ); + * var oFC = new FixedColumns( oTable ); + * + * // Resize the table container and then have FixedColumns adjust its layout.... + * $('#content').width( 1200 ); + * oFC.fnRedrawLayout(); + */ + "fnRedrawLayout": function () + { + this._fnGridLayout(); + }, + + + /** + * Mark a row such that it's height should be recalculated when using 'semiauto' row + * height matching. This function will have no effect when 'none' or 'auto' row height + * matching is used. + * @param {Node} nTr TR element that should have it's height recalculated + * @returns {void} + * @example + * var oTable = $('#example').dataTable( { + * "sScrollX": "100%" + * } ); + * var oFC = new FixedColumns( oTable ); + * + * // manipulate the table - mark the row as needing an update then update the table + * // this allows the redraw performed by DataTables fnUpdate to recalculate the row + * // height + * oFC.fnRecalculateHeight(); + * oTable.fnUpdate( $('#example tbody tr:eq(0)')[0], ["insert date", 1, 2, 3 ... ]); + */ + "fnRecalculateHeight": function ( nTr ) + { + nTr._DTTC_iHeight = null; + nTr.style.height = 'auto'; + }, + + + /** + * Set the height of a given row - provides cross browser compatibility + * @param {Node} nTarget TR element that should have it's height recalculated + * @param {int} iHeight Height in pixels to set + * @returns {void} + * @example + * var oTable = $('#example').dataTable( { + * "sScrollX": "100%" + * } ); + * var oFC = new FixedColumns( oTable ); + * + * // You may want to do this after manipulating a row in the fixed column + * oFC.fnSetRowHeight( $('#example tbody tr:eq(0)')[0], 50 ); + */ + "fnSetRowHeight": function ( nTarget, iHeight ) + { + var jqBoxHack = $(nTarget).children(':first'); + var iBoxHack = jqBoxHack.outerHeight() - jqBoxHack.height(); + + /* Can we use some kind of object detection here?! This is very nasty - damn browsers */ + if ( $.browser.mozilla || $.browser.opera ) + { + nTarget.style.height = iHeight+"px"; + } + else + { + $(nTarget).children().height( iHeight-iBoxHack ); + } + }, + + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Private methods (they are of course public in JS, but recommended as private) + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** + * Initialisation for FixedColumns + * @param {Object} oInit User settings for initialisation + * @returns {void} + * @private + */ + "_fnConstruct": function ( oInit ) + { + var i, iLen, iWidth, + that = this; + + /* Sanity checking */ + if ( typeof this.s.dt.oInstance.fnVersionCheck != 'function' || + this.s.dt.oInstance.fnVersionCheck( '1.8.0' ) !== true ) + { + alert( "FixedColumns "+FixedColumns.VERSION+" required DataTables 1.8.0 or later. "+ + "Please upgrade your DataTables installation" ); + return; + } + + if ( this.s.dt.oScroll.sX === "" ) + { + this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "FixedColumns is not needed (no "+ + "x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for "+ + "column fixing when scrolling is not enabled" ); + return; + } + + /* Apply the settings from the user / defaults */ + this.s = $.extend( true, this.s, FixedColumns.defaults, oInit ); + + /* Set up the DOM as we need it and cache nodes */ + this.dom.grid.dt = $(this.s.dt.nTable).parents('div.dataTables_scroll')[0]; + this.dom.scroller = $('div.dataTables_scrollBody', this.dom.grid.dt )[0]; + + var iScrollWidth = $(this.dom.grid.dt).width(); + var iLeftWidth = 0; + var iRightWidth = 0; + + $('tbody>tr:eq(0)>td', this.s.dt.nTable).each( function (i) { + iWidth = $(this).outerWidth(); + that.s.aiWidths.push( iWidth ); + if ( i < that.s.iLeftColumns ) + { + iLeftWidth += iWidth; + } + if ( that.s.iTableColumns-that.s.iRightColumns <= i ) + { + iRightWidth += iWidth; + } + } ); + + if ( this.s.iLeftWidth === null ) + { + this.s.iLeftWidth = this.s.sLeftWidth == 'fixed' ? + iLeftWidth : (iLeftWidth/iScrollWidth) * 100; + } + + if ( this.s.iRightWidth === null ) + { + this.s.iRightWidth = this.s.sRightWidth == 'fixed' ? + iRightWidth : (iRightWidth/iScrollWidth) * 100; + } + + /* Set up the DOM that we want for the fixed column layout grid */ + this._fnGridSetup(); + + /* Use the DataTables API method fnSetColumnVis to hide the columns we are going to fix */ + for ( i=0 ; i 0 ) + { + that.dom.grid.right.body.scrollTop = that.dom.scroller.scrollTop; + } + } ); + + $(window).resize( function () { + that._fnGridLayout.call( that ); + } ); + + var bFirstDraw = true; + this.s.dt.aoDrawCallback = [ { + "fn": function () { + that._fnDraw.call( that, bFirstDraw ); + that._fnGridHeight( that ); + bFirstDraw = false; + }, + "sName": "FixedColumns" + } ].concat( this.s.dt.aoDrawCallback ); + + /* Get things right to start with - note that due to adjusting the columns, there must be + * another redraw of the main table. It doesn't need to be a full redraw however. + */ + this._fnGridLayout(); + this._fnGridHeight(); + this.s.dt.oInstance.fnDraw(false); + }, + + + /** + * Set up the DOM for the fixed column. The way the layout works is to create a 1x3 grid + * for the left column, the DataTable (for which we just reuse the scrolling element DataTable + * puts into the DOM) and the right column. In each of he two fixed column elements there is a + * grouping wrapper element and then a head, body and footer wrapper. In each of these we then + * place the cloned header, body or footer tables. This effectively gives as 3x3 grid structure. + * @returns {void} + * @private + */ + "_fnGridSetup": function () + { + var that = this; + + this.dom.body = this.s.dt.nTable; + this.dom.header = this.s.dt.nTHead.parentNode; + this.dom.header.parentNode.parentNode.style.position = "relative"; + + var nSWrapper = + $('
'+ + '
'+ + '
'+ + '
'+ + '
'+ + '
'+ + '
'+ + '
'+ + '
'+ + '
'+ + '
'+ + '
')[0]; + nLeft = nSWrapper.childNodes[0]; + nRight = nSWrapper.childNodes[1]; + + this.dom.grid.wrapper = nSWrapper; + this.dom.grid.left.wrapper = nLeft; + this.dom.grid.left.head = nLeft.childNodes[0]; + this.dom.grid.left.body = nLeft.childNodes[1]; + + if ( this.s.iRightColumns > 0 ) + { + this.dom.grid.right.wrapper = nRight; + this.dom.grid.right.head = nRight.childNodes[0]; + this.dom.grid.right.body = nRight.childNodes[1]; + } + + if ( this.s.dt.nTFoot ) + { + this.dom.footer = this.s.dt.nTFoot.parentNode; + this.dom.grid.left.foot = nLeft.childNodes[2]; + if ( this.s.iRightColumns > 0 ) + { + this.dom.grid.right.foot = nRight.childNodes[2]; + } + } + + nSWrapper.appendChild( nLeft ); + this.dom.grid.dt.parentNode.insertBefore( nSWrapper, this.dom.grid.dt ); + nSWrapper.appendChild( this.dom.grid.dt ); + + this.dom.grid.dt.style.position = "absolute"; + this.dom.grid.dt.style.top = "0px"; + this.dom.grid.dt.style.left = this.s.iLeftWidth+"px"; + this.dom.grid.dt.style.width = ($(this.dom.grid.dt).width()-this.s.iLeftWidth-this.s.iRightWidth)+"px"; + }, + + + /** + * Style and position the grid used for the FixedColumns layout based on the instance settings. + * Specifically sLeftWidth ('fixed' or 'absolute'), iLeftWidth (px if fixed, % if absolute) and + * there 'right' counterparts. + * @returns {void} + * @private + */ + "_fnGridLayout": function () + { + var oGrid = this.dom.grid; + var iTotal = $(oGrid.wrapper).width(); + var iLeft = 0, iRight = 0, iRemainder = 0; + + if ( this.s.sLeftWidth == 'fixed' ) + { + iLeft = this.s.iLeftWidth; + } + else + { + iLeft = ( this.s.iLeftWidth / 100 ) * iTotal; + } + + if ( this.s.sRightWidth == 'fixed' ) + { + iRight = this.s.iRightWidth; + } + else + { + iRight = ( this.s.iRightWidth / 100 ) * iTotal; + } + + iRemainder = iTotal - iLeft - iRight; + + oGrid.left.wrapper.style.width = iLeft+"px"; + oGrid.dt.style.width = iRemainder+"px"; + oGrid.dt.style.left = iLeft+"px"; + + if ( this.s.iRightColumns > 0 ) + { + oGrid.right.wrapper.style.width = iRight+"px"; + oGrid.right.wrapper.style.left = (iTotal-iRight)+"px"; + } + }, + + + /** + * Recalculate and set the height of the grid components used for positioning of the + * FixedColumn display grid. + * @returns {void} + * @private + */ + "_fnGridHeight": function () + { + var oGrid = this.dom.grid; + var iHeight = $(this.dom.grid.dt).height(); + + oGrid.wrapper.style.height = iHeight+"px"; + oGrid.left.body.style.height = $(this.dom.scroller).height()+"px"; + oGrid.left.wrapper.style.height = iHeight+"px"; + + if ( this.s.iRightColumns > 0 ) + { + oGrid.right.wrapper.style.height = iHeight+"px"; + oGrid.right.body.style.height = $(this.dom.scroller).height()+"px"; + } + }, + + + /** + * Clone and position the fixed columns + * @returns {void} + * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true) + * @private + */ + "_fnDraw": function ( bAll ) + { + this._fnCloneLeft( bAll ); + this._fnCloneRight( bAll ); + + /* Draw callback function */ + if ( this.s.fnDrawCallback !== null ) + { + this.s.fnDrawCallback.call( this, this.dom.clone.left, this.dom.clone.right ); + } + + /* Event triggering */ + $(this).trigger( 'draw', { + "leftClone": this.dom.clone.left, + "rightClone": this.dom.clone.right + } ); + }, + + + /** + * Clone the right columns + * @returns {void} + * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true) + * @private + */ + "_fnCloneRight": function ( bAll ) + { + if ( this.s.iRightColumns <= 0 ) + { + return; + } + + var that = this, + i, jq, + aiColumns = []; + + for ( i=this.s.iTableColumns-this.s.iRightColumns ; ithead', oClone.header); + jqCloneThead.empty(); + + /* Add the created cloned TR elements to the table */ + for ( i=0, iLen=aoCloneLayout.length ; ithead', oClone.header)[0] ); + + for ( i=0, iLen=aoCloneLayout.length ; itbody>tr', that.dom.body).css('height', 'auto'); + } + + if ( oClone.body !== null ) + { + oClone.body.parentNode.removeChild( oClone.body ); + oClone.body = null; + } + + oClone.body = $(this.dom.body).clone(true)[0]; + oClone.body.className += " DTFC_Cloned"; + oClone.body.style.paddingBottom = this.s.dt.oScroll.iBarWidth+"px"; + oClone.body.style.marginBottom = (this.s.dt.oScroll.iBarWidth*2)+"px"; /* For IE */ + if ( oClone.body.getAttribute('id') !== null ) + { + oClone.body.removeAttribute('id'); + } + + $('>thead>tr', oClone.body).empty(); + $('>tfoot', oClone.body).remove(); + + var nBody = $('tbody', oClone.body)[0]; + $(nBody).empty(); + if ( this.s.dt.aiDisplay.length > 0 ) + { + /* Copy the DataTables' header elements to force the column width in exactly the + * same way that DataTables does it - have the header element, apply the width and + * colapse it down + */ + var nInnerThead = $('>thead>tr', oClone.body)[0]; + for ( iIndex=0 ; iIndextbody>tr', that.dom.body).each( function (z) { + var n = this.cloneNode(false); + var i = that.s.dt.oFeatures.bServerSide===false ? + that.s.dt.aiDisplay[ that.s.dt._iDisplayStart+z ] : z; + for ( iIndex=0 ; iIndextbody>tr', that.dom.body).each( function (z) { + nClone = this.cloneNode(true); + nClone.className += ' DTFC_NoData'; + $('td', nClone).html(''); + nBody.appendChild( nClone ); + } ); + } + + oClone.body.style.width = "100%"; + oGrid.body.appendChild( oClone.body ); + + this._fnEqualiseHeights( 'tbody', that.dom.body, oClone.body ); + + /* + * Footer + */ + if ( this.s.dt.nTFoot !== null ) + { + if ( bAll ) + { + if ( oClone.footer !== null ) + { + oClone.footer.parentNode.removeChild( oClone.footer ); + } + oClone.footer = $(this.dom.footer).clone(true)[0]; + oClone.footer.className += " DTFC_Cloned"; + oClone.footer.style.width = "100%"; + oGrid.foot.appendChild( oClone.footer ); + + /* Copy the footer just like we do for the header */ + var aoCloneLayout = this._fnCopyLayout( this.s.dt.aoFooter, aiColumns ); + var jqCloneTfoot = $('>tfoot', oClone.footer); + jqCloneTfoot.empty(); + + for ( i=0, iLen=aoCloneLayout.length ; itfoot', oClone.footer)[0] ); + + for ( i=0, iLen=aoCloneLayout.length ; ithead', oClone.header)[0] ); + $(anUnique).each( function (i) { + iColumn = aiColumns[i]; + this.style.width = that.s.aiWidths[iColumn]+"px"; + } ); + + if ( that.s.dt.nTFoot !== null ) + { + anUnique = this.s.dt.oApi._fnGetUniqueThs( this.s.dt, $('>tfoot', oClone.footer)[0] ); + $(anUnique).each( function (i) { + iColumn = aiColumns[i]; + this.style.width = that.s.aiWidths[iColumn]+"px"; + } ); + } + }, + + + /** + * From a given table node (THEAD etc), get a list of TR direct child elements + * @param {Node} nIn Table element to search for TR elements (THEAD, TBODY or TFOOT element) + * @returns {Array} List of TR elements found + * @private + */ + "_fnGetTrNodes": function ( nIn ) + { + var aOut = []; + for ( var i=0, iLen=nIn.childNodes.length ; i'+nodeName+'>tr:eq(0)', original).children(':first'), + iBoxHack = jqBoxHack.outerHeight() - jqBoxHack.height(), + anOriginal = this._fnGetTrNodes( rootOriginal ), + anClone = this._fnGetTrNodes( rootClone ); + + for ( i=0, iLen=anClone.length ; i iHeightOriginal ? iHeightClone : iHeightOriginal; + + if ( this.s.sHeightMatch == 'semiauto' ) + { + anOriginal[i]._DTTC_iHeight = iHeight; + } + + /* Can we use some kind of object detection here?! This is very nasty - damn browsers */ + if ( $.browser.msie && $.browser.version < 8 ) + { + $(anClone[i]).children().height( iHeight-iBoxHack ); + $(anOriginal[i]).children().height( iHeight-iBoxHack ); + } + else + { + anClone[i].style.height = iHeight+"px"; + anOriginal[i].style.height = iHeight+"px"; + } + } + } +}; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Statics + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +/** + * FixedColumns default settings for initialisation + * @namespace + * @static + */ +FixedColumns.defaults = { + /** + * Number of left hand columns to fix in position + * @type int + * @default 1 + * @static + * @example + * var oTable = $('#example').dataTable( { + * "sScrollX": "100%" + * } ); + * new FixedColumns( oTable, { + * "iLeftColumns": 2 + * } ); + */ + "iLeftColumns": 1, + + /** + * Number of right hand columns to fix in position + * @type int + * @default 0 + * @static + * @example + * var oTable = $('#example').dataTable( { + * "sScrollX": "100%" + * } ); + * new FixedColumns( oTable, { + * "iRightColumns": 1 + * } ); + */ + "iRightColumns": 0, + + /** + * Draw callback function which is called when FixedColumns has redrawn the fixed assets + * @type function(object, object):void + * @default null + * @static + * @example + * var oTable = $('#example').dataTable( { + * "sScrollX": "100%" + * } ); + * new FixedColumns( oTable, { + * "fnDrawCallback": function () { + * alert( "FixedColumns redraw" ); + * } + * } ); + */ + "fnDrawCallback": null, + + /** + * Type of left column size calculation. Can take the values of "fixed", whereby the iLeftWidth + * value will be treated as a pixel value, or "relative" for which case iLeftWidth will be + * treated as a percentage value. + * @type string + * @default fixed + * @static + * @example + * var oTable = $('#example').dataTable( { + * "sScrollX": "100%" + * } ); + * new FixedColumns( oTable, { + * "sLeftWidth": "relative", + * "iLeftWidth": 10 // percentage + * } ); + */ + "sLeftWidth": "fixed", + + /** + * Width to set for the width of the left fixed column(s) - note that the behaviour of this + * property is directly effected by the sLeftWidth property. If not defined then this property + * is calculated automatically from what has been assigned by DataTables. + * @type int + * @default null + * @static + * @example + * var oTable = $('#example').dataTable( { + * "sScrollX": "100%" + * } ); + * new FixedColumns( oTable, { + * "iLeftWidth": 100 // pixels + * } ); + */ + "iLeftWidth": null, + + /** + * Type of right column size calculation. Can take the values of "fixed", whereby the + * iRightWidth value will be treated as a pixel value, or "relative" for which case + * iRightWidth will be treated as a percentage value. + * @type string + * @default fixed + * @static + * @example + * var oTable = $('#example').dataTable( { + * "sScrollX": "100%" + * } ); + * new FixedColumns( oTable, { + * "sRightWidth": "relative", + * "iRightWidth": 10 // percentage + * } ); + */ + "sRightWidth": "fixed", + + /** + * Width to set for the width of the right fixed column(s) - note that the behaviour of this + * property is directly effected by the sRightWidth property. If not defined then this property + * is calculated automatically from what has been assigned by DataTables. + * @type int + * @default null + * @static + * @example + * var oTable = $('#example').dataTable( { + * "sScrollX": "100%" + * } ); + * new FixedColumns( oTable, { + * "iRightWidth": 200 // pixels + * } ); + */ + "iRightWidth": null, + + /** + * Height matching algorthim to use. This can be "none" which will result in no height + * matching being applied by FixedColumns (height matching could be forced by CSS in this + * case), "semiauto" whereby the height calculation will be performed once, and the result + * cached to be used again (fnRecalculateHeight can be used to force recalculation), or + * "auto" when height matching is performed on every draw (slowest but must accurate) + * @type string + * @default semiauto + * @static + * @example + * var oTable = $('#example').dataTable( { + * "sScrollX": "100%" + * } ); + * new FixedColumns( oTable, { + * "sHeightMatch": "auto" + * } ); + */ + "sHeightMatch": "semiauto" +}; + + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Constants + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +/** + * Name of this class + * @constant CLASS + * @type String + * @default FixedColumns + */ +FixedColumns.prototype.CLASS = "FixedColumns"; + + +/** + * FixedColumns version + * @constant FixedColumns.VERSION + * @type String + * @default See code + * @static + */ +FixedColumns.VERSION = "2.0.3"; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Fired events (for documentation) + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +/** + * Event fired whenever FixedColumns redraws the fixed columns (i.e. clones the table elements from the main DataTable). This will occur whenever the DataTable that the FixedColumns instance is attached does its own draw. + * @name FixedColumns#draw + * @event + * @param {event} e jQuery event object + * @param {object} o Event parameters from FixedColumns + * @param {object} o.leftClone Instance's object dom.clone.left for easy reference. This object contains references to the left fixed clumn column's nodes + * @param {object} o.rightClone Instance's object dom.clone.right for easy reference. This object contains references to the right fixed clumn column's nodes + */ + +})(jQuery, window, document); diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/media/js/FixedColumns.min.js b/modules/thirdparty/jquery/datatables/extras/FixedColumns/media/js/FixedColumns.min.js new file mode 100644 index 0000000..21e4a52 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/media/js/FixedColumns.min.js @@ -0,0 +1,48 @@ +/* + * File: FixedColumns.min.js + * Version: 2.0.3 + * Author: Allan Jardine (www.sprymedia.co.uk) + * + * Copyright 2010-2010 Allan Jardine, all rights reserved. + * + * This source file is free software, under either the GPL v2 license or a + * BSD style license, available at: + * http://datatables.net/license_gpl2 + * http://datatables.net/license_bsd + * + * This source file 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 license files for details. + */ +/* + GPL v2 or BSD 3 point style + @contact www.sprymedia.co.uk/contact + + @copyright Copyright 2010-2011 Allan Jardine, all rights reserved. + + This source file is free software, under either the GPL v2 license or a + BSD style license, available at: + http://datatables.net/license_gpl2 + http://datatables.net/license_bsd +*/ +var FixedColumns; +(function(b,q){FixedColumns=function(a,e){!this instanceof FixedColumns?alert("FixedColumns warning: FixedColumns must be initialised with the 'new' keyword."):("undefined"==typeof e&&(e={}),this.s={dt:a.fnSettings(),iTableColumns:a.fnSettings().aoColumns.length,aiWidths:[],bOldIE:b.browser.msie&&("6.0"==b.browser.version||"7.0"==b.browser.version)},this.dom={scroller:null,header:null,body:null,footer:null,grid:{wrapper:null,dt:null,left:{wrapper:null,head:null,body:null,foot:null},right:{wrapper:null, +head:null,body:null,foot:null}},clone:{left:{header:null,body:null,footer:null},right:{header:null,body:null,footer:null}}},this.s.dt.oFixedColumns=this,this._fnConstruct(e))};FixedColumns.prototype={fnUpdate:function(){this._fnDraw(!0)},fnRedrawLayout:function(){this._fnGridLayout()},fnRecalculateHeight:function(a){a._DTTC_iHeight=null;a.style.height="auto"},fnSetRowHeight:function(a,e){var c=b(a).children(":first"),c=c.outerHeight()-c.height();b.browser.mozilla||b.browser.opera?a.style.height=e+ +"px":b(a).children().height(e-c)},_fnConstruct:function(a){var e,c=this;if("function"!=typeof this.s.dt.oInstance.fnVersionCheck||!0!==this.s.dt.oInstance.fnVersionCheck("1.8.0"))alert("FixedColumns "+FixedColumns.VERSION+" required DataTables 1.8.0 or later. Please upgrade your DataTables installation");else if(""===this.s.dt.oScroll.sX)this.s.dt.oInstance.oApi._fnLog(this.s.dt,1,"FixedColumns is not needed (no x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for column fixing when scrolling is not enabled"); +else{this.s=b.extend(!0,this.s,FixedColumns.defaults,a);this.dom.grid.dt=b(this.s.dt.nTable).parents("div.dataTables_scroll")[0];this.dom.scroller=b("div.dataTables_scrollBody",this.dom.grid.dt)[0];var a=b(this.dom.grid.dt).width(),f=0,g=0;b("tbody>tr:eq(0)>td",this.s.dt.nTable).each(function(a){e=b(this).outerWidth();c.s.aiWidths.push(e);a0)c.dom.grid.right.body.scrollTop=c.dom.scroller.scrollTop});b(q).resize(function(){c._fnGridLayout.call(c)}); +var d=!0;this.s.dt.aoDrawCallback=[{fn:function(){c._fnDraw.call(c,d);c._fnGridHeight(c);d=false},sName:"FixedColumns"}].concat(this.s.dt.aoDrawCallback);this._fnGridLayout();this._fnGridHeight();this.s.dt.oInstance.fnDraw(!1)}},_fnGridSetup:function(){this.dom.body=this.s.dt.nTable;this.dom.header=this.s.dt.nTHead.parentNode;this.dom.header.parentNode.parentNode.style.position="relative";var a=b('
')[0]; +nLeft=a.childNodes[0];nRight=a.childNodes[1];this.dom.grid.wrapper=a;this.dom.grid.left.wrapper=nLeft;this.dom.grid.left.head=nLeft.childNodes[0];this.dom.grid.left.body=nLeft.childNodes[1];0=this.s.iRightColumns)){var b,c=[];for(b=this.s.iTableColumns-this.s.iRightColumns;b=this.s.iLeftColumns)){var b,c=[];for(b=0;bthead",a.header);k.empty();d=0;for(h=l.length;dthead",a.header)[0]);d=0;for(h=l.length;dtbody>tr",g.dom.body).css("height","auto");null!==a.body&&(a.body.parentNode.removeChild(a.body),a.body=null); +a.body=b(this.dom.body).clone(!0)[0];a.body.className+=" DTFC_Cloned";a.body.style.paddingBottom=this.s.dt.oScroll.iBarWidth+"px";a.body.style.marginBottom=2*this.s.dt.oScroll.iBarWidth+"px";null!==a.body.getAttribute("id")&&a.body.removeAttribute("id");b(">thead>tr",a.body).empty();b(">tfoot",a.body).remove();var p=b("tbody",a.body)[0];b(p).empty();if(0thead>tr",a.body)[0];for(n=0;ntbody>tr",g.dom.body).each(function(a){var d=this.cloneNode(false),a=g.s.dt.oFeatures.bServerSide===false?g.s.dt.aiDisplay[g.s.dt._iDisplayStart+a]:a;for(n=0;ntbody>tr", +g.dom.body).each(function(){j=this.cloneNode(true);j.className=j.className+" DTFC_NoData";b("td",j).html("");p.appendChild(j)});a.body.style.width="100%";e.body.appendChild(a.body);this._fnEqualiseHeights("tbody",g.dom.body,a.body);if(null!==this.s.dt.nTFoot){if(f){null!==a.footer&&a.footer.parentNode.removeChild(a.footer);a.footer=b(this.dom.footer).clone(!0)[0];a.footer.className+=" DTFC_Cloned";a.footer.style.width="100%";e.foot.appendChild(a.footer);l=this._fnCopyLayout(this.s.dt.aoFooter,c); +e=b(">tfoot",a.footer);e.empty();d=0;for(h=l.length;dtfoot",a.footer)[0]);d=0;for(h=l.length;dthead",a.header)[0]);b(h).each(function(a){m=c[a]; +this.style.width=g.s.aiWidths[m]+"px"});null!==g.s.dt.nTFoot&&(h=this.s.dt.oApi._fnGetUniqueThs(this.s.dt,b(">tfoot",a.footer)[0]),b(h).each(function(a){m=c[a];this.style.width=g.s.aiWidths[m]+"px"}))},_fnGetTrNodes:function(a){for(var b=[],c=0,f=a.childNodes.length;c"+a+">tr:eq(0)",e).children(":first"),a=a.outerHeight()-a.height(),d=this._fnGetTrNodes(d),h=this._fnGetTrNodes(c),c=0,e=h.length;cf?g:f,"semiauto"==this.s.sHeightMatch&&(d[c]._DTTC_iHeight=f),b.browser.msie&&8>b.browser.version)?(b(h[c]).children().height(f-a),b(d[c]).children().height(f- +a)):(h[c].style.height=f+"px",d[c].style.height=f+"px")}};FixedColumns.defaults={iLeftColumns:1,iRightColumns:0,fnDrawCallback:null,sLeftWidth:"fixed",iLeftWidth:null,sRightWidth:"fixed",iRightWidth:null,sHeightMatch:"semiauto"};FixedColumns.prototype.CLASS="FixedColumns";FixedColumns.VERSION="2.0.3"})(jQuery,window,document); diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/media/js/FixedColumns.min.js.gz b/modules/thirdparty/jquery/datatables/extras/FixedColumns/media/js/FixedColumns.min.js.gz new file mode 100644 index 0000000..df5a5a3 Binary files /dev/null and b/modules/thirdparty/jquery/datatables/extras/FixedColumns/media/js/FixedColumns.min.js.gz differ diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/right_column.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/right_column.html new file mode 100644 index 0000000..dac22e8 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/right_column.html @@ -0,0 +1,520 @@ + + + + + + + FixedColumns example + + + + + + + +
+
+ FixedColumns example - right hand column only fixed +
+ +

Preamble

+

FixedColumns has the ability to freeze columns on both the left and right hand sides of the table. By default it will fix the first column on the left, but using the initialisation parameters iLeftColumns and iRightColumns you can alter this to fix the columns on the right as well. This example shows a single column fixed in place, in this case the right most column.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+ 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%",
+ 		"sScrollXInner": "150%",
+ 		"bScrollCollapse": true
+ 	} );
+ 	new FixedColumns( oTable, {
+		"iLeftColumns": 0,
+		"iRightColumns": 1
+ 	} );
+ } );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/row_grouping.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/row_grouping.html new file mode 100644 index 0000000..4cf5049 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/row_grouping.html @@ -0,0 +1,606 @@ + + + + + + + FixedColumns example + + + + + + + +
+
+ FixedColumns example - row grouping +
+ +

Preamble

+

This example is designed to re-implement the visual effect of the DataTables row grouping example with a fixed column. It is alternative row grouping style to that presented in the row grouping by height example.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BrowserRendering enginePlatform(s)Engine versionCSS grade
Internet + Explorer 4.0TridentWin 95+4X
Internet + Explorer 5.0TridentWin 95+5C
Internet + Explorer 5.5TridentWin 95+5.5A
Internet + Explorer 6TridentWin 98+6A
Internet Explorer 7TridentWin XP SP2+7A
AOL browser (AOL desktop)TridentWin XP6A
Firefox 1.0GeckoWin 98+ / OSX.2+1.7A
Firefox 1.5GeckoWin 98+ / OSX.2+1.8A
Firefox 2.0GeckoWin 98+ / OSX.2+1.8A
Firefox 3.0GeckoWin 2k+ / OSX.3+1.9A
Camino 1.0GeckoOSX.2+1.8A
Camino 1.5GeckoOSX.3+1.8A
Netscape 7.2GeckoWin 95+ / Mac OS 8.6-9.21.7A
Netscape Browser 8GeckoWin 98SE+1.7A
Netscape Navigator 9GeckoWin 98+ / OSX.2+1.8A
Mozilla 1.0GeckoWin 95+ / OSX.1+1A
Mozilla 1.1GeckoWin 95+ / OSX.1+1.1A
Mozilla 1.2GeckoWin 95+ / OSX.1+1.2A
Mozilla 1.3GeckoWin 95+ / OSX.1+1.3A
Mozilla 1.4GeckoWin 95+ / OSX.1+1.4A
Mozilla 1.5GeckoWin 95+ / OSX.1+1.5A
Mozilla 1.6GeckoWin 95+ / OSX.1+1.6A
Mozilla 1.7GeckoWin 98+ / OSX.1+1.7A
Mozilla 1.8GeckoWin 98+ / OSX.1+1.8A
Seamonkey 1.1GeckoWin 98+ / OSX.2+1.8A
Epiphany 2.20GeckoGnome1.8A
Safari 1.2WebkitOSX.3125.5A
Safari 1.3WebkitOSX.3312.8A
Safari 2.0WebkitOSX.4+419.3A
Safari 3.0WebkitOSX.4+522.1A
OmniWeb 5.5WebkitOSX.4+420A
iPod Touch / iPhoneWebkitiPod420.1A
S60WebkitS60413A
Opera 7.0PrestoWin 95+ / OSX.1+-A
Opera 7.5PrestoWin 95+ / OSX.2+-A
Opera 8.0PrestoWin 95+ / OSX.2+-A
Opera 8.5PrestoWin 95+ / OSX.2+-A
Opera 9.0PrestoWin 95+ / OSX.3+-A
Opera 9.2PrestoWin 88+ / OSX.3+-A
Opera 9.5PrestoWin 88+ / OSX.3+-A
Opera for WiiPrestoWii-A
Nokia N800PrestoN800-A
Nintendo DS browserPrestoNintendo DS8.5C/A
Konqureror 3.1KHTMLKDE 3.13.1C
Konqureror 3.3KHTMLKDE 3.33.3A
Konqureror 3.5KHTMLKDE 3.53.5A
Internet Explorer 4.5TasmanMac OS 8-9-X
Internet Explorer 5.1TasmanMac OS 7.6-91C
Internet Explorer 5.2TasmanMac OS 8-X1C
NetFront 3.1MiscEmbedded devices-C
NetFront 3.4MiscEmbedded devices-A
Dillo 0.8MiscEmbedded devices-X
LinksMiscText only-X
LynxMiscText only-X
IE MobileMiscWindows Mobile 6-C
PSP browserMiscPSP-C
All othersOther browsers--U
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sScrollY": "300px",
+		"sScrollX": "100%",
+		"sScrollXInner": "150%",
+		"bScrollCollapse": true,
+		"bPaginate": false,
+		"aaSortingFixed": [ [1, 'asc'] ],
+		"aoColumnDefs": [
+			{ "bVisible": false, "aTargets": [1] }
+		]
+	} );
+
+	new FixedColumns( oTable, {
+		"fnDrawCallback": function ( left, right ) {
+			var oSettings = oTable.fnSettings();
+			if ( oSettings.aiDisplay.length == 0 )
+			{
+				return;
+			}
+
+			var nGroup, nCell, iIndex, sGroup;
+			var sLastGroup = "", iCorrector=0;
+			var nTrs = $('#example tbody tr');
+			var iColspan = nTrs[0].getElementsByTagName('td').length;
+
+			for ( var i=0 ; i<nTrs.length ; i++ )
+			{
+				iIndex = oSettings._iDisplayStart + i;
+				sGroup = oSettings.aoData[ oSettings.aiDisplay[iIndex] ]._aData[1]			;
+				
+				if ( sGroup != sLastGroup )
+				{
+					/* Cell to insert into main table */
+					nGroup = document.createElement( 'tr' );
+					nCell = document.createElement( 'td' );
+					nCell.colSpan = iColspan;
+					nCell.className = "group";
+					nCell.innerHTML = "&nbsp;";
+					nGroup.appendChild( nCell );
+					nTrs[i].parentNode.insertBefore( nGroup, nTrs[i] );
+
+					/* Cell to insert into the frozen columns */
+					nGroup = document.createElement( 'tr' );
+					nCell = document.createElement( 'td' );
+					nCell.className = "group";
+					nCell.innerHTML = sGroup;
+					nGroup.appendChild( nCell );
+					$(nGroup).insertBefore( $('tbody tr:eq('+(i+iCorrector)+')', left.body)[0] );
+
+					iCorrector++;
+					sLastGroup = sGroup;
+				}
+			}
+		}
+	} );
+} );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/row_grouping_height.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/row_grouping_height.html new file mode 100644 index 0000000..f265348 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/row_grouping_height.html @@ -0,0 +1,571 @@ + + + + + + + FixedColumns example + + + + + + + +
+
+ FixedColumns example - row grouping using the fixed column +
+ +

Preamble

+

This example shows how it is possible to manipulate the DOM of the fixed column to create the effect of row grouping in the table (or more generally any manipulation you wish to make). When ordered by the first column it is possible to see the grouping in full effect - if you then change the ordering to one of the other columns the grouping is dynamically changed to combine like cells. It would be readily possible to extend this example to use two fixed columns and only 'group' rows in one of the columns, potentially achieving quite a powerful effect.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox
1.5
Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sScrollY": "300px",
+		"sScrollX": "100%",
+		"sScrollXInner": "150%",
+		"bScrollCollapse": true,
+		"bPaginate": false
+	} );
+
+	new FixedColumns( oTable, {
+		"iLeftWidth": 150,
+		"fnDrawCallback": function ( left, right ) {
+			var that = this, groupVal = null, matches = 0, heights = [], index = -1;
+			
+			/* Get the heights of the cells and remove redundant ones */
+			$('tbody tr td', left.body).each( function ( i ) {
+				var currVal = this.innerHTML;
+				
+				/* Reset values on new cell data. */
+				if (currVal != groupVal) {
+					groupVal = currVal;
+					index++;
+					heights[index] = 0;
+					matches = 0;
+				} else  {
+					matches++;
+				}
+				
+				heights[ index ] += $(this.parentNode).height();
+				if ( currVal == groupVal && matches > 0 ) {
+					this.parentNode.parentNode.removeChild(this.parentNode);
+				}
+			} );
+
+			/* Now set the height of the cells which remain, from the summed heights */
+			$('tbody tr td', left.body).each( function ( i ) {
+				that.fnSetRowHeight( this.parentNode, heights[ i ] );
+			} );
+		}
+	} );
+} );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/rowspan.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/rowspan.html new file mode 100644 index 0000000..094e9ef --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/rowspan.html @@ -0,0 +1,515 @@ + + + + + + + FixedColumns example + + + + + + + +
+
+ FixedColumns example - rowspan in the header +
+ +

Preamble

+

If you are using multiple rows in the table header, it can be useful to have a rowspanning cell on the column(s) you have fixed in place - equally at other times it can be useful to not and make use of the two or more cells per column. FixedColumns builds on the complex header support in DataTables to make this trivial to use in FixedColumns. Just initialise your FixedColumns instance as you normally would!

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Name and versionOperating systemsRendering engineSupport level
TridentInternet + Explorer
4.0
Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sScrollY": "300px",
+		"bPaginate": false,
+		"sScrollX": "100%",
+		"sScrollXInner": "150%",
+		"bScrollCollapse": true
+	} );
+	new FixedColumns( oTable );
+} );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/scale_fixed.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/scale_fixed.html new file mode 100644 index 0000000..f4dbba2 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/scale_fixed.html @@ -0,0 +1,523 @@ + + + + + + + FixedColumns example + + + + + + + +
+
+ FixedColumns example - fixed width fixed column +
+ +

Preamble

+

This example shows how the fixed column can have a specific pixel width defined for it. By giving the parameter iLeftWidth to FixedColumns, it will use this value to set the width of the fixed column (or columns, if multiple columns are used). Resizing the window will simply cause the DataTable scrolling area to resize dynamically. Note that sScrollXInner is used to force the width of the DataTable - you probably won't want or need this. Note also that the scaling in this demo contrasts with the relative scaling example where the fixed column width is a percentage of the visible area.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox
1.5
Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sScrollY": "300px",
+		"sScrollX": "100%",
+		"sScrollXInner": "1200px",
+		"bScrollCollapse": true,
+		"bPaginate": false
+	} );
+	new FixedColumns( oTable, {
+		"iLeftWidth": 150
+	} );
+} );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/scale_relative.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/scale_relative.html new file mode 100644 index 0000000..b612c92 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/scale_relative.html @@ -0,0 +1,525 @@ + + + + + + + FixedColumns example + + + + + + + +
+
+ FixedColumns example - relative width fixed columns +
+ +

Preamble

+

This example shows how the fixed column can be given a relative width (relative to the DataTables viewport). By giving sLeftWidth as 'relative' (the default is 'fixed') and using iLeftWidth to indicate what percentage of the viewport you wish the fixed column to take, FixedColumns will automatically scale the DataTables display. Resizing the window will cause the DataTable scrolling area to resize dynamically, including the fixed column. Note that sScrollXInner is used to force the width of the DataTable - you probably won't want or need this. Note also that the scaling in this demo contrasts with the fixed scaling example where the fixed column width fixed to an abslute pixel value.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox
1.5
Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sScrollY": "300px",
+		"sScrollX": "100%",
+		"sScrollXInner": "1200px",
+		"bScrollCollapse": true,
+		"bPaginate": false
+	} );
+	new FixedColumns( oTable, {
+		"sLeftWidth": 'relative',
+		"iLeftWidth": 20
+	} );
+} );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/server-side-processing.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/server-side-processing.html new file mode 100644 index 0000000..1cd2176 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/server-side-processing.html @@ -0,0 +1,119 @@ + + + + + + + FixedColumns example + + + + + + + +
+
+ FixedColumns example - server-side processing +
+ +

Preamble

+

This example shows how FixedColumns can be used with server-side processing in DataTables to cope with very large tables. The only special thing to consider here is that the FixedColumns instance must be initialised once the table has completed its full initialisation - this is done using fnInitComplete.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"bProcessing": true,
+		"bServerSide": true,
+		"sAjaxSource": "../../examples/server_side/scripts/server_processing.php",
+		"sScrollX": "100%",
+		"sScrollXInner": "150%",
+		"fnInitComplete": function () {
+	    new FixedColumns( oTable );
+	  }
+	} );
+} );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/themed.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/themed.html new file mode 100644 index 0000000..8db8e98 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/themed.html @@ -0,0 +1,521 @@ + + + + + + + FixedColumns example + + + + + + + +
+
+ FixedColumns example - jQuery UI themed table +
+ +

Preamble

+

This example is basically the same as the main example, but in this case the table is themed with jQuery UI ThemeRoller.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox
1.5
Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"bJQueryUI": true,
+		"sScrollY": "300px",
+		"sScrollX": "100%",
+		"sScrollXInner": "150%",
+		"bScrollCollapse": true,
+		"bPaginate": false
+	} );
+	new FixedColumns( oTable );
+} );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/two_columns.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/two_columns.html new file mode 100644 index 0000000..9140f41 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/two_columns.html @@ -0,0 +1,520 @@ + + + + + + + FixedColumns example + + + + + + + +
+
+ FixedColumns example - two columns fixed +
+ +

Preamble

+

FixedColumns allows more than one column to be frozen into place using the iLeftColumns parameter. The example below shows two columns fixed.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+ 	var oTable = $('#example').dataTable( {
+ 		"sScrollX": "100%",
+ 		"sScrollXInner": "150%",
+ 		"bScrollCollapse": true
+ 	} );
+ 	new FixedColumns( oTable, {
+ 		"iLeftColumns": 2,
+		"iLeftWidth": 350
+ 	} );
+ } );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedColumns/x_y_scrolling.html b/modules/thirdparty/jquery/datatables/extras/FixedColumns/x_y_scrolling.html new file mode 100644 index 0000000..750452f --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedColumns/x_y_scrolling.html @@ -0,0 +1,599 @@ + + + + + + + FixedColumns example + + + + + + + +
+
+ FixedColumns example - X and Y scrolling +
+ +

Preamble

+

This example is basically the same as the index column example but in this case shows pagination disabled and Y scrolling in use.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 Rendering engineBrowserPlatform(s)Engine versionCSS grade
1TridentInternet + Explorer 4.0Win 95+4X
2TridentInternet + Explorer 5.0Win 95+5C
3TridentInternet + Explorer 5.5Win 95+5.5A
4TridentInternet + Explorer 6Win 98+6A
5TridentInternet Explorer 7Win XP SP2+7A
6TridentAOL browser (AOL desktop)Win XP6A
7GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
8GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
9GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
10GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
11GeckoCamino 1.0OSX.2+1.8A
12GeckoCamino 1.5OSX.3+1.8A
13GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
14GeckoNetscape Browser 8Win 98SE+1.7A
15GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
16GeckoMozilla 1.0Win 95+ / OSX.1+1A
17GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
18GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
19GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
20GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
21GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
22GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
23GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
24GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
25GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
26GeckoEpiphany 2.20Gnome1.8A
27WebkitSafari 1.2OSX.3125.5A
28WebkitSafari 1.3OSX.3312.8A
29WebkitSafari 2.0OSX.4+419.3A
30WebkitSafari 3.0OSX.4+522.1A
31WebkitOmniWeb 5.5OSX.4+420A
32WebkitiPod Touch / iPhoneiPod420.1A
33WebkitS60S60413A
34PrestoOpera 7.0Win 95+ / OSX.1+-A
35PrestoOpera 7.5Win 95+ / OSX.2+-A
36PrestoOpera 8.0Win 95+ / OSX.2+-A
37PrestoOpera 8.5Win 95+ / OSX.2+-A
38PrestoOpera 9.0Win 95+ / OSX.3+-A
39PrestoOpera 9.2Win 88+ / OSX.3+-A
40PrestoOpera 9.5Win 88+ / OSX.3+-A
41PrestoOpera for WiiWii-A
42PrestoNokia N800N800-A
43PrestoNintendo DS browserNintendo DS8.5C/A
44KHTMLKonqureror 3.1KDE 3.13.1C
45KHTMLKonqureror 3.3KDE 3.33.3A
46KHTMLKonqureror 3.5KDE 3.53.5A
47TasmanInternet Explorer 4.5Mac OS 8-9-X
48TasmanInternet Explorer 5.1Mac OS 7.6-91C
49TasmanInternet Explorer 5.2Mac OS 8-X1C
50MiscNetFront 3.1Embedded devices-C
51MiscNetFront 3.4Embedded devices-A
52MiscDillo 0.8Embedded devices-X
53MiscLinksText only-X
54MiscLynxText only-X
55MiscIE MobileWindows Mobile 6-C
56MiscPSP browserPSP-C
57Other browsersAll others--U
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sScrollY": "300px",
+		"sScrollX": "100%",
+		"sScrollXInner": "150%",
+		"bScrollCollapse": true,
+		"bPaginate": false,
+		"fnDrawCallback": function ( oSettings ) {
+			/* Need to redo the counters if filtered or sorted */
+			if ( oSettings.bSorted || oSettings.bFiltered ) {
+				for ( var i=0, iLen=oSettings.aiDisplay.length ; i<iLen ; i++ ) {
+					var nTr = oSettings.aoData[ oSettings.aiDisplay[i] ].nTr;
+
+					// Update the index column and do so without redrawing the table
+					this.fnUpdate( i+1, nTr, 0, false, false );
+				}
+			}
+		},
+		"aoColumnDefs": [
+			{ "bSortable": false, "sClass": "index", "aTargets": [ 0 ] }
+		],
+		"aaSorting": [[ 1, 'asc' ]]
+	} );
+	new FixedColumns( oTable );
+} );
+ + +

Documentation

+ + +

Basic examples

+ + +

Advanced examples

+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedHeader/html_table.html b/modules/thirdparty/jquery/datatables/extras/FixedHeader/html_table.html new file mode 100644 index 0000000..418a5b3 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedHeader/html_table.html @@ -0,0 +1,486 @@ + + + + + + + FixedHeader example + + + + + + +
+
+ FixedHeader example - HTML table +
+ +

Preamble

+

FixedHeader will work standalone as well (i.e. without DataTables), as can be seen in this example. The standard settings can be applied to FixedHeader to enhance the table.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	new FixedHeader( document.getElementById('example') );
+} );
+ +

Examples

+ + +

Empty paragraphs to force scrolling!...

+

 

+ + + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedHeader/js/FixedHeader.js b/modules/thirdparty/jquery/datatables/extras/FixedHeader/js/FixedHeader.js new file mode 100644 index 0000000..bb20a8a --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedHeader/js/FixedHeader.js @@ -0,0 +1,937 @@ +/* + * File: FixedHeader.js + * Version: 2.0.6 + * Description: "Fix" a header at the top of the table, so it scrolls with the table + * Author: Allan Jardine (www.sprymedia.co.uk) + * Created: Wed 16 Sep 2009 19:46:30 BST + * Language: Javascript + * License: GPL v2 or BSD 3 point style + * Project: Just a little bit of fun - enjoy :-) + * Contact: www.sprymedia.co.uk/contact + * + * Copyright 2009-2012 Allan Jardine, all rights reserved. + * + * This source file is free software, under either the GPL v2 license or a + * BSD style license, available at: + * http://datatables.net/license_gpl2 + * http://datatables.net/license_bsd + */ + +/* + * Function: FixedHeader + * Purpose: Provide 'fixed' header, footer and columns on an HTML table + * Returns: object:FixedHeader - must be called with 'new' + * Inputs: mixed:mTable - target table + * 1. DataTable object - when using FixedHeader with DataTables, or + * 2. HTML table node - when using FixedHeader without DataTables + * object:oInit - initialisation settings, with the following properties (each optional) + * bool:top - fix the header (default true) + * bool:bottom - fix the footer (default false) + * bool:left - fix the left most column (default false) + * bool:right - fix the right most column (default false) + * int:zTop - fixed header zIndex + * int:zBottom - fixed footer zIndex + * int:zLeft - fixed left zIndex + * int:zRight - fixed right zIndex + */ +var FixedHeader = function ( mTable, oInit ) { + /* Sanity check - you just know it will happen */ + if ( typeof this.fnInit != 'function' ) + { + alert( "FixedHeader warning: FixedHeader must be initialised with the 'new' keyword." ); + return; + } + + var that = this; + var oSettings = { + "aoCache": [], + "oSides": { + "top": true, + "bottom": false, + "left": false, + "right": false + }, + "oZIndexes": { + "top": 104, + "bottom": 103, + "left": 102, + "right": 101 + }, + "oMes": { + "iTableWidth": 0, + "iTableHeight": 0, + "iTableLeft": 0, + "iTableRight": 0, /* note this is left+width, not actually "right" */ + "iTableTop": 0, + "iTableBottom": 0 /* note this is top+height, not actually "bottom" */ + }, + "oOffset": { + "top": 0 + }, + "nTable": null, + "bUseAbsPos": false, + "bFooter": false + }; + + /* + * Function: fnGetSettings + * Purpose: Get the settings for this object + * Returns: object: - settings object + * Inputs: - + */ + this.fnGetSettings = function () { + return oSettings; + }; + + /* + * Function: fnUpdate + * Purpose: Update the positioning and copies of the fixed elements + * Returns: - + * Inputs: - + */ + this.fnUpdate = function () { + this._fnUpdateClones(); + this._fnUpdatePositions(); + }; + + /* + * Function: fnPosition + * Purpose: Update the positioning of the fixed elements + * Returns: - + * Inputs: - + */ + this.fnPosition = function () { + this._fnUpdatePositions(); + }; + + /* Let's do it */ + this.fnInit( mTable, oInit ); + + /* Store the instance on the DataTables object for easy access */ + if ( typeof mTable.fnSettings == 'function' ) + { + mTable._oPluginFixedHeader = this; + } +}; + + +/* + * Variable: FixedHeader + * Purpose: Prototype for FixedHeader + * Scope: global + */ +FixedHeader.prototype = { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Initialisation + */ + + /* + * Function: fnInit + * Purpose: The "constructor" + * Returns: - + * Inputs: {as FixedHeader function} + */ + fnInit: function ( oTable, oInit ) + { + var s = this.fnGetSettings(); + var that = this; + + /* Record the user definable settings */ + this.fnInitSettings( s, oInit ); + + /* DataTables specific stuff */ + if ( typeof oTable.fnSettings == 'function' ) + { + if ( typeof oTable.fnVersionCheck == 'functon' && + oTable.fnVersionCheck( '1.6.0' ) !== true ) + { + alert( "FixedHeader 2 required DataTables 1.6.0 or later. "+ + "Please upgrade your DataTables installation" ); + return; + } + + var oDtSettings = oTable.fnSettings(); + + if ( oDtSettings.oScroll.sX != "" || oDtSettings.oScroll.sY != "" ) + { + alert( "FixedHeader 2 is not supported with DataTables' scrolling mode at this time" ); + return; + } + + s.nTable = oDtSettings.nTable; + oDtSettings.aoDrawCallback.push( { + "fn": function () { + FixedHeader.fnMeasure(); + that._fnUpdateClones.call(that); + that._fnUpdatePositions.call(that); + }, + "sName": "FixedHeader" + } ); + } + else + { + s.nTable = oTable; + } + + s.bFooter = ($('>tfoot', s.nTable).length > 0) ? true : false; + + /* "Detect" browsers that don't support absolute positioing - or have bugs */ + s.bUseAbsPos = (jQuery.browser.msie && (jQuery.browser.version=="6.0"||jQuery.browser.version=="7.0")); + + /* Add the 'sides' that are fixed */ + if ( s.oSides.top ) + { + s.aoCache.push( that._fnCloneTable( "fixedHeader", "FixedHeader_Header", that._fnCloneThead ) ); + } + if ( s.oSides.bottom ) + { + s.aoCache.push( that._fnCloneTable( "fixedFooter", "FixedHeader_Footer", that._fnCloneTfoot ) ); + } + if ( s.oSides.left ) + { + s.aoCache.push( that._fnCloneTable( "fixedLeft", "FixedHeader_Left", that._fnCloneTLeft ) ); + } + if ( s.oSides.right ) + { + s.aoCache.push( that._fnCloneTable( "fixedRight", "FixedHeader_Right", that._fnCloneTRight ) ); + } + + /* Event listeners for window movement */ + FixedHeader.afnScroll.push( function () { + that._fnUpdatePositions.call(that); + } ); + + jQuery(window).resize( function () { + FixedHeader.fnMeasure(); + that._fnUpdateClones.call(that); + that._fnUpdatePositions.call(that); + } ); + + /* Get things right to start with */ + FixedHeader.fnMeasure(); + that._fnUpdateClones(); + that._fnUpdatePositions(); + }, + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Support functions + */ + + /* + * Function: fnInitSettings + * Purpose: Take the user's settings and copy them to our local store + * Returns: - + * Inputs: object:s - the local settings object + * object:oInit - the user's settings object + */ + fnInitSettings: function ( s, oInit ) + { + if ( typeof oInit != 'undefined' ) + { + if ( typeof oInit.top != 'undefined' ) { + s.oSides.top = oInit.top; + } + if ( typeof oInit.bottom != 'undefined' ) { + s.oSides.bottom = oInit.bottom; + } + if ( typeof oInit.left != 'undefined' ) { + s.oSides.left = oInit.left; + } + if ( typeof oInit.right != 'undefined' ) { + s.oSides.right = oInit.right; + } + + if ( typeof oInit.zTop != 'undefined' ) { + s.oZIndexes.top = oInit.zTop; + } + if ( typeof oInit.zBottom != 'undefined' ) { + s.oZIndexes.bottom = oInit.zBottom; + } + if ( typeof oInit.zLeft != 'undefined' ) { + s.oZIndexes.left = oInit.zLeft; + } + if ( typeof oInit.zRight != 'undefined' ) { + s.oZIndexes.right = oInit.zRight; + } + + if ( typeof oInit.offsetTop != 'undefined' ) { + s.oOffset.top = oInit.offsetTop; + } + } + + /* Detect browsers which have poor position:fixed support so we can use absolute positions. + * This is much slower since the position must be updated for each scroll, but widens + * compatibility + */ + s.bUseAbsPos = (jQuery.browser.msie && + (jQuery.browser.version=="6.0"||jQuery.browser.version=="7.0")); + }, + + /* + * Function: _fnCloneTable + * Purpose: Clone the table node and do basic initialisation + * Returns: - + * Inputs: - + */ + _fnCloneTable: function ( sType, sClass, fnClone ) + { + var s = this.fnGetSettings(); + var nCTable; + + /* We know that the table _MUST_ has a DIV wrapped around it, because this is simply how + * DataTables works. Therefore, we can set this to be relatively position (if it is not + * alreadu absolute, and use this as the base point for the cloned header + */ + if ( jQuery(s.nTable.parentNode).css('position') != "absolute" ) + { + s.nTable.parentNode.style.position = "relative"; + } + + /* Just a shallow clone will do - we only want the table node */ + nCTable = s.nTable.cloneNode( false ); + nCTable.removeAttribute( 'id' ); + + var nDiv = document.createElement( 'div' ); + nDiv.style.position = "absolute"; + nDiv.style.top = "0px"; + nDiv.style.left = "0px"; + nDiv.className += " FixedHeader_Cloned "+sType+" "+sClass; + + /* Set the zIndexes */ + if ( sType == "fixedHeader" ) + { + nDiv.style.zIndex = s.oZIndexes.top; + } + if ( sType == "fixedFooter" ) + { + nDiv.style.zIndex = s.oZIndexes.bottom; + } + if ( sType == "fixedLeft" ) + { + nDiv.style.zIndex = s.oZIndexes.left; + } + else if ( sType == "fixedRight" ) + { + nDiv.style.zIndex = s.oZIndexes.right; + } + + /* remove margins since we are going to poistion it absolutely */ + nCTable.style.margin = "0"; + + /* Insert the newly cloned table into the DOM, on top of the "real" header */ + nDiv.appendChild( nCTable ); + document.body.appendChild( nDiv ); + + return { + "nNode": nCTable, + "nWrapper": nDiv, + "sType": sType, + "sPosition": "", + "sTop": "", + "sLeft": "", + "fnClone": fnClone + }; + }, + + /* + * Function: _fnUpdatePositions + * Purpose: Get the current positioning of the table in the DOM + * Returns: - + * Inputs: - + */ + _fnMeasure: function () + { + var + s = this.fnGetSettings(), + m = s.oMes, + jqTable = jQuery(s.nTable), + oOffset = jqTable.offset(), + iParentScrollTop = this._fnSumScroll( s.nTable.parentNode, 'scrollTop' ), + iParentScrollLeft = this._fnSumScroll( s.nTable.parentNode, 'scrollLeft' ); + + m.iTableWidth = jqTable.outerWidth(); + m.iTableHeight = jqTable.outerHeight(); + m.iTableLeft = oOffset.left + s.nTable.parentNode.scrollLeft; + m.iTableTop = oOffset.top + iParentScrollTop; + m.iTableRight = m.iTableLeft + m.iTableWidth; + m.iTableRight = FixedHeader.oDoc.iWidth - m.iTableLeft - m.iTableWidth; + m.iTableBottom = FixedHeader.oDoc.iHeight - m.iTableTop - m.iTableHeight; + }, + + /* + * Function: _fnSumScroll + * Purpose: Sum node parameters all the way to the top + * Returns: int: sum + * Inputs: node:n - node to consider + * string:side - scrollTop or scrollLeft + */ + _fnSumScroll: function ( n, side ) + { + var i = n[side]; + while ( n = n.parentNode ) + { + if ( n.nodeName == 'HTML' || n.nodeName == 'BODY' ) + { + break; + } + i = n[side]; + } + return i; + }, + + /* + * Function: _fnUpdatePositions + * Purpose: Loop over the fixed elements for this table and update their positions + * Returns: - + * Inputs: - + */ + _fnUpdatePositions: function () + { + var s = this.fnGetSettings(); + this._fnMeasure(); + + for ( var i=0, iLen=s.aoCache.length ; i oWin.iScrollTop + s.oOffset.top ) + { + /* Above the table */ + this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); + } + else if ( oWin.iScrollTop + s.oOffset.top > oMes.iTableTop+iTbodyHeight ) + { + /* At the bottom of the table */ + this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+iTbodyHeight)+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); + } + else + { + /* In the middle of the table */ + if ( s.bUseAbsPos ) + { + this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', oWin.iScrollTop+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); + } + else + { + this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style ); + this._fnUpdateCache( oCache, 'sTop', s.oOffset.top+"px", 'top', nTable.style ); + this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft-oWin.iScrollLeft)+"px", 'left', nTable.style ); + } + } + }, + + /* + * Function: _fnUpdateCache + * Purpose: Check the cache and update cache and value if needed + * Returns: - + * Inputs: object:oCache - local cache object + * string:sCache - cache property + * string:sSet - value to set + * string:sProperty - object property to set + * object:oObj - object to update + */ + _fnUpdateCache: function ( oCache, sCache, sSet, sProperty, oObj ) + { + if ( oCache[sCache] != sSet ) + { + oObj[sProperty] = sSet; + oCache[sCache] = sSet; + } + }, + + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Cloning functions + */ + + /* + * Function: _fnCloneThead + * Purpose: Clone the thead element + * Returns: - + * Inputs: object:oCache - the cahced values for this fixed element + */ + _fnCloneThead: function ( oCache ) + { + var s = this.fnGetSettings(); + var nTable = oCache.nNode; + + /* Set the wrapper width to match that of the cloned table */ + oCache.nWrapper.style.width = jQuery(s.nTable).outerWidth()+"px"; + + /* Remove any children the cloned table has */ + while ( nTable.childNodes.length > 0 ) + { + jQuery('thead th', nTable).unbind( 'click' ); + nTable.removeChild( nTable.childNodes[0] ); + } + + /* Clone the DataTables header */ + var nThead = jQuery('thead', s.nTable).clone(true)[0]; + nTable.appendChild( nThead ); + + /* Copy the widths across - apparently a clone isn't good enough for this */ + jQuery("thead>tr th", s.nTable).each( function (i) { + jQuery("thead>tr th:eq("+i+")", nTable).width( jQuery(this).width() ); + } ); + + jQuery("thead>tr td", s.nTable).each( function (i) { + jQuery("thead>tr td:eq("+i+")", nTable).width( jQuery(this).width() ); + } ); + }, + + /* + * Function: _fnCloneTfoot + * Purpose: Clone the tfoot element + * Returns: - + * Inputs: object:oCache - the cahced values for this fixed element + */ + _fnCloneTfoot: function ( oCache ) + { + var s = this.fnGetSettings(); + var nTable = oCache.nNode; + + /* Set the wrapper width to match that of the cloned table */ + oCache.nWrapper.style.width = jQuery(s.nTable).outerWidth()+"px"; + + /* Remove any children the cloned table has */ + while ( nTable.childNodes.length > 0 ) + { + nTable.removeChild( nTable.childNodes[0] ); + } + + /* Clone the DataTables footer */ + var nTfoot = jQuery('tfoot', s.nTable).clone(true)[0]; + nTable.appendChild( nTfoot ); + + /* Copy the widths across - apparently a clone isn't good enough for this */ + jQuery("tfoot:eq(0)>tr th", s.nTable).each( function (i) { + jQuery("tfoot:eq(0)>tr th:eq("+i+")", nTable).width( jQuery(this).width() ); + } ); + + jQuery("tfoot:eq(0)>tr td", s.nTable).each( function (i) { + jQuery("tfoot:eq(0)>tr th:eq("+i+")", nTable)[0].style.width( jQuery(this).width() ); + } ); + }, + + /* + * Function: _fnCloneTLeft + * Purpose: Clone the left column + * Returns: - + * Inputs: object:oCache - the cached values for this fixed element + */ + _fnCloneTLeft: function ( oCache ) + { + var s = this.fnGetSettings(); + var nTable = oCache.nNode; + var nBody = $('tbody', s.nTable)[0]; + var iCols = $('tbody tr:eq(0) td', s.nTable).length; + var bRubbishOldIE = ($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0")); + + /* Remove any children the cloned table has */ + while ( nTable.childNodes.length > 0 ) + { + nTable.removeChild( nTable.childNodes[0] ); + } + + /* Is this the most efficient way to do this - it looks horrible... */ + nTable.appendChild( jQuery("thead", s.nTable).clone(true)[0] ); + nTable.appendChild( jQuery("tbody", s.nTable).clone(true)[0] ); + if ( s.bFooter ) + { + nTable.appendChild( jQuery("tfoot", s.nTable).clone(true)[0] ); + } + + /* Remove unneeded cells */ + $('thead tr', nTable).each( function (k) { + $('th:gt(0)', this).remove(); + } ); + + $('tfoot tr', nTable).each( function (k) { + $('th:gt(0)', this).remove(); + } ); + + $('tbody tr', nTable).each( function (k) { + $('td:gt(0)', this).remove(); + } ); + + this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable ); + + var iWidth = jQuery('thead tr th:eq(0)', s.nTable).outerWidth(); + nTable.style.width = iWidth+"px"; + oCache.nWrapper.style.width = iWidth+"px"; + }, + + /* + * Function: _fnCloneTRight + * Purpose: Clone the right most colun + * Returns: - + * Inputs: object:oCache - the cahced values for this fixed element + */ + _fnCloneTRight: function ( oCache ) + { + var s = this.fnGetSettings(); + var nBody = $('tbody', s.nTable)[0]; + var nTable = oCache.nNode; + var iCols = jQuery('tbody tr:eq(0) td', s.nTable).length; + var bRubbishOldIE = ($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0")); + + /* Remove any children the cloned table has */ + while ( nTable.childNodes.length > 0 ) + { + nTable.removeChild( nTable.childNodes[0] ); + } + + /* Is this the most efficient way to do this - it looks horrible... */ + nTable.appendChild( jQuery("thead", s.nTable).clone(true)[0] ); + nTable.appendChild( jQuery("tbody", s.nTable).clone(true)[0] ); + if ( s.bFooter ) + { + nTable.appendChild( jQuery("tfoot", s.nTable).clone(true)[0] ); + } + jQuery('thead tr th:not(:nth-child('+iCols+'n))', nTable).remove(); + jQuery('tfoot tr th:not(:nth-child('+iCols+'n))', nTable).remove(); + + /* Remove unneeded cells */ + $('tbody tr', nTable).each( function (k) { + $('td:lt('+(iCols-1)+')', this).remove(); + } ); + + this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable ); + + var iWidth = jQuery('thead tr th:eq('+(iCols-1)+')', s.nTable).outerWidth(); + nTable.style.width = iWidth+"px"; + oCache.nWrapper.style.width = iWidth+"px"; + }, + + + /** + * Equalise the heights of the rows in a given table node in a cross browser way. Note that this + * is more or less lifted as is from FixedColumns + * @method fnEqualiseHeights + * @returns void + * @param {string} parent Node type - thead, tbody or tfoot + * @param {element} original Original node to take the heights from + * @param {element} clone Copy the heights to + * @private + */ + "fnEqualiseHeights": function ( parent, original, clone ) + { + var that = this, + jqBoxHack = $(parent+' tr:eq(0)', original).children(':eq(0)'), + iBoxHack = jqBoxHack.outerHeight() - jqBoxHack.height(), + bRubbishOldIE = ($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0")); + + /* Remove cells which are not needed and copy the height from the original table */ + $(parent+' tr', clone).each( function (k) { + /* Can we use some kind of object detection here?! This is very nasty - damn browsers */ + if ( $.browser.mozilla || $.browser.opera ) + { + $(this).children().height( $(parent+' tr:eq('+k+')', original).outerHeight() ); + } + else + { + $(this).children().height( $(parent+' tr:eq('+k+')', original).outerHeight() - iBoxHack ); + } + + if ( !bRubbishOldIE ) + { + $(parent+' tr:eq('+k+')', original).height( $(parent+' tr:eq('+k+')', original).outerHeight() ); + } + } ); + } +}; + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Static properties and methods + * We use these for speed! This information is common to all instances of FixedHeader, so no + * point if having them calculated and stored for each different instance. + */ + +/* + * Variable: oWin + * Purpose: Store information about the window positioning + * Scope: FixedHeader + */ +FixedHeader.oWin = { + "iScrollTop": 0, + "iScrollRight": 0, + "iScrollBottom": 0, + "iScrollLeft": 0, + "iHeight": 0, + "iWidth": 0 +}; + +/* + * Variable: oDoc + * Purpose: Store information about the document size + * Scope: FixedHeader + */ +FixedHeader.oDoc = { + "iHeight": 0, + "iWidth": 0 +}; + +/* + * Variable: afnScroll + * Purpose: Array of functions that are to be used for the scrolling components + * Scope: FixedHeader + */ +FixedHeader.afnScroll = []; + +/* + * Function: fnMeasure + * Purpose: Update the measurements for the window and document + * Returns: - + * Inputs: - + */ +FixedHeader.fnMeasure = function () +{ + var + jqWin = jQuery(window), + jqDoc = jQuery(document), + oWin = FixedHeader.oWin, + oDoc = FixedHeader.oDoc; + + oDoc.iHeight = jqDoc.height(); + oDoc.iWidth = jqDoc.width(); + + oWin.iHeight = jqWin.height(); + oWin.iWidth = jqWin.width(); + oWin.iScrollTop = jqWin.scrollTop(); + oWin.iScrollLeft = jqWin.scrollLeft(); + oWin.iScrollRight = oDoc.iWidth - oWin.iScrollLeft - oWin.iWidth; + oWin.iScrollBottom = oDoc.iHeight - oWin.iScrollTop - oWin.iHeight; +}; + + +FixedHeader.VERSION = "2.0.6"; +FixedHeader.prototype.VERSION = FixedHeader.VERSION; + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Global processing + */ + +/* + * Just one 'scroll' event handler in FixedHeader, which calls the required components. This is + * done as an optimisation, to reduce calculation and proagation time + */ +jQuery(window).scroll( function () { + FixedHeader.fnMeasure(); + for ( var i=0, iLen=FixedHeader.afnScroll.length ; itfoot",b.nTable).length?!0:!1;b.bUseAbsPos=jQuery.browser.msie&&("6.0"==jQuery.browser.version||"7.0"==jQuery.browser.version);b.oSides.top&&b.aoCache.push(d._fnCloneTable("fixedHeader","FixedHeader_Header",d._fnCloneThead));b.oSides.bottom&&b.aoCache.push(d._fnCloneTable("fixedFooter","FixedHeader_Footer",d._fnCloneTfoot));b.oSides.left&&b.aoCache.push(d._fnCloneTable("fixedLeft","FixedHeader_Left", +d._fnCloneTLeft));b.oSides.right&&b.aoCache.push(d._fnCloneTable("fixedRight","FixedHeader_Right",d._fnCloneTRight));FixedHeader.afnScroll.push(function(){d._fnUpdatePositions.call(d)});jQuery(window).resize(function(){FixedHeader.fnMeasure();d._fnUpdateClones.call(d);d._fnUpdatePositions.call(d)});FixedHeader.fnMeasure();d._fnUpdateClones();d._fnUpdatePositions()},fnInitSettings:function(a,c){if("undefined"!=typeof c&&("undefined"!=typeof c.top&&(a.oSides.top=c.top),"undefined"!=typeof c.bottom&& +(a.oSides.bottom=c.bottom),"undefined"!=typeof c.left&&(a.oSides.left=c.left),"undefined"!=typeof c.right&&(a.oSides.right=c.right),"undefined"!=typeof c.zTop&&(a.oZIndexes.top=c.zTop),"undefined"!=typeof c.zBottom&&(a.oZIndexes.bottom=c.zBottom),"undefined"!=typeof c.zLeft&&(a.oZIndexes.left=c.zLeft),"undefined"!=typeof c.zRight&&(a.oZIndexes.right=c.zRight),"undefined"!=typeof c.offsetTop))a.oOffset.top=c.offsetTop;a.bUseAbsPos=jQuery.browser.msie&&("6.0"==jQuery.browser.version||"7.0"==jQuery.browser.version)}, +_fnCloneTable:function(a,c,b){var d=this.fnGetSettings(),e;"absolute"!=jQuery(d.nTable.parentNode).css("position")&&(d.nTable.parentNode.style.position="relative");e=d.nTable.cloneNode(!1);e.removeAttribute("id");var f=document.createElement("div");f.style.position="absolute";f.style.top="0px";f.style.left="0px";f.className+=" FixedHeader_Cloned "+a+" "+c;"fixedHeader"==a&&(f.style.zIndex=d.oZIndexes.top);"fixedFooter"==a&&(f.style.zIndex=d.oZIndexes.bottom);"fixedLeft"==a?f.style.zIndex=d.oZIndexes.left: +"fixedRight"==a&&(f.style.zIndex=d.oZIndexes.right);e.style.margin="0";f.appendChild(e);document.body.appendChild(f);return{nNode:e,nWrapper:f,sType:a,sPosition:"",sTop:"",sLeft:"",fnClone:b}},_fnMeasure:function(){var a=this.fnGetSettings(),c=a.oMes,b=jQuery(a.nTable),d=b.offset(),e=this._fnSumScroll(a.nTable.parentNode,"scrollTop");this._fnSumScroll(a.nTable.parentNode,"scrollLeft");c.iTableWidth=b.outerWidth();c.iTableHeight=b.outerHeight();c.iTableLeft=d.left+a.nTable.parentNode.scrollLeft;c.iTableTop= +d.top+e;c.iTableRight=c.iTableLeft+c.iTableWidth;c.iTableRight=FixedHeader.oDoc.iWidth-c.iTableLeft-c.iTableWidth;c.iTableBottom=FixedHeader.oDoc.iHeight-c.iTableTop-c.iTableHeight},_fnSumScroll:function(a,c){for(var b=a[c];(a=a.parentNode)&&!("HTML"==a.nodeName||"BODY"==a.nodeName);)b=a[c];return b},_fnUpdatePositions:function(){var a=this.fnGetSettings();this._fnMeasure();for(var c=0,b=a.aoCache.length;cd.iScrollTop+c.oOffset.top?(this._fnUpdateCache(a,"sPosition","absolute","position",e.style),this._fnUpdateCache(a,"sTop",b.iTableTop+"px","top",e.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+"px","left",e.style)):d.iScrollTop+c.oOffset.top>b.iTableTop+f?(this._fnUpdateCache(a,"sPosition","absolute","position",e.style),this._fnUpdateCache(a,"sTop",b.iTableTop+f+"px","top",e.style),this._fnUpdateCache(a, +"sLeft",b.iTableLeft+"px","left",e.style)):c.bUseAbsPos?(this._fnUpdateCache(a,"sPosition","absolute","position",e.style),this._fnUpdateCache(a,"sTop",d.iScrollTop+"px","top",e.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+"px","left",e.style)):(this._fnUpdateCache(a,"sPosition","fixed","position",e.style),this._fnUpdateCache(a,"sTop",c.oOffset.top+"px","top",e.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft-d.iScrollLeft+"px","left",e.style))},_fnUpdateCache:function(a,c,b,d,e){a[c]!=b&&(e[d]= +b,a[c]=b)},_fnCloneThead:function(a){var c=this.fnGetSettings(),b=a.nNode;for(a.nWrapper.style.width=jQuery(c.nTable).outerWidth()+"px";0tr th",c.nTable).each(function(a){jQuery("thead>tr th:eq("+a+")",b).width(jQuery(this).width())});jQuery("thead>tr td",c.nTable).each(function(a){jQuery("thead>tr td:eq("+a+")",b).width(jQuery(this).width())})}, +_fnCloneTfoot:function(a){var c=this.fnGetSettings(),b=a.nNode;for(a.nWrapper.style.width=jQuery(c.nTable).outerWidth()+"px";0tr th",c.nTable).each(function(a){jQuery("tfoot:eq(0)>tr th:eq("+a+")",b).width(jQuery(this).width())});jQuery("tfoot:eq(0)>tr td",c.nTable).each(function(a){jQuery("tfoot:eq(0)>tr th:eq("+a+")",b)[0].style.width(jQuery(this).width())})},_fnCloneTLeft:function(a){var c= +this.fnGetSettings(),b=a.nNode,d=$("tbody",c.nTable)[0];for($("tbody tr:eq(0) td",c.nTable);0 + + + + + + FixedHeader example + + + + + + + +
+

FixedHeader example - top, bottom, left and right fixed

+

This example shows how FixedHeader can be made to look more like a spreadsheet application. Click 'View source' in your browser to see the set up.

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedHeader/top_left.html b/modules/thirdparty/jquery/datatables/extras/FixedHeader/top_left.html new file mode 100644 index 0000000..0f72147 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedHeader/top_left.html @@ -0,0 +1,490 @@ + + + + + + + FixedHeader example + + + + + + + +
+
+ FixedHeader example - header and left columns fixed +
+ +

Preamble

+

This example shows how tivial it is to fix the left hand column of the table as well as the header. In fact, the header, footer, left and right columns can all be fixed in exactly the same manner. The header is the only one to be fixed by default.

+

Note that the window has of course been made artificially wide to show the fixed left column in action.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable();
+	new FixedHeader( oTable, { "left": true } );
+} );
+ +

Examples

+ + +

Empty paragraphs to force scrolling!...

+

 

+ + + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedHeader/two_tables.html b/modules/thirdparty/jquery/datatables/extras/FixedHeader/two_tables.html new file mode 100644 index 0000000..28ece10 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedHeader/two_tables.html @@ -0,0 +1,923 @@ + + + + + + + FixedHeader example + + + + + + + +
+
+ FixedHeader example - two tables +
+ +

Preamble

+

The following example shows two DataTables enhanced tables both with FixedHeader enabled on them. The footer is also fixed for both table.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
Rendering engineBrowserPlatform(s)Engine versionCSS grade
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet
Explorer 7
Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable();
+	new FixedHeader( oTable, { "bottom": true } );
+	
+	var oTable2 = $('#example2').dataTable();
+	new FixedHeader( oTable2, { "bottom": true } );
+} );
+ +

Examples

+ + +

Empty paragraphs to force scrolling!...

+

 

+ + + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/FixedHeader/zIndexes.html b/modules/thirdparty/jquery/datatables/extras/FixedHeader/zIndexes.html new file mode 100644 index 0000000..e9e0dae --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/FixedHeader/zIndexes.html @@ -0,0 +1,496 @@ + + + + + + + FixedHeader example + + + + + + + +
+
+ FixedHeader example - zIndex example +
+ +

Preamble

+

When you have two or more columns fixed on a table, there might be occasions when you which to have one column floating on top of another. This example shows how you can do that with the initialisation parameters zTop, zBottom, zLeft and zRight. In this example the left column is set to float on top of the header. The difference is subtle, but can be effective.

+

The default zIndexes are:

+
    +
  • zTop: 104
  • +
  • zBottom: 103
  • +
  • zLeft: 102
  • +
  • zRight: 101
  • +
+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable();
+	new FixedHeader( oTable, { "left": true, "zLeft": 105 } );
+} );
+ +

Examples

+ + +

Empty paragraphs to force scrolling!...

+

 

+ + + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/KeyTable/datatable.html b/modules/thirdparty/jquery/datatables/extras/KeyTable/datatable.html new file mode 100644 index 0000000..5950fe3 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/KeyTable/datatable.html @@ -0,0 +1,494 @@ + + + + + + + KeyTable / DataTables example + + + + + + + +
+
+ KeyTable with DataTables integration example +
+ +

Preamble

+

KeyTable will work great with any plain HTML table, but it also integrates with DataTables plug-in for jQuery. This allows the navigation to take account of paging, sorting etc. This is shown in an example below.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable();
+	
+	var keys = new KeyTable( {
+		"table": document.getElementById('example'),
+		"datatable": oTable
+	} );
+} );
+ + +

Other examples

+ + + + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/KeyTable/datatable_scrolling.html b/modules/thirdparty/jquery/datatables/extras/KeyTable/datatable_scrolling.html new file mode 100644 index 0000000..a9ff2ed --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/KeyTable/datatable_scrolling.html @@ -0,0 +1,502 @@ + + + + + + + KeyTable / DataTables example + + + + + + + +
+
+ KeyTable with DataTables (when using scrolling) integration example +
+ +

Preamble

+

A new feature in DataTables 1.7 is the ability to have the table body scroll in the x and y dimensions. KeyTable supports this capability of DataTables "out of the box" (no extra initialisation is needed), as shown in this example.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet + Explorer 4.0Win 95+4X
TridentInternet + Explorer 5.0Win 95+5C
TridentInternet + Explorer 5.5Win 95+5.5A
TridentInternet + Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var oTable = $('#example').dataTable( {
+		"sScrollY": 200,
+		"sScrollX": "100%",
+		"sScrollXInner": "110%"
+	} );
+	
+	var keys = new KeyTable( {
+		"table": document.getElementById('example'),
+		"datatable": oTable
+	} );
+} );
+ + +

Other examples

+ + + + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/KeyTable/editing.html b/modules/thirdparty/jquery/datatables/extras/KeyTable/editing.html new file mode 100644 index 0000000..602856b --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/KeyTable/editing.html @@ -0,0 +1,536 @@ + + + + + + + KeyTables editing example + + + + + + + +
+
+ KeyTable editing example +
+ +

Preamble

+

Possibly one of the most obvious applications of KeyTable is using it to navigate around a table, allowing a user to edit data as they go. This is an example of how that might be done through integration with the excellent jEditable plug-in for jQuery.

+

To edit data in the table, simply navigate to where you want to edit using the arrow keys, hit return and they make your edit. Hit return again to complete and submit the edit (note this example doesn't actually send the data to the server!) and then continue navigating.

+ +

Live example

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
TridentAOL browser (AOL desktop)Win XP6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
GeckoFirefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
Rendering engineBrowserPlatform(s)Engine versionCSS grade
+
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var keys = new KeyTable( {
+		"table": document.getElementById('example')
+	} );
+	
+	/* Apply a return key event to each cell in the table */
+	keys.event.action( null, null, function (nCell) {
+		/* Block KeyTable from performing any events while jEditable is in edit mode */
+		keys.block = true;
+		
+		/* Initialise the Editable instance for this table */
+		$(nCell).editable( function (sVal) {
+			/* Submit function (local only) - unblock KeyTable */
+			keys.block = false;
+			return sVal;
+		}, { 
+			"onblur": 'submit', 
+			"onreset": function(){ 
+				/* Unblock KeyTable, but only after this 'esc' key event has finished. Otherwise
+				 * it will 'esc' KeyTable as well
+				 */
+				setTimeout( function () {keys.block = false;}, 0); 
+			}
+		} );
+		
+		/* Dispatch click event to go into edit mode - Saf 4 needs a timeout... */
+		setTimeout( function () { $(nCell).click(); }, 0 );
+	} );
+} );
+ + +

Other examples

+ + + + + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/KeyTable/form.html b/modules/thirdparty/jquery/datatables/extras/KeyTable/form.html new file mode 100644 index 0000000..332e647 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/KeyTable/form.html @@ -0,0 +1,133 @@ + + + + + + + KeyTables example + + + + + + +
+
+ KeyTable form integration example +
+ +

Preamble

+

One of possible use of KeyTable is to use a table as a form element (for example a calendar date selector). For this you want to be table to tab into and out of the table, as you would do with any other form element on the page.

+

The example shown below as a small table as it's third input element, and you can tab between input fields. When the 'focus' reaches the end of the table, hitting tab will take you into the next field.

+ +

Live example

+ + + + + + + + + + + + + + + + + + + + + + + +
Input 1:
Input 2:
Input 3: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0Win 95+4X
TridentInternet Explorer 5.0Win 95+5C
TridentInternet Explorer 5.5Win 95+5.5A
TridentInternet Explorer 6Win 98+6A
TridentInternet Explorer 7Win XP SP2+7A
+
Input 4:
Input 5:
+
+ + +

Initialisation code

+
$(document).ready( function () {
+	var keys = new KeyTable( {
+		"form": true
+	} );
+} );
+ + +

Other examples

+ + + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/KeyTable/index.html b/modules/thirdparty/jquery/datatables/extras/KeyTable/index.html new file mode 100644 index 0000000..1162d52 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/KeyTable/index.html @@ -0,0 +1,595 @@ + + + + + + + KeyTables example + + + + + + +
+
+ KeyTable example +
+ +

Preamble

+

KeyTable allows you to use keyboard navigation on an HTML table. The focused cell is shown through the CSS class ('focus') which in the case below is simply a blue border. Events such as 'focus', 'blur', 'esc' (the escape key) and 'return' (the return key) can be assigned event handling functions thought the API presented.

+

The example shown below has a few cells (selected at random, but near the top) with blur and focus events assigned to them. You can also see the navigation around the table using arrow keys.

+ +

Live example

+
+ Event information:
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rendering engineBrowserPlatform(s)Engine versionCSS grade
TridentInternet Explorer 4.0 (focus once)Win 95+4X
TridentInternet Explorer 5.0Win 95+ (blur)5C
Trident (focus)Internet Explorer 5.5Win 95+ (action/bold)5.5A
TridentInternet Explorer 6 (focus)Win 98+6A
TridentInternet Explorer 7Win XP SP2+ (blur)7A
TridentAOL browser (AOL desktop)Win XP (action/italic)6A
GeckoFirefox 1.0Win 98+ / OSX.2+1.7A
Gecko (focus - row)Firefox 1.5Win 98+ / OSX.2+1.8A
GeckoFirefox 2.0Win 98+ / OSX.2+1.8A
GeckoFirefox 3.0Win 2k+ / OSX.3+1.9A
GeckoCamino 1.0OSX.2+1.8A
GeckoCamino 1.5OSX.3+1.8A
GeckoNetscape 7.2Win 95+ / Mac OS 8.6-9.21.7A
GeckoNetscape Browser 8Win 98SE+1.7A
GeckoNetscape Navigator 9Win 98+ / OSX.2+1.8A
GeckoMozilla 1.0Win 95+ / OSX.1+1A
GeckoMozilla 1.1Win 95+ / OSX.1+1.1A
GeckoMozilla 1.2Win 95+ / OSX.1+1.2A
GeckoMozilla 1.3Win 95+ / OSX.1+1.3A
GeckoMozilla 1.4Win 95+ / OSX.1+1.4A
GeckoMozilla 1.5Win 95+ / OSX.1+1.5A
GeckoMozilla 1.6Win 95+ / OSX.1+1.6A
GeckoMozilla 1.7Win 98+ / OSX.1+1.7A
GeckoMozilla 1.8Win 98+ / OSX.1+1.8A
GeckoSeamonkey 1.1Win 98+ / OSX.2+1.8A
GeckoEpiphany 2.20Gnome1.8A
WebkitSafari 1.2OSX.3125.5A
WebkitSafari 1.3OSX.3312.8A
WebkitSafari 2.0OSX.4+419.3A
WebkitSafari 3.0OSX.4+522.1A
WebkitOmniWeb 5.5OSX.4+420A
WebkitiPod Touch / iPhoneiPod420.1A
WebkitS60S60413A
PrestoOpera 7.0Win 95+ / OSX.1+-A
PrestoOpera 7.5Win 95+ / OSX.2+-A
PrestoOpera 8.0Win 95+ / OSX.2+-A
PrestoOpera 8.5Win 95+ / OSX.2+-A
PrestoOpera 9.0Win 95+ / OSX.3+-A
PrestoOpera 9.2Win 88+ / OSX.3+-A
PrestoOpera 9.5Win 88+ / OSX.3+-A
PrestoOpera for WiiWii-A
PrestoNokia N800N800-A
PrestoNintendo DS browserNintendo DS8.5C/A1
KHTMLKonqureror 3.1KDE 3.13.1C
KHTMLKonqureror 3.3KDE 3.33.3A
KHTMLKonqureror 3.5KDE 3.53.5A
TasmanInternet Explorer 4.5Mac OS 8-9-X
TasmanInternet Explorer 5.1Mac OS 7.6-91C
TasmanInternet Explorer 5.2Mac OS 8-X1C
MiscNetFront 3.1Embedded devices-C
MiscNetFront 3.4Embedded devices-A
MiscDillo 0.8Embedded devices-X
MiscLinksText only-X
MiscLynxText only-X
MiscIE MobileWindows Mobile 6-C
MiscPSP browserPSP-C
Other browsersAll others--U
+
+
+ + +

Initialisation code

+
function fnMessage ( sMesg )
+{
+	var n = document.getElementById('info');
+	n.innerHTML += sMesg+"<br>";
+	n.scrollTop = n.scrollHeight;
+}
+
+$(document).ready( function () {
+	var keys = new KeyTable();
+	
+	/* Focus handler for all cells in last column */
+	keys.event.focus( 4, null, function( nNode, x, y ) {
+		fnMessage( "Cell "+x+","+y+" focused ('live' event - column)" );
+	} );
+	
+	/* Focus handler for all cells in 8th row */
+	keys.event.focus( null, 7, function( nNode, x, y ) {
+		fnMessage( "Cell "+x+","+y+" focused ('live' event - row)" );
+	} );
+	
+	/* Focus using coords. */
+	keys.event.focus( 1, 0, function( nNode ) {
+		keys.event.remove.focus( nNode );
+		fnMessage( "Cell 1,0 focus - this event has now been removed" );
+	} );
+	
+	keys.event.focus( 1, 3, function() {
+		fnMessage( "Cell 1,3 focus" );
+	} );
+	
+	/* focus with a node */
+	keys.event.focus( $('#example tbody tr:eq(2) td:eq(0)')[0], function() {
+		fnMessage( "Cell 0,2 focus" );
+	} );
+	
+	/* Blur using a node */
+	keys.event.blur( $('#example tbody tr:eq(1) td:eq(2)')[0], function() {
+		fnMessage( "Cell 1,2 blur" );
+	} );
+	
+	/* Blur using coords */
+	keys.event.blur( 2, 4, function() {
+		fnMessage( "Cell 2,4 blur" );
+	} );
+	
+	/* Action */
+	keys.event.action( 2, 2, function( nNode ) {
+		fnMessage( "Cell 2,2 action" );
+		if ( nNode.style.fontWeight == "" || nNode.style.fontWeight == "normal" ) {
+			nNode.style.fontWeight = "bold";
+		} else {
+			nNode.style.fontWeight = "normal";
+		}
+	} );
+	
+	keys.event.action( 2, 5, function( nNode ) {
+		fnMessage( "Cell 2,5 action" );
+		if ( nNode.style.fontStyle == "" ) {
+			nNode.style.fontStyle = "italic";
+		} else {
+			nNode.style.fontStyle = "";
+		}
+	} );
+} );
+ + +

Other examples

+ + + +
+ + \ No newline at end of file diff --git a/modules/thirdparty/jquery/datatables/extras/KeyTable/js/KeyTable.js b/modules/thirdparty/jquery/datatables/extras/KeyTable/js/KeyTable.js new file mode 100644 index 0000000..90ed723 --- /dev/null +++ b/modules/thirdparty/jquery/datatables/extras/KeyTable/js/KeyTable.js @@ -0,0 +1,1111 @@ +/* + * File: KeyTable.js + * Version: 1.1.7 + * CVS: $Idj$ + * Description: Keyboard navigation for HTML tables + * Author: Allan Jardine (www.sprymedia.co.uk) + * Created: Fri Mar 13 21:24:02 GMT 2009 + * Modified: $Date$ by $Author$ + * Language: Javascript + * License: GPL v2 or BSD 3 point style + * Project: Just a little bit of fun :-) + * Contact: www.sprymedia.co.uk/contact + * + * Copyright 2009-2011 Allan Jardine, all rights reserved. + * + * This source file is free software, under either the GPL v2 license or a + * BSD style license, available at: + * http://datatables.net/license_gpl2 + * http://datatables.net/license_bsd + */ + + +function KeyTable ( oInit ) +{ + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * API parameters + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /* + * Variable: block + * Purpose: Flag whether or not KeyTable events should be processed + * Scope: KeyTable - public + */ + this.block = false; + + /* + * Variable: event + * Purpose: Container for all event application methods + * Scope: KeyTable - public + * Notes: This object contains all the public methods for adding and removing events - these + * are dynamically added later on + */ + this.event = { + "remove": {} + }; + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * API methods + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /* + * Function: fnGetCurrentPosition + * Purpose: Get the currently focused cell's position + * Returns: array int: [ x, y ] + * Inputs: void + */ + this.fnGetCurrentPosition = function () + { + return [ _iOldX, _iOldY ]; + }; + + + /* + * Function: fnGetCurrentData + * Purpose: Get the currently focused cell's data (innerHTML) + * Returns: string: - data requested + * Inputs: void + */ + this.fnGetCurrentData = function () + { + return _nOldFocus.innerHTML; + }; + + + /* + * Function: fnGetCurrentTD + * Purpose: Get the currently focused cell + * Returns: node: - focused element + * Inputs: void + */ + this.fnGetCurrentTD = function () + { + return _nOldFocus; + }; + + + /* + * Function: fnSetPosition + * Purpose: Set the position of the focused cell + * Returns: - + * Inputs: int:x - x coordinate + * int:y - y coordinate + * Notes: Thanks to Rohan Daxini for the basis of this function + */ + this.fnSetPosition = function( x, y ) + { + if ( typeof x == 'object' && x.nodeName ) + { + _fnSetFocus( x ); + } + else + { + _fnSetFocus( _fnCellFromCoords(x, y) ); + } + }; + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Private parameters + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /* + * Variable: _nBody + * Purpose: Body node of the table - cached for renference + * Scope: KeyTable - private + */ + var _nBody = null; + + /* + * Variable: + * Purpose: + * Scope: KeyTable - private + */ + var _nOldFocus = null; + + /* + * Variable: _iOldX and _iOldY + * Purpose: X and Y coords of the old elemet that was focused on + * Scope: KeyTable - private + */ + var _iOldX = null; + var _iOldY = null; + + /* + * Variable: _that + * Purpose: Scope saving for 'this' after a jQuery event + * Scope: KeyTable - private + */ + var _that = null; + + /* + * Variable: sFocusClass + * Purpose: Class that should be used for focusing on a cell + * Scope: KeyTable - private + */ + var _sFocusClass = "focus"; + + /* + * Variable: _bKeyCapture + * Purpose: Flag for should KeyTable capture key events or not + * Scope: KeyTable - private + */ + var _bKeyCapture = false; + + /* + * Variable: _oaoEvents + * Purpose: Event cache object, one array for each supported event for speed of searching + * Scope: KeyTable - private + */ + var _oaoEvents = { + "action": [], + "esc": [], + "focus": [], + "blur": [] + }; + + /* + * Variable: _oDatatable + * Purpose: DataTables object for if we are actually using a DataTables table + * Scope: KeyTable - private + */ + var _oDatatable = null; + + var _bForm; + var _nInput; + var _bInputFocused = false; + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Private methods + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Key table events + */ + + /* + * Function: _fnEventAddTemplate + * Purpose: Create a function (with closure for sKey) event addition API + * Returns: function: - template function + * Inputs: string:sKey - type of event to detect + */ + function _fnEventAddTemplate( sKey ) + { + /* + * Function: - + * Purpose: API function for adding event to cache + * Returns: - + * Inputs: 1. node:x - target node to add event for + * 2. function:y - callback function to apply + * or + * 1. int:x - x coord. of target cell (can be null for live events) + * 2. int:y - y coord. of target cell (can be null for live events) + * 3. function:z - callback function to apply + * Notes: This function is (interally) overloaded (in as much as javascript allows for + * that) - the target cell can be given by either node or coords. + */ + return function ( x, y, z ) { + if ( (x===null || typeof x == "number") && + (y===null || typeof y == "number") && + typeof z == "function" ) + { + _fnEventAdd( sKey, x, y, z ); + } + else if ( typeof x == "object" && typeof y == "function" ) + { + var aCoords = _fnCoordsFromCell( x ); + _fnEventAdd( sKey, aCoords[0], aCoords[1], y ); + } + else + { + alert( "Unhandable event type was added: x" +x+ " y:" +y+ " z:" +z ); + } + }; + } + + + /* + * Function: _fnEventRemoveTemplate + * Purpose: Create a function (with closure for sKey) event removal API + * Returns: function: - template function + * Inputs: string:sKey - type of event to detect + */ + function _fnEventRemoveTemplate( sKey ) + { + /* + * Function: - + * Purpose: API function for removing event from cache + * Returns: int: - number of events removed + * Inputs: 1. node:x - target node to remove event from + * 2. function:y - callback function to apply + * or + * 1. int:x - x coord. of target cell (can be null for live events) + * 2. int:y - y coord. of target cell (can be null for live events) + * 3. function:z - callback function to remove - optional + * Notes: This function is (interally) overloaded (in as much as javascript allows for + * that) - the target cell can be given by either node or coords and the function + * to remove is optional + */ + return function ( x, y, z ) { + if ( (x===null || typeof arguments[0] == "number") && + (y===null || typeof arguments[1] == "number" ) ) + { + if ( typeof arguments[2] == "function" ) + { + _fnEventRemove( sKey, x, y, z ); + } + else + { + _fnEventRemove( sKey, x, y ); + } + } + else if ( typeof arguments[0] == "object" ) + { + var aCoords = _fnCoordsFromCell( x ); + if ( typeof arguments[1] == "function" ) + { + _fnEventRemove( sKey, aCoords[0], aCoords[1], y ); + } + else + { + _fnEventRemove( sKey, aCoords[0], aCoords[1] ); + } + } + else + { + alert( "Unhandable event type was removed: x" +x+ " y:" +y+ " z:" +z ); + } + }; + } + + /* Use the template functions to add the event API functions */ + for ( var sKey in _oaoEvents ) + { + if ( sKey ) + { + this.event[sKey] = _fnEventAddTemplate( sKey ); + this.event.remove[sKey] = _fnEventRemoveTemplate( sKey ); + } + } + + + /* + * Function: _fnEventAdd + * Purpose: Add an event to the internal cache + * Returns: - + * Inputs: string:sType - type of event to add, given by the available elements in _oaoEvents + * int:x - x-coords to add event to - can be null for "blanket" event + * int:y - y-coords to add event to - can be null for "blanket" event + * function:fn - callback function for when triggered + */ + function _fnEventAdd( sType, x, y, fn ) + { + _oaoEvents[sType].push( { + "x": x, + "y": y, + "fn": fn + } ); + } + + + /* + * Function: _fnEventRemove + * Purpose: Remove an event from the event cache + * Returns: int: - number of matching events removed + * Inputs: string:sType - type of event to look for + * node:nTarget - target table cell + * function:fn - optional - remove this function. If not given all handlers of this + * type will be removed + */ + function _fnEventRemove( sType, x, y, fn ) + { + var iCorrector = 0; + + for ( var i=0, iLen=_oaoEvents[sType].length ; i= oSettings.fnDisplayEnd() ) + { + if ( oSettings._iDisplayLength >= 0 ) + { + /* Make sure we are not over running the display array */ + if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() ) + { + oSettings._iDisplayStart += oSettings._iDisplayLength; + } + } + else + { + oSettings._iDisplayStart = 0; + } + _oDatatable.oApi._fnCalculateEnd( oSettings ); + } + + /* Page backwards */ + while ( iRow < oSettings._iDisplayStart ) + { + oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ? + oSettings._iDisplayStart - oSettings._iDisplayLength : + 0; + + if ( oSettings._iDisplayStart < 0 ) + { + oSettings._iDisplayStart = 0; + } + _oDatatable.oApi._fnCalculateEnd( oSettings ); + } + + /* Re-draw the table */ + _oDatatable.oApi._fnDraw( oSettings ); + + /* Restore the key capture */ + _bKeyCapture = bKeyCaptureCache; + } + + /* Cache the information that we are interested in */ + var aNewPos = _fnCoordsFromCell( nTarget ); + _nOldFocus = nTarget; + _iOldX = aNewPos[0]; + _iOldY = aNewPos[1]; + + var iViewportHeight, iViewportWidth, iScrollTop, iScrollLeft, iHeight, iWidth, aiPos; + if ( bAutoScroll ) + { + /* Scroll the viewport such that the new cell is fully visible in the rendered window */ + iViewportHeight = document.documentElement.clientHeight; + iViewportWidth = document.documentElement.clientWidth; + iScrollTop = document.body.scrollTop || document.documentElement.scrollTop; + iScrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft; + iHeight = nTarget.offsetHeight; + iWidth = nTarget.offsetWidth; + aiPos = _fnGetPos( nTarget ); + + /* Take account of scrolling in DataTables 1.7 - remove scrolling since that would add to + * the positioning calculation + */ + if ( _oDatatable && typeof oSettings.oScroll != 'undefined' && + (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) + { + aiPos[1] -= $(oSettings.nTable.parentNode).scrollTop(); + aiPos[0] -= $(oSettings.nTable.parentNode).scrollLeft(); + } + + /* Correct viewport positioning for vertical scrolling */ + if ( aiPos[1]+iHeight > iScrollTop+iViewportHeight ) + { + /* Displayed element if off the bottom of the viewport */ + _fnSetScrollTop( aiPos[1]+iHeight - iViewportHeight ); + } + else if ( aiPos[1] < iScrollTop ) + { + /* Displayed element if off the top of the viewport */ + _fnSetScrollTop( aiPos[1] ); + } + + /* Correct viewport positioning for horizontal scrolling */ + if ( aiPos[0]+iWidth > iScrollLeft+iViewportWidth ) + { + /* Displayed element is off the bottom of the viewport */ + _fnSetScrollLeft( aiPos[0]+iWidth - iViewportWidth ); + } + else if ( aiPos[0] < iScrollLeft ) + { + /* Displayed element if off the Left of the viewport */ + _fnSetScrollLeft( aiPos[0] ); + } + } + + /* Take account of scrolling in DataTables 1.7 */ + if ( _oDatatable && typeof oSettings.oScroll != 'undefined' && + (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) + { + var dtScrollBody = oSettings.nTable.parentNode; + iViewportHeight = dtScrollBody.clientHeight; + iViewportWidth = dtScrollBody.clientWidth; + iScrollTop = dtScrollBody.scrollTop; + iScrollLeft = dtScrollBody.scrollLeft; + iHeight = nTarget.offsetHeight; + iWidth = nTarget.offsetWidth; + + /* Correct for vertical scrolling */ + if ( nTarget.offsetTop + iHeight > iViewportHeight+iScrollTop ) + { + dtScrollBody.scrollTop = (nTarget.offsetTop + iHeight) - iViewportHeight; + } + else if ( nTarget.offsetTop < iScrollTop ) + { + dtScrollBody.scrollTop = nTarget.offsetTop; + } + + /* Correct for horizontal scrolling */ + if ( nTarget.offsetLeft + iWidth > iViewportWidth+iScrollLeft ) + { + dtScrollBody.scrollLeft = (nTarget.offsetLeft + iWidth) - iViewportWidth; + } + else if ( nTarget.offsetLeft < iScrollLeft ) + { + dtScrollBody.scrollLeft = nTarget.offsetLeft; + } + } + + /* Focused - so we want to capture the keys */ + _fnCaptureKeys(); + + /* Fire of the focus event if there is one */ + _fnEventFire( "focus", _iOldX, _iOldY ); + } + + + /* + * Function: _fnBlur + * Purpose: Blur focus from the whole table + * Returns: - + * Inputs: - + */ + function _fnBlur() + { + _fnRemoveFocus( _nOldFocus ); + _iOldX = null; + _iOldY = null; + _nOldFocus = null; + _fnReleaseKeys(); + } + + + /* + * Function: _fnRemoveFocus + * Purpose: Remove focus from a cell and fire any blur events which are attached + * Returns: - + * Inputs: node:nTarget - cell of interest + */ + function _fnRemoveFocus( nTarget ) + { + jQuery(nTarget).removeClass( _sFocusClass ); + jQuery(nTarget).parent().removeClass( _sFocusClass ); + _fnEventFire( "blur", _iOldX, _iOldY ); + } + + + /* + * Function: _fnClick + * Purpose: Focus on the element that has been clicked on by the user + * Returns: - + * Inputs: event:e - click event + */ + function _fnClick ( e ) + { + var nTarget = this; + while ( nTarget.nodeName != "TD" ) + { + nTarget = nTarget.parentNode; + } + + _fnSetFocus( nTarget ); + _fnCaptureKeys(); + } + + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Key events + */ + + /* + * Function: _fnKey + * Purpose: Deal with a key events, be it moving the focus or return etc. + * Returns: bool: - allow browser default action + * Inputs: event:e - key event + */ + function _fnKey ( e ) + { + /* If user or system has blocked KeyTable from doing anything, just ignore this event */ + if ( _that.block || !_bKeyCapture ) + { + return true; + } + + /* If a modifier key is pressed (exapct shift), ignore the event */ + if ( e.metaKey || e.altKey || e.ctrlKey ) + { + return true; + } + var + x, y, + iTableWidth = _nBody.getElementsByTagName('tr')[0].getElementsByTagName('td').length, + iTableHeight; + + /* Get table height and width - done here so as to be dynamic (if table is updated) */ + if ( _oDatatable ) + { + /* + * Locate the current node in the DataTable overriding the old positions - the reason for + * is is that there might have been some DataTables interaction between the last focus and + * now + */ + var oSettings = _oDatatable.fnSettings(); + iTableHeight = oSettings.aiDisplay.length; + + var aDtPos = _fnFindDtCell( _nOldFocus ); + if ( aDtPos === null ) + { + /* If the table has been updated such that the focused cell can't be seen - do nothing */ + return; + } + _iOldX = aDtPos[ 0 ]; + _iOldY = aDtPos[ 1 ]; + } + else + { + iTableHeight = _nBody.getElementsByTagName('tr').length; + } + + /* Capture shift+tab to match the left arrow key */ + var iKey = (e.keyCode == 9 && e.shiftKey) ? -1 : e.keyCode; + + switch( iKey ) + { + case 13: /* return */ + e.preventDefault(); + e.stopPropagation(); + _fnEventFire( "action", _iOldX, _iOldY ); + return true; + + case 27: /* esc */ + if ( !_fnEventFire( "esc", _iOldX, _iOldY ) ) + { + /* Only lose focus if there isn't an escape handler on the cell */ + _fnBlur(); + return; + } + x = _iOldX; + y = _iOldY; + break; + + case -1: + case 37: /* left arrow */ + if ( _iOldX > 0 ) { + x = _iOldX - 1; + y = _iOldY; + } else if ( _iOldY > 0 ) { + x = iTableWidth-1; + y = _iOldY - 1; + } else { + /* at start of table */ + if ( iKey == -1 && _bForm ) + { + /* If we are in a form, return focus to the 'input' element such that tabbing will + * follow correctly in the browser + */ + _bInputFocused = true; + _nInput.focus(); + + /* This timeout is a little nasty - but IE appears to have some asyhnc behaviour for + * focus + */ + setTimeout( function(){ _bInputFocused = false; }, 0 ); + _bKeyCapture = false; + _fnBlur(); + return true; + } + else + { + return false; + } + } + break; + + case 38: /* up arrow */ + if ( _iOldY > 0 ) { + x = _iOldX; + y = _iOldY - 1; + } else { + return false; + } + break; + + case 9: /* tab */ + case 39: /* right arrow */ + if ( _iOldX < iTableWidth-1 ) { + x = _iOldX + 1; + y = _iOldY; + } else if ( _iOldY < iTableHeight-1 ) { + x = 0; + y = _iOldY + 1; + } else { + /* at end of table */ + if ( iKey == 9 && _bForm ) + { + /* If we are in a form, return focus to the 'input' element such that tabbing will + * follow correctly in the browser + */ + _bInputFocused = true; + _nInput.focus(); + + /* This timeout is a little nasty - but IE appears to have some asyhnc behaviour for + * focus + */ + setTimeout( function(){ _bInputFocused = false; }, 0 ); + _bKeyCapture = false; + _fnBlur(); + return true; + } + else + { + return false; + } + } + break; + + case 40: /* down arrow */ + if ( _iOldY < iTableHeight-1 ) { + x = _iOldX; + y = _iOldY + 1; + } else { + return false; + } + break; + + default: /* Nothing we are interested in */ + return true; + } + + _fnSetFocus( _fnCellFromCoords(x, y) ); + return false; + } + + + /* + * Function: _fnCaptureKeys + * Purpose: Start capturing key events for this table + * Returns: - + * Inputs: - + */ + function _fnCaptureKeys( ) + { + if ( !_bKeyCapture ) + { + _bKeyCapture = true; + } + } + + + /* + * Function: _fnReleaseKeys + * Purpose: Stop capturing key events for this table + * Returns: - + * Inputs: - + */ + function _fnReleaseKeys( ) + { + _bKeyCapture = false; + } + + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Support functions + */ + + /* + * Function: _fnCellFromCoords + * Purpose: Calulate the target TD cell from x and y coordinates + * Returns: node: - TD target + * Inputs: int:x - x coordinate + * int:y - y coordinate + */ + function _fnCellFromCoords( x, y ) + { + if ( _oDatatable ) + { + var oSettings = _oDatatable.fnSettings(); + if ( typeof oSettings.aoData[ oSettings.aiDisplay[ y ] ] != 'undefined' ) + { + return oSettings.aoData[ oSettings.aiDisplay[ y ] ].nTr.getElementsByTagName('td')[x]; + } + else + { + return null; + } + } + else + { + return jQuery('tr:eq('+y+')>td:eq('+x+')', _nBody )[0]; + } + } + + + /* + * Function: _fnCoordsFromCell + * Purpose: Calculate the x and y position in a table from a TD cell + * Returns: array[2] int: [x, y] + * Inputs: node:n - TD cell of interest + * Notes: Not actually interested in this for DataTables since it might go out of date + */ + function _fnCoordsFromCell( n ) + { + if ( _oDatatable ) + { + var oSettings = _oDatatable.fnSettings(); + return [ + jQuery('td', n.parentNode).index(n), + jQuery('tr', n.parentNode.parentNode).index(n.parentNode) + oSettings._iDisplayStart + ]; + } + else + { + return [ + jQuery('td', n.parentNode).index(n), + jQuery('tr', n.parentNode.parentNode).index(n.parentNode) + ]; + } + } + + + /* + * Function: _fnSetScrollTop + * Purpose: Set the vertical scrolling position + * Returns: - + * Inputs: int:iPos - scrolltop + * Notes: This is so nasty, but without browser detection you can't tell which you should set + * So on browsers that support both, the scroll top will be set twice. I can live with + * that :-) + */ + function _fnSetScrollTop( iPos ) + { + document.documentElement.scrollTop = iPos; + document.body.scrollTop = iPos; + } + + + /* + * Function: _fnSetScrollLeft + * Purpose: Set the horizontal scrolling position + * Returns: - + * Inputs: int:iPos - scrollleft + */ + function _fnSetScrollLeft( iPos ) + { + document.documentElement.scrollLeft = iPos; + document.body.scrollLeft = iPos; + } + + + /* + * Function: _fnGetPos + * Purpose: Get the position of an object on the rendered page + * Returns: array[2] int: [left, right] + * Inputs: node:obj - element of interest + */ + function _fnGetPos ( obj ) + { + var iLeft = 0; + var iTop = 0; + + if (obj.offsetParent) + { + iLeft = obj.offsetLeft; + iTop = obj.offsetTop; + obj = obj.offsetParent; + while (obj) + { + iLeft += obj.offsetLeft; + iTop += obj.offsetTop; + obj = obj.offsetParent; + } + } + return [iLeft,iTop]; + } + + + /* + * Function: _fnFindDtCell + * Purpose: Get the coords. of a cell from the DataTables internal information + * Returns: array[2] int: [x, y] coords. or null if not found + * Inputs: node:nTarget - the node of interest + */ + function _fnFindDtCell( nTarget ) + { + var oSettings = _oDatatable.fnSettings(); + for ( var i=0, iLen=oSettings.aiDisplay.length ; i