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