Mercurial > hg > rr-repo
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"> </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); + +