summaryrefslogtreecommitdiff
path: root/sites/all/modules/ctools/js
diff options
context:
space:
mode:
authorCtibor Brančík <ctibor@brancik.cz>2016-03-20 19:27:01 +0100
committerCtibor Brančík <ctibor@brancik.cz>2016-03-20 19:27:01 +0100
commit29a6913890a675ddf1a9239b4407f105e02dc95d (patch)
treedd9ba21b73e9e704952b49d5153616a9dfa9b98f /sites/all/modules/ctools/js
parent5ddacae6306ce071d4f7e4d438960d6d3a4c6bd8 (diff)
downloadbrdo-29a6913890a675ddf1a9239b4407f105e02dc95d.tar.gz
brdo-29a6913890a675ddf1a9239b4407f105e02dc95d.tar.bz2
Added drupal modules for site
Diffstat (limited to 'sites/all/modules/ctools/js')
-rw-r--r--sites/all/modules/ctools/js/ajax-responder.js126
-rw-r--r--sites/all/modules/ctools/js/auto-submit.js100
-rw-r--r--sites/all/modules/ctools/js/collapsible-div.js241
-rw-r--r--sites/all/modules/ctools/js/dependent.js231
-rw-r--r--sites/all/modules/ctools/js/dropbutton.js94
-rw-r--r--sites/all/modules/ctools/js/dropdown.js87
-rw-r--r--sites/all/modules/ctools/js/jump-menu.js42
-rw-r--r--sites/all/modules/ctools/js/modal.js696
-rw-r--r--sites/all/modules/ctools/js/states-show.js43
-rw-r--r--sites/all/modules/ctools/js/stylizer.js220
10 files changed, 1880 insertions, 0 deletions
diff --git a/sites/all/modules/ctools/js/ajax-responder.js b/sites/all/modules/ctools/js/ajax-responder.js
new file mode 100644
index 000000000..1cad618ef
--- /dev/null
+++ b/sites/all/modules/ctools/js/ajax-responder.js
@@ -0,0 +1,126 @@
+/**
+ * @file
+ *
+ * CTools flexible AJAX responder object.
+ */
+
+(function ($) {
+ Drupal.CTools = Drupal.CTools || {};
+ Drupal.CTools.AJAX = Drupal.CTools.AJAX || {};
+ /**
+ * Grab the response from the server and store it.
+ *
+ * @todo restore the warm cache functionality
+ */
+ Drupal.CTools.AJAX.warmCache = function () {
+ // Store this expression for a minor speed improvement.
+ $this = $(this);
+ var old_url = $this.attr('href');
+ // If we are currently fetching, or if we have fetched this already which is
+ // ideal for things like pagers, where the previous page might already have
+ // been seen in the cache.
+ if ($this.hasClass('ctools-fetching') || Drupal.CTools.AJAX.commandCache[old_url]) {
+ return false;
+ }
+
+ // Grab all the links that match this url and add the fetching class.
+ // This allows the caching system to grab each url once and only once
+ // instead of grabbing the url once per <a>.
+ var $objects = $('a[href="' + old_url + '"]')
+ $objects.addClass('ctools-fetching');
+ try {
+ url = old_url.replace(/\/nojs(\/|$)/g, '/ajax$1');
+ $.ajax({
+ type: "POST",
+ url: url,
+ data: { 'js': 1, 'ctools_ajax': 1},
+ global: true,
+ success: function (data) {
+ Drupal.CTools.AJAX.commandCache[old_url] = data;
+ $objects.addClass('ctools-cache-warmed').trigger('ctools-cache-warm', [data]);
+ },
+ complete: function() {
+ $objects.removeClass('ctools-fetching');
+ },
+ dataType: 'json'
+ });
+ }
+ catch (err) {
+ $objects.removeClass('ctools-fetching');
+ return false;
+ }
+
+ return false;
+ };
+
+ /**
+ * Cachable click handler to fetch the commands out of the cache or from url.
+ */
+ Drupal.CTools.AJAX.clickAJAXCacheLink = function () {
+ $this = $(this);
+ if ($this.hasClass('ctools-fetching')) {
+ $this.bind('ctools-cache-warm', function (event, data) {
+ Drupal.CTools.AJAX.respond(data);
+ });
+ return false;
+ }
+ else {
+ if ($this.hasClass('ctools-cache-warmed') && Drupal.CTools.AJAX.commandCache[$this.attr('href')]) {
+ Drupal.CTools.AJAX.respond(Drupal.CTools.AJAX.commandCache[$this.attr('href')]);
+ return false;
+ }
+ else {
+ return Drupal.CTools.AJAX.clickAJAXLink.apply(this);
+ }
+ }
+ };
+
+ /**
+ * Find a URL for an AJAX button.
+ *
+ * The URL for this gadget will be composed of the values of items by
+ * taking the ID of this item and adding -url and looking for that
+ * class. They need to be in the form in order since we will
+ * concat them all together using '/'.
+ */
+ Drupal.CTools.AJAX.findURL = function(item) {
+ var url = '';
+ var url_class = '.' + $(item).attr('id') + '-url';
+ $(url_class).each(
+ function() {
+ var $this = $(this);
+ if (url && $this.val()) {
+ url += '/';
+ }
+ url += $this.val();
+ });
+ return url;
+ };
+
+ // Hide these in a ready to ensure that Drupal.ajax is set up first.
+ $(function() {
+ Drupal.ajax.prototype.commands.attr = function(ajax, data, status) {
+ $(data.selector).attr(data.name, data.value);
+ };
+
+
+ Drupal.ajax.prototype.commands.redirect = function(ajax, data, status) {
+ if (data.delay > 0) {
+ setTimeout(function () {
+ location.href = data.url;
+ }, data.delay);
+ }
+ else {
+ location.href = data.url;
+ }
+ };
+
+ Drupal.ajax.prototype.commands.reload = function(ajax, data, status) {
+ location.reload();
+ };
+
+ Drupal.ajax.prototype.commands.submit = function(ajax, data, status) {
+ $(data.selector).submit();
+ }
+ });
+})(jQuery);
diff --git a/sites/all/modules/ctools/js/auto-submit.js b/sites/all/modules/ctools/js/auto-submit.js
new file mode 100644
index 000000000..a3e9aa42a
--- /dev/null
+++ b/sites/all/modules/ctools/js/auto-submit.js
@@ -0,0 +1,100 @@
+(function($){
+/**
+ * To make a form auto submit, all you have to do is 3 things:
+ *
+ * ctools_add_js('auto-submit');
+ *
+ * On gadgets you want to auto-submit when changed, add the ctools-auto-submit
+ * class. With FAPI, add:
+ * @code
+ * '#attributes' => array('class' => array('ctools-auto-submit')),
+ * @endcode
+ *
+ * If you want to have auto-submit for every form element,
+ * add the ctools-auto-submit-full-form to the form. With FAPI, add:
+ * @code
+ * '#attributes' => array('class' => array('ctools-auto-submit-full-form')),
+ * @endcode
+ *
+ * If you want to exclude a field from the ctool-auto-submit-full-form auto submission,
+ * add the class ctools-auto-submit-exclude to the form element. With FAPI, add:
+ * @code
+ * '#attributes' => array('class' => array('ctools-auto-submit-exclude')),
+ * @endcode
+ *
+ * Finally, you have to identify which button you want clicked for autosubmit.
+ * The behavior of this button will be honored if it's ajaxy or not:
+ * @code
+ * '#attributes' => array('class' => array('ctools-use-ajax', 'ctools-auto-submit-click')),
+ * @endcode
+ *
+ * Currently only 'select', 'radio', 'checkbox' and 'textfield' types are supported. We probably
+ * could use additional support for HTML5 input types.
+ */
+
+Drupal.behaviors.CToolsAutoSubmit = {
+ attach: function(context) {
+ // 'this' references the form element
+ function triggerSubmit (e) {
+ var $this = $(this);
+ if (!$this.hasClass('ctools-ajaxing')) {
+ $this.find('.ctools-auto-submit-click').click();
+ }
+ }
+
+ // the change event bubbles so we only need to bind it to the outer form
+ $('form.ctools-auto-submit-full-form', context)
+ .add('.ctools-auto-submit', context)
+ .filter('form, select, input:not(:text, :submit)')
+ .once('ctools-auto-submit')
+ .change(function (e) {
+ // don't trigger on text change for full-form
+ if ($(e.target).is(':not(:text, :submit, .ctools-auto-submit-exclude)')) {
+ triggerSubmit.call(e.target.form);
+ }
+ });
+
+ // e.keyCode: key
+ var discardKeyCode = [
+ 16, // shift
+ 17, // ctrl
+ 18, // alt
+ 20, // caps lock
+ 33, // page up
+ 34, // page down
+ 35, // end
+ 36, // home
+ 37, // left arrow
+ 38, // up arrow
+ 39, // right arrow
+ 40, // down arrow
+ 9, // tab
+ 13, // enter
+ 27 // esc
+ ];
+ // Don't wait for change event on textfields
+ $('.ctools-auto-submit-full-form input:text, input:text.ctools-auto-submit', context)
+ .filter(':not(.ctools-auto-submit-exclude)')
+ .once('ctools-auto-submit', function () {
+ // each textinput element has his own timeout
+ var timeoutID = 0;
+ $(this)
+ .bind('keydown keyup', function (e) {
+ if ($.inArray(e.keyCode, discardKeyCode) === -1) {
+ timeoutID && clearTimeout(timeoutID);
+ }
+ })
+ .keyup(function(e) {
+ if ($.inArray(e.keyCode, discardKeyCode) === -1) {
+ timeoutID = setTimeout($.proxy(triggerSubmit, this.form), 500);
+ }
+ })
+ .bind('change', function (e) {
+ if ($.inArray(e.keyCode, discardKeyCode) === -1) {
+ timeoutID = setTimeout($.proxy(triggerSubmit, this.form), 500);
+ }
+ });
+ });
+ }
+}
+})(jQuery);
diff --git a/sites/all/modules/ctools/js/collapsible-div.js b/sites/all/modules/ctools/js/collapsible-div.js
new file mode 100644
index 000000000..134151c3d
--- /dev/null
+++ b/sites/all/modules/ctools/js/collapsible-div.js
@@ -0,0 +1,241 @@
+/**
+ * @file
+ * Javascript required for a simple collapsible div.
+ *
+ * Creating a collapsible div with this doesn't take too much. There are
+ * three classes necessary:
+ *
+ * - ctools-collapsible-container: This is the overall container that will be
+ * collapsible. This must be a div.
+ * - ctools-collapsible-handle: This is the title area, and is what will be
+ * visible when it is collapsed. This can be any block element, such as div
+ * or h2.
+ * - ctools-collapsible-content: This is the ocntent area and will only be
+ * visible when expanded. This must be a div.
+ *
+ * Adding 'ctools-collapsible-remember' to the container class will cause the
+ * state of the container to be stored in a cookie, and remembered from page
+ * load to page load. This will only work if the container has a unique ID, so
+ * very carefully add IDs to your containers.
+ *
+ * If the class 'ctools-no-container' is placed on the container, the container
+ * will be the handle. The content will be found by appending '-content' to the
+ * id of the handle. The ctools-collapsible-handle and
+ * ctools-collapsible-content classes will not be required in that case, and no
+ * restrictions on what of data the container is are placed. Like
+ * ctools-collapsible-remember this requires an id to eist.
+ *
+ * The content will be 'open' unless the container class has 'ctools-collapsed'
+ * as a class, which will cause the container to draw collapsed.
+ */
+
+(function ($) {
+ // All CTools tools begin with this if they need to use the CTools namespace.
+ if (!Drupal.CTools) {
+ Drupal.CTools = {};
+ }
+
+ /**
+ * Object to store state.
+ *
+ * This object will remember the state of collapsible containers. The first
+ * time a state is requested, it will check the cookie and set up the variable.
+ * If a state has been changed, when the window is unloaded the state will be
+ * saved.
+ */
+ Drupal.CTools.Collapsible = {
+ state: {},
+ stateLoaded: false,
+ stateChanged: false,
+ cookieString: 'ctools-collapsible-state=',
+
+ /**
+ * Get the current collapsed state of a container.
+ *
+ * If set to 1, the container is open. If set to -1, the container is
+ * collapsed. If unset the state is unknown, and the default state should
+ * be used.
+ */
+ getState: function (id) {
+ if (!this.stateLoaded) {
+ this.loadCookie();
+ }
+
+ return this.state[id];
+ },
+
+ /**
+ * Set the collapsed state of a container for subsequent page loads.
+ *
+ * Set the state to 1 for open, -1 for collapsed.
+ */
+ setState: function (id, state) {
+ if (!this.stateLoaded) {
+ this.loadCookie();
+ }
+
+ this.state[id] = state;
+
+ if (!this.stateChanged) {
+ this.stateChanged = true;
+ $(window).unload(this.unload);
+ }
+ },
+
+ /**
+ * Check the cookie and load the state variable.
+ */
+ loadCookie: function () {
+ // If there is a previous instance of this cookie
+ if (document.cookie.length > 0) {
+ // Get the number of characters that have the list of values
+ // from our string index.
+ offset = document.cookie.indexOf(this.cookieString);
+
+ // If its positive, there is a list!
+ if (offset != -1) {
+ offset += this.cookieString.length;
+ var end = document.cookie.indexOf(';', offset);
+ if (end == -1) {
+ end = document.cookie.length;
+ }
+
+ // Get a list of all values that are saved on our string
+ var cookie = unescape(document.cookie.substring(offset, end));
+
+ if (cookie != '') {
+ var cookieList = cookie.split(',');
+ for (var i = 0; i < cookieList.length; i++) {
+ var info = cookieList[i].split(':');
+ this.state[info[0]] = info[1];
+ }
+ }
+ }
+ }
+
+ this.stateLoaded = true;
+ },
+
+ /**
+ * Turn the state variable into a string and store it in the cookie.
+ */
+ storeCookie: function () {
+ var cookie = '';
+
+ // Get a list of IDs, saparated by comma
+ for (i in this.state) {
+ if (cookie != '') {
+ cookie += ',';
+ }
+ cookie += i + ':' + this.state[i];
+ }
+
+ // Save this values on the cookie
+ document.cookie = this.cookieString + escape(cookie) + ';path=/';
+ },
+
+ /**
+ * Respond to the unload event by storing the current state.
+ */
+ unload: function() {
+ Drupal.CTools.Collapsible.storeCookie();
+ }
+ };
+
+ // Set up an array for callbacks.
+ Drupal.CTools.CollapsibleCallbacks = [];
+ Drupal.CTools.CollapsibleCallbacksAfterToggle = [];
+
+ /**
+ * Bind collapsible behavior to a given container.
+ */
+ Drupal.CTools.bindCollapsible = function () {
+ var $container = $(this);
+
+ // Allow the specification of the 'no container' class, which means the
+ // handle and the container can be completely independent.
+ if ($container.hasClass('ctools-no-container') && $container.attr('id')) {
+ // In this case, the container *is* the handle and the content is found
+ // by adding '-content' to the id. Obviously, an id is required.
+ var handle = $container;
+ var content = $('#' + $container.attr('id') + '-content');
+ }
+ else {
+ var handle = $container.children('.ctools-collapsible-handle');
+ var content = $container.children('div.ctools-collapsible-content');
+ }
+
+ if (content.length) {
+ // Create the toggle item and place it in front of the toggle.
+ var toggle = $('<span class="ctools-toggle"></span>');
+ handle.before(toggle);
+
+ // If the remember class is set, check to see if we have a remembered
+ // state stored.
+ if ($container.hasClass('ctools-collapsible-remember') && $container.attr('id')) {
+ var state = Drupal.CTools.Collapsible.getState($container.attr('id'));
+ if (state == 1) {
+ $container.removeClass('ctools-collapsed');
+ }
+ else if (state == -1) {
+ $container.addClass('ctools-collapsed');
+ }
+ }
+
+ // If we should start collapsed, do so:
+ if ($container.hasClass('ctools-collapsed')) {
+ toggle.toggleClass('ctools-toggle-collapsed');
+ content.hide();
+ }
+
+ var afterToggle = function () {
+ if (Drupal.CTools.CollapsibleCallbacksAfterToggle) {
+ for (i in Drupal.CTools.CollapsibleCallbacksAfterToggle) {
+ Drupal.CTools.CollapsibleCallbacksAfterToggle[i]($container, handle, content, toggle);
+ }
+ }
+ }
+
+ var clickMe = function () {
+ if (Drupal.CTools.CollapsibleCallbacks) {
+ for (i in Drupal.CTools.CollapsibleCallbacks) {
+ Drupal.CTools.CollapsibleCallbacks[i]($container, handle, content, toggle);
+ }
+ }
+
+ // If the container is a table element slideToggle does not do what
+ // we want, so use toggle() instead.
+ if ($container.is('table')) {
+ content.toggle(0, afterToggle);
+ }
+ else {
+ content.slideToggle(100, afterToggle);
+ }
+
+ $container.toggleClass('ctools-collapsed');
+ toggle.toggleClass('ctools-toggle-collapsed');
+
+ // If we're supposed to remember the state of this class, do so.
+ if ($container.hasClass('ctools-collapsible-remember') && $container.attr('id')) {
+ var state = toggle.hasClass('ctools-toggle-collapsed') ? -1 : 1;
+ Drupal.CTools.Collapsible.setState($container.attr('id'), state);
+ }
+
+ return false;
+ }
+
+ // Let both the toggle and the handle be clickable.
+ toggle.click(clickMe);
+ handle.click(clickMe);
+ }
+ };
+
+ /**
+ * Support Drupal's 'behaviors' system for binding.
+ */
+ Drupal.behaviors.CToolsCollapsible = {
+ attach: function(context) {
+ $('.ctools-collapsible-container', context).once('ctools-collapsible', Drupal.CTools.bindCollapsible);
+ }
+ }
+})(jQuery);
diff --git a/sites/all/modules/ctools/js/dependent.js b/sites/all/modules/ctools/js/dependent.js
new file mode 100644
index 000000000..f74ec81ba
--- /dev/null
+++ b/sites/all/modules/ctools/js/dependent.js
@@ -0,0 +1,231 @@
+/**
+ * @file
+ * Provides dependent visibility for form items in CTools' ajax forms.
+ *
+ * To your $form item definition add:
+ * - '#process' => array('ctools_process_dependency'),
+ * - '#dependency' => array('id-of-form-item' => array(list, of, values, that,
+ * make, this, item, show),
+ *
+ * Special considerations:
+ * - Radios are harder. Because Drupal doesn't give radio groups individual IDs,
+ * use 'radio:name-of-radio'.
+ *
+ * - Checkboxes don't have their own id, so you need to add one in a div
+ * around the checkboxes via #prefix and #suffix. You actually need to add TWO
+ * divs because it's the parent that gets hidden. Also be sure to retain the
+ * 'expand_checkboxes' in the #process array, because the CTools process will
+ * override it.
+ */
+
+(function ($) {
+ Drupal.CTools = Drupal.CTools || {};
+ Drupal.CTools.dependent = {};
+
+ Drupal.CTools.dependent.bindings = {};
+ Drupal.CTools.dependent.activeBindings = {};
+ Drupal.CTools.dependent.activeTriggers = [];
+
+ Drupal.CTools.dependent.inArray = function(array, search_term) {
+ var i = array.length;
+ while (i--) {
+ if (array[i] == search_term) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ Drupal.CTools.dependent.autoAttach = function() {
+ // Clear active bindings and triggers.
+ for (i in Drupal.CTools.dependent.activeTriggers) {
+ $(Drupal.CTools.dependent.activeTriggers[i]).unbind('change.ctools-dependent');
+ }
+ Drupal.CTools.dependent.activeTriggers = [];
+ Drupal.CTools.dependent.activeBindings = {};
+ Drupal.CTools.dependent.bindings = {};
+
+ if (!Drupal.settings.CTools) {
+ return;
+ }
+
+ // Iterate through all relationships
+ for (id in Drupal.settings.CTools.dependent) {
+ // Test to make sure the id even exists; this helps clean up multiple
+ // AJAX calls with multiple forms.
+
+ // Drupal.CTools.dependent.activeBindings[id] is a boolean,
+ // whether the binding is active or not. Defaults to no.
+ Drupal.CTools.dependent.activeBindings[id] = 0;
+ // Iterate through all possible values
+ for(bind_id in Drupal.settings.CTools.dependent[id].values) {
+ // This creates a backward relationship. The bind_id is the ID
+ // of the element which needs to change in order for the id to hide or become shown.
+ // The id is the ID of the item which will be conditionally hidden or shown.
+ // Here we're setting the bindings for the bind
+ // id to be an empty array if it doesn't already have bindings to it
+ if (!Drupal.CTools.dependent.bindings[bind_id]) {
+ Drupal.CTools.dependent.bindings[bind_id] = [];
+ }
+ // Add this ID
+ Drupal.CTools.dependent.bindings[bind_id].push(id);
+ // Big long if statement.
+ // Drupal.settings.CTools.dependent[id].values[bind_id] holds the possible values
+
+ if (bind_id.substring(0, 6) == 'radio:') {
+ var trigger_id = "input[name='" + bind_id.substring(6) + "']";
+ }
+ else {
+ var trigger_id = '#' + bind_id;
+ }
+
+ Drupal.CTools.dependent.activeTriggers.push(trigger_id);
+
+ if ($(trigger_id).attr('type') == 'checkbox') {
+ $(trigger_id).siblings('label').addClass('hidden-options');
+ }
+
+ var getValue = function(item, trigger) {
+ if ($(trigger).size() == 0) {
+ return null;
+ }
+
+ if (item.substring(0, 6) == 'radio:') {
+ var val = $(trigger + ':checked').val();
+ }
+ else {
+ switch ($(trigger).attr('type')) {
+ case 'checkbox':
+ var val = $(trigger).attr('checked') ? true : false;
+
+ if (val) {
+ $(trigger).siblings('label').removeClass('hidden-options').addClass('expanded-options');
+ }
+ else {
+ $(trigger).siblings('label').removeClass('expanded-options').addClass('hidden-options');
+ }
+
+ break;
+ default:
+ var val = $(trigger).val();
+ }
+ }
+ return val;
+ }
+
+ var setChangeTrigger = function(trigger_id, bind_id) {
+ // Triggered when change() is clicked.
+ var changeTrigger = function() {
+ var val = getValue(bind_id, trigger_id);
+
+ if (val == null) {
+ return;
+ }
+
+ for (i in Drupal.CTools.dependent.bindings[bind_id]) {
+ var id = Drupal.CTools.dependent.bindings[bind_id][i];
+ // Fix numerous errors
+ if (typeof id != 'string') {
+ continue;
+ }
+
+ // This bit had to be rewritten a bit because two properties on the
+ // same set caused the counter to go up and up and up.
+ if (!Drupal.CTools.dependent.activeBindings[id]) {
+ Drupal.CTools.dependent.activeBindings[id] = {};
+ }
+
+ if (val != null && Drupal.CTools.dependent.inArray(Drupal.settings.CTools.dependent[id].values[bind_id], val)) {
+ Drupal.CTools.dependent.activeBindings[id][bind_id] = 'bind';
+ }
+ else {
+ delete Drupal.CTools.dependent.activeBindings[id][bind_id];
+ }
+
+ var len = 0;
+ for (i in Drupal.CTools.dependent.activeBindings[id]) {
+ len++;
+ }
+
+ var object = $('#' + id + '-wrapper');
+ if (!object.size()) {
+ // Some elements can't use the parent() method or they can
+ // damage things. They are guaranteed to have wrappers but
+ // only if dependent.inc provided them. This check prevents
+ // problems when multiple AJAX calls cause settings to build
+ // up.
+ var $original = $('#' + id);
+ if ($original.is('fieldset') || $original.is('textarea')) {
+ continue;
+ }
+
+ object = $('#' + id).parent();
+ }
+
+ if (Drupal.settings.CTools.dependent[id].type == 'disable') {
+ if (Drupal.settings.CTools.dependent[id].num <= len) {
+ // Show if the element if criteria is matched
+ object.attr('disabled', false);
+ object.addClass('dependent-options');
+ object.children().attr('disabled', false);
+ }
+ else {
+ // Otherwise hide. Use css rather than hide() because hide()
+ // does not work if the item is already hidden, for example,
+ // in a collapsed fieldset.
+ object.attr('disabled', true);
+ object.children().attr('disabled', true);
+ }
+ }
+ else {
+ if (Drupal.settings.CTools.dependent[id].num <= len) {
+ // Show if the element if criteria is matched
+ object.show(0);
+ object.addClass('dependent-options');
+ }
+ else {
+ // Otherwise hide. Use css rather than hide() because hide()
+ // does not work if the item is already hidden, for example,
+ // in a collapsed fieldset.
+ object.css('display', 'none');
+ }
+ }
+ }
+ }
+
+ $(trigger_id).bind('change.ctools-dependent', function() {
+ // Trigger the internal change function
+ // the attr('id') is used because closures are more confusing
+ changeTrigger(trigger_id, bind_id);
+ });
+ // Trigger initial reaction
+ changeTrigger(trigger_id, bind_id);
+ }
+ setChangeTrigger(trigger_id, bind_id);
+ }
+ }
+ }
+
+ Drupal.behaviors.CToolsDependent = {
+ attach: function (context) {
+ Drupal.CTools.dependent.autoAttach();
+
+ // Really large sets of fields are too slow with the above method, so this
+ // is a sort of hacked one that's faster but much less flexible.
+ $("select.ctools-master-dependent")
+ .once('ctools-dependent')
+ .bind('change.ctools-dependent', function() {
+ var val = $(this).val();
+ if (val == 'all') {
+ $('.ctools-dependent-all').show(0);
+ }
+ else {
+ $('.ctools-dependent-all').hide(0);
+ $('.ctools-dependent-' + val).show(0);
+ }
+ })
+ .trigger('change.ctools-dependent');
+ }
+ }
+})(jQuery);
diff --git a/sites/all/modules/ctools/js/dropbutton.js b/sites/all/modules/ctools/js/dropbutton.js
new file mode 100644
index 000000000..f505550b6
--- /dev/null
+++ b/sites/all/modules/ctools/js/dropbutton.js
@@ -0,0 +1,94 @@
+/**
+ * @file
+ * Implement a simple, clickable dropbutton menu.
+ *
+ * See dropbutton.theme.inc for primary documentation.
+ *
+ * The javascript relies on four classes:
+ * - The dropbutton must be fully contained in a div with the class
+ * ctools-dropbutton. It must also contain the class ctools-no-js
+ * which will be immediately removed by the javascript; this allows for
+ * graceful degradation.
+ * - The trigger that opens the dropbutton must be an a tag wit hthe class
+ * ctools-dropbutton-link. The href should just be '#' as this will never
+ * be allowed to complete.
+ * - The part of the dropbutton that will appear when the link is clicked must
+ * be a div with class ctools-dropbutton-container.
+ * - Finally, ctools-dropbutton-hover will be placed on any link that is being
+ * hovered over, so that the browser can restyle the links.
+ *
+ * This tool isn't meant to replace click-tips or anything, it is specifically
+ * meant to work well presenting menus.
+ */
+
+(function ($) {
+ Drupal.behaviors.CToolsDropbutton = {
+ attach: function() {
+ // Process buttons. All dropbuttons are buttons.
+ $('.ctools-button')
+ .once('ctools-button')
+ .removeClass('ctools-no-js');
+
+ // Process dropbuttons. Not all buttons are dropbuttons.
+ $('.ctools-dropbutton').once('ctools-dropbutton', function() {
+ var $dropbutton = $(this);
+ var $button = $('.ctools-content', $dropbutton);
+ var $secondaryActions = $('li', $button).not(':first');
+ var $twisty = $(".ctools-link", $dropbutton);
+ var open = false;
+ var hovering = false;
+ var timerID = 0;
+
+ var toggle = function(close) {
+ // if it's open or we're told to close it, close it.
+ if (open || close) {
+ // If we're just toggling it, close it immediately.
+ if (!close) {
+ open = false;
+ $secondaryActions.slideUp(100);
+ $dropbutton.removeClass('open');
+ }
+ else {
+ // If we were told to close it, wait half a second to make
+ // sure that's what the user wanted.
+ // Clear any previous timer we were using.
+ if (timerID) {
+ clearTimeout(timerID);
+ }
+ timerID = setTimeout(function() {
+ if (!hovering) {
+ open = false;
+ $secondaryActions.slideUp(100);
+ $dropbutton.removeClass('open');
+ }}, 500);
+ }
+ }
+ else {
+ // open it.
+ open = true;
+ $secondaryActions.animate({height: "show", opacity: "show"}, 100);
+ $dropbutton.addClass('open');
+ }
+ }
+ // Hide the secondary actions initially.
+ $secondaryActions.hide();
+
+ $twisty.click(function() {
+ toggle();
+ return false;
+ });
+
+ $dropbutton.hover(
+ function() {
+ hovering = true;
+ }, // hover in
+ function() { // hover out
+ hovering = false;
+ toggle(true);
+ return false;
+ }
+ );
+ });
+ }
+ }
+})(jQuery);
diff --git a/sites/all/modules/ctools/js/dropdown.js b/sites/all/modules/ctools/js/dropdown.js
new file mode 100644
index 000000000..c829ae2fe
--- /dev/null
+++ b/sites/all/modules/ctools/js/dropdown.js
@@ -0,0 +1,87 @@
+/**
+ * @file
+ * Implement a simple, clickable dropdown menu.
+ *
+ * See dropdown.theme.inc for primary documentation.
+ *
+ * The javascript relies on four classes:
+ * - The dropdown must be fully contained in a div with the class
+ * ctools-dropdown. It must also contain the class ctools-dropdown-no-js
+ * which will be immediately removed by the javascript; this allows for
+ * graceful degradation.
+ * - The trigger that opens the dropdown must be an a tag wit hthe class
+ * ctools-dropdown-link. The href should just be '#' as this will never
+ * be allowed to complete.
+ * - The part of the dropdown that will appear when the link is clicked must
+ * be a div with class ctools-dropdown-container.
+ * - Finally, ctools-dropdown-hover will be placed on any link that is being
+ * hovered over, so that the browser can restyle the links.
+ *
+ * This tool isn't meant to replace click-tips or anything, it is specifically
+ * meant to work well presenting menus.
+ */
+
+(function ($) {
+ Drupal.behaviors.CToolsDropdown = {
+ attach: function() {
+ $('div.ctools-dropdown').once('ctools-dropdown', function() {
+ var $dropdown = $(this);
+ var open = false;
+ var hovering = false;
+ var timerID = 0;
+
+ $dropdown.removeClass('ctools-dropdown-no-js');
+
+ var toggle = function(close) {
+ // if it's open or we're told to close it, close it.
+ if (open || close) {
+ // If we're just toggling it, close it immediately.
+ if (!close) {
+ open = false;
+ $("div.ctools-dropdown-container", $dropdown).slideUp(100);
+ }
+ else {
+ // If we were told to close it, wait half a second to make
+ // sure that's what the user wanted.
+ // Clear any previous timer we were using.
+ if (timerID) {
+ clearTimeout(timerID);
+ }
+ timerID = setTimeout(function() {
+ if (!hovering) {
+ open = false;
+ $("div.ctools-dropdown-container", $dropdown).slideUp(100);
+ }
+ }, 500);
+ }
+ }
+ else {
+ // open it.
+ open = true;
+ $("div.ctools-dropdown-container", $dropdown)
+ .animate({height: "show", opacity: "show"}, 100);
+ }
+ }
+ $("a.ctools-dropdown-link", $dropdown).click(function() {
+ toggle();
+ return false;
+ });
+
+ $dropdown.hover(
+ function() {
+ hovering = true;
+ }, // hover in
+ function() { // hover out
+ hovering = false;
+ toggle(true);
+ return false;
+ });
+ // @todo -- just use CSS for this noise.
+ $("div.ctools-dropdown-container a").hover(
+ function() { $(this).addClass('ctools-dropdown-hover'); },
+ function() { $(this).removeClass('ctools-dropdown-hover'); }
+ );
+ });
+ }
+ }
+})(jQuery);
diff --git a/sites/all/modules/ctools/js/jump-menu.js b/sites/all/modules/ctools/js/jump-menu.js
new file mode 100644
index 000000000..7b0928a68
--- /dev/null
+++ b/sites/all/modules/ctools/js/jump-menu.js
@@ -0,0 +1,42 @@
+
+(function($) {
+ Drupal.behaviors.CToolsJumpMenu = {
+ attach: function(context) {
+ $('.ctools-jump-menu-hide')
+ .once('ctools-jump-menu')
+ .hide();
+
+ $('.ctools-jump-menu-change')
+ .once('ctools-jump-menu')
+ .change(function() {
+ var loc = $(this).val();
+ var urlArray = loc.split('::');
+ if (urlArray[1]) {
+ location.href = urlArray[1];
+ }
+ else {
+ location.href = loc;
+ }
+ return false;
+ });
+
+ $('.ctools-jump-menu-button')
+ .once('ctools-jump-menu')
+ .click(function() {
+ // Instead of submitting the form, just perform the redirect.
+
+ // Find our sibling value.
+ var $select = $(this).parents('form').find('.ctools-jump-menu-select');
+ var loc = $select.val();
+ var urlArray = loc.split('::');
+ if (urlArray[1]) {
+ location.href = urlArray[1];
+ }
+ else {
+ location.href = loc;
+ }
+ return false;
+ });
+ }
+ }
+})(jQuery);
diff --git a/sites/all/modules/ctools/js/modal.js b/sites/all/modules/ctools/js/modal.js
new file mode 100644
index 000000000..c757ef274
--- /dev/null
+++ b/sites/all/modules/ctools/js/modal.js
@@ -0,0 +1,696 @@
+/**
+ * @file
+ *
+ * Implement a modal form.
+ *
+ * @see modal.inc for documentation.
+ *
+ * This javascript relies on the CTools ajax responder.
+ */
+
+(function ($) {
+ // Make sure our objects are defined.
+ Drupal.CTools = Drupal.CTools || {};
+ Drupal.CTools.Modal = Drupal.CTools.Modal || {};
+
+ /**
+ * Display the modal
+ *
+ * @todo -- document the settings.
+ */
+ Drupal.CTools.Modal.show = function(choice) {
+ var opts = {};
+
+ if (choice && typeof choice == 'string' && Drupal.settings[choice]) {
+ // This notation guarantees we are actually copying it.
+ $.extend(true, opts, Drupal.settings[choice]);
+ }
+ else if (choice) {
+ $.extend(true, opts, choice);
+ }
+
+ var defaults = {
+ modalTheme: 'CToolsModalDialog',
+ throbberTheme: 'CToolsModalThrobber',
+ animation: 'show',
+ animationSpeed: 'fast',
+ modalSize: {
+ type: 'scale',
+ width: .8,
+ height: .8,
+ addWidth: 0,
+ addHeight: 0,
+ // How much to remove from the inner content to make space for the
+ // theming.
+ contentRight: 25,
+ contentBottom: 45
+ },
+ modalOptions: {
+ opacity: .55,
+ background: '#fff'
+ },
+ modalClass: 'default'
+ };
+
+ var settings = {};
+ $.extend(true, settings, defaults, Drupal.settings.CToolsModal, opts);
+
+ if (Drupal.CTools.Modal.currentSettings && Drupal.CTools.Modal.currentSettings != settings) {
+ Drupal.CTools.Modal.modal.remove();
+ Drupal.CTools.Modal.modal = null;
+ }
+
+ Drupal.CTools.Modal.currentSettings = settings;
+
+ var resize = function(e) {
+ // When creating the modal, it actually exists only in a theoretical
+ // place that is not in the DOM. But once the modal exists, it is in the
+ // DOM so the context must be set appropriately.
+ var context = e ? document : Drupal.CTools.Modal.modal;
+
+ if (Drupal.CTools.Modal.currentSettings.modalSize.type == 'scale') {
+ var width = $(window).width() * Drupal.CTools.Modal.currentSettings.modalSize.width;
+ var height = $(window).height() * Drupal.CTools.Modal.currentSettings.modalSize.height;
+ }
+ else {
+ var width = Drupal.CTools.Modal.currentSettings.modalSize.width;
+ var height = Drupal.CTools.Modal.currentSettings.modalSize.height;
+ }
+
+ // Use the additionol pixels for creating the width and height.
+ $('div.ctools-modal-content', context).css({
+ 'width': width + Drupal.CTools.Modal.currentSettings.modalSize.addWidth + 'px',
+ 'height': height + Drupal.CTools.Modal.currentSettings.modalSize.addHeight + 'px'
+ });
+ $('div.ctools-modal-content .modal-content', context).css({
+ 'width': (width - Drupal.CTools.Modal.currentSettings.modalSize.contentRight) + 'px',
+ 'height': (height - Drupal.CTools.Modal.currentSettings.modalSize.contentBottom) + 'px'
+ });
+ }
+
+ if (!Drupal.CTools.Modal.modal) {
+ Drupal.CTools.Modal.modal = $(Drupal.theme(settings.modalTheme));
+ if (settings.modalSize.type == 'scale') {
+ $(window).bind('resize', resize);
+ }
+ }
+
+ resize();
+
+ $('span.modal-title', Drupal.CTools.Modal.modal).html(Drupal.CTools.Modal.currentSettings.loadingText);
+ Drupal.CTools.Modal.modalContent(Drupal.CTools.Modal.modal, settings.modalOptions, settings.animation, settings.animationSpeed, settings.modalClass);
+ $('#modalContent .modal-content').html(Drupal.theme(settings.throbberTheme)).addClass('ctools-modal-loading');
+
+ // Position autocomplete results based on the scroll position of the modal.
+ $('#modalContent .modal-content').delegate('input.form-autocomplete', 'keyup', function() {
+ $('#autocomplete').css('top', $(this).position().top + $(this).outerHeight() + $(this).offsetParent().filter('#modal-content').scrollTop());
+ });
+ };
+
+ /**
+ * Hide the modal
+ */
+ Drupal.CTools.Modal.dismiss = function() {
+ if (Drupal.CTools.Modal.modal) {
+ Drupal.CTools.Modal.unmodalContent(Drupal.CTools.Modal.modal);
+ }
+ };
+
+ /**
+ * Provide the HTML to create the modal dialog.
+ */
+ Drupal.theme.prototype.CToolsModalDialog = function () {
+ var html = ''
+ html += ' <div id="ctools-modal">'
+ html += ' <div class="ctools-modal-content">' // panels-modal-content
+ html += ' <div class="modal-header">';
+ html += ' <a class="close" href="#">';
+ html += Drupal.CTools.Modal.currentSettings.closeText + Drupal.CTools.Modal.currentSettings.closeImage;
+ html += ' </a>';
+ html += ' <span id="modal-title" class="modal-title">&nbsp;</span>';
+ html += ' </div>';
+ html += ' <div id="modal-content" class="modal-content">';
+ html += ' </div>';
+ html += ' </div>';
+ html += ' </div>';
+
+ return html;
+ }
+
+ /**
+ * Provide the HTML to create the throbber.
+ */
+ Drupal.theme.prototype.CToolsModalThrobber = function () {
+ var html = '';
+ html += ' <div id="modal-throbber">';
+ html += ' <div class="modal-throbber-wrapper">';
+ html += Drupal.CTools.Modal.currentSettings.throbber;
+ html += ' </div>';
+ html += ' </div>';
+
+ return html;
+ };
+
+ /**
+ * Figure out what settings string to use to display a modal.
+ */
+ Drupal.CTools.Modal.getSettings = function (object) {
+ var match = $(object).attr('class').match(/ctools-modal-(\S+)/);
+ if (match) {
+ return match[1];
+ }
+ }
+
+ /**
+ * Click function for modals that can be cached.
+ */
+ Drupal.CTools.Modal.clickAjaxCacheLink = function () {
+ Drupal.CTools.Modal.show(Drupal.CTools.Modal.getSettings(this));
+ return Drupal.CTools.AJAX.clickAJAXCacheLink.apply(this);
+ };
+
+ /**
+ * Handler to prepare the modal for the response
+ */
+ Drupal.CTools.Modal.clickAjaxLink = function () {
+ Drupal.CTools.Modal.show(Drupal.CTools.Modal.getSettings(this));
+ return false;
+ };
+
+ /**
+ * Submit responder to do an AJAX submit on all modal forms.
+ */
+ Drupal.CTools.Modal.submitAjaxForm = function(e) {
+ var $form = $(this);
+ var url = $form.attr('action');
+
+ setTimeout(function() { Drupal.CTools.AJAX.ajaxSubmit($form, url); }, 1);
+ return false;
+ }
+
+ /**
+ * Bind links that will open modals to the appropriate function.
+ */
+ Drupal.behaviors.ZZCToolsModal = {
+ attach: function(context) {
+ // Bind links
+ // Note that doing so in this order means that the two classes can be
+ // used together safely.
+ /*
+ * @todo remimplement the warm caching feature
+ $('a.ctools-use-modal-cache', context).once('ctools-use-modal', function() {
+ $(this).click(Drupal.CTools.Modal.clickAjaxCacheLink);
+ Drupal.CTools.AJAX.warmCache.apply(this);
+ });
+ */
+
+ $('area.ctools-use-modal, a.ctools-use-modal', context).once('ctools-use-modal', function() {
+ var $this = $(this);
+ $this.click(Drupal.CTools.Modal.clickAjaxLink);
+ // Create a drupal ajax object
+ var element_settings = {};
+ if ($this.attr('href')) {
+ element_settings.url = $this.attr('href');
+ element_settings.event = 'click';
+ element_settings.progress = { type: 'throbber' };
+ }
+ var base = $this.attr('href');
+ Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
+ });
+
+ // Bind buttons
+ $('input.ctools-use-modal, button.ctools-use-modal', context).once('ctools-use-modal', function() {
+ var $this = $(this);
+ $this.click(Drupal.CTools.Modal.clickAjaxLink);
+ var button = this;
+ var element_settings = {};
+
+ // AJAX submits specified in this manner automatically submit to the
+ // normal form action.
+ element_settings.url = Drupal.CTools.Modal.findURL(this);
+ if (element_settings.url == '') {
+ element_settings.url = $(this).closest('form').attr('action');
+ }
+ element_settings.event = 'click';
+ element_settings.setClick = true;
+
+ var base = $this.attr('id');
+ Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
+
+ // Make sure changes to settings are reflected in the URL.
+ $('.' + $(button).attr('id') + '-url').change(function() {
+ Drupal.ajax[base].options.url = Drupal.CTools.Modal.findURL(button);
+ });
+ });
+
+ // Bind our custom event to the form submit
+ $('#modal-content form', context).once('ctools-use-modal', function() {
+ var $this = $(this);
+ var element_settings = {};
+
+ element_settings.url = $this.attr('action');
+ element_settings.event = 'submit';
+ element_settings.progress = { 'type': 'throbber' }
+ var base = $this.attr('id');
+
+ Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
+ Drupal.ajax[base].form = $this;
+
+ $('input[type=submit], button', this).click(function(event) {
+ Drupal.ajax[base].element = this;
+ this.form.clk = this;
+ // Stop autocomplete from submitting.
+ if (Drupal.autocompleteSubmit && !Drupal.autocompleteSubmit()) {
+ return false;
+ }
+ // An empty event means we were triggered via .click() and
+ // in jquery 1.4 this won't trigger a submit.
+ if (event.bubbles == undefined) {
+ $(this.form).trigger('submit');
+ return false;
+ }
+ });
+ });
+
+ // Bind a click handler to allow elements with the 'ctools-close-modal'
+ // class to close the modal.
+ $('.ctools-close-modal', context).once('ctools-close-modal')
+ .click(function() {
+ Drupal.CTools.Modal.dismiss();
+ return false;
+ });
+ }
+ };
+
+ // The following are implementations of AJAX responder commands.
+
+ /**
+ * AJAX responder command to place HTML within the modal.
+ */
+ Drupal.CTools.Modal.modal_display = function(ajax, response, status) {
+ if ($('#modalContent').length == 0) {
+ Drupal.CTools.Modal.show(Drupal.CTools.Modal.getSettings(ajax.element));
+ }
+ $('#modal-title').html(response.title);
+ // Simulate an actual page load by scrolling to the top after adding the
+ // content. This is helpful for allowing users to see error messages at the
+ // top of a form, etc.
+ $('#modal-content').html(response.output).scrollTop(0);
+
+ // Attach behaviors within a modal dialog.
+ var settings = response.settings || ajax.settings || Drupal.settings;
+ Drupal.attachBehaviors('#modalContent', settings);
+
+ if ($('#modal-content').hasClass('ctools-modal-loading')) {
+ $('#modal-content').removeClass('ctools-modal-loading');
+ }
+ else {
+ // If the modal was already shown, and we are simply replacing its
+ // content, then focus on the first focusable element in the modal.
+ // (When first showing the modal, focus will be placed on the close
+ // button by the show() function called above.)
+ $('#modal-content :focusable:first').focus();
+ }
+ }
+
+ /**
+ * AJAX responder command to dismiss the modal.
+ */
+ Drupal.CTools.Modal.modal_dismiss = function(command) {
+ Drupal.CTools.Modal.dismiss();
+ $('link.ctools-temporary-css').remove();
+ }
+
+ /**
+ * Display loading
+ */
+ //Drupal.CTools.AJAX.commands.modal_loading = function(command) {
+ Drupal.CTools.Modal.modal_loading = function(command) {
+ Drupal.CTools.Modal.modal_display({
+ output: Drupal.theme(Drupal.CTools.Modal.currentSettings.throbberTheme),
+ title: Drupal.CTools.Modal.currentSettings.loadingText
+ });
+ }
+
+ /**
+ * Find a URL for an AJAX button.
+ *
+ * The URL for this gadget will be composed of the values of items by
+ * taking the ID of this item and adding -url and looking for that
+ * class. They need to be in the form in order since we will
+ * concat them all together using '/'.
+ */
+ Drupal.CTools.Modal.findURL = function(item) {
+ var url = '';
+ var url_class = '.' + $(item).attr('id') + '-url';
+ $(url_class).each(
+ function() {
+ var $this = $(this);
+ if (url && $this.val()) {
+ url += '/';
+ }
+ url += $this.val();
+ });
+ return url;
+ };
+
+
+ /**
+ * modalContent
+ * @param content string to display in the content box
+ * @param css obj of css attributes
+ * @param animation (fadeIn, slideDown, show)
+ * @param speed (valid animation speeds slow, medium, fast or # in ms)
+ * @param modalClass class added to div#modalContent
+ */
+ Drupal.CTools.Modal.modalContent = function(content, css, animation, speed, modalClass) {
+ // If our animation isn't set, make it just show/pop
+ if (!animation) {
+ animation = 'show';
+ }
+ else {
+ // If our animation isn't "fadeIn" or "slideDown" then it always is show
+ if (animation != 'fadeIn' && animation != 'slideDown') {
+ animation = 'show';
+ }
+ }
+
+ if (!speed) {
+ speed = 'fast';
+ }
+
+ // Build our base attributes and allow them to be overriden
+ css = jQuery.extend({
+ position: 'absolute',
+ left: '0px',
+ margin: '0px',
+ background: '#000',
+ opacity: '.55'
+ }, css);
+
+ // Add opacity handling for IE.
+ css.filter = 'alpha(opacity=' + (100 * css.opacity) + ')';
+ content.hide();
+
+ // If we already have modalContent, remove it.
+ if ($('#modalBackdrop').length) $('#modalBackdrop').remove();
+ if ($('#modalContent').length) $('#modalContent').remove();
+
+ // position code lifted from http://www.quirksmode.org/viewport/compatibility.html
+ if (self.pageYOffset) { // all except Explorer
+ var wt = self.pageYOffset;
+ } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
+ var wt = document.documentElement.scrollTop;
+ } else if (document.body) { // all other Explorers
+ var wt = document.body.scrollTop;
+ }
+
+ // Get our dimensions
+
+ // Get the docHeight and (ugly hack) add 50 pixels to make sure we dont have a *visible* border below our div
+ var docHeight = $(document).height() + 50;
+ var docWidth = $(document).width();
+ var winHeight = $(window).height();
+ var winWidth = $(window).width();
+ if( docHeight < winHeight ) docHeight = winHeight;
+
+ // Create our divs
+ $('body').append('<div id="modalBackdrop" class="backdrop-' + modalClass + '" style="z-index: 1000; display: none;"></div><div id="modalContent" class="modal-' + modalClass + '" style="z-index: 1001; position: absolute;">' + $(content).html() + '</div>');
+
+ // Get a list of the tabbable elements in the modal content.
+ var getTabbableElements = function () {
+ var tabbableElements = $('#modalContent :tabbable'),
+ radioButtons = tabbableElements.filter('input[type="radio"]');
+
+ // The list of tabbable elements from jQuery is *almost* right. The
+ // exception is with groups of radio buttons. The list from jQuery will
+ // include all radio buttons, when in fact, only the selected radio button
+ // is tabbable, and if no radio buttons in a group are selected, then only
+ // the first is tabbable.
+ if (radioButtons.length > 0) {
+ // First, build up an index of which groups have an item selected or not.
+ var anySelected = {};
+ radioButtons.each(function () {
+ var name = this.name;
+
+ if (typeof anySelected[name] === 'undefined') {
+ anySelected[name] = radioButtons.filter('input[name="' + name + '"]:checked').length !== 0;
+ }
+ });
+
+ // Next filter out the radio buttons that aren't really tabbable.
+ var found = {};
+ tabbableElements = tabbableElements.filter(function () {
+ var keep = true;
+
+ if (this.type == 'radio') {
+ if (anySelected[this.name]) {
+ // Only keep the selected one.
+ keep = this.checked;
+ }
+ else {
+ // Only keep the first one.
+ if (found[this.name]) {
+ keep = false;
+ }
+ found[this.name] = true;
+ }
+ }
+
+ return keep;
+ });
+ }
+
+ return tabbableElements.get();
+ };
+
+ // Keyboard and focus event handler ensures only modal elements gain focus.
+ modalEventHandler = function( event ) {
+ target = null;
+ if ( event ) { //Mozilla
+ target = event.target;
+ } else { //IE
+ event = window.event;
+ target = event.srcElement;
+ }
+
+ var parents = $(target).parents().get();
+ for (var i = 0; i < parents.length; ++i) {
+ var position = $(parents[i]).css('position');
+ if (position == 'absolute' || position == 'fixed') {
+ return true;
+ }
+ }
+
+ if ($(target).is('#modalContent, body') || $(target).filter('*:visible').parents('#modalContent').length) {
+ // Allow the event only if target is a visible child node
+ // of #modalContent.
+ return true;
+ }
+ else {
+ getTabbableElements()[0].focus();
+ }
+
+ event.preventDefault();
+ };
+ $('body').bind( 'focus', modalEventHandler );
+ $('body').bind( 'keypress', modalEventHandler );
+
+ // Keypress handler Ensures you can only TAB to elements within the modal.
+ // Based on the psuedo-code from WAI-ARIA 1.0 Authoring Practices section
+ // 3.3.1 "Trapping Focus".
+ modalTabTrapHandler = function (evt) {
+ // We only care about the TAB key.
+ if (evt.which != 9) {
+ return true;
+ }
+
+ var tabbableElements = getTabbableElements(),
+ firstTabbableElement = tabbableElements[0],
+ lastTabbableElement = tabbableElements[tabbableElements.length - 1],
+ singleTabbableElement = firstTabbableElement == lastTabbableElement,
+ node = evt.target;
+
+ // If this is the first element and the user wants to go backwards, then
+ // jump to the last element.
+ if (node == firstTabbableElement && evt.shiftKey) {
+ if (!singleTabbableElement) {
+ lastTabbableElement.focus();
+ }
+ return false;
+ }
+ // If this is the last element and the user wants to go forwards, then
+ // jump to the first element.
+ else if (node == lastTabbableElement && !evt.shiftKey) {
+ if (!singleTabbableElement) {
+ firstTabbableElement.focus();
+ }
+ return false;
+ }
+ // If this element isn't in the dialog at all, then jump to the first
+ // or last element to get the user into the game.
+ else if ($.inArray(node, tabbableElements) == -1) {
+ // Make sure the node isn't in another modal (ie. WYSIWYG modal).
+ var parents = $(node).parents().get();
+ for (var i = 0; i < parents.length; ++i) {
+ var position = $(parents[i]).css('position');
+ if (position == 'absolute' || position == 'fixed') {
+ return true;
+ }
+ }
+
+ if (evt.shiftKey) {
+ lastTabbableElement.focus();
+ }
+ else {
+ firstTabbableElement.focus();
+ }
+ }
+ };
+ $('body').bind('keydown', modalTabTrapHandler);
+
+ // Create our content div, get the dimensions, and hide it
+ var modalContent = $('#modalContent').css('top','-1000px');
+ var mdcTop = wt + ( winHeight / 2 ) - ( modalContent.outerHeight() / 2);
+ var mdcLeft = ( winWidth / 2 ) - ( modalContent.outerWidth() / 2);
+ $('#modalBackdrop').css(css).css('top', 0).css('height', docHeight + 'px').css('width', docWidth + 'px').show();
+ modalContent.css({top: mdcTop + 'px', left: mdcLeft + 'px'}).hide()[animation](speed);
+
+ // Bind a click for closing the modalContent
+ modalContentClose = function(){close(); return false;};
+ $('.close').bind('click', modalContentClose);
+
+ // Bind a keypress on escape for closing the modalContent
+ modalEventEscapeCloseHandler = function(event) {
+ if (event.keyCode == 27) {
+ close();
+ return false;
+ }
+ };
+
+ $(document).bind('keydown', modalEventEscapeCloseHandler);
+
+ // Per WAI-ARIA 1.0 Authoring Practices, initial focus should be on the
+ // close button, but we should save the original focus to restore it after
+ // the dialog is closed.
+ var oldFocus = document.activeElement;
+ $('.close').focus();
+
+ // Close the open modal content and backdrop
+ function close() {
+ // Unbind the events
+ $(window).unbind('resize', modalContentResize);
+ $('body').unbind( 'focus', modalEventHandler);
+ $('body').unbind( 'keypress', modalEventHandler );
+ $('body').unbind( 'keydown', modalTabTrapHandler );
+ $('.close').unbind('click', modalContentClose);
+ $('body').unbind('keypress', modalEventEscapeCloseHandler);
+ $(document).trigger('CToolsDetachBehaviors', $('#modalContent'));
+
+ // Set our animation parameters and use them
+ if ( animation == 'fadeIn' ) animation = 'fadeOut';
+ if ( animation == 'slideDown' ) animation = 'slideUp';
+ if ( animation == 'show' ) animation = 'hide';
+
+ // Close the content
+ modalContent.hide()[animation](speed);
+
+ // Remove the content
+ $('#modalContent').remove();
+ $('#modalBackdrop').remove();
+
+ // Restore focus to where it was before opening the dialog
+ $(oldFocus).focus();
+ };
+
+ // Move and resize the modalBackdrop and modalContent on window resize.
+ modalContentResize = function(){
+
+ // Reset the backdrop height/width to get accurate document size.
+ $('#modalBackdrop').css('height', '').css('width', '');
+
+ // Position code lifted from:
+ // http://www.quirksmode.org/viewport/compatibility.html
+ if (self.pageYOffset) { // all except Explorer
+ var wt = self.pageYOffset;
+ } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
+ var wt = document.documentElement.scrollTop;
+ } else if (document.body) { // all other Explorers
+ var wt = document.body.scrollTop;
+ }
+
+ // Get our heights
+ var docHeight = $(document).height();
+ var docWidth = $(document).width();
+ var winHeight = $(window).height();
+ var winWidth = $(window).width();
+ if( docHeight < winHeight ) docHeight = winHeight;
+
+ // Get where we should move content to
+ var modalContent = $('#modalContent');
+ var mdcTop = wt + ( winHeight / 2 ) - ( modalContent.outerHeight() / 2);
+ var mdcLeft = ( winWidth / 2 ) - ( modalContent.outerWidth() / 2);
+
+ // Apply the changes
+ $('#modalBackdrop').css('height', docHeight + 'px').css('width', docWidth + 'px').show();
+ modalContent.css('top', mdcTop + 'px').css('left', mdcLeft + 'px').show();
+ };
+ $(window).bind('resize', modalContentResize);
+ };
+
+ /**
+ * unmodalContent
+ * @param content (The jQuery object to remove)
+ * @param animation (fadeOut, slideUp, show)
+ * @param speed (valid animation speeds slow, medium, fast or # in ms)
+ */
+ Drupal.CTools.Modal.unmodalContent = function(content, animation, speed)
+ {
+ // If our animation isn't set, make it just show/pop
+ if (!animation) { var animation = 'show'; } else {
+ // If our animation isn't "fade" then it always is show
+ if (( animation != 'fadeOut' ) && ( animation != 'slideUp')) animation = 'show';
+ }
+ // Set a speed if we dont have one
+ if ( !speed ) var speed = 'fast';
+
+ // Unbind the events we bound
+ $(window).unbind('resize', modalContentResize);
+ $('body').unbind('focus', modalEventHandler);
+ $('body').unbind('keypress', modalEventHandler);
+ $('body').unbind( 'keydown', modalTabTrapHandler );
+ $('.close').unbind('click', modalContentClose);
+ $('body').unbind('keypress', modalEventEscapeCloseHandler);
+ $(document).trigger('CToolsDetachBehaviors', $('#modalContent'));
+
+ // jQuery magic loop through the instances and run the animations or removal.
+ content.each(function(){
+ if ( animation == 'fade' ) {
+ $('#modalContent').fadeOut(speed, function() {
+ $('#modalBackdrop').fadeOut(speed, function() {
+ $(this).remove();
+ });
+ $(this).remove();
+ });
+ } else {
+ if ( animation == 'slide' ) {
+ $('#modalContent').slideUp(speed,function() {
+ $('#modalBackdrop').slideUp(speed, function() {
+ $(this).remove();
+ });
+ $(this).remove();
+ });
+ } else {
+ $('#modalContent').remove();
+ $('#modalBackdrop').remove();
+ }
+ }
+ });
+ };
+
+$(function() {
+ Drupal.ajax.prototype.commands.modal_display = Drupal.CTools.Modal.modal_display;
+ Drupal.ajax.prototype.commands.modal_dismiss = Drupal.CTools.Modal.modal_dismiss;
+});
+
+})(jQuery);
diff --git a/sites/all/modules/ctools/js/states-show.js b/sites/all/modules/ctools/js/states-show.js
new file mode 100644
index 000000000..88df58419
--- /dev/null
+++ b/sites/all/modules/ctools/js/states-show.js
@@ -0,0 +1,43 @@
+/**
+ * @file
+ * Custom state for handling visibility
+ */
+
+/**
+ * Add a new state to Drupal #states. We use this to toggle element-invisible
+ * to show/hidden #states elements. This allows elements to be visible to
+ * screen readers.
+ *
+ * To use:
+ * $form['my_form_field'] = array(
+ * ..
+ * // Only show this field if 'some_other_field' is checked.
+ * '#states => array(
+ * 'show' => array(
+ * 'some-other-field' => array('checked' => TRUE),
+ * ),
+ * ),
+ * ..
+ * // Required to load the 'show' state handler.
+ * '#attached' => array(
+ * 'js' => array(ctools_attach_js('states-show')),
+ * ),
+ * );
+ */
+
+(function ($) {
+ 'use strict';
+
+ Drupal.states.State.aliases.hidden = '!show';
+
+ // Show/hide form items by toggling the 'element-invisible' class. This is a
+ // more accessible option than the core 'visible' state.
+ $(document).bind('state:show', function(e) {
+ if (e.trigger) {
+ var element = $(e.target).closest('.form-item, .form-submit, .form-wrapper');
+ element.toggle(e.value);
+ e.value === true ? element.removeClass('element-invisible') : element.addClass('element-invisible');
+ }
+ });
+
+})(jQuery);
diff --git a/sites/all/modules/ctools/js/stylizer.js b/sites/all/modules/ctools/js/stylizer.js
new file mode 100644
index 000000000..16d6c49d5
--- /dev/null
+++ b/sites/all/modules/ctools/js/stylizer.js
@@ -0,0 +1,220 @@
+
+(function ($) {
+ Drupal.CTools = Drupal.CTools || {};
+ Drupal.CTools.Stylizer = {};
+
+ Drupal.CTools.Stylizer.addFarbtastic = function(context) {
+ // This behavior attaches by ID, so is only valid once on a page.
+ if ($('ctools_stylizer_color_scheme_form .color-form.Stylizer-processed').size()) {
+ return;
+ }
+
+ var form = $('.color-form', context);
+ var inputs = [];
+ var hooks = [];
+ var locks = [];
+ var focused = null;
+
+ // Add Farbtastic
+ $(form).prepend('<div id="placeholder"></div>').addClass('color-processed');
+ var farb = $.farbtastic('#placeholder');
+
+ // Decode reference colors to HSL
+ /*var reference = Drupal.settings.Stylizer.reference.clone();
+ for (i in reference) {
+ reference[i] = farb.RGBToHSL(farb.unpack(reference[i]));
+ } */
+
+ // Set up colorscheme selector
+ $('#edit-scheme', form).change(function () {
+ var colors = this.options[this.selectedIndex].value;
+ if (colors != '') {
+ colors = colors.split(',');
+ for (i in colors) {
+ callback(inputs[i], colors[i], false, true);
+ }
+ }
+ });
+
+ /**
+ * Shift a given color, using a reference pair (ref in HSL).
+ *
+ * This algorithm ensures relative ordering on the saturation and luminance
+ * axes is preserved, and performs a simple hue shift.
+ *
+ * It is also symmetrical. If: shift_color(c, a, b) == d,
+ * then shift_color(d, b, a) == c.
+ */
+ function shift_color(given, ref1, ref2) {
+ // Convert to HSL
+ given = farb.RGBToHSL(farb.unpack(given));
+
+ // Hue: apply delta
+ given[0] += ref2[0] - ref1[0];
+
+ // Saturation: interpolate
+ if (ref1[1] == 0 || ref2[1] == 0) {
+ given[1] = ref2[1];
+ }
+ else {
+ var d = ref1[1] / ref2[1];
+ if (d > 1) {
+ given[1] /= d;
+ }
+ else {
+ given[1] = 1 - (1 - given[1]) * d;
+ }
+ }
+
+ // Luminance: interpolate
+ if (ref1[2] == 0 || ref2[2] == 0) {
+ given[2] = ref2[2];
+ }
+ else {
+ var d = ref1[2] / ref2[2];
+ if (d > 1) {
+ given[2] /= d;
+ }
+ else {
+ given[2] = 1 - (1 - given[2]) * d;
+ }
+ }
+
+ return farb.pack(farb.HSLToRGB(given));
+ }
+
+ /**
+ * Callback for Farbtastic when a new color is chosen.
+ */
+ function callback(input, color, propagate, colorscheme) {
+ // Set background/foreground color
+ $(input).css({
+ backgroundColor: color,
+ 'color': farb.RGBToHSL(farb.unpack(color))[2] > 0.5 ? '#000' : '#fff'
+ });
+
+ // Change input value
+ if (input.value && input.value != color) {
+ input.value = color;
+
+ // Update locked values
+ if (propagate) {
+ var i = input.i;
+ for (j = i + 1; ; ++j) {
+ if (!locks[j - 1] || $(locks[j - 1]).is('.unlocked')) break;
+ var matched = shift_color(color, reference[input.key], reference[inputs[j].key]);
+ callback(inputs[j], matched, false);
+ }
+ for (j = i - 1; ; --j) {
+ if (!locks[j] || $(locks[j]).is('.unlocked')) break;
+ var matched = shift_color(color, reference[input.key], reference[inputs[j].key]);
+ callback(inputs[j], matched, false);
+ }
+
+ }
+
+ // Reset colorscheme selector
+ if (!colorscheme) {
+ resetScheme();
+ }
+ }
+
+ }
+
+ /**
+ * Reset the color scheme selector.
+ */
+ function resetScheme() {
+ $('#edit-scheme', form).each(function () {
+ this.selectedIndex = this.options.length - 1;
+ });
+ }
+
+ // Focus the Farbtastic on a particular field.
+ function focus() {
+ var input = this;
+ // Remove old bindings
+ focused && $(focused).unbind('keyup', farb.updateValue)
+ .unbind('keyup', resetScheme)
+ .parent().removeClass('item-selected');
+
+ // Add new bindings
+ focused = this;
+ farb.linkTo(function (color) { callback(input, color, true, false); });
+ farb.setColor(this.value);
+ $(focused).keyup(farb.updateValue).keyup(resetScheme)
+ .parent().addClass('item-selected');
+ }
+
+ // Initialize color fields
+ $('#palette input.form-text', form)
+ .each(function () {
+ // Extract palette field name
+ this.key = this.id.substring(13);
+
+ // Link to color picker temporarily to initialize.
+ farb.linkTo(function () {}).setColor('#000').linkTo(this);
+
+ // Add lock
+ var i = inputs.length;
+ if (inputs.length) {
+ var lock = $('<div class="lock"></div>').toggle(
+ function () {
+ $(this).addClass('unlocked');
+ $(hooks[i - 1]).attr('class',
+ locks[i - 2] && $(locks[i - 2]).is(':not(.unlocked)') ? 'hook up' : 'hook'
+ );
+ $(hooks[i]).attr('class',
+ locks[i] && $(locks[i]).is(':not(.unlocked)') ? 'hook down' : 'hook'
+ );
+ },
+ function () {
+ $(this).removeClass('unlocked');
+ $(hooks[i - 1]).attr('class',
+ locks[i - 2] && $(locks[i - 2]).is(':not(.unlocked)') ? 'hook both' : 'hook down'
+ );
+ $(hooks[i]).attr('class',
+ locks[i] && $(locks[i]).is(':not(.unlocked)') ? 'hook both' : 'hook up'
+ );
+ }
+ );
+ $(this).after(lock);
+ locks.push(lock);
+ };
+
+ // Add hook
+ var $this = $(this);
+ var hook = $('<div class="hook"></div>');
+ $this.after(hook);
+ hooks.push(hook);
+
+ $this.parent().find('.lock').click();
+ this.i = i;
+ inputs.push(this);
+ })
+ .focus(focus);
+
+ $('#palette label', form);
+
+ // Focus first color
+ focus.call(inputs[0]);
+ };
+
+ Drupal.behaviors.CToolsColorSettings = {
+ attach: function() {
+ $('.ctools-stylizer-color-edit:not(.ctools-color-processed)')
+ .addClass('ctools-color-processed')
+ .each(function() {
+ Drupal.CTools.Stylizer.addFarbtastic('#' + $(this).attr('id'));
+ });
+
+ $('div.form-item div.ctools-style-icon:not(.ctools-color-processed)')
+ .addClass('ctools-color-processed')
+ .click(function() {
+ $widget = $('input', $(this).parent());
+ // Toggle if a checkbox, turn on if a radio.
+ $widget.attr('checked', !$widget.attr('checked') || $widget.is('input[type=radio]'));
+ });
+ }
+ }
+})(jQuery);