| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429 | /** * 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');      });      //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 updateComponentCountInfo(item, section) {        switch (section) {          case 'select':            var parent = $(item).closest('.features-export-list').siblings('.features-export-component');            $('.component-count', parent).text(function (index, text) {                return +text + 1;              }            );            break;          case 'added':          case 'detected':            var parent = $(item).closest('.features-export-component');            $('.component-count', parent).text(function (index, text) {              return text - 1;            });        }      }      function moveCheckbox(item, section, value) {        updateComponentCountInfo(item, section);        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);
 |