summaryrefslogtreecommitdiffstats
path: root/usr
diff options
context:
space:
mode:
authorChris Buechler <cmb@pfsense.org>2011-07-25 05:23:31 -0400
committerChris Buechler <cmb@pfsense.org>2011-07-25 05:23:31 -0400
commit581e4f7afd2f6297f81fa08ca1698210597d1e64 (patch)
tree5013760332cd0011f945a7d76e2f2d052d88992b /usr
parentcb2518bf5a57d6459753e205e91e7f157ca60cd3 (diff)
parent9ee5069a078d050313c290d5c24eeff1ad07154e (diff)
downloadpfsense-581e4f7afd2f6297f81fa08ca1698210597d1e64.zip
pfsense-581e4f7afd2f6297f81fa08ca1698210597d1e64.tar.gz
Merge branch 'master' of github.com:bsdperimeter/pfsense
Diffstat (limited to 'usr')
-rwxr-xr-xusr/local/captiveportal/index.php10
-rw-r--r--usr/local/www/csrf/csrf-magic.js354
-rw-r--r--usr/local/www/csrf/csrf-magic.php744
-rwxr-xr-xusr/local/www/diag_logs_ppp.php2
-rwxr-xr-xusr/local/www/firewall_aliases.php2
-rwxr-xr-xusr/local/www/firewall_aliases_edit.php1
-rwxr-xr-xusr/local/www/firewall_nat.php2
-rwxr-xr-xusr/local/www/firewall_nat_edit.php5
-rwxr-xr-xusr/local/www/firewall_rules.php63
-rwxr-xr-xusr/local/www/firewall_rules_edit.php6
-rw-r--r--usr/local/www/firewall_shaper_vinterface.php2
-rwxr-xr-xusr/local/www/guiconfig.inc2
-rwxr-xr-xusr/local/www/index.php2
-rwxr-xr-xusr/local/www/interfaces.php8
-rwxr-xr-xusr/local/www/interfaces_assign.php1
-rwxr-xr-xusr/local/www/interfaces_groups.php2
-rw-r--r--usr/local/www/javascript/chosen/chosen-sprite.pngbin0 -> 1866 bytes
-rw-r--r--usr/local/www/javascript/chosen/chosen.css317
-rw-r--r--usr/local/www/javascript/chosen/chosen.jquery.js755
-rw-r--r--usr/local/www/javascript/chosen/chosen.jquery.min.js9
-rw-r--r--usr/local/www/javascript/chosen/chosen.proto.js765
-rw-r--r--usr/local/www/javascript/chosen/chosen.proto.min.js9
-rw-r--r--usr/local/www/javascript/chosen/coffee/chosen.jquery.coffee633
-rw-r--r--usr/local/www/javascript/chosen/coffee/chosen.proto.coffee629
-rw-r--r--usr/local/www/javascript/scriptaculous/prototype.js3467
-rwxr-xr-xusr/local/www/services_captiveportal.php9
-rw-r--r--usr/local/www/services_captiveportal_vouchers.php2
-rwxr-xr-xusr/local/www/services_dhcp.php4
-rwxr-xr-xusr/local/www/status_services.php2
-rwxr-xr-xusr/local/www/system.php2
-rw-r--r--usr/local/www/system_advanced_admin.php2
-rw-r--r--usr/local/www/system_advanced_misc.php8
-rw-r--r--usr/local/www/system_advanced_notifications.php4
-rw-r--r--usr/local/www/system_crlmanager.php4
-rwxr-xr-xusr/local/www/system_gateways_edit.php4
-rwxr-xr-xusr/local/www/vpn_pppoe_edit.php4
-rw-r--r--usr/local/www/wizards/openvpn_wizard.inc4
-rw-r--r--usr/local/www/wizards/traffic_shaper_wizard.inc53
-rwxr-xr-xusr/local/www/wizards/traffic_shaper_wizard_dedicated.inc329
-rwxr-xr-xusr/local/www/wizards/traffic_shaper_wizard_multi_all.inc146
-rw-r--r--usr/local/www/wizards/traffic_shaper_wizard_multi_lan.inc8
41 files changed, 6392 insertions, 1983 deletions
diff --git a/usr/local/captiveportal/index.php b/usr/local/captiveportal/index.php
index 0170a7a..1bd9366 100755
--- a/usr/local/captiveportal/index.php
+++ b/usr/local/captiveportal/index.php
@@ -77,12 +77,12 @@ if ($orig_host != $ourhostname) {
exit;
}
-if (preg_match("/redirurl=(.*)/", $orig_request, $matches))
- $redirurl = urldecode($matches[1]);
-if ($_POST['redirurl'])
- $redirurl = $_POST['redirurl'];
if (!empty($config['captiveportal']['redirurl']))
$redirurl = $config['captiveportal']['redirurl'];
+else if (preg_match("/redirurl=(.*)/", $orig_request, $matches))
+ $redirurl = urldecode($matches[1]);
+else if ($_REQUEST['redirurl'])
+ $redirurl = $_REQUEST['redirurl'];
$macfilter = !isset($config['captiveportal']['nomacfilter']);
$passthrumac = isset($config['captiveportal']['passthrumacadd']);
@@ -193,7 +193,7 @@ EOD;
captiveportal_logportalauth($_POST['auth_user'],$clientmac,$clientip,"FAILURE");
portal_reply_page($redirurl, "error", $errormsg);
}
-} else if ($_POST['accept'] && $clientip) {
+} else if ($_POST['accept'] && $clientip && $config['captiveportal']['auth_method'] == "none") {
captiveportal_logportalauth("unauthenticated",$clientmac,$clientip,"ACCEPT");
portal_allow($clientip, $clientmac, "unauthenticated");
} else {
diff --git a/usr/local/www/csrf/csrf-magic.js b/usr/local/www/csrf/csrf-magic.js
index 820f6e8..6992402 100644
--- a/usr/local/www/csrf/csrf-magic.js
+++ b/usr/local/www/csrf/csrf-magic.js
@@ -1,177 +1,177 @@
-/**
- * @file
- *
- * Rewrites XMLHttpRequest to automatically send CSRF token with it. In theory
- * plays nice with other JavaScript libraries, needs testing though.
- */
-
-// Here are the basic overloaded method definitions
-// The wrapper must be set BEFORE onreadystatechange is written to, since
-// a bug in ActiveXObject prevents us from properly testing for it.
-CsrfMagic = function(real) {
- // try to make it ourselves, if you didn't pass it
- if (!real) try { real = new XMLHttpRequest; } catch (e) {;}
- if (!real) try { real = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) {;}
- if (!real) try { real = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {;}
- if (!real) try { real = new ActiveXObject('Msxml2.XMLHTTP.4.0'); } catch (e) {;}
- this.csrf = real;
- // properties
- var csrfMagic = this;
- real.onreadystatechange = function() {
- csrfMagic._updateProps();
- return csrfMagic.onreadystatechange ? csrfMagic.onreadystatechange() : null;
- };
- csrfMagic._updateProps();
-}
-
-CsrfMagic.prototype = {
-
- open: function(method, url, async, username, password) {
- if (method == 'POST') this.csrf_isPost = true;
- // deal with Opera bug, thanks jQuery
- if (username) return this.csrf_open(method, url, async, username, password);
- else return this.csrf_open(method, url, async);
- },
- csrf_open: function(method, url, async, username, password) {
- if (username) return this.csrf.open(method, url, async, username, password);
- else return this.csrf.open(method, url, async);
- },
-
- send: function(data) {
- if (!this.csrf_isPost) return this.csrf_send(data);
- prepend = csrfMagicName + '=' + csrfMagicToken + '&';
- if (this.csrf_purportedLength === undefined) {
- this.csrf_setRequestHeader("Content-length", this.csrf_purportedLength + prepend.length);
- delete this.csrf_purportedLength;
- }
- delete this.csrf_isPost;
- return this.csrf_send(prepend + data);
- },
- csrf_send: function(data) {
- return this.csrf.send(data);
- },
-
- setRequestHeader: function(header, value) {
- // We have to auto-set this at the end, since we don't know how long the
- // nonce is when added to the data.
- if (this.csrf_isPost && header == "Content-length") {
- this.csrf_purportedLength = value;
- return;
- }
- return this.csrf_setRequestHeader(header, value);
- },
- csrf_setRequestHeader: function(header, value) {
- return this.csrf.setRequestHeader(header, value);
- },
-
- abort: function() {
- return this.csrf.abort();
- },
- getAllResponseHeaders: function() {
- return this.csrf.getAllResponseHeaders();
- },
- getResponseHeader: function(header) {
- return this.csrf.getResponseHeader(header);
- } // ,
-}
-
-// proprietary
-CsrfMagic.prototype._updateProps = function() {
- this.readyState = this.csrf.readyState;
- if (this.readyState == 4) {
- this.responseText = this.csrf.responseText;
- this.responseXML = this.csrf.responseXML;
- this.status = this.csrf.status;
- this.statusText = this.csrf.statusText;
- }
-}
-CsrfMagic.process = function(base) {
- var prepend = csrfMagicName + '=' + csrfMagicToken;
- if (base) return prepend + '&' + base;
- return prepend;
-}
-// callback function for when everything on the page has loaded
-CsrfMagic.end = function() {
- // This rewrites forms AGAIN, so in case buffering didn't work this
- // certainly will.
- forms = document.getElementsByTagName('form');
- for (var i = 0; i < forms.length; i++) {
- form = forms[i];
- if (form.method.toUpperCase() !== 'POST') continue;
- if (form.elements[csrfMagicName]) continue;
- var input = document.createElement('input');
- input.setAttribute('name', csrfMagicName);
- input.setAttribute('value', csrfMagicToken);
- input.setAttribute('type', 'hidden');
- form.appendChild(input);
- }
-}
-
-// Sets things up for Mozilla/Opera/nice browsers
-if (window.XMLHttpRequest && window.XMLHttpRequest.prototype) {
- var x = XMLHttpRequest.prototype;
- var c = CsrfMagic.prototype;
-
- // Save the original functions
- x.csrf_open = x.open;
- x.csrf_send = x.send;
- x.csrf_setRequestHeader = x.setRequestHeader;
-
- // Notice that CsrfMagic is itself an instantiatable object, but only
- // open, send and setRequestHeader are necessary as decorators.
- x.open = c.open;
- x.send = c.send;
- x.setRequestHeader = c.setRequestHeader;
-} else {
- // The only way we can do this is by modifying a library you have been
- // using. We support YUI, script.aculo.us, prototype, MooTools,
- // jQuery, Ext and Dojo.
- if (window.jQuery) {
- // jQuery didn't implement a new XMLHttpRequest function, so we have
- // to do this the hard way.
- jQuery.csrf_ajax = jQuery.ajax;
- jQuery.ajax = function( s ) {
- if (s.type && s.type.toUpperCase() == 'POST') {
- s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
- if ( s.data && s.processData && typeof s.data != "string" ) {
- s.data = jQuery.param(s.data);
- }
- s.data = CsrfMagic.process(s.data);
- }
- return jQuery.csrf_ajax( s );
- }
- } else if (window.Prototype) {
- // This works for script.aculo.us too
- Ajax.csrf_getTransport = Ajax.getTransport;
- Ajax.getTransport = function() {
- return new CsrfMagic(Ajax.csrf_getTransport());
- }
- } else if (window.MooTools) {
- Browser.csrf_Request = Browser.Request;
- Browser.Request = function () {
- return new CsrfMagic(Browser.csrf_Request());
- }
- } else if (window.YAHOO) {
- YAHOO.util.Connect.csrf_createXhrObject = YAHOO.util.Connect.createXhrObject;
- YAHOO.util.Connect.createXhrObject = function (transaction) {
- obj = YAHOO.util.Connect.csrf_createXhrObject(transaction);
- obj.conn = new CsrfMagic(obj.conn);
- return obj;
- }
- } else if (window.Ext) {
- // Ext can use other js libraries as loaders, so it has to come last
- // Ext's implementation is pretty identical to Yahoo's, but we duplicate
- // it for comprehensiveness's sake.
- Ext.lib.Ajax.csrf_createXhrObject = Ext.lib.Ajax.createXhrObject;
- Ext.lib.Ajax.createXhrObject = function (transaction) {
- obj = Ext.lib.Ajax.csrf_createXhrObject(transaction);
- obj.conn = new CsrfMagic(obj.conn);
- return obj;
- }
- } else if (window.dojo) {
- dojo.csrf__xhrObj = dojo._xhrObj;
- dojo._xhrObj = function () {
- return new CsrfMagic(dojo.csrf__xhrObj());
- }
- }
-}
+/**
+ * @file
+ *
+ * Rewrites XMLHttpRequest to automatically send CSRF token with it. In theory
+ * plays nice with other JavaScript libraries, needs testing though.
+ */
+
+// Here are the basic overloaded method definitions
+// The wrapper must be set BEFORE onreadystatechange is written to, since
+// a bug in ActiveXObject prevents us from properly testing for it.
+CsrfMagic = function(real) {
+ // try to make it ourselves, if you didn't pass it
+ if (!real) try { real = new XMLHttpRequest; } catch (e) {;}
+ if (!real) try { real = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) {;}
+ if (!real) try { real = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {;}
+ if (!real) try { real = new ActiveXObject('Msxml2.XMLHTTP.4.0'); } catch (e) {;}
+ this.csrf = real;
+ // properties
+ var csrfMagic = this;
+ real.onreadystatechange = function() {
+ csrfMagic._updateProps();
+ return csrfMagic.onreadystatechange ? csrfMagic.onreadystatechange() : null;
+ };
+ csrfMagic._updateProps();
+}
+
+CsrfMagic.prototype = {
+
+ open: function(method, url, async, username, password) {
+ if (method == 'POST') this.csrf_isPost = true;
+ // deal with Opera bug, thanks jQuery
+ if (username) return this.csrf_open(method, url, async, username, password);
+ else return this.csrf_open(method, url, async);
+ },
+ csrf_open: function(method, url, async, username, password) {
+ if (username) return this.csrf.open(method, url, async, username, password);
+ else return this.csrf.open(method, url, async);
+ },
+
+ send: function(data) {
+ if (!this.csrf_isPost) return this.csrf_send(data);
+ prepend = csrfMagicName + '=' + csrfMagicToken + '&';
+ if (this.csrf_purportedLength === undefined) {
+ this.csrf_setRequestHeader("Content-length", this.csrf_purportedLength + prepend.length);
+ delete this.csrf_purportedLength;
+ }
+ delete this.csrf_isPost;
+ return this.csrf_send(prepend + data);
+ },
+ csrf_send: function(data) {
+ return this.csrf.send(data);
+ },
+
+ setRequestHeader: function(header, value) {
+ // We have to auto-set this at the end, since we don't know how long the
+ // nonce is when added to the data.
+ if (this.csrf_isPost && header == "Content-length") {
+ this.csrf_purportedLength = value;
+ return;
+ }
+ return this.csrf_setRequestHeader(header, value);
+ },
+ csrf_setRequestHeader: function(header, value) {
+ return this.csrf.setRequestHeader(header, value);
+ },
+
+ abort: function() {
+ return this.csrf.abort();
+ },
+ getAllResponseHeaders: function() {
+ return this.csrf.getAllResponseHeaders();
+ },
+ getResponseHeader: function(header) {
+ return this.csrf.getResponseHeader(header);
+ } // ,
+}
+
+// proprietary
+CsrfMagic.prototype._updateProps = function() {
+ this.readyState = this.csrf.readyState;
+ if (this.readyState == 4) {
+ this.responseText = this.csrf.responseText;
+ this.responseXML = this.csrf.responseXML;
+ this.status = this.csrf.status;
+ this.statusText = this.csrf.statusText;
+ }
+}
+CsrfMagic.process = function(base) {
+ var prepend = csrfMagicName + '=' + csrfMagicToken;
+ if (base) return prepend + '&' + base;
+ return prepend;
+}
+// callback function for when everything on the page has loaded
+CsrfMagic.end = function() {
+ // This rewrites forms AGAIN, so in case buffering didn't work this
+ // certainly will.
+ forms = document.getElementsByTagName('form');
+ for (var i = 0; i < forms.length; i++) {
+ form = forms[i];
+ if (form.method.toUpperCase() !== 'POST') continue;
+ if (form.elements[csrfMagicName]) continue;
+ var input = document.createElement('input');
+ input.setAttribute('name', csrfMagicName);
+ input.setAttribute('value', csrfMagicToken);
+ input.setAttribute('type', 'hidden');
+ form.appendChild(input);
+ }
+}
+
+// Sets things up for Mozilla/Opera/nice browsers
+if (window.XMLHttpRequest && window.XMLHttpRequest.prototype) {
+ var x = XMLHttpRequest.prototype;
+ var c = CsrfMagic.prototype;
+
+ // Save the original functions
+ x.csrf_open = x.open;
+ x.csrf_send = x.send;
+ x.csrf_setRequestHeader = x.setRequestHeader;
+
+ // Notice that CsrfMagic is itself an instantiatable object, but only
+ // open, send and setRequestHeader are necessary as decorators.
+ x.open = c.open;
+ x.send = c.send;
+ x.setRequestHeader = c.setRequestHeader;
+} else {
+ // The only way we can do this is by modifying a library you have been
+ // using. We support YUI, script.aculo.us, prototype, MooTools,
+ // jQuery, Ext and Dojo.
+ if (window.jQuery) {
+ // jQuery didn't implement a new XMLHttpRequest function, so we have
+ // to do this the hard way.
+ jQuery.csrf_ajax = jQuery.ajax;
+ jQuery.ajax = function( s ) {
+ if (s.type && s.type.toUpperCase() == 'POST') {
+ s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
+ if ( s.data && s.processData && typeof s.data != "string" ) {
+ s.data = jQuery.param(s.data);
+ }
+ s.data = CsrfMagic.process(s.data);
+ }
+ return jQuery.csrf_ajax( s );
+ }
+ } else if (window.Prototype) {
+ // This works for script.aculo.us too
+ Ajax.csrf_getTransport = Ajax.getTransport;
+ Ajax.getTransport = function() {
+ return new CsrfMagic(Ajax.csrf_getTransport());
+ }
+ } else if (window.MooTools) {
+ Browser.csrf_Request = Browser.Request;
+ Browser.Request = function () {
+ return new CsrfMagic(Browser.csrf_Request());
+ }
+ } else if (window.YAHOO) {
+ YAHOO.util.Connect.csrf_createXhrObject = YAHOO.util.Connect.createXhrObject;
+ YAHOO.util.Connect.createXhrObject = function (transaction) {
+ obj = YAHOO.util.Connect.csrf_createXhrObject(transaction);
+ obj.conn = new CsrfMagic(obj.conn);
+ return obj;
+ }
+ } else if (window.Ext) {
+ // Ext can use other js libraries as loaders, so it has to come last
+ // Ext's implementation is pretty identical to Yahoo's, but we duplicate
+ // it for comprehensiveness's sake.
+ Ext.lib.Ajax.csrf_createXhrObject = Ext.lib.Ajax.createXhrObject;
+ Ext.lib.Ajax.createXhrObject = function (transaction) {
+ obj = Ext.lib.Ajax.csrf_createXhrObject(transaction);
+ obj.conn = new CsrfMagic(obj.conn);
+ return obj;
+ }
+ } else if (window.dojo) {
+ dojo.csrf__xhrObj = dojo._xhrObj;
+ dojo._xhrObj = function () {
+ return new CsrfMagic(dojo.csrf__xhrObj());
+ }
+ }
+}
diff --git a/usr/local/www/csrf/csrf-magic.php b/usr/local/www/csrf/csrf-magic.php
index ccb1617..befad0a 100644
--- a/usr/local/www/csrf/csrf-magic.php
+++ b/usr/local/www/csrf/csrf-magic.php
@@ -1,372 +1,372 @@
-<?php
-
-/**
- * @file
- *
- * csrf-magic is a PHP library that makes adding CSRF-protection to your
- * web applications a snap. No need to modify every form or create a database
- * of valid nonces; just include this file at the top of every
- * web-accessible page (or even better, your common include file included
- * in every page), and forget about it! (There are, of course, configuration
- * options for advanced users).
- *
- * This library is PHP4 and PHP5 compatible.
- */
-
-// CONFIGURATION:
-
-/**
- * By default, when you include this file csrf-magic will automatically check
- * and exit if the CSRF token is invalid. This will defer executing
- * csrf_check() until you're ready. You can also pass false as a parameter to
- * that function, in which case the function will not exit but instead return
- * a boolean false if the CSRF check failed. This allows for tighter integration
- * with your system.
- */
-$GLOBALS['csrf']['defer'] = false;
-
-/**
- * This is the amount of seconds you wish to allow before any token becomes
- * invalid; the default is two hours, which should be more than enough for
- * most websites.
- */
-$GLOBALS['csrf']['expires'] = 7200;
-
-/**
- * Callback function to execute when there's the CSRF check fails and
- * $fatal == true (see csrf_check). This will usually output an error message
- * about the failure.
- */
-$GLOBALS['csrf']['callback'] = 'csrf_callback';
-
-/**
- * Whether or not to include our JavaScript library which also rewrites
- * AJAX requests on this domain. Set this to the web path. This setting only works
- * with supported JavaScript libraries in Internet Explorer; see README.txt for
- * a list of supported libraries.
- */
-$GLOBALS['csrf']['rewrite-js'] = false;
-
-/**
- * A secret key used when hashing items. Please generate a random string and
- * place it here. If you change this value, all previously generated tokens
- * will become invalid.
- */
-$GLOBALS['csrf']['secret'] = '';
-
-/**
- * Set this to false to disable csrf-magic's output handler, and therefore,
- * its rewriting capabilities. If you're serving non HTML content, you should
- * definitely set this false.
- */
-$GLOBALS['csrf']['rewrite'] = true;
-
-/**
- * Whether or not to use IP addresses when binding a user to a token. This is
- * less reliable and less secure than sessions, but is useful when you need
- * to give facilities to anonymous users and do not wish to maintain a database
- * of valid keys.
- */
-$GLOBALS['csrf']['allow-ip'] = true;
-
-/**
- * If this information is available, use the cookie by this name to determine
- * whether or not to allow the request. This is a shortcut implementation
- * very similar to 'key', but we randomly set the cookie ourselves.
- */
-$GLOBALS['csrf']['cookie'] = '__csrf_cookie';
-
-/**
- * If this information is available, set this to a unique identifier (it
- * can be an integer or a unique username) for the current "user" of this
- * application. The token will then be globally valid for all of that user's
- * operations, but no one else. This requires that 'secret' be set.
- */
-$GLOBALS['csrf']['user'] = false;
-
-/**
- * This is an arbitrary secret value associated with the user's session. This
- * will most probably be the contents of a cookie, as an attacker cannot easily
- * determine this information. Warning: If the attacker knows this value, they
- * can easily spoof a token. This is a generic implementation; sessions should
- * work in most cases.
- *
- * Why would you want to use this? Lets suppose you have a squid cache for your
- * website, and the presence of a session cookie bypasses it. Let's also say
- * you allow anonymous users to interact with the website; submitting forms
- * and AJAX. Previously, you didn't have any CSRF protection for anonymous users
- * and so they never got sessions; you don't want to start using sessions either,
- * otherwise you'll bypass the Squid cache. Setup a different cookie for CSRF
- * tokens, and have Squid ignore that cookie for get requests, for anonymous
- * users. (If you haven't guessed, this scheme was(?) used for MediaWiki).
- */
-$GLOBALS['csrf']['key'] = false;
-
-/**
- * The name of the magic CSRF token that will be placed in all forms, i.e.
- * the contents of <input type="hidden" name="$name" value="CSRF-TOKEN" />
- */
-$GLOBALS['csrf']['input-name'] = '__csrf_magic';
-
-/**
- * Set this to false if your site must work inside of frame/iframe elements,
- * but do so at your own risk: this configuration protects you against CSS
- * overlay attacks that defeat tokens.
- */
-$GLOBALS['csrf']['frame-breaker'] = true;
-
-/**
- * Whether or not CSRF Magic should be allowed to start a new session in order
- * to determine the key.
- */
-$GLOBALS['csrf']['auto-session'] = true;
-
-/**
- * Whether or not csrf-magic should produce XHTML style tags.
- */
-$GLOBALS['csrf']['xhtml'] = true;
-
-// FUNCTIONS:
-
-// Don't edit this!
-$GLOBALS['csrf']['version'] = '1.0.1';
-
-/**
- * Rewrites <form> on the fly to add CSRF tokens to them. This can also
- * inject our JavaScript library.
- */
-function csrf_ob_handler($buffer, $flags) {
- // Even though the user told us to rewrite, we should do a quick heuristic
- // to check if the page is *actually* HTML. We don't begin rewriting until
- // we hit the first <html tag.
- static $is_html = false;
- if (!$is_html) {
- // not HTML until proven otherwise
- if (stripos($buffer, '<html') !== false) {
- $is_html = true;
- } else {
- return $buffer;
- }
- }
- $tokens = csrf_get_tokens();
- $name = $GLOBALS['csrf']['input-name'];
- $endslash = $GLOBALS['csrf']['xhtml'] ? ' /' : '';
- $input = "<input type='hidden' name='$name' value=\"$tokens\"$endslash>";
- $buffer = preg_replace('#(<form[^>]*method\s*=\s*["\']post["\'][^>]*>)#i', '$1' . $input, $buffer);
- if ($GLOBALS['csrf']['frame-breaker']) {
- $buffer = str_ireplace('</head>', '<script type="text/javascript">if (top != self) {top.location.href = self.location.href;}</script></head>', $buffer);
- }
- if ($js = $GLOBALS['csrf']['rewrite-js']) {
- $buffer = str_ireplace(
- '</head>',
- '<script type="text/javascript">'.
- 'var csrfMagicToken = "'.$tokens.'";'.
- 'var csrfMagicName = "'.$name.'";</script>'.
- '<script src="'.$js.'" type="text/javascript"></script></head>',
- $buffer
- );
- $script = '<script type="text/javascript">CsrfMagic.end();</script>';
- $buffer = str_ireplace('</body>', $script . '</body>', $buffer, $count);
- if (!$count) {
- $buffer .= $script;
- }
- }
- return $buffer;
-}
-
-/**
- * Checks if this is a post request, and if it is, checks if the nonce is valid.
- * @param bool $fatal Whether or not to fatally error out if there is a problem.
- * @return True if check passes or is not necessary, false if failure.
- */
-function csrf_check($fatal = true) {
- if ($_SERVER['REQUEST_METHOD'] !== 'POST') return true;
- csrf_start();
- $name = $GLOBALS['csrf']['input-name'];
- $ok = false;
- $tokens = '';
- do {
- if (!isset($_POST[$name])) break;
- // we don't regenerate a token and check it because some token creation
- // schemes are volatile.
- $tokens = $_POST[$name];
- if (!csrf_check_tokens($tokens)) break;
- $ok = true;
- } while (false);
- if ($fatal && !$ok) {
- $callback = $GLOBALS['csrf']['callback'];
- if (trim($tokens, 'A..Za..z0..9:;,') !== '') $tokens = 'hidden';
- $callback($tokens);
- exit;
- }
- return $ok;
-}
-
-/**
- * Retrieves a valid token(s) for a particular context. Tokens are separated
- * by semicolons.
- */
-function csrf_get_tokens() {
- $has_cookies = !empty($_COOKIE);
-
- // $ip implements a composite key, which is sent if the user hasn't sent
- // any cookies. It may or may not be used, depending on whether or not
- // the cookies "stick"
- if (!$has_cookies && $secret) {
- // :TODO: Harden this against proxy-spoofing attacks
- $ip = ';ip:' . csrf_hash($_SERVER['IP_ADDRESS']);
- } else {
- $ip = '';
- }
- csrf_start();
-
- // These are "strong" algorithms that don't require per se a secret
- if (session_id()) return 'sid:' . csrf_hash(session_id()) . $ip;
- if ($GLOBALS['csrf']['cookie']) {
- $val = csrf_generate_secret();
- setcookie($GLOBALS['csrf']['cookie'], $val);
- return 'cookie:' . csrf_hash($val) . $ip;
- }
- if ($GLOBALS['csrf']['key']) return 'key:' . csrf_hash($GLOBALS['csrf']['key']) . $ip;
- // These further algorithms require a server-side secret
- if ($secret === '') return 'invalid';
- if ($GLOBALS['csrf']['user'] !== false) {
- return 'user:' . csrf_hash($GLOBALS['csrf']['user']);
- }
- if ($GLOBALS['csrf']['allow-ip']) {
- return ltrim($ip, ';');
- }
- return 'invalid';
-}
-
-/**
- * @param $tokens is safe for HTML consumption
- */
-function csrf_callback($tokens) {
- header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
- echo "<html><head><title>CSRF check failed</title></head><body>CSRF check failed. Either your session has expired, this page has been inactive too long, or you need to enable cookies.<br />Debug: ".$tokens."</body></html>
-";
-}
-
-/**
- * Checks if a composite token is valid. Outward facing code should use this
- * instead of csrf_check_token()
- */
-function csrf_check_tokens($tokens) {
- if (is_string($tokens)) $tokens = explode(';', $tokens);
- foreach ($tokens as $token) {
- if (csrf_check_token($token)) return true;
- }
- return false;
-}
-
-/**
- * Checks if a token is valid.
- */
-function csrf_check_token($token) {
- if (strpos($token, ':') === false) return false;
- list($type, $value) = explode(':', $token, 2);
- if (strpos($value, ',') === false) return false;
- list($x, $time) = explode(',', $token, 2);
- if ($GLOBALS['csrf']['expires']) {
- if (time() > $time + $GLOBALS['csrf']['expires']) return false;
- }
- switch ($type) {
- case 'sid':
- return $value === csrf_hash(session_id(), $time);
- case 'cookie':
- $n = $GLOBALS['csrf']['cookie'];
- if (!$n) return false;
- if (!isset($_COOKIE[$n])) return false;
- return $value === csrf_hash($_COOKIE[$n], $time);
- case 'key':
- if (!$GLOBALS['csrf']['key']) return false;
- return $value === csrf_hash($GLOBALS['csrf']['key'], $time);
- // We could disable these 'weaker' checks if 'key' was set, but
- // that doesn't make me feel good then about the cookie-based
- // implementation.
- case 'user':
- if ($GLOBALS['csrf']['secret'] === '') return false;
- if ($GLOBALS['csrf']['user'] === false) return false;
- return $value === csrf_hash($GLOBALS['csrf']['user'], $time);
- case 'ip':
- if (csrf_get_secret() === '') return false;
- // do not allow IP-based checks if the username is set, or if
- // the browser sent cookies
- if ($GLOBALS['csrf']['user'] !== false) return false;
- if (!empty($_COOKIE)) return false;
- if (!$GLOBALS['csrf']['allow-ip']) return false;
- return $value === csrf_hash($_SERVER['IP_ADDRESS'], $time);
- }
- return false;
-}
-
-/**
- * Sets a configuration value.
- */
-function csrf_conf($key, $val) {
- if (!isset($GLOBALS['csrf'][$key])) {
- trigger_error('No such configuration ' . $key, E_USER_WARNING);
- return;
- }
- $GLOBALS['csrf'][$key] = $val;
-}
-
-/**
- * Starts a session if we're allowed to.
- */
-function csrf_start() {
- if ($GLOBALS['csrf']['auto-session'] && !session_id()) {
- session_start();
- }
-}
-
-/**
- * Retrieves the secret, and generates one if necessary.
- */
-function csrf_get_secret() {
- if ($GLOBALS['csrf']['secret']) return $GLOBALS['csrf']['secret'];
- $dir = dirname(__FILE__);
- $file = $dir . '/csrf-secret.php';
- $secret = '';
- if (file_exists($file)) {
- include $file;
- return $secret;
- }
- if (is_writable($dir)) {
- $secret = csrf_generate_secret();
- $fh = fopen($file, 'w');
- fwrite($fh, '<?php $secret = "'.$secret.'";' . PHP_EOL);
- fclose($fh);
- return $secret;
- }
- return '';
-}
-
-/**
- * Generates a random string as the hash of time, microtime, and mt_rand.
- */
-function csrf_generate_secret($len = 32) {
- $secret = '';
- for ($i = 0; $i < 32; $i++) {
- $secret .= chr(mt_rand(0, 255));
- }
- $secret .= time() . microtime();
- return sha1($secret);
-}
-
-/**
- * Generates a hash/expiry double. If time isn't set it will be calculated
- * from the current time.
- */
-function csrf_hash($value, $time = null) {
- if (!$time) $time = time();
- return sha1($secret . $value . $time) . ',' . $time;
-}
-
-// Load user configuration
-if (function_exists('csrf_startup')) csrf_startup();
-// Initialize our handler
-if ($GLOBALS['csrf']['rewrite']) ob_start('csrf_ob_handler');
-// Perform check
-if (!$GLOBALS['csrf']['defer']) csrf_check();
+<?php
+
+/**
+ * @file
+ *
+ * csrf-magic is a PHP library that makes adding CSRF-protection to your
+ * web applications a snap. No need to modify every form or create a database
+ * of valid nonces; just include this file at the top of every
+ * web-accessible page (or even better, your common include file included
+ * in every page), and forget about it! (There are, of course, configuration
+ * options for advanced users).
+ *
+ * This library is PHP4 and PHP5 compatible.
+ */
+
+// CONFIGURATION:
+
+/**
+ * By default, when you include this file csrf-magic will automatically check
+ * and exit if the CSRF token is invalid. This will defer executing
+ * csrf_check() until you're ready. You can also pass false as a parameter to
+ * that function, in which case the function will not exit but instead return
+ * a boolean false if the CSRF check failed. This allows for tighter integration
+ * with your system.
+ */
+$GLOBALS['csrf']['defer'] = false;
+
+/**
+ * This is the amount of seconds you wish to allow before any token becomes
+ * invalid; the default is two hours, which should be more than enough for
+ * most websites.
+ */
+$GLOBALS['csrf']['expires'] = 7200;
+
+/**
+ * Callback function to execute when there's the CSRF check fails and
+ * $fatal == true (see csrf_check). This will usually output an error message
+ * about the failure.
+ */
+$GLOBALS['csrf']['callback'] = 'csrf_callback';
+
+/**
+ * Whether or not to include our JavaScript library which also rewrites
+ * AJAX requests on this domain. Set this to the web path. This setting only works
+ * with supported JavaScript libraries in Internet Explorer; see README.txt for
+ * a list of supported libraries.
+ */
+$GLOBALS['csrf']['rewrite-js'] = false;
+
+/**
+ * A secret key used when hashing items. Please generate a random string and
+ * place it here. If you change this value, all previously generated tokens
+ * will become invalid.
+ */
+$GLOBALS['csrf']['secret'] = '';
+
+/**
+ * Set this to false to disable csrf-magic's output handler, and therefore,
+ * its rewriting capabilities. If you're serving non HTML content, you should
+ * definitely set this false.
+ */
+$GLOBALS['csrf']['rewrite'] = true;
+
+/**
+ * Whether or not to use IP addresses when binding a user to a token. This is
+ * less reliable and less secure than sessions, but is useful when you need
+ * to give facilities to anonymous users and do not wish to maintain a database
+ * of valid keys.
+ */
+$GLOBALS['csrf']['allow-ip'] = true;
+
+/**
+ * If this information is available, use the cookie by this name to determine
+ * whether or not to allow the request. This is a shortcut implementation
+ * very similar to 'key', but we randomly set the cookie ourselves.
+ */
+$GLOBALS['csrf']['cookie'] = '__csrf_cookie';
+
+/**
+ * If this information is available, set this to a unique identifier (it
+ * can be an integer or a unique username) for the current "user" of this
+ * application. The token will then be globally valid for all of that user's
+ * operations, but no one else. This requires that 'secret' be set.
+ */
+$GLOBALS['csrf']['user'] = false;
+
+/**
+ * This is an arbitrary secret value associated with the user's session. This
+ * will most probably be the contents of a cookie, as an attacker cannot easily
+ * determine this information. Warning: If the attacker knows this value, they
+ * can easily spoof a token. This is a generic implementation; sessions should
+ * work in most cases.
+ *
+ * Why would you want to use this? Lets suppose you have a squid cache for your
+ * website, and the presence of a session cookie bypasses it. Let's also say
+ * you allow anonymous users to interact with the website; submitting forms
+ * and AJAX. Previously, you didn't have any CSRF protection for anonymous users
+ * and so they never got sessions; you don't want to start using sessions either,
+ * otherwise you'll bypass the Squid cache. Setup a different cookie for CSRF
+ * tokens, and have Squid ignore that cookie for get requests, for anonymous
+ * users. (If you haven't guessed, this scheme was(?) used for MediaWiki).
+ */
+$GLOBALS['csrf']['key'] = false;
+
+/**
+ * The name of the magic CSRF token that will be placed in all forms, i.e.
+ * the contents of <input type="hidden" name="$name" value="CSRF-TOKEN" />
+ */
+$GLOBALS['csrf']['input-name'] = '__csrf_magic';
+
+/**
+ * Set this to false if your site must work inside of frame/iframe elements,
+ * but do so at your own risk: this configuration protects you against CSS
+ * overlay attacks that defeat tokens.
+ */
+$GLOBALS['csrf']['frame-breaker'] = true;
+
+/**
+ * Whether or not CSRF Magic should be allowed to start a new session in order
+ * to determine the key.
+ */
+$GLOBALS['csrf']['auto-session'] = true;
+
+/**
+ * Whether or not csrf-magic should produce XHTML style tags.
+ */
+$GLOBALS['csrf']['xhtml'] = true;
+
+// FUNCTIONS:
+
+// Don't edit this!
+$GLOBALS['csrf']['version'] = '1.0.1';
+
+/**
+ * Rewrites <form> on the fly to add CSRF tokens to them. This can also
+ * inject our JavaScript library.
+ */
+function csrf_ob_handler($buffer, $flags) {
+ // Even though the user told us to rewrite, we should do a quick heuristic
+ // to check if the page is *actually* HTML. We don't begin rewriting until
+ // we hit the first <html tag.
+ static $is_html = false;
+ if (!$is_html) {
+ // not HTML until proven otherwise
+ if (stripos($buffer, '<html') !== false) {
+ $is_html = true;
+ } else {
+ return $buffer;
+ }
+ }
+ $tokens = csrf_get_tokens();
+ $name = $GLOBALS['csrf']['input-name'];
+ $endslash = $GLOBALS['csrf']['xhtml'] ? ' /' : '';
+ $input = "<input type='hidden' name='$name' value=\"$tokens\"$endslash>";
+ $buffer = preg_replace('#(<form[^>]*method\s*=\s*["\']post["\'][^>]*>)#i', '$1' . $input, $buffer);
+ if ($GLOBALS['csrf']['frame-breaker']) {
+ $buffer = str_ireplace('</head>', '<script type="text/javascript">if (top != self) {top.location.href = self.location.href;}</script></head>', $buffer);
+ }
+ if ($js = $GLOBALS['csrf']['rewrite-js']) {
+ $buffer = str_ireplace(
+ '</head>',
+ '<script type="text/javascript">'.
+ 'var csrfMagicToken = "'.$tokens.'";'.
+ 'var csrfMagicName = "'.$name.'";</script>'.
+ '<script src="'.$js.'" type="text/javascript"></script></head>',
+ $buffer
+ );
+ $script = '<script type="text/javascript">CsrfMagic.end();</script>';
+ $buffer = str_ireplace('</body>', $script . '</body>', $buffer, $count);
+ if (!$count) {
+ $buffer .= $script;
+ }
+ }
+ return $buffer;
+}
+
+/**
+ * Checks if this is a post request, and if it is, checks if the nonce is valid.
+ * @param bool $fatal Whether or not to fatally error out if there is a problem.
+ * @return True if check passes or is not necessary, false if failure.
+ */
+function csrf_check($fatal = true) {
+ if ($_SERVER['REQUEST_METHOD'] !== 'POST') return true;
+ csrf_start();
+ $name = $GLOBALS['csrf']['input-name'];
+ $ok = false;
+ $tokens = '';
+ do {
+ if (!isset($_POST[$name])) break;
+ // we don't regenerate a token and check it because some token creation
+ // schemes are volatile.
+ $tokens = $_POST[$name];
+ if (!csrf_check_tokens($tokens)) break;
+ $ok = true;
+ } while (false);
+ if ($fatal && !$ok) {
+ $callback = $GLOBALS['csrf']['callback'];
+ if (trim($tokens, 'A..Za..z0..9:;,') !== '') $tokens = 'hidden';
+ $callback($tokens);
+ exit;
+ }
+ return $ok;
+}
+
+/**
+ * Retrieves a valid token(s) for a particular context. Tokens are separated
+ * by semicolons.
+ */
+function csrf_get_tokens() {
+ $has_cookies = !empty($_COOKIE);
+
+ // $ip implements a composite key, which is sent if the user hasn't sent
+ // any cookies. It may or may not be used, depending on whether or not
+ // the cookies "stick"
+ if (!$has_cookies && $secret) {
+ // :TODO: Harden this against proxy-spoofing attacks
+ $ip = ';ip:' . csrf_hash($_SERVER['IP_ADDRESS']);
+ } else {
+ $ip = '';
+ }
+ csrf_start();
+
+ // These are "strong" algorithms that don't require per se a secret
+ if (session_id()) return 'sid:' . csrf_hash(session_id()) . $ip;
+ if ($GLOBALS['csrf']['cookie']) {
+ $val = csrf_generate_secret();
+ setcookie($GLOBALS['csrf']['cookie'], $val);
+ return 'cookie:' . csrf_hash($val) . $ip;
+ }
+ if ($GLOBALS['csrf']['key']) return 'key:' . csrf_hash($GLOBALS['csrf']['key']) . $ip;
+ // These further algorithms require a server-side secret
+ if ($secret === '') return 'invalid';
+ if ($GLOBALS['csrf']['user'] !== false) {
+ return 'user:' . csrf_hash($GLOBALS['csrf']['user']);
+ }
+ if ($GLOBALS['csrf']['allow-ip']) {
+ return ltrim($ip, ';');
+ }
+ return 'invalid';
+}
+
+/**
+ * @param $tokens is safe for HTML consumption
+ */
+function csrf_callback($tokens) {
+ header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
+ echo "<html><head><title>CSRF check failed</title></head><body>CSRF check failed. Either your session has expired, this page has been inactive too long, or you need to enable cookies.<br />Debug: ".$tokens."</body></html>
+";
+}
+
+/**
+ * Checks if a composite token is valid. Outward facing code should use this
+ * instead of csrf_check_token()
+ */
+function csrf_check_tokens($tokens) {
+ if (is_string($tokens)) $tokens = explode(';', $tokens);
+ foreach ($tokens as $token) {
+ if (csrf_check_token($token)) return true;
+ }
+ return false;
+}
+
+/**
+ * Checks if a token is valid.
+ */
+function csrf_check_token($token) {
+ if (strpos($token, ':') === false) return false;
+ list($type, $value) = explode(':', $token, 2);
+ if (strpos($value, ',') === false) return false;
+ list($x, $time) = explode(',', $token, 2);
+ if ($GLOBALS['csrf']['expires']) {
+ if (time() > $time + $GLOBALS['csrf']['expires']) return false;
+ }
+ switch ($type) {
+ case 'sid':
+ return $value === csrf_hash(session_id(), $time);
+ case 'cookie':
+ $n = $GLOBALS['csrf']['cookie'];
+ if (!$n) return false;
+ if (!isset($_COOKIE[$n])) return false;
+ return $value === csrf_hash($_COOKIE[$n], $time);
+ case 'key':
+ if (!$GLOBALS['csrf']['key']) return false;
+ return $value === csrf_hash($GLOBALS['csrf']['key'], $time);
+ // We could disable these 'weaker' checks if 'key' was set, but
+ // that doesn't make me feel good then about the cookie-based
+ // implementation.
+ case 'user':
+ if ($GLOBALS['csrf']['secret'] === '') return false;
+ if ($GLOBALS['csrf']['user'] === false) return false;
+ return $value === csrf_hash($GLOBALS['csrf']['user'], $time);
+ case 'ip':
+ if (csrf_get_secret() === '') return false;
+ // do not allow IP-based checks if the username is set, or if
+ // the browser sent cookies
+ if ($GLOBALS['csrf']['user'] !== false) return false;
+ if (!empty($_COOKIE)) return false;
+ if (!$GLOBALS['csrf']['allow-ip']) return false;
+ return $value === csrf_hash($_SERVER['IP_ADDRESS'], $time);
+ }
+ return false;
+}
+
+/**
+ * Sets a configuration value.
+ */
+function csrf_conf($key, $val) {
+ if (!isset($GLOBALS['csrf'][$key])) {
+ trigger_error('No such configuration ' . $key, E_USER_WARNING);
+ return;
+ }
+ $GLOBALS['csrf'][$key] = $val;
+}
+
+/**
+ * Starts a session if we're allowed to.
+ */
+function csrf_start() {
+ if ($GLOBALS['csrf']['auto-session'] && !session_id()) {
+ session_start();
+ }
+}
+
+/**
+ * Retrieves the secret, and generates one if necessary.
+ */
+function csrf_get_secret() {
+ if ($GLOBALS['csrf']['secret']) return $GLOBALS['csrf']['secret'];
+ $dir = dirname(__FILE__);
+ $file = $dir . '/csrf-secret.php';
+ $secret = '';
+ if (file_exists($file)) {
+ include $file;
+ return $secret;
+ }
+ if (is_writable($dir)) {
+ $secret = csrf_generate_secret();
+ $fh = fopen($file, 'w');
+ fwrite($fh, '<?php $secret = "'.$secret.'";' . PHP_EOL);
+ fclose($fh);
+ return $secret;
+ }
+ return '';
+}
+
+/**
+ * Generates a random string as the hash of time, microtime, and mt_rand.
+ */
+function csrf_generate_secret($len = 32) {
+ $secret = '';
+ for ($i = 0; $i < 32; $i++) {
+ $secret .= chr(mt_rand(0, 255));
+ }
+ $secret .= time() . microtime();
+ return sha1($secret);
+}
+
+/**
+ * Generates a hash/expiry double. If time isn't set it will be calculated
+ * from the current time.
+ */
+function csrf_hash($value, $time = null) {
+ if (!$time) $time = time();
+ return sha1($secret . $value . $time) . ',' . $time;
+}
+
+// Load user configuration
+if (function_exists('csrf_startup')) csrf_startup();
+// Initialize our handler
+if ($GLOBALS['csrf']['rewrite']) ob_start('csrf_ob_handler');
+// Perform check
+if (!$GLOBALS['csrf']['defer']) csrf_check();
diff --git a/usr/local/www/diag_logs_ppp.php b/usr/local/www/diag_logs_ppp.php
index 9609132..c58b589 100755
--- a/usr/local/www/diag_logs_ppp.php
+++ b/usr/local/www/diag_logs_ppp.php
@@ -87,7 +87,7 @@ include("head.inc");
<div id="mainarea">
<table class="tabcont" width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
- <td colspan="2" class="listtopic"><?php printf (gettext("Last $nentries PPP log entries"),$nentries);?></td>
+ <td colspan="2" class="listtopic"><?php printf(gettext("Last %s PPP log entries"),$nentries);?></td>
</tr>
<?php
foreach($ppp_logarr as $logent){
diff --git a/usr/local/www/firewall_aliases.php b/usr/local/www/firewall_aliases.php
index 575240c..03d0539 100755
--- a/usr/local/www/firewall_aliases.php
+++ b/usr/local/www/firewall_aliases.php
@@ -159,7 +159,7 @@ include("head.inc");
<?php if (is_subsystem_dirty('aliases')): ?><p>
<?php print_info_box_np(gettext("The alias list has been changed.") . "<br>" . gettext("You must apply the changes in order for them to take effect."));?>
<?php endif; ?>
-
+<?php pfSense_handle_custom_code("/usr/local/pkg/firewall_aliases/pre_table"); ?>
<table width="100%" border="0" cellpadding="0" cellspacing="0" class="tabcont">
<tr>
<td width="25%" class="listhdrr"><?=gettext("Name"); ?></td>
diff --git a/usr/local/www/firewall_aliases_edit.php b/usr/local/www/firewall_aliases_edit.php
index 3d44694..adaa2c7 100755
--- a/usr/local/www/firewall_aliases_edit.php
+++ b/usr/local/www/firewall_aliases_edit.php
@@ -558,6 +558,7 @@ EOD;
rowsize[2] = "50";
</script>
+<?php pfSense_handle_custom_code("/usr/local/pkg/firewall_aliases_edit/pre_input_errors"); ?>
<?php if ($input_errors) print_input_errors($input_errors); ?>
<div id="inputerrors"></div>
diff --git a/usr/local/www/firewall_nat.php b/usr/local/www/firewall_nat.php
index ac67291..d2a9caa 100755
--- a/usr/local/www/firewall_nat.php
+++ b/usr/local/www/firewall_nat.php
@@ -70,6 +70,8 @@ if ($_POST) {
$retval |= filter_configure();
$savemsg = get_std_save_message($retval);
+ pfSense_handle_custom_code("/usr/local/pkg/firewall_nat/apply");
+
if ($retval == 0) {
clear_subsystem_dirty('natconf');
clear_subsystem_dirty('filter');
diff --git a/usr/local/www/firewall_nat_edit.php b/usr/local/www/firewall_nat_edit.php
index 5aa069c..95286eb 100755
--- a/usr/local/www/firewall_nat_edit.php
+++ b/usr/local/www/firewall_nat_edit.php
@@ -439,8 +439,11 @@ $pgtitle = array(gettext("Firewall"),gettext("NAT"),gettext("Port Forward"),gett
include("head.inc");
?>
+<link rel="stylesheet" href="/javascript/chosen/chosen.css" />
+</head>
<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+<script src="/javascript/chosen/chosen.proto.js" type="text/javascript"></script>
<?php
include("fbegin.inc"); ?>
<?php if ($input_errors) print_input_errors($input_errors); ?>
@@ -476,6 +479,8 @@ include("fbegin.inc"); ?>
<?php
$iflist = get_configured_interface_with_descr(false, true);
+ // Allow extending of the firewall edit interfaces
+ pfSense_handle_custom_code("/usr/local/pkg/firewall_nat/pre_interfaces_edit");
foreach ($iflist as $if => $ifdesc)
if(have_ruleint_access($if))
$interfaces[$if] = $ifdesc;
diff --git a/usr/local/www/firewall_rules.php b/usr/local/www/firewall_rules.php
index 1aaea16..da9abd1 100755
--- a/usr/local/www/firewall_rules.php
+++ b/usr/local/www/firewall_rules.php
@@ -177,6 +177,8 @@ if (isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enabl
if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"])
$iflist["openvpn"] = "OpenVPN";
+pfSense_handle_custom_code("/usr/local/pkg/firewall_rules/interfaces_override");
+
if (!$if || !isset($iflist[$if])) {
if ("any" == $if)
$if = "FloatingRules";
@@ -194,6 +196,8 @@ if ($_POST) {
clear_subsystem_dirty('filter');
+ pfSense_handle_custom_code("/usr/local/pkg/firewall_rules/apply");
+
$savemsg = sprintf(gettext("The settings have been applied. The firewall rules are now reloading in the background.<br/>You can also %s monitor %s the reload progress"),"<a href='status_filter_reload.php'>","</a>");
}
}
@@ -292,9 +296,11 @@ echo "<script type=\"text/javascript\" language=\"javascript\" src=\"/javascript
echo "<script type=\"text/javascript\" language=\"javascript\" src=\"/javascript/domTT/behaviour.js\"></script>";
echo "<script type=\"text/javascript\" language=\"javascript\" src=\"/javascript/domTT/fadomatic.js\"></script>";
?>
+<link rel="stylesheet" href="/javascript/chosen/chosen.css" />
</head>
<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+<script src="/javascript/chosen/chosen.proto.js" type="text/javascript"></script>
<?php include("fbegin.inc"); ?>
<form action="firewall_rules.php" method="post">
@@ -317,6 +323,9 @@ if($_REQUEST['undodrag']) {
<img src="/themes/<?=$g['theme']?>/images/misc/loader.gif"> Loading, please wait...
<p/>&nbsp;
</div>
+<?php
+ pfSense_handle_custom_code("/usr/local/pkg/firewall_rules/before_table");
+?>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><td class="tabnavtbl">
<?php
@@ -340,21 +349,30 @@ if($_REQUEST['undodrag']) {
<tr>
<td>
<div id="mainarea">
- <table class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0">
- <tr id="frheader">
- <td width="3%" class="list">&nbsp;</td>
- <td width="5%" class="list">&nbsp;</td>
- <td width="3%" class="listhdrr"><?=gettext("ID");?></td>
- <td width="6%" class="listhdrr"><?=gettext("Proto");?></td>
- <td width="12%" class="listhdrr"><?=gettext("Source");?></td>
- <td width="6%" class="listhdrr"><?=gettext("Port");?></td>
- <td width="12%" class="listhdrr"><?=gettext("Destination");?></td>
- <td width="6%" class="listhdrr"><?=gettext("Port");?></td>
- <td width="5%" class="listhdrr"><?=gettext("Gateway");?></td>
- <td width="8%" class="listhdrr"><?=gettext("Queue");?></td>
- <td width="5%" class="listhdrr"><?=gettext("Schedule");?></td>
- <td width="19%" class="listhdr"><?=gettext("Description");?></td>
- <td width="10%" class="list">
+ <table class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0">
+<?php
+ pfSense_handle_custom_code("/usr/local/pkg/firewall_rules/before_first_tr");
+?>
+ <tr id="frheader">
+ <td width="3%" class="list">&nbsp;</td>
+ <td width="5%" class="list">&nbsp;</td>
+ <td width="3%" class="listhdrr"><?=gettext("ID");?></td>
+<?php
+ pfSense_handle_custom_code("/usr/local/pkg/firewall_rules/pre_id_tablehead");
+?>
+ <td width="6%" class="listhdrr"><?=gettext("Proto");?></td>
+ <td width="12%" class="listhdrr"><?=gettext("Source");?></td>
+ <td width="6%" class="listhdrr"><?=gettext("Port");?></td>
+ <td width="12%" class="listhdrr"><?=gettext("Destination");?></td>
+ <td width="6%" class="listhdrr"><?=gettext("Port");?></td>
+ <td width="5%" class="listhdrr"><?=gettext("Gateway");?></td>
+ <td width="8%" class="listhdrr"><?=gettext("Queue");?></td>
+ <td width="5%" class="listhdrr"><?=gettext("Schedule");?></td>
+<?php
+ pfSense_handle_custom_code("/usr/local/pkg/firewall_rules/pre_desc_tablehead");
+?>
+ <td width="19%" class="listhdr"><?=gettext("Description");?></td>
+ <td width="10%" class="list">
<table border="0" cellspacing="0" cellpadding="1">
<tr>
<?php
@@ -401,6 +419,9 @@ if($_REQUEST['undodrag']) {
<td class="list">&nbsp;</td>
<td class="listt" align="center"><img src="./themes/<?= $g['theme']; ?>/images/icons/icon_pass.gif" width="11" height="11" border="0"></td>
<td class="listlr" style="background-color: #E0E0E0"></td>
+<?php
+ pfSense_handle_custom_code("/usr/local/pkg/firewall_rules/pre_id_tr_antilockout");
+?>
<td class="listr" style="background-color: #E0E0E0">*</td>
<td class="listr" style="background-color: #E0E0E0">*</td>
<td class="listr" style="background-color: #E0E0E0">*</td>
@@ -483,6 +504,7 @@ if($_REQUEST['undodrag']) {
<?php endif; ?>
<tbody id="dragtable" width="100%">
<?php $nrules = 0; for ($i = 0; isset($a_filter[$i]); $i++):
+ pfSense_handle_custom_code("/usr/local/pkg/firewall_rules/row_start");
$filterent = $a_filter[$i];
if ($filterent['interface'] != $if && !isset($filterent['floating']))
continue;
@@ -492,7 +514,7 @@ if($_REQUEST['undodrag']) {
if($isadvset)
$advanced_set = "<img src=\"./themes/{$g['theme']}/images/icons/icon_advanced.gif\" title=\"" . gettext("advanced settings set") . ": {$isadvset}\" border=\"0\">";
else
- $advanced_set = ""
+ $advanced_set = "";
?>
<tr valign="top" id="fr<?=$nrules;?>">
<td class="listt">
@@ -685,6 +707,9 @@ if($_REQUEST['undodrag']) {
<td class="listlr" onClick="fr_toggle(<?=$nrules;?>)" id="frd<?=$nrules;?>" ondblclick="document.location='firewall_rules_edit.php?id=<?=$i;?>';">
<?=$textss;?><?php if (isset($filterent['id'])) echo $filterent['id']; else echo ""; ?><?=$textse;?>
</td>
+<?php
+ pfSense_handle_custom_code("/usr/local/pkg/firewall_rules/pre_id_tr");
+?>
<td class="listr" onClick="fr_toggle(<?=$nrules;?>)" id="frd<?=$nrules;?>" ondblclick="document.location='firewall_rules_edit.php?id=<?=$i;?>';">
<?=$textss;?><?php
if (isset($filterent['ipprotocol'])) {
@@ -740,6 +765,9 @@ if($_REQUEST['undodrag']) {
<td class="listr" onClick="fr_toggle(<?=$nrules;?>)" id="frd<?=$nrules;?>" ondblclick="document.location='firewall_rules_edit.php?id=<?=$i;?>';"><font color="black">
<?php if ($printicon) { ?><img src="./themes/<?= $g['theme']; ?>/images/icons/<?php echo $image; ?>.gif" title="<?php echo $alttext;?>" border="0"><?php } ?>&nbsp;<?=$textss;?><?php echo $schedule_span_begin;?><?=htmlspecialchars($filterent['sched']);?><?php echo $schedule_span_end; ?><?=$textse;?>
</td>
+<?php
+ pfSense_handle_custom_code("/usr/local/pkg/firewall_rules/pre_descr_tr");
+?>
<td class="listbg" onClick="fr_toggle(<?=$nrules;?>)" ondblclick="document.location='firewall_rules_edit.php?id=<?=$i;?>';" class="descr">
<?=$textss;?><?=htmlspecialchars($filterent['descr']);?>&nbsp;<?=$textse;?>
</td>
@@ -771,6 +799,9 @@ if($_REQUEST['undodrag']) {
<tr id="fr<?=$nrules;?>">
<td class="list"></td>
<td class="list"></td>
+<?php
+ pfSense_handle_custom_code("/usr/local/pkg/firewall_rules/pre_id_tr_belowtable");
+?>
<td class="list">&nbsp;</td>
<td class="list">&nbsp;</td>
<td class="list">&nbsp;</td>
diff --git a/usr/local/www/firewall_rules_edit.php b/usr/local/www/firewall_rules_edit.php
index 0e61806..8857d8d 100755
--- a/usr/local/www/firewall_rules_edit.php
+++ b/usr/local/www/firewall_rules_edit.php
@@ -603,11 +603,13 @@ $page_filename = "firewall_rules_edit.php";
include("head.inc");
?>
-
+<link rel="stylesheet" href="/javascript/chosen/chosen.css" />
</head>
<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+<script src="/javascript/chosen/chosen.proto.js" type="text/javascript"></script>
<?php include("fbegin.inc"); ?>
+<?php pfSense_handle_custom_code("/usr/local/pkg/firewall_rules/pre_input_errors"); ?>
<?php if ($input_errors) print_input_errors($input_errors); ?>
<form action="firewall_rules_edit.php" method="post" name="iform" id="iform">
@@ -693,7 +695,7 @@ include("head.inc");
<td width="22%" valign="top" class="vncellreq"><?=gettext("Interface");?></td>
<td width="78%" class="vtable">
<?php if ($if == "FloatingRules" || isset($pconfig['floating'])): ?>
- <select name="interface[]" multiple="true" class="formselect" size="3" <?=$edit_disabled;?>>
+ <select name="interface[]" title="Select interfaces..." multiple style="width:350px;" class="chzn-select" tabindex="2" <?=$edit_disabled;?>>
<?php else: ?>
<select name="interface" class="formselect" <?=$edit_disabled;?>>
<?php
diff --git a/usr/local/www/firewall_shaper_vinterface.php b/usr/local/www/firewall_shaper_vinterface.php
index fae5429..b325a30 100644
--- a/usr/local/www/firewall_shaper_vinterface.php
+++ b/usr/local/www/firewall_shaper_vinterface.php
@@ -111,7 +111,7 @@ if ($_GET) {
}
$output_form .= $queue->build_form();
} else {
- $input_errors[] = gettext("No queue with name {$qname} was found!");
+ $input_errors[] = sprintf(gettext("No queue with name %s was found!"),$qname);
$output_form .= "<p class=\"pgtitle\">" . $dn_default_shaper_msg."</p>";
$dontshow = true;
}
diff --git a/usr/local/www/guiconfig.inc b/usr/local/www/guiconfig.inc
index 63fadab..6b579db 100755
--- a/usr/local/www/guiconfig.inc
+++ b/usr/local/www/guiconfig.inc
@@ -914,7 +914,7 @@ function display_top_tabs(& $tab_array, $no_drop_down = false) {
}
if ($tab_array_char_limit == '') {
- $tab_array_char_limit = 82;
+ $tab_array_char_limit = 92;
}
$tab_temp = array ();
diff --git a/usr/local/www/index.php b/usr/local/www/index.php
index 2b9be16..1638196 100755
--- a/usr/local/www/index.php
+++ b/usr/local/www/index.php
@@ -475,6 +475,8 @@ echo $jscriptstr;
if ($savemsg)
print_info_box($savemsg);
+pfSense_handle_custom_code("/usr/local/pkg/dashboard/pre_dashboard");
+
?>
<div id="widgetcontainer" style="display:none">
<div id="content1"><h1><?=gettext("Available Widgets"); ?></h1><p><?php
diff --git a/usr/local/www/interfaces.php b/usr/local/www/interfaces.php
index 66aed5b..a62fee5 100755
--- a/usr/local/www/interfaces.php
+++ b/usr/local/www/interfaces.php
@@ -451,9 +451,9 @@ if ($_POST['apply']) {
}
case "dhcp":
if (in_array($wancfg['ipaddr'], array("ppp", "pppoe", "pptp", "l2tp")))
- $input_errors[] = gettext("You have to reassign the interface to be able to configure as {$_POST['type']}.");
+ $input_errors[] = sprintf(gettext("You have to reassign the interface to be able to configure as %s."),$_POST['type']);
if (in_array($wancfg['ipaddrv6'], array("ppp", "pppoe", "pptp", "l2tp")))
- $input_errors[] = gettext("You have to reassign the interface to be able to configure as {$_POST['type']}.");
+ $input_errors[] = sprintf(gettext("You have to reassign the interface to be able to configure as %s."),$_POST['type']);
break;
case "ppp":
$reqdfields = explode(" ", "port phone");
@@ -657,7 +657,7 @@ if ($_POST['apply']) {
}
if($skip == false) {
$gateway_item['gateway'] = "dynamic";
- $gateway_item['descr'] = gettext("Interface") . $if . gettext("dynamic gateway");
+ $gateway_item['descr'] = sprintf(gettext("Interface %s dynamic gateway"),$if);
$gateway_item['name'] = "GW_" . strtoupper($if);
$gateway_item['interface'] = "{$if}";
} else {
@@ -1617,7 +1617,7 @@ $types = array("none" => gettext("None"), "staticv4" => gettext("Static IPv4"),
<?php if(is_readable("/var/db/dhcp6c_duid")) {
// $current_duid = file_get_contents("/var/db/dhcp6c_duid");
}
- echo gettext("The current DUID is: '") . $current_duid ."'";
+ printf(gettext("The current DUID is: '%s'"),$current_duid);
?>
</td>
diff --git a/usr/local/www/interfaces_assign.php b/usr/local/www/interfaces_assign.php
index cf0203c..230ce1a 100755
--- a/usr/local/www/interfaces_assign.php
+++ b/usr/local/www/interfaces_assign.php
@@ -392,6 +392,7 @@ if(file_exists("/var/run/interface_mismatch_reboot_needed"))
<?php print_info_box($savemsg); ?>
<?php endif; ?>
+<?php pfSense_handle_custom_code("/usr/local/pkg/interfaces_assign/pre_input_errors"); ?>
<?php if ($input_errors) print_input_errors($input_errors); ?>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
diff --git a/usr/local/www/interfaces_groups.php b/usr/local/www/interfaces_groups.php
index df628c8..00bc613 100755
--- a/usr/local/www/interfaces_groups.php
+++ b/usr/local/www/interfaces_groups.php
@@ -47,7 +47,7 @@ $a_ifgroups = &$config['ifgroups']['ifgroupentry'];
if ($_GET['act'] == "del") {
if ($a_ifgroups[$_GET['id']]) {
- $members = explode(" ", $a_ifgroups[$_GET[$id]]);
+ $members = explode(" ", $a_ifgroups[$_GET[$id]]['members']);
foreach ($members as $ifs) {
$realif = get_real_interface($ifs);
if ($realif)
diff --git a/usr/local/www/javascript/chosen/chosen-sprite.png b/usr/local/www/javascript/chosen/chosen-sprite.png
new file mode 100644
index 0000000..6ec9bbf
--- /dev/null
+++ b/usr/local/www/javascript/chosen/chosen-sprite.png
Binary files differ
diff --git a/usr/local/www/javascript/chosen/chosen.css b/usr/local/www/javascript/chosen/chosen.css
new file mode 100644
index 0000000..d2b1eb4
--- /dev/null
+++ b/usr/local/www/javascript/chosen/chosen.css
@@ -0,0 +1,317 @@
+div.chzn-container {
+ font-size: 13px;
+ position: relative;
+}
+
+div.chzn-container input {
+ background: #fff;
+ background: -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee));
+ background: -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%);
+ background: -o-linear-gradient(bottom, white 85%, #eeeeee 99%);
+ border: 1px solid #aaa;
+ font-family: sans-serif;
+ font-size: 1em;
+ margin: 0px;
+ padding: 4px 5px;
+ outline: none;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ -o-border-radius: 3px;
+ -ms-border-radius: 3px;
+ -khtml-border-radius: 3px;
+ border-radius: 3px;
+}
+div.chzn-container textarea:focus {
+ border-color: #058cf5;
+ -moz-box-shadow: 0px 0px 3px #aaa;
+ -webkit-box-shadow: 0px 0px 3px #aaa;
+ box-shadow: 0px 0px 3px #aaa;
+}
+
+
+div.chzn-container div.chzn-drop {
+ background: #FFF;
+ border: 1px solid #aaa;
+ border-width: 0 1px 1px;
+ left: 0;
+ position: absolute;
+ top: 29px;
+ -webkit-box-shadow: 0px 4px 5px rgba(0, 0, 0, 0.15);
+ -moz-box-shadow: 0px 4px 5px rgba(0, 0, 0, 0.15);
+ box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.15);
+ z-index: 20;
+}
+div.chzn-container-single div.chzn-drop {
+ -moz-border-radius: 0 0 4px 4px;
+ -webkit-border-radius: 0 0 4px 4px;
+ -o-border-radius: 0 0 4px 4px;
+ -ms-border-radius: 0 0 4px 4px;
+ -khtml-border-radius: 0 0 4px 4px;
+ border-radius: 0 0 4px 4px;
+}
+
+
+/* SINGLE */
+div.chzn-container a.chzn-single {
+ background: #FFF;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(0.5, white));
+ background-image: -moz-linear-gradient(center bottom, #eeeeee 0%, white 50%);
+ background-image: -o-linear-gradient(bottom, #eeeeee 0%, white 50%);
+ border: 1px solid #aaa;
+ display: block;
+ overflow: hidden;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -o-border-radius: 4px;
+ -ms-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ border-radius: 4px;
+ height: 25px;
+ color: #444;
+ line-height: 26px;
+ padding: 0px 0px 0px 8px;
+ position: relative;
+ text-decoration: none;
+ z-index: 19;
+ white-space: nowrap;
+}
+div.chzn-container a.chzn-single span {
+ display: block;
+ margin-right: 26px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+div.chzn-container a.chzn-single div {
+ -moz-border-radius-topright: 4px;
+ -webkit-border-top-right-radius: 4px;
+ -o-border-top-right-radius: 4px;
+ -ms-border-top-right-radius: 4px;
+ -khtml-border-top-right-radius: 4px;
+ border-top-right-radius: 4px;
+ -moz-border-radius-bottomright: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ -o-border-bottom-right-radius: 4px;
+ -ms-border-bottom-right-radius: 4px;
+ -khtml-border-bottom-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ background: #ccc;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee));
+ background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%);
+ background-image: -o-linear-gradient(bottom, #ccc 0%, #eee 60%);
+ border-left: 1px solid #aaa;
+ display: block;
+ height: 100%;
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 18px;
+}
+div.chzn-container a.chzn-single div b {
+ background: url('chosen-sprite.png') no-repeat 0 1px;
+ display: block;
+ width: 100%;
+ height: 100%;
+}
+div.chzn-container div.chzn-search {
+ padding: 3px 4px;
+ margin: 0px;
+ white-space: nowrap;
+}
+div.chzn-container div.chzn-search input {
+ background: url('chosen-sprite.png') no-repeat 97% -35px, #ffffff;
+ background: url('chosen-sprite.png') no-repeat 97% -35px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee));
+ background: url('chosen-sprite.png') no-repeat 97% -35px, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%);
+ background: url('chosen-sprite.png') no-repeat 97% -35px, -o-linear-gradient(bottom, white 85%, #eeeeee 99%);
+ -moz-border-radius: 0px;
+ -webkit-border-radius: 0px;
+ -o-border-radius: 0px;
+ -ms-border-radius: 0px;
+ -khtml-border-radius: 0px;
+ border-radius: 0px;
+ margin: 1px 0;
+ outline: 0;
+}
+
+
+/* Multi */
+div.chzn-container ul.chzn-choices {
+ background: #fff;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee));
+ background-image: -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%);
+ background-image: -o-linear-gradient(bottom, white 85%, #eeeeee 99%);
+ margin: 0;
+ cursor: text;
+ border: 1px solid #aaa;
+ overflow: hidden;
+ height: auto !important;
+ height: 1%;
+ padding: 0;
+ position: relative;
+}
+div.chzn-container ul.chzn-choices:focus {
+ border-color: #058cf5;
+ -moz-box-shadow: 0px 0px 5px #999;
+ -webkit-box-shadow: 0px 0px 5px #999;
+ box-shadow: 0px 0px 5px #999;
+}
+div.chzn-container ul.chzn-choices li {
+ float: left;
+ list-style-type: none;
+ margin: 0px;
+}
+div.chzn-container ul.chzn-choices li.search-field {
+ margin: 0px;
+ white-space: nowrap;
+ padding: 0px;
+}
+div.chzn-container ul.chzn-choices li.search-field input {
+ color: #666;
+ background: transparent !important;
+ border: 0px !important;
+ padding: 5px;
+ margin: 1px 0;
+ outline: 0;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+}
+div.chzn-container ul.chzn-choices li.search-field input.default {
+ color: #999;
+}
+div.chzn-container ul.chzn-choices li.search-choice {
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ background: #e4e4e4;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #e4e4e4), color-stop(0.7, #eeeeee));
+ background-image: -moz-linear-gradient(center bottom, #e4e4e4 0%, #eeeeee 70%);
+ background-image: -o-linear-gradient(bottom, #e4e4e4 0%, #eeeeee 70%);
+ color: #333;
+ border: 1px solid #b4b4b4;
+ line-height: 13px;
+ padding: 3px 19px 3px 6px;
+ position: relative;
+ margin: 3px 0px 3px 5px;
+}
+div.chzn-container ul.chzn-choices li.search-choice span {
+ cursor: default;
+}
+div.chzn-container ul.chzn-choices li.search-choice.search-choice-focus {
+ background: #d4d4d4;
+}
+div.chzn-container ul.chzn-choices li.search-choice a.search-choice-close {
+ position: absolute;
+ right: 5px;
+ top: 6px;
+ display: block;
+ width: 8px;
+ height: 9px;
+ font-size: 1px;
+ background: url(chosen-sprite.png) right top no-repeat;
+}
+div.chzn-container ul.chzn-choices li.search-choice a.search-choice-close:hover {
+ background-position: right -9px;
+}
+div.chzn-container ul.chzn-choices li.search-choice.search-choice-focus a.search-choice-close {
+ background-position: right -9px;
+}
+
+
+/* Results */
+div.chzn-container ul.chzn-results {
+ margin: 0 4px 4px 0;
+ max-height: 190px;
+ padding: 0 0 0 4px;
+ position: relative;
+ overflow-x: hidden;
+ overflow-y: auto;
+ z-index: 20;
+}
+div.chzn-container-multi ul.chzn-results {
+ margin: -1px 0 0;
+ padding: 0;
+}
+div.chzn-container-multi ul.chzn-results li {
+ border-left: 0px !important;
+ border-right: 0px !important;
+}
+div.chzn-container ul.chzn-results li {
+ line-height: 80%;
+ padding: 7px 7px 8px;
+ z-index: 22;
+ margin: 0;
+ list-style-type: none;
+}
+div.chzn-container ul.chzn-results li.active-result {
+ cursor: pointer;
+}
+div.chzn-container ul.chzn-results li em {
+ font-style: normal;
+ background: #FEFFDC;
+}
+div.chzn-container ul.chzn-results li.highlighted {
+ background: #3875d7;
+ color: #fff;
+}
+div.chzn-container ul.chzn-results li.highlighted em {
+ background: transparent;
+}
+div.chzn-container ul.chzn-results li.no-results {
+ background: #F4F4F4;
+}
+div.chzn-container ul.chzn-results li.group-result {
+ cursor: default;
+ color: #999;
+ font-weight: bold;
+}
+div.chzn-container ul.chzn-results li.group-option {
+ padding-left: 20px;
+}
+
+div.chzn-container-multi div.chzn-drop li.result-selected {
+ display: none;
+}
+
+
+
+/* Active */
+div.chzn-container-active a.chzn-single {
+ -webkit-box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
+ box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
+ border: 1px solid #5897fb;
+}
+div.chzn-container-active a.chzn-single-with-drop {
+ border: 1px solid #aaa;
+ border-width: 1px 1px 1px;
+ -moz-box-shadow: 0px 1px 0px #FFF inset;
+ -webkit-box-shadow: 0px 1px 0px #FFF inset;
+ box-shadow: 0px 1px 0px #FFF inset;
+ background: #EEE;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, white), color-stop(0.5, #eeeeee));
+ background-image: -moz-linear-gradient(center bottom, white 0%, #eeeeee 50%);
+ background-image: -o-linear-gradient(bottom, white 0%, #eeeeee 50%);
+ -webkit-border-bottom-left-radius: 0px;
+ -webkit-border-bottom-right-radius: 0px;
+ -moz-border-radius-bottomleft: 0px;
+ -moz-border-radius-bottomright: 0px;
+ border-bottom-left-radius: 0px;
+ border-bottom-right-radius: 0px;
+}
+div.chzn-container-active a.chzn-single-with-drop div {
+ background: transparent;
+ border-left: none;
+}
+div.chzn-container-active a.chzn-single-with-drop div b {
+ background-position: -18px 1px;
+}
+div.chzn-container-active ul.chzn-choices {
+ z-index: 21;
+ -webkit-box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
+ box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
+ border: 1px solid #5897fb;
+}
+div.chzn-container-active ul.chzn-choices input {
+ color: #111 !important;
+}
diff --git a/usr/local/www/javascript/chosen/chosen.jquery.js b/usr/local/www/javascript/chosen/chosen.jquery.js
new file mode 100644
index 0000000..21e822a
--- /dev/null
+++ b/usr/local/www/javascript/chosen/chosen.jquery.js
@@ -0,0 +1,755 @@
+(function() {
+ /*
+ Chosen, a Select Box Enhancer for jQuery and Protoype
+ by Patrick Filler for Harvest, http://getharvest.com
+
+ Available for use under the MIT License, http://en.wikipedia.org/wiki/MIT_License
+
+ Copyright (c) 2011 by Harvest
+ */ var $, Chosen, SelectParser, get_side_border_padding, root;
+ var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
+ root = typeof exports !== "undefined" && exports !== null ? exports : this;
+ $ = jQuery;
+ $.fn.extend({
+ chosen: function(data, options) {
+ return $(this).each(function(input_field) {
+ if (!($(this)).hasClass("chzn-done")) {
+ return new Chosen(this, data, options);
+ }
+ });
+ }
+ });
+ Chosen = (function() {
+ function Chosen(elmn) {
+ this.set_default_values();
+ this.form_field = elmn;
+ this.form_field_jq = $(this.form_field);
+ this.is_multiple = this.form_field.multiple;
+ this.default_text_default = this.form_field.multiple ? "Select Some Options" : "Select an Option";
+ this.set_up_html();
+ this.register_observers();
+ this.form_field_jq.addClass("chzn-done");
+ }
+ Chosen.prototype.set_default_values = function() {
+ this.click_test_action = __bind(function(evt) {
+ return this.test_active_click(evt);
+ }, this);
+ this.active_field = false;
+ this.mouse_on_container = false;
+ this.results_showing = false;
+ this.result_highlighted = null;
+ this.result_single_selected = null;
+ return this.choices = 0;
+ };
+ Chosen.prototype.set_up_html = function() {
+ var container_div, dd_top, dd_width, sf_width;
+ this.container_id = this.form_field.id + "_chzn";
+ this.f_width = this.form_field_jq.width();
+ this.default_text = this.form_field_jq.attr('title') ? this.form_field_jq.attr('title') : this.default_text_default;
+ container_div = $("<div />", {
+ id: this.container_id,
+ "class": 'chzn-container',
+ style: 'width: ' + this.f_width + 'px;'
+ });
+ if (this.is_multiple) {
+ container_div.html('<ul class="chzn-choices"><li class="search-field"><input type="text" value="' + this.default_text + '" class="default" style="width:25px;" /></li></ul><div class="chzn-drop" style="left:-9000px;"><ul class="chzn-results"></ul></div>');
+ } else {
+ container_div.html('<a href="javascript:void(0)" class="chzn-single"><span>' + this.default_text + '</span><div><b></b></div></a><div class="chzn-drop" style="left:-9000px;"><div class="chzn-search"><input type="text" /></div><ul class="chzn-results"></ul></div>');
+ }
+ this.form_field_jq.hide().after(container_div);
+ this.container = $('#' + this.container_id);
+ this.container.addClass("chzn-container-" + (this.is_multiple ? "multi" : "single"));
+ this.dropdown = this.container.find('div.chzn-drop').first();
+ dd_top = this.container.height();
+ dd_width = this.f_width - get_side_border_padding(this.dropdown);
+ this.dropdown.css({
+ "width": dd_width + "px",
+ "top": dd_top + "px"
+ });
+ this.search_field = this.container.find('input').first();
+ this.search_results = this.container.find('ul.chzn-results').first();
+ this.search_field_scale();
+ this.search_no_results = this.container.find('li.no-results').first();
+ if (this.is_multiple) {
+ this.search_choices = this.container.find('ul.chzn-choices').first();
+ this.search_container = this.container.find('li.search-field').first();
+ } else {
+ this.search_container = this.container.find('div.chzn-search').first();
+ this.selected_item = this.container.find('.chzn-single').first();
+ sf_width = dd_width - get_side_border_padding(this.search_container) - get_side_border_padding(this.search_field);
+ this.search_field.css({
+ "width": sf_width + "px"
+ });
+ }
+ this.results_build();
+ return this.set_tab_index();
+ };
+ Chosen.prototype.register_observers = function() {
+ this.container.click(__bind(function(evt) {
+ return this.container_click(evt);
+ }, this));
+ this.container.mouseenter(__bind(function(evt) {
+ return this.mouse_enter(evt);
+ }, this));
+ this.container.mouseleave(__bind(function(evt) {
+ return this.mouse_leave(evt);
+ }, this));
+ this.search_results.click(__bind(function(evt) {
+ return this.search_results_click(evt);
+ }, this));
+ this.search_results.mouseover(__bind(function(evt) {
+ return this.search_results_mouseover(evt);
+ }, this));
+ this.search_results.mouseout(__bind(function(evt) {
+ return this.search_results_mouseout(evt);
+ }, this));
+ this.form_field_jq.bind("liszt:updated", __bind(function(evt) {
+ return this.results_update_field(evt);
+ }, this));
+ this.search_field.blur(__bind(function(evt) {
+ return this.input_blur(evt);
+ }, this));
+ this.search_field.keyup(__bind(function(evt) {
+ return this.keyup_checker(evt);
+ }, this));
+ this.search_field.keydown(__bind(function(evt) {
+ return this.keydown_checker(evt);
+ }, this));
+ if (this.is_multiple) {
+ this.search_choices.click(__bind(function(evt) {
+ return this.choices_click(evt);
+ }, this));
+ return this.search_field.focus(__bind(function(evt) {
+ return this.input_focus(evt);
+ }, this));
+ } else {
+ return this.selected_item.focus(__bind(function(evt) {
+ return this.activate_field(evt);
+ }, this));
+ }
+ };
+ Chosen.prototype.container_click = function(evt) {
+ if (evt && evt.type === "click") {
+ evt.stopPropagation();
+ }
+ if (!this.pending_destroy_click) {
+ if (!this.active_field) {
+ if (this.is_multiple) {
+ this.search_field.val("");
+ }
+ $(document).click(this.click_test_action);
+ this.results_show();
+ } else if (!this.is_multiple && evt && ($(evt.target) === this.selected_item || $(evt.target).parents("a.chzn-single").length)) {
+ evt.preventDefault();
+ this.results_toggle();
+ }
+ return this.activate_field();
+ } else {
+ return this.pending_destroy_click = false;
+ }
+ };
+ Chosen.prototype.mouse_enter = function() {
+ return this.mouse_on_container = true;
+ };
+ Chosen.prototype.mouse_leave = function() {
+ return this.mouse_on_container = false;
+ };
+ Chosen.prototype.input_focus = function(evt) {
+ if (!this.active_field) {
+ return setTimeout((__bind(function() {
+ return this.container_click();
+ }, this)), 50);
+ }
+ };
+ Chosen.prototype.input_blur = function(evt) {
+ if (!this.mouse_on_container) {
+ this.active_field = false;
+ return setTimeout((__bind(function() {
+ return this.blur_test();
+ }, this)), 100);
+ }
+ };
+ Chosen.prototype.blur_test = function(evt) {
+ if (!this.active_field && this.container.hasClass("chzn-container-active")) {
+ return this.close_field();
+ }
+ };
+ Chosen.prototype.close_field = function() {
+ $(document).unbind("click", this.click_test_action);
+ if (!this.is_multiple) {
+ this.selected_item.attr("tabindex", this.search_field.attr("tabindex"));
+ this.search_field.attr("tabindex", -1);
+ }
+ this.active_field = false;
+ this.results_hide();
+ this.container.removeClass("chzn-container-active");
+ this.winnow_results_clear();
+ this.clear_backstroke();
+ this.show_search_field_default();
+ return this.search_field_scale();
+ };
+ Chosen.prototype.activate_field = function() {
+ if (!this.is_multiple && !this.active_field) {
+ this.search_field.attr("tabindex", this.selected_item.attr("tabindex"));
+ this.selected_item.attr("tabindex", -1);
+ }
+ this.container.addClass("chzn-container-active");
+ this.active_field = true;
+ this.search_field.val(this.search_field.val());
+ return this.search_field.focus();
+ };
+ Chosen.prototype.test_active_click = function(evt) {
+ if ($(evt.target).parents('#' + this.container.id).length) {
+ return this.active_field = true;
+ } else {
+ return this.close_field();
+ }
+ };
+ Chosen.prototype.results_build = function() {
+ var content, data, startTime, _i, _len, _ref;
+ startTime = new Date();
+ this.parsing = true;
+ this.results_data = SelectParser.select_to_array(this.form_field);
+ if (this.is_multiple && this.choices > 0) {
+ this.search_choices.find("li.search-choice").remove();
+ this.choices = 0;
+ } else if (!this.is_multiple) {
+ this.selected_item.find("span").text(this.default_text);
+ }
+ content = '';
+ _ref = this.results_data;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ data = _ref[_i];
+ if (data.group) {
+ content += this.result_add_group(data);
+ } else if (!data.empty) {
+ content += this.result_add_option(data);
+ if (data.selected && this.is_multiple) {
+ this.choice_build(data);
+ } else if (data.selected && !this.is_multiple) {
+ this.selected_item.find("span").text(data.text);
+ }
+ }
+ }
+ this.show_search_field_default();
+ this.search_field_scale();
+ this.search_results.html(content);
+ return this.parsing = false;
+ };
+ Chosen.prototype.result_add_group = function(group) {
+ if (!group.disabled) {
+ group.dom_id = this.form_field.id + "chzn_g_" + group.array_index;
+ return '<li id="' + group.dom_id + '" class="group-result">' + $("<div />").text(group.label).html() + '</li>';
+ } else {
+ return "";
+ }
+ };
+ Chosen.prototype.result_add_option = function(option) {
+ var classes;
+ if (!option.disabled) {
+ option.dom_id = this.form_field.id + "chzn_o_" + option.array_index;
+ classes = option.selected && this.is_multiple ? [] : ["active-result"];
+ if (option.selected) {
+ classes.push("result-selected");
+ }
+ if (option.group_array_index != null) {
+ classes.push("group-option");
+ }
+ return '<li id="' + option.dom_id + '" class="' + classes.join(' ') + '">' + $("<div />").text(option.text).html() + '</li>';
+ } else {
+ return "";
+ }
+ };
+ Chosen.prototype.results_update_field = function() {
+ this.result_clear_highlight();
+ this.result_single_selected = null;
+ return this.results_build();
+ };
+ Chosen.prototype.result_do_highlight = function(el) {
+ var high_bottom, high_top, maxHeight, visible_bottom, visible_top;
+ if (el.length) {
+ this.result_clear_highlight();
+ this.result_highlight = el;
+ this.result_highlight.addClass("highlighted");
+ maxHeight = parseInt(this.search_results.css("maxHeight"), 10);
+ visible_top = this.search_results.scrollTop();
+ visible_bottom = maxHeight + visible_top;
+ high_top = this.result_highlight.position().top + this.search_results.scrollTop();
+ high_bottom = high_top + this.result_highlight.outerHeight();
+ if (high_bottom >= visible_bottom) {
+ return this.search_results.scrollTop((high_bottom - maxHeight) > 0 ? high_bottom - maxHeight : 0);
+ } else if (high_top < visible_top) {
+ return this.search_results.scrollTop(high_top);
+ }
+ }
+ };
+ Chosen.prototype.result_clear_highlight = function() {
+ if (this.result_highlight) {
+ this.result_highlight.removeClass("highlighted");
+ }
+ return this.result_highlight = null;
+ };
+ Chosen.prototype.results_toggle = function() {
+ if (this.results_showing) {
+ return this.results_hide();
+ } else {
+ return this.results_show();
+ }
+ };
+ Chosen.prototype.results_show = function() {
+ var dd_top;
+ if (!this.is_multiple) {
+ this.selected_item.addClass("chzn-single-with-drop");
+ if (this.result_single_selected) {
+ this.result_do_highlight(this.result_single_selected);
+ }
+ }
+ dd_top = this.is_multiple ? this.container.height() : this.container.height() - 1;
+ this.dropdown.css({
+ "top": dd_top + "px",
+ "left": 0
+ });
+ this.results_showing = true;
+ this.search_field.focus();
+ this.search_field.val(this.search_field.val());
+ return this.winnow_results();
+ };
+ Chosen.prototype.results_hide = function() {
+ if (!this.is_multiple) {
+ this.selected_item.removeClass("chzn-single-with-drop");
+ }
+ this.result_clear_highlight();
+ this.dropdown.css({
+ "left": "-9000px"
+ });
+ return this.results_showing = false;
+ };
+ Chosen.prototype.set_tab_index = function(el) {
+ var ti;
+ if (this.form_field_jq.attr("tabindex")) {
+ ti = this.form_field_jq.attr("tabindex");
+ this.form_field_jq.attr("tabindex", -1);
+ if (this.is_multiple) {
+ return this.search_field.attr("tabindex", ti);
+ } else {
+ this.selected_item.attr("tabindex", ti);
+ return this.search_field.attr("tabindex", -1);
+ }
+ }
+ };
+ Chosen.prototype.show_search_field_default = function() {
+ if (this.is_multiple && this.choices < 1 && !this.active_field) {
+ this.search_field.val(this.default_text);
+ return this.search_field.addClass("default");
+ } else {
+ this.search_field.val("");
+ return this.search_field.removeClass("default");
+ }
+ };
+ Chosen.prototype.search_results_click = function(evt) {
+ var target;
+ target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first();
+ if (target.length) {
+ this.result_highlight = target;
+ return this.result_select();
+ }
+ };
+ Chosen.prototype.search_results_mouseover = function(evt) {
+ var target;
+ target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first();
+ if (target) {
+ return this.result_do_highlight(target);
+ }
+ };
+ Chosen.prototype.search_results_mouseout = function(evt) {
+ if ($(evt.target).hasClass("active-result" || $(evt.target).parents('.active-result').first())) {
+ return this.result_clear_highlight();
+ }
+ };
+ Chosen.prototype.choices_click = function(evt) {
+ evt.preventDefault();
+ if (this.active_field && !($(evt.target).hasClass("search-choice" || $(evt.target).parents('.search-choice').first)) && !this.results_showing) {
+ return this.results_show();
+ }
+ };
+ Chosen.prototype.choice_build = function(item) {
+ var choice_id, link;
+ choice_id = this.form_field.id + "_chzn_c_" + item.array_index;
+ this.choices += 1;
+ this.search_container.before('<li class="search-choice" id="' + choice_id + '"><span>' + item.text + '</span><a href="javascript:void(0)" class="search-choice-close" rel="' + item.array_index + '"></a></li>');
+ link = $('#' + choice_id).find("a").first();
+ return link.click(__bind(function(evt) {
+ return this.choice_destroy_link_click(evt);
+ }, this));
+ };
+ Chosen.prototype.choice_destroy_link_click = function(evt) {
+ evt.preventDefault();
+ this.pending_destroy_click = true;
+ return this.choice_destroy($(evt.target));
+ };
+ Chosen.prototype.choice_destroy = function(link) {
+ this.choices -= 1;
+ this.show_search_field_default();
+ if (this.is_multiple && this.choices > 0 && this.search_field.val().length < 1) {
+ this.results_hide();
+ }
+ this.result_deselect(link.attr("rel"));
+ return link.parents('li').first().remove();
+ };
+ Chosen.prototype.result_select = function() {
+ var high, high_id, item, position;
+ if (this.result_highlight) {
+ high = this.result_highlight;
+ high_id = high.attr("id");
+ this.result_clear_highlight();
+ high.addClass("result-selected");
+ if (this.is_multiple) {
+ this.result_deactivate(high);
+ } else {
+ this.result_single_selected = high;
+ }
+ position = high_id.substr(high_id.lastIndexOf("_") + 1);
+ item = this.results_data[position];
+ item.selected = true;
+ this.form_field.options[item.options_index].selected = true;
+ if (this.is_multiple) {
+ this.choice_build(item);
+ } else {
+ this.selected_item.find("span").first().text(item.text);
+ }
+ this.results_hide();
+ this.search_field.val("");
+ this.form_field_jq.trigger("change");
+ return this.search_field_scale();
+ }
+ };
+ Chosen.prototype.result_activate = function(el) {
+ return el.addClass("active-result").show();
+ };
+ Chosen.prototype.result_deactivate = function(el) {
+ return el.removeClass("active-result").hide();
+ };
+ Chosen.prototype.result_deselect = function(pos) {
+ var result, result_data;
+ result_data = this.results_data[pos];
+ result_data.selected = false;
+ this.form_field.options[result_data.options_index].selected = false;
+ result = $("#" + this.form_field.id + "chzn_o_" + pos);
+ result.removeClass("result-selected").addClass("active-result").show();
+ this.result_clear_highlight();
+ this.winnow_results();
+ this.form_field_jq.trigger("change");
+ return this.search_field_scale();
+ };
+ Chosen.prototype.results_search = function(evt) {
+ if (this.results_showing) {
+ return this.winnow_results();
+ } else {
+ return this.results_show();
+ }
+ };
+ Chosen.prototype.winnow_results = function() {
+ var found, option, part, parts, regex, result_id, results, searchText, startTime, startpos, text, zregex, _i, _j, _len, _len2, _ref;
+ startTime = new Date();
+ this.no_results_clear();
+ results = 0;
+ searchText = this.search_field.val() === this.default_text ? "" : $.trim(this.search_field.val());
+ regex = new RegExp('^' + searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i');
+ zregex = new RegExp(searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i');
+ _ref = this.results_data;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ option = _ref[_i];
+ if (!option.disabled && !option.empty) {
+ if (option.group) {
+ $('#' + option.dom_id).hide();
+ } else if (!(this.is_multiple && option.selected)) {
+ found = false;
+ result_id = option.dom_id;
+ if (regex.test(option.text)) {
+ found = true;
+ results += 1;
+ } else if (option.text.indexOf(" ") >= 0 || option.text.indexOf("[") === 0) {
+ parts = option.text.replace(/\[|\]/g, "").split(" ");
+ if (parts.length) {
+ for (_j = 0, _len2 = parts.length; _j < _len2; _j++) {
+ part = parts[_j];
+ if (regex.test(part)) {
+ found = true;
+ results += 1;
+ }
+ }
+ }
+ }
+ if (found) {
+ if (searchText.length) {
+ startpos = option.text.search(zregex);
+ text = option.text.substr(0, startpos + searchText.length) + '</em>' + option.text.substr(startpos + searchText.length);
+ text = text.substr(0, startpos) + '<em>' + text.substr(startpos);
+ } else {
+ text = option.text;
+ }
+ if ($("#" + result_id).html !== text) {
+ $("#" + result_id).html(text);
+ }
+ this.result_activate($("#" + result_id));
+ if (option.group_array_index != null) {
+ $("#" + this.results_data[option.group_array_index].dom_id).show();
+ }
+ } else {
+ if (this.result_highlight && result_id === this.result_highlight.attr('id')) {
+ this.result_clear_highlight();
+ }
+ this.result_deactivate($("#" + result_id));
+ }
+ }
+ }
+ }
+ if (results < 1 && searchText.length) {
+ return this.no_results(searchText);
+ } else {
+ return this.winnow_results_set_highlight();
+ }
+ };
+ Chosen.prototype.winnow_results_clear = function() {
+ var li, lis, _i, _len, _results;
+ this.search_field.val("");
+ lis = this.search_results.find("li");
+ _results = [];
+ for (_i = 0, _len = lis.length; _i < _len; _i++) {
+ li = lis[_i];
+ li = $(li);
+ _results.push(li.hasClass("group-result") ? li.show() : !this.is_multiple || !li.hasClass("result-selected") ? this.result_activate(li) : void 0);
+ }
+ return _results;
+ };
+ Chosen.prototype.winnow_results_set_highlight = function() {
+ var do_high;
+ if (!this.result_highlight) {
+ do_high = this.search_results.find(".active-result").first();
+ if (do_high) {
+ return this.result_do_highlight(do_high);
+ }
+ }
+ };
+ Chosen.prototype.no_results = function(terms) {
+ var no_results_html;
+ no_results_html = $('<li class="no-results">No results match "<span></span>"</li>');
+ no_results_html.find("span").first().text(terms);
+ return this.search_results.append(no_results_html);
+ };
+ Chosen.prototype.no_results_clear = function() {
+ return this.search_results.find(".no-results").remove();
+ };
+ Chosen.prototype.keydown_arrow = function() {
+ var first_active, next_sib;
+ if (!this.result_highlight) {
+ first_active = this.search_results.find("li.active-result").first();
+ if (first_active) {
+ this.result_do_highlight($(first_active));
+ }
+ } else if (this.results_showing) {
+ next_sib = this.result_highlight.nextAll("li.active-result").first();
+ if (next_sib) {
+ this.result_do_highlight(next_sib);
+ }
+ }
+ if (!this.results_showing) {
+ return this.results_show();
+ }
+ };
+ Chosen.prototype.keyup_arrow = function() {
+ var prev_sibs;
+ if (!this.results_showing && !this.is_multiple) {
+ return this.results_show();
+ } else if (this.result_highlight) {
+ prev_sibs = this.result_highlight.prevAll("li.active-result");
+ if (prev_sibs.length) {
+ return this.result_do_highlight(prev_sibs.first());
+ } else {
+ if (this.choices > 0) {
+ this.results_hide();
+ }
+ return this.result_clear_highlight();
+ }
+ }
+ };
+ Chosen.prototype.keydown_backstroke = function() {
+ if (this.pending_backstroke) {
+ this.choice_destroy(this.pending_backstroke.find("a").first());
+ return this.clear_backstroke();
+ } else {
+ this.pending_backstroke = this.search_container.siblings("li.search-choice").last();
+ return this.pending_backstroke.addClass("search-choice-focus");
+ }
+ };
+ Chosen.prototype.clear_backstroke = function() {
+ if (this.pending_backstroke) {
+ this.pending_backstroke.removeClass("search-choice-focus");
+ }
+ return this.pending_backstroke = null;
+ };
+ Chosen.prototype.keyup_checker = function(evt) {
+ var stroke, _ref;
+ stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
+ this.search_field_scale();
+ switch (stroke) {
+ case 8:
+ if (this.is_multiple && this.backstroke_length < 1 && this.choices > 0) {
+ return this.keydown_backstroke();
+ } else if (!this.pending_backstroke) {
+ this.result_clear_highlight();
+ return this.results_search();
+ }
+ break;
+ case 13:
+ evt.preventDefault();
+ if (this.results_showing) {
+ return this.result_select();
+ }
+ break;
+ case 27:
+ if (this.results_showing) {
+ return this.results_hide();
+ }
+ break;
+ case 9:
+ case 38:
+ case 40:
+ case 16:
+ break;
+ default:
+ return this.results_search();
+ }
+ };
+ Chosen.prototype.keydown_checker = function(evt) {
+ var stroke, _ref;
+ stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
+ this.search_field_scale();
+ if (stroke !== 8 && this.pending_backstroke) {
+ this.clear_backstroke();
+ }
+ switch (stroke) {
+ case 8:
+ this.backstroke_length = this.search_field.val().length;
+ break;
+ case 9:
+ this.mouse_on_container = false;
+ break;
+ case 13:
+ evt.preventDefault();
+ break;
+ case 38:
+ evt.preventDefault();
+ this.keyup_arrow();
+ break;
+ case 40:
+ this.keydown_arrow();
+ break;
+ }
+ };
+ Chosen.prototype.search_field_scale = function() {
+ var dd_top, div, h, style, style_block, styles, w, _i, _len;
+ if (this.is_multiple) {
+ h = 0;
+ w = 0;
+ style_block = "position:absolute; left: -1000px; top: -1000px; display:none;";
+ styles = ['font-size', 'font-style', 'font-weight', 'font-family', 'line-height', 'text-transform', 'letter-spacing'];
+ for (_i = 0, _len = styles.length; _i < _len; _i++) {
+ style = styles[_i];
+ style_block += style + ":" + this.search_field.css(style) + ";";
+ }
+ div = $('<div />', {
+ 'style': style_block
+ });
+ div.text(this.search_field.val());
+ $('body').append(div);
+ w = div.width() + 25;
+ div.remove();
+ if (w > this.f_width - 10) {
+ w = this.f_width - 10;
+ }
+ this.search_field.css({
+ 'width': w + 'px'
+ });
+ dd_top = this.container.height();
+ return this.dropdown.css({
+ "top": dd_top + "px"
+ });
+ }
+ };
+ return Chosen;
+ })();
+ get_side_border_padding = function(elmt) {
+ var side_border_padding;
+ return side_border_padding = elmt.outerWidth() - elmt.width();
+ };
+ root.get_side_border_padding = get_side_border_padding;
+ SelectParser = (function() {
+ function SelectParser() {
+ this.options_index = 0;
+ this.parsed = [];
+ }
+ SelectParser.prototype.add_node = function(child) {
+ if (child.nodeName === "OPTGROUP") {
+ return this.add_group(child);
+ } else {
+ return this.add_option(child);
+ }
+ };
+ SelectParser.prototype.add_group = function(group) {
+ var group_position, option, _i, _len, _ref, _results;
+ group_position = this.parsed.length;
+ this.parsed.push({
+ array_index: group_position,
+ group: true,
+ label: group.label,
+ children: 0,
+ disabled: group.disabled
+ });
+ _ref = group.childNodes;
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ option = _ref[_i];
+ _results.push(this.add_option(option, group_position, group.disabled));
+ }
+ return _results;
+ };
+ SelectParser.prototype.add_option = function(option, group_position, group_disabled) {
+ if (option.nodeName === "OPTION") {
+ if (option.text !== "") {
+ if (group_position != null) {
+ this.parsed[group_position].children += 1;
+ }
+ this.parsed.push({
+ array_index: this.parsed.length,
+ options_index: this.options_index,
+ value: option.value,
+ text: option.text,
+ selected: option.selected,
+ disabled: group_disabled === true ? group_disabled : option.disabled,
+ group_array_index: group_position
+ });
+ } else {
+ this.parsed.push({
+ array_index: this.parsed.length,
+ options_index: this.options_index,
+ empty: true
+ });
+ }
+ return this.options_index += 1;
+ }
+ };
+ return SelectParser;
+ })();
+ SelectParser.select_to_array = function(select) {
+ var child, parser, _i, _len, _ref;
+ parser = new SelectParser();
+ _ref = select.childNodes;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ child = _ref[_i];
+ parser.add_node(child);
+ }
+ return parser.parsed;
+ };
+ root.SelectParser = SelectParser;
+}).call(this);
diff --git a/usr/local/www/javascript/chosen/chosen.jquery.min.js b/usr/local/www/javascript/chosen/chosen.jquery.min.js
new file mode 100644
index 0000000..ae69f22
--- /dev/null
+++ b/usr/local/www/javascript/chosen/chosen.jquery.min.js
@@ -0,0 +1,9 @@
+/*
+Chosen, a Select Box Enhancer for jQuery and Protoype
+by Patrick Filler for Harvest, http://getharvest.com
+
+Available for use under the MIT License, http://en.wikipedia.org/wiki/MIT_License
+
+Copyright (c) 2011 by Harvest
+*/
+(function(){var $,Chosen,SelectParser,get_side_border_padding,root;var __bind=function(fn,me){return function(){return fn.apply(me,arguments);};};root=typeof exports!=="undefined"&&exports!==null?exports:this;$=jQuery;$.fn.extend({chosen:function(data,options){return $(this).each(function(input_field){if(!($(this)).hasClass("chzn-done")){return new Chosen(this,data,options);}});}});Chosen=(function(){function Chosen(elmn){this.set_default_values();this.form_field=elmn;this.form_field_jq=$(this.form_field);this.is_multiple=this.form_field.multiple;this.default_text_default=this.form_field.multiple?"Select Some Options":"Select an Option";this.set_up_html();this.register_observers();this.form_field_jq.addClass("chzn-done");}Chosen.prototype.set_default_values=function(){this.click_test_action=__bind(function(evt){return this.test_active_click(evt);},this);this.active_field=false;this.mouse_on_container=false;this.results_showing=false;this.result_highlighted=null;this.result_single_selected=null;return this.choices=0;};Chosen.prototype.set_up_html=function(){var container_div,dd_top,dd_width,sf_width;this.container_id=this.form_field.id+"_chzn";this.f_width=this.form_field_jq.width();this.default_text=this.form_field_jq.attr("title")?this.form_field_jq.attr("title"):this.default_text_default;container_div=$("<div />",{id:this.container_id,"class":"chzn-container",style:"width: "+this.f_width+"px;"});if(this.is_multiple){container_div.html('<ul class="chzn-choices"><li class="search-field"><input type="text" value="'+this.default_text+'" class="default" style="width:25px;" /></li></ul><div class="chzn-drop" style="left:-9000px;"><ul class="chzn-results"></ul></div>');}else{container_div.html('<a href="javascript:void(0)" class="chzn-single"><span>'+this.default_text+'</span><div><b></b></div></a><div class="chzn-drop" style="left:-9000px;"><div class="chzn-search"><input type="text" /></div><ul class="chzn-results"></ul></div>');}this.form_field_jq.hide().after(container_div);this.container=$("#"+this.container_id);this.container.addClass("chzn-container-"+(this.is_multiple?"multi":"single"));this.dropdown=this.container.find("div.chzn-drop").first();dd_top=this.container.height();dd_width=this.f_width-get_side_border_padding(this.dropdown);this.dropdown.css({width:dd_width+"px",top:dd_top+"px"});this.search_field=this.container.find("input").first();this.search_results=this.container.find("ul.chzn-results").first();this.search_field_scale();this.search_no_results=this.container.find("li.no-results").first();if(this.is_multiple){this.search_choices=this.container.find("ul.chzn-choices").first();this.search_container=this.container.find("li.search-field").first();}else{this.search_container=this.container.find("div.chzn-search").first();this.selected_item=this.container.find(".chzn-single").first();sf_width=dd_width-get_side_border_padding(this.search_container)-get_side_border_padding(this.search_field);this.search_field.css({width:sf_width+"px"});}this.results_build();return this.set_tab_index();};Chosen.prototype.register_observers=function(){this.container.click(__bind(function(evt){return this.container_click(evt);},this));this.container.mouseenter(__bind(function(evt){return this.mouse_enter(evt);},this));this.container.mouseleave(__bind(function(evt){return this.mouse_leave(evt);},this));this.search_results.click(__bind(function(evt){return this.search_results_click(evt);},this));this.search_results.mouseover(__bind(function(evt){return this.search_results_mouseover(evt);},this));this.search_results.mouseout(__bind(function(evt){return this.search_results_mouseout(evt);},this));this.form_field_jq.bind("liszt:updated",__bind(function(evt){return this.results_update_field(evt);},this));this.search_field.blur(__bind(function(evt){return this.input_blur(evt);},this));this.search_field.keyup(__bind(function(evt){return this.keyup_checker(evt);},this));this.search_field.keydown(__bind(function(evt){return this.keydown_checker(evt);},this));if(this.is_multiple){this.search_choices.click(__bind(function(evt){return this.choices_click(evt);},this));return this.search_field.focus(__bind(function(evt){return this.input_focus(evt);},this));}else{return this.selected_item.focus(__bind(function(evt){return this.activate_field(evt);},this));}};Chosen.prototype.container_click=function(evt){if(evt&&evt.type==="click"){evt.stopPropagation();}if(!this.pending_destroy_click){if(!this.active_field){if(this.is_multiple){this.search_field.val("");}$(document).click(this.click_test_action);this.results_show();}else{if(!this.is_multiple&&evt&&($(evt.target)===this.selected_item||$(evt.target).parents("a.chzn-single").length)){evt.preventDefault();this.results_toggle();}}return this.activate_field();}else{return this.pending_destroy_click=false;}};Chosen.prototype.mouse_enter=function(){return this.mouse_on_container=true;};Chosen.prototype.mouse_leave=function(){return this.mouse_on_container=false;};Chosen.prototype.input_focus=function(evt){if(!this.active_field){return setTimeout((__bind(function(){return this.container_click();},this)),50);}};Chosen.prototype.input_blur=function(evt){if(!this.mouse_on_container){this.active_field=false;return setTimeout((__bind(function(){return this.blur_test();},this)),100);}};Chosen.prototype.blur_test=function(evt){if(!this.active_field&&this.container.hasClass("chzn-container-active")){return this.close_field();}};Chosen.prototype.close_field=function(){$(document).unbind("click",this.click_test_action);if(!this.is_multiple){this.selected_item.attr("tabindex",this.search_field.attr("tabindex"));this.search_field.attr("tabindex",-1);}this.active_field=false;this.results_hide();this.container.removeClass("chzn-container-active");this.winnow_results_clear();this.clear_backstroke();this.show_search_field_default();return this.search_field_scale();};Chosen.prototype.activate_field=function(){if(!this.is_multiple&&!this.active_field){this.search_field.attr("tabindex",this.selected_item.attr("tabindex"));this.selected_item.attr("tabindex",-1);}this.container.addClass("chzn-container-active");this.active_field=true;this.search_field.val(this.search_field.val());return this.search_field.focus();};Chosen.prototype.test_active_click=function(evt){if($(evt.target).parents("#"+this.container.id).length){return this.active_field=true;}else{return this.close_field();}};Chosen.prototype.results_build=function(){var content,data,startTime,_i,_len,_ref;startTime=new Date();this.parsing=true;this.results_data=SelectParser.select_to_array(this.form_field);if(this.is_multiple&&this.choices>0){this.search_choices.find("li.search-choice").remove();this.choices=0;}else{if(!this.is_multiple){this.selected_item.find("span").text(this.default_text);}}content="";_ref=this.results_data;for(_i=0,_len=_ref.length;_i<_len;_i++){data=_ref[_i];if(data.group){content+=this.result_add_group(data);}else{if(!data.empty){content+=this.result_add_option(data);if(data.selected&&this.is_multiple){this.choice_build(data);}else{if(data.selected&&!this.is_multiple){this.selected_item.find("span").text(data.text);}}}}}this.show_search_field_default();this.search_field_scale();this.search_results.html(content);return this.parsing=false;};Chosen.prototype.result_add_group=function(group){if(!group.disabled){group.dom_id=this.form_field.id+"chzn_g_"+group.array_index;return'<li id="'+group.dom_id+'" class="group-result">'+$("<div />").text(group.label).html()+"</li>";}else{return"";}};Chosen.prototype.result_add_option=function(option){var classes;if(!option.disabled){option.dom_id=this.form_field.id+"chzn_o_"+option.array_index;classes=option.selected&&this.is_multiple?[]:["active-result"];if(option.selected){classes.push("result-selected");}if(option.group_array_index!=null){classes.push("group-option");}return'<li id="'+option.dom_id+'" class="'+classes.join(" ")+'">'+$("<div />").text(option.text).html()+"</li>";}else{return"";}};Chosen.prototype.results_update_field=function(){this.result_clear_highlight();this.result_single_selected=null;return this.results_build();};Chosen.prototype.result_do_highlight=function(el){var high_bottom,high_top,maxHeight,visible_bottom,visible_top;if(el.length){this.result_clear_highlight();this.result_highlight=el;this.result_highlight.addClass("highlighted");maxHeight=parseInt(this.search_results.css("maxHeight"),10);visible_top=this.search_results.scrollTop();visible_bottom=maxHeight+visible_top;high_top=this.result_highlight.position().top+this.search_results.scrollTop();high_bottom=high_top+this.result_highlight.outerHeight();if(high_bottom>=visible_bottom){return this.search_results.scrollTop((high_bottom-maxHeight)>0?high_bottom-maxHeight:0);}else{if(high_top<visible_top){return this.search_results.scrollTop(high_top);}}}};Chosen.prototype.result_clear_highlight=function(){if(this.result_highlight){this.result_highlight.removeClass("highlighted");}return this.result_highlight=null;};Chosen.prototype.results_toggle=function(){if(this.results_showing){return this.results_hide();}else{return this.results_show();}};Chosen.prototype.results_show=function(){var dd_top;if(!this.is_multiple){this.selected_item.addClass("chzn-single-with-drop");if(this.result_single_selected){this.result_do_highlight(this.result_single_selected);}}dd_top=this.is_multiple?this.container.height():this.container.height()-1;this.dropdown.css({top:dd_top+"px",left:0});this.results_showing=true;this.search_field.focus();this.search_field.val(this.search_field.val());return this.winnow_results();};Chosen.prototype.results_hide=function(){if(!this.is_multiple){this.selected_item.removeClass("chzn-single-with-drop");}this.result_clear_highlight();this.dropdown.css({left:"-9000px"});return this.results_showing=false;};Chosen.prototype.set_tab_index=function(el){var ti;if(this.form_field_jq.attr("tabindex")){ti=this.form_field_jq.attr("tabindex");this.form_field_jq.attr("tabindex",-1);if(this.is_multiple){return this.search_field.attr("tabindex",ti);}else{this.selected_item.attr("tabindex",ti);return this.search_field.attr("tabindex",-1);}}};Chosen.prototype.show_search_field_default=function(){if(this.is_multiple&&this.choices<1&&!this.active_field){this.search_field.val(this.default_text);return this.search_field.addClass("default");}else{this.search_field.val("");return this.search_field.removeClass("default");}};Chosen.prototype.search_results_click=function(evt){var target;target=$(evt.target).hasClass("active-result")?$(evt.target):$(evt.target).parents(".active-result").first();if(target.length){this.result_highlight=target;return this.result_select();}};Chosen.prototype.search_results_mouseover=function(evt){var target;target=$(evt.target).hasClass("active-result")?$(evt.target):$(evt.target).parents(".active-result").first();if(target){return this.result_do_highlight(target);}};Chosen.prototype.search_results_mouseout=function(evt){if($(evt.target).hasClass("active-result"||$(evt.target).parents(".active-result").first())){return this.result_clear_highlight();}};Chosen.prototype.choices_click=function(evt){evt.preventDefault();if(this.active_field&&!($(evt.target).hasClass("search-choice"||$(evt.target).parents(".search-choice").first))&&!this.results_showing){return this.results_show();}};Chosen.prototype.choice_build=function(item){var choice_id,link;choice_id=this.form_field.id+"_chzn_c_"+item.array_index;this.choices+=1;this.search_container.before('<li class="search-choice" id="'+choice_id+'"><span>'+item.text+'</span><a href="javascript:void(0)" class="search-choice-close" rel="'+item.array_index+'"></a></li>');link=$("#"+choice_id).find("a").first();return link.click(__bind(function(evt){return this.choice_destroy_link_click(evt);},this));};Chosen.prototype.choice_destroy_link_click=function(evt){evt.preventDefault();this.pending_destroy_click=true;return this.choice_destroy($(evt.target));};Chosen.prototype.choice_destroy=function(link){this.choices-=1;this.show_search_field_default();if(this.is_multiple&&this.choices>0&&this.search_field.val().length<1){this.results_hide();}this.result_deselect(link.attr("rel"));return link.parents("li").first().remove();};Chosen.prototype.result_select=function(){var high,high_id,item,position;if(this.result_highlight){high=this.result_highlight;high_id=high.attr("id");this.result_clear_highlight();high.addClass("result-selected");if(this.is_multiple){this.result_deactivate(high);}else{this.result_single_selected=high;}position=high_id.substr(high_id.lastIndexOf("_")+1);item=this.results_data[position];item.selected=true;this.form_field.options[item.options_index].selected=true;if(this.is_multiple){this.choice_build(item);}else{this.selected_item.find("span").first().text(item.text);}this.results_hide();this.search_field.val("");this.form_field_jq.trigger("change");return this.search_field_scale();}};Chosen.prototype.result_activate=function(el){return el.addClass("active-result").show();};Chosen.prototype.result_deactivate=function(el){return el.removeClass("active-result").hide();};Chosen.prototype.result_deselect=function(pos){var result,result_data;result_data=this.results_data[pos];result_data.selected=false;this.form_field.options[result_data.options_index].selected=false;result=$("#"+this.form_field.id+"chzn_o_"+pos);result.removeClass("result-selected").addClass("active-result").show();this.result_clear_highlight();this.winnow_results();this.form_field_jq.trigger("change");return this.search_field_scale();};Chosen.prototype.results_search=function(evt){if(this.results_showing){return this.winnow_results();}else{return this.results_show();}};Chosen.prototype.winnow_results=function(){var found,option,part,parts,regex,result_id,results,searchText,startTime,startpos,text,zregex,_i,_j,_len,_len2,_ref;startTime=new Date();this.no_results_clear();results=0;searchText=this.search_field.val()===this.default_text?"":$.trim(this.search_field.val());regex=new RegExp("^"+searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i");zregex=new RegExp(searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i");_ref=this.results_data;for(_i=0,_len=_ref.length;_i<_len;_i++){option=_ref[_i];if(!option.disabled&&!option.empty){if(option.group){$("#"+option.dom_id).hide();}else{if(!(this.is_multiple&&option.selected)){found=false;result_id=option.dom_id;if(regex.test(option.text)){found=true;results+=1;}else{if(option.text.indexOf(" ")>=0||option.text.indexOf("[")===0){parts=option.text.replace(/\[|\]/g,"").split(" ");if(parts.length){for(_j=0,_len2=parts.length;_j<_len2;_j++){part=parts[_j];if(regex.test(part)){found=true;results+=1;}}}}}if(found){if(searchText.length){startpos=option.text.search(zregex);text=option.text.substr(0,startpos+searchText.length)+"</em>"+option.text.substr(startpos+searchText.length);text=text.substr(0,startpos)+"<em>"+text.substr(startpos);}else{text=option.text;}if($("#"+result_id).html!==text){$("#"+result_id).html(text);}this.result_activate($("#"+result_id));if(option.group_array_index!=null){$("#"+this.results_data[option.group_array_index].dom_id).show();}}else{if(this.result_highlight&&result_id===this.result_highlight.attr("id")){this.result_clear_highlight();}this.result_deactivate($("#"+result_id));}}}}}if(results<1&&searchText.length){return this.no_results(searchText);}else{return this.winnow_results_set_highlight();}};Chosen.prototype.winnow_results_clear=function(){var li,lis,_i,_len,_results;this.search_field.val("");lis=this.search_results.find("li");_results=[];for(_i=0,_len=lis.length;_i<_len;_i++){li=lis[_i];li=$(li);_results.push(li.hasClass("group-result")?li.show():!this.is_multiple||!li.hasClass("result-selected")?this.result_activate(li):void 0);}return _results;};Chosen.prototype.winnow_results_set_highlight=function(){var do_high;if(!this.result_highlight){do_high=this.search_results.find(".active-result").first();if(do_high){return this.result_do_highlight(do_high);}}};Chosen.prototype.no_results=function(terms){var no_results_html;no_results_html=$('<li class="no-results">No results match "<span></span>"</li>');no_results_html.find("span").first().text(terms);return this.search_results.append(no_results_html);};Chosen.prototype.no_results_clear=function(){return this.search_results.find(".no-results").remove();};Chosen.prototype.keydown_arrow=function(){var first_active,next_sib;if(!this.result_highlight){first_active=this.search_results.find("li.active-result").first();if(first_active){this.result_do_highlight($(first_active));}}else{if(this.results_showing){next_sib=this.result_highlight.nextAll("li.active-result").first();if(next_sib){this.result_do_highlight(next_sib);}}}if(!this.results_showing){return this.results_show();}};Chosen.prototype.keyup_arrow=function(){var prev_sibs;if(!this.results_showing&&!this.is_multiple){return this.results_show();}else{if(this.result_highlight){prev_sibs=this.result_highlight.prevAll("li.active-result");if(prev_sibs.length){return this.result_do_highlight(prev_sibs.first());}else{if(this.choices>0){this.results_hide();}return this.result_clear_highlight();}}}};Chosen.prototype.keydown_backstroke=function(){if(this.pending_backstroke){this.choice_destroy(this.pending_backstroke.find("a").first());return this.clear_backstroke();}else{this.pending_backstroke=this.search_container.siblings("li.search-choice").last();return this.pending_backstroke.addClass("search-choice-focus");}};Chosen.prototype.clear_backstroke=function(){if(this.pending_backstroke){this.pending_backstroke.removeClass("search-choice-focus");}return this.pending_backstroke=null;};Chosen.prototype.keyup_checker=function(evt){var stroke,_ref;stroke=(_ref=evt.which)!=null?_ref:evt.keyCode;this.search_field_scale();switch(stroke){case 8:if(this.is_multiple&&this.backstroke_length<1&&this.choices>0){return this.keydown_backstroke();}else{if(!this.pending_backstroke){this.result_clear_highlight();return this.results_search();}}break;case 13:evt.preventDefault();if(this.results_showing){return this.result_select();}break;case 27:if(this.results_showing){return this.results_hide();}break;case 9:case 38:case 40:case 16:break;default:return this.results_search();}};Chosen.prototype.keydown_checker=function(evt){var stroke,_ref;stroke=(_ref=evt.which)!=null?_ref:evt.keyCode;this.search_field_scale();if(stroke!==8&&this.pending_backstroke){this.clear_backstroke();}switch(stroke){case 8:this.backstroke_length=this.search_field.val().length;break;case 9:this.mouse_on_container=false;break;case 13:evt.preventDefault();break;case 38:evt.preventDefault();this.keyup_arrow();break;case 40:this.keydown_arrow();break;}};Chosen.prototype.search_field_scale=function(){var dd_top,div,h,style,style_block,styles,w,_i,_len;if(this.is_multiple){h=0;w=0;style_block="position:absolute; left: -1000px; top: -1000px; display:none;";styles=["font-size","font-style","font-weight","font-family","line-height","text-transform","letter-spacing"];for(_i=0,_len=styles.length;_i<_len;_i++){style=styles[_i];style_block+=style+":"+this.search_field.css(style)+";";}div=$("<div />",{style:style_block});div.text(this.search_field.val());$("body").append(div);w=div.width()+25;div.remove();if(w>this.f_width-10){w=this.f_width-10;}this.search_field.css({width:w+"px"});dd_top=this.container.height();return this.dropdown.css({top:dd_top+"px"});}};return Chosen;})();get_side_border_padding=function(elmt){var side_border_padding;return side_border_padding=elmt.outerWidth()-elmt.width();};root.get_side_border_padding=get_side_border_padding;SelectParser=(function(){function SelectParser(){this.options_index=0;this.parsed=[];}SelectParser.prototype.add_node=function(child){if(child.nodeName==="OPTGROUP"){return this.add_group(child);}else{return this.add_option(child);}};SelectParser.prototype.add_group=function(group){var group_position,option,_i,_len,_ref,_results;group_position=this.parsed.length;this.parsed.push({array_index:group_position,group:true,label:group.label,children:0,disabled:group.disabled});_ref=group.childNodes;_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){option=_ref[_i];_results.push(this.add_option(option,group_position,group.disabled));}return _results;};SelectParser.prototype.add_option=function(option,group_position,group_disabled){if(option.nodeName==="OPTION"){if(option.text!==""){if(group_position!=null){this.parsed[group_position].children+=1;}this.parsed.push({array_index:this.parsed.length,options_index:this.options_index,value:option.value,text:option.text,selected:option.selected,disabled:group_disabled===true?group_disabled:option.disabled,group_array_index:group_position});}else{this.parsed.push({array_index:this.parsed.length,options_index:this.options_index,empty:true});}return this.options_index+=1;}};return SelectParser;})();SelectParser.select_to_array=function(select){var child,parser,_i,_len,_ref;parser=new SelectParser();_ref=select.childNodes;for(_i=0,_len=_ref.length;_i<_len;_i++){child=_ref[_i];parser.add_node(child);}return parser.parsed;};root.SelectParser=SelectParser;}).call(this); \ No newline at end of file
diff --git a/usr/local/www/javascript/chosen/chosen.proto.js b/usr/local/www/javascript/chosen/chosen.proto.js
new file mode 100644
index 0000000..e3c0fbd
--- /dev/null
+++ b/usr/local/www/javascript/chosen/chosen.proto.js
@@ -0,0 +1,765 @@
+(function() {
+ /*
+ Chosen, a Select Box Enhancer for jQuery and Protoype
+ by Patrick Filler for Harvest, http://getharvest.com
+
+ Available for use under the MIT License, http://en.wikipedia.org/wiki/MIT_License
+
+ Copyright (c) 2011 by Harvest
+ */ var Chosen, SelectParser, get_side_border_padding, root;
+ var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
+ root = typeof exports !== "undefined" && exports !== null ? exports : this;
+ Chosen = (function() {
+ function Chosen(elmn) {
+ this.set_default_values();
+ this.form_field = elmn;
+ this.is_multiple = this.form_field.multiple;
+ this.default_text_default = this.form_field.multiple ? "Select Some Options" : "Select an Option";
+ this.set_up_html();
+ this.register_observers();
+ }
+ Chosen.prototype.set_default_values = function() {
+ this.click_test_action = __bind(function(evt) {
+ return this.test_active_click(evt);
+ }, this);
+ this.active_field = false;
+ this.mouse_on_container = false;
+ this.results_showing = false;
+ this.result_highlighted = null;
+ this.result_single_selected = null;
+ this.choices = 0;
+ this.single_temp = new Template('<a href="javascript:void(0)" class="chzn-single"><span>#{default}</span><div><b></b></div></a><div class="chzn-drop" style="left:-9000px;"><div class="chzn-search"><input type="text" /></div><ul class="chzn-results"></ul></div>');
+ this.multi_temp = new Template('<ul class="chzn-choices"><li class="search-field"><input type="text" value="#{default}" class="default" style="width:25px;" /></li></ul><div class="chzn-drop" style="left:-9000px;"><ul class="chzn-results"></ul></div>');
+ this.choice_temp = new Template('<li class="search-choice" id="#{id}"><span>#{choice}</span><a href="javascript:void(0)" class="search-choice-close" rel="#{position}"></a></li>');
+ return this.no_results_temp = new Template('<li class="no-results">No results match "<span>#{terms}</span>"</li>');
+ };
+ Chosen.prototype.set_up_html = function() {
+ var base_template, container_props, dd_top, dd_width, sf_width;
+ this.container_id = this.form_field.id + "_chzn";
+ this.f_width = this.form_field.getStyle("width") ? parseInt(this.form_field.getStyle("width"), 10) : this.form_field.getWidth();
+ container_props = {
+ 'id': this.container_id,
+ 'class': 'chzn-container',
+ 'style': 'width: ' + this.f_width + 'px'
+ };
+ this.default_text = this.form_field.readAttribute('title') ? this.form_field.readAttribute('title') : this.default_text_default;
+ base_template = this.is_multiple ? new Element('div', container_props).update(this.multi_temp.evaluate({
+ "default": this.default_text
+ })) : new Element('div', container_props).update(this.single_temp.evaluate({
+ "default": this.default_text
+ }));
+ this.form_field.hide().insert({
+ after: base_template
+ });
+ this.container = $(this.container_id);
+ this.container.addClassName("chzn-container-" + (this.is_multiple ? "multi" : "single"));
+ this.dropdown = this.container.down('div.chzn-drop');
+ dd_top = this.container.getHeight();
+ dd_width = this.f_width - get_side_border_padding(this.dropdown);
+ this.dropdown.setStyle({
+ "width": dd_width + "px",
+ "top": dd_top + "px"
+ });
+ this.search_field = this.container.down('input');
+ this.search_results = this.container.down('ul.chzn-results');
+ this.search_field_scale();
+ this.search_no_results = this.container.down('li.no-results');
+ if (this.is_multiple) {
+ this.search_choices = this.container.down('ul.chzn-choices');
+ this.search_container = this.container.down('li.search-field');
+ } else {
+ this.search_container = this.container.down('div.chzn-search');
+ this.selected_item = this.container.down('.chzn-single');
+ sf_width = dd_width - get_side_border_padding(this.search_container) - get_side_border_padding(this.search_field);
+ this.search_field.setStyle({
+ "width": sf_width + "px"
+ });
+ }
+ this.results_build();
+ return this.set_tab_index();
+ };
+ Chosen.prototype.register_observers = function() {
+ this.container.observe("click", __bind(function(evt) {
+ return this.container_click(evt);
+ }, this));
+ this.container.observe("mouseenter", __bind(function(evt) {
+ return this.mouse_enter(evt);
+ }, this));
+ this.container.observe("mouseleave", __bind(function(evt) {
+ return this.mouse_leave(evt);
+ }, this));
+ this.search_results.observe("click", __bind(function(evt) {
+ return this.search_results_click(evt);
+ }, this));
+ this.search_results.observe("mouseover", __bind(function(evt) {
+ return this.search_results_mouseover(evt);
+ }, this));
+ this.search_results.observe("mouseout", __bind(function(evt) {
+ return this.search_results_mouseout(evt);
+ }, this));
+ this.form_field.observe("liszt:updated", __bind(function(evt) {
+ return this.results_update_field(evt);
+ }, this));
+ this.search_field.observe("blur", __bind(function(evt) {
+ return this.input_blur(evt);
+ }, this));
+ this.search_field.observe("keyup", __bind(function(evt) {
+ return this.keyup_checker(evt);
+ }, this));
+ this.search_field.observe("keydown", __bind(function(evt) {
+ return this.keydown_checker(evt);
+ }, this));
+ if (this.is_multiple) {
+ this.search_choices.observe("click", __bind(function(evt) {
+ return this.choices_click(evt);
+ }, this));
+ return this.search_field.observe("focus", __bind(function(evt) {
+ return this.input_focus(evt);
+ }, this));
+ } else {
+ return this.selected_item.observe("focus", __bind(function(evt) {
+ return this.activate_field(evt);
+ }, this));
+ }
+ };
+ Chosen.prototype.container_click = function(evt) {
+ if (evt && evt.type === "click") {
+ evt.stop();
+ }
+ if (!this.pending_destroy_click) {
+ if (!this.active_field) {
+ if (this.is_multiple) {
+ this.search_field.clear();
+ }
+ document.observe("click", this.click_test_action);
+ this.results_show();
+ } else if (!this.is_multiple && evt && (evt.target === this.selected_item || evt.target.up("a.chzn-single"))) {
+ this.results_toggle();
+ }
+ return this.activate_field();
+ } else {
+ return this.pending_destroy_click = false;
+ }
+ };
+ Chosen.prototype.mouse_enter = function() {
+ return this.mouse_on_container = true;
+ };
+ Chosen.prototype.mouse_leave = function() {
+ return this.mouse_on_container = false;
+ };
+ Chosen.prototype.input_focus = function(evt) {
+ if (!this.active_field) {
+ return setTimeout(this.container_click.bind(this), 50);
+ }
+ };
+ Chosen.prototype.input_blur = function(evt) {
+ if (!this.mouse_on_container) {
+ this.active_field = false;
+ return setTimeout(this.blur_test.bind(this), 100);
+ }
+ };
+ Chosen.prototype.blur_test = function(evt) {
+ if (!this.active_field && this.container.hasClassName("chzn-container-active")) {
+ return this.close_field();
+ }
+ };
+ Chosen.prototype.close_field = function() {
+ document.stopObserving("click", this.click_test_action);
+ if (!this.is_multiple) {
+ this.selected_item.tabIndex = this.search_field.tabIndex;
+ this.search_field.tabIndex = -1;
+ }
+ this.active_field = false;
+ this.results_hide();
+ this.container.removeClassName("chzn-container-active");
+ this.winnow_results_clear();
+ this.clear_backstroke();
+ this.show_search_field_default();
+ return this.search_field_scale();
+ };
+ Chosen.prototype.activate_field = function() {
+ if (!this.is_multiple && !this.active_field) {
+ this.search_field.tabIndex = this.selected_item.tabIndex;
+ this.selected_item.tabIndex = -1;
+ }
+ this.container.addClassName("chzn-container-active");
+ this.active_field = true;
+ this.search_field.value = this.search_field.value;
+ return this.search_field.focus();
+ };
+ Chosen.prototype.test_active_click = function(evt) {
+ if (evt.target.up('#' + this.container.id)) {
+ return this.active_field = true;
+ } else {
+ return this.close_field();
+ }
+ };
+ Chosen.prototype.results_build = function() {
+ var content, data, startTime, _i, _len, _ref;
+ startTime = new Date();
+ this.parsing = true;
+ this.results_data = SelectParser.select_to_array(this.form_field);
+ if (this.is_multiple && this.choices > 0) {
+ this.search_choices.select("li.search-choice").invoke("remove");
+ this.choices = 0;
+ } else if (!this.is_multiple) {
+ this.selected_item.down("span").update(this.default_text);
+ }
+ content = '';
+ _ref = this.results_data;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ data = _ref[_i];
+ if (data.group) {
+ content += this.result_add_group(data);
+ } else if (!data.empty) {
+ content += this.result_add_option(data);
+ if (data.selected && this.is_multiple) {
+ this.choice_build(data);
+ } else if (data.selected && !this.is_multiple) {
+ this.selected_item.down("span").update(data.text);
+ }
+ }
+ }
+ this.show_search_field_default();
+ this.search_field_scale();
+ this.search_results.update(content);
+ return this.parsing = false;
+ };
+ Chosen.prototype.result_add_group = function(group) {
+ if (!group.disabled) {
+ group.dom_id = this.form_field.id + "chzn_g_" + group.array_index;
+ return '<li id="' + group.dom_id + '" class="group-result">' + group.label.escapeHTML() + '</li>';
+ } else {
+ return "";
+ }
+ };
+ Chosen.prototype.result_add_option = function(option) {
+ var classes;
+ if (!option.disabled) {
+ option.dom_id = this.form_field.id + "chzn_o_" + option.array_index;
+ classes = option.selected && this.is_multiple ? [] : ["active-result"];
+ if (option.selected) {
+ classes.push("result-selected");
+ }
+ if (option.group_array_index != null) {
+ classes.push("group-option");
+ }
+ return '<li id="' + option.dom_id + '" class="' + classes.join(' ') + '">' + option.text.escapeHTML() + '</li>';
+ } else {
+ return "";
+ }
+ };
+ Chosen.prototype.results_update_field = function() {
+ this.result_clear_highlight();
+ this.result_single_selected = null;
+ return this.results_build();
+ };
+ Chosen.prototype.result_do_highlight = function(el) {
+ var high_bottom, high_top, maxHeight, visible_bottom, visible_top;
+ this.result_clear_highlight();
+ this.result_highlight = el;
+ this.result_highlight.addClassName("highlighted");
+ maxHeight = parseInt(this.search_results.getStyle('maxHeight'), 10);
+ visible_top = this.search_results.scrollTop;
+ visible_bottom = maxHeight + visible_top;
+ high_top = this.result_highlight.positionedOffset().top;
+ high_bottom = high_top + this.result_highlight.getHeight();
+ if (high_bottom >= visible_bottom) {
+ return this.search_results.scrollTop = (high_bottom - maxHeight) > 0 ? high_bottom - maxHeight : 0;
+ } else if (high_top < visible_top) {
+ return this.search_results.scrollTop = high_top;
+ }
+ };
+ Chosen.prototype.result_clear_highlight = function() {
+ if (this.result_highlight) {
+ this.result_highlight.removeClassName('highlighted');
+ }
+ return this.result_highlight = null;
+ };
+ Chosen.prototype.results_toggle = function() {
+ if (this.results_showing) {
+ return this.results_hide();
+ } else {
+ return this.results_show();
+ }
+ };
+ Chosen.prototype.results_show = function() {
+ var dd_top;
+ if (!this.is_multiple) {
+ this.selected_item.addClassName('chzn-single-with-drop');
+ if (this.result_single_selected) {
+ this.result_do_highlight(this.result_single_selected);
+ }
+ }
+ dd_top = this.is_multiple ? this.container.getHeight() : this.container.getHeight() - 1;
+ this.dropdown.setStyle({
+ "top": dd_top + "px",
+ "left": 0
+ });
+ this.results_showing = true;
+ this.search_field.focus();
+ this.search_field.value = this.search_field.value;
+ return this.winnow_results();
+ };
+ Chosen.prototype.results_hide = function() {
+ if (!this.is_multiple) {
+ this.selected_item.removeClassName('chzn-single-with-drop');
+ }
+ this.result_clear_highlight();
+ this.dropdown.setStyle({
+ "left": "-9000px"
+ });
+ return this.results_showing = false;
+ };
+ Chosen.prototype.set_tab_index = function(el) {
+ var ti;
+ if (this.form_field.tabIndex) {
+ ti = this.form_field.tabIndex;
+ this.form_field.tabIndex = -1;
+ if (this.is_multiple) {
+ return this.search_field.tabIndex = ti;
+ } else {
+ this.selected_item.tabIndex = ti;
+ return this.search_field.tabIndex = -1;
+ }
+ }
+ };
+ Chosen.prototype.show_search_field_default = function() {
+ if (this.is_multiple && this.choices < 1 && !this.active_field) {
+ this.search_field.value = this.default_text;
+ return this.search_field.addClassName("default");
+ } else {
+ this.search_field.value = "";
+ return this.search_field.removeClassName("default");
+ }
+ };
+ Chosen.prototype.search_results_click = function(evt) {
+ var target;
+ target = evt.target.hasClassName("active-result") ? evt.target : evt.target.up(".active-result");
+ if (target) {
+ this.result_highlight = target;
+ return this.result_select();
+ }
+ };
+ Chosen.prototype.search_results_mouseover = function(evt) {
+ var target;
+ target = evt.target.hasClassName("active-result") ? evt.target : evt.target.up(".active-result");
+ if (target) {
+ return this.result_do_highlight(target);
+ }
+ };
+ Chosen.prototype.search_results_mouseout = function(evt) {
+ if (evt.target.hasClassName('active-result') || evt.target.up('.active-result')) {
+ return this.result_clear_highlight();
+ }
+ };
+ Chosen.prototype.choices_click = function(evt) {
+ evt.preventDefault();
+ if (this.active_field && !(evt.target.hasClassName('search-choice') || evt.target.up('.search-choice')) && !this.results_showing) {
+ return this.results_show();
+ }
+ };
+ Chosen.prototype.choice_build = function(item) {
+ var choice_id, link;
+ choice_id = this.form_field.id + "_chzn_c_" + item.array_index;
+ this.choices += 1;
+ this.search_container.insert({
+ before: this.choice_temp.evaluate({
+ "id": choice_id,
+ "choice": item.text,
+ "position": item.array_index
+ })
+ });
+ link = $(choice_id).down('a');
+ return link.observe("click", __bind(function(evt) {
+ return this.choice_destroy_link_click(evt);
+ }, this));
+ };
+ Chosen.prototype.choice_destroy_link_click = function(evt) {
+ evt.preventDefault();
+ this.pending_destroy_click = true;
+ return this.choice_destroy(evt.target);
+ };
+ Chosen.prototype.choice_destroy = function(link) {
+ this.choices -= 1;
+ this.show_search_field_default();
+ if (this.is_multiple && this.choices > 0 && this.search_field.value.length < 1) {
+ this.results_hide();
+ }
+ this.result_deselect(link.readAttribute("rel"));
+ return link.up('li').remove();
+ };
+ Chosen.prototype.result_select = function() {
+ var high, item, position;
+ if (this.result_highlight) {
+ high = this.result_highlight;
+ this.result_clear_highlight();
+ high.addClassName("result-selected");
+ if (this.is_multiple) {
+ this.result_deactivate(high);
+ } else {
+ this.result_single_selected = high;
+ }
+ position = high.id.substr(high.id.lastIndexOf("_") + 1);
+ item = this.results_data[position];
+ item.selected = true;
+ this.form_field.options[item.options_index].selected = true;
+ if (this.is_multiple) {
+ this.choice_build(item);
+ } else {
+ this.selected_item.down("span").update(item.text);
+ }
+ this.results_hide();
+ this.search_field.value = "";
+ if (typeof Event.simulate === 'function') {
+ this.form_field.simulate("change");
+ }
+ return this.search_field_scale();
+ }
+ };
+ Chosen.prototype.result_activate = function(el) {
+ return el.addClassName("active-result").show();
+ };
+ Chosen.prototype.result_deactivate = function(el) {
+ return el.removeClassName("active-result").hide();
+ };
+ Chosen.prototype.result_deselect = function(pos) {
+ var result, result_data;
+ result_data = this.results_data[pos];
+ result_data.selected = false;
+ this.form_field.options[result_data.options_index].selected = false;
+ result = $(this.form_field.id + "chzn_o_" + pos);
+ result.removeClassName("result-selected").addClassName("active-result").show();
+ this.result_clear_highlight();
+ this.winnow_results();
+ if (typeof Event.simulate === 'function') {
+ this.form_field.simulate("change");
+ }
+ return this.search_field_scale();
+ };
+ Chosen.prototype.results_search = function(evt) {
+ if (this.results_showing) {
+ return this.winnow_results();
+ } else {
+ return this.results_show();
+ }
+ };
+ Chosen.prototype.winnow_results = function() {
+ var found, option, part, parts, regex, result_id, results, searchText, startTime, startpos, text, zregex, _i, _j, _len, _len2, _ref;
+ startTime = new Date();
+ this.no_results_clear();
+ results = 0;
+ searchText = this.search_field.value === this.default_text ? "" : this.search_field.value.strip();
+ regex = new RegExp('^' + searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i');
+ zregex = new RegExp(searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i');
+ _ref = this.results_data;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ option = _ref[_i];
+ if (!option.disabled && !option.empty) {
+ if (option.group) {
+ $(option.dom_id).hide();
+ } else if (!(this.is_multiple && option.selected)) {
+ found = false;
+ result_id = option.dom_id;
+ if (regex.test(option.text)) {
+ found = true;
+ results += 1;
+ } else if (option.text.indexOf(" ") >= 0 || option.text.indexOf("[") === 0) {
+ parts = option.text.replace(/\[|\]/g, "").split(" ");
+ if (parts.length) {
+ for (_j = 0, _len2 = parts.length; _j < _len2; _j++) {
+ part = parts[_j];
+ if (regex.test(part)) {
+ found = true;
+ results += 1;
+ }
+ }
+ }
+ }
+ if (found) {
+ if (searchText.length) {
+ startpos = option.text.search(zregex);
+ text = option.text.substr(0, startpos + searchText.length) + '</em>' + option.text.substr(startpos + searchText.length);
+ text = text.substr(0, startpos) + '<em>' + text.substr(startpos);
+ } else {
+ text = option.text;
+ }
+ if ($(result_id).innerHTML !== text) {
+ $(result_id).update(text);
+ }
+ this.result_activate($(result_id));
+ if (option.group_array_index != null) {
+ $(this.results_data[option.group_array_index].dom_id).show();
+ }
+ } else {
+ if ($(result_id) === this.result_highlight) {
+ this.result_clear_highlight();
+ }
+ this.result_deactivate($(result_id));
+ }
+ }
+ }
+ }
+ if (results < 1 && searchText.length) {
+ return this.no_results(searchText);
+ } else {
+ return this.winnow_results_set_highlight();
+ }
+ };
+ Chosen.prototype.winnow_results_clear = function() {
+ var li, lis, _i, _len, _results;
+ this.search_field.clear();
+ lis = this.search_results.select("li");
+ _results = [];
+ for (_i = 0, _len = lis.length; _i < _len; _i++) {
+ li = lis[_i];
+ _results.push(li.hasClassName("group-result") ? li.show() : !this.is_multiple || !li.hasClassName("result-selected") ? this.result_activate(li) : void 0);
+ }
+ return _results;
+ };
+ Chosen.prototype.winnow_results_set_highlight = function() {
+ var do_high;
+ if (!this.result_highlight) {
+ do_high = this.search_results.down(".active-result");
+ if (do_high) {
+ return this.result_do_highlight(do_high);
+ }
+ }
+ };
+ Chosen.prototype.no_results = function(terms) {
+ return this.search_results.insert(this.no_results_temp.evaluate({
+ "terms": terms.escapeHTML()
+ }));
+ };
+ Chosen.prototype.no_results_clear = function() {
+ var nr, _results;
+ nr = null;
+ _results = [];
+ while (nr = this.search_results.down(".no-results")) {
+ _results.push(nr.remove());
+ }
+ return _results;
+ };
+ Chosen.prototype.keydown_arrow = function() {
+ var actives, nexts, sibs;
+ actives = this.search_results.select("li.active-result");
+ if (actives.length) {
+ if (!this.result_highlight) {
+ this.result_do_highlight(actives.first());
+ } else if (this.results_showing) {
+ sibs = this.result_highlight.nextSiblings();
+ nexts = sibs.intersect(actives);
+ if (nexts.length) {
+ this.result_do_highlight(nexts.first());
+ }
+ }
+ if (!this.results_showing) {
+ return this.results_show();
+ }
+ }
+ };
+ Chosen.prototype.keyup_arrow = function() {
+ var actives, prevs, sibs;
+ if (!this.results_showing && !this.is_multiple) {
+ return this.results_show();
+ } else if (this.result_highlight) {
+ sibs = this.result_highlight.previousSiblings();
+ actives = this.search_results.select("li.active-result");
+ prevs = sibs.intersect(actives);
+ if (prevs.length) {
+ return this.result_do_highlight(prevs.first());
+ } else {
+ if (this.choices > 0) {
+ this.results_hide();
+ }
+ return this.result_clear_highlight();
+ }
+ }
+ };
+ Chosen.prototype.keydown_backstroke = function() {
+ if (this.pending_backstroke) {
+ this.choice_destroy(this.pending_backstroke.down("a"));
+ return this.clear_backstroke();
+ } else {
+ this.pending_backstroke = this.search_container.siblings("li.search-choice").last();
+ return this.pending_backstroke.addClassName("search-choice-focus");
+ }
+ };
+ Chosen.prototype.clear_backstroke = function() {
+ if (this.pending_backstroke) {
+ this.pending_backstroke.removeClassName("search-choice-focus");
+ }
+ return this.pending_backstroke = null;
+ };
+ Chosen.prototype.keyup_checker = function(evt) {
+ var stroke, _ref;
+ stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
+ this.search_field_scale();
+ switch (stroke) {
+ case 8:
+ if (this.is_multiple && this.backstroke_length < 1 && this.choices > 0) {
+ return this.keydown_backstroke();
+ } else if (!this.pending_backstroke) {
+ this.result_clear_highlight();
+ return this.results_search();
+ }
+ break;
+ case 13:
+ evt.preventDefault();
+ if (this.results_showing) {
+ return this.result_select();
+ }
+ break;
+ case 27:
+ if (this.results_showing) {
+ return this.results_hide();
+ }
+ break;
+ case 9:
+ case 38:
+ case 40:
+ case 16:
+ break;
+ default:
+ return this.results_search();
+ }
+ };
+ Chosen.prototype.keydown_checker = function(evt) {
+ var stroke, _ref;
+ stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
+ this.search_field_scale();
+ if (stroke !== 8 && this.pending_backstroke) {
+ this.clear_backstroke();
+ }
+ switch (stroke) {
+ case 8:
+ return this.backstroke_length = this.search_field.value.length;
+ case 9:
+ return this.mouse_on_container = false;
+ case 13:
+ return evt.preventDefault();
+ case 38:
+ evt.preventDefault();
+ return this.keyup_arrow();
+ case 40:
+ return this.keydown_arrow();
+ }
+ };
+ Chosen.prototype.search_field_scale = function() {
+ var dd_top, div, h, style, style_block, styles, w, _i, _len;
+ if (this.is_multiple) {
+ h = 0;
+ w = 0;
+ style_block = "position:absolute; left: -1000px; top: -1000px; display:none;";
+ styles = ['font-size', 'font-style', 'font-weight', 'font-family', 'line-height', 'text-transform', 'letter-spacing'];
+ for (_i = 0, _len = styles.length; _i < _len; _i++) {
+ style = styles[_i];
+ style_block += style + ":" + this.search_field.getStyle(style) + ";";
+ }
+ div = new Element('div', {
+ 'style': style_block
+ }).update(this.search_field.value);
+ document.body.appendChild(div);
+ w = Element.measure(div, 'width') + 25;
+ div.remove();
+ if (w > this.f_width - 10) {
+ w = this.f_width - 10;
+ }
+ this.search_field.setStyle({
+ 'width': w + 'px'
+ });
+ dd_top = this.container.getHeight();
+ return this.dropdown.setStyle({
+ "top": dd_top + "px"
+ });
+ }
+ };
+ return Chosen;
+ })();
+ root.Chosen = Chosen;
+ document.observe('dom:loaded', function(evt) {
+ var select, selects, _i, _len, _results;
+ selects = $$(".chzn-select");
+ _results = [];
+ for (_i = 0, _len = selects.length; _i < _len; _i++) {
+ select = selects[_i];
+ _results.push(new Chosen(select));
+ }
+ return _results;
+ });
+ get_side_border_padding = function(elmt) {
+ var layout, side_border_padding;
+ layout = new Element.Layout(elmt);
+ return side_border_padding = layout.get("border-left") + layout.get("border-right") + layout.get("padding-left") + layout.get("padding-right");
+ };
+ root.get_side_border_padding = get_side_border_padding;
+ root = typeof exports !== "undefined" && exports !== null ? exports : this;
+ SelectParser = (function() {
+ function SelectParser() {
+ this.options_index = 0;
+ this.parsed = [];
+ }
+ SelectParser.prototype.add_node = function(child) {
+ if (child.nodeName === "OPTGROUP") {
+ return this.add_group(child);
+ } else {
+ return this.add_option(child);
+ }
+ };
+ SelectParser.prototype.add_group = function(group) {
+ var group_position, option, _i, _len, _ref, _results;
+ group_position = this.parsed.length;
+ this.parsed.push({
+ array_index: group_position,
+ group: true,
+ label: group.label,
+ children: 0,
+ disabled: group.disabled
+ });
+ _ref = group.childNodes;
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ option = _ref[_i];
+ _results.push(this.add_option(option, group_position, group.disabled));
+ }
+ return _results;
+ };
+ SelectParser.prototype.add_option = function(option, group_position, group_disabled) {
+ if (option.nodeName === "OPTION") {
+ if (option.text !== "") {
+ if (group_position != null) {
+ this.parsed[group_position].children += 1;
+ }
+ this.parsed.push({
+ array_index: this.parsed.length,
+ options_index: this.options_index,
+ value: option.value,
+ text: option.text,
+ selected: option.selected,
+ disabled: group_disabled === true ? group_disabled : option.disabled,
+ group_array_index: group_position
+ });
+ } else {
+ this.parsed.push({
+ array_index: this.parsed.length,
+ options_index: this.options_index,
+ empty: true
+ });
+ }
+ return this.options_index += 1;
+ }
+ };
+ return SelectParser;
+ })();
+ SelectParser.select_to_array = function(select) {
+ var child, parser, _i, _len, _ref;
+ parser = new SelectParser();
+ _ref = select.childNodes;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ child = _ref[_i];
+ parser.add_node(child);
+ }
+ return parser.parsed;
+ };
+ root.SelectParser = SelectParser;
+}).call(this);
diff --git a/usr/local/www/javascript/chosen/chosen.proto.min.js b/usr/local/www/javascript/chosen/chosen.proto.min.js
new file mode 100644
index 0000000..79109c5
--- /dev/null
+++ b/usr/local/www/javascript/chosen/chosen.proto.min.js
@@ -0,0 +1,9 @@
+/*
+Chosen, a Select Box Enhancer for jQuery and Protoype
+by Patrick Filler for Harvest, http://getharvest.com
+
+Available for use under the MIT License, http://en.wikipedia.org/wiki/MIT_License
+
+Copyright (c) 2011 by Harvest
+*/
+(function(){var Chosen,SelectParser,get_side_border_padding,root;var __bind=function(fn,me){return function(){return fn.apply(me,arguments);};};root=typeof exports!=="undefined"&&exports!==null?exports:this;Chosen=(function(){function Chosen(elmn){this.set_default_values();this.form_field=elmn;this.is_multiple=this.form_field.multiple;this.default_text_default=this.form_field.multiple?"Select Some Options":"Select an Option";this.set_up_html();this.register_observers();}Chosen.prototype.set_default_values=function(){this.click_test_action=__bind(function(evt){return this.test_active_click(evt);},this);this.active_field=false;this.mouse_on_container=false;this.results_showing=false;this.result_highlighted=null;this.result_single_selected=null;this.choices=0;this.single_temp=new Template('<a href="javascript:void(0)" class="chzn-single"><span>#{default}</span><div><b></b></div></a><div class="chzn-drop" style="left:-9000px;"><div class="chzn-search"><input type="text" /></div><ul class="chzn-results"></ul></div>');this.multi_temp=new Template('<ul class="chzn-choices"><li class="search-field"><input type="text" value="#{default}" class="default" style="width:25px;" /></li></ul><div class="chzn-drop" style="left:-9000px;"><ul class="chzn-results"></ul></div>');this.choice_temp=new Template('<li class="search-choice" id="#{id}"><span>#{choice}</span><a href="javascript:void(0)" class="search-choice-close" rel="#{position}"></a></li>');return this.no_results_temp=new Template('<li class="no-results">No results match "<span>#{terms}</span>"</li>');};Chosen.prototype.set_up_html=function(){var base_template,container_props,dd_top,dd_width,sf_width;this.container_id=this.form_field.id+"_chzn";this.f_width=this.form_field.getStyle("width")?parseInt(this.form_field.getStyle("width"),10):this.form_field.getWidth();container_props={id:this.container_id,"class":"chzn-container",style:"width: "+this.f_width+"px"};this.default_text=this.form_field.readAttribute("title")?this.form_field.readAttribute("title"):this.default_text_default;base_template=this.is_multiple?new Element("div",container_props).update(this.multi_temp.evaluate({"default":this.default_text})):new Element("div",container_props).update(this.single_temp.evaluate({"default":this.default_text}));this.form_field.hide().insert({after:base_template});this.container=$(this.container_id);this.container.addClassName("chzn-container-"+(this.is_multiple?"multi":"single"));this.dropdown=this.container.down("div.chzn-drop");dd_top=this.container.getHeight();dd_width=this.f_width-get_side_border_padding(this.dropdown);this.dropdown.setStyle({width:dd_width+"px",top:dd_top+"px"});this.search_field=this.container.down("input");this.search_results=this.container.down("ul.chzn-results");this.search_field_scale();this.search_no_results=this.container.down("li.no-results");if(this.is_multiple){this.search_choices=this.container.down("ul.chzn-choices");this.search_container=this.container.down("li.search-field");}else{this.search_container=this.container.down("div.chzn-search");this.selected_item=this.container.down(".chzn-single");sf_width=dd_width-get_side_border_padding(this.search_container)-get_side_border_padding(this.search_field);this.search_field.setStyle({width:sf_width+"px"});}this.results_build();return this.set_tab_index();};Chosen.prototype.register_observers=function(){this.container.observe("click",__bind(function(evt){return this.container_click(evt);},this));this.container.observe("mouseenter",__bind(function(evt){return this.mouse_enter(evt);},this));this.container.observe("mouseleave",__bind(function(evt){return this.mouse_leave(evt);},this));this.search_results.observe("click",__bind(function(evt){return this.search_results_click(evt);},this));this.search_results.observe("mouseover",__bind(function(evt){return this.search_results_mouseover(evt);},this));this.search_results.observe("mouseout",__bind(function(evt){return this.search_results_mouseout(evt);},this));this.form_field.observe("liszt:updated",__bind(function(evt){return this.results_update_field(evt);},this));this.search_field.observe("blur",__bind(function(evt){return this.input_blur(evt);},this));this.search_field.observe("keyup",__bind(function(evt){return this.keyup_checker(evt);},this));this.search_field.observe("keydown",__bind(function(evt){return this.keydown_checker(evt);},this));if(this.is_multiple){this.search_choices.observe("click",__bind(function(evt){return this.choices_click(evt);},this));return this.search_field.observe("focus",__bind(function(evt){return this.input_focus(evt);},this));}else{return this.selected_item.observe("focus",__bind(function(evt){return this.activate_field(evt);},this));}};Chosen.prototype.container_click=function(evt){if(evt&&evt.type==="click"){evt.stop();}if(!this.pending_destroy_click){if(!this.active_field){if(this.is_multiple){this.search_field.clear();}document.observe("click",this.click_test_action);this.results_show();}else{if(!this.is_multiple&&evt&&(evt.target===this.selected_item||evt.target.up("a.chzn-single"))){this.results_toggle();}}return this.activate_field();}else{return this.pending_destroy_click=false;}};Chosen.prototype.mouse_enter=function(){return this.mouse_on_container=true;};Chosen.prototype.mouse_leave=function(){return this.mouse_on_container=false;};Chosen.prototype.input_focus=function(evt){if(!this.active_field){return setTimeout(this.container_click.bind(this),50);}};Chosen.prototype.input_blur=function(evt){if(!this.mouse_on_container){this.active_field=false;return setTimeout(this.blur_test.bind(this),100);}};Chosen.prototype.blur_test=function(evt){if(!this.active_field&&this.container.hasClassName("chzn-container-active")){return this.close_field();}};Chosen.prototype.close_field=function(){document.stopObserving("click",this.click_test_action);if(!this.is_multiple){this.selected_item.tabIndex=this.search_field.tabIndex;this.search_field.tabIndex=-1;}this.active_field=false;this.results_hide();this.container.removeClassName("chzn-container-active");this.winnow_results_clear();this.clear_backstroke();this.show_search_field_default();return this.search_field_scale();};Chosen.prototype.activate_field=function(){if(!this.is_multiple&&!this.active_field){this.search_field.tabIndex=this.selected_item.tabIndex;this.selected_item.tabIndex=-1;}this.container.addClassName("chzn-container-active");this.active_field=true;this.search_field.value=this.search_field.value;return this.search_field.focus();};Chosen.prototype.test_active_click=function(evt){if(evt.target.up("#"+this.container.id)){return this.active_field=true;}else{return this.close_field();}};Chosen.prototype.results_build=function(){var content,data,startTime,_i,_len,_ref;startTime=new Date();this.parsing=true;this.results_data=SelectParser.select_to_array(this.form_field);if(this.is_multiple&&this.choices>0){this.search_choices.select("li.search-choice").invoke("remove");this.choices=0;}else{if(!this.is_multiple){this.selected_item.down("span").update(this.default_text);}}content="";_ref=this.results_data;for(_i=0,_len=_ref.length;_i<_len;_i++){data=_ref[_i];if(data.group){content+=this.result_add_group(data);}else{if(!data.empty){content+=this.result_add_option(data);if(data.selected&&this.is_multiple){this.choice_build(data);}else{if(data.selected&&!this.is_multiple){this.selected_item.down("span").update(data.text);}}}}}this.show_search_field_default();this.search_field_scale();this.search_results.update(content);return this.parsing=false;};Chosen.prototype.result_add_group=function(group){if(!group.disabled){group.dom_id=this.form_field.id+"chzn_g_"+group.array_index;return'<li id="'+group.dom_id+'" class="group-result">'+group.label.escapeHTML()+"</li>";}else{return"";}};Chosen.prototype.result_add_option=function(option){var classes;if(!option.disabled){option.dom_id=this.form_field.id+"chzn_o_"+option.array_index;classes=option.selected&&this.is_multiple?[]:["active-result"];if(option.selected){classes.push("result-selected");}if(option.group_array_index!=null){classes.push("group-option");}return'<li id="'+option.dom_id+'" class="'+classes.join(" ")+'">'+option.text.escapeHTML()+"</li>";}else{return"";}};Chosen.prototype.results_update_field=function(){this.result_clear_highlight();this.result_single_selected=null;return this.results_build();};Chosen.prototype.result_do_highlight=function(el){var high_bottom,high_top,maxHeight,visible_bottom,visible_top;this.result_clear_highlight();this.result_highlight=el;this.result_highlight.addClassName("highlighted");maxHeight=parseInt(this.search_results.getStyle("maxHeight"),10);visible_top=this.search_results.scrollTop;visible_bottom=maxHeight+visible_top;high_top=this.result_highlight.positionedOffset().top;high_bottom=high_top+this.result_highlight.getHeight();if(high_bottom>=visible_bottom){return this.search_results.scrollTop=(high_bottom-maxHeight)>0?high_bottom-maxHeight:0;}else{if(high_top<visible_top){return this.search_results.scrollTop=high_top;}}};Chosen.prototype.result_clear_highlight=function(){if(this.result_highlight){this.result_highlight.removeClassName("highlighted");}return this.result_highlight=null;};Chosen.prototype.results_toggle=function(){if(this.results_showing){return this.results_hide();}else{return this.results_show();}};Chosen.prototype.results_show=function(){var dd_top;if(!this.is_multiple){this.selected_item.addClassName("chzn-single-with-drop");if(this.result_single_selected){this.result_do_highlight(this.result_single_selected);}}dd_top=this.is_multiple?this.container.getHeight():this.container.getHeight()-1;this.dropdown.setStyle({top:dd_top+"px",left:0});this.results_showing=true;this.search_field.focus();this.search_field.value=this.search_field.value;return this.winnow_results();};Chosen.prototype.results_hide=function(){if(!this.is_multiple){this.selected_item.removeClassName("chzn-single-with-drop");}this.result_clear_highlight();this.dropdown.setStyle({left:"-9000px"});return this.results_showing=false;};Chosen.prototype.set_tab_index=function(el){var ti;if(this.form_field.tabIndex){ti=this.form_field.tabIndex;this.form_field.tabIndex=-1;if(this.is_multiple){return this.search_field.tabIndex=ti;}else{this.selected_item.tabIndex=ti;return this.search_field.tabIndex=-1;}}};Chosen.prototype.show_search_field_default=function(){if(this.is_multiple&&this.choices<1&&!this.active_field){this.search_field.value=this.default_text;return this.search_field.addClassName("default");}else{this.search_field.value="";return this.search_field.removeClassName("default");}};Chosen.prototype.search_results_click=function(evt){var target;target=evt.target.hasClassName("active-result")?evt.target:evt.target.up(".active-result");if(target){this.result_highlight=target;return this.result_select();}};Chosen.prototype.search_results_mouseover=function(evt){var target;target=evt.target.hasClassName("active-result")?evt.target:evt.target.up(".active-result");if(target){return this.result_do_highlight(target);}};Chosen.prototype.search_results_mouseout=function(evt){if(evt.target.hasClassName("active-result")||evt.target.up(".active-result")){return this.result_clear_highlight();}};Chosen.prototype.choices_click=function(evt){evt.preventDefault();if(this.active_field&&!(evt.target.hasClassName("search-choice")||evt.target.up(".search-choice"))&&!this.results_showing){return this.results_show();}};Chosen.prototype.choice_build=function(item){var choice_id,link;choice_id=this.form_field.id+"_chzn_c_"+item.array_index;this.choices+=1;this.search_container.insert({before:this.choice_temp.evaluate({id:choice_id,choice:item.text,position:item.array_index})});link=$(choice_id).down("a");return link.observe("click",__bind(function(evt){return this.choice_destroy_link_click(evt);},this));};Chosen.prototype.choice_destroy_link_click=function(evt){evt.preventDefault();this.pending_destroy_click=true;return this.choice_destroy(evt.target);};Chosen.prototype.choice_destroy=function(link){this.choices-=1;this.show_search_field_default();if(this.is_multiple&&this.choices>0&&this.search_field.value.length<1){this.results_hide();}this.result_deselect(link.readAttribute("rel"));return link.up("li").remove();};Chosen.prototype.result_select=function(){var high,item,position;if(this.result_highlight){high=this.result_highlight;this.result_clear_highlight();high.addClassName("result-selected");if(this.is_multiple){this.result_deactivate(high);}else{this.result_single_selected=high;}position=high.id.substr(high.id.lastIndexOf("_")+1);item=this.results_data[position];item.selected=true;this.form_field.options[item.options_index].selected=true;if(this.is_multiple){this.choice_build(item);}else{this.selected_item.down("span").update(item.text);}this.results_hide();this.search_field.value="";if(typeof Event.simulate==="function"){this.form_field.simulate("change");}return this.search_field_scale();}};Chosen.prototype.result_activate=function(el){return el.addClassName("active-result").show();};Chosen.prototype.result_deactivate=function(el){return el.removeClassName("active-result").hide();};Chosen.prototype.result_deselect=function(pos){var result,result_data;result_data=this.results_data[pos];result_data.selected=false;this.form_field.options[result_data.options_index].selected=false;result=$(this.form_field.id+"chzn_o_"+pos);result.removeClassName("result-selected").addClassName("active-result").show();this.result_clear_highlight();this.winnow_results();if(typeof Event.simulate==="function"){this.form_field.simulate("change");}return this.search_field_scale();};Chosen.prototype.results_search=function(evt){if(this.results_showing){return this.winnow_results();}else{return this.results_show();}};Chosen.prototype.winnow_results=function(){var found,option,part,parts,regex,result_id,results,searchText,startTime,startpos,text,zregex,_i,_j,_len,_len2,_ref;startTime=new Date();this.no_results_clear();results=0;searchText=this.search_field.value===this.default_text?"":this.search_field.value.strip();regex=new RegExp("^"+searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i");zregex=new RegExp(searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i");_ref=this.results_data;for(_i=0,_len=_ref.length;_i<_len;_i++){option=_ref[_i];if(!option.disabled&&!option.empty){if(option.group){$(option.dom_id).hide();}else{if(!(this.is_multiple&&option.selected)){found=false;result_id=option.dom_id;if(regex.test(option.text)){found=true;results+=1;}else{if(option.text.indexOf(" ")>=0||option.text.indexOf("[")===0){parts=option.text.replace(/\[|\]/g,"").split(" ");if(parts.length){for(_j=0,_len2=parts.length;_j<_len2;_j++){part=parts[_j];if(regex.test(part)){found=true;results+=1;}}}}}if(found){if(searchText.length){startpos=option.text.search(zregex);text=option.text.substr(0,startpos+searchText.length)+"</em>"+option.text.substr(startpos+searchText.length);text=text.substr(0,startpos)+"<em>"+text.substr(startpos);}else{text=option.text;}if($(result_id).innerHTML!==text){$(result_id).update(text);}this.result_activate($(result_id));if(option.group_array_index!=null){$(this.results_data[option.group_array_index].dom_id).show();}}else{if($(result_id)===this.result_highlight){this.result_clear_highlight();}this.result_deactivate($(result_id));}}}}}if(results<1&&searchText.length){return this.no_results(searchText);}else{return this.winnow_results_set_highlight();}};Chosen.prototype.winnow_results_clear=function(){var li,lis,_i,_len,_results;this.search_field.clear();lis=this.search_results.select("li");_results=[];for(_i=0,_len=lis.length;_i<_len;_i++){li=lis[_i];_results.push(li.hasClassName("group-result")?li.show():!this.is_multiple||!li.hasClassName("result-selected")?this.result_activate(li):void 0);}return _results;};Chosen.prototype.winnow_results_set_highlight=function(){var do_high;if(!this.result_highlight){do_high=this.search_results.down(".active-result");if(do_high){return this.result_do_highlight(do_high);}}};Chosen.prototype.no_results=function(terms){return this.search_results.insert(this.no_results_temp.evaluate({terms:terms.escapeHTML()}));};Chosen.prototype.no_results_clear=function(){var nr,_results;nr=null;_results=[];while(nr=this.search_results.down(".no-results")){_results.push(nr.remove());}return _results;};Chosen.prototype.keydown_arrow=function(){var actives,nexts,sibs;actives=this.search_results.select("li.active-result");if(actives.length){if(!this.result_highlight){this.result_do_highlight(actives.first());}else{if(this.results_showing){sibs=this.result_highlight.nextSiblings();nexts=sibs.intersect(actives);if(nexts.length){this.result_do_highlight(nexts.first());}}}if(!this.results_showing){return this.results_show();}}};Chosen.prototype.keyup_arrow=function(){var actives,prevs,sibs;if(!this.results_showing&&!this.is_multiple){return this.results_show();}else{if(this.result_highlight){sibs=this.result_highlight.previousSiblings();actives=this.search_results.select("li.active-result");prevs=sibs.intersect(actives);if(prevs.length){return this.result_do_highlight(prevs.first());}else{if(this.choices>0){this.results_hide();}return this.result_clear_highlight();}}}};Chosen.prototype.keydown_backstroke=function(){if(this.pending_backstroke){this.choice_destroy(this.pending_backstroke.down("a"));return this.clear_backstroke();}else{this.pending_backstroke=this.search_container.siblings("li.search-choice").last();return this.pending_backstroke.addClassName("search-choice-focus");}};Chosen.prototype.clear_backstroke=function(){if(this.pending_backstroke){this.pending_backstroke.removeClassName("search-choice-focus");}return this.pending_backstroke=null;};Chosen.prototype.keyup_checker=function(evt){var stroke,_ref;stroke=(_ref=evt.which)!=null?_ref:evt.keyCode;this.search_field_scale();switch(stroke){case 8:if(this.is_multiple&&this.backstroke_length<1&&this.choices>0){return this.keydown_backstroke();}else{if(!this.pending_backstroke){this.result_clear_highlight();return this.results_search();}}break;case 13:evt.preventDefault();if(this.results_showing){return this.result_select();}break;case 27:if(this.results_showing){return this.results_hide();}break;case 9:case 38:case 40:case 16:break;default:return this.results_search();}};Chosen.prototype.keydown_checker=function(evt){var stroke,_ref;stroke=(_ref=evt.which)!=null?_ref:evt.keyCode;this.search_field_scale();if(stroke!==8&&this.pending_backstroke){this.clear_backstroke();}switch(stroke){case 8:return this.backstroke_length=this.search_field.value.length;case 9:return this.mouse_on_container=false;case 13:return evt.preventDefault();case 38:evt.preventDefault();return this.keyup_arrow();case 40:return this.keydown_arrow();}};Chosen.prototype.search_field_scale=function(){var dd_top,div,h,style,style_block,styles,w,_i,_len;if(this.is_multiple){h=0;w=0;style_block="position:absolute; left: -1000px; top: -1000px; display:none;";styles=["font-size","font-style","font-weight","font-family","line-height","text-transform","letter-spacing"];for(_i=0,_len=styles.length;_i<_len;_i++){style=styles[_i];style_block+=style+":"+this.search_field.getStyle(style)+";";}div=new Element("div",{style:style_block}).update(this.search_field.value);document.body.appendChild(div);w=Element.measure(div,"width")+25;div.remove();if(w>this.f_width-10){w=this.f_width-10;}this.search_field.setStyle({width:w+"px"});dd_top=this.container.getHeight();return this.dropdown.setStyle({top:dd_top+"px"});}};return Chosen;})();root.Chosen=Chosen;document.observe("dom:loaded",function(evt){var select,selects,_i,_len,_results;selects=$$(".chzn-select");_results=[];for(_i=0,_len=selects.length;_i<_len;_i++){select=selects[_i];_results.push(new Chosen(select));}return _results;});get_side_border_padding=function(elmt){var layout,side_border_padding;layout=new Element.Layout(elmt);return side_border_padding=layout.get("border-left")+layout.get("border-right")+layout.get("padding-left")+layout.get("padding-right");};root.get_side_border_padding=get_side_border_padding;root=typeof exports!=="undefined"&&exports!==null?exports:this;SelectParser=(function(){function SelectParser(){this.options_index=0;this.parsed=[];}SelectParser.prototype.add_node=function(child){if(child.nodeName==="OPTGROUP"){return this.add_group(child);}else{return this.add_option(child);}};SelectParser.prototype.add_group=function(group){var group_position,option,_i,_len,_ref,_results;group_position=this.parsed.length;this.parsed.push({array_index:group_position,group:true,label:group.label,children:0,disabled:group.disabled});_ref=group.childNodes;_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){option=_ref[_i];_results.push(this.add_option(option,group_position,group.disabled));}return _results;};SelectParser.prototype.add_option=function(option,group_position,group_disabled){if(option.nodeName==="OPTION"){if(option.text!==""){if(group_position!=null){this.parsed[group_position].children+=1;}this.parsed.push({array_index:this.parsed.length,options_index:this.options_index,value:option.value,text:option.text,selected:option.selected,disabled:group_disabled===true?group_disabled:option.disabled,group_array_index:group_position});}else{this.parsed.push({array_index:this.parsed.length,options_index:this.options_index,empty:true});}return this.options_index+=1;}};return SelectParser;})();SelectParser.select_to_array=function(select){var child,parser,_i,_len,_ref;parser=new SelectParser();_ref=select.childNodes;for(_i=0,_len=_ref.length;_i<_len;_i++){child=_ref[_i];parser.add_node(child);}return parser.parsed;};root.SelectParser=SelectParser;}).call(this); \ No newline at end of file
diff --git a/usr/local/www/javascript/chosen/coffee/chosen.jquery.coffee b/usr/local/www/javascript/chosen/coffee/chosen.jquery.coffee
new file mode 100644
index 0000000..0d6596a
--- /dev/null
+++ b/usr/local/www/javascript/chosen/coffee/chosen.jquery.coffee
@@ -0,0 +1,633 @@
+###
+Chosen, a Select Box Enhancer for jQuery and Protoype
+by Patrick Filler for Harvest, http://getharvest.com
+
+Available for use under the MIT License, http://en.wikipedia.org/wiki/MIT_License
+
+Copyright (c) 2011 by Harvest
+###
+
+root = exports ? this
+$ = jQuery
+
+$.fn.extend({
+ chosen: (data, options) ->
+ $(this).each((input_field) ->
+ new Chosen(this, data, options) unless ($ this).hasClass "chzn-done"
+ )
+})
+
+class Chosen
+
+ constructor: (elmn) ->
+ this.set_default_values()
+
+ @form_field = elmn
+ @form_field_jq = $ @form_field
+ @is_multiple = @form_field.multiple
+
+ @default_text_default = if @form_field.multiple then "Select Some Options" else "Select an Option"
+
+ this.set_up_html()
+ this.register_observers()
+ @form_field_jq.addClass "chzn-done"
+
+ set_default_values: ->
+
+ @click_test_action = (evt) => this.test_active_click(evt)
+ @active_field = false
+ @mouse_on_container = false
+ @results_showing = false
+ @result_highlighted = null
+ @result_single_selected = null
+ @choices = 0
+
+ set_up_html: ->
+ @container_id = @form_field.id + "_chzn"
+
+ @f_width = @form_field_jq.width()
+
+ @default_text = if @form_field_jq.attr 'title' then @form_field_jq.attr 'title' else @default_text_default
+
+ container_div = ($ "<div />", {
+ id: @container_id
+ class: 'chzn-container'
+ style: 'width: ' + (@f_width) + 'px;' #use parens around @f_width so coffeescript doesn't think + ' px' is a function parameter
+ })
+
+ if @is_multiple
+ container_div.html '<ul class="chzn-choices"><li class="search-field"><input type="text" value="' + @default_text + '" class="default" style="width:25px;" /></li></ul><div class="chzn-drop" style="left:-9000px;"><ul class="chzn-results"></ul></div>'
+ else
+ container_div.html '<a href="javascript:void(0)" class="chzn-single"><span>' + @default_text + '</span><div><b></b></div></a><div class="chzn-drop" style="left:-9000px;"><div class="chzn-search"><input type="text" /></div><ul class="chzn-results"></ul></div>'
+
+ @form_field_jq.hide().after container_div
+ @container = ($ '#' + @container_id)
+ @container.addClass( "chzn-container-" + (if @is_multiple then "multi" else "single") )
+ @dropdown = @container.find('div.chzn-drop').first()
+
+ dd_top = @container.height()
+ dd_width = (@f_width - get_side_border_padding(@dropdown))
+
+ @dropdown.css({"width": dd_width + "px", "top": dd_top + "px"})
+
+ @search_field = @container.find('input').first()
+ @search_results = @container.find('ul.chzn-results').first()
+ this.search_field_scale()
+
+ @search_no_results = @container.find('li.no-results').first()
+
+ if @is_multiple
+ @search_choices = @container.find('ul.chzn-choices').first()
+ @search_container = @container.find('li.search-field').first()
+ else
+ @search_container = @container.find('div.chzn-search').first()
+ @selected_item = @container.find('.chzn-single').first()
+ sf_width = dd_width - get_side_border_padding(@search_container) - get_side_border_padding(@search_field)
+ @search_field.css( {"width" : sf_width + "px"} )
+
+ this.results_build()
+ this.set_tab_index()
+
+
+ register_observers: ->
+ @container.click (evt) => this.container_click(evt)
+ @container.mouseenter (evt) => this.mouse_enter(evt)
+ @container.mouseleave (evt) => this.mouse_leave(evt)
+
+ @search_results.click (evt) => this.search_results_click(evt)
+ @search_results.mouseover (evt) => this.search_results_mouseover(evt)
+ @search_results.mouseout (evt) => this.search_results_mouseout(evt)
+
+ @form_field_jq.bind "liszt:updated", (evt) => this.results_update_field(evt)
+
+ @search_field.blur (evt) => this.input_blur(evt)
+ @search_field.keyup (evt) => this.keyup_checker(evt)
+ @search_field.keydown (evt) => this.keydown_checker(evt)
+
+ if @is_multiple
+ @search_choices.click (evt) => this.choices_click(evt)
+ @search_field.focus (evt) => this.input_focus(evt)
+ else
+ @selected_item.focus (evt) => this.activate_field(evt)
+
+ container_click: (evt) ->
+ if evt and evt.type is "click"
+ evt.stopPropagation()
+ if not @pending_destroy_click
+ if not @active_field
+ @search_field.val "" if @is_multiple
+ $(document).click @click_test_action
+ this.results_show()
+ else if not @is_multiple and evt and ($(evt.target) is @selected_item || $(evt.target).parents("a.chzn-single").length)
+ evt.preventDefault()
+ this.results_toggle()
+
+ this.activate_field()
+ else
+ @pending_destroy_click = false
+
+ mouse_enter: -> @mouse_on_container = true
+ mouse_leave: -> @mouse_on_container = false
+
+ input_focus: (evt) ->
+ setTimeout (=> this.container_click()), 50 unless @active_field
+
+ input_blur: (evt) ->
+ if not @mouse_on_container
+ @active_field = false
+ setTimeout (=> this.blur_test()), 100
+
+ blur_test: (evt) ->
+ this.close_field() if not @active_field and @container.hasClass "chzn-container-active"
+
+ close_field: ->
+ $(document).unbind "click", @click_test_action
+
+ if not @is_multiple
+ @selected_item.attr "tabindex", @search_field.attr("tabindex")
+ @search_field.attr "tabindex", -1
+
+ @active_field = false
+ this.results_hide()
+
+ @container.removeClass "chzn-container-active"
+ this.winnow_results_clear()
+ this.clear_backstroke()
+
+ this.show_search_field_default()
+ this.search_field_scale()
+
+ activate_field: ->
+ if not @is_multiple and not @active_field
+ @search_field.attr "tabindex", (@selected_item.attr "tabindex")
+ @selected_item.attr "tabindex", -1
+
+ @container.addClass "chzn-container-active"
+ @active_field = true
+
+ @search_field.val(@search_field.val())
+ @search_field.focus()
+
+
+ test_active_click: (evt) ->
+ if $(evt.target).parents('#' + @container.id).length
+ @active_field = true
+ else
+ this.close_field()
+
+ results_build: ->
+ startTime = new Date()
+ @parsing = true
+ @results_data = SelectParser.select_to_array @form_field
+
+ if @is_multiple and @choices > 0
+ @search_choices.find("li.search-choice").remove()
+ @choices = 0
+ else if not @is_multiple
+ @selected_item.find("span").text @default_text
+
+ content = ''
+ for data in @results_data
+ if data.group
+ content += this.result_add_group data
+ else if !data.empty
+ content += this.result_add_option data
+ if data.selected and @is_multiple
+ this.choice_build data
+ else if data.selected and not @is_multiple
+ @selected_item.find("span").text data.text
+
+ this.show_search_field_default()
+ this.search_field_scale()
+
+ @search_results.html content
+ @parsing = false
+
+
+ result_add_group: (group) ->
+ if not group.disabled
+ group.dom_id = @form_field.id + "chzn_g_" + group.array_index
+ '<li id="' + group.dom_id + '" class="group-result">' + $("<div />").text(group.label).html() + '</li>'
+ else
+ ""
+
+ result_add_option: (option) ->
+ if not option.disabled
+ option.dom_id = @form_field.id + "chzn_o_" + option.array_index
+
+ classes = if option.selected and @is_multiple then [] else ["active-result"]
+ classes.push "result-selected" if option.selected
+ classes.push "group-option" if option.group_array_index?
+
+ '<li id="' + option.dom_id + '" class="' + classes.join(' ') + '">' + $("<div />").text(option.text).html() + '</li>'
+ else
+ ""
+
+ results_update_field: ->
+ this.result_clear_highlight()
+ @result_single_selected = null
+ this.results_build()
+
+ result_do_highlight: (el) ->
+ if el.length
+ this.result_clear_highlight()
+
+ @result_highlight = el
+ @result_highlight.addClass "highlighted"
+
+ maxHeight = parseInt @search_results.css("maxHeight"), 10
+ visible_top = @search_results.scrollTop()
+ visible_bottom = maxHeight + visible_top
+
+ high_top = @result_highlight.position().top + @search_results.scrollTop()
+ high_bottom = high_top + @result_highlight.outerHeight()
+
+ if high_bottom >= visible_bottom
+ @search_results.scrollTop if (high_bottom - maxHeight) > 0 then (high_bottom - maxHeight) else 0
+ else if high_top < visible_top
+ @search_results.scrollTop high_top
+
+ result_clear_highlight: ->
+ @result_highlight.removeClass "highlighted" if @result_highlight
+ @result_highlight = null
+
+ results_toggle: ->
+ if @results_showing
+ this.results_hide()
+ else
+ this.results_show()
+
+ results_show: ->
+ if not @is_multiple
+ @selected_item.addClass "chzn-single-with-drop"
+ if @result_single_selected
+ this.result_do_highlight( @result_single_selected )
+
+ dd_top = if @is_multiple then @container.height() else (@container.height() - 1)
+ @dropdown.css {"top": dd_top + "px", "left":0}
+ @results_showing = true
+
+ @search_field.focus()
+ @search_field.val @search_field.val()
+
+ this.winnow_results()
+
+ results_hide: ->
+ @selected_item.removeClass "chzn-single-with-drop" unless @is_multiple
+ this.result_clear_highlight()
+ @dropdown.css {"left":"-9000px"}
+ @results_showing = false
+
+
+ set_tab_index: (el) ->
+ if @form_field_jq.attr "tabindex"
+ ti = @form_field_jq.attr "tabindex"
+ @form_field_jq.attr "tabindex", -1
+
+ if @is_multiple
+ @search_field.attr "tabindex", ti
+ else
+ @selected_item.attr "tabindex", ti
+ @search_field.attr "tabindex", -1
+
+ show_search_field_default: ->
+ if @is_multiple and @choices < 1 and not @active_field
+ @search_field.val(@default_text)
+ @search_field.addClass "default"
+ else
+ @search_field.val("")
+ @search_field.removeClass "default"
+
+ search_results_click: (evt) ->
+ target = if $(evt.target).hasClass "active-result" then $(evt.target) else $(evt.target).parents(".active-result").first()
+ if target.length
+ @result_highlight = target
+ this.result_select()
+
+ search_results_mouseover: (evt) ->
+ target = if $(evt.target).hasClass "active-result" then $(evt.target) else $(evt.target).parents(".active-result").first()
+ this.result_do_highlight( target ) if target
+
+ search_results_mouseout: (evt) ->
+ this.result_clear_highlight() if $(evt.target).hasClass "active-result" or $(evt.target).parents('.active-result').first()
+
+
+ choices_click: (evt) ->
+ evt.preventDefault()
+ if( @active_field and not($(evt.target).hasClass "search-choice" or $(evt.target).parents('.search-choice').first) and not @results_showing )
+ this.results_show()
+
+ choice_build: (item) ->
+ choice_id = @form_field.id + "_chzn_c_" + item.array_index
+ @choices += 1
+ @search_container.before '<li class="search-choice" id="' + choice_id + '"><span>' + item.text + '</span><a href="javascript:void(0)" class="search-choice-close" rel="' + item.array_index + '"></a></li>'
+ link = $('#' + choice_id).find("a").first()
+ link.click (evt) => this.choice_destroy_link_click(evt)
+
+ choice_destroy_link_click: (evt) ->
+ evt.preventDefault()
+ @pending_destroy_click = true
+ this.choice_destroy $(evt.target)
+
+ choice_destroy: (link) ->
+ @choices -= 1
+ this.show_search_field_default()
+
+ this.results_hide() if @is_multiple and @choices > 0 and @search_field.val().length < 1
+
+ this.result_deselect (link.attr "rel")
+ link.parents('li').first().remove()
+
+ result_select: ->
+ if @result_highlight
+ high = @result_highlight
+ high_id = high.attr "id"
+
+ this.result_clear_highlight()
+
+ high.addClass "result-selected"
+
+ if @is_multiple
+ this.result_deactivate high
+ else
+ @result_single_selected = high
+
+ position = high_id.substr(high_id.lastIndexOf("_") + 1 )
+ item = @results_data[position]
+ item.selected = true
+
+ @form_field.options[item.options_index].selected = true
+
+ if @is_multiple
+ this.choice_build item
+ else
+ @selected_item.find("span").first().text item.text
+
+ this.results_hide()
+ @search_field.val ""
+
+ @form_field_jq.trigger "change"
+ this.search_field_scale()
+
+ result_activate: (el) ->
+ el.addClass("active-result").show()
+
+ result_deactivate: (el) ->
+ el.removeClass("active-result").hide()
+
+ result_deselect: (pos) ->
+ result_data = @results_data[pos]
+ result_data.selected = false
+
+ @form_field.options[result_data.options_index].selected = false
+ result = $("#" + @form_field.id + "chzn_o_" + pos)
+ result.removeClass("result-selected").addClass("active-result").show()
+
+ this.result_clear_highlight()
+ this.winnow_results()
+
+ @form_field_jq.trigger "change"
+ this.search_field_scale()
+
+ results_search: (evt) ->
+ if @results_showing
+ this.winnow_results()
+ else
+ this.results_show()
+
+ winnow_results: ->
+ startTime = new Date()
+ this.no_results_clear()
+
+ results = 0
+
+ searchText = if @search_field.val() is @default_text then "" else $.trim @search_field.val()
+ regex = new RegExp('^' + searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i')
+ zregex = new RegExp(searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i')
+
+ for option in @results_data
+ if not option.disabled and not option.empty
+ if option.group
+ $('#' + option.dom_id).hide()
+ else if not (@is_multiple and option.selected)
+ found = false
+ result_id = option.dom_id
+
+ if regex.test option.text
+ found = true
+ results += 1
+ else if option.text.indexOf(" ") >= 0 or option.text.indexOf("[") == 0
+ #TODO: replace this substitution of /\[\]/ with a list of characters to skip.
+ parts = option.text.replace(/\[|\]/g, "").split(" ")
+ if parts.length
+ for part in parts
+ if regex.test part
+ found = true
+ results += 1
+
+ if found
+ if searchText.length
+ startpos = option.text.search zregex
+ text = option.text.substr(0, startpos + searchText.length) + '</em>' + option.text.substr(startpos + searchText.length)
+ text = text.substr(0, startpos) + '<em>' + text.substr(startpos)
+ else
+ text = option.text
+
+ $("#" + result_id).html text if $("#" + result_id).html != text
+
+ this.result_activate $("#" + result_id)
+
+ $("#" + @results_data[option.group_array_index].dom_id).show() if option.group_array_index?
+ else
+ this.result_clear_highlight() if @result_highlight and result_id is @result_highlight.attr 'id'
+ this.result_deactivate $("#" + result_id)
+
+ if results < 1 and searchText.length
+ this.no_results searchText
+ else
+ this.winnow_results_set_highlight()
+
+ winnow_results_clear: ->
+ @search_field.val ""
+ lis = @search_results.find("li")
+
+ for li in lis
+ li = $(li)
+ if li.hasClass "group-result"
+ li.show()
+ else if not @is_multiple or not li.hasClass "result-selected"
+ this.result_activate li
+
+ winnow_results_set_highlight: ->
+ if not @result_highlight
+ do_high = @search_results.find(".active-result").first()
+ if(do_high)
+ this.result_do_highlight do_high
+
+ no_results: (terms) ->
+ no_results_html = $('<li class="no-results">No results match "<span></span>"</li>')
+ no_results_html.find("span").first().text(terms)
+
+ @search_results.append no_results_html
+
+ no_results_clear: ->
+ @search_results.find(".no-results").remove()
+
+ keydown_arrow: ->
+ if not @result_highlight
+ first_active = @search_results.find("li.active-result").first()
+ this.result_do_highlight $(first_active) if first_active
+ else if @results_showing
+ next_sib = @result_highlight.nextAll("li.active-result").first()
+ this.result_do_highlight next_sib if next_sib
+ this.results_show() if not @results_showing
+
+ keyup_arrow: ->
+ if not @results_showing and not @is_multiple
+ this.results_show()
+ else if @result_highlight
+ prev_sibs = @result_highlight.prevAll("li.active-result")
+
+ if prev_sibs.length
+ this.result_do_highlight prev_sibs.first()
+ else
+ this.results_hide() if @choices > 0
+ this.result_clear_highlight()
+
+ keydown_backstroke: ->
+ if @pending_backstroke
+ this.choice_destroy @pending_backstroke.find("a").first()
+ this.clear_backstroke()
+ else
+ @pending_backstroke = @search_container.siblings("li.search-choice").last()
+ @pending_backstroke.addClass "search-choice-focus"
+
+ clear_backstroke: ->
+ @pending_backstroke.removeClass "search-choice-focus" if @pending_backstroke
+ @pending_backstroke = null
+
+ keyup_checker: (evt) ->
+ stroke = evt.which ? evt.keyCode
+ this.search_field_scale()
+
+ switch stroke
+ when 8
+ if @is_multiple and @backstroke_length < 1 and @choices > 0
+ this.keydown_backstroke()
+ else if not @pending_backstroke
+ this.result_clear_highlight()
+ this.results_search()
+ when 13
+ evt.preventDefault()
+ this.result_select() if this.results_showing
+ when 27
+ this.results_hide() if @results_showing
+ when 9, 38, 40, 16
+ # don't do anything on these keys
+ else this.results_search()
+
+
+ keydown_checker: (evt) ->
+ stroke = evt.which ? evt.keyCode
+ this.search_field_scale()
+
+ this.clear_backstroke() if stroke != 8 and this.pending_backstroke
+
+ switch stroke
+ when 8
+ @backstroke_length = this.search_field.val().length
+ break
+ when 9
+ @mouse_on_container = false
+ break
+ when 13
+ evt.preventDefault()
+ break
+ when 38
+ evt.preventDefault()
+ this.keyup_arrow()
+ break
+ when 40
+ this.keydown_arrow()
+ break
+
+
+ search_field_scale: ->
+ if @is_multiple
+ h = 0
+ w = 0
+
+ style_block = "position:absolute; left: -1000px; top: -1000px; display:none;"
+ styles = ['font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing']
+
+ for style in styles
+ style_block += style + ":" + @search_field.css(style) + ";"
+
+ div = $('<div />', { 'style' : style_block })
+ div.text @search_field.val()
+ $('body').append div
+
+ w = div.width() + 25
+ div.remove()
+
+ if( w > @f_width-10 )
+ w = @f_width - 10
+
+ @search_field.css({'width': w + 'px'})
+
+ dd_top = @container.height()
+ @dropdown.css({"top": dd_top + "px"})
+
+get_side_border_padding = (elmt) ->
+ side_border_padding = elmt.outerWidth() - elmt.width()
+
+root.get_side_border_padding = get_side_border_padding
+
+class SelectParser
+
+ constructor: ->
+ @options_index = 0
+ @parsed = []
+
+ add_node: (child) ->
+ if child.nodeName is "OPTGROUP"
+ this.add_group child
+ else
+ this.add_option child
+
+ add_group: (group) ->
+ group_position = @parsed.length
+ @parsed.push
+ array_index: group_position
+ group: true
+ label: group.label
+ children: 0
+ disabled: group.disabled
+ this.add_option( option, group_position, group.disabled ) for option in group.childNodes
+
+ add_option: (option, group_position, group_disabled) ->
+ if option.nodeName is "OPTION"
+ if option.text != ""
+ if group_position?
+ @parsed[group_position].children += 1
+ @parsed.push
+ array_index: @parsed.length
+ options_index: @options_index
+ value: option.value
+ text: option.text
+ selected: option.selected
+ disabled: if group_disabled is true then group_disabled else option.disabled
+ group_array_index: group_position
+ else
+ @parsed.push
+ array_index: @parsed.length
+ options_index: @options_index
+ empty: true
+ @options_index += 1
+
+SelectParser.select_to_array = (select) ->
+ parser = new SelectParser()
+ parser.add_node( child ) for child in select.childNodes
+ parser.parsed
+
+root.SelectParser = SelectParser
diff --git a/usr/local/www/javascript/chosen/coffee/chosen.proto.coffee b/usr/local/www/javascript/chosen/coffee/chosen.proto.coffee
new file mode 100644
index 0000000..87a22b6
--- /dev/null
+++ b/usr/local/www/javascript/chosen/coffee/chosen.proto.coffee
@@ -0,0 +1,629 @@
+###
+Chosen, a Select Box Enhancer for jQuery and Protoype
+by Patrick Filler for Harvest, http://getharvest.com
+
+Available for use under the MIT License, http://en.wikipedia.org/wiki/MIT_License
+
+Copyright (c) 2011 by Harvest
+###
+
+root = exports ? this
+
+class Chosen
+
+ constructor: (elmn) ->
+ this.set_default_values()
+
+ @form_field = elmn
+ @is_multiple = @form_field.multiple
+
+ @default_text_default = if @form_field.multiple then "Select Some Options" else "Select an Option"
+
+ this.set_up_html()
+ this.register_observers()
+
+
+ set_default_values: ->
+
+ @click_test_action = (evt) => this.test_active_click(evt)
+ @active_field = false
+ @mouse_on_container = false
+ @results_showing = false
+ @result_highlighted = null
+ @result_single_selected = null
+ @choices = 0
+
+ # HTML Templates
+ @single_temp = new Template('<a href="javascript:void(0)" class="chzn-single"><span>#{default}</span><div><b></b></div></a><div class="chzn-drop" style="left:-9000px;"><div class="chzn-search"><input type="text" /></div><ul class="chzn-results"></ul></div>')
+ @multi_temp = new Template('<ul class="chzn-choices"><li class="search-field"><input type="text" value="#{default}" class="default" style="width:25px;" /></li></ul><div class="chzn-drop" style="left:-9000px;"><ul class="chzn-results"></ul></div>')
+ @choice_temp = new Template('<li class="search-choice" id="#{id}"><span>#{choice}</span><a href="javascript:void(0)" class="search-choice-close" rel="#{position}"></a></li>')
+ @no_results_temp = new Template('<li class="no-results">No results match "<span>#{terms}</span>"</li>')
+
+
+ set_up_html: ->
+ @container_id = @form_field.id + "_chzn"
+
+ @f_width = if @form_field.getStyle("width") then parseInt @form_field.getStyle("width"), 10 else @form_field.getWidth()
+
+ container_props =
+ 'id': @container_id
+ 'class': 'chzn-container'
+ 'style': 'width: ' + (@f_width) + 'px' #use parens around @f_width so coffeescript doesn't think + ' px' is a function parameter
+
+ @default_text = if @form_field.readAttribute 'title' then @form_field.readAttribute 'title' else @default_text_default
+
+ base_template = if @is_multiple then new Element('div', container_props).update( @multi_temp.evaluate({ "default": @default_text}) ) else new Element('div', container_props).update( @single_temp.evaluate({ "default":@default_text }) )
+
+ @form_field.hide().insert({ after: base_template })
+ @container = $(@container_id)
+ @container.addClassName( "chzn-container-" + (if @is_multiple then "multi" else "single") )
+ @dropdown = @container.down('div.chzn-drop')
+
+ dd_top = @container.getHeight()
+ dd_width = (@f_width - get_side_border_padding(@dropdown))
+
+ @dropdown.setStyle({"width": dd_width + "px", "top": dd_top + "px"})
+
+ @search_field = @container.down('input')
+ @search_results = @container.down('ul.chzn-results')
+ this.search_field_scale()
+
+ @search_no_results = @container.down('li.no-results')
+
+ if @is_multiple
+ @search_choices = @container.down('ul.chzn-choices')
+ @search_container = @container.down('li.search-field')
+ else
+ @search_container = @container.down('div.chzn-search')
+ @selected_item = @container.down('.chzn-single')
+ sf_width = dd_width - get_side_border_padding(@search_container) - get_side_border_padding(@search_field)
+ @search_field.setStyle( {"width" : sf_width + "px"} )
+
+ this.results_build()
+ this.set_tab_index()
+
+
+ register_observers: ->
+ @container.observe "click", (evt) => this.container_click(evt)
+ @container.observe "mouseenter", (evt) => this.mouse_enter(evt)
+ @container.observe "mouseleave", (evt) => this.mouse_leave(evt)
+
+ @search_results.observe "click", (evt) => this.search_results_click(evt)
+ @search_results.observe "mouseover", (evt) => this.search_results_mouseover(evt)
+ @search_results.observe "mouseout", (evt) => this.search_results_mouseout(evt)
+
+ @form_field.observe "liszt:updated", (evt) => this.results_update_field(evt)
+
+ @search_field.observe "blur", (evt) => this.input_blur(evt)
+ @search_field.observe "keyup", (evt) => this.keyup_checker(evt)
+ @search_field.observe "keydown", (evt) => this.keydown_checker(evt)
+
+ if @is_multiple
+ @search_choices.observe "click", (evt) => this.choices_click(evt)
+ @search_field.observe "focus", (evt) => this.input_focus(evt)
+ else
+ @selected_item.observe "focus", (evt) => this.activate_field(evt)
+
+
+ container_click: (evt) ->
+ if evt and evt.type is "click"
+ evt.stop()
+ if not @pending_destroy_click
+ if not @active_field
+ @search_field.clear() if @is_multiple
+ document.observe "click", @click_test_action
+ this.results_show()
+ else if not @is_multiple and evt and (evt.target is @selected_item || evt.target.up("a.chzn-single"))
+ this.results_toggle()
+
+ this.activate_field()
+ else
+ @pending_destroy_click = false
+
+ mouse_enter: -> @mouse_on_container = true
+ mouse_leave: -> @mouse_on_container = false
+
+ input_focus: (evt) ->
+ setTimeout this.container_click.bind(this), 50 unless @active_field
+
+ input_blur: (evt) ->
+ if not @mouse_on_container
+ @active_field = false
+ setTimeout this.blur_test.bind(this), 100
+
+ blur_test: (evt) ->
+ this.close_field() if not @active_field and @container.hasClassName("chzn-container-active")
+
+ close_field: ->
+ document.stopObserving "click", @click_test_action
+
+ if not @is_multiple
+ @selected_item.tabIndex = @search_field.tabIndex
+ @search_field.tabIndex = -1
+
+ @active_field = false
+ this.results_hide()
+
+ @container.removeClassName "chzn-container-active"
+ this.winnow_results_clear()
+ this.clear_backstroke()
+
+ this.show_search_field_default()
+ this.search_field_scale()
+
+ activate_field: ->
+ if not @is_multiple and not @active_field
+ @search_field.tabIndex = @selected_item.tabIndex
+ @selected_item.tabIndex = -1
+
+ @container.addClassName "chzn-container-active"
+ @active_field = true
+
+ @search_field.value = @search_field.value
+ @search_field.focus()
+
+
+ test_active_click: (evt) ->
+ if evt.target.up('#' + @container.id)
+ @active_field = true
+ else
+ this.close_field()
+
+ results_build: ->
+ startTime = new Date()
+ @parsing = true
+ @results_data = SelectParser.select_to_array @form_field
+
+ if @is_multiple and @choices > 0
+ @search_choices.select("li.search-choice").invoke("remove")
+ @choices = 0
+ else if not @is_multiple
+ @selected_item.down("span").update(@default_text)
+
+ content = ''
+ for data in @results_data
+ if data.group
+ content += this.result_add_group data
+ else if !data.empty
+ content += this.result_add_option data
+ if data.selected and @is_multiple
+ this.choice_build data
+ else if data.selected and not @is_multiple
+ @selected_item.down("span").update( data.text )
+
+ this.show_search_field_default()
+ this.search_field_scale()
+
+ @search_results.update content
+ @parsing = false
+
+
+ result_add_group: (group) ->
+ if not group.disabled
+ group.dom_id = @form_field.id + "chzn_g_" + group.array_index
+ '<li id="' + group.dom_id + '" class="group-result">' + group.label.escapeHTML() + '</li>'
+ else
+ ""
+
+ result_add_option: (option) ->
+ if not option.disabled
+ option.dom_id = @form_field.id + "chzn_o_" + option.array_index
+
+ classes = if option.selected and @is_multiple then [] else ["active-result"]
+ classes.push "result-selected" if option.selected
+ classes.push "group-option" if option.group_array_index?
+
+ '<li id="' + option.dom_id + '" class="' + classes.join(' ') + '">' + option.text.escapeHTML() + '</li>'
+ else
+ ""
+
+ results_update_field: ->
+ this.result_clear_highlight()
+ @result_single_selected = null
+ this.results_build()
+
+ result_do_highlight: (el) ->
+ this.result_clear_highlight()
+
+ @result_highlight = el
+ @result_highlight.addClassName "highlighted"
+
+ maxHeight = parseInt @search_results.getStyle('maxHeight'), 10
+ visible_top = @search_results.scrollTop
+ visible_bottom = maxHeight + visible_top
+
+ high_top = @result_highlight.positionedOffset().top
+ high_bottom = high_top + @result_highlight.getHeight()
+
+ if high_bottom >= visible_bottom
+ @search_results.scrollTop = if (high_bottom - maxHeight) > 0 then (high_bottom - maxHeight) else 0
+ else if high_top < visible_top
+ @search_results.scrollTop = high_top
+
+ result_clear_highlight: ->
+ @result_highlight.removeClassName('highlighted') if @result_highlight
+ @result_highlight = null
+
+ results_toggle: ->
+ if @results_showing
+ this.results_hide()
+ else
+ this.results_show()
+
+ results_show: ->
+ if not @is_multiple
+ @selected_item.addClassName('chzn-single-with-drop')
+ if @result_single_selected
+ this.result_do_highlight( @result_single_selected )
+
+ dd_top = if @is_multiple then @container.getHeight() else (@container.getHeight() - 1)
+ @dropdown.setStyle {"top": dd_top + "px", "left":0}
+ @results_showing = true
+
+ @search_field.focus()
+ @search_field.value = @search_field.value
+
+ this.winnow_results()
+
+ results_hide: ->
+ @selected_item.removeClassName('chzn-single-with-drop') unless @is_multiple
+ this.result_clear_highlight()
+ @dropdown.setStyle({"left":"-9000px"})
+ @results_showing = false
+
+
+ set_tab_index: (el) ->
+ if @form_field.tabIndex
+ ti = @form_field.tabIndex
+ @form_field.tabIndex = -1
+
+ if @is_multiple
+ @search_field.tabIndex = ti
+ else
+ @selected_item.tabIndex = ti
+ @search_field.tabIndex = -1
+
+ show_search_field_default: ->
+ if @is_multiple and @choices < 1 and not @active_field
+ @search_field.value = @default_text
+ @search_field.addClassName "default"
+ else
+ @search_field.value = ""
+ @search_field.removeClassName "default"
+
+ search_results_click: (evt) ->
+ target = if evt.target.hasClassName("active-result") then evt.target else evt.target.up(".active-result")
+ if target
+ @result_highlight = target
+ this.result_select()
+
+ search_results_mouseover: (evt) ->
+ target = if evt.target.hasClassName("active-result") then evt.target else evt.target.up(".active-result")
+ this.result_do_highlight( target ) if target
+
+ search_results_mouseout: (evt) ->
+ this.result_clear_highlight() if evt.target.hasClassName('active-result') or evt.target.up('.active-result')
+
+
+ choices_click: (evt) ->
+ evt.preventDefault()
+ if( @active_field and not(evt.target.hasClassName('search-choice') or evt.target.up('.search-choice')) and not @results_showing )
+ this.results_show()
+
+ choice_build: (item) ->
+ choice_id = @form_field.id + "_chzn_c_" + item.array_index
+ @choices += 1
+ @search_container.insert { before: @choice_temp.evaluate({"id":choice_id, "choice":item.text, "position":item.array_index}) }
+ link = $(choice_id).down('a')
+ link.observe "click", (evt) => this.choice_destroy_link_click(evt)
+
+ choice_destroy_link_click: (evt) ->
+ evt.preventDefault()
+ @pending_destroy_click = true
+ this.choice_destroy evt.target
+
+ choice_destroy: (link) ->
+ @choices -= 1
+ this.show_search_field_default()
+
+ this.results_hide() if @is_multiple and @choices > 0 and @search_field.value.length < 1
+
+ this.result_deselect link.readAttribute("rel")
+ link.up('li').remove()
+
+ result_select: ->
+ if @result_highlight
+ high = @result_highlight
+ this.result_clear_highlight()
+
+ high.addClassName("result-selected")
+
+ if @is_multiple
+ this.result_deactivate high
+ else
+ @result_single_selected = high
+
+ position = high.id.substr(high.id.lastIndexOf("_") + 1 )
+ item = @results_data[position]
+ item.selected = true
+
+ @form_field.options[item.options_index].selected = true
+
+ if @is_multiple
+ this.choice_build item
+ else
+ @selected_item.down("span").update(item.text)
+
+ this.results_hide()
+ @search_field.value = ""
+
+ @form_field.simulate("change") if typeof Event.simulate is 'function'
+ this.search_field_scale()
+
+ result_activate: (el) ->
+ el.addClassName("active-result").show()
+
+ result_deactivate: (el) ->
+ el.removeClassName("active-result").hide()
+
+ result_deselect: (pos) ->
+ result_data = @results_data[pos]
+ result_data.selected = false
+
+ @form_field.options[result_data.options_index].selected = false
+ result = $(@form_field.id + "chzn_o_" + pos)
+ result.removeClassName("result-selected").addClassName("active-result").show()
+
+ this.result_clear_highlight()
+ this.winnow_results()
+
+ @form_field.simulate("change") if typeof Event.simulate is 'function'
+ this.search_field_scale()
+
+ results_search: (evt) ->
+ if @results_showing
+ this.winnow_results()
+ else
+ this.results_show()
+
+ winnow_results: ->
+ startTime = new Date()
+ this.no_results_clear()
+
+ results = 0
+
+ searchText = if @search_field.value is @default_text then "" else @search_field.value.strip()
+ regex = new RegExp('^' + searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i')
+ zregex = new RegExp(searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i')
+
+ for option in @results_data
+ if not option.disabled and not option.empty
+ if option.group
+ $(option.dom_id).hide()
+ else if not (@is_multiple and option.selected)
+ found = false
+ result_id = option.dom_id
+
+ if regex.test option.text
+ found = true
+ results += 1
+ else if option.text.indexOf(" ") >= 0 or option.text.indexOf("[") == 0
+ #TODO: replace this substitution of /\[\]/ with a list of characters to skip.
+ parts = option.text.replace(/\[|\]/g, "").split(" ")
+ if parts.length
+ for part in parts
+ if regex.test part
+ found = true
+ results += 1
+
+ if found
+ if searchText.length
+ startpos = option.text.search zregex
+ text = option.text.substr(0, startpos + searchText.length) + '</em>' + option.text.substr(startpos + searchText.length)
+ text = text.substr(0, startpos) + '<em>' + text.substr(startpos)
+ else
+ text = option.text
+
+ $(result_id).update text if $(result_id).innerHTML != text
+
+ this.result_activate $(result_id)
+
+ $(@results_data[option.group_array_index].dom_id).show() if option.group_array_index?
+ else
+ this.result_clear_highlight() if $(result_id) is @result_highlight
+ this.result_deactivate $(result_id)
+
+ if results < 1 and searchText.length
+ this.no_results(searchText)
+ else
+ this.winnow_results_set_highlight()
+
+ winnow_results_clear: ->
+ @search_field.clear()
+ lis = @search_results.select("li")
+
+ for li in lis
+ if li.hasClassName("group-result")
+ li.show()
+ else if not @is_multiple or not li.hasClassName("result-selected")
+ this.result_activate li
+
+ winnow_results_set_highlight: ->
+ if not @result_highlight
+ do_high = @search_results.down(".active-result")
+ if(do_high)
+ this.result_do_highlight do_high
+
+ no_results: (terms) ->
+ @search_results.insert @no_results_temp.evaluate({"terms":terms.escapeHTML()})
+
+ no_results_clear: ->
+ nr = null
+ nr.remove() while nr = @search_results.down(".no-results")
+
+
+ keydown_arrow: ->
+ actives = @search_results.select("li.active-result")
+ if actives.length
+ if not @result_highlight
+ this.result_do_highlight actives.first()
+ else if @results_showing
+ sibs = @result_highlight.nextSiblings()
+ nexts = sibs.intersect(actives)
+ this.result_do_highlight nexts.first() if nexts.length
+ this.results_show() if not @results_showing
+
+ keyup_arrow: ->
+ if not @results_showing and not @is_multiple
+ this.results_show()
+ else if @result_highlight
+ sibs = @result_highlight.previousSiblings()
+ actives = @search_results.select("li.active-result")
+ prevs = sibs.intersect(actives)
+
+ if prevs.length
+ this.result_do_highlight prevs.first()
+ else
+ this.results_hide() if @choices > 0
+ this.result_clear_highlight()
+
+ keydown_backstroke: ->
+ if @pending_backstroke
+ this.choice_destroy @pending_backstroke.down("a")
+ this.clear_backstroke()
+ else
+ @pending_backstroke = @search_container.siblings("li.search-choice").last()
+ @pending_backstroke.addClassName("search-choice-focus")
+
+ clear_backstroke: ->
+ @pending_backstroke.removeClassName("search-choice-focus") if @pending_backstroke
+ @pending_backstroke = null
+
+ keyup_checker: (evt) ->
+ stroke = evt.which ? evt.keyCode
+ this.search_field_scale()
+
+ switch stroke
+ when 8
+ if @is_multiple and @backstroke_length < 1 and @choices > 0
+ this.keydown_backstroke()
+ else if not @pending_backstroke
+ this.result_clear_highlight()
+ this.results_search()
+ when 13
+ evt.preventDefault()
+ this.result_select() if this.results_showing
+ when 27
+ this.results_hide() if @results_showing
+ when 9, 38, 40, 16
+ # don't do anything on these keys
+ else this.results_search()
+
+
+ keydown_checker: (evt) ->
+ stroke = evt.which ? evt.keyCode
+ this.search_field_scale()
+
+ this.clear_backstroke() if stroke != 8 and this.pending_backstroke
+
+ switch stroke
+ when 8
+ @backstroke_length = this.search_field.value.length
+ when 9
+ @mouse_on_container = false
+ when 13
+ evt.preventDefault()
+ when 38
+ evt.preventDefault()
+ this.keyup_arrow()
+ when 40
+ this.keydown_arrow()
+
+
+ search_field_scale: ->
+ if @is_multiple
+ h = 0
+ w = 0
+
+ style_block = "position:absolute; left: -1000px; top: -1000px; display:none;"
+ styles = ['font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing']
+
+ for style in styles
+ style_block += style + ":" + @search_field.getStyle(style) + ";"
+
+ div = new Element('div', { 'style' : style_block }).update(@search_field.value)
+ document.body.appendChild(div)
+
+ w = Element.measure(div, 'width') + 25
+ div.remove()
+
+ if( w > @f_width-10 )
+ w = @f_width - 10
+
+ @search_field.setStyle({'width': w + 'px'})
+
+ dd_top = @container.getHeight()
+ @dropdown.setStyle({"top": dd_top + "px"})
+
+root.Chosen = Chosen
+
+document.observe 'dom:loaded', (evt) ->
+ selects = $$(".chzn-select")
+ new Chosen select for select in selects
+
+get_side_border_padding = (elmt) ->
+ layout = new Element.Layout(elmt)
+ side_border_padding = layout.get("border-left") + layout.get("border-right") + layout.get("padding-left") + layout.get("padding-right")
+
+root.get_side_border_padding = get_side_border_padding
+
+root = exports ? this
+
+class SelectParser
+
+ constructor: ->
+ @options_index = 0
+ @parsed = []
+
+ add_node: (child) ->
+ if child.nodeName is "OPTGROUP"
+ this.add_group child
+ else
+ this.add_option child
+
+ add_group: (group) ->
+ group_position = @parsed.length
+ @parsed.push
+ array_index: group_position
+ group: true
+ label: group.label
+ children: 0
+ disabled: group.disabled
+ this.add_option( option, group_position, group.disabled ) for option in group.childNodes
+
+ add_option: (option, group_position, group_disabled) ->
+ if option.nodeName is "OPTION"
+ if option.text != ""
+ if group_position?
+ @parsed[group_position].children += 1
+ @parsed.push
+ array_index: @parsed.length
+ options_index: @options_index
+ value: option.value
+ text: option.text
+ selected: option.selected
+ disabled: if group_disabled is true then group_disabled else option.disabled
+ group_array_index: group_position
+ else
+ @parsed.push
+ array_index: @parsed.length
+ options_index: @options_index
+ empty: true
+ @options_index += 1
+
+SelectParser.select_to_array = (select) ->
+ parser = new SelectParser()
+ parser.add_node( child ) for child in select.childNodes
+ parser.parsed
+
+root.SelectParser = SelectParser
diff --git a/usr/local/www/javascript/scriptaculous/prototype.js b/usr/local/www/javascript/scriptaculous/prototype.js
index bfc9d7a..474b223 100644
--- a/usr/local/www/javascript/scriptaculous/prototype.js
+++ b/usr/local/www/javascript/scriptaculous/prototype.js
@@ -1,5 +1,5 @@
-/* Prototype JavaScript framework, version 1.6.1
- * (c) 2005-2009 Sam Stephenson
+/* Prototype JavaScript framework, version 1.7
+ * (c) 2005-2010 Sam Stephenson
*
* Prototype is freely distributable under the terms of an MIT-style license.
* For details, see the Prototype web site: http://www.prototypejs.org/
@@ -7,7 +7,8 @@
*--------------------------------------------------------------------------*/
var Prototype = {
- Version: '1.6.1',
+
+ Version: '1.7',
Browser: (function(){
var ua = navigator.userAgent;
@@ -17,13 +18,15 @@ var Prototype = {
Opera: isOpera,
WebKit: ua.indexOf('AppleWebKit/') > -1,
Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
- MobileSafari: /Apple.*Mobile.*Safari/.test(ua)
+ MobileSafari: /Apple.*Mobile/.test(ua)
}
})(),
BrowserFeatures: {
XPath: !!document.evaluate,
+
SelectorsAPI: !!document.querySelector,
+
ElementExtensions: (function() {
var constructor = window.Element || window.HTMLElement;
return !!(constructor && constructor.prototype);
@@ -32,9 +35,9 @@ var Prototype = {
if (typeof window.HTMLDivElement !== 'undefined')
return true;
- var div = document.createElement('div');
- var form = document.createElement('form');
- var isSupported = false;
+ var div = document.createElement('div'),
+ form = document.createElement('form'),
+ isSupported = false;
if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
isSupported = true;
@@ -50,6 +53,7 @@ var Prototype = {
JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
emptyFunction: function() { },
+
K: function(x) { return x }
};
@@ -79,6 +83,14 @@ var Try = {
/* Based on Alex Arnell's inheritance implementation. */
var Class = (function() {
+
+ var IS_DONTENUM_BUGGY = (function(){
+ for (var p in { toString: 1 }) {
+ if (p === 'toString') return false;
+ }
+ return true;
+ })();
+
function subclass() {};
function create() {
var parent = null, properties = $A(arguments);
@@ -99,7 +111,7 @@ var Class = (function() {
parent.subclasses.push(klass);
}
- for (var i = 0; i < properties.length; i++)
+ for (var i = 0, length = properties.length; i < length; i++)
klass.addMethods(properties[i]);
if (!klass.prototype.initialize)
@@ -110,10 +122,10 @@ var Class = (function() {
}
function addMethods(source) {
- var ancestor = this.superclass && this.superclass.prototype;
- var properties = Object.keys(source);
+ var ancestor = this.superclass && this.superclass.prototype,
+ properties = Object.keys(source);
- if (!Object.keys({ toString: true }).length) {
+ if (IS_DONTENUM_BUGGY) {
if (source.toString != Object.prototype.toString)
properties.push("toString");
if (source.valueOf != Object.prototype.valueOf)
@@ -123,7 +135,7 @@ var Class = (function() {
for (var i = 0, length = properties.length; i < length; i++) {
var property = properties[i], value = source[property];
if (ancestor && Object.isFunction(value) &&
- value.argumentNames().first() == "$super") {
+ value.argumentNames()[0] == "$super") {
var method = value;
value = (function(m) {
return function() { return ancestor[m].apply(this, arguments); };
@@ -147,7 +159,37 @@ var Class = (function() {
})();
(function() {
- var _toString = Object.prototype.toString;
+ var _toString = Object.prototype.toString,
+ NULL_TYPE = 'Null',
+ UNDEFINED_TYPE = 'Undefined',
+ BOOLEAN_TYPE = 'Boolean',
+ NUMBER_TYPE = 'Number',
+ STRING_TYPE = 'String',
+ OBJECT_TYPE = 'Object',
+ FUNCTION_CLASS = '[object Function]',
+ BOOLEAN_CLASS = '[object Boolean]',
+ NUMBER_CLASS = '[object Number]',
+ STRING_CLASS = '[object String]',
+ ARRAY_CLASS = '[object Array]',
+ DATE_CLASS = '[object Date]',
+ NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON &&
+ typeof JSON.stringify === 'function' &&
+ JSON.stringify(0) === '0' &&
+ typeof JSON.stringify(Prototype.K) === 'undefined';
+
+ function Type(o) {
+ switch(o) {
+ case null: return NULL_TYPE;
+ case (void 0): return UNDEFINED_TYPE;
+ }
+ var type = typeof o;
+ switch(type) {
+ case 'boolean': return BOOLEAN_TYPE;
+ case 'number': return NUMBER_TYPE;
+ case 'string': return STRING_TYPE;
+ }
+ return OBJECT_TYPE;
+ }
function extend(destination, source) {
for (var property in source)
@@ -166,31 +208,73 @@ var Class = (function() {
}
}
- function toJSON(object) {
- var type = typeof object;
- switch (type) {
- case 'undefined':
- case 'function':
- case 'unknown': return;
- case 'boolean': return object.toString();
+ function toJSON(value) {
+ return Str('', { '': value }, []);
+ }
+
+ function Str(key, holder, stack) {
+ var value = holder[key],
+ type = typeof value;
+
+ if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
}
- if (object === null) return 'null';
- if (object.toJSON) return object.toJSON();
- if (isElement(object)) return;
+ var _class = _toString.call(value);
- var results = [];
- for (var property in object) {
- var value = toJSON(object[property]);
- if (!isUndefined(value))
- results.push(property.toJSON() + ': ' + value);
+ switch (_class) {
+ case NUMBER_CLASS:
+ case BOOLEAN_CLASS:
+ case STRING_CLASS:
+ value = value.valueOf();
+ }
+
+ switch (value) {
+ case null: return 'null';
+ case true: return 'true';
+ case false: return 'false';
+ }
+
+ type = typeof value;
+ switch (type) {
+ case 'string':
+ return value.inspect(true);
+ case 'number':
+ return isFinite(value) ? String(value) : 'null';
+ case 'object':
+
+ for (var i = 0, length = stack.length; i < length; i++) {
+ if (stack[i] === value) { throw new TypeError(); }
+ }
+ stack.push(value);
+
+ var partial = [];
+ if (_class === ARRAY_CLASS) {
+ for (var i = 0, length = value.length; i < length; i++) {
+ var str = Str(i, value, stack);
+ partial.push(typeof str === 'undefined' ? 'null' : str);
+ }
+ partial = '[' + partial.join(',') + ']';
+ } else {
+ var keys = Object.keys(value);
+ for (var i = 0, length = keys.length; i < length; i++) {
+ var key = keys[i], str = Str(key, value, stack);
+ if (typeof str !== "undefined") {
+ partial.push(key.inspect(true)+ ':' + str);
+ }
+ }
+ partial = '{' + partial.join(',') + '}';
+ }
+ stack.pop();
+ return partial;
}
+ }
- return '{' + results.join(', ') + '}';
+ function stringify(object) {
+ return JSON.stringify(object);
}
function toQueryString(object) {
- //console.debug(object);
return $H(object).toQueryString();
}
@@ -199,9 +283,13 @@ var Class = (function() {
}
function keys(object) {
+ if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); }
var results = [];
- for (var property in object)
- results.push(property);
+ for (var property in object) {
+ if (object.hasOwnProperty(property)) {
+ results.push(property);
+ }
+ }
return results;
}
@@ -221,24 +309,34 @@ var Class = (function() {
}
function isArray(object) {
- return _toString.call(object) == "[object Array]";
+ return _toString.call(object) === ARRAY_CLASS;
}
+ var hasNativeIsArray = (typeof Array.isArray == 'function')
+ && Array.isArray([]) && !Array.isArray({});
+
+ if (hasNativeIsArray) {
+ isArray = Array.isArray;
+ }
function isHash(object) {
return object instanceof Hash;
}
function isFunction(object) {
- return typeof object === "function";
+ return _toString.call(object) === FUNCTION_CLASS;
}
function isString(object) {
- return _toString.call(object) == "[object String]";
+ return _toString.call(object) === STRING_CLASS;
}
function isNumber(object) {
- return _toString.call(object) == "[object Number]";
+ return _toString.call(object) === NUMBER_CLASS;
+ }
+
+ function isDate(object) {
+ return _toString.call(object) === DATE_CLASS;
}
function isUndefined(object) {
@@ -248,10 +346,10 @@ var Class = (function() {
extend(Object, {
extend: extend,
inspect: inspect,
- toJSON: toJSON,
+ toJSON: NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON,
toQueryString: toQueryString,
toHTML: toHTML,
- keys: keys,
+ keys: Object.keys || keys,
values: values,
clone: clone,
isElement: isElement,
@@ -260,6 +358,7 @@ var Class = (function() {
isFunction: isFunction,
isString: isString,
isNumber: isNumber,
+ isDate: isDate,
isUndefined: isUndefined
});
})();
@@ -312,7 +411,7 @@ Object.extend(Function.prototype, (function() {
function delay(timeout) {
var __method = this, args = slice.call(arguments, 1);
- timeout = timeout * 1000
+ timeout = timeout * 1000;
return window.setTimeout(function() {
return __method.apply(__method, args);
}, timeout);
@@ -353,14 +452,28 @@ Object.extend(Function.prototype, (function() {
})());
-Date.prototype.toJSON = function() {
- return '"' + this.getUTCFullYear() + '-' +
- (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
- this.getUTCDate().toPaddedString(2) + 'T' +
- this.getUTCHours().toPaddedString(2) + ':' +
- this.getUTCMinutes().toPaddedString(2) + ':' +
- this.getUTCSeconds().toPaddedString(2) + 'Z"';
-};
+
+(function(proto) {
+
+
+ function toISOString() {
+ return this.getUTCFullYear() + '-' +
+ (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
+ this.getUTCDate().toPaddedString(2) + 'T' +
+ this.getUTCHours().toPaddedString(2) + ':' +
+ this.getUTCMinutes().toPaddedString(2) + ':' +
+ this.getUTCSeconds().toPaddedString(2) + 'Z';
+ }
+
+
+ function toJSON() {
+ return this.toISOString();
+ }
+
+ if (!proto.toISOString) proto.toISOString = toISOString;
+ if (!proto.toJSON) proto.toJSON = toJSON;
+
+})(Date.prototype);
RegExp.prototype.match = RegExp.prototype.test;
@@ -419,6 +532,9 @@ Object.extend(String, {
});
Object.extend(String.prototype, (function() {
+ var NATIVE_JSON_PARSE_SUPPORT = window.JSON &&
+ typeof JSON.parse === 'function' &&
+ JSON.parse('{"test": true}').test;
function prepareReplacement(replacement) {
if (Object.isFunction(replacement)) return replacement;
@@ -485,8 +601,8 @@ Object.extend(String.prototype, (function() {
}
function extractScripts() {
- var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
- var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img'),
+ matchOne = new RegExp(Prototype.ScriptFragment, 'im');
return (this.match(matchAll) || []).map(function(scriptTag) {
return (scriptTag.match(matchOne) || ['', ''])[1];
});
@@ -511,8 +627,9 @@ Object.extend(String.prototype, (function() {
return match[1].split(separator || '&').inject({ }, function(hash, pair) {
if ((pair = pair.split('='))[0]) {
- var key = decodeURIComponent(pair.shift());
- var value = pair.length > 1 ? pair.join('=') : pair[0];
+ var key = decodeURIComponent(pair.shift()),
+ value = pair.length > 1 ? pair.join('=') : pair[0];
+
if (value != undefined) value = decodeURIComponent(value);
if (key in hash) {
@@ -539,17 +656,9 @@ Object.extend(String.prototype, (function() {
}
function camelize() {
- var parts = this.split('-'), len = parts.length;
- if (len == 1) return parts[0];
-
- var camelized = this.charAt(0) == '-'
- ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
- : parts[0];
-
- for (var i = 1; i < len; i++)
- camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
-
- return camelized;
+ return this.replace(/-+(.)?/g, function(match, chr) {
+ return chr ? chr.toUpperCase() : '';
+ });
}
function capitalize() {
@@ -579,10 +688,6 @@ Object.extend(String.prototype, (function() {
return "'" + escapedString.replace(/'/g, '\\\'') + "'";
}
- function toJSON() {
- return this.inspect(true);
- }
-
function unfilterJSON(filter) {
return this.replace(filter || Prototype.JSONFilter, '$1');
}
@@ -590,29 +695,42 @@ Object.extend(String.prototype, (function() {
function isJSON() {
var str = this;
if (str.blank()) return false;
- str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
- return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
+ str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
+ str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
+ str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
+ return (/^[\],:{}\s]*$/).test(str);
}
function evalJSON(sanitize) {
- var json = this.unfilterJSON();
+ var json = this.unfilterJSON(),
+ cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
+ if (cx.test(json)) {
+ json = json.replace(cx, function (a) {
+ return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
try {
if (!sanitize || json.isJSON()) return eval('(' + json + ')');
} catch (e) { }
throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
}
+ function parseJSON() {
+ var json = this.unfilterJSON();
+ return JSON.parse(json);
+ }
+
function include(pattern) {
return this.indexOf(pattern) > -1;
}
function startsWith(pattern) {
- return this.indexOf(pattern) === 0;
+ return this.lastIndexOf(pattern, 0) === 0;
}
function endsWith(pattern) {
var d = this.length - pattern.length;
- return d >= 0 && this.lastIndexOf(pattern) === d;
+ return d >= 0 && this.indexOf(pattern, d) === d;
}
function empty() {
@@ -632,7 +750,7 @@ Object.extend(String.prototype, (function() {
sub: sub,
scan: scan,
truncate: truncate,
- strip: String.prototype.trim ? String.prototype.trim : strip,
+ strip: String.prototype.trim || strip,
stripTags: stripTags,
stripScripts: stripScripts,
extractScripts: extractScripts,
@@ -649,10 +767,9 @@ Object.extend(String.prototype, (function() {
underscore: underscore,
dasherize: dasherize,
inspect: inspect,
- toJSON: toJSON,
unfilterJSON: unfilterJSON,
isJSON: isJSON,
- evalJSON: evalJSON,
+ evalJSON: NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON,
include: include,
startsWith: startsWith,
endsWith: endsWith,
@@ -678,8 +795,9 @@ var Template = Class.create({
var before = match[1] || '';
if (before == '\\') return match[2];
- var ctx = object, expr = match[3];
- var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
+ var ctx = object, expr = match[3],
+ pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
+
match = pattern.exec(expr);
if (match == null) return before;
@@ -944,6 +1062,7 @@ var Enumerable = (function() {
find: detect
};
})();
+
function $A(iterable) {
if (!iterable) return [];
if ('toArray' in Object(iterable)) return iterable.toArray();
@@ -952,6 +1071,7 @@ function $A(iterable) {
return results;
}
+
function $w(string) {
if (!Object.isString(string)) return [];
string = string.strip();
@@ -966,9 +1086,10 @@ Array.from = $A;
slice = arrayProto.slice,
_each = arrayProto.forEach; // use native browser JS 1.6 implementation if available
- function each(iterator) {
- for (var i = 0, length = this.length; i < length; i++)
- iterator(this[i]);
+ function each(iterator, context) {
+ for (var i = 0, length = this.length >>> 0; i < length; i++) {
+ if (i in this) iterator.call(context, this[i], i, this);
+ }
}
if (!_each) _each = each;
@@ -1008,7 +1129,7 @@ Array.from = $A;
}
function reverse(inline) {
- return (inline !== false ? this : this.toArray())._reverse();
+ return (inline === false ? this.toArray() : this)._reverse();
}
function uniq(sorted) {
@@ -1038,15 +1159,6 @@ Array.from = $A;
return '[' + this.map(Object.inspect).join(', ') + ']';
}
- function toJSON() {
- var results = [];
- this.each(function(object) {
- var value = Object.toJSON(object);
- if (!Object.isUndefined(value)) results.push(value);
- });
- return '[' + results.join(', ') + ']';
- }
-
function indexOf(item, i) {
i || (i = 0);
var length = this.length;
@@ -1095,8 +1207,7 @@ Array.from = $A;
clone: clone,
toArray: clone,
size: size,
- inspect: inspect,
- toJSON: toJSON
+ inspect: inspect
});
var CONCAT_ARGUMENTS_BUGGY = (function() {
@@ -1117,6 +1228,7 @@ var Hash = Class.create(Enumerable, (function() {
this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
}
+
function _each(iterator) {
for (var key in this._object) {
var value = this._object[key], pair = [key, value];
@@ -1145,6 +1257,8 @@ var Hash = Class.create(Enumerable, (function() {
return Object.clone(this._object);
}
+
+
function keys() {
return this.pluck('key');
}
@@ -1181,8 +1295,14 @@ var Hash = Class.create(Enumerable, (function() {
var key = encodeURIComponent(pair.key), values = pair.value;
if (values && typeof values == 'object') {
- if (Object.isArray(values))
- return results.concat(values.map(toQueryPair.curry(key)));
+ if (Object.isArray(values)) {
+ var queryValues = [];
+ for (var i = 0, len = values.length, value; i < len; i++) {
+ value = values[i];
+ queryValues.push(toQueryPair(key, value));
+ }
+ return results.concat(queryValues);
+ }
} else results.push(toQueryPair(key, values));
return results;
}).join('&');
@@ -1194,10 +1314,6 @@ var Hash = Class.create(Enumerable, (function() {
}).join(', ') + '}>';
}
- function toJSON() {
- return Object.toJSON(this.toObject());
- }
-
function clone() {
return new Hash(this);
}
@@ -1217,7 +1333,7 @@ var Hash = Class.create(Enumerable, (function() {
update: update,
toQueryString: toQueryString,
inspect: inspect,
- toJSON: toJSON,
+ toJSON: toObject,
clone: clone
};
})());
@@ -1242,10 +1358,6 @@ Object.extend(Number.prototype, (function() {
return '0'.times(length - string.length) + string;
}
- function toJSON() {
- return isFinite(this) ? this.toString() : 'null';
- }
-
function abs() {
return Math.abs(this);
}
@@ -1267,7 +1379,6 @@ Object.extend(Number.prototype, (function() {
succ: succ,
times: times,
toPaddedString: toPaddedString,
- toJSON: toJSON,
abs: abs,
round: round,
ceil: ceil,
@@ -1371,9 +1482,7 @@ Ajax.Base = Class.create({
this.options.method = this.options.method.toLowerCase();
- if (Object.isString(this.options.parameters))
- this.options.parameters = this.options.parameters.toQueryParams();
- else if (Object.isHash(this.options.parameters))
+ if (Object.isHash(this.options.parameters))
this.options.parameters = this.options.parameters.toObject();
}
});
@@ -1389,22 +1498,21 @@ Ajax.Request = Class.create(Ajax.Base, {
request: function(url) {
this.url = url;
this.method = this.options.method;
- var params = Object.clone(this.options.parameters);
+ var params = Object.isString(this.options.parameters) ?
+ this.options.parameters :
+ Object.toQueryString(this.options.parameters);
if (!['get', 'post'].include(this.method)) {
- params['_method'] = this.method;
+ params += (params ? '&' : '') + "_method=" + this.method;
this.method = 'post';
}
- this.parameters = params;
-
- if (params = Object.toQueryString(params)) {
- if (this.method == 'get')
- this.url += (this.url.include('?') ? '&' : '?') + params;
- else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
- params += '&_=';
+ if (params && this.method === 'get') {
+ this.url += (this.url.include('?') ? '&' : '?') + params;
}
+ this.parameters = params.toQueryParams();
+
try {
var response = new Ajax.Response(this);
if (this.options.onCreate) this.options.onCreate(response);
@@ -1473,11 +1581,12 @@ Ajax.Request = Class.create(Ajax.Base, {
success: function() {
var status = this.getStatus();
- return !status || (status >= 200 && status < 300);
+ return !status || (status >= 200 && status < 300) || status == 304;
},
getStatus: function() {
try {
+ if (this.transport.status === 1223) return 204;
return this.transport.status || 0;
} catch (e) { return 0 }
},
@@ -1559,14 +1668,14 @@ Ajax.Response = Class.create({
var transport = this.transport = request.transport,
readyState = this.readyState = transport.readyState;
- if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
+ if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
this.status = this.getStatus();
this.statusText = this.getStatusText();
this.responseText = String.interpret(transport.responseText);
this.headerJSON = this._getHeaderJSON();
}
- if(readyState == 4) {
+ if (readyState == 4) {
var xml = transport.responseXML;
this.responseXML = Object.isUndefined(xml) ? null : xml;
this.responseJSON = this._getResponseJSON();
@@ -1706,7 +1815,6 @@ Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
});
-
function $(element) {
if (arguments.length > 1) {
for (var i = 0, elements = [], length = arguments.length; i < length; i++)
@@ -1731,7 +1839,7 @@ if (Prototype.BrowserFeatures.XPath) {
/*--------------------------------------------------------------------------*/
-if (!window.Node) var Node = { };
+if (!Node) var Node = { };
if (!Node.ELEMENT_NODE) {
Object.extend(Node, {
@@ -1751,42 +1859,61 @@ if (!Node.ELEMENT_NODE) {
}
+
(function(global) {
+ function shouldUseCache(tagName, attributes) {
+ if (tagName === 'select') return false;
+ if ('type' in attributes) return false;
+ return true;
+ }
- var SETATTRIBUTE_IGNORES_NAME = (function(){
- var elForm = document.createElement("form");
- var elInput = document.createElement("input");
- var root = document.documentElement;
- elInput.setAttribute("name", "test");
- elForm.appendChild(elInput);
- root.appendChild(elForm);
- var isBuggy = elForm.elements
- ? (typeof elForm.elements.test == "undefined")
- : null;
- root.removeChild(elForm);
- elForm = elInput = null;
- return isBuggy;
+ var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){
+ try {
+ var el = document.createElement('<input name="x">');
+ return el.tagName.toLowerCase() === 'input' && el.name === 'x';
+ }
+ catch(err) {
+ return false;
+ }
})();
var element = global.Element;
+
global.Element = function(tagName, attributes) {
attributes = attributes || { };
tagName = tagName.toLowerCase();
var cache = Element.cache;
- if (SETATTRIBUTE_IGNORES_NAME && attributes.name) {
+
+ if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) {
tagName = '<' + tagName + ' name="' + attributes.name + '">';
delete attributes.name;
return Element.writeAttribute(document.createElement(tagName), attributes);
}
+
if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
- return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
+
+ var node = shouldUseCache(tagName, attributes) ?
+ cache[tagName].cloneNode(false) : document.createElement(tagName);
+
+ return Element.writeAttribute(node, attributes);
};
+
Object.extend(global.Element, element || { });
if (element) global.Element.prototype = element.prototype;
+
})(this);
-Element.cache = { };
Element.idCounter = 1;
+Element.cache = { };
+
+Element._purgeElement = function(element) {
+ var uid = element._prototypeUID;
+ if (uid) {
+ Element.stopObserving(element);
+ element._prototypeUID = void 0;
+ delete Element.Storage[uid];
+ }
+}
Element.Methods = {
visible: function(element) {
@@ -1799,7 +1926,6 @@ Element.Methods = {
return element;
},
-
hide: function(element) {
element = $(element);
element.style.display = 'none';
@@ -1845,6 +1971,21 @@ Element.Methods = {
}
})();
+ var LINK_ELEMENT_INNERHTML_BUGGY = (function() {
+ try {
+ var el = document.createElement('div');
+ el.innerHTML = "<link>";
+ var isBuggy = (el.childNodes.length === 0);
+ el = null;
+ return isBuggy;
+ } catch(e) {
+ return true;
+ }
+ })();
+
+ var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY ||
+ TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY;
+
var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
var s = document.createElement("script"),
isBuggy = false;
@@ -1859,8 +2000,14 @@ Element.Methods = {
return isBuggy;
})();
+
function update(element, content) {
element = $(element);
+ var purgeElement = Element._purgeElement;
+
+ var descendants = element.getElementsByTagName('*'),
+ i = descendants.length;
+ while (i--) purgeElement(descendants[i]);
if (content && content.toElement)
content = content.toElement();
@@ -1877,7 +2024,7 @@ Element.Methods = {
return element;
}
- if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) {
+ if (ANY_INNERHTML_BUGGY) {
if (tagName in Element._insertionTranslations.tags) {
while (element.firstChild) {
element.removeChild(element.firstChild);
@@ -1886,6 +2033,12 @@ Element.Methods = {
.each(function(node) {
element.appendChild(node)
});
+ } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf('<link') > -1) {
+ while (element.firstChild) {
+ element.removeChild(element.firstChild);
+ }
+ var nodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts(), true);
+ nodes.each(function(node) { element.appendChild(node) });
}
else {
element.innerHTML = content.stripScripts();
@@ -1968,19 +2121,26 @@ Element.Methods = {
element = $(element);
var result = '<' + element.tagName.toLowerCase();
$H({'id': 'id', 'className': 'class'}).each(function(pair) {
- var property = pair.first(), attribute = pair.last();
- var value = (element[property] || '').toString();
+ var property = pair.first(),
+ attribute = pair.last(),
+ value = (element[property] || '').toString();
if (value) result += ' ' + attribute + '=' + value.inspect(true);
});
return result + '>';
},
- recursivelyCollect: function(element, property) {
+ recursivelyCollect: function(element, property, maximumLength) {
element = $(element);
+ maximumLength = maximumLength || -1;
var elements = [];
- while (element = element[property])
+
+ while (element = element[property]) {
if (element.nodeType == 1)
elements.push(Element.extend(element));
+ if (elements.length == maximumLength)
+ break;
+ }
+
return elements;
},
@@ -1999,13 +2159,17 @@ Element.Methods = {
},
immediateDescendants: function(element) {
- if (!(element = $(element).firstChild)) return [];
- while (element && element.nodeType != 1) element = element.nextSibling;
- if (element) return [element].concat($(element).nextSiblings());
- return [];
+ var results = [], child = $(element).firstChild;
+ while (child) {
+ if (child.nodeType === 1) {
+ results.push(Element.extend(child));
+ }
+ child = child.nextSibling;
+ }
+ return results;
},
- previousSiblings: function(element) {
+ previousSiblings: function(element, maximumLength) {
return Element.recursivelyCollect(element, 'previousSibling');
},
@@ -2020,9 +2184,10 @@ Element.Methods = {
},
match: function(element, selector) {
+ element = $(element);
if (Object.isString(selector))
- selector = new Selector(selector);
- return selector.match($(element));
+ return Prototype.Selector.match(element, selector);
+ return selector.match(element);
},
up: function(element, expression, index) {
@@ -2030,7 +2195,7 @@ Element.Methods = {
if (arguments.length == 1) return $(element.parentNode);
var ancestors = Element.ancestors(element);
return Object.isNumber(expression) ? ancestors[expression] :
- Selector.findElement(ancestors, expression, index);
+ Prototype.Selector.find(ancestors, expression, index);
},
down: function(element, expression, index) {
@@ -2042,29 +2207,40 @@ Element.Methods = {
previous: function(element, expression, index) {
element = $(element);
- if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
- var previousSiblings = Element.previousSiblings(element);
- return Object.isNumber(expression) ? previousSiblings[expression] :
- Selector.findElement(previousSiblings, expression, index);
+ if (Object.isNumber(expression)) index = expression, expression = false;
+ if (!Object.isNumber(index)) index = 0;
+
+ if (expression) {
+ return Prototype.Selector.find(element.previousSiblings(), expression, index);
+ } else {
+ return element.recursivelyCollect("previousSibling", index + 1)[index];
+ }
},
next: function(element, expression, index) {
element = $(element);
- if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
- var nextSiblings = Element.nextSiblings(element);
- return Object.isNumber(expression) ? nextSiblings[expression] :
- Selector.findElement(nextSiblings, expression, index);
+ if (Object.isNumber(expression)) index = expression, expression = false;
+ if (!Object.isNumber(index)) index = 0;
+
+ if (expression) {
+ return Prototype.Selector.find(element.nextSiblings(), expression, index);
+ } else {
+ var maximumLength = Object.isNumber(index) ? index + 1 : 1;
+ return element.recursivelyCollect("nextSibling", index + 1)[index];
+ }
},
select: function(element) {
- var args = Array.prototype.slice.call(arguments, 1);
- return Selector.findChildElements(element, args);
+ element = $(element);
+ var expressions = Array.prototype.slice.call(arguments, 1).join(', ');
+ return Prototype.Selector.select(expressions, element);
},
adjacent: function(element) {
- var args = Array.prototype.slice.call(arguments, 1);
- return Selector.findChildElements(element.parentNode, args).without(element);
+ element = $(element);
+ var expressions = Array.prototype.slice.call(arguments, 1).join(', ');
+ return Prototype.Selector.select(expressions, element.parentNode).without(element);
},
identify: function(element) {
@@ -2228,28 +2404,6 @@ Element.Methods = {
return element;
},
- getDimensions: function(element) {
- element = $(element);
- var display = Element.getStyle(element, 'display');
- if (display != 'none' && display != null) // Safari bug
- return {width: element.offsetWidth, height: element.offsetHeight};
-
- var els = element.style;
- var originalVisibility = els.visibility;
- var originalPosition = els.position;
- var originalDisplay = els.display;
- els.visibility = 'hidden';
- if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari
- els.position = 'absolute';
- els.display = 'block';
- var originalWidth = element.clientWidth;
- var originalHeight = element.clientHeight;
- els.display = originalDisplay;
- els.position = originalPosition;
- els.visibility = originalVisibility;
- return {width: originalWidth, height: originalHeight};
- },
-
makePositioned: function(element) {
element = $(element);
var pos = Element.getStyle(element, 'position');
@@ -2294,114 +2448,6 @@ Element.Methods = {
return element;
},
- cumulativeOffset: function(element) {
- var valueT = 0, valueL = 0;
- do {
- valueT += element.offsetTop || 0;
- valueL += element.offsetLeft || 0;
- element = element.offsetParent;
- } while (element);
- return Element._returnOffset(valueL, valueT);
- },
-
- positionedOffset: function(element) {
- var valueT = 0, valueL = 0;
- do {
- valueT += element.offsetTop || 0;
- valueL += element.offsetLeft || 0;
- element = element.offsetParent;
- if (element) {
- if (element.tagName.toUpperCase() == 'BODY') break;
- var p = Element.getStyle(element, 'position');
- if (p !== 'static') break;
- }
- } while (element);
- return Element._returnOffset(valueL, valueT);
- },
-
- absolutize: function(element) {
- element = $(element);
- if (Element.getStyle(element, 'position') == 'absolute') return element;
-
- var offsets = Element.positionedOffset(element);
- var top = offsets[1];
- var left = offsets[0];
- var width = element.clientWidth;
- var height = element.clientHeight;
-
- element._originalLeft = left - parseFloat(element.style.left || 0);
- element._originalTop = top - parseFloat(element.style.top || 0);
- element._originalWidth = element.style.width;
- element._originalHeight = element.style.height;
-
- element.style.position = 'absolute';
- element.style.top = top + 'px';
- element.style.left = left + 'px';
- element.style.width = width + 'px';
- element.style.height = height + 'px';
- return element;
- },
-
- relativize: function(element) {
- element = $(element);
- if (Element.getStyle(element, 'position') == 'relative') return element;
-
- element.style.position = 'relative';
- var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
- var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
-
- element.style.top = top + 'px';
- element.style.left = left + 'px';
- element.style.height = element._originalHeight;
- element.style.width = element._originalWidth;
- return element;
- },
-
- cumulativeScrollOffset: function(element) {
- var valueT = 0, valueL = 0;
- do {
- valueT += element.scrollTop || 0;
- valueL += element.scrollLeft || 0;
- element = element.parentNode;
- } while (element);
- return Element._returnOffset(valueL, valueT);
- },
-
- getOffsetParent: function(element) {
- if (element.offsetParent) return $(element.offsetParent);
- if (element == document.body) return $(element);
-
- while ((element = element.parentNode) && element != document.body)
- if (Element.getStyle(element, 'position') != 'static')
- return $(element);
-
- return $(document.body);
- },
-
- viewportOffset: function(forElement) {
- var valueT = 0, valueL = 0;
-
- var element = forElement;
- do {
- valueT += element.offsetTop || 0;
- valueL += element.offsetLeft || 0;
-
- if (element.offsetParent == document.body &&
- Element.getStyle(element, 'position') == 'absolute') break;
-
- } while (element = element.offsetParent);
-
- element = forElement;
- do {
- if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {
- valueT -= element.scrollTop || 0;
- valueL -= element.scrollLeft || 0;
- }
- } while (element = element.parentNode);
-
- return Element._returnOffset(valueL, valueT);
- },
-
clonePosition: function(element, source) {
var options = Object.extend({
setLeft: true,
@@ -2413,11 +2459,10 @@ Element.Methods = {
}, arguments[2] || { });
source = $(source);
- var p = Element.viewportOffset(source);
+ var p = Element.viewportOffset(source), delta = [0, 0], parent = null;
element = $(element);
- var delta = [0, 0];
- var parent = null;
+
if (Element.getStyle(element, 'position') == 'absolute') {
parent = Element.getOffsetParent(element);
delta = Element.viewportOffset(parent);
@@ -2456,8 +2501,6 @@ if (Prototype.Browser.Opera) {
Element.Methods.getStyle = Element.Methods.getStyle.wrap(
function(proceed, element, style) {
switch (style) {
- case 'left': case 'top': case 'right': case 'bottom':
- if (proceed(element, 'position') === 'static') return null;
case 'height': case 'width':
if (!Element.visible(element)) return null;
@@ -2493,47 +2536,6 @@ if (Prototype.Browser.Opera) {
}
else if (Prototype.Browser.IE) {
- Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
- function(proceed, element) {
- element = $(element);
- try { element.offsetParent }
- catch(e) { return $(document.body) }
- var position = element.getStyle('position');
- if (position !== 'static') return proceed(element);
- element.setStyle({ position: 'relative' });
- var value = proceed(element);
- element.setStyle({ position: position });
- return value;
- }
- );
-
- $w('positionedOffset viewportOffset').each(function(method) {
- Element.Methods[method] = Element.Methods[method].wrap(
- function(proceed, element) {
- element = $(element);
- try { element.offsetParent }
- catch(e) { return Element._returnOffset(0,0) }
- var position = element.getStyle('position');
- if (position !== 'static') return proceed(element);
- var offsetParent = element.getOffsetParent();
- if (offsetParent && offsetParent.getStyle('position') === 'fixed')
- offsetParent.setStyle({ zoom: 1 });
- element.setStyle({ position: 'relative' });
- var value = proceed(element);
- element.setStyle({ position: position });
- return value;
- }
- );
- });
-
- Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(
- function(proceed, element) {
- try { element.offsetParent }
- catch(e) { return Element._returnOffset(0,0) }
- return proceed(element);
- }
- );
-
Element.Methods.getStyle = function(element, style) {
element = $(element);
style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
@@ -2577,10 +2579,9 @@ else if (Prototype.Browser.IE) {
Element._attributeTranslations = (function(){
- var classProp = 'className';
- var forProp = 'for';
-
- var el = document.createElement('div');
+ var classProp = 'className',
+ forProp = 'for',
+ el = document.createElement('div');
el.setAttribute(classProp, 'x');
@@ -2623,10 +2624,9 @@ else if (Prototype.Browser.IE) {
},
_getEv: (function(){
- var el = document.createElement('div');
+ var el = document.createElement('div'), f;
el.onclick = Prototype.emptyFunction;
var value = el.getAttribute('onclick');
- var f;
if (String(value).indexOf('{') > -1) {
f = function(element, attribute) {
@@ -2754,7 +2754,7 @@ else if (Prototype.Browser.WebKit) {
(value < 0.00001) ? 0 : value;
if (value == 1)
- if(element.tagName.toUpperCase() == 'IMG' && element.width) {
+ if (element.tagName.toUpperCase() == 'IMG' && element.width) {
element.width++; element.width--;
} else try {
var n = document.createTextNode(' ');
@@ -2764,20 +2764,6 @@ else if (Prototype.Browser.WebKit) {
return element;
};
-
- Element.Methods.cumulativeOffset = function(element) {
- var valueT = 0, valueL = 0;
- do {
- valueT += element.offsetTop || 0;
- valueL += element.offsetLeft || 0;
- if (element.offsetParent == document.body)
- if (Element.getStyle(element, 'position') == 'absolute') break;
-
- element = element.offsetParent;
- } while (element);
-
- return Element._returnOffset(valueL, valueT);
- };
}
if ('outerHTML' in document.documentElement) {
@@ -2794,8 +2780,8 @@ if ('outerHTML' in document.documentElement) {
var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
if (Element._insertionTranslations.tags[tagName]) {
- var nextSibling = element.next();
- var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+ var nextSibling = element.next(),
+ fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
parent.removeChild(element);
if (nextSibling)
fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
@@ -2816,12 +2802,27 @@ Element._returnOffset = function(l, t) {
return result;
};
-Element._getContentFromAnonymousElement = function(tagName, html) {
- var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
- if (t) {
- div.innerHTML = t[0] + html + t[1];
- t[2].times(function() { div = div.firstChild });
- } else div.innerHTML = html;
+Element._getContentFromAnonymousElement = function(tagName, html, force) {
+ var div = new Element('div'),
+ t = Element._insertionTranslations.tags[tagName];
+
+ var workaround = false;
+ if (t) workaround = true;
+ else if (force) {
+ workaround = true;
+ t = ['', '', 0];
+ }
+
+ if (workaround) {
+ div.innerHTML = '&nbsp;' + t[0] + html + t[1];
+ div.removeChild(div.firstChild);
+ for (var i = t[2]; i--; ) {
+ div = div.firstChild;
+ }
+ }
+ else {
+ div.innerHTML = html;
+ }
return $A(div.childNodes);
};
@@ -2878,7 +2879,7 @@ Object.extend(Element, Element.Methods);
div = null;
-})(document.createElement('div'))
+})(document.createElement('div'));
Element.extend = (function() {
@@ -2886,8 +2887,8 @@ Element.extend = (function() {
if (typeof window.Element != 'undefined') {
var proto = window.Element.prototype;
if (proto) {
- var id = '_' + (Math.random()+'').slice(2);
- var el = document.createElement(tagName);
+ var id = '_' + (Math.random()+'').slice(2),
+ el = document.createElement(tagName);
proto[id] = 'x';
var isBuggy = (el[id] !== 'x');
delete proto[id];
@@ -2954,10 +2955,14 @@ Element.extend = (function() {
return extend;
})();
-Element.hasAttribute = function(element, attribute) {
- if (element.hasAttribute) return element.hasAttribute(attribute);
- return Element.Methods.Simulated.hasAttribute(element, attribute);
-};
+if (document.documentElement.hasAttribute) {
+ Element.hasAttribute = function(element, attribute) {
+ return element.hasAttribute(attribute);
+ };
+}
+else {
+ Element.hasAttribute = Element.Methods.Simulated.hasAttribute;
+}
Element.addMethods = function(methods) {
var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
@@ -2969,7 +2974,8 @@ Element.addMethods = function(methods) {
"FORM": Object.clone(Form.Methods),
"INPUT": Object.clone(Form.Element.Methods),
"SELECT": Object.clone(Form.Element.Methods),
- "TEXTAREA": Object.clone(Form.Element.Methods)
+ "TEXTAREA": Object.clone(Form.Element.Methods),
+ "BUTTON": Object.clone(Form.Element.Methods)
});
}
@@ -3021,8 +3027,9 @@ Element.addMethods = function(methods) {
klass = 'HTML' + tagName.capitalize() + 'Element';
if (window[klass]) return window[klass];
- var element = document.createElement(tagName);
- var proto = element['__proto__'] || element.constructor.prototype;
+ var element = document.createElement(tagName),
+ proto = element['__proto__'] || element.constructor.prototype;
+
element = null;
return proto;
}
@@ -3105,8 +3112,8 @@ Element.addMethods({
uid = 0;
} else {
if (typeof element._prototypeUID === "undefined")
- element._prototypeUID = [Element.Storage.UID++];
- uid = element._prototypeUID[0];
+ element._prototypeUID = Element.Storage.UID++;
+ uid = element._prototypeUID;
}
if (!Element.Storage[uid])
@@ -3151,770 +3158,1808 @@ Element.addMethods({
}
}
return Element.extend(clone);
- }
-});
-/* Portions of the Selector class are derived from Jack Slocum's DomQuery,
- * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
- * license. Please see http://www.yui-ext.com/ for more information. */
-
-var Selector = Class.create({
- initialize: function(expression) {
- this.expression = expression.strip();
-
- if (this.shouldUseSelectorsAPI()) {
- this.mode = 'selectorsAPI';
- } else if (this.shouldUseXPath()) {
- this.mode = 'xpath';
- this.compileXPathMatcher();
- } else {
- this.mode = "normal";
- this.compileMatcher();
- }
-
},
- shouldUseXPath: (function() {
-
- var IS_DESCENDANT_SELECTOR_BUGGY = (function(){
- var isBuggy = false;
- if (document.evaluate && window.XPathResult) {
- var el = document.createElement('div');
- el.innerHTML = '<ul><li></li></ul><div><ul><li></li></ul></div>';
+ purge: function(element) {
+ if (!(element = $(element))) return;
+ var purgeElement = Element._purgeElement;
- var xpath = ".//*[local-name()='ul' or local-name()='UL']" +
- "//*[local-name()='li' or local-name()='LI']";
+ purgeElement(element);
- var result = document.evaluate(xpath, el, null,
- XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+ var descendants = element.getElementsByTagName('*'),
+ i = descendants.length;
- isBuggy = (result.snapshotLength !== 2);
- el = null;
- }
- return isBuggy;
- })();
+ while (i--) purgeElement(descendants[i]);
- return function() {
- if (!Prototype.BrowserFeatures.XPath) return false;
-
- var e = this.expression;
-
- if (Prototype.Browser.WebKit &&
- (e.include("-of-type") || e.include(":empty")))
- return false;
+ return null;
+ }
+});
- if ((/(\[[\w-]*?:|:checked)/).test(e))
- return false;
+(function() {
- if (IS_DESCENDANT_SELECTOR_BUGGY) return false;
+ function toDecimal(pctString) {
+ var match = pctString.match(/^(\d+)%?$/i);
+ if (!match) return null;
+ return (Number(match[1]) / 100);
+ }
- return true;
+ function getPixelValue(value, property, context) {
+ var element = null;
+ if (Object.isElement(value)) {
+ element = value;
+ value = element.getStyle(property);
}
- })(),
+ if (value === null) {
+ return null;
+ }
- shouldUseSelectorsAPI: function() {
- if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
+ if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) {
+ return window.parseFloat(value);
+ }
- if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false;
+ var isPercentage = value.include('%'), isViewport = (context === document.viewport);
- if (!Selector._div) Selector._div = new Element('div');
+ if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) {
+ var style = element.style.left, rStyle = element.runtimeStyle.left;
+ element.runtimeStyle.left = element.currentStyle.left;
+ element.style.left = value || 0;
+ value = element.style.pixelLeft;
+ element.style.left = style;
+ element.runtimeStyle.left = rStyle;
- try {
- Selector._div.querySelector(this.expression);
- } catch(e) {
- return false;
+ return value;
}
- return true;
- },
+ if (element && isPercentage) {
+ context = context || element.parentNode;
+ var decimal = toDecimal(value);
+ var whole = null;
+ var position = element.getStyle('position');
- compileMatcher: function() {
- var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
- c = Selector.criteria, le, p, m, len = ps.length, name;
+ var isHorizontal = property.include('left') || property.include('right') ||
+ property.include('width');
- if (Selector._cache[e]) {
- this.matcher = Selector._cache[e];
- return;
- }
+ var isVertical = property.include('top') || property.include('bottom') ||
+ property.include('height');
- this.matcher = ["this.matcher = function(root) {",
- "var r = root, h = Selector.handlers, c = false, n;"];
-
- while (e && le != e && (/\S/).test(e)) {
- le = e;
- for (var i = 0; i<len; i++) {
- p = ps[i].re;
- name = ps[i].name;
- if (m = e.match(p)) {
- this.matcher.push(Object.isFunction(c[name]) ? c[name](m) :
- new Template(c[name]).evaluate(m));
- e = e.replace(m[0], '');
- break;
+ if (context === document.viewport) {
+ if (isHorizontal) {
+ whole = document.viewport.getWidth();
+ } else if (isVertical) {
+ whole = document.viewport.getHeight();
+ }
+ } else {
+ if (isHorizontal) {
+ whole = $(context).measure('width');
+ } else if (isVertical) {
+ whole = $(context).measure('height');
}
}
- }
- this.matcher.push("return h.unique(n);\n}");
- eval(this.matcher.join('\n'));
- Selector._cache[this.expression] = this.matcher;
- },
+ return (whole === null) ? 0 : whole * decimal;
+ }
- compileXPathMatcher: function() {
- var e = this.expression, ps = Selector.patterns,
- x = Selector.xpath, le, m, len = ps.length, name;
+ return 0;
+ }
- if (Selector._cache[e]) {
- this.xpath = Selector._cache[e]; return;
+ function toCSSPixels(number) {
+ if (Object.isString(number) && number.endsWith('px')) {
+ return number;
}
+ return number + 'px';
+ }
- this.matcher = ['.//*'];
- while (e && le != e && (/\S/).test(e)) {
- le = e;
- for (var i = 0; i<len; i++) {
- name = ps[i].name;
- if (m = e.match(ps[i].re)) {
- this.matcher.push(Object.isFunction(x[name]) ? x[name](m) :
- new Template(x[name]).evaluate(m));
- e = e.replace(m[0], '');
- break;
- }
+ function isDisplayed(element) {
+ var originalElement = element;
+ while (element && element.parentNode) {
+ var display = element.getStyle('display');
+ if (display === 'none') {
+ return false;
}
+ element = $(element.parentNode);
}
+ return true;
+ }
- this.xpath = this.matcher.join('');
- Selector._cache[this.expression] = this.xpath;
- },
+ var hasLayout = Prototype.K;
+ if ('currentStyle' in document.documentElement) {
+ hasLayout = function(element) {
+ if (!element.currentStyle.hasLayout) {
+ element.style.zoom = 1;
+ }
+ return element;
+ };
+ }
- findElements: function(root) {
- root = root || document;
- var e = this.expression, results;
+ function cssNameFor(key) {
+ if (key.include('border')) key = key + '-width';
+ return key.camelize();
+ }
- switch (this.mode) {
- case 'selectorsAPI':
- if (root !== document) {
- var oldId = root.id, id = $(root).identify();
- id = id.replace(/([\.:])/g, "\\$1");
- e = "#" + id + " " + e;
- }
+ Element.Layout = Class.create(Hash, {
+ initialize: function($super, element, preCompute) {
+ $super();
+ this.element = $(element);
- results = $A(root.querySelectorAll(e)).map(Element.extend);
- root.id = oldId;
+ Element.Layout.PROPERTIES.each( function(property) {
+ this._set(property, null);
+ }, this);
- return results;
- case 'xpath':
- return document._getElementsByXPath(this.xpath, root);
- default:
- return this.matcher(root);
- }
- },
+ if (preCompute) {
+ this._preComputing = true;
+ this._begin();
+ Element.Layout.PROPERTIES.each( this._compute, this );
+ this._end();
+ this._preComputing = false;
+ }
+ },
- match: function(element) {
- this.tokens = [];
-
- var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
- var le, p, m, len = ps.length, name;
-
- while (e && le !== e && (/\S/).test(e)) {
- le = e;
- for (var i = 0; i<len; i++) {
- p = ps[i].re;
- name = ps[i].name;
- if (m = e.match(p)) {
- if (as[name]) {
- this.tokens.push([name, Object.clone(m)]);
- e = e.replace(m[0], '');
- } else {
- return this.findElements(document).include(element);
- }
- }
+ _set: function(property, value) {
+ return Hash.prototype.set.call(this, property, value);
+ },
+
+ set: function(property, value) {
+ throw "Properties of Element.Layout are read-only.";
+ },
+
+ get: function($super, property) {
+ var value = $super(property);
+ return value === null ? this._compute(property) : value;
+ },
+
+ _begin: function() {
+ if (this._prepared) return;
+
+ var element = this.element;
+ if (isDisplayed(element)) {
+ this._prepared = true;
+ return;
}
- }
- var match = true, name, matches;
- for (var i = 0, token; token = this.tokens[i]; i++) {
- name = token[0], matches = token[1];
- if (!Selector.assertions[name](element, matches)) {
- match = false; break;
+ var originalStyles = {
+ position: element.style.position || '',
+ width: element.style.width || '',
+ visibility: element.style.visibility || '',
+ display: element.style.display || ''
+ };
+
+ element.store('prototype_original_styles', originalStyles);
+
+ var position = element.getStyle('position'),
+ width = element.getStyle('width');
+
+ if (width === "0px" || width === null) {
+ element.style.display = 'block';
+ width = element.getStyle('width');
}
- }
- return match;
- },
+ var context = (position === 'fixed') ? document.viewport :
+ element.parentNode;
- toString: function() {
- return this.expression;
- },
+ element.setStyle({
+ position: 'absolute',
+ visibility: 'hidden',
+ display: 'block'
+ });
- inspect: function() {
- return "#<Selector:" + this.expression.inspect() + ">";
- }
-});
+ var positionedWidth = element.getStyle('width');
-if (Prototype.BrowserFeatures.SelectorsAPI &&
- document.compatMode === 'BackCompat') {
- Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){
- var div = document.createElement('div'),
- span = document.createElement('span');
-
- div.id = "prototype_test_id";
- span.className = 'Test';
- div.appendChild(span);
- var isIgnored = (div.querySelector('#prototype_test_id .test') !== null);
- div = span = null;
- return isIgnored;
- })();
-}
+ var newWidth;
+ if (width && (positionedWidth === width)) {
+ newWidth = getPixelValue(element, 'width', context);
+ } else if (position === 'absolute' || position === 'fixed') {
+ newWidth = getPixelValue(element, 'width', context);
+ } else {
+ var parent = element.parentNode, pLayout = $(parent).getLayout();
+
+ newWidth = pLayout.get('width') -
+ this.get('margin-left') -
+ this.get('border-left') -
+ this.get('padding-left') -
+ this.get('padding-right') -
+ this.get('border-right') -
+ this.get('margin-right');
+ }
-Object.extend(Selector, {
- _cache: { },
-
- xpath: {
- descendant: "//*",
- child: "/*",
- adjacent: "/following-sibling::*[1]",
- laterSibling: '/following-sibling::*',
- tagName: function(m) {
- if (m[1] == '*') return '';
- return "[local-name()='" + m[1].toLowerCase() +
- "' or local-name()='" + m[1].toUpperCase() + "']";
+ element.setStyle({ width: newWidth + 'px' });
+
+ this._prepared = true;
+ },
+
+ _end: function() {
+ var element = this.element;
+ var originalStyles = element.retrieve('prototype_original_styles');
+ element.store('prototype_original_styles', null);
+ element.setStyle(originalStyles);
+ this._prepared = false;
},
- className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
- id: "[@id='#{1}']",
- attrPresence: function(m) {
- m[1] = m[1].toLowerCase();
- return new Template("[@#{1}]").evaluate(m);
+
+ _compute: function(property) {
+ var COMPUTATIONS = Element.Layout.COMPUTATIONS;
+ if (!(property in COMPUTATIONS)) {
+ throw "Property not found.";
+ }
+
+ return this._set(property, COMPUTATIONS[property].call(this, this.element));
},
- attr: function(m) {
- m[1] = m[1].toLowerCase();
- m[3] = m[5] || m[6];
- return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
+
+ toObject: function() {
+ var args = $A(arguments);
+ var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
+ args.join(' ').split(' ');
+ var obj = {};
+ keys.each( function(key) {
+ if (!Element.Layout.PROPERTIES.include(key)) return;
+ var value = this.get(key);
+ if (value != null) obj[key] = value;
+ }, this);
+ return obj;
},
- pseudo: function(m) {
- var h = Selector.xpath.pseudos[m[1]];
- if (!h) return '';
- if (Object.isFunction(h)) return h(m);
- return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
+
+ toHash: function() {
+ var obj = this.toObject.apply(this, arguments);
+ return new Hash(obj);
},
- operators: {
- '=': "[@#{1}='#{3}']",
- '!=': "[@#{1}!='#{3}']",
- '^=': "[starts-with(@#{1}, '#{3}')]",
- '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
- '*=': "[contains(@#{1}, '#{3}')]",
- '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
- '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
+
+ toCSS: function() {
+ var args = $A(arguments);
+ var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
+ args.join(' ').split(' ');
+ var css = {};
+
+ keys.each( function(key) {
+ if (!Element.Layout.PROPERTIES.include(key)) return;
+ if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return;
+
+ var value = this.get(key);
+ if (value != null) css[cssNameFor(key)] = value + 'px';
+ }, this);
+ return css;
},
- pseudos: {
- 'first-child': '[not(preceding-sibling::*)]',
- 'last-child': '[not(following-sibling::*)]',
- 'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
- 'empty': "[count(*) = 0 and (count(text()) = 0)]",
- 'checked': "[@checked]",
- 'disabled': "[(@disabled) and (@type!='hidden')]",
- 'enabled': "[not(@disabled) and (@type!='hidden')]",
- 'not': function(m) {
- var e = m[6], p = Selector.patterns,
- x = Selector.xpath, le, v, len = p.length, name;
-
- var exclusion = [];
- while (e && le != e && (/\S/).test(e)) {
- le = e;
- for (var i = 0; i<len; i++) {
- name = p[i].name
- if (m = e.match(p[i].re)) {
- v = Object.isFunction(x[name]) ? x[name](m) : new Template(x[name]).evaluate(m);
- exclusion.push("(" + v.substring(1, v.length - 1) + ")");
- e = e.replace(m[0], '');
- break;
- }
- }
+
+ inspect: function() {
+ return "#<Element.Layout>";
+ }
+ });
+
+ Object.extend(Element.Layout, {
+ PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'),
+
+ COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
+
+ COMPUTATIONS: {
+ 'height': function(element) {
+ if (!this._preComputing) this._begin();
+
+ var bHeight = this.get('border-box-height');
+ if (bHeight <= 0) {
+ if (!this._preComputing) this._end();
+ return 0;
}
- return "[not(" + exclusion.join(" and ") + ")]";
+
+ var bTop = this.get('border-top'),
+ bBottom = this.get('border-bottom');
+
+ var pTop = this.get('padding-top'),
+ pBottom = this.get('padding-bottom');
+
+ if (!this._preComputing) this._end();
+
+ return bHeight - bTop - bBottom - pTop - pBottom;
},
- 'nth-child': function(m) {
- return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
+
+ 'width': function(element) {
+ if (!this._preComputing) this._begin();
+
+ var bWidth = this.get('border-box-width');
+ if (bWidth <= 0) {
+ if (!this._preComputing) this._end();
+ return 0;
+ }
+
+ var bLeft = this.get('border-left'),
+ bRight = this.get('border-right');
+
+ var pLeft = this.get('padding-left'),
+ pRight = this.get('padding-right');
+
+ if (!this._preComputing) this._end();
+
+ return bWidth - bLeft - bRight - pLeft - pRight;
},
- 'nth-last-child': function(m) {
- return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
+
+ 'padding-box-height': function(element) {
+ var height = this.get('height'),
+ pTop = this.get('padding-top'),
+ pBottom = this.get('padding-bottom');
+
+ return height + pTop + pBottom;
},
- 'nth-of-type': function(m) {
- return Selector.xpath.pseudos.nth("position() ", m);
+
+ 'padding-box-width': function(element) {
+ var width = this.get('width'),
+ pLeft = this.get('padding-left'),
+ pRight = this.get('padding-right');
+
+ return width + pLeft + pRight;
},
- 'nth-last-of-type': function(m) {
- return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
+
+ 'border-box-height': function(element) {
+ if (!this._preComputing) this._begin();
+ var height = element.offsetHeight;
+ if (!this._preComputing) this._end();
+ return height;
},
- 'first-of-type': function(m) {
- m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
+
+ 'border-box-width': function(element) {
+ if (!this._preComputing) this._begin();
+ var width = element.offsetWidth;
+ if (!this._preComputing) this._end();
+ return width;
+ },
+
+ 'margin-box-height': function(element) {
+ var bHeight = this.get('border-box-height'),
+ mTop = this.get('margin-top'),
+ mBottom = this.get('margin-bottom');
+
+ if (bHeight <= 0) return 0;
+
+ return bHeight + mTop + mBottom;
},
- 'last-of-type': function(m) {
- m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
+
+ 'margin-box-width': function(element) {
+ var bWidth = this.get('border-box-width'),
+ mLeft = this.get('margin-left'),
+ mRight = this.get('margin-right');
+
+ if (bWidth <= 0) return 0;
+
+ return bWidth + mLeft + mRight;
},
- 'only-of-type': function(m) {
- var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
+
+ 'top': function(element) {
+ var offset = element.positionedOffset();
+ return offset.top;
},
- nth: function(fragment, m) {
- var mm, formula = m[6], predicate;
- if (formula == 'even') formula = '2n+0';
- if (formula == 'odd') formula = '2n+1';
- if (mm = formula.match(/^(\d+)$/)) // digit only
- return '[' + fragment + "= " + mm[1] + ']';
- if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
- if (mm[1] == "-") mm[1] = -1;
- var a = mm[1] ? Number(mm[1]) : 1;
- var b = mm[2] ? Number(mm[2]) : 0;
- predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
- "((#{fragment} - #{b}) div #{a} >= 0)]";
- return new Template(predicate).evaluate({
- fragment: fragment, a: a, b: b });
- }
+
+ 'bottom': function(element) {
+ var offset = element.positionedOffset(),
+ parent = element.getOffsetParent(),
+ pHeight = parent.measure('height');
+
+ var mHeight = this.get('border-box-height');
+
+ return pHeight - mHeight - offset.top;
+ },
+
+ 'left': function(element) {
+ var offset = element.positionedOffset();
+ return offset.left;
+ },
+
+ 'right': function(element) {
+ var offset = element.positionedOffset(),
+ parent = element.getOffsetParent(),
+ pWidth = parent.measure('width');
+
+ var mWidth = this.get('border-box-width');
+
+ return pWidth - mWidth - offset.left;
+ },
+
+ 'padding-top': function(element) {
+ return getPixelValue(element, 'paddingTop');
+ },
+
+ 'padding-bottom': function(element) {
+ return getPixelValue(element, 'paddingBottom');
+ },
+
+ 'padding-left': function(element) {
+ return getPixelValue(element, 'paddingLeft');
+ },
+
+ 'padding-right': function(element) {
+ return getPixelValue(element, 'paddingRight');
+ },
+
+ 'border-top': function(element) {
+ return getPixelValue(element, 'borderTopWidth');
+ },
+
+ 'border-bottom': function(element) {
+ return getPixelValue(element, 'borderBottomWidth');
+ },
+
+ 'border-left': function(element) {
+ return getPixelValue(element, 'borderLeftWidth');
+ },
+
+ 'border-right': function(element) {
+ return getPixelValue(element, 'borderRightWidth');
+ },
+
+ 'margin-top': function(element) {
+ return getPixelValue(element, 'marginTop');
+ },
+
+ 'margin-bottom': function(element) {
+ return getPixelValue(element, 'marginBottom');
+ },
+
+ 'margin-left': function(element) {
+ return getPixelValue(element, 'marginLeft');
+ },
+
+ 'margin-right': function(element) {
+ return getPixelValue(element, 'marginRight');
}
}
- },
+ });
- criteria: {
- tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
- className: 'n = h.className(n, r, "#{1}", c); c = false;',
- id: 'n = h.id(n, r, "#{1}", c); c = false;',
- attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
- attr: function(m) {
- m[3] = (m[5] || m[6]);
- return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
- },
- pseudo: function(m) {
- if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
- return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
- },
- descendant: 'c = "descendant";',
- child: 'c = "child";',
- adjacent: 'c = "adjacent";',
- laterSibling: 'c = "laterSibling";'
- },
+ if ('getBoundingClientRect' in document.documentElement) {
+ Object.extend(Element.Layout.COMPUTATIONS, {
+ 'right': function(element) {
+ var parent = hasLayout(element.getOffsetParent());
+ var rect = element.getBoundingClientRect(),
+ pRect = parent.getBoundingClientRect();
+
+ return (pRect.right - rect.right).round();
+ },
- patterns: [
- { name: 'laterSibling', re: /^\s*~\s*/ },
- { name: 'child', re: /^\s*>\s*/ },
- { name: 'adjacent', re: /^\s*\+\s*/ },
- { name: 'descendant', re: /^\s/ },
-
- { name: 'tagName', re: /^\s*(\*|[\w\-]+)(\b|$)?/ },
- { name: 'id', re: /^#([\w\-\*]+)(\b|$)/ },
- { name: 'className', re: /^\.([\w\-\*]+)(\b|$)/ },
- { name: 'pseudo', re: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/ },
- { name: 'attrPresence', re: /^\[((?:[\w-]+:)?[\w-]+)\]/ },
- { name: 'attr', re: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ }
- ],
-
- assertions: {
- tagName: function(element, matches) {
- return matches[1].toUpperCase() == element.tagName.toUpperCase();
+ 'bottom': function(element) {
+ var parent = hasLayout(element.getOffsetParent());
+ var rect = element.getBoundingClientRect(),
+ pRect = parent.getBoundingClientRect();
+
+ return (pRect.bottom - rect.bottom).round();
+ }
+ });
+ }
+
+ Element.Offset = Class.create({
+ initialize: function(left, top) {
+ this.left = left.round();
+ this.top = top.round();
+
+ this[0] = this.left;
+ this[1] = this.top;
},
- className: function(element, matches) {
- return Element.hasClassName(element, matches[1]);
+ relativeTo: function(offset) {
+ return new Element.Offset(
+ this.left - offset.left,
+ this.top - offset.top
+ );
},
- id: function(element, matches) {
- return element.id === matches[1];
+ inspect: function() {
+ return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
},
- attrPresence: function(element, matches) {
- return Element.hasAttribute(element, matches[1]);
+ toString: function() {
+ return "[#{left}, #{top}]".interpolate(this);
},
- attr: function(element, matches) {
- var nodeValue = Element.readAttribute(element, matches[1]);
- return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
+ toArray: function() {
+ return [this.left, this.top];
}
- },
+ });
- handlers: {
- concat: function(a, b) {
- for (var i = 0, node; node = b[i]; i++)
- a.push(node);
- return a;
- },
+ function getLayout(element, preCompute) {
+ return new Element.Layout(element, preCompute);
+ }
- mark: function(nodes) {
- var _true = Prototype.emptyFunction;
- for (var i = 0, node; node = nodes[i]; i++)
- node._countedByPrototype = _true;
- return nodes;
- },
+ function measure(element, property) {
+ return $(element).getLayout().get(property);
+ }
- unmark: (function(){
+ function getDimensions(element) {
+ element = $(element);
+ var display = Element.getStyle(element, 'display');
- var PROPERTIES_ATTRIBUTES_MAP = (function(){
- var el = document.createElement('div'),
- isBuggy = false,
- propName = '_countedByPrototype',
- value = 'x'
- el[propName] = value;
- isBuggy = (el.getAttribute(propName) === value);
- el = null;
- return isBuggy;
- })();
-
- return PROPERTIES_ATTRIBUTES_MAP ?
- function(nodes) {
- for (var i = 0, node; node = nodes[i]; i++)
- node.removeAttribute('_countedByPrototype');
- return nodes;
- } :
- function(nodes) {
- for (var i = 0, node; node = nodes[i]; i++)
- node._countedByPrototype = void 0;
- return nodes;
- }
- })(),
+ if (display && display !== 'none') {
+ return { width: element.offsetWidth, height: element.offsetHeight };
+ }
- index: function(parentNode, reverse, ofType) {
- parentNode._countedByPrototype = Prototype.emptyFunction;
- if (reverse) {
- for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
- var node = nodes[i];
- if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
- }
- } else {
- for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
- if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
- }
- },
+ var style = element.style;
+ var originalStyles = {
+ visibility: style.visibility,
+ position: style.position,
+ display: style.display
+ };
- unique: function(nodes) {
- if (nodes.length == 0) return nodes;
- var results = [], n;
- for (var i = 0, l = nodes.length; i < l; i++)
- if (typeof (n = nodes[i])._countedByPrototype == 'undefined') {
- n._countedByPrototype = Prototype.emptyFunction;
- results.push(Element.extend(n));
- }
- return Selector.handlers.unmark(results);
- },
+ var newStyles = {
+ visibility: 'hidden',
+ display: 'block'
+ };
- descendant: function(nodes) {
- var h = Selector.handlers;
- for (var i = 0, results = [], node; node = nodes[i]; i++)
- h.concat(results, node.getElementsByTagName('*'));
- return results;
- },
+ if (originalStyles.position !== 'fixed')
+ newStyles.position = 'absolute';
- child: function(nodes) {
- var h = Selector.handlers;
- for (var i = 0, results = [], node; node = nodes[i]; i++) {
- for (var j = 0, child; child = node.childNodes[j]; j++)
- if (child.nodeType == 1 && child.tagName != '!') results.push(child);
- }
- return results;
- },
+ Element.setStyle(element, newStyles);
- adjacent: function(nodes) {
- for (var i = 0, results = [], node; node = nodes[i]; i++) {
- var next = this.nextElementSibling(node);
- if (next) results.push(next);
- }
- return results;
- },
+ var dimensions = {
+ width: element.offsetWidth,
+ height: element.offsetHeight
+ };
- laterSibling: function(nodes) {
- var h = Selector.handlers;
- for (var i = 0, results = [], node; node = nodes[i]; i++)
- h.concat(results, Element.nextSiblings(node));
- return results;
- },
+ Element.setStyle(element, originalStyles);
- nextElementSibling: function(node) {
- while (node = node.nextSibling)
- if (node.nodeType == 1) return node;
- return null;
- },
+ return dimensions;
+ }
- previousElementSibling: function(node) {
- while (node = node.previousSibling)
- if (node.nodeType == 1) return node;
- return null;
- },
+ function getOffsetParent(element) {
+ element = $(element);
- tagName: function(nodes, root, tagName, combinator) {
- var uTagName = tagName.toUpperCase();
- var results = [], h = Selector.handlers;
- if (nodes) {
- if (combinator) {
- if (combinator == "descendant") {
- for (var i = 0, node; node = nodes[i]; i++)
- h.concat(results, node.getElementsByTagName(tagName));
- return results;
- } else nodes = this[combinator](nodes);
- if (tagName == "*") return nodes;
- }
- for (var i = 0, node; node = nodes[i]; i++)
- if (node.tagName.toUpperCase() === uTagName) results.push(node);
- return results;
- } else return root.getElementsByTagName(tagName);
- },
+ if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
+ return $(document.body);
- id: function(nodes, root, id, combinator) {
- var targetNode = $(id), h = Selector.handlers;
+ var isInline = (Element.getStyle(element, 'display') === 'inline');
+ if (!isInline && element.offsetParent) return $(element.offsetParent);
- if (root == document) {
- if (!targetNode) return [];
- if (!nodes) return [targetNode];
- } else {
- if (!root.sourceIndex || root.sourceIndex < 1) {
- var nodes = root.getElementsByTagName('*');
- for (var j = 0, node; node = nodes[j]; j++) {
- if (node.id === id) return [node];
- }
- }
+ while ((element = element.parentNode) && element !== document.body) {
+ if (Element.getStyle(element, 'position') !== 'static') {
+ return isHtml(element) ? $(document.body) : $(element);
}
+ }
- if (nodes) {
- if (combinator) {
- if (combinator == 'child') {
- for (var i = 0, node; node = nodes[i]; i++)
- if (targetNode.parentNode == node) return [targetNode];
- } else if (combinator == 'descendant') {
- for (var i = 0, node; node = nodes[i]; i++)
- if (Element.descendantOf(targetNode, node)) return [targetNode];
- } else if (combinator == 'adjacent') {
- for (var i = 0, node; node = nodes[i]; i++)
- if (Selector.handlers.previousElementSibling(targetNode) == node)
- return [targetNode];
- } else nodes = h[combinator](nodes);
- }
- for (var i = 0, node; node = nodes[i]; i++)
- if (node == targetNode) return [targetNode];
- return [];
- }
- return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
- },
+ return $(document.body);
+ }
- className: function(nodes, root, className, combinator) {
- if (nodes && combinator) nodes = this[combinator](nodes);
- return Selector.handlers.byClassName(nodes, root, className);
- },
- byClassName: function(nodes, root, className) {
- if (!nodes) nodes = Selector.handlers.descendant([root]);
- var needle = ' ' + className + ' ';
- for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
- nodeClassName = node.className;
- if (nodeClassName.length == 0) continue;
- if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
- results.push(node);
+ function cumulativeOffset(element) {
+ element = $(element);
+ var valueT = 0, valueL = 0;
+ if (element.parentNode) {
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ } while (element);
+ }
+ return new Element.Offset(valueL, valueT);
+ }
+
+ function positionedOffset(element) {
+ element = $(element);
+
+ var layout = element.getLayout();
+
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ if (element) {
+ if (isBody(element)) break;
+ var p = Element.getStyle(element, 'position');
+ if (p !== 'static') break;
}
- return results;
- },
+ } while (element);
- attrPresence: function(nodes, root, attr, combinator) {
- if (!nodes) nodes = root.getElementsByTagName("*");
- if (nodes && combinator) nodes = this[combinator](nodes);
- var results = [];
- for (var i = 0, node; node = nodes[i]; i++)
- if (Element.hasAttribute(node, attr)) results.push(node);
- return results;
- },
+ valueL -= layout.get('margin-top');
+ valueT -= layout.get('margin-left');
- attr: function(nodes, root, attr, value, operator, combinator) {
- if (!nodes) nodes = root.getElementsByTagName("*");
- if (nodes && combinator) nodes = this[combinator](nodes);
- var handler = Selector.operators[operator], results = [];
- for (var i = 0, node; node = nodes[i]; i++) {
- var nodeValue = Element.readAttribute(node, attr);
- if (nodeValue === null) continue;
- if (handler(nodeValue, value)) results.push(node);
+ return new Element.Offset(valueL, valueT);
+ }
+
+ function cumulativeScrollOffset(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.scrollTop || 0;
+ valueL += element.scrollLeft || 0;
+ element = element.parentNode;
+ } while (element);
+ return new Element.Offset(valueL, valueT);
+ }
+
+ function viewportOffset(forElement) {
+ element = $(element);
+ var valueT = 0, valueL = 0, docBody = document.body;
+
+ var element = forElement;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ if (element.offsetParent == docBody &&
+ Element.getStyle(element, 'position') == 'absolute') break;
+ } while (element = element.offsetParent);
+
+ element = forElement;
+ do {
+ if (element != docBody) {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
}
- return results;
- },
+ } while (element = element.parentNode);
+ return new Element.Offset(valueL, valueT);
+ }
- pseudo: function(nodes, name, value, root, combinator) {
- if (nodes && combinator) nodes = this[combinator](nodes);
- if (!nodes) nodes = root.getElementsByTagName("*");
- return Selector.pseudos[name](nodes, value, root);
+ function absolutize(element) {
+ element = $(element);
+
+ if (Element.getStyle(element, 'position') === 'absolute') {
+ return element;
}
- },
- pseudos: {
- 'first-child': function(nodes, value, root) {
- for (var i = 0, results = [], node; node = nodes[i]; i++) {
- if (Selector.handlers.previousElementSibling(node)) continue;
- results.push(node);
- }
- return results;
- },
- 'last-child': function(nodes, value, root) {
- for (var i = 0, results = [], node; node = nodes[i]; i++) {
- if (Selector.handlers.nextElementSibling(node)) continue;
- results.push(node);
- }
- return results;
- },
- 'only-child': function(nodes, value, root) {
- var h = Selector.handlers;
- for (var i = 0, results = [], node; node = nodes[i]; i++)
- if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
- results.push(node);
- return results;
- },
- 'nth-child': function(nodes, formula, root) {
- return Selector.pseudos.nth(nodes, formula, root);
- },
- 'nth-last-child': function(nodes, formula, root) {
- return Selector.pseudos.nth(nodes, formula, root, true);
- },
- 'nth-of-type': function(nodes, formula, root) {
- return Selector.pseudos.nth(nodes, formula, root, false, true);
- },
- 'nth-last-of-type': function(nodes, formula, root) {
- return Selector.pseudos.nth(nodes, formula, root, true, true);
- },
- 'first-of-type': function(nodes, formula, root) {
- return Selector.pseudos.nth(nodes, "1", root, false, true);
- },
- 'last-of-type': function(nodes, formula, root) {
- return Selector.pseudos.nth(nodes, "1", root, true, true);
- },
- 'only-of-type': function(nodes, formula, root) {
- var p = Selector.pseudos;
- return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
- },
+ var offsetParent = getOffsetParent(element);
+ var eOffset = element.viewportOffset(),
+ pOffset = offsetParent.viewportOffset();
- getIndices: function(a, b, total) {
- if (a == 0) return b > 0 ? [b] : [];
- return $R(1, total).inject([], function(memo, i) {
- if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
- return memo;
- });
- },
+ var offset = eOffset.relativeTo(pOffset);
+ var layout = element.getLayout();
- nth: function(nodes, formula, root, reverse, ofType) {
- if (nodes.length == 0) return [];
- if (formula == 'even') formula = '2n+0';
- if (formula == 'odd') formula = '2n+1';
- var h = Selector.handlers, results = [], indexed = [], m;
- h.mark(nodes);
- for (var i = 0, node; node = nodes[i]; i++) {
- if (!node.parentNode._countedByPrototype) {
- h.index(node.parentNode, reverse, ofType);
- indexed.push(node.parentNode);
- }
- }
- if (formula.match(/^\d+$/)) { // just a number
- formula = Number(formula);
- for (var i = 0, node; node = nodes[i]; i++)
- if (node.nodeIndex == formula) results.push(node);
- } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
- if (m[1] == "-") m[1] = -1;
- var a = m[1] ? Number(m[1]) : 1;
- var b = m[2] ? Number(m[2]) : 0;
- var indices = Selector.pseudos.getIndices(a, b, nodes.length);
- for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
- for (var j = 0; j < l; j++)
- if (node.nodeIndex == indices[j]) results.push(node);
- }
- }
- h.unmark(nodes);
- h.unmark(indexed);
- return results;
- },
+ element.store('prototype_absolutize_original_styles', {
+ left: element.getStyle('left'),
+ top: element.getStyle('top'),
+ width: element.getStyle('width'),
+ height: element.getStyle('height')
+ });
+
+ element.setStyle({
+ position: 'absolute',
+ top: offset.top + 'px',
+ left: offset.left + 'px',
+ width: layout.get('width') + 'px',
+ height: layout.get('height') + 'px'
+ });
+
+ return element;
+ }
- 'empty': function(nodes, value, root) {
- for (var i = 0, results = [], node; node = nodes[i]; i++) {
- if (node.tagName == '!' || node.firstChild) continue;
- results.push(node);
+ function relativize(element) {
+ element = $(element);
+ if (Element.getStyle(element, 'position') === 'relative') {
+ return element;
+ }
+
+ var originalStyles =
+ element.retrieve('prototype_absolutize_original_styles');
+
+ if (originalStyles) element.setStyle(originalStyles);
+ return element;
+ }
+
+ if (Prototype.Browser.IE) {
+ getOffsetParent = getOffsetParent.wrap(
+ function(proceed, element) {
+ element = $(element);
+
+ if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
+ return $(document.body);
+
+ var position = element.getStyle('position');
+ if (position !== 'static') return proceed(element);
+
+ element.setStyle({ position: 'relative' });
+ var value = proceed(element);
+ element.setStyle({ position: position });
+ return value;
}
- return results;
- },
+ );
- 'not': function(nodes, selector, root) {
- var h = Selector.handlers, selectorType, m;
- var exclusions = new Selector(selector).findElements(root);
- h.mark(exclusions);
- for (var i = 0, results = [], node; node = nodes[i]; i++)
- if (!node._countedByPrototype) results.push(node);
- h.unmark(exclusions);
- return results;
- },
+ positionedOffset = positionedOffset.wrap(function(proceed, element) {
+ element = $(element);
+ if (!element.parentNode) return new Element.Offset(0, 0);
+ var position = element.getStyle('position');
+ if (position !== 'static') return proceed(element);
- 'enabled': function(nodes, value, root) {
- for (var i = 0, results = [], node; node = nodes[i]; i++)
- if (!node.disabled && (!node.type || node.type !== 'hidden'))
- results.push(node);
- return results;
- },
+ var offsetParent = element.getOffsetParent();
+ if (offsetParent && offsetParent.getStyle('position') === 'fixed')
+ hasLayout(offsetParent);
- 'disabled': function(nodes, value, root) {
- for (var i = 0, results = [], node; node = nodes[i]; i++)
- if (node.disabled) results.push(node);
- return results;
- },
+ element.setStyle({ position: 'relative' });
+ var value = proceed(element);
+ element.setStyle({ position: position });
+ return value;
+ });
+ } else if (Prototype.Browser.Webkit) {
+ cumulativeOffset = function(element) {
+ element = $(element);
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ if (element.offsetParent == document.body)
+ if (Element.getStyle(element, 'position') == 'absolute') break;
- 'checked': function(nodes, value, root) {
- for (var i = 0, results = [], node; node = nodes[i]; i++)
- if (node.checked) results.push(node);
- return results;
- }
- },
+ element = element.offsetParent;
+ } while (element);
- operators: {
- '=': function(nv, v) { return nv == v; },
- '!=': function(nv, v) { return nv != v; },
- '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },
- '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },
- '*=': function(nv, v) { return nv == v || nv && nv.include(v); },
- '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
- '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
- '-').include('-' + (v || "").toUpperCase() + '-'); }
- },
+ return new Element.Offset(valueL, valueT);
+ };
+ }
- split: function(expression) {
- var expressions = [];
- expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
- expressions.push(m[1].strip());
+
+ Element.addMethods({
+ getLayout: getLayout,
+ measure: measure,
+ getDimensions: getDimensions,
+ getOffsetParent: getOffsetParent,
+ cumulativeOffset: cumulativeOffset,
+ positionedOffset: positionedOffset,
+ cumulativeScrollOffset: cumulativeScrollOffset,
+ viewportOffset: viewportOffset,
+ absolutize: absolutize,
+ relativize: relativize
+ });
+
+ function isBody(element) {
+ return element.nodeName.toUpperCase() === 'BODY';
+ }
+
+ function isHtml(element) {
+ return element.nodeName.toUpperCase() === 'HTML';
+ }
+
+ function isDocument(element) {
+ return element.nodeType === Node.DOCUMENT_NODE;
+ }
+
+ function isDetached(element) {
+ return element !== document.body &&
+ !Element.descendantOf(element, document.body);
+ }
+
+ if ('getBoundingClientRect' in document.documentElement) {
+ Element.addMethods({
+ viewportOffset: function(element) {
+ element = $(element);
+ if (isDetached(element)) return new Element.Offset(0, 0);
+
+ var rect = element.getBoundingClientRect(),
+ docEl = document.documentElement;
+ return new Element.Offset(rect.left - docEl.clientLeft,
+ rect.top - docEl.clientTop);
+ }
});
- return expressions;
- },
+ }
+})();
+window.$$ = function() {
+ var expression = $A(arguments).join(', ');
+ return Prototype.Selector.select(expression, document);
+};
- matchElements: function(elements, expression) {
- var matches = $$(expression), h = Selector.handlers;
- h.mark(matches);
- for (var i = 0, results = [], element; element = elements[i]; i++)
- if (element._countedByPrototype) results.push(element);
- h.unmark(matches);
- return results;
- },
+Prototype.Selector = (function() {
+
+ function select() {
+ throw new Error('Method "Prototype.Selector.select" must be defined.');
+ }
- findElement: function(elements, expression, index) {
- if (Object.isNumber(expression)) {
- index = expression; expression = false;
+ function match() {
+ throw new Error('Method "Prototype.Selector.match" must be defined.');
+ }
+
+ function find(elements, expression, index) {
+ index = index || 0;
+ var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i;
+
+ for (i = 0; i < length; i++) {
+ if (match(elements[i], expression) && index == matchIndex++) {
+ return Element.extend(elements[i]);
+ }
}
- return Selector.matchElements(elements, expression || '*')[index || 0];
- },
+ }
- findChildElements: function(element, expressions) {
- expressions = Selector.split(expressions.join(','));
- var results = [], h = Selector.handlers;
- for (var i = 0, l = expressions.length, selector; i < l; i++) {
- selector = new Selector(expressions[i].strip());
- h.concat(results, selector.findElements(element));
+ function extendElements(elements) {
+ for (var i = 0, length = elements.length; i < length; i++) {
+ Element.extend(elements[i]);
}
- return (l > 1) ? h.unique(results) : results;
+ return elements;
}
+
+
+ var K = Prototype.K;
+
+ return {
+ select: select,
+ match: match,
+ find: find,
+ extendElements: (Element.extend === K) ? K : extendElements,
+ extendElement: Element.extend
+ };
+})();
+Prototype._original_property = window.Sizzle;
+/*!
+ * Sizzle CSS Selector Engine - v1.0
+ * Copyright 2009, 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;
+
+[0, 0].sort(function(){
+ baseHasDuplicate = false;
+ return 0;
});
-if (Prototype.Browser.IE) {
- Object.extend(Selector.handlers, {
- concat: function(a, b) {
- for (var i = 0, node; node = b[i]; i++)
- if (node.tagName !== "!") a.push(node);
- return a;
- }
- });
+var Sizzle = function(selector, context, results, seed) {
+ results = results || [];
+ var origContext = context = context || document;
+
+ if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context),
+ soFar = selector;
+
+ while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
+ soFar = m[3];
+
+ parts.push( m[1] );
+
+ if ( m[2] ) {
+ extra = m[3];
+ break;
+ }
+ }
+
+ if ( parts.length > 1 && origPOS.exec( selector ) ) {
+ if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+ set = posProcess( parts[0] + parts[1], context );
+ } else {
+ set = Expr.relative[ parts[0] ] ?
+ [ context ] :
+ Sizzle( parts.shift(), context );
+
+ while ( parts.length ) {
+ selector = parts.shift();
+
+ if ( Expr.relative[ selector ] )
+ selector += parts.shift();
+
+ set = posProcess( selector, set );
+ }
+ }
+ } else {
+ if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
+ Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
+ var ret = Sizzle.find( parts.shift(), context, contextXML );
+ context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
+ }
+
+ if ( context ) {
+ var 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 ) {
+ var 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 ) {
+ throw "Syntax error, unrecognized expression: " + (cur || selector);
+ }
+
+ if ( toString.call(checkSet) === "[object Array]" ) {
+ if ( !prune ) {
+ results.push.apply( results, checkSet );
+ } else if ( context && context.nodeType === 1 ) {
+ for ( var i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
+ results.push( set[i] );
+ }
+ }
+ } else {
+ for ( var 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.find = function(expr, context, isXML){
+ var set, match;
+
+ if ( !expr ) {
+ return [];
+ }
+
+ for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
+ var type = Expr.order[i], match;
+
+ 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(/\\/g, "");
+ set = Expr.find[ type ]( match, context, isXML );
+ if ( set != null ) {
+ expr = expr.replace( Expr.match[ type ], "" );
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !set ) {
+ set = context.getElementsByTagName("*");
+ }
+
+ return {set: set, expr: expr};
+};
+
+Sizzle.filter = function(expr, set, inplace, not){
+ var old = expr, result = [], curLoop = set, match, anyFound,
+ isXMLFilter = set && set[0] && isXML(set[0]);
+
+ while ( expr && set.length ) {
+ for ( var type in Expr.filter ) {
+ if ( (match = Expr.match[ type ].exec( expr )) != null ) {
+ var filter = Expr.filter[ type ], found, item;
+ anyFound = false;
+
+ if ( curLoop == result ) {
+ result = [];
+ }
+
+ if ( Expr.preFilter[ type ] ) {
+ match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+ if ( !match ) {
+ anyFound = found = true;
+ } else if ( match === true ) {
+ continue;
+ }
+ }
+
+ if ( match ) {
+ for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
+ if ( item ) {
+ found = filter( item, match, i, curLoop );
+ var pass = not ^ !!found;
+
+ if ( inplace && found != null ) {
+ if ( pass ) {
+ anyFound = true;
+ } else {
+ curLoop[i] = false;
+ }
+ } else if ( pass ) {
+ result.push( item );
+ anyFound = true;
+ }
+ }
+ }
+ }
+
+ if ( found !== undefined ) {
+ if ( !inplace ) {
+ curLoop = result;
+ }
+
+ expr = expr.replace( Expr.match[ type ], "" );
+
+ if ( !anyFound ) {
+ return [];
+ }
+
+ break;
+ }
+ }
+ }
+
+ if ( expr == old ) {
+ if ( anyFound == null ) {
+ throw "Syntax error, unrecognized expression: " + expr;
+ } else {
+ break;
+ }
+ }
+
+ old = expr;
+ }
+
+ return curLoop;
+};
+
+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|)\s*\]/,
+ TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
+ CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
+ POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
+ PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
+ },
+ leftMatch: {},
+ attrMap: {
+ "class": "className",
+ "for": "htmlFor"
+ },
+ attrHandle: {
+ href: function(elem){
+ return elem.getAttribute("href");
+ }
+ },
+ relative: {
+ "+": function(checkSet, part, isXML){
+ var isPartStr = typeof part === "string",
+ isTag = isPartStr && !/\W/.test(part),
+ isPartStrNotTag = isPartStr && !isTag;
+
+ if ( isTag && !isXML ) {
+ part = part.toUpperCase();
+ }
+
+ 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 === part ?
+ elem || false :
+ elem === part;
+ }
+ }
+
+ if ( isPartStrNotTag ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ },
+ ">": function(checkSet, part, isXML){
+ var isPartStr = typeof part === "string";
+
+ if ( isPartStr && !/\W/.test(part) ) {
+ part = isXML ? part : part.toUpperCase();
+
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ var parent = elem.parentNode;
+ checkSet[i] = parent.nodeName === part ? parent : false;
+ }
+ }
+ } else {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var 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 doneName = done++, checkFn = dirCheck;
+
+ if ( !/\W/.test(part) ) {
+ var nodeCheck = part = isXML ? part : part.toUpperCase();
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
+ },
+ "~": function(checkSet, part, isXML){
+ var doneName = done++, checkFn = dirCheck;
+
+ if ( typeof part === "string" && !/\W/.test(part) ) {
+ var nodeCheck = part = isXML ? part : part.toUpperCase();
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
+ }
+ },
+ find: {
+ ID: function(match, context, isXML){
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+ return m ? [m] : [];
+ }
+ },
+ NAME: function(match, context, isXML){
+ 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){
+ return context.getElementsByTagName(match[1]);
+ }
+ },
+ preFilter: {
+ CLASS: function(match, curLoop, inplace, result, not, isXML){
+ match = " " + match[1].replace(/\\/g, "") + " ";
+
+ if ( isXML ) {
+ return match;
+ }
+
+ for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+ if ( elem ) {
+ if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
+ if ( !inplace )
+ result.push( elem );
+ } else if ( inplace ) {
+ curLoop[i] = false;
+ }
+ }
+ }
+
+ return false;
+ },
+ ID: function(match){
+ return match[1].replace(/\\/g, "");
+ },
+ TAG: function(match, curLoop){
+ for ( var i = 0; curLoop[i] === false; i++ ){}
+ return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
+ },
+ CHILD: function(match){
+ if ( match[1] == "nth" ) {
+ var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
+ match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
+ !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+ match[2] = (test[1] + (test[2] || 1)) - 0;
+ match[3] = test[3] - 0;
+ }
+
+ match[0] = done++;
+
+ return match;
+ },
+ ATTR: function(match, curLoop, inplace, result, not, isXML){
+ var name = match[1].replace(/\\/g, "");
+
+ if ( !isXML && Expr.attrMap[name] ) {
+ match[1] = Expr.attrMap[name];
+ }
+
+ if ( match[2] === "~=" ) {
+ match[4] = " " + match[4] + " ";
+ }
+
+ return match;
+ },
+ PSEUDO: function(match, curLoop, inplace, result, not){
+ if ( match[1] === "not" ) {
+ if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
+ match[3] = Sizzle(match[3], null, null, curLoop);
+ } else {
+ var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+ if ( !inplace ) {
+ result.push.apply( result, ret );
+ }
+ return false;
+ }
+ } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+ return true;
+ }
+
+ return match;
+ },
+ POS: function(match){
+ match.unshift( true );
+ return match;
+ }
+ },
+ filters: {
+ enabled: function(elem){
+ return elem.disabled === false && elem.type !== "hidden";
+ },
+ disabled: function(elem){
+ return elem.disabled === true;
+ },
+ checked: function(elem){
+ return elem.checked === true;
+ },
+ selected: function(elem){
+ 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){
+ return "text" === elem.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.toUpperCase() === "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 || "").indexOf(match[3]) >= 0;
+ } else if ( name === "not" ) {
+ var not = match[3];
+
+ for ( var i = 0, l = not.length; i < l; i++ ) {
+ if ( not[i] === elem ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ },
+ 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 === 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;
+
+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 );
+}
+
+var makeArray = function(array, results) {
+ array = Array.prototype.slice.call( array, 0 );
+
+ if ( results ) {
+ results.push.apply( results, array );
+ return results;
+ }
+
+ return array;
+};
+
+try {
+ Array.prototype.slice.call( document.documentElement.childNodes, 0 );
+
+} catch(e){
+ makeArray = function(array, results) {
+ var ret = results || [];
+
+ if ( toString.call(array) === "[object Array]" ) {
+ Array.prototype.push.apply( ret, array );
+ } else {
+ if ( typeof array.length === "number" ) {
+ for ( var i = 0, l = array.length; i < l; i++ ) {
+ ret.push( array[i] );
+ }
+ } else {
+ for ( var i = 0; array[i]; i++ ) {
+ ret.push( array[i] );
+ }
+ }
+ }
+
+ return ret;
+ };
}
-function $$() {
- return Selector.findChildElements(document, $A(arguments));
+var sortOrder;
+
+if ( document.documentElement.compareDocumentPosition ) {
+ sortOrder = function( a, b ) {
+ if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
+ if ( a == b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ }
+
+ var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
+ if ( ret === 0 ) {
+ hasDuplicate = true;
+ }
+ return ret;
+ };
+} else if ( "sourceIndex" in document.documentElement ) {
+ sortOrder = function( a, b ) {
+ if ( !a.sourceIndex || !b.sourceIndex ) {
+ if ( a == b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ }
+
+ var ret = a.sourceIndex - b.sourceIndex;
+ if ( ret === 0 ) {
+ hasDuplicate = true;
+ }
+ return ret;
+ };
+} else if ( document.createRange ) {
+ sortOrder = function( a, b ) {
+ if ( !a.ownerDocument || !b.ownerDocument ) {
+ if ( a == b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ }
+
+ var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
+ aRange.setStart(a, 0);
+ aRange.setEnd(a, 0);
+ bRange.setStart(b, 0);
+ bRange.setEnd(b, 0);
+ var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
+ if ( ret === 0 ) {
+ hasDuplicate = true;
+ }
+ return ret;
+ };
}
+(function(){
+ var form = document.createElement("div"),
+ id = "script" + (new Date).getTime();
+ form.innerHTML = "<a name='" + id + "'/>";
+
+ var root = document.documentElement;
+ root.insertBefore( form, root.firstChild );
+
+ if ( !!document.getElementById( id ) ) {
+ Expr.find.ID = function(match, context, isXML){
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+ return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
+ }
+ };
+
+ Expr.filter.ID = function(elem, match){
+ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+ return elem.nodeType === 1 && node && node.nodeValue === match;
+ };
+ }
+
+ root.removeChild( form );
+ root = form = null; // release memory in IE
+})();
+
+(function(){
+
+ var div = document.createElement("div");
+ div.appendChild( document.createComment("") );
+
+ if ( div.getElementsByTagName("*").length > 0 ) {
+ Expr.find.TAG = function(match, context){
+ var results = context.getElementsByTagName(match[1]);
+
+ if ( match[1] === "*" ) {
+ var tmp = [];
+
+ for ( var i = 0; results[i]; i++ ) {
+ if ( results[i].nodeType === 1 ) {
+ tmp.push( results[i] );
+ }
+ }
+
+ results = tmp;
+ }
+
+ return results;
+ };
+ }
+
+ div.innerHTML = "<a href='#'></a>";
+ if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+ div.firstChild.getAttribute("href") !== "#" ) {
+ Expr.attrHandle.href = function(elem){
+ return elem.getAttribute("href", 2);
+ };
+ }
+
+ div = null; // release memory in IE
+})();
+
+if ( document.querySelectorAll ) (function(){
+ var oldSizzle = Sizzle, div = document.createElement("div");
+ div.innerHTML = "<p class='TEST'></p>";
+
+ if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+ return;
+ }
+
+ Sizzle = function(query, context, extra, seed){
+ context = context || document;
+
+ if ( !seed && context.nodeType === 9 && !isXML(context) ) {
+ try {
+ return makeArray( context.querySelectorAll(query), extra );
+ } catch(e){}
+ }
+
+ return oldSizzle(query, context, extra, seed);
+ };
+
+ for ( var prop in oldSizzle ) {
+ Sizzle[ prop ] = oldSizzle[ prop ];
+ }
+
+ div = null; // release memory in IE
+})();
+
+if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
+ var div = document.createElement("div");
+ div.innerHTML = "<div class='test e'></div><div class='test'></div>";
+
+ if ( div.getElementsByClassName("e").length === 0 )
+ return;
+
+ div.lastChild.className = "e";
+
+ if ( div.getElementsByClassName("e").length === 1 )
+ return;
+
+ Expr.order.splice(1, 0, "CLASS");
+ Expr.find.CLASS = function(match, context, isXML) {
+ if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+ return context.getElementsByClassName(match[1]);
+ }
+ };
+
+ div = null; // release memory in IE
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ var sibDir = dir == "previousSibling" && !isXML;
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ if ( sibDir && elem.nodeType === 1 ){
+ elem.sizcache = doneName;
+ elem.sizset = i;
+ }
+ elem = elem[dir];
+ var match = false;
+
+ 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 === cur ) {
+ match = elem;
+ break;
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ var sibDir = dir == "previousSibling" && !isXML;
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ if ( sibDir && elem.nodeType === 1 ) {
+ elem.sizcache = doneName;
+ elem.sizset = i;
+ }
+ elem = elem[dir];
+ var match = false;
+
+ 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;
+ }
+ }
+}
+
+var contains = document.compareDocumentPosition ? function(a, b){
+ return a.compareDocumentPosition(b) & 16;
+} : function(a, b){
+ return a !== b && (a.contains ? a.contains(b) : true);
+};
+
+var isXML = function(elem){
+ return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
+ !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
+};
+
+var posProcess = function(selector, context){
+ var tmpSet = [], later = "", match,
+ root = context.nodeType ? [context] : context;
+
+ while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+ later += match[0];
+ selector = selector.replace( Expr.match.PSEUDO, "" );
+ }
+
+ selector = Expr.relative[selector] ? selector + "*" : selector;
+
+ for ( var i = 0, l = root.length; i < l; i++ ) {
+ Sizzle( selector, root[i], tmpSet );
+ }
+
+ return Sizzle.filter( later, tmpSet );
+};
+
+
+window.Sizzle = Sizzle;
+
+})();
+
+;(function(engine) {
+ var extendElements = Prototype.Selector.extendElements;
+
+ function select(selector, scope) {
+ return extendElements(engine(selector, scope || document));
+ }
+
+ function match(element, selector) {
+ return engine.matches(selector, [element]).length == 1;
+ }
+
+ Prototype.Selector.engine = engine;
+ Prototype.Selector.select = select;
+ Prototype.Selector.match = match;
+})(Sizzle);
+
+window.Sizzle = Prototype._original_property;
+delete Prototype._original_property;
+
var Form = {
reset: function(form) {
form = $(form);
@@ -3925,24 +4970,34 @@ var Form = {
serializeElements: function(elements, options) {
if (typeof options != 'object') options = { hash: !!options };
else if (Object.isUndefined(options.hash)) options.hash = true;
- var key, value, submitted = false, submit = options.submit;
+ var key, value, submitted = false, submit = options.submit, accumulator, initial;
+
+ if (options.hash) {
+ initial = {};
+ accumulator = function(result, key, value) {
+ if (key in result) {
+ if (!Object.isArray(result[key])) result[key] = [result[key]];
+ result[key].push(value);
+ } else result[key] = value;
+ return result;
+ };
+ } else {
+ initial = '';
+ accumulator = function(result, key, value) {
+ return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + encodeURIComponent(value);
+ }
+ }
- var data = elements.inject({ }, function(result, element) {
+ return elements.inject(initial, function(result, element) {
if (!element.disabled && element.name) {
key = element.name; value = $(element).getValue();
if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
submit !== false && (!submit || key == submit) && (submitted = true)))) {
- if (key in result) {
- if (!Object.isArray(result[key])) result[key] = [result[key]];
- result[key].push(value);
- }
- else result[key] = value;
+ result = accumulator(result, key, value);
}
}
return result;
});
-
- return options.hash ? data : Object.toQueryString(data);
}
};
@@ -4009,7 +5064,8 @@ Form.Methods = {
focusFirstElement: function(form) {
form = $(form);
- form.findFirstElement().activate();
+ var element = form.findFirstElement();
+ if (element) element.activate();
return form;
},
@@ -4116,67 +5172,77 @@ var $F = Form.Element.Methods.getValue;
/*--------------------------------------------------------------------------*/
-Form.Element.Serializers = {
- input: function(element, value) {
+Form.Element.Serializers = (function() {
+ function input(element, value) {
switch (element.type.toLowerCase()) {
case 'checkbox':
case 'radio':
- return Form.Element.Serializers.inputSelector(element, value);
+ return inputSelector(element, value);
default:
- return Form.Element.Serializers.textarea(element, value);
+ return valueSelector(element, value);
}
- },
+ }
- inputSelector: function(element, value) {
- if (Object.isUndefined(value)) return element.checked ? element.value : null;
+ function inputSelector(element, value) {
+ if (Object.isUndefined(value))
+ return element.checked ? element.value : null;
else element.checked = !!value;
- },
+ }
- textarea: function(element, value) {
+ function valueSelector(element, value) {
if (Object.isUndefined(value)) return element.value;
else element.value = value;
- },
+ }
- select: function(element, value) {
+ function select(element, value) {
if (Object.isUndefined(value))
- return this[element.type == 'select-one' ?
- 'selectOne' : 'selectMany'](element);
- else {
- var opt, currentValue, single = !Object.isArray(value);
- for (var i = 0, length = element.length; i < length; i++) {
- opt = element.options[i];
- currentValue = this.optionValue(opt);
- if (single) {
- if (currentValue == value) {
- opt.selected = true;
- return;
- }
+ return (element.type === 'select-one' ? selectOne : selectMany)(element);
+
+ var opt, currentValue, single = !Object.isArray(value);
+ for (var i = 0, length = element.length; i < length; i++) {
+ opt = element.options[i];
+ currentValue = this.optionValue(opt);
+ if (single) {
+ if (currentValue == value) {
+ opt.selected = true;
+ return;
}
- else opt.selected = value.include(currentValue);
}
+ else opt.selected = value.include(currentValue);
}
- },
+ }
- selectOne: function(element) {
+ function selectOne(element) {
var index = element.selectedIndex;
- return index >= 0 ? this.optionValue(element.options[index]) : null;
- },
+ return index >= 0 ? optionValue(element.options[index]) : null;
+ }
- selectMany: function(element) {
+ function selectMany(element) {
var values, length = element.length;
if (!length) return null;
for (var i = 0, values = []; i < length; i++) {
var opt = element.options[i];
- if (opt.selected) values.push(this.optionValue(opt));
+ if (opt.selected) values.push(optionValue(opt));
}
return values;
- },
+ }
- optionValue: function(opt) {
- return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
+ function optionValue(opt) {
+ return Element.hasAttribute(opt, 'value') ? opt.value : opt.text;
}
-};
+
+ return {
+ input: input,
+ inputSelector: inputSelector,
+ textarea: valueSelector,
+ select: select,
+ selectOne: selectOne,
+ selectMany: selectMany,
+ optionValue: optionValue,
+ button: valueSelector
+ };
+})();
/*--------------------------------------------------------------------------*/
@@ -4287,24 +5353,53 @@ Form.EventObserver = Class.create(Abstract.EventObserver, {
var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
&& 'onmouseleave' in docEl;
+
+
+ var isIELegacyEvent = function(event) { return false; };
+
+ if (window.attachEvent) {
+ if (window.addEventListener) {
+ isIELegacyEvent = function(event) {
+ return !(event instanceof window.Event);
+ };
+ } else {
+ isIELegacyEvent = function(event) { return true; };
+ }
+ }
+
var _isButton;
- if (Prototype.Browser.IE) {
- var buttonMap = { 0: 1, 1: 4, 2: 2 };
- _isButton = function(event, code) {
- return event.button === buttonMap[code];
- };
- } else if (Prototype.Browser.WebKit) {
- _isButton = function(event, code) {
- switch (code) {
- case 0: return event.which == 1 && !event.metaKey;
- case 1: return event.which == 1 && event.metaKey;
- default: return false;
+
+ function _isButtonForDOMEvents(event, code) {
+ return event.which ? (event.which === code + 1) : (event.button === code);
+ }
+
+ var legacyButtonMap = { 0: 1, 1: 4, 2: 2 };
+ function _isButtonForLegacyEvents(event, code) {
+ return event.button === legacyButtonMap[code];
+ }
+
+ function _isButtonForWebKit(event, code) {
+ switch (code) {
+ case 0: return event.which == 1 && !event.metaKey;
+ case 1: return event.which == 2 || (event.which == 1 && event.metaKey);
+ case 2: return event.which == 3;
+ default: return false;
+ }
+ }
+
+ if (window.attachEvent) {
+ if (!window.addEventListener) {
+ _isButton = _isButtonForLegacyEvents;
+ } else {
+ _isButton = function(event, code) {
+ return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) :
+ _isButtonForDOMEvents(event, code);
}
- };
+ }
+ } else if (Prototype.Browser.WebKit) {
+ _isButton = _isButtonForWebKit;
} else {
- _isButton = function(event, code) {
- return event.which ? (event.which === code + 1) : (event.button === code);
- };
+ _isButton = _isButtonForDOMEvents;
}
function isLeftClick(event) { return _isButton(event, 0) }
@@ -4334,9 +5429,14 @@ Form.EventObserver = Class.create(Abstract.EventObserver, {
function findElement(event, expression) {
var element = Event.element(event);
+
if (!expression) return element;
- var elements = [element].concat(element.ancestors());
- return Selector.findElement(elements, expression, 0);
+ while (element) {
+ if (Object.isElement(element) && Prototype.Selector.match(element, expression)) {
+ return Element.extend(element);
+ }
+ element = element.parentNode;
+ }
}
function pointer(event) {
@@ -4370,49 +5470,59 @@ Form.EventObserver = Class.create(Abstract.EventObserver, {
event.stopped = true;
}
+
Event.Methods = {
- isLeftClick: isLeftClick,
+ isLeftClick: isLeftClick,
isMiddleClick: isMiddleClick,
- isRightClick: isRightClick,
+ isRightClick: isRightClick,
- element: element,
+ element: element,
findElement: findElement,
- pointer: pointer,
+ pointer: pointer,
pointerX: pointerX,
pointerY: pointerY,
stop: stop
};
-
var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
m[name] = Event.Methods[name].methodize();
return m;
});
- if (Prototype.Browser.IE) {
+ if (window.attachEvent) {
function _relatedTarget(event) {
var element;
switch (event.type) {
- case 'mouseover': element = event.fromElement; break;
- case 'mouseout': element = event.toElement; break;
- default: return null;
+ case 'mouseover':
+ case 'mouseenter':
+ element = event.fromElement;
+ break;
+ case 'mouseout':
+ case 'mouseleave':
+ element = event.toElement;
+ break;
+ default:
+ return null;
}
return Element.extend(element);
}
- Object.extend(methods, {
+ var additionalMethods = {
stopPropagation: function() { this.cancelBubble = true },
preventDefault: function() { this.returnValue = false },
inspect: function() { return '[object Event]' }
- });
+ };
Event.extend = function(event, element) {
if (!event) return false;
- if (event._extendedByPrototype) return event;
+ if (!isIELegacyEvent(event)) return event;
+
+ if (event._extendedByPrototype) return event;
event._extendedByPrototype = Prototype.emptyFunction;
+
var pointer = Event.pointer(event);
Object.extend(event, {
@@ -4422,12 +5532,18 @@ Form.EventObserver = Class.create(Abstract.EventObserver, {
pageY: pointer.y
});
- return Object.extend(event, methods);
+ Object.extend(event, methods);
+ Object.extend(event, additionalMethods);
+
+ return event;
};
} else {
+ Event.extend = Prototype.K;
+ }
+
+ if (window.addEventListener) {
Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
Object.extend(Event.prototype, methods);
- Event.extend = Prototype.K;
}
function _createResponder(element, eventName, handler) {
@@ -4505,12 +5621,12 @@ Form.EventObserver = Class.create(Abstract.EventObserver, {
window.addEventListener('unload', Prototype.emptyFunction, false);
- var _getDOMEventName = Prototype.K;
+ var _getDOMEventName = Prototype.K,
+ translations = { mouseenter: "mouseover", mouseleave: "mouseout" };
if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) {
_getDOMEventName = function(eventName) {
- var translations = { mouseenter: "mouseover", mouseleave: "mouseout" };
- return eventName in translations ? translations[eventName] : eventName;
+ return (translations[eventName] || eventName);
};
}
@@ -4526,7 +5642,7 @@ Form.EventObserver = Class.create(Abstract.EventObserver, {
element.addEventListener("dataavailable", responder, false);
else {
element.attachEvent("ondataavailable", responder);
- element.attachEvent("onfilterchange", responder);
+ element.attachEvent("onlosecapture", responder);
}
} else {
var actualEventName = _getDOMEventName(eventName);
@@ -4544,46 +5660,44 @@ Form.EventObserver = Class.create(Abstract.EventObserver, {
element = $(element);
var registry = Element.retrieve(element, 'prototype_event_registry');
+ if (!registry) return element;
- if (Object.isUndefined(registry)) return element;
-
- if (eventName && !handler) {
- var responders = registry.get(eventName);
-
- if (Object.isUndefined(responders)) return element;
-
- responders.each( function(r) {
- Element.stopObserving(element, eventName, r.handler);
- });
- return element;
- } else if (!eventName) {
+ if (!eventName) {
registry.each( function(pair) {
- var eventName = pair.key, responders = pair.value;
-
- responders.each( function(r) {
- Element.stopObserving(element, eventName, r.handler);
- });
+ var eventName = pair.key;
+ stopObserving(element, eventName);
});
return element;
}
var responders = registry.get(eventName);
+ if (!responders) return element;
- if (!responders) return;
+ if (!handler) {
+ responders.each(function(r) {
+ stopObserving(element, eventName, r.handler);
+ });
+ return element;
+ }
- var responder = responders.find( function(r) { return r.handler === handler; });
+ var i = responders.length, responder;
+ while (i--) {
+ if (responders[i].handler === handler) {
+ responder = responders[i];
+ break;
+ }
+ }
if (!responder) return element;
- var actualEventName = _getDOMEventName(eventName);
-
if (eventName.include(':')) {
if (element.removeEventListener)
element.removeEventListener("dataavailable", responder, false);
else {
element.detachEvent("ondataavailable", responder);
- element.detachEvent("onfilterchange", responder);
+ element.detachEvent("onlosecapture", responder);
}
} else {
+ var actualEventName = _getDOMEventName(eventName);
if (element.removeEventListener)
element.removeEventListener(actualEventName, responder, false);
else
@@ -4607,10 +5721,10 @@ Form.EventObserver = Class.create(Abstract.EventObserver, {
var event;
if (document.createEvent) {
event = document.createEvent('HTMLEvents');
- event.initEvent('dataavailable', true, true);
+ event.initEvent('dataavailable', bubble, true);
} else {
event = document.createEventObject();
- event.eventType = bubble ? 'ondataavailable' : 'onfilterchange';
+ event.eventType = bubble ? 'ondataavailable' : 'onlosecapture';
}
event.eventName = eventName;
@@ -4624,13 +5738,47 @@ Form.EventObserver = Class.create(Abstract.EventObserver, {
return Event.extend(event);
}
+ Event.Handler = Class.create({
+ initialize: function(element, eventName, selector, callback) {
+ this.element = $(element);
+ this.eventName = eventName;
+ this.selector = selector;
+ this.callback = callback;
+ this.handler = this.handleEvent.bind(this);
+ },
+
+ start: function() {
+ Event.observe(this.element, this.eventName, this.handler);
+ return this;
+ },
+
+ stop: function() {
+ Event.stopObserving(this.element, this.eventName, this.handler);
+ return this;
+ },
+
+ handleEvent: function(event) {
+ var element = Event.findElement(event, this.selector);
+ if (element) this.callback.call(this.element, event, element);
+ }
+ });
+
+ function on(element, eventName, selector, callback) {
+ element = $(element);
+ if (Object.isFunction(selector) && Object.isUndefined(callback)) {
+ callback = selector, selector = null;
+ }
+
+ return new Event.Handler(element, eventName, selector, callback).start();
+ }
Object.extend(Event, Event.Methods);
Object.extend(Event, {
fire: fire,
observe: observe,
- stopObserving: stopObserving
+ stopObserving: stopObserving,
+ on: on
});
Element.addMethods({
@@ -4638,7 +5786,9 @@ Form.EventObserver = Class.create(Abstract.EventObserver, {
observe: observe,
- stopObserving: stopObserving
+ stopObserving: stopObserving,
+
+ on: on
});
Object.extend(document, {
@@ -4648,6 +5798,8 @@ Form.EventObserver = Class.create(Abstract.EventObserver, {
stopObserving: stopObserving.methodize(),
+ on: on.methodize(),
+
loaded: false
});
@@ -4872,4 +6024,59 @@ Element.ClassNames.prototype = {
Object.extend(Element.ClassNames.prototype, Enumerable);
-/*--------------------------------------------------------------------------*/ \ No newline at end of file
+/*--------------------------------------------------------------------------*/
+
+(function() {
+ window.Selector = Class.create({
+ initialize: function(expression) {
+ this.expression = expression.strip();
+ },
+
+ findElements: function(rootElement) {
+ return Prototype.Selector.select(this.expression, rootElement);
+ },
+
+ match: function(element) {
+ return Prototype.Selector.match(element, this.expression);
+ },
+
+ toString: function() {
+ return this.expression;
+ },
+
+ inspect: function() {
+ return "#<Selector: " + this.expression + ">";
+ }
+ });
+
+ Object.extend(Selector, {
+ matchElements: function(elements, expression) {
+ var match = Prototype.Selector.match,
+ results = [];
+
+ for (var i = 0, length = elements.length; i < length; i++) {
+ var element = elements[i];
+ if (match(element, expression)) {
+ results.push(Element.extend(element));
+ }
+ }
+ return results;
+ },
+
+ findElement: function(elements, expression, index) {
+ index = index || 0;
+ var matchIndex = 0, element;
+ for (var i = 0, length = elements.length; i < length; i++) {
+ element = elements[i];
+ if (Prototype.Selector.match(element, expression) && index === matchIndex++) {
+ return Element.extend(element);
+ }
+ }
+ },
+
+ findChildElements: function(element, expressions) {
+ var selector = expressions.toArray().join(', ');
+ return Prototype.Selector.select(selector, element || document);
+ }
+ });
+})();
diff --git a/usr/local/www/services_captiveportal.php b/usr/local/www/services_captiveportal.php
index e86a2d1..2f1db79 100755
--- a/usr/local/www/services_captiveportal.php
+++ b/usr/local/www/services_captiveportal.php
@@ -67,7 +67,6 @@ if ($_GET['act'] == "viewhtml") {
}
$pconfig['cinterface'] = $config['captiveportal']['interface'];
-$pconfig['maxproc'] = $config['captiveportal']['maxproc'];
$pconfig['maxprocperip'] = $config['captiveportal']['maxprocperip'];
$pconfig['timeout'] = $config['captiveportal']['timeout'];
$pconfig['idletimeout'] = $config['captiveportal']['idletimeout'];
@@ -172,18 +171,13 @@ if ($_POST) {
if (($_POST['radiusacctport'] && !is_port($_POST['radiusacctport']))) {
$input_errors[] = sprintf(gettext("A valid port number must be specified. [%s]"), $_POST['radiusacctport']);
}
- if ($_POST['maxproc'] && (!is_numeric($_POST['maxproc']) || ($_POST['maxproc'] < 4) || ($_POST['maxproc'] > 100))) {
- $input_errors[] = gettext("The total maximum number of concurrent connections must be between 4 and 100.");
- }
- $mymaxproc = $_POST['maxproc'] ? $_POST['maxproc'] : 16;
- if ($_POST['maxprocperip'] && (!is_numeric($_POST['maxprocperip']) || ($_POST['maxprocperip'] > $mymaxproc))) {
+ if ($_POST['maxprocperip'] && (!is_numeric($_POST['maxprocperip']) || ($_POST['maxprocperip'] < 4) || $_POST['maxprocperip'] > 100)) {
$input_errors[] = gettext("The maximum number of concurrent connections per client IP address may not be larger than the global maximum.");
}
if (!$input_errors) {
if (is_array($_POST['cinterface']))
$config['captiveportal']['interface'] = implode(",", $_POST['cinterface']);
- $config['captiveportal']['maxproc'] = $_POST['maxproc'];
$config['captiveportal']['maxprocperip'] = $_POST['maxprocperip'] ? $_POST['maxprocperip'] : false;
$config['captiveportal']['timeout'] = $_POST['timeout'];
$config['captiveportal']['idletimeout'] = $_POST['idletimeout'];
@@ -256,7 +250,6 @@ function enable_change(enable_change) {
radius_endis = !((!endis && document.iform.auth_method[2].checked) || enable_change);
document.iform.cinterface.disabled = endis;
- //document.iform.maxproc.disabled = endis;
document.iform.maxprocperip.disabled = endis;
document.iform.idletimeout.disabled = endis;
document.iform.freelogins_count.disabled = endis;
diff --git a/usr/local/www/services_captiveportal_vouchers.php b/usr/local/www/services_captiveportal_vouchers.php
index f4f4b89..05bce04 100644
--- a/usr/local/www/services_captiveportal_vouchers.php
+++ b/usr/local/www/services_captiveportal_vouchers.php
@@ -295,7 +295,7 @@ EOF;
$config['voucher']['msgexpired'] = $toreturn['voucher']['msgexpired'];
if($toreturn['voucher']['msgnoaccess'])
$config['voucher']['msgnoaccess'] = $toreturn['voucher']['msgnoaccess'];
- $savemsg = gettext("Voucher database has been synchronized from {$url}:{$port}");
+ $savemsg = sprintf(gettext("Voucher database has been synchronized from %1\$s:%2\$s"),$url,$port);
write_config();
voucher_configure(true);
diff --git a/usr/local/www/services_dhcp.php b/usr/local/www/services_dhcp.php
index 122912d..e818738 100755
--- a/usr/local/www/services_dhcp.php
+++ b/usr/local/www/services_dhcp.php
@@ -156,8 +156,8 @@ if (is_array($config['dhcpd'][$if])){
$a_maps = &$config['dhcpd'][$if]['staticmap'];
}
-$ifcfgip = get_interface_ip($if);
-$ifcfgsn = get_interface_subnet($if);
+$ifcfgip = $config['interfaces'][$if]['ipaddr'];
+$ifcfgsn = $config['interfaces'][$if]['subnet'];
/* set the enabled flag which will tell us if DHCP relay is enabled
* on any interface. We will use this to disable DHCP server since
diff --git a/usr/local/www/status_services.php b/usr/local/www/status_services.php
index d463f3a..2303054 100755
--- a/usr/local/www/status_services.php
+++ b/usr/local/www/status_services.php
@@ -63,6 +63,7 @@ if($_GET['mode'] == "restartservice" and !empty($_GET['service'])) {
switch($_GET['service']) {
case 'captiveportal':
killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid");
+ killbypid("{$g['varrun_path']}/lighty-CaptivePortal-SSL.pid");
captiveportal_init_webgui();
break;
case 'ntpd':
@@ -157,6 +158,7 @@ if($_GET['mode'] == "stopservice" && !empty($_GET['service'])) {
switch($_GET['service']) {
case 'captiveportal':
killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid");
+ killbypid("{$g['varrun_path']}/lighty-CaptivePortal-SSL.pid");
break;
case 'ntpd':
killbyname("ntpd");
diff --git a/usr/local/www/system.php b/usr/local/www/system.php
index caf8e78..6be9f99 100755
--- a/usr/local/www/system.php
+++ b/usr/local/www/system.php
@@ -135,7 +135,7 @@ if ($_POST) {
if(interface_has_gateway($_POST[$dnsgwitem])) {
foreach($direct_networks_list as $direct_network) {
if(ip_in_subnet($_POST[$dnsitem], $direct_network)) {
- $input_errors[] = gettext("You can not assign a gateway to DNS '{$_POST[$dnsitem]}' server which is on a directly connected network.");
+ $input_errors[] = sprintf(gettext("You can not assign a gateway to DNS '%s' server which is on a directly connected network."),$_POST[$dnsitem]);
}
}
}
diff --git a/usr/local/www/system_advanced_admin.php b/usr/local/www/system_advanced_admin.php
index d1150a2..02614e2 100644
--- a/usr/local/www/system_advanced_admin.php
+++ b/usr/local/www/system_advanced_admin.php
@@ -93,7 +93,7 @@ if ($_POST) {
$althosts = explode(" ", $_POST['althostnames']);
foreach ($althosts as $ah)
if (!is_hostname($ah))
- $input_errors[] = gettext("Alternate hostname " . htmlspecialchars($ah) . " is not a valid hostname.");
+ $input_errors[] = sprintf(gettext("Alternate hostname %s is not a valid hostname."),htmlspecialchars($ah));
}
if ($_POST['sshport'])
diff --git a/usr/local/www/system_advanced_misc.php b/usr/local/www/system_advanced_misc.php
index c31bc92..c418505 100644
--- a/usr/local/www/system_advanced_misc.php
+++ b/usr/local/www/system_advanced_misc.php
@@ -232,7 +232,7 @@ function maxmss_checked(obj) {
<td width="78%" class="vtable">
<input name="proxyurl" id="proxyurl" value="<?php if ($pconfig['proxyurl'] <> "") echo $pconfig['proxyurl']; ?>" class="formfld unknown">
<br />
- <?=gettext("Proxy url for allowing {$g['product']} to use this proxy to connect outside."); ?>
+ <?php printf(gettext("Proxy url for allowing %s to use this proxy to connect outside."),$g['product']); ?>
</td>
</tr>
<tr>
@@ -240,7 +240,7 @@ function maxmss_checked(obj) {
<td width="78%" class="vtable">
<input name="proxyport" id="proxyport" value="<?php if ($pconfig['proxyport'] <> "") echo $pconfig['proxyport']; ?>" class="formfld unknown">
<br />
- <?=gettext("Proxy url for allowing {$g['product']} to use this proxy port to connect outside. Default is 8080 for http protocol or ssl for 443."); ?>
+ <?php printf(gettext("Proxy url for allowing %s to use this proxy port to connect outside. Default is 8080 for http protocol or ssl for 443."),$g['product']); ?>
</td>
</tr>
<tr>
@@ -248,7 +248,7 @@ function maxmss_checked(obj) {
<td width="78%" class="vtable">
<input name="proxyuser" id="proxyuser" value="<?php if ($pconfig['proxyuser'] <> "") echo $pconfig['proxyuser']; ?>" class="formfld unknown">
<br />
- <?=gettext("Proxy username for allowing {$g['product']} to use this proxy to connect outside"); ?>
+ <?php printf(gettext("Proxy username for allowing %s to use this proxy to connect outside"),$g['product']); ?>
</td>
</tr>
<tr>
@@ -256,7 +256,7 @@ function maxmss_checked(obj) {
<td width="78%" class="vtable">
<input type="password" name="proxypass" id="proxypass" value="<?php if ($pconfig['proxypass'] <> "") echo $pconfig['proxypass']; ?>" class="formfld unknown">
<br />
- <?=gettext("Proxy password for allowing {$g['product']} to use this proxy to connect outside"); ?>
+ <?php printf(gettext("Proxy password for allowing %s to use this proxy to connect outside"),$g['product']); ?>
</td>
</tr>
<tr>
diff --git a/usr/local/www/system_advanced_notifications.php b/usr/local/www/system_advanced_notifications.php
index 7da289a..3c997ce 100644
--- a/usr/local/www/system_advanced_notifications.php
+++ b/usr/local/www/system_advanced_notifications.php
@@ -202,10 +202,10 @@ include("head.inc");
<td colspan="2" valign="top" class="listtopic"><?=gettext("SMTP E-Mail"); ?></td>
</tr>
<tr>
- <td width="22%" valign="top" class="vncell"><?=gettext("IP Address of E-Mail server"); ?></td>
+ <td width="22%" valign="top" class="vncell"><?=gettext("E-Mail server"); ?></td>
<td width="78%" class="vtable">
<input name='smtpipaddress' value='<?php echo $pconfig['smtpipaddress']; ?>'><br/>
- <?=gettext("This is the IP address of the SMTP E-Mail server that will be used to send notifications to."); ?>
+ <?=gettext("This is the FQDN or IP address of the SMTP E-Mail server to which notifications will be sent."); ?>
</td>
</tr>
<tr>
diff --git a/usr/local/www/system_crlmanager.php b/usr/local/www/system_crlmanager.php
index 2ecc866..201d8ab 100644
--- a/usr/local/www/system_crlmanager.php
+++ b/usr/local/www/system_crlmanager.php
@@ -525,11 +525,11 @@ function method_change() {
<td class="list">
<?php if ($cainternal == "YES"): ?>
<a href="system_crlmanager.php?act=new&caref=<?php echo $ca['refid']; ?>">
- <img src="/themes/<?= $g['theme'];?>/images/icons/icon_plus.gif" title="<?=gettext("Add or Import CRL for ") . $ca['descr'];?>" alt="<?=gettext("add crl");?>" width="17" height="17" border="0" />
+ <img src="/themes/<?= $g['theme'];?>/images/icons/icon_plus.gif" title="<?php printf(gettext("Add or Import CRL for %s"),$ca['descr']);?>" alt="<?=gettext("add crl");?>" width="17" height="17" border="0" />
</a>
<?php else: ?>
<a href="system_crlmanager.php?act=new&caref=<?php echo $ca['refid']; ?>&importonly=yes">
- <img src="/themes/<?= $g['theme'];?>/images/icons/icon_plus.gif" title="<?=gettext("Import CRL for ") . $ca['descr'];?>" alt="<?=gettext("add crl");?>" width="17" height="17" border="0" />
+ <img src="/themes/<?= $g['theme'];?>/images/icons/icon_plus.gif" title="<?php printf(gettext("Import CRL for %s"),$ca['descr']);?>" alt="<?=gettext("add crl");?>" width="17" height="17" border="0" />
</a>
<?php endif; ?>
</td>
diff --git a/usr/local/www/system_gateways_edit.php b/usr/local/www/system_gateways_edit.php
index 02fac7c..f34df9f 100755
--- a/usr/local/www/system_gateways_edit.php
+++ b/usr/local/www/system_gateways_edit.php
@@ -122,14 +122,14 @@ if ($_POST) {
$parent_sn = get_interface_subnet($_POST['interface']);
$subnet = gen_subnet($parent_ip, $parent_sn) . "/" . $parent_sn;
if(!ip_in_subnet($_POST['gateway'], $subnet) && !ip_in_interface_alias_subnet($_POST['interface'], $_POST['gateway'])) {
- $input_errors[] = sprintf(gettext("The gateway address %s does not lie within the chosen interface's subnet '{$subnet}'."), $_POST['gateway']);
+ $input_errors[] = sprintf(gettext("The gateway address %1\$s does not lie within the chosen interface's subnet '%2\$s'."), $_POST['gateway'],$subnet);
}
}
if (is_ipaddrv6($parent_ip)) {
$parent_sn = get_interface_subnetv6($_POST['interface']);
$subnet = gen_subnetv6($parent_ip, $parent_sn) . "/" . $parent_sn;
if(!ip_in_subnet($_POST['gateway'], $subnet)) {
- $input_errors[] = sprintf(gettext("The gateway address %s does not lie within the chosen interface's subnet '{$subnet}'."), $_POST['gateway']);
+ $input_errors[] = sprintf(gettext("The gateway address %1\$s does not lie within the chosen interface's subnet '%2\$s'."), $_POST['gateway'],$subnet);
}
}
}
diff --git a/usr/local/www/vpn_pppoe_edit.php b/usr/local/www/vpn_pppoe_edit.php
index 6c94797..ea6f5f0 100755
--- a/usr/local/www/vpn_pppoe_edit.php
+++ b/usr/local/www/vpn_pppoe_edit.php
@@ -139,9 +139,9 @@ if ($_POST) {
for($x=0; $x<4999; $x++) {
if ($_POST["username{$x}"]) {
if (empty($_POST["password{$x}"]))
- $input_errors[] = gettext("No password specified for username ") . $_POST["username{$x}"];
+ $input_errors[] = sprintf(gettext("No password specified for username %s"),$_POST["username{$x}"]);
if ($_POST["ip{$x}"] <> "" && !is_ipaddr($_POST["ip{$x}"]))
- $input_errors[] = gettext("Incorrect ip address specified for username ") . $_POST["username{$x}"];
+ $input_errors[] = sprintf(gettext("Incorrect ip address specified for username %s"),$_POST["username{$x}"]);
}
}
}
diff --git a/usr/local/www/wizards/openvpn_wizard.inc b/usr/local/www/wizards/openvpn_wizard.inc
index 51c7a63..348abbd 100644
--- a/usr/local/www/wizards/openvpn_wizard.inc
+++ b/usr/local/www/wizards/openvpn_wizard.inc
@@ -599,7 +599,7 @@ function step12_submitphpaction() {
if (isset($pconfig['step11']['ovpnrule'])) {
$rule = array();
- $rule['descr'] = gettext("OpenVPN {$server['description']} wizard");
+ $rule['descr'] = sprintf(gettext("OpenVPN %s wizard"),$server['description']);
/* Ensure the rule descr is not too long for pf to handle */
if (strlen($rule['descr']) > 52)
$rule['descr'] = substr($rule['descr'], 0, 52);
@@ -615,7 +615,7 @@ function step12_submitphpaction() {
}
if (isset($pconfig['step11']['ovpnallow'])) {
$rule = array();
- $rule['descr'] = gettext("OpenVPN {$server['description']} wizard");
+ $rule['descr'] = sprintf(gettext("OpenVPN %s wizard"),$server['description']);
/* Ensure the rule descr is not too long for pf to handle */
if (strlen($rule['descr']) > 52)
$rule['descr'] = substr($rule['descr'], 0, 52);
diff --git a/usr/local/www/wizards/traffic_shaper_wizard.inc b/usr/local/www/wizards/traffic_shaper_wizard.inc
index e6d8823..ee800ce 100644
--- a/usr/local/www/wizards/traffic_shaper_wizard.inc
+++ b/usr/local/www/wizards/traffic_shaper_wizard.inc
@@ -600,12 +600,15 @@ function apply_all_choosen_items() {
$lanbw += $input_bw;
}
+ $interfacelist = array();
+
for ($i = 0; $i < $steps; $i++) {
$altq =& new altq_root_queue();
$tmppath = array();
$altq->SetInterface($config['ezshaper']['step2']["conn{$i}interface"]);
+ $interfacelist[] = $config['ezshaper']['step2']["conn{$i}interface"];
$altq->SetScheduler($config['ezshaper']['step2']["conn{$i}uploadscheduler"]);
$altq->SetBandwidth(floatval($config['ezshaper']['step2']["conn{$i}upload"]));
$altq->SetBwscale($config['ezshaper']['step2']["conn{$i}uploadspeed"]);
@@ -1329,11 +1332,17 @@ function apply_all_choosen_items() {
if (!is_array($config['filter']['rule']))
$config['filter']['rule'] = array();
+ if (empty($interfacelist))
+ $interfacelist = "";
+ else
+ $interfacelist = implode(",", $interfacelist);
+
/* Rules */
if ($penalty) {
if( is_ipaddr($config['ezshaper']['step4']['address']) || is_alias($config['ezshaper']['step4']['address'])) {
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
$rule['descr'] = gettext("Penalty Box");
$rule['source']['any'] = TRUE;
$rule['defaultqueue'] = "qOthersLow";
@@ -1353,6 +1362,7 @@ function apply_all_choosen_items() {
/* create VOIP rules */
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
$rule['descr'] = gettext("VOIP Adapter");
$rule['protocol'] = "udp";
$rule['defaultqueue'] = "qVoIP";
@@ -1367,6 +1377,7 @@ function apply_all_choosen_items() {
/* create VOIP rules */
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
$rule['descr'] = "DiffServ/Lowdelay/Upload";
$rule['protocol'] = "udp";
$rule['source']['any'] = TRUE;
@@ -1383,6 +1394,7 @@ function apply_all_choosen_items() {
foreach ($voiplist[$config['ezshaper']['step3']['provider']] as $voip) {
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
$rule['defaultqueue'] = 'qVoIP';
$rule['source']['any'] = TRUE;
$rule['destination']['any'] = TRUE;
@@ -1406,6 +1418,7 @@ function apply_all_choosen_items() {
foreach ($p2plist[$key] as $p2pclient) {
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
$rule['defaultqueue'] = 'qP2P';
$rule['source']['any'] = TRUE;
$rule['destination']['any'] = TRUE;
@@ -1428,6 +1441,7 @@ function apply_all_choosen_items() {
foreach ($gamesplist[$key] as $Gameclient) {
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
$rule['defaultqueue'] = 'qGames';
if ($Gameclient[1] == "tcp")
$rule['ackqueue'] = 'qACK';
@@ -1453,6 +1467,7 @@ function apply_all_choosen_items() {
foreach ($othersplist[$key] as $otherclient) {
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
switch ($val) {
case "H":
$rule['defaultqueue'] = 'qOthersHigh'; /* posted value H or L */
@@ -1475,29 +1490,29 @@ function apply_all_choosen_items() {
} else
$loop = 1; /* It automitaclly goes to default queue */
break;
- default:
- $loop = 1;
- }
- if (!$loop) {
- $rule['source']['any'] = TRUE;
- $rule['destination']['any'] = TRUE;
- $rule['floating'] = "yes";
- $rule['wizard'] = "yes";
- $rule['enabled'] = "on";
- $rule['descr'] = "m_Other {$otherclient[0]} outbound";
-
- if($otherclient[2] or $otherclient[3]) {
- $rule['destination']['port'] = $otherclient[2]."-".$otherclient[3];
- }
- if($otherclient[1] != '')
- $rule['protocol'] = $otherclient[1];
-
- $config['filter']['rule'][] = $rule;
+ default:
+ $loop = 1;
+ }
+ if (!$loop) {
+ $rule['source']['any'] = TRUE;
+ $rule['destination']['any'] = TRUE;
+ $rule['floating'] = "yes";
+ $rule['wizard'] = "yes";
+ $rule['enabled'] = "on";
+ $rule['descr'] = "m_Other {$otherclient[0]} outbound";
+
+ if($otherclient[2] or $otherclient[3]) {
+ $rule['destination']['port'] = $otherclient[2]."-".$otherclient[3];
}
+ if($otherclient[1] != '')
+ $rule['protocol'] = $otherclient[1];
+
+ $config['filter']['rule'][] = $rule;
}
}
}
- write_config();
+ }
+ write_config();
}
function wizard_get_bandwidthtype_scale($type = "b") {
diff --git a/usr/local/www/wizards/traffic_shaper_wizard_dedicated.inc b/usr/local/www/wizards/traffic_shaper_wizard_dedicated.inc
index 9707d06..bb25f79 100755
--- a/usr/local/www/wizards/traffic_shaper_wizard_dedicated.inc
+++ b/usr/local/www/wizards/traffic_shaper_wizard_dedicated.inc
@@ -625,13 +625,16 @@ function apply_all_choosen_items() {
$altq_list_queues = array();
$steps = intval($config['ezshaper']['step1']['numberofconnections']);
-
+
+ $interfacelist = array();
+
for ($i = 0; $i < $steps; $i++) {
$tmppath = array();
$altq =& new altq_root_queue();
$altq->SetInterface($config['ezshaper']['step2']["conn{$i}interface"]);
+ $interfacelist[] = $config['ezshaper']['step2']["conn{$i}interface"];
$altq->SetScheduler($config['ezshaper']['step2']["conn{$i}uploadscheduler"]);
$altq->SetBandwidth(floatval($config['ezshaper']['step2']["conn{$i}upload"]));
$altq->SetBwscale($config['ezshaper']['step2']["conn{$i}uploadspeed"]);
@@ -1394,175 +1397,183 @@ function apply_all_choosen_items() {
if (!is_array($config['filter']['rule']))
$config['filter']['rule'] = array();
- /* Rules */
- if ($penalty) {
- if( is_ipaddr($config['ezshaper']['step4']['address']) || is_alias($config['ezshaper']['step4']['address'])) {
- $rule = array();
- $rule['type'] = "match";
- $rule['descr'] = gettext("Penalty Box");
- $rule['source']['any'] = TRUE;
- $rule['defaultqueue'] = "qOthersLow";
- $rule['source']['address'] = $config['ezshaper']['step4']['address'];
- $rule['destination']['any'] = TRUE;
- $rule['floating'] = "yes";
- $rule['wizard'] = "yes";
- $rule['enabled'] = "on";
- $config['filter']['rule'][] = $rule;
-
- }
+ $interfacelist = implode(",", $interfacelist);
+
+ /* Rules */
+ if ($penalty) {
+ if( is_ipaddr($config['ezshaper']['step4']['address']) || is_alias($config['ezshaper']['step4']['address'])) {
+ $rule = array();
+ $rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
+ $rule['descr'] = gettext("Penalty Box");
+ $rule['source']['any'] = TRUE;
+ $rule['defaultqueue'] = "qOthersLow";
+ $rule['source']['address'] = $config['ezshaper']['step4']['address'];
+ $rule['destination']['any'] = TRUE;
+ $rule['floating'] = "yes";
+ $rule['wizard'] = "yes";
+ $rule['enabled'] = "on";
+ $config['filter']['rule'][] = $rule;
+ }
+ }
+
+ /* If user specifies an IP, we don't bother with providers */
+ if ($voip) {
+ if( is_ipaddr($config['ezshaper']['step3']['address']) || is_alias($config['ezshaper']['step3']['address'])) {
+ /* create VOIP rules */
+ $rule = array();
+ $rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
+ $rule['descr'] = gettext("VOIP Adapter");
+ $rule['protocol'] = "udp";
+ $rule['defaultqueue'] = "qVoIP";
+ $rule['source']['address'] = $config['ezshaper']['step3']['address'];
+ $rule['destination']['any'] = TRUE;
+ $rule['floating'] = "yes";
+ $rule['wizard'] = "yes";
+ $rule['enabled'] = "on";
+ $config['filter']['rule'][] = $rule;
+
+ } elseif( $config['ezshaper']['step3']['provider'] == "Generic" ) {
+ /* create VOIP rules */
+ $rule = array();
+ $rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
+ $rule['descr'] = "DiffServ/Lowdelay/Upload";
+ $rule['protocol'] = "udp";
+ $rule['source']['any'] = TRUE;
+ $rule['defaultqueue'] = "qVoIP";
+ $rule['destination']['any'] = TRUE;
+ $rule['iptos'] = "lowdelay";
+ $rule['floating'] = "yes";
+ $rule['wizard'] = "yes";
+ $rule['enabled'] = "on";
+ $config['filter']['rule'][] = $rule;
+
+ } else {
+ /* loop through voiplist[] */
+ foreach ($voiplist[$config['ezshaper']['step3']['provider']] as $voip) {
+ $rule = array();
+ $rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
+ $rule['defaultqueue'] = 'qVoIP';
+ $rule['source']['any'] = TRUE;
+ $rule['destination']['any'] = TRUE;
+ $rule['descr'] = "m_voip {$voip[0]} outbound";
+ $rule['floating'] = "yes";
+ $rule['wizard'] = "yes";
+ $rule['enabled'] = "on";
+ $rule['destination']['port'] = $voip[2]."-".$voip[3];
+ if($voip[1] != '')
+ $rule['protocol'] = $voip[1];
+ $config['filter']['rule'][] = $rule;
}
+ }
+ }
- /* If user specifies an IP, we don't bother with providers */
- if ($voip) {
- if( is_ipaddr($config['ezshaper']['step3']['address']) || is_alias($config['ezshaper']['step3']['address'])) {
- /* create VOIP rules */
- $rule = array();
- $rule['type'] = "match";
- $rule['descr'] = gettext("VOIP Adapter");
- $rule['protocol'] = "udp";
- $rule['defaultqueue'] = "qVoIP";
- $rule['source']['address'] = $config['ezshaper']['step3']['address'];
- $rule['destination']['any'] = TRUE;
- $rule['floating'] = "yes";
- $rule['wizard'] = "yes";
- $rule['enabled'] = "on";
- $config['filter']['rule'][] = $rule;
-
- } elseif( $config['ezshaper']['step3']['provider'] == "Generic" ) {
- /* create VOIP rules */
- $rule = array();
- $rule['type'] = "match";
- $rule['descr'] = "DiffServ/Lowdelay/Upload";
- $rule['protocol'] = "udp";
+ /* loop through p2plist[] */
+ if ($p2p) {
+ foreach($config['ezshaper']['step5'] as $key => $val) {
+ if (!is_array($p2plist[$key]))
+ continue;
+ foreach ($p2plist[$key] as $p2pclient) {
+ $rule = array();
+ $rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
+ $rule['defaultqueue'] = 'qP2P';
+ $rule['source']['any'] = TRUE;
+ $rule['destination']['any'] = TRUE;
+ $rule['descr'] = "m_P2P {$p2pclient[0]} outbound";
+ $rule['floating'] = "yes";
+ $rule['wizard'] = "yes";
+ $rule['destination']['port'] = $p2pclient[2]."-".$p2pclient[3];
+ if($p2pclient[1] != '')
+ $rule['protocol'] = $p2pclient[1];
+ $config['filter']['rule'][] = $rule;
+ }
+ }
+ }
+
+ /* loop through gamesplist[] */
+ if ($games) {
+ foreach($config['ezshaper']['step6'] as $key => $val) {
+ if (!is_array($gamesplist[$key]))
+ continue;
+ foreach ($gamesplist[$key] as $Gameclient) {
+ $rule = array();
+ $rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
+ $rule['defaultqueue'] = 'qGames';
+ if ($Gameclient[1] == "tcp")
+ $rule['ackqueue'] = 'qACK';
+ $rule['source']['any'] = TRUE;
+ $rule['destination']['any'] = TRUE;
+ $rule['floating'] = "yes";
+ $rule['wizard'] = "yes";
+ $rule['enabled'] = "on";
+ $rule['descr'] = "m_Game {$Gameclient[0]} outbound";
+ $rule['destination']['port'] = $Gameclient[2]."-".$Gameclient[3];
+ if($Gameclient[1] != '')
+ $rule['protocol'] = $Gameclient[1];
+ $config['filter']['rule'][] = $rule;
+ }
+ }
+ }
+
+ /* loop through othersplist[] */
+ if ($otherpriority) {
+ foreach($config['ezshaper']['step7'] as $key => $val) {
+ if (!is_array($othersplist[$key]))
+ continue;
+ foreach ($othersplist[$key] as $otherclient) {
+ $rule = array();
+ $rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
+ switch ($val) {
+ case "H":
+ $rule['defaultqueue'] = 'qOthersHigh'; /* posted value H or L */
+ if ($otherclient[1] == "tcp")
+ $rule['ackqueue'] = 'qACK';
+ $loop = 0;
+ break;
+ case "L":
+ $rule['defaultqueue'] = 'qOthersLow'; /* posted value H or L */
+ if ($otherclient[1] == "tcp")
+ $rule['ackqueue'] = 'qACK';
+ $loop = 0;
+ break;
+ case "D":
+ if ($p2pcatchall) {
+ $loop = 0;
+ $rule['defaultqueue'] = 'qOthersDefault';
+ if ($otherclient[1] == "tcp")
+ $rule['ackqueue'] = 'qACK';
+ } else
+ $loop = 1; /* It automitaclly goes to default queue */
+ break;
+ default:
+ $loop = 1;
+ }
+ if (!$loop) {
$rule['source']['any'] = TRUE;
- $rule['defaultqueue'] = "qVoIP";
$rule['destination']['any'] = TRUE;
- $rule['iptos'] = "lowdelay";
$rule['floating'] = "yes";
$rule['wizard'] = "yes";
$rule['enabled'] = "on";
- $config['filter']['rule'][] = $rule;
-
- } else {
- /* loop through voiplist[] */
- foreach ($voiplist[$config['ezshaper']['step3']['provider']] as $voip) {
- $rule = array();
- $rule['type'] = "match";
- $rule['defaultqueue'] = 'qVoIP';
- $rule['source']['any'] = TRUE;
- $rule['destination']['any'] = TRUE;
- $rule['descr'] = "m_voip {$voip[0]} outbound";
- $rule['floating'] = "yes";
- $rule['wizard'] = "yes";
- $rule['enabled'] = "on";
- $rule['destination']['port'] = $voip[2]."-".$voip[3];
- if($voip[1] != '')
- $rule['protocol'] = $voip[1];
- $config['filter']['rule'][] = $rule;
- }
- }
- }
+ $rule['descr'] = "m_Other {$otherclient[0]} outbound";
- /* loop through p2plist[] */
- if ($p2p) {
- foreach($config['ezshaper']['step5'] as $key => $val) {
- if (!is_array($p2plist[$key]))
- continue;
- foreach ($p2plist[$key] as $p2pclient) {
- $rule = array();
- $rule['type'] = "match";
- $rule['defaultqueue'] = 'qP2P';
- $rule['source']['any'] = TRUE;
- $rule['destination']['any'] = TRUE;
- $rule['descr'] = "m_P2P {$p2pclient[0]} outbound";
- $rule['floating'] = "yes";
- $rule['wizard'] = "yes";
- $rule['destination']['port'] = $p2pclient[2]."-".$p2pclient[3];
- if($p2pclient[1] != '')
- $rule['protocol'] = $p2pclient[1];
- $config['filter']['rule'][] = $rule;
- }
- }
- }
-
- /* loop through gamesplist[] */
- if ($games) {
- foreach($config['ezshaper']['step6'] as $key => $val) {
- if (!is_array($gamesplist[$key]))
- continue;
- foreach ($gamesplist[$key] as $Gameclient) {
- $rule = array();
- $rule['type'] = "match";
- $rule['defaultqueue'] = 'qGames';
- if ($Gameclient[1] == "tcp")
- $rule['ackqueue'] = 'qACK';
- $rule['source']['any'] = TRUE;
- $rule['destination']['any'] = TRUE;
- $rule['floating'] = "yes";
- $rule['wizard'] = "yes";
- $rule['enabled'] = "on";
- $rule['descr'] = "m_Game {$Gameclient[0]} outbound";
- $rule['destination']['port'] = $Gameclient[2]."-".$Gameclient[3];
- if($Gameclient[1] != '')
- $rule['protocol'] = $Gameclient[1];
- $config['filter']['rule'][] = $rule;
- }
- }
- }
-
- /* loop through othersplist[] */
- if ($otherpriority) {
- foreach($config['ezshaper']['step7'] as $key => $val) {
- if (!is_array($othersplist[$key]))
- continue;
- foreach ($othersplist[$key] as $otherclient) {
- $rule = array();
- $rule['type'] = "match";
- switch ($val) {
- case "H":
- $rule['defaultqueue'] = 'qOthersHigh'; /* posted value H or L */
- if ($otherclient[1] == "tcp")
- $rule['ackqueue'] = 'qACK';
- $loop = 0;
- break;
- case "L":
- $rule['defaultqueue'] = 'qOthersLow'; /* posted value H or L */
- if ($otherclient[1] == "tcp")
- $rule['ackqueue'] = 'qACK';
- $loop = 0;
- break;
- case "D":
- if ($p2pcatchall) {
- $loop = 0;
- $rule['defaultqueue'] = 'qOthersDefault';
- if ($otherclient[1] == "tcp")
- $rule['ackqueue'] = 'qACK';
- } else
- $loop = 1; /* It automitaclly goes to default queue */
- break;
- default:
- $loop = 1;
- }
- if (!$loop) {
- $rule['source']['any'] = TRUE;
- $rule['destination']['any'] = TRUE;
- $rule['floating'] = "yes";
- $rule['wizard'] = "yes";
- $rule['enabled'] = "on";
- $rule['descr'] = "m_Other {$otherclient[0]} outbound";
-
- if($otherclient[2] or $otherclient[3]) {
- $rule['destination']['port'] = $otherclient[2]."-".$otherclient[3];
- }
- if($otherclient[1] != '')
- $rule['protocol'] = $otherclient[1];
-
- $config['filter']['rule'][] = $rule;
- }
+ if($otherclient[2] or $otherclient[3]) {
+ $rule['destination']['port'] = $otherclient[2]."-".$otherclient[3];
}
+ if($otherclient[1] != '')
+ $rule['protocol'] = $otherclient[1];
+
+ $config['filter']['rule'][] = $rule;
}
}
- write_config();
+ }
+ }
+ write_config();
}
function wizard_get_bandwidthtype_scale($type = "b") {
diff --git a/usr/local/www/wizards/traffic_shaper_wizard_multi_all.inc b/usr/local/www/wizards/traffic_shaper_wizard_multi_all.inc
index 2ff0b84..519364f 100755
--- a/usr/local/www/wizards/traffic_shaper_wizard_multi_all.inc
+++ b/usr/local/www/wizards/traffic_shaper_wizard_multi_all.inc
@@ -658,13 +658,16 @@ function apply_all_choosen_items() {
$altq_list_queues = array();
$steps = intval($config['ezshaper']['step1']['numberofconnections']);
-
+
+ $interfacelist = array();
+
for ($i = 0; $i < $steps; $i++) {
$tmppath = array();
$altq =& new altq_root_queue();
$altq->SetInterface($config['ezshaper']['step2']["conn{$i}interface"]);
+ $interfacelist[] = $config['ezshaper']['step2']["conn{$i}interface"];
$altq->SetScheduler($config['ezshaper']['step2']["conn{$i}uploadscheduler"]);
$altq->SetBandwidth(floatval($config['ezshaper']['step2']["conn{$i}upload"]));
$altq->SetBwscale($config['ezshaper']['step2']["conn{$i}uploadspeed"]);
@@ -1448,23 +1451,26 @@ function apply_all_choosen_items() {
if (!is_array($config['filter']['rule']))
$config['filter']['rule'] = array();
- /* Rules */
- if ($penalty) {
- if( is_ipaddr($config['ezshaper']['step4']['address']) || is_alias($config['ezshaper']['step4']['address'])) {
- $rule = array();
- $rule['type'] = "match";
- $rule['descr'] = gettext("Penalty Box");
- $rule['source']['any'] = TRUE;
- $rule['defaultqueue'] = "qOthersLow";
- $rule['source']['address'] = $config['ezshaper']['step4']['address'];
- $rule['destination']['any'] = TRUE;
- $rule['floating'] = "yes";
- $rule['wizard'] = "yes";
- $rule['enabled'] = "on";
- $config['filter']['rule'][] = $rule;
-
- }
- }
+ $interfacelist = implode(",", $interfacelist);
+
+ /* Rules */
+ if ($penalty) {
+ if( is_ipaddr($config['ezshaper']['step4']['address']) || is_alias($config['ezshaper']['step4']['address'])) {
+ $rule = array();
+ $rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
+ $rule['descr'] = gettext("Penalty Box");
+ $rule['source']['any'] = TRUE;
+ $rule['defaultqueue'] = "qOthersLow";
+ $rule['source']['address'] = $config['ezshaper']['step4']['address'];
+ $rule['destination']['any'] = TRUE;
+ $rule['floating'] = "yes";
+ $rule['wizard'] = "yes";
+ $rule['enabled'] = "on";
+ $config['filter']['rule'][] = $rule;
+
+ }
+ }
/* If user specifies an IP, we don't bother with providers */
if ($voip) {
@@ -1472,6 +1478,7 @@ function apply_all_choosen_items() {
/* create VOIP rules */
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
$rule['descr'] = gettext("VOIP Adapter");
$rule['protocol'] = "udp";
$rule['defaultqueue'] = "qVoIP";
@@ -1486,6 +1493,7 @@ function apply_all_choosen_items() {
/* create VOIP rules */
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
$rule['descr'] = "DiffServ/Lowdelay/Upload";
$rule['protocol'] = "udp";
$rule['source']['any'] = TRUE;
@@ -1502,6 +1510,7 @@ function apply_all_choosen_items() {
foreach ($voiplist[$config['ezshaper']['step3']['provider']] as $voip) {
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
$rule['defaultqueue'] = 'qVoIP';
$rule['source']['any'] = TRUE;
$rule['destination']['any'] = TRUE;
@@ -1525,6 +1534,7 @@ function apply_all_choosen_items() {
foreach ($p2plist[$key] as $p2pclient) {
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
$rule['defaultqueue'] = 'qP2P';
$rule['source']['any'] = TRUE;
$rule['destination']['any'] = TRUE;
@@ -1547,6 +1557,7 @@ function apply_all_choosen_items() {
foreach ($gamesplist[$key] as $Gameclient) {
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
$rule['defaultqueue'] = 'qGames';
if ($Gameclient[1] == "tcp")
$rule['ackqueue'] = 'qACK';
@@ -1564,59 +1575,60 @@ function apply_all_choosen_items() {
}
}
- /* loop through othersplist[] */
- if ($otherpriority) {
- foreach($config['ezshaper']['step7'] as $key => $val) {
- if (!is_array($othersplist[$key]))
- continue;
- foreach ($othersplist[$key] as $otherclient) {
- $rule = array();
- $rule['type'] = "match";
- switch ($val) {
- case "H":
- $rule['defaultqueue'] = 'qOthersHigh'; /* posted value H or L */
- if ($otherclient[1] == "tcp")
+ /* loop through othersplist[] */
+ if ($otherpriority) {
+ foreach($config['ezshaper']['step7'] as $key => $val) {
+ if (!is_array($othersplist[$key]))
+ continue;
+ foreach ($othersplist[$key] as $otherclient) {
+ $rule = array();
+ $rule['type'] = "match";
+ $rule['interface'] = $interfacelist;
+ switch ($val) {
+ case "H":
+ $rule['defaultqueue'] = 'qOthersHigh'; /* posted value H or L */
+ if ($otherclient[1] == "tcp")
$rule['ackqueue'] = 'qACK';
- $loop = 0;
- break;
- case "L":
- $rule['defaultqueue'] = 'qOthersLow'; /* posted value H or L */
- if ($otherclient[1] == "tcp")
- $rule['ackqueue'] = 'qACK';
- $loop = 0;
- break;
- case "D":
- if ($p2pcatchall) {
- $loop = 0;
- $rule['defaultqueue'] = 'qOthersDefault';
- if ($otherclient[1] == "tcp")
- $rule['ackqueue'] = 'qACK';
- } else
- $loop = 1; /* It automitaclly goes to default queue */
- break;
- default:
- $loop = 1;
- }
- if (!$loop) {
- $rule['source']['any'] = TRUE;
- $rule['destination']['any'] = TRUE;
- $rule['floating'] = "yes";
- $rule['wizard'] = "yes";
- $rule['enabled'] = "on";
- $rule['descr'] = "m_Other {$otherclient[0]} outbound";
-
- if($otherclient[2] or $otherclient[3]) {
- $rule['destination']['port'] = $otherclient[2]."-".$otherclient[3];
- }
- if($otherclient[1] != '')
- $rule['protocol'] = $otherclient[1];
-
- $config['filter']['rule'][] = $rule;
- }
+ $loop = 0;
+ break;
+ case "L":
+ $rule['defaultqueue'] = 'qOthersLow'; /* posted value H or L */
+ if ($otherclient[1] == "tcp")
+ $rule['ackqueue'] = 'qACK';
+ $loop = 0;
+ break;
+ case "D":
+ if ($p2pcatchall) {
+ $loop = 0;
+ $rule['defaultqueue'] = 'qOthersDefault';
+ if ($otherclient[1] == "tcp")
+ $rule['ackqueue'] = 'qACK';
+ } else
+ $loop = 1; /* It automitaclly goes to default queue */
+ break;
+ default:
+ $loop = 1;
+ }
+ if (!$loop) {
+ $rule['source']['any'] = TRUE;
+ $rule['destination']['any'] = TRUE;
+ $rule['floating'] = "yes";
+ $rule['wizard'] = "yes";
+ $rule['enabled'] = "on";
+ $rule['descr'] = "m_Other {$otherclient[0]} outbound";
+
+ if($otherclient[2] or $otherclient[3]) {
+ $rule['destination']['port'] = $otherclient[2]."-".$otherclient[3];
}
+ if($otherclient[1] != '')
+ $rule['protocol'] = $otherclient[1];
+
+ $config['filter']['rule'][] = $rule;
}
}
- write_config();
+ }
+ }
+ write_config();
}
function wizard_get_bandwidthtype_scale($type = "b") {
diff --git a/usr/local/www/wizards/traffic_shaper_wizard_multi_lan.inc b/usr/local/www/wizards/traffic_shaper_wizard_multi_lan.inc
index 7ab8e69..9fdc3a3 100644
--- a/usr/local/www/wizards/traffic_shaper_wizard_multi_lan.inc
+++ b/usr/local/www/wizards/traffic_shaper_wizard_multi_lan.inc
@@ -451,6 +451,7 @@ function apply_all_choosen_items() {
$altq_list_queues = array();
$steps = floatval($config['ezshaper']['step1']['numberofconnections']);
+
for ($i = 0; $i < $steps; $i++) {
$tmppath = array();
@@ -1202,6 +1203,7 @@ function apply_all_choosen_items() {
if( is_ipaddr($config['ezshaper']['step4']['address']) || is_alias($config['ezshaper']['step4']['address'])) {
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = "wan";
$rule['descr'] = gettext("Penalty Box");
$rule['source']['any'] = TRUE;
$rule['defaultqueue'] = "qOthersLow";
@@ -1221,6 +1223,7 @@ function apply_all_choosen_items() {
/* create VOIP rules */
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = "wan";
$rule['descr'] = gettext("VOIP Adapter");
$rule['protocol'] = "udp";
$rule['defaultqueue'] = "qVoIP";
@@ -1235,6 +1238,7 @@ function apply_all_choosen_items() {
/* create VOIP rules */
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = "wan";
$rule['descr'] = "DiffServ/Lowdelay/Upload";
$rule['protocol'] = "udp";
$rule['source']['any'] = TRUE;
@@ -1251,6 +1255,7 @@ function apply_all_choosen_items() {
foreach ($voiplist[$config['ezshaper']['step3']['provider']] as $voip) {
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = "wan";
$rule['defaultqueue'] = 'qVoIP';
$rule['source']['any'] = TRUE;
$rule['destination']['any'] = TRUE;
@@ -1274,6 +1279,7 @@ function apply_all_choosen_items() {
foreach ($p2plist[$key] as $p2pclient) {
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = "wan";
$rule['defaultqueue'] = 'qP2P';
$rule['source']['any'] = TRUE;
$rule['destination']['any'] = TRUE;
@@ -1296,6 +1302,7 @@ function apply_all_choosen_items() {
foreach ($gamesplist[$key] as $Gameclient) {
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = "wan";
$rule['defaultqueue'] = 'qGames';
if ($Gameclient[1] == "tcp")
$rule['ackqueue'] = 'qACK';
@@ -1321,6 +1328,7 @@ function apply_all_choosen_items() {
foreach ($othersplist[$key] as $otherclient) {
$rule = array();
$rule['type'] = "match";
+ $rule['interface'] = "wan";
switch ($val) {
case "H":
$rule['defaultqueue'] = 'qOthersHigh'; /* posted value H or L */
OpenPOWER on IntegriCloud