diff sites/all/modules/features/features.js @ 4:ce11bbd8f642

added modules
author danieleb <danielebarchiesi@me.com>
date Thu, 19 Sep 2013 10:38:44 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/features.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,437 @@
+/**
+ * jQuery.fn.sortElements
+ * --------------
+ * @param Function comparator:
+ *   Exactly the same behaviour as [1,2,3].sort(comparator)
+ *
+ * @param Function getSortable
+ *   A function that should return the element that is
+ *   to be sorted. The comparator will run on the
+ *   current collection, but you may want the actual
+ *   resulting sort to occur on a parent or another
+ *   associated element.
+ *
+ *   E.g. $('td').sortElements(comparator, function(){
+ *      return this.parentNode;
+ *   })
+ *
+ *   The <td>'s parent (<tr>) will be sorted instead
+ *   of the <td> itself.
+ *
+ * Credit: http://james.padolsey.com/javascript/sorting-elements-with-jquery/
+ *
+ */
+jQuery.fn.sortElements = (function(){
+
+    var sort = [].sort;
+
+    return function(comparator, getSortable) {
+
+        getSortable = getSortable || function(){return this;};
+
+        var placements = this.map(function(){
+
+            var sortElement = getSortable.call(this),
+                parentNode = sortElement.parentNode,
+
+                // Since the element itself will change position, we have
+                // to have some way of storing its original position in
+                // the DOM. The easiest way is to have a 'flag' node:
+                nextSibling = parentNode.insertBefore(
+                    document.createTextNode(''),
+                    sortElement.nextSibling
+                );
+
+            return function() {
+
+                if (parentNode === this) {
+                    throw new Error(
+                        "You can't sort elements if any one is a descendant of another."
+                    );
+                }
+
+                // Insert before flag:
+                parentNode.insertBefore(this, nextSibling);
+                // Remove flag:
+                parentNode.removeChild(nextSibling);
+
+            };
+
+        });
+
+        return sort.call(this, comparator).each(function(i){
+            placements[i].call(getSortable.call(this));
+        });
+
+    };
+
+})();
+
+(function ($) {
+  Drupal.behaviors.features = {
+    attach: function(context, settings) {
+      // Features management form
+      $('table.features:not(.processed)', context).each(function() {
+        $(this).addClass('processed');
+
+        // Check the overridden status of each feature
+        Drupal.features.checkStatus();
+
+        // Add some nicer row hilighting when checkboxes change values
+        $('input', this).bind('change', function() {
+          if (!$(this).attr('checked')) {
+            $(this).parents('tr').removeClass('enabled').addClass('disabled');
+          }
+          else {
+            $(this).parents('tr').addClass('enabled').removeClass('disabled');
+          }
+        });
+      });
+
+      // Export form component selector
+      $('form.features-export-form select.features-select-components:not(.processed)', context).each(function() {
+        $(this)
+          .addClass('processed')
+          .change(function() {
+            var target = $(this).val();
+            $('div.features-select').hide();
+            $('div.features-select-' + target).show();
+            return false;
+        }).trigger('change');
+      });
+
+      // Export form machine-readable JS
+      $('.feature-name:not(.processed)', context).each(function() {
+        $('.feature-name')
+          .addClass('processed')
+          .after(' <small class="feature-module-name-suffix">&nbsp;</small>');
+        if ($('.feature-module-name').val() === $('.feature-name').val().toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/_+/g, '_') || $('.feature-module-name').val() === '') {
+          $('.feature-module-name').parents('.form-item').hide();
+          $('.feature-name').bind('keyup change', function() {
+            var machine = $(this).val().toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/_+/g, '_');
+            if (machine !== '_' && machine !== '') {
+              $('.feature-module-name').val(machine);
+              $('.feature-module-name-suffix').empty().append(' Machine name: ' + machine + ' [').append($('<a href="#">'+ Drupal.t('Edit') +'</a>').click(function() {
+                $('.feature-module-name').parents('.form-item').show();
+                $('.feature-module-name-suffix').hide();
+                $('.feature-name').unbind('keyup');
+                return false;
+              })).append(']');
+            }
+            else {
+              $('.feature-module-name').val(machine);
+              $('.feature-module-name-suffix').text('');
+            }
+          });
+          $('.feature-name').keyup();
+        }
+      });
+
+      //View info dialog
+      var infoDialog = $('#features-info-file');
+      if (infoDialog.length != 0) {
+        infoDialog.dialog({
+          autoOpen: false,
+          modal: true,
+          draggable: false,
+          resizable: false,
+          width: 600,
+          height: 480
+        });
+      }
+
+      if ((Drupal.settings.features != undefined) && (Drupal.settings.features.info != undefined)) {
+        $('#features-info-file textarea').val(Drupal.settings.features.info);
+        $('#features-info-file').dialog('open');
+        //To be reset by the button click ajax
+        Drupal.settings.features.info = undefined;
+      }
+
+      // mark any conflicts with a class
+      if ((Drupal.settings.features != undefined) && (Drupal.settings.features.conflicts != undefined)) {
+        for (var moduleName in Drupal.settings.features.conflicts) {
+          moduleConflicts = Drupal.settings.features.conflicts[moduleName];
+          $('#features-export-wrapper input[type=checkbox]', context).each(function() {
+            if (!$(this).hasClass('features-checkall')) {
+              var key = $(this).attr('name');
+              var matches = key.match(/^([^\[]+)(\[.+\])?\[(.+)\]\[(.+)\]$/);
+              var component = matches[1];
+              var item = matches[4];
+              if ((component in moduleConflicts) && (moduleConflicts[component].indexOf(item) != -1)) {
+                $(this).parent().addClass('features-conflict');
+              }
+            }
+          });
+        }
+      }
+
+      function _checkAll(value) {
+        if (value) {
+          $('#features-export-wrapper .component-select input[type=checkbox]:visible', context).each(function() {
+            var move_id = $(this).attr('id');
+            $(this).click();
+            $('#'+ move_id).attr('checked', 'checked');
+        });
+        }
+        else {
+          $('#features-export-wrapper .component-added input[type=checkbox]:visible', context).each(function() {
+            var move_id = $(this).attr('id');
+            $('#'+ move_id).removeAttr('checked');
+            $(this).click();
+            $('#'+ move_id).removeAttr('checked');
+          });
+        }
+      }
+
+      function moveCheckbox(item, section, value) {
+        var curParent = item;
+        if ($(item).hasClass('form-type-checkbox')) {
+          item = $(item).children('input[type=checkbox]');
+        }
+        else {
+          curParent = $(item).parents('.form-type-checkbox');
+        }
+        var newParent = $(curParent).parents('.features-export-parent').find('.form-checkboxes.component-'+section);
+        $(curParent).detach();
+        $(curParent).appendTo(newParent);
+        var list = ['select', 'added', 'detected', 'included'];
+        for (i in list) {
+          $(curParent).removeClass('component-' + list[i]);
+          $(item).removeClass('component-' + list[i]);
+        }
+        $(curParent).addClass('component-'+section);
+        $(item).addClass('component-'+section);
+        if (value) {
+          $(item).attr('checked', 'checked');
+        }
+        else {
+          $(item).removeAttr('checked')
+        }
+        $(newParent).parent().removeClass('features-export-empty');
+
+        // re-sort new list of checkboxes based on labels
+        $(newParent).find('label').sortElements(
+          function(a, b){
+            return $(a).text() > $(b).text() ? 1 : -1;
+          },
+          function(){
+            return this.parentNode;
+          }
+        );
+      }
+
+      // provide timer for auto-refresh trigger
+      var timeoutID = 0;
+      var inTimeout = 0;
+      function _triggerTimeout() {
+        timeoutID = 0;
+        _updateDetected();
+      }
+      function _resetTimeout() {
+        inTimeout++;
+        // if timeout is already active, reset it
+        if (timeoutID != 0) {
+          window.clearTimeout(timeoutID);
+          if (inTimeout > 0) inTimeout--;
+        }
+        timeoutID = window.setTimeout(_triggerTimeout, 500);
+      }
+
+      function _updateDetected() {
+        var autodetect = $('#features-autodetect input[type=checkbox]');
+        if ((autodetect.length > 0) && (!autodetect.is(':checked'))) return;
+        // query the server for a list of components/items in the feature and update
+        // the auto-detected items
+        var items = [];  // will contain a list of selected items exported to feature
+        var components = {};  // contains object of component names that have checked items
+        $('#features-export-wrapper input[type=checkbox]:checked', context).each(function() {
+          if (!$(this).hasClass('features-checkall')) {
+            var key = $(this).attr('name');
+            var matches = key.match(/^([^\[]+)(\[.+\])?\[(.+)\]\[(.+)\]$/);
+            components[matches[1]] = matches[1];
+            if (!$(this).hasClass('component-detected')) {
+              items.push(key);
+            }
+          }
+        });
+        var featureName = $('#edit-module-name').val();
+        if (featureName == '') {
+          featureName = '*';
+        }
+        var url = Drupal.settings.basePath + 'features/ajaxcallback/' + featureName;
+        var excluded = Drupal.settings.features.excluded;
+        var postData = {'items': items, 'excluded': excluded};
+        jQuery.post(url, postData, function(data) {
+          if (inTimeout > 0) inTimeout--;
+          // if we have triggered another timeout then don't update with old results
+          if (inTimeout == 0) {
+            // data is an object keyed by component listing the exports of the feature
+            for (var component in data) {
+              var itemList = data[component];
+              $('#features-export-wrapper .component-' + component + ' input[type=checkbox]', context).each(function() {
+                var key = $(this).attr('value');
+                // first remove any auto-detected items that are no longer in component
+                if ($(this).hasClass('component-detected')) {
+                  if (!(key in itemList)) {
+                    moveCheckbox(this, 'select', false)
+                  }
+                }
+                // next, add any new auto-detected items
+                else if ($(this).hasClass('component-select')) {
+                  if (key in itemList) {
+                    moveCheckbox(this, 'detected', itemList[key]);
+                    $(this).parent().show(); // make sure it's not hidden from filter
+                  }
+                }
+              });
+            }
+            // loop over all selected components and check for any that have been completely removed
+            for (var component in components) {
+              if ((data == null) || !(component in data)) {
+                $('#features-export-wrapper .component-' + component + ' input[type=checkbox].component-detected', context).each(function() {
+                  moveCheckbox(this, 'select', false);
+                });
+              }
+            }
+          }
+        }, "json");
+      }
+
+      // Handle component selection UI
+      $('#features-export-wrapper input[type=checkbox]', context).click(function() {
+        _resetTimeout();
+        if ($(this).hasClass('component-select')) {
+          moveCheckbox(this, 'added', true);
+        }
+        else if ($(this).hasClass('component-included')) {
+          moveCheckbox(this, 'added', false);
+        }
+        else if ($(this).hasClass('component-added')) {
+          if ($(this).is(':checked')) {
+            moveCheckbox(this, 'included', true);
+          }
+          else {
+            moveCheckbox(this, 'select', false);
+          }
+        }
+      });
+
+      // Handle select/unselect all
+      $('#features-filter .features-checkall', context).click(function() {
+        if ($(this).attr('checked')) {
+          _checkAll(true);
+          $(this).next().html(Drupal.t('Deselect all'));
+        }
+        else {
+          _checkAll(false);
+          $(this).next().html(Drupal.t('Select all'));
+        }
+        _resetTimeout();
+      });
+
+      // Handle filtering
+
+      // provide timer for auto-refresh trigger
+      var filterTimeoutID = 0;
+      var inFilterTimeout = 0;
+      function _triggerFilterTimeout() {
+        filterTimeoutID = 0;
+        _updateFilter();
+      }
+      function _resetFilterTimeout() {
+        inFilterTimeout++;
+        // if timeout is already active, reset it
+        if (filterTimeoutID != 0) {
+          window.clearTimeout(filterTimeoutID);
+          if (inFilterTimeout > 0) inFilterTimeout--;
+        }
+        filterTimeoutID = window.setTimeout(_triggerFilterTimeout, 200);
+      }
+      function _updateFilter() {
+        var filter = $('#features-filter input').val();
+        var regex = new RegExp(filter, 'i');
+        // collapse fieldsets
+        var newState = {};
+        var currentState = {};
+        $('#features-export-wrapper fieldset.features-export-component', context).each(function() {
+          // expand parent fieldset
+          var section = $(this).attr('id');
+          currentState[section] = !($(this).hasClass('collapsed'));
+          if (!(section in newState)) {
+            newState[section] = false;
+          }
+
+          $(this).find('div.component-select label').each(function() {
+            if (filter == '') {
+              if (currentState[section]) {
+                Drupal.toggleFieldset($('#'+section));
+                currentState[section] = false;
+              }
+              $(this).parent().show();
+            }
+            else if ($(this).text().match(regex)) {
+              $(this).parent().show();
+              newState[section] = true;
+            }
+            else {
+              $(this).parent().hide();
+            }
+          });
+        });
+        for (section in newState) {
+          if (currentState[section] != newState[section]) {
+            Drupal.toggleFieldset($('#'+section));
+          }
+        }
+      }
+      $('#features-filter input', context).bind("input", function() {
+        _resetFilterTimeout();
+      });
+      $('#features-filter .features-filter-clear', context).click(function() {
+        $('#features-filter input').val('');
+        _updateFilter();
+      });
+
+      // show the filter bar
+      $('#features-filter', context).removeClass('element-invisible');
+    }
+  }
+
+
+  Drupal.features = {
+    'checkStatus': function() {
+      $('table.features tbody tr').not('.processed').filter(':first').each(function() {
+        var elem = $(this);
+        $(elem).addClass('processed');
+        var uri = $(this).find('a.admin-check').attr('href');
+        if (uri) {
+          $.get(uri, [], function(data) {
+            $(elem).find('.admin-loading').hide();
+            switch (data.storage) {
+              case 3:
+                $(elem).find('.admin-rebuilding').show();
+                break;
+              case 2:
+                $(elem).find('.admin-needs-review').show();
+                break;
+              case 1:
+                $(elem).find('.admin-overridden').show();
+                break;
+              default:
+                $(elem).find('.admin-default').show();
+                break;
+            }
+            Drupal.features.checkStatus();
+          }, 'json');
+        }
+        else {
+            Drupal.features.checkStatus();
+          }
+      });
+    }
+  };
+
+
+})(jQuery);
+
+