',
+ '#pre_render' => array('shortcut_toolbar_pre_render'),
+ );
+ }
}
/**
@@ -126,8 +188,30 @@ function adminimal_admin_menu_preprocess_html(&$vars) {
// Add the "adminimal" class to the body for better css selection.
$vars['classes_array'][] = 'adminimal-menu';
+ // Add frontend and backend classes to the body.
+ if (path_is_admin(current_path())) {
+ $vars['classes_array'][] = 'adminimal-backend';
+ }
+ else {
+ $vars['classes_array'][] = 'adminimal-frontend';
+ }
+
// Add the shortcut render mode class.
- $vars['classes_array'][] = 'menu-render-'.variable_get('adminimal_admin_menu_render', 'collapsed');
+ $vars['classes_array'][] = 'menu-render-' . variable_get('adminimal_admin_menu_render', 'collapsed');
+
+ // Fix the viewport, correcting the mobile device zoom.
+ /** @todo - Mybre remove this and let the theme manage the view pont.
+ * But i was suprised that only few "responsive" drupal themes were fixing
+ * the viewport.
+ */
+ $viewport = array(
+ '#tag' => 'meta',
+ '#attributes' => array(
+ 'name' => 'viewport',
+ 'content' => 'width=device-width, initial-scale=1, maximum-scale=1',
+ ),
+ );
+ drupal_add_html_head($viewport, 'viewport');
}
diff --git a/sites/all/modules/contrib/admin/adminimal_admin_menu/adminimal_menu_settings.inc b/sites/all/modules/contrib/admin/adminimal_admin_menu/adminimal_menu_settings.inc
index f7da6a21..e1147f47 100644
--- a/sites/all/modules/contrib/admin/adminimal_admin_menu/adminimal_menu_settings.inc
+++ b/sites/all/modules/contrib/admin/adminimal_admin_menu/adminimal_menu_settings.inc
@@ -33,6 +33,41 @@ function adminimal_admin_menu_settings($form, &$form_state) {
'#required' => TRUE,
);
+ // Create the shortcut category.
+ $form['advanced_settings'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Advanced Settings'),
+ '#description' => '
WARNING: Do not change any of the advanced setting unless you know what you are doing!
',
+ );
+
+ $form['advanced_settings']['adminimal_admin_menu_slicknav'] = array(
+ '#type' => 'checkbox',
+ '#default_value' => variable_get('adminimal_admin_menu_slicknav', 'TRUE'),
+ '#title' => t('Enable Responsive Menu.'),
+ '#description' => t('Default value => Checked.
+ Enable this option if you want to have responsive menu and mobile device support.
+ While disabling this option could save you few kilobytes (around 3KB), i will completely disable the responsive menu functionality.'),
+ );
+
+ $form['advanced_settings']['adminimal_admin_menu_jquery'] = array(
+ '#type' => 'checkbox',
+ '#default_value' => variable_get('adminimal_admin_menu_jquery', 'TRUE'),
+ '#title' => t('Load the requred jQuery 1.7 library automagically.'),
+ '#description' => t('Default value => Checked. This will load the newer jQuery version 1.7 using
+ the no-conflict method so it wont interfere with any existing jQuery or other java-script libraries.
+ The only reason to uncheck this if you are already using a newer version of jQuery site-wide and its globally accessible by the "$" variable.
+ Unchekig this option could save you 33KB, but it may also break your javasctipt if not used correctly.'),
+ '#states' => array(
+ // Hide the settings when the cancel notify checkbox is disabled.
+ 'visible' => array(
+ ':input[name="adminimal_admin_menu_slicknav"]' => array('checked' => TRUE),
+ ),
+ 'unchecked' => array(
+ variable_get('adminimal_admin_menu_jquery', 'TRUE') => FALSE,
+ ),
+ ),
+ );
+
// Create the submit button.
$form['submit'] = array(
'#type' => 'submit',
diff --git a/sites/all/modules/contrib/admin/adminimal_admin_menu/credits.txt b/sites/all/modules/contrib/admin/adminimal_admin_menu/credits.txt
new file mode 100644
index 00000000..cd21dc49
--- /dev/null
+++ b/sites/all/modules/contrib/admin/adminimal_admin_menu/credits.txt
@@ -0,0 +1,2 @@
+Designed and developed by: ANDiTKO -> http://anditko.com
+Some of the Icons are from the Icons8 set -> http://icons8.com/ and -> http://VisualPharm.com
\ No newline at end of file
diff --git a/sites/all/modules/contrib/admin/adminimal_admin_menu/images/circledown.svg b/sites/all/modules/contrib/admin/adminimal_admin_menu/images/circledown.svg
new file mode 100644
index 00000000..7b90bcf4
--- /dev/null
+++ b/sites/all/modules/contrib/admin/adminimal_admin_menu/images/circledown.svg
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/sites/all/modules/contrib/admin/adminimal_admin_menu/images/home.svg b/sites/all/modules/contrib/admin/adminimal_admin_menu/images/home.svg
new file mode 100644
index 00000000..b2ee0278
--- /dev/null
+++ b/sites/all/modules/contrib/admin/adminimal_admin_menu/images/home.svg
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/sites/all/modules/contrib/admin/adminimal_admin_menu/images/house.svg b/sites/all/modules/contrib/admin/adminimal_admin_menu/images/house.svg
new file mode 100644
index 00000000..973095ad
--- /dev/null
+++ b/sites/all/modules/contrib/admin/adminimal_admin_menu/images/house.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/sites/all/modules/contrib/admin/adminimal_admin_menu/images/menu-arrows.svg b/sites/all/modules/contrib/admin/adminimal_admin_menu/images/menu-arrows.svg
new file mode 100644
index 00000000..9eff00eb
--- /dev/null
+++ b/sites/all/modules/contrib/admin/adminimal_admin_menu/images/menu-arrows.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/sites/all/modules/contrib/admin/adminimal_admin_menu/images/menu.svg b/sites/all/modules/contrib/admin/adminimal_admin_menu/images/menu.svg
new file mode 100644
index 00000000..4eea8dcf
--- /dev/null
+++ b/sites/all/modules/contrib/admin/adminimal_admin_menu/images/menu.svg
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+]>
+
diff --git a/sites/all/modules/contrib/admin/adminimal_admin_menu/images/tasks.svg b/sites/all/modules/contrib/admin/adminimal_admin_menu/images/tasks.svg
new file mode 100644
index 00000000..6469da85
--- /dev/null
+++ b/sites/all/modules/contrib/admin/adminimal_admin_menu/images/tasks.svg
@@ -0,0 +1,27 @@
+
+
+
+
diff --git a/sites/all/modules/contrib/admin/adminimal_admin_menu/adminimal_admin_menu.js b/sites/all/modules/contrib/admin/adminimal_admin_menu/js/adminimal_admin_menu.js
similarity index 70%
rename from sites/all/modules/contrib/admin/adminimal_admin_menu/adminimal_admin_menu.js
rename to sites/all/modules/contrib/admin/adminimal_admin_menu/js/adminimal_admin_menu.js
index 4c4340bb..bad746ab 100644
--- a/sites/all/modules/contrib/admin/adminimal_admin_menu/adminimal_admin_menu.js
+++ b/sites/all/modules/contrib/admin/adminimal_admin_menu/js/adminimal_admin_menu.js
@@ -19,43 +19,39 @@ Drupal.admin.behaviors.toolbarActiveTrail = function (context, settings, $adminM
}
};
-/**
- * @} End of "ingroup admin_behaviors".
- */
-
Drupal.admin.behaviors.shorcutcollapsed = function (context, settings, $adminMenu) {
// Create the dropdown base
- $("
+####Initialize
+
+
+
+### Options
+ 'label' : 'MENU', // Label for menu button. Use an empty string for no label.
+ 'duplicate': true, // If true, the mobile menu is a copy of the original.
+ 'duration': true, // The duration of the sliding animation.
+ 'easingOpen': 'swing', // Easing used for open animations.
+ 'easingClose': 'swing' // Easing used for close animations.
+ 'closedSymbol': '►', // Character after collapsed parents.
+ 'openedSymbol': '▼', // Character after expanded parents.
+ 'prependTo': 'body', // Element, jQuery object, or jQuery selector string to prepend the mobile menu to.
+ 'parentTag': 'a', // Element type for parent menu items.
+ 'closeOnClick': false, // Close menu when a link is clicked.
+ 'allowParentLinks': false // Allow clickable links as parent elements.
+
+### Callbacks
+ 'init': function(){}, // Called after SlickNav creation
+ 'open': function(trigger){}, // Called after menu or sub-menu opened.
+ 'close': function(trigger){} // Called after menu or sub-menu closed.
+
+### Methods
+ $('.menu').slicknav('toggle'); // Method to toggle the menu
+ $('.menu').slicknav('open'); // Method to open the menu
+ $('.menu').slicknav('close'); // Method to close the menu
+
+Without any additional configuration, both the original and mobile menus will be displayed. It is recommended to use media queries to hide the original menu and display the mobile menu when appropriate. Modernizr or similar can be used for graceful degradation.
+
+For example:
+
+ .slicknav_menu {
+ display:none;
+ }
+
+ @media screen and (max-width: 40em) {
+ /* #menu is the original menu */
+ .js #menu {
+ display:none;
+ }
+
+ .js .slicknav_menu {
+ display:block;
+ }
+ }
+
+More examples at [SlickNav.com](http://slicknav.com)
+
+### Browser Support
+* Chrome
+* Firefox
+* Safari
+* Opera
+* IE7+
+* Android Browser
+* iOS Safari
\ No newline at end of file
diff --git a/sites/all/modules/contrib/admin/adminimal_admin_menu/js/slicknav/jquery-no-conflict.slicknav.js b/sites/all/modules/contrib/admin/adminimal_admin_menu/js/slicknav/jquery-no-conflict.slicknav.js
new file mode 100644
index 00000000..ff7af8bc
--- /dev/null
+++ b/sites/all/modules/contrib/admin/adminimal_admin_menu/js/slicknav/jquery-no-conflict.slicknav.js
@@ -0,0 +1,432 @@
+/*!
+ SlickNav Responsive Mobile Menu
+ (c) 2014 Josh Cope
+ licensed under MIT
+*/
+;(function ($, document, window) {
+ var
+ // default settings object.
+ defaults = {
+ label: 'MENU',
+ duplicate: true,
+ duration: 200,
+ easingOpen: 'swing',
+ easingClose: 'swing',
+ closedSymbol: '►',
+ openedSymbol: '▼',
+ prependTo: 'body',
+ parentTag: 'a',
+ closeOnClick: false,
+ allowParentLinks: false,
+ init: function(){},
+ open: function(){},
+ close: function(){}
+ },
+ mobileMenu = 'slicknav',
+ prefix = 'slicknav';
+
+ function Plugin( element, options ) {
+ this.element = element;
+
+ // jQuery has an extend method which merges the contents of two or
+ // more objects, storing the result in the first object. The first object
+ // is generally empty as we don't want to alter the default options for
+ // future instances of the plugin
+ this.settings = $.extend( {}, defaults, options) ;
+
+ this._defaults = defaults;
+ this._name = mobileMenu;
+
+ this.init();
+ }
+
+ Plugin.prototype.init = function () {
+ var $this = this;
+ var menu = $(this.element);
+ var settings = this.settings;
+
+ // clone menu if needed
+ if (settings.duplicate) {
+ $this.mobileNav = menu.clone();
+ //remove ids from clone to prevent css issues
+ $this.mobileNav.removeAttr('id');
+ $this.mobileNav.find('*').each(function(i,e){
+ $(e).removeAttr('id');
+ });
+ }
+ else
+ $this.mobileNav = menu;
+
+ // styling class for the button
+ var iconClass = prefix+'_icon';
+
+ if (settings.label == '') {
+ iconClass += ' '+prefix+'_no-text';
+ }
+
+ if (settings.parentTag == 'a') {
+ settings.parentTag = 'a href="#"';
+ }
+
+ // create menu bar
+ $this.mobileNav.attr('class', prefix+'_nav');
+ var menuBar = $('');
+ $this.btn = $('<'+settings.parentTag+' aria-haspopup="true" tabindex="0" class="'+prefix+'_btn '+prefix+'_collapsed">'+settings.label+'');
+ $(menuBar).append($this.btn);
+ $(settings.prependTo).prepend(menuBar);
+ menuBar.append($this.mobileNav);
+
+ // iterate over structure adding additional structure
+ var items = $this.mobileNav.find('li');
+ $(items).each(function () {
+ var item = $(this);
+ data = {};
+ data.children = item.children('ul').attr('role','menu');
+ item.data("menu", data);
+
+ // if a list item has a nested menu
+ if (data.children.length > 0) {
+
+ // select all text before the child menu
+ var a = item.contents();
+ var nodes = [];
+ $(a).each(function(){
+ if(!$(this).is("ul")) {
+ nodes.push(this);
+ }
+ else {
+ return false;
+ }
+ });
+
+ // wrap item text with tag and add classes
+ var wrap = $(nodes).wrapAll('<'+settings.parentTag+' role="menuitem" aria-haspopup="true" tabindex="-1" class="'+prefix+'_item"/>').parent();
+
+ item.addClass(prefix+'_collapsed');
+ item.addClass(prefix+'_parent');
+
+ // create parent arrow
+ $(nodes).last().after(''+settings.closedSymbol+'');
+
+
+ } else if ( item.children().length == 0) {
+ item.addClass(prefix+'_txtnode');
+ }
+
+ // accessibility for links
+ item.children('a').attr('role', 'menuitem').click(function(){
+ //Emulate menu close if set
+ if (settings.closeOnClick)
+ $($this.btn).click();
+ });
+ });
+
+ // structure is in place, now hide appropriate items
+ $(items).each(function () {
+ var data = $(this).data("menu");
+ $this._visibilityToggle(data.children, false, null, true);
+ });
+
+ // finally toggle entire menu
+ $this._visibilityToggle($this.mobileNav, false, 'init', true);
+
+ // accessibility for menu button
+ $this.mobileNav.attr('role','menu');
+
+ // outline prevention when using mouse
+ $(document).mousedown(function(){
+ $this._outlines(false);
+ });
+
+ $(document).keyup(function(){
+ $this._outlines(true);
+ });
+
+ // menu button click
+ $($this.btn).click(function (e) {
+ e.preventDefault();
+ $this._menuToggle();
+ });
+
+ // click on menu parent
+ $this.mobileNav.on('click', '.'+prefix+'_item', function(e){
+ e.preventDefault();
+ $this._itemClick($(this));
+ });
+
+ // check for enter key on menu button and menu parents
+ $($this.btn).keydown(function (e) {
+ var ev = e || event;
+ if(ev.keyCode == 13) {
+ e.preventDefault();
+ $this._menuToggle();
+ }
+ });
+
+ $this.mobileNav.on('keydown', '.'+prefix+'_item', function(e) {
+ var ev = e || event;
+ if(ev.keyCode == 13) {
+ e.preventDefault();
+ $this._itemClick($(e.target));
+ }
+ });
+
+ // allow links clickable within parent tags if set
+ if (settings.allowParentLinks) {
+ $('.'+prefix+'_item a').click(function(e){
+ e.stopImmediatePropagation();
+ });
+ }
+ };
+
+ //toggle menu
+ Plugin.prototype._menuToggle = function(el){
+ var $this = this;
+ var btn = $this.btn;
+ var mobileNav = $this.mobileNav;
+
+ if (btn.hasClass(prefix+'_collapsed')) {
+ btn.removeClass(prefix+'_collapsed');
+ btn.addClass(prefix+'_open');
+ } else {
+ btn.removeClass(prefix+'_open');
+ btn.addClass(prefix+'_collapsed');
+ }
+ btn.addClass(prefix+'_animating');
+ $this._visibilityToggle(mobileNav, true, btn);
+ }
+
+ // toggle clicked items
+ Plugin.prototype._itemClick = function(el) {
+ var $this = this;
+ var settings = $this.settings;
+ var data = el.data("menu");
+ if (!data) {
+ data = {};
+ data.arrow = el.children('.'+prefix+'_arrow');
+ data.ul = el.next('ul');
+ data.parent = el.parent();
+ el.data("menu", data);
+ }
+ if (data.parent.hasClass(prefix+'_collapsed')) {
+ data.arrow.html(settings.openedSymbol);
+ data.parent.removeClass(prefix+'_collapsed');
+ data.parent.addClass(prefix+'_open');
+ data.parent.addClass(prefix+'_animating');
+ $this._visibilityToggle(data.ul, true, el);
+ } else {
+ data.arrow.html(settings.closedSymbol);
+ data.parent.addClass(prefix+'_collapsed');
+ data.parent.removeClass(prefix+'_open');
+ data.parent.addClass(prefix+'_animating');
+ $this._visibilityToggle(data.ul, true, el);
+ }
+ }
+
+ // toggle actual visibility and accessibility tags
+ Plugin.prototype._visibilityToggle = function(el, animate, trigger, init) {
+ var $this = this;
+ var settings = $this.settings;
+ var items = $this._getActionItems(el);
+ var duration = 0;
+ if (animate)
+ duration = settings.duration;
+
+ if (el.hasClass(prefix+'_hidden')) {
+ el.removeClass(prefix+'_hidden');
+ el.slideDown(duration, settings.easingOpen, function(){
+
+ $(trigger).removeClass(prefix+'_animating');
+ $(trigger).parent().removeClass(prefix+'_animating');
+
+ //Fire open callback
+ if (!init) {
+ settings.open(trigger);
+ }
+ });
+ el.attr('aria-hidden','false');
+ items.attr('tabindex', '0');
+ $this._setVisAttr(el, false);
+ } else {
+ el.addClass(prefix+'_hidden');
+ el.slideUp(duration, this.settings.easingClose, function() {
+ el.attr('aria-hidden','true');
+ items.attr('tabindex', '-1');
+ $this._setVisAttr(el, true);
+ el.hide(); //jQuery 1.7 bug fix
+
+ $(trigger).removeClass(prefix+'_animating');
+ $(trigger).parent().removeClass(prefix+'_animating');
+
+ //Fire init or close callback
+ if (!init)
+ settings.close(trigger);
+ else if (trigger == 'init')
+ settings.init();
+ });
+ }
+ }
+
+ // set attributes of element and children based on visibility
+ Plugin.prototype._setVisAttr = function(el, hidden) {
+ var $this = this;
+
+ // select all parents that aren't hidden
+ var nonHidden = el.children('li').children('ul').not('.'+prefix+'_hidden');
+
+ // iterate over all items setting appropriate tags
+ if (!hidden) {
+ nonHidden.each(function(){
+ var ul = $(this);
+ ul.attr('aria-hidden','false');
+ var items = $this._getActionItems(ul);
+ items.attr('tabindex', '0');
+ $this._setVisAttr(ul, hidden);
+ });
+ } else {
+ nonHidden.each(function(){
+ var ul = $(this);
+ ul.attr('aria-hidden','true');
+ var items = $this._getActionItems(ul);
+ items.attr('tabindex', '-1');
+ $this._setVisAttr(ul, hidden);
+ });
+ }
+ }
+
+ // get all 1st level items that are clickable
+ Plugin.prototype._getActionItems = function(el) {
+ var data = el.data("menu");
+ if (!data) {
+ data = {};
+ var items = el.children('li');
+ var anchors = items.children('a');
+ data.links = anchors.add(items.children('.'+prefix+'_item'));
+ el.data("menu", data);
+ }
+ return data.links;
+ }
+
+ Plugin.prototype._outlines = function(state) {
+ if (!state) {
+ $('.'+prefix+'_item, .'+prefix+'_btn').css('outline','none');
+ } else {
+ $('.'+prefix+'_item, .'+prefix+'_btn').css('outline','');
+ }
+ }
+
+ Plugin.prototype.toggle = function(){
+ $this._menuToggle();
+ }
+
+ Plugin.prototype.open = function(){
+ $this = this;
+ if ($this.btn.hasClass(prefix+'_collapsed')) {
+ $this._menuToggle();
+ }
+ }
+
+ Plugin.prototype.close = function(){
+ $this = this;
+ if ($this.btn.hasClass(prefix+'_open')) {
+ $this._menuToggle();
+ }
+ }
+
+ $.fn[mobileMenu] = function ( options ) {
+ var args = arguments;
+
+ // Is the first parameter an object (options), or was omitted, instantiate a new instance
+ if (options === undefined || typeof options === 'object') {
+ return this.each(function () {
+
+ // Only allow the plugin to be instantiated once due to methods
+ if (!$.data(this, 'plugin_' + mobileMenu)) {
+
+ // if it has no instance, create a new one, pass options to our plugin constructor,
+ // and store the plugin instance in the elements jQuery data object.
+ $.data(this, 'plugin_' + mobileMenu, new Plugin( this, options ));
+ }
+ });
+
+ // If is a string and doesn't start with an underscore or 'init' function, treat this as a call to a public method.
+ } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
+
+ // Cache the method call to make it possible to return a value
+ var returns;
+
+ this.each(function () {
+ var instance = $.data(this, 'plugin_' + mobileMenu);
+
+ // Tests that there's already a plugin-instance and checks that the requested public method exists
+ if (instance instanceof Plugin && typeof instance[options] === 'function') {
+
+ // Call the method of our plugin instance, and pass it the supplied arguments.
+ returns = instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) );
+ }
+ });
+
+ // If the earlier cached method gives a value back return the value, otherwise return this to preserve chainability.
+ return returns !== undefined ? returns : this;
+ }
+ };
+}($jQueryAdminimal, document, window));
+
+(function($) {
+
+// Create the responsive menu using SlickNav.
+Drupal.admin.behaviors.responsivemenu = function (context, settings, $adminMenu) {
+
+ $('#admin-menu-menu-responsive').slicknav({
+ label: 'Menu',
+ prependTo:'body',
+ closedSymbol: "",
+ openedSymbol: "",
+ allowParentLinks: true
+ });
+
+};
+
+// Create the responsive shortcuts dropdown.
+Drupal.admin.behaviors.responsiveshortcuts = function (context, settings, $adminMenu) {
+
+ // Check if there are any shortucts to respondify.
+ if(jQuery("div.toolbar-shortcuts ul.menu li").length){
+
+ // Create the dropdown base
+ $("").appendTo("#admin-menu-shortcuts-responsive div.toolbar-shortcuts");
+
+ // Create default option "Select"
+ $("", {
+ "selected" : "selected",
+ "class" : "hide",
+ "value" : "",
+ "text" : Drupal.t('Shortcuts')
+ }).appendTo("#admin-menu-shortcuts-responsive div.toolbar-shortcuts select");
+
+ // Populate dropdown with menu items
+ $("#admin-menu-shortcuts-responsive div.toolbar-shortcuts a").each(function() {
+ var el = $(this);
+ $("", {
+ "value" : el.attr("href"),
+ "text" : el.text()
+ }).appendTo("#admin-menu-shortcuts-responsive div.toolbar-shortcuts select");
+ });
+
+ // Redirect the user when selecting an option.
+ $("#admin-menu-shortcuts-responsive div.toolbar-shortcuts select").change(function() {
+ window.location = $(this).find("option:selected").val();
+ });
+
+ // Clean the mess.
+ $('#admin-menu-shortcuts-responsive div.toolbar-shortcuts ul').remove();
+ // Move the select box into the responsive menu.
+ $("#admin-menu-shortcuts-responsive").prependTo(".slicknav_menu");
+
+ }
+
+ // Remove the edit shortcuts link from the DOM to avoid duble rendering.
+ $('#admin-menu-shortcuts-responsive #edit-shortcuts').remove();
+
+};
+})($jQueryAdminimal);
\ No newline at end of file
diff --git a/sites/all/modules/contrib/admin/adminimal_admin_menu/js/slicknav/jquery.slicknav.js b/sites/all/modules/contrib/admin/adminimal_admin_menu/js/slicknav/jquery.slicknav.js
new file mode 100644
index 00000000..d9a29e26
--- /dev/null
+++ b/sites/all/modules/contrib/admin/adminimal_admin_menu/js/slicknav/jquery.slicknav.js
@@ -0,0 +1,432 @@
+/*!
+ SlickNav Responsive Mobile Menu
+ (c) 2014 Josh Cope
+ licensed under MIT
+*/
+;(function ($, document, window) {
+ var
+ // default settings object.
+ defaults = {
+ label: 'MENU',
+ duplicate: true,
+ duration: 200,
+ easingOpen: 'swing',
+ easingClose: 'swing',
+ closedSymbol: '►',
+ openedSymbol: '▼',
+ prependTo: 'body',
+ parentTag: 'a',
+ closeOnClick: false,
+ allowParentLinks: false,
+ init: function(){},
+ open: function(){},
+ close: function(){}
+ },
+ mobileMenu = 'slicknav',
+ prefix = 'slicknav';
+
+ function Plugin( element, options ) {
+ this.element = element;
+
+ // jQuery has an extend method which merges the contents of two or
+ // more objects, storing the result in the first object. The first object
+ // is generally empty as we don't want to alter the default options for
+ // future instances of the plugin
+ this.settings = $.extend( {}, defaults, options) ;
+
+ this._defaults = defaults;
+ this._name = mobileMenu;
+
+ this.init();
+ }
+
+ Plugin.prototype.init = function () {
+ var $this = this;
+ var menu = $(this.element);
+ var settings = this.settings;
+
+ // clone menu if needed
+ if (settings.duplicate) {
+ $this.mobileNav = menu.clone();
+ //remove ids from clone to prevent css issues
+ $this.mobileNav.removeAttr('id');
+ $this.mobileNav.find('*').each(function(i,e){
+ $(e).removeAttr('id');
+ });
+ }
+ else
+ $this.mobileNav = menu;
+
+ // styling class for the button
+ var iconClass = prefix+'_icon';
+
+ if (settings.label == '') {
+ iconClass += ' '+prefix+'_no-text';
+ }
+
+ if (settings.parentTag == 'a') {
+ settings.parentTag = 'a href="#"';
+ }
+
+ // create menu bar
+ $this.mobileNav.attr('class', prefix+'_nav');
+ var menuBar = $('');
+ $this.btn = $('<'+settings.parentTag+' aria-haspopup="true" tabindex="0" class="'+prefix+'_btn '+prefix+'_collapsed">'+settings.label+'');
+ $(menuBar).append($this.btn);
+ $(settings.prependTo).prepend(menuBar);
+ menuBar.append($this.mobileNav);
+
+ // iterate over structure adding additional structure
+ var items = $this.mobileNav.find('li');
+ $(items).each(function () {
+ var item = $(this);
+ data = {};
+ data.children = item.children('ul').attr('role','menu');
+ item.data("menu", data);
+
+ // if a list item has a nested menu
+ if (data.children.length > 0) {
+
+ // select all text before the child menu
+ var a = item.contents();
+ var nodes = [];
+ $(a).each(function(){
+ if(!$(this).is("ul")) {
+ nodes.push(this);
+ }
+ else {
+ return false;
+ }
+ });
+
+ // wrap item text with tag and add classes
+ var wrap = $(nodes).wrapAll('<'+settings.parentTag+' role="menuitem" aria-haspopup="true" tabindex="-1" class="'+prefix+'_item"/>').parent();
+
+ item.addClass(prefix+'_collapsed');
+ item.addClass(prefix+'_parent');
+
+ // create parent arrow
+ $(nodes).last().after(''+settings.closedSymbol+'');
+
+
+ } else if ( item.children().length == 0) {
+ item.addClass(prefix+'_txtnode');
+ }
+
+ // accessibility for links
+ item.children('a').attr('role', 'menuitem').click(function(){
+ //Emulate menu close if set
+ if (settings.closeOnClick)
+ $($this.btn).click();
+ });
+ });
+
+ // structure is in place, now hide appropriate items
+ $(items).each(function () {
+ var data = $(this).data("menu");
+ $this._visibilityToggle(data.children, false, null, true);
+ });
+
+ // finally toggle entire menu
+ $this._visibilityToggle($this.mobileNav, false, 'init', true);
+
+ // accessibility for menu button
+ $this.mobileNav.attr('role','menu');
+
+ // outline prevention when using mouse
+ $(document).mousedown(function(){
+ $this._outlines(false);
+ });
+
+ $(document).keyup(function(){
+ $this._outlines(true);
+ });
+
+ // menu button click
+ $($this.btn).click(function (e) {
+ e.preventDefault();
+ $this._menuToggle();
+ });
+
+ // click on menu parent
+ $this.mobileNav.on('click', '.'+prefix+'_item', function(e){
+ e.preventDefault();
+ $this._itemClick($(this));
+ });
+
+ // check for enter key on menu button and menu parents
+ $($this.btn).keydown(function (e) {
+ var ev = e || event;
+ if(ev.keyCode == 13) {
+ e.preventDefault();
+ $this._menuToggle();
+ }
+ });
+
+ $this.mobileNav.on('keydown', '.'+prefix+'_item', function(e) {
+ var ev = e || event;
+ if(ev.keyCode == 13) {
+ e.preventDefault();
+ $this._itemClick($(e.target));
+ }
+ });
+
+ // allow links clickable within parent tags if set
+ if (settings.allowParentLinks) {
+ $('.'+prefix+'_item a').click(function(e){
+ e.stopImmediatePropagation();
+ });
+ }
+ };
+
+ //toggle menu
+ Plugin.prototype._menuToggle = function(el){
+ var $this = this;
+ var btn = $this.btn;
+ var mobileNav = $this.mobileNav;
+
+ if (btn.hasClass(prefix+'_collapsed')) {
+ btn.removeClass(prefix+'_collapsed');
+ btn.addClass(prefix+'_open');
+ } else {
+ btn.removeClass(prefix+'_open');
+ btn.addClass(prefix+'_collapsed');
+ }
+ btn.addClass(prefix+'_animating');
+ $this._visibilityToggle(mobileNav, true, btn);
+ }
+
+ // toggle clicked items
+ Plugin.prototype._itemClick = function(el) {
+ var $this = this;
+ var settings = $this.settings;
+ var data = el.data("menu");
+ if (!data) {
+ data = {};
+ data.arrow = el.children('.'+prefix+'_arrow');
+ data.ul = el.next('ul');
+ data.parent = el.parent();
+ el.data("menu", data);
+ }
+ if (data.parent.hasClass(prefix+'_collapsed')) {
+ data.arrow.html(settings.openedSymbol);
+ data.parent.removeClass(prefix+'_collapsed');
+ data.parent.addClass(prefix+'_open');
+ data.parent.addClass(prefix+'_animating');
+ $this._visibilityToggle(data.ul, true, el);
+ } else {
+ data.arrow.html(settings.closedSymbol);
+ data.parent.addClass(prefix+'_collapsed');
+ data.parent.removeClass(prefix+'_open');
+ data.parent.addClass(prefix+'_animating');
+ $this._visibilityToggle(data.ul, true, el);
+ }
+ }
+
+ // toggle actual visibility and accessibility tags
+ Plugin.prototype._visibilityToggle = function(el, animate, trigger, init) {
+ var $this = this;
+ var settings = $this.settings;
+ var items = $this._getActionItems(el);
+ var duration = 0;
+ if (animate)
+ duration = settings.duration;
+
+ if (el.hasClass(prefix+'_hidden')) {
+ el.removeClass(prefix+'_hidden');
+ el.slideDown(duration, settings.easingOpen, function(){
+
+ $(trigger).removeClass(prefix+'_animating');
+ $(trigger).parent().removeClass(prefix+'_animating');
+
+ //Fire open callback
+ if (!init) {
+ settings.open(trigger);
+ }
+ });
+ el.attr('aria-hidden','false');
+ items.attr('tabindex', '0');
+ $this._setVisAttr(el, false);
+ } else {
+ el.addClass(prefix+'_hidden');
+ el.slideUp(duration, this.settings.easingClose, function() {
+ el.attr('aria-hidden','true');
+ items.attr('tabindex', '-1');
+ $this._setVisAttr(el, true);
+ el.hide(); //jQuery 1.7 bug fix
+
+ $(trigger).removeClass(prefix+'_animating');
+ $(trigger).parent().removeClass(prefix+'_animating');
+
+ //Fire init or close callback
+ if (!init)
+ settings.close(trigger);
+ else if (trigger == 'init')
+ settings.init();
+ });
+ }
+ }
+
+ // set attributes of element and children based on visibility
+ Plugin.prototype._setVisAttr = function(el, hidden) {
+ var $this = this;
+
+ // select all parents that aren't hidden
+ var nonHidden = el.children('li').children('ul').not('.'+prefix+'_hidden');
+
+ // iterate over all items setting appropriate tags
+ if (!hidden) {
+ nonHidden.each(function(){
+ var ul = $(this);
+ ul.attr('aria-hidden','false');
+ var items = $this._getActionItems(ul);
+ items.attr('tabindex', '0');
+ $this._setVisAttr(ul, hidden);
+ });
+ } else {
+ nonHidden.each(function(){
+ var ul = $(this);
+ ul.attr('aria-hidden','true');
+ var items = $this._getActionItems(ul);
+ items.attr('tabindex', '-1');
+ $this._setVisAttr(ul, hidden);
+ });
+ }
+ }
+
+ // get all 1st level items that are clickable
+ Plugin.prototype._getActionItems = function(el) {
+ var data = el.data("menu");
+ if (!data) {
+ data = {};
+ var items = el.children('li');
+ var anchors = items.children('a');
+ data.links = anchors.add(items.children('.'+prefix+'_item'));
+ el.data("menu", data);
+ }
+ return data.links;
+ }
+
+ Plugin.prototype._outlines = function(state) {
+ if (!state) {
+ $('.'+prefix+'_item, .'+prefix+'_btn').css('outline','none');
+ } else {
+ $('.'+prefix+'_item, .'+prefix+'_btn').css('outline','');
+ }
+ }
+
+ Plugin.prototype.toggle = function(){
+ $this._menuToggle();
+ }
+
+ Plugin.prototype.open = function(){
+ $this = this;
+ if ($this.btn.hasClass(prefix+'_collapsed')) {
+ $this._menuToggle();
+ }
+ }
+
+ Plugin.prototype.close = function(){
+ $this = this;
+ if ($this.btn.hasClass(prefix+'_open')) {
+ $this._menuToggle();
+ }
+ }
+
+ $.fn[mobileMenu] = function ( options ) {
+ var args = arguments;
+
+ // Is the first parameter an object (options), or was omitted, instantiate a new instance
+ if (options === undefined || typeof options === 'object') {
+ return this.each(function () {
+
+ // Only allow the plugin to be instantiated once due to methods
+ if (!$.data(this, 'plugin_' + mobileMenu)) {
+
+ // if it has no instance, create a new one, pass options to our plugin constructor,
+ // and store the plugin instance in the elements jQuery data object.
+ $.data(this, 'plugin_' + mobileMenu, new Plugin( this, options ));
+ }
+ });
+
+ // If is a string and doesn't start with an underscore or 'init' function, treat this as a call to a public method.
+ } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
+
+ // Cache the method call to make it possible to return a value
+ var returns;
+
+ this.each(function () {
+ var instance = $.data(this, 'plugin_' + mobileMenu);
+
+ // Tests that there's already a plugin-instance and checks that the requested public method exists
+ if (instance instanceof Plugin && typeof instance[options] === 'function') {
+
+ // Call the method of our plugin instance, and pass it the supplied arguments.
+ returns = instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) );
+ }
+ });
+
+ // If the earlier cached method gives a value back return the value, otherwise return this to preserve chainability.
+ return returns !== undefined ? returns : this;
+ }
+ };
+}(jQuery, document, window));
+
+(function($) {
+
+// Create the responsive menu using SlickNav.
+Drupal.admin.behaviors.responsivemenu = function (context, settings, $adminMenu) {
+
+ $('#admin-menu-menu-responsive').slicknav({
+ label: 'Menu',
+ prependTo:'body',
+ closedSymbol: "",
+ openedSymbol: "",
+ allowParentLinks: true
+ });
+
+};
+
+// Create the responsive shortcuts dropdown.
+Drupal.admin.behaviors.responsiveshortcuts = function (context, settings, $adminMenu) {
+
+ // Check if there are any shortucts to respondify.
+ if(jQuery("div.toolbar-shortcuts ul.menu li").length){
+
+ // Create the dropdown base
+ $("").appendTo("#admin-menu-shortcuts-responsive div.toolbar-shortcuts");
+
+ // Create default option "Select"
+ $("", {
+ "selected" : "selected",
+ "class" : "hide",
+ "value" : "",
+ "text" : Drupal.t('Shortcuts')
+ }).appendTo("#admin-menu-shortcuts-responsive div.toolbar-shortcuts select");
+
+ // Populate dropdown with menu items
+ $("#admin-menu-shortcuts-responsive div.toolbar-shortcuts a").each(function() {
+ var el = $(this);
+ $("", {
+ "value" : el.attr("href"),
+ "text" : el.text()
+ }).appendTo("#admin-menu-shortcuts-responsive div.toolbar-shortcuts select");
+ });
+
+ // Redirect the user when selecting an option.
+ $("#admin-menu-shortcuts-responsive div.toolbar-shortcuts select").change(function() {
+ window.location = $(this).find("option:selected").val();
+ });
+
+ // Clean the mess.
+ $('#admin-menu-shortcuts-responsive div.toolbar-shortcuts ul').remove();
+ // Move the select box into the responsive menu.
+ $("#admin-menu-shortcuts-responsive").prependTo(".slicknav_menu");
+
+ }
+
+ // Remove the edit shortcuts link from the DOM to avoid duble rendering.
+ $('#admin-menu-shortcuts-responsive #edit-shortcuts').remove();
+
+};
+})(jQuery);
\ No newline at end of file
diff --git a/sites/all/modules/contrib/admin/adminimal_admin_menu/js/slicknav/slicknav.css b/sites/all/modules/contrib/admin/adminimal_admin_menu/js/slicknav/slicknav.css
new file mode 100644
index 00000000..ef2be8cb
--- /dev/null
+++ b/sites/all/modules/contrib/admin/adminimal_admin_menu/js/slicknav/slicknav.css
@@ -0,0 +1,256 @@
+/*
+ Mobile Menu Core Style
+*/
+
+.slicknav_btn { position: relative; display: block; vertical-align: middle; float: right; padding: 0.438em 0.625em 0.438em 0.625em; line-height: 1.125em; cursor: pointer; }
+.slicknav_menu .slicknav_menutxt { display: block; line-height: 1.188em; float: left; }
+.slicknav_menu .slicknav_icon { float: left; margin: 0.188em 0 0 0.438em; }
+.slicknav_menu .slicknav_no-text { margin: 0 }
+.slicknav_menu .slicknav_icon-bar { display: block; width: 1.125em; height: 0.125em; -webkit-border-radius: 1px; -moz-border-radius: 1px; border-radius: 1px; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); }
+.slicknav_btn .slicknav_icon-bar + .slicknav_icon-bar { margin-top: 0.188em }
+.slicknav_nav { clear: both }
+.slicknav_nav ul,
+.slicknav_nav li { display: block }
+.slicknav_nav .slicknav_arrow { font-size: 0.8em; margin: 0 0 0 0.4em; }
+.slicknav_nav .slicknav_item { display: block; cursor: pointer; }
+.slicknav_nav a { display: block }
+.slicknav_nav .slicknav_item a { display: inline }
+.slicknav_menu:before,
+.slicknav_menu:after { content: " "; display: table; }
+.slicknav_menu:after { clear: both }
+/* IE6/7 support */
+.slicknav_menu { *zoom: 1 }
+
+/*
+ User Default Style
+ Change the following styles to modify the appearance of the menu.
+*/
+
+.slicknav_menu {
+ font-size:16px;
+}
+/* Button */
+.slicknav_btn {
+ margin: 5px 5px 6px;
+ text-decoration:none;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ background-color: #222222;
+}
+/* Button Text */
+.slicknav_menu .slicknav_menutxt {
+ color: #FFF;
+ font-weight: bold;
+ text-shadow: 0 1px 3px #000;
+}
+/* Button Lines */
+.slicknav_menu .slicknav_icon-bar {
+ background-color: #f5f5f5;
+}
+.slicknav_menu {
+ background:#4c4c4c;
+ padding:5px;
+}
+.slicknav_nav {
+ color:#fff;
+ margin:0;
+ padding:0;
+ font-size:0.875em;
+}
+.slicknav_nav, .slicknav_nav ul {
+ list-style: none;
+ overflow:hidden;
+}
+.slicknav_nav ul {
+ padding:0;
+ margin:0 0 0 20px;
+}
+.slicknav_nav .slicknav_item {
+ padding:5px 10px;
+ margin:2px 5px;
+}
+.slicknav_nav a{
+ padding:5px 10px;
+ margin:2px 5px;
+ text-decoration:none;
+ color:#fff;
+}
+.slicknav_nav .slicknav_item a {
+ padding:0;
+ margin:0;
+}
+.slicknav_nav .slicknav_item:hover {
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ background:#ccc;
+ color:#fff;
+}
+.slicknav_nav a:hover{
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ background:#ccc;
+ color:#222;
+}
+.slicknav_nav .slicknav_txtnode {
+ margin-left:15px;
+}
+
+/* ADMiNiMAL MENU STYLING */
+.slicknav_menu {
+ display:none;
+}
+
+#admin-menu-menu-responsive {
+ display: none;
+}
+
+@media screen and (max-width: 1024px) {
+ body.admin-menu.adminimal-menu:before {
+ display: none;
+ }
+ #admin-menu-menu, a#edit-shortcuts, li.admin-menu-account, #admin-menu-search, #admin-menu-users, {
+ display:none;
+ }
+
+ #admin-menu {
+ display: none !important;
+ }
+
+ body.admin-menu, body.admin-menu.adminimal-menu.adminimal-backend, body.admin-menu.adminimal-menu.adminimal-frontend {
+ margin-top: 0px !important;
+ }
+
+ .slicknav_menu {
+ display:block;
+ }
+
+ #admin-menu-shortcuts-responsive {
+ background: url("../../images/circledown.svg") no-repeat scroll 16px 50% transparent;
+ float: right;
+ }
+
+ #admin-menu-shortcuts-responsive select {
+ -moz-appearance: none;
+ -webkit-appearance: none;
+ text-indent: 0.01px;
+ text-overflow: '';
+ border: none;
+ font-size: 0px;
+ background: transparent;
+ height: 46px;
+ width: 46px;
+ display: block;
+ }
+
+ #admin-menu-shortcuts-responsive select option {
+ font-size: 14px;
+ background: #fff;
+ color: #333;
+ }
+
+}
+
+.slicknav_btn {
+ float: left;
+}
+
+.slicknav_menu {
+ background: none repeat scroll 0 0 #222222;
+ padding: 0;
+ font-family: Open Sans, "Segoe UI", "Helvetica", sans-serif;
+ color: color: #FFFFFF;
+}
+
+.slicknav_menu a, .slicknav_menu a:link, .slicknav_menu a:active {
+ color: #fff !important;
+ text-decoration: none !important;
+}
+
+.slicknav_menu:after {
+ clear: none;
+}
+
+.slicknav_btn {
+ margin: 0;
+ outline: medium none;
+ padding: 5px 10px;
+ text-shadow: none;
+ border-radius: 0;
+}
+
+.slicknav_icon {
+ display: none;
+}
+
+.slicknav_menu .slicknav_menutxt {
+ text-shadow: none;
+ font-weight: normal;
+}
+
+.slicknav_nav a:hover, .slicknav_nav .slicknav_item:hover {
+ border-radius: 0;
+}
+
+.slicknav_nav li.expandable, #admin-menu .slicknav_nav .dropdown li {
+ float: none !important;
+}
+
+.slicknav_nav .slicknav_item {
+
+}
+
+.slicknav_btn {
+ background: url("../../images/menu.svg") no-repeat scroll 8px 16px rgba(0, 0, 0, 0);
+ font-size: 23px;
+ padding: 10px 34px;
+}
+
+.slicknav_menu:after {
+ clear: both;
+}
+
+.slicknav_nav .slicknav_item:hover, .slicknav_nav a:hover {
+ background: none repeat scroll 0 0 #0074BD;
+ border-radius: 0;
+ color: #FFFFFF;
+ text-decoration: none !important;
+}
+
+.slicknav_nav .slicknav_arrow i {
+ display: inline-block;
+ background: url("../../images/menu-arrows.svg") no-repeat scroll 0px 3px rgba(0, 0, 0, 0);
+ font-size: 0.8em;
+ height: 16px;
+ margin: 0 0 0 0.4em;
+ width: 16px;
+}
+
+.slicknav_open .slicknav_arrow i.open {
+ background: url("../../images/menu-arrows.svg") no-repeat scroll -37px 0 rgba(0, 0, 0, 0);
+}
+
+.slicknav_nav li.admin-menu-toolbar-home-menu {
+ background-color: #333;
+}
+
+li.admin-menu-icon.slicknav_parent > a {
+ padding: 0;
+ margin: 0;
+}
+
+li.admin-menu-icon.slicknav_parent > a > span.slicknav_arrow {
+ position: absolute;
+ margin-top: 10px;
+ margin-left: -5px;
+}
+
+.slicknav_nav li.admin-menu-toolbar-home-menu span.admin-menu-home-icon {
+ background: url("../../images/house.svg") no-repeat scroll 17px 10px rgba(0, 0, 0, 0);
+ display: inline-block;
+ height: 40px;
+ width: 50px;
+}
\ No newline at end of file
diff --git a/sites/all/modules/contrib/admin/adminimal_admin_menu/updates/update_7100.php b/sites/all/modules/contrib/admin/adminimal_admin_menu/updates/update_7100.php
new file mode 100644
index 00000000..ddc268e5
--- /dev/null
+++ b/sites/all/modules/contrib/admin/adminimal_admin_menu/updates/update_7100.php
@@ -0,0 +1,18 @@
+type);
+ // Ran into an issue when using the Print module where the node type isn't set, throwing an error
+ // so we are checking to see if the node type is set first
+ $hide_title = isset($vars['node']->type) ? content_type_extras_get_setting('content_type_extras_title_hide', $vars['node']->type) : '';
if ($hide_title) {
$hide_title_css = content_type_extras_get_default('content_type_extras_title_hide_css');
if ($hide_title_css) {
@@ -142,6 +144,8 @@ function content_type_extras_form_alter(&$form, &$form_state, $form_id) {
$form['title']['#title'] = $title_label;
}
+ $form['actions']['submit']['#value'] = content_type_extras_get_setting('content_type_extras_save_button', $type);
+
$save_and_new = content_type_extras_get_setting('content_type_extras_save_and_new', $type);
if (!empty($save_and_new)) {
$form['actions']['save_and_new'] = array(
@@ -172,10 +176,26 @@ function content_type_extras_form_alter(&$form, &$form_state, $form_id) {
if (!empty($preview)) {
$form['actions']['preview']['#value'] = content_type_extras_get_setting('content_type_extras_preview_button', $type);
}
+ elseif (isset($form['actions']['preview'])) {
+ unset($form['actions']['preview']);
+ }
$cancel = content_type_extras_get_setting('content_type_extras_cancel', $type);
if (!empty($cancel)) {
- drupal_add_js(drupal_get_path('module', 'content_type_extras') . '/js/content_type_extras.cancel_button.js');
+ $cancel_hide_warning = content_type_extras_get_setting('content_type_extras_cancel_hide_warning', $type);
+ $cancel_location = content_type_extras_get_setting('content_type_extras_cancel_button_location', $type);
+ $location_path = content_type_extras_get_setting('content_type_extras_cancel_button_location_path', $type);
+
+ $form['#attached']['js'][] = drupal_get_path('module', 'content_type_extras') . '/js/content_type_extras.cancel_button.js';
+ $form['#attached']['js'][] = array(
+ 'data' => array('content_type_extras' => array(
+ 'hide_warning' => $cancel_hide_warning,
+ 'cancel_location' => $cancel_location,
+ 'location_path' => $location_path,
+ )),
+ 'type' => 'setting',
+ );
+
$form['actions']['cancel'] = array(
'#type' => 'button',
'#value' => t('Cancel'),
@@ -186,8 +206,9 @@ function content_type_extras_form_alter(&$form, &$form_state, $form_id) {
// Add the form buttons to the top of the page
// Based on: http://blog.urbaninsight.com/2011/09/20/editors-perspective-creating-content-drupal
- $top_buttons = content_type_extras_get_default('content_type_extras_top_buttons');
- if (!empty($top_buttons['node_edit'])) {
+ $top_buttons = content_type_extras_get_setting('content_type_extras_top_buttons', $type);
+
+ if (!empty($top_buttons['node_edit']) && in_array('node_edit', $top_buttons)) {
$form['pre_actions'] = $form['actions'];
$form['pre_actions']['#weight'] = -100;
}
@@ -199,16 +220,20 @@ function content_type_extras_form_alter(&$form, &$form_state, $form_id) {
// but the user can enter a name any length, getting an error message if the name is too long
// That drives me crazy!! This fixes that!
elseif ($form_id == 'field_ui_field_overview_form') {
+ $type = arg(4);
+
drupal_add_js(drupal_get_path('module', 'content_type_extras') . '/js/content_type_extras.manage_fields.js');
- $top_buttons = content_type_extras_get_default('content_type_extras_top_buttons');
- if (!empty($top_buttons['manage_fields'])) {
+ $top_buttons = content_type_extras_get_setting('content_type_extras_top_buttons', $type);
+ if (!empty($top_buttons['manage_fields']) || in_array('manage_fields', $top_buttons)) {
$form['pre_actions'] = $form['actions'];
$form['pre_actions']['#weight'] = -100;
}
- $form['fields']['_add_new_field']['field_name']['#maxlength'] = 26;
- $form['fields']['_add_new_field']['field_name']['#description'] .= t(' - 26 characters max.');
+ if (isset($form['fields']['_add_new_field'])) {
+ $form['fields']['_add_new_field']['field_name']['#maxlength'] = 26;
+ $form['fields']['_add_new_field']['field_name']['#description'] .= t(' - 26 characters max.');
+ }
// The field_group module does the same thing, so if that is enabled, handle it the same way
if (module_exists('field_group')) {
$form['fields']['_add_new_group']['group_name']['#maxlength'] = 26;
@@ -238,8 +263,30 @@ function content_type_extras_node_form_new_submit(&$form, &$form_state) {
* Form submission for $form_id *_node_form
*/
function content_type_extras_node_form_edit_submit(&$form, &$form_state) {
+ $query_string = array();
+ // Allow compatibility with content lock module.
+ if (isset($_REQUEST['content_lock_token'])) {
+ $query_string['content_lock_token'] = $_REQUEST['content_lock_token'];
+ }
+ // Allow compatibility with additional query parameters.
+ $query_parameters = drupal_get_query_parameters();
+ if (!empty($query_parameters)) {
+ foreach ($query_parameters as $key => $value) {
+ $query_string[$key] = $value;
+ }
+ }
+ if (!empty($query_string)) {
+ $form_state['redirect'] = url('node/' . $form_state['values']['nid'] . '/edit',
+ array(
+ 'query' => $query_string,
+ 'absolute' => TRUE,
+ )
+ );
+ }
+ else {
+ $form_state['redirect'] = 'node/' . $form_state['values']['nid'] . '/edit';
+ }
unset($_GET['destination']);
- $form_state['redirect'] = 'node/' . $form_state['values']['nid'] . '/edit';
}
/**
@@ -319,23 +366,16 @@ function content_type_extras_get_setting($setting, $type) {
*/
function content_type_extras_get_default($setting = NULL) {
// This has to be unserialized as it will crash the default settings page.
- $defaults = variable_get('content_type_extras_default_settings');
+ $defaults = variable_get('content_type_extras_default_settings', array()) + content_type_extras_get_initial();
+ // Return all default settings.
if ($setting == NULL) {
- if (!empty($defaults)) {
- return $defaults;
- }
- else {
- return content_type_extras_get_initial();
- }
+ return $defaults;
}
- else {
- if (isset($defaults[$setting])) {
- return $defaults[$setting];
- }
- else {
- return content_type_extras_get_initial($setting);
- }
+
+ // Return specific default setting.
+ else if (isset($defaults[$setting])) {
+ return $defaults[$setting];
}
}
@@ -362,20 +402,25 @@ function content_type_extras_get_initial($setting = NULL) {
),
'node_submitted' => 1,
// Values set by content_type_extras.module
- 'content_type_extras_preview_button' => t('Preview'),
- 'content_type_extras_save_and_new' => 0,
- 'content_type_extras_save_and_new_button' => t('Save and New'),
- 'content_type_extras_save_and_edit' => 0,
- 'content_type_extras_save_and_edit_button' => t('Save and Edit'),
- 'content_type_extras_cancel' => 0,
- 'content_type_extras_title_hide' => 0,
- 'content_type_extras_title_hide_css' => 0,
- 'content_type_extras_title_hide_front' => 0,
- 'content_type_extras_top_buttons' => array(),
- 'content_type_extras_remove_body' => 0,
- 'content_type_extras_descriptions_required' => 0,
- 'content_type_extras_user_permissions_select' => 'cte',
- 'content_type_extras_excluded_node_forms' => array(),
+ 'content_type_extras_save_button' => t('Save'),
+ 'content_type_extras_preview_button' => t('Preview'),
+ 'content_type_extras_save_and_new' => 0,
+ 'content_type_extras_save_and_new_button' => t('Save and New'),
+ 'content_type_extras_save_and_edit' => 0,
+ 'content_type_extras_save_and_edit_button' => t('Save and Edit'),
+ 'content_type_extras_cancel' => 0,
+ 'content_type_extras_cancel_hide_warning' => 0,
+ 'content_type_extras_title_hide' => 0,
+ 'content_type_extras_title_hide_css' => 0,
+ 'content_type_extras_title_hide_front' => 0,
+ 'content_type_extras_top_buttons' => array(),
+ 'content_type_extras_remove_body' => 0,
+ 'content_type_extras_disable_token_display' => 0,
+ 'content_type_extras_cancel_button_location' => 'previous',
+ 'content_type_extras_cancel_button_location_path' => '',
+ 'content_type_extras_descriptions_required' => 0,
+ 'content_type_extras_user_permissions_select' => 'cte',
+ 'content_type_extras_excluded_node_forms' => array(),
// Values set by comment.module
'comment' => array(
'comment' => 2,
@@ -408,9 +453,11 @@ function content_type_extras_get_initial($setting = NULL) {
$admin_role = variable_get('user_admin_role', '');
$initial_values['user_permissions'] = array(
- 'create_roles' => array($admin_role => $admin_role),
- 'edit_roles' => array($admin_role => $admin_role),
- 'delete_roles' => array($admin_role => $admin_role),
+ 'create_roles' => array($admin_role => $admin_role),
+ 'edit_roles' => array($admin_role => $admin_role),
+ 'delete_roles' => array($admin_role => $admin_role),
+ 'edit_own_roles' => array($admin_role => $admin_role),
+ 'delete_own_roles' => array($admin_role => $admin_role),
);
if ($setting == NULL) {
diff --git a/sites/all/modules/contrib/admin/content_type_extras/includes/content_type_extras.admin.inc b/sites/all/modules/contrib/admin/content_type_extras/includes/content_type_extras.admin.inc
index acf14f97..e6e26441 100644
--- a/sites/all/modules/contrib/admin/content_type_extras/includes/content_type_extras.admin.inc
+++ b/sites/all/modules/contrib/admin/content_type_extras/includes/content_type_extras.admin.inc
@@ -5,11 +5,17 @@ function content_type_extras_settings() {
// Get all available user roles
$roles = user_roles();
$admin_role = variable_get('user_admin_role', 0);
-
+
if ($admin_role != 0) {
$roles[$admin_role] .= t(' (administrator role)');
}
-
+ if(!isset($defaults['user_permissions']['edit_own_roles'])) {
+ $defaults['user_permissions']['edit_own_roles'] = array();
+ }
+ if(!isset($defaults['user_permissions']['delete_own_roles'])) {
+ $defaults['user_permissions']['delete_own_roles'] = array();
+ }
+
$form = array(
'intro' => array(
'#markup' => t('Set the default settings for all new content types below. These settings can be overridden on the content type page.'),
@@ -137,12 +143,24 @@ function content_type_extras_settings() {
'#options' => $roles,
'#default_value' => $defaults['user_permissions']['edit_roles'],
),
+ 'edit_own_roles' => array(
+ '#type' => 'checkboxes',
+ '#title' => t('Roles that can EDIT own content'),
+ '#options' => $roles,
+ '#default_value' => $defaults['user_permissions']['edit_own_roles'],
+ ),
'delete_roles' => array(
'#type' => 'checkboxes',
'#title' => t('Roles that can DELETE any content'),
'#options' => $roles,
'#default_value' => $defaults['user_permissions']['delete_roles'],
),
+ 'delete_own_roles' => array(
+ '#type' => 'checkboxes',
+ '#title' => t('Roles that can DELETE own content'),
+ '#options' => $roles,
+ '#default_value' => $defaults['user_permissions']['delete_own_roles'],
+ ),
),
'extras' => array(
'#type' => 'fieldset',
@@ -164,6 +182,33 @@ function content_type_extras_settings() {
'#title' => t('Remove body field from content types'),
'#default_value' => $defaults['content_type_extras_remove_body'],
),
+ 'content_type_extras_disable_token_display' => array(
+ '#type' => 'checkbox',
+ '#description' => t('Using modules such as pathauto uses tokens and, by default, we show the replacement patterns to use available tokens. However, this can slow some page loads down considerably. To disable token replacement patterns from being displayed on pages altered by Content Type: Extras (i.e. the content type edit page) check this box. This feature only hides the token replacement patterns. Tokens may still be used, they just must be entered manually.'),
+ '#title' => t('Disable token replacement patterns'),
+ '#default_value' => $defaults['content_type_extras_disable_token_display'],
+ ),
+ 'content_type_extras_cancel_button_location' => array(
+ '#type' => 'radios',
+ '#description' => t('Choose whether the user will be taken to the previous page or a specific page when the Cancel button is pressed.'),
+ '#title' => t('Cancel button destination'),
+ '#options' => array(
+ 'previous' => t('Previous page'),
+ 'static_path' => t('Static path'),
+ ),
+ '#default_value' => $defaults['content_type_extras_cancel_button_location'],
+ ),
+ 'content_type_extras_cancel_button_location_path' => array(
+ '#type' => 'textfield',
+ '#description' => t('Set the path where the user should be redirected when the cancel button is pressed. Note: In most cases you will probably want to prepend the path with a /.'),
+ '#title' => t('Path'),
+ '#default_value' => $defaults['content_type_extras_cancel_button_location_path'],
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="content_type_extras_cancel_button_location"]' => array('value' => 'static_path'),
+ ),
+ ),
+ ),
),
'node_titles' => array(
'#type' => 'fieldset',
@@ -217,7 +262,7 @@ function content_type_extras_settings() {
),
),
);
-
+
if (module_exists('comment')) {
$form['content_type_extras']['comment'] = array(
'#type' => 'fieldset',
@@ -279,7 +324,7 @@ function content_type_extras_settings() {
),
);
}
-
+
if (module_exists('xmlsitemap')) {
$form['content_type_extras']['xmlsitemap_settings'] = array(
'#type' => 'fieldset',
@@ -376,14 +421,14 @@ function content_type_extras_settings() {
'#default_value' => $defaults['content_type_extras_user_permissions_select'],
);
}
-
+
$form['actions'] = array(
'submit' => array(
'#type' => 'submit',
'#value' => t('Save configuration'),
),
);
-
+
return $form;
}
@@ -391,7 +436,7 @@ function content_type_extras_settings_submit(&$form, &$form_state) {
$values = $form_state['values'];
// Place the values of content_type_extras_excluded_node_forms into an array
$values['content_type_extras_excluded_node_forms'] = explode("\n", $values['content_type_extras_excluded_node_forms']);
-
+
unset($values['submit'], $values['form_build_id'], $values['form_token'], $values['form_id'], $values['op']);
variable_set('content_type_extras_default_settings', $values);
diff --git a/sites/all/modules/contrib/admin/content_type_extras/includes/content_type_extras.node_type_form.inc b/sites/all/modules/contrib/admin/content_type_extras/includes/content_type_extras.node_type_form.inc
index f4e71028..b000988f 100644
--- a/sites/all/modules/contrib/admin/content_type_extras/includes/content_type_extras.node_type_form.inc
+++ b/sites/all/modules/contrib/admin/content_type_extras/includes/content_type_extras.node_type_form.inc
@@ -9,12 +9,12 @@ function content_type_extras_node_type_form(&$form) {
// We need to set the weights of the 'Preview' button radios
$form['submission']['node_preview']['#weight'] = 2;
-
+
$type = $form['type']['#default_value'];
-
+
// We need to check whether the description field should be required or not.
$form['description']['#required'] = content_type_extras_get_setting('content_type_extras_descriptions_required', $type);
-
+
// Add Preview button text option
$form['submission']['content_type_extras_preview_button'] = array(
'#type' => 'textfield',
@@ -28,7 +28,15 @@ function content_type_extras_node_type_form(&$form) {
),
),
);
-
+
+ $form['submission']['content_type_extras_save_button'] = array(
+ '#type' => 'textfield',
+ '#title' => "'Save' button value",
+ '#description' => t(''),
+ '#default_value' => content_type_extras_get_setting('content_type_extras_save_button', $type),
+ '#weight' => $form['submission']['node_preview']['#weight'] - 1,
+ );
+
// Add the option to have a "Save and New" button added to the content type
$form['submission']['content_type_extras_save_and_new'] = array(
'#type' => 'radios',
@@ -53,7 +61,7 @@ function content_type_extras_node_type_form(&$form) {
),
),
);
-
+
// Add the option to have a "Save and Edit" button added to the content type
$form['submission']['content_type_extras_save_and_edit'] = array(
'#type' => 'radios',
@@ -78,7 +86,7 @@ function content_type_extras_node_type_form(&$form) {
),
),
);
-
+
// Add the option to have a "Cancel" button added to the content type
$form['submission']['content_type_extras_cancel'] = array(
'#type' => 'radios',
@@ -91,20 +99,33 @@ function content_type_extras_node_type_form(&$form) {
'#default_value' => content_type_extras_get_setting('content_type_extras_cancel', $type),
'#weight' => $form['submission']['node_preview']['#weight'] + 6,
);
-
+ // Add the option to have the warning message appear when using the "Cancel" button
+ $form['submission']['content_type_extras_cancel_hide_warning'] = array(
+ '#type' => 'checkbox',
+ '#title' => 'Hide cancel button warning message',
+ '#description' => t('If checked, a javascript alert box will not display warning the user that their changes will not be saved.'),
+ '#default_value' => content_type_extras_get_setting('content_type_extras_cancel_hide_warning', $type),
+ '#weight' => $form['submission']['content_type_extras_cancel']['#weight'] + 1,
+ '#states' => array(
+ 'visible' => array(
+ 'input[name=content_type_extras_cancel]' => array('value' => '1'),
+ ),
+ ),
+ );
+
// Set weight of help text area
$form['submission']['help']['#weight'] = $form['submission']['node_preview']['#weight'] + 7;
-
+
// Set 'Title field label'
$form['submission']['title_label']['#default_value'] = content_type_extras_get_setting('title_label', $type);
// Set 'Preview' button default
$form['submission']['node_preview']['#default_value'] = content_type_extras_get_setting('node_preview', $type);
// Set 'Display author and date information.'
$form['display']['node_submitted']['#default_value'] = content_type_extras_get_setting('node_submitted', $type);
-
+
// Set 'Publishing options'
$form['workflow']['node_options']['#default_value'] = content_type_extras_get_setting('node_options', $type);
-
+
if (module_exists('comment')) {
// A new content type is being added
if (empty($form['#node_type']->name)) {
@@ -118,25 +139,28 @@ function content_type_extras_node_type_form(&$form) {
$form['comment']['comment_preview']['#default_value'] = $comment_settings['preview'];
}
}
-
- if (module_exists('xmlsitemap')) {
- // XML Sitemap stores its variables a little differently, so we have to adjust for it here.
- $xmlsitemap_settings = content_type_extras_get_setting('xmlsitemap_settings', 'node_' . $type);
- $form['xmlsitemap']['status']['#default_value'] = $xmlsitemap_settings['status'];
- $form['xmlsitemap']['priority']['#default_value'] = $xmlsitemap_settings['priority'];
- }
- if (module_exists('scheduler')) {
- // Scheduler stores its variables a little differently, so we have to adjust for it here.
- $scheduler_settings = content_type_extras_get_setting('scheduler_settings', 'node_' . $type);
-
- $form['scheduler']['publish']['scheduler_publish_enable']['#default_value'] = $scheduler_settings['publish_enable'];
- $form['scheduler']['publish']['scheduler_publish_touch']['#default_value'] = $scheduler_settings['publish_touch'];
- $form['scheduler']['publish']['scheduler_publish_require']['#default_value'] = $scheduler_settings['publish_require'];
- $form['scheduler']['publish']['scheduler_publish_revision']['#default_value'] = $scheduler_settings['publish_revision'];
- $form['scheduler']['unpublish']['scheduler_unpublish_enable']['#default_value'] = $scheduler_settings['unpublish_enable'];
- $form['scheduler']['unpublish']['scheduler_unpublish_require']['#default_value'] = $scheduler_settings['unpublish_require'];
- $form['scheduler']['unpublish']['scheduler_unpublish_revision']['#default_value'] = $scheduler_settings['unpublish_revision'];
+ // A new content type is being added
+ if (empty($form['#node_type']->name)) {
+ if (module_exists('xmlsitemap')) {
+ // XML Sitemap stores its variables a little differently, so we have to adjust for it here.
+ $xmlsitemap_settings = content_type_extras_get_setting('xmlsitemap_settings', 'node_' . $type);
+ $form['xmlsitemap']['status']['#default_value'] = $xmlsitemap_settings['status'];
+ $form['xmlsitemap']['priority']['#default_value'] = $xmlsitemap_settings['priority'];
+ }
+
+ if (module_exists('scheduler')) {
+ // Scheduler stores its variables a little differently, so we have to adjust for it here.
+ $scheduler_settings = content_type_extras_get_setting('scheduler_settings', 'node_' . $type);
+
+ $form['scheduler']['publish']['scheduler_publish_enable']['#default_value'] = $scheduler_settings['publish_enable'];
+ $form['scheduler']['publish']['scheduler_publish_touch']['#default_value'] = $scheduler_settings['publish_touch'];
+ $form['scheduler']['publish']['scheduler_publish_require']['#default_value'] = $scheduler_settings['publish_require'];
+ $form['scheduler']['publish']['scheduler_publish_revision']['#default_value'] = $scheduler_settings['publish_revision'];
+ $form['scheduler']['unpublish']['scheduler_unpublish_enable']['#default_value'] = $scheduler_settings['unpublish_enable'];
+ $form['scheduler']['unpublish']['scheduler_unpublish_require']['#default_value'] = $scheduler_settings['unpublish_require'];
+ $form['scheduler']['unpublish']['scheduler_unpublish_revision']['#default_value'] = $scheduler_settings['unpublish_revision'];
+ }
}
// Get all available user roles
@@ -149,28 +173,35 @@ function content_type_extras_node_type_form(&$form) {
$create_roles = array();
$edit_roles = array();
$delete_roles = array();
+ $edit_own_roles = array();
+ $delete_own_roles = array();
+
// If we are on an existing content type form
if (!empty($form['name']['#default_value'])) {
$create_roles = user_roles(FALSE, 'create ' . $form['#node_type']->type . ' content');
$edit_roles = user_roles(FALSE, 'edit any ' . $form['#node_type']->type . ' content');
$delete_roles = user_roles(FALSE, 'delete any ' . $form['#node_type']->type . ' content');
+ $delete_own_roles = user_roles(FALSE, 'delete own ' . $form['#node_type']->type . ' content');
+ $edit_own_roles = user_roles(FALSE, 'edit own ' . $form['#node_type']->type . ' content');
}
// We are creating a new content type
else {
$user_permissions = content_type_extras_get_setting('user_permissions', '');
-
+
$selected_perms = content_type_extras_get_selected_roles($user_permissions);
-
+
$create_roles = $selected_perms['create_roles'];
$edit_roles = $selected_perms['edit_roles'];
+ $edit_own_roles = $selected_perms['edit_own_roles'];
$delete_roles = $selected_perms['delete_roles'];
+ $delete_own_roles = $selected_perms['delete_own_roles'];
}
-
+
$permission_select = content_type_extras_get_default('content_type_extras_user_permissions_select');
if ($permission_select == 'cte') {
// We need to remove FPA's implementation
unset($form['fpa_fieldset']);
-
+
$form['user_permissions'] = array(
'#type' => 'fieldset',
'#title' => t('User permissions'),
@@ -189,15 +220,27 @@ function content_type_extras_node_type_form(&$form) {
'#options' => $roles,
'#default_value' => array_keys($edit_roles),
),
+ 'edit_own_roles' => array(
+ '#type' => 'checkboxes',
+ '#title' => t('Roles that can EDIT own content of this type'),
+ '#options' => $roles,
+ '#default_value' => array_keys($edit_own_roles),
+ ),
'delete_roles' => array(
'#type' => 'checkboxes',
'#title' => t('Roles that can DELETE any content of this type'),
'#options' => $roles,
'#default_value' => array_keys($delete_roles),
),
+ 'delete_own_roles' => array(
+ '#type' => 'checkboxes',
+ '#title' => t('Roles that can DELETE own content of this type'),
+ '#options' => $roles,
+ '#default_value' => array_keys($delete_own_roles),
+ ),
);
}
-
+
$form['extras'] = array(
'#type' => 'fieldset',
'#title' => t('Extra settings'),
@@ -209,8 +252,18 @@ function content_type_extras_node_type_form(&$form) {
'#default_value' => content_type_extras_get_setting('content_type_extras_title_hide', $type),
'#weight' => 0,
),
+ 'content_type_extras_top_buttons' => array(
+ '#type' => 'checkboxes',
+ '#title' => t('Show form buttons at top of'),
+ '#description' => t('Select the areas to duplicate form submission buttons on the top of the page.'),
+ '#options' => array(
+ 'manage_fields' => t('Manage fields form'),
+ 'node_edit' => t('Node edit form'),
+ ),
+ '#default_value' => content_type_extras_get_setting('content_type_extras_top_buttons', $type),
+ ),
);
-
+
if (!empty($form['#node_type']->is_new)) {
// I decided to make this option only available when creating content types because:
// 1. Once the content type is created, the admin can manage the body field just like
@@ -225,7 +278,7 @@ function content_type_extras_node_type_form(&$form) {
'#weight' => 10,
);
}
-
+
if (module_exists('pathauto')) {
$form['extras']['pathauto_node'] = array(
'#type' => 'textfield',
@@ -234,20 +287,22 @@ function content_type_extras_node_type_form(&$form) {
'#default_value' => content_type_extras_get_setting('pathauto_node', $type . '_pattern'),
'#weight' => 20,
);
-
- $form['extras']['token_help'] = array(
- '#title' => t('Replacement patterns'),
- '#type' => 'fieldset',
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- 'help' => array(
- '#theme' => 'token_tree',
- '#token_types' => array('node'),
- ),
- '#weight' => 30,
- );
+
+ if (!content_type_extras_get_default('content_type_extras_disable_token_display')) {
+ $form['extras']['token_help'] = array(
+ '#title' => t('Replacement patterns'),
+ '#type' => 'fieldset',
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ 'help' => array(
+ '#theme' => 'token_tree',
+ '#token_types' => array('node'),
+ ),
+ '#weight' => 30,
+ );
+ }
}
-
+
// Custom form submission handler
// See why this is done in the notes for the redirect function in
// content_type_extras.module
@@ -260,9 +315,9 @@ function content_type_extras_node_type_form(&$form) {
function content_type_extras_node_type_form_submit(&$form, &$form_state) {
$values = $form_state['values'];
$user_permissions = $values['user_permissions'];
-
+
$selected_perms = content_type_extras_get_selected_roles($user_permissions);
-
+
foreach ($user_permissions as $action => $group) {
list($type, $trash) = explode('_', $action);
$set_perms = array();
@@ -271,13 +326,29 @@ function content_type_extras_node_type_form_submit(&$form, &$form_state) {
'create ' . $values['type'] . ' content',
);
}
- else {
- $set_perms = array(
- $type . ' own ' . $values['type'] . ' content',
- $type . ' any ' . $values['type'] . ' content',
- );
+ elseif ($type == 'edit') {
+ if($trash == 'own') {
+ $set_perms = array(
+ $type . ' own ' . $values['type'] . ' content',
+ );
+ } else {
+ $set_perms = array(
+ $type . ' any ' . $values['type'] . ' content',
+ );
+ }
}
-
+ elseif ($type == 'delete') {
+ if($trash == 'own') {
+ $set_perms = array(
+ $type . ' own ' . $values['type'] . ' content',
+ );
+ } else {
+ $set_perms = array(
+ $type . ' any ' . $values['type'] . ' content',
+ );
+ }
+ }
+
foreach ($group as $rid => $setting) {
if ($setting) {
user_role_grant_permissions($rid, $set_perms);
@@ -287,7 +358,7 @@ function content_type_extras_node_type_form_submit(&$form, &$form_state) {
}
}
}
-
+
if (!empty($values['content_type_extras_remove_body'])) {
// I'm not sure of a better way to not have a body field, other than to
// delete it after it has been created by Core.
@@ -296,7 +367,7 @@ function content_type_extras_node_type_form_submit(&$form, &$form_state) {
}
// Remove variable that is automatically created, it's not needed
variable_del('content_type_extras_remove_body_' . $values['type']);
-
+
// We have to rename the pathauto variable. Drupal by default creates one, but
// it's not named properly for pathauto to recognize it.
variable_set('pathauto_node_' . $values['type'] . '_pattern', variable_get('pathauto_node_' . $values['type']));
@@ -314,10 +385,10 @@ function content_type_extras_get_selected_roles($permissions, $perm_type = NULL)
}
}
}
-
+
if (!empty($perm_type)) {
return $selected_perms[$perm_type];
}
-
+
return $selected_perms;
}
diff --git a/sites/all/modules/contrib/admin/content_type_extras/js/content_type_extras.cancel_button.js b/sites/all/modules/contrib/admin/content_type_extras/js/content_type_extras.cancel_button.js
index 3906c22e..1241acca 100644
--- a/sites/all/modules/contrib/admin/content_type_extras/js/content_type_extras.cancel_button.js
+++ b/sites/all/modules/contrib/admin/content_type_extras/js/content_type_extras.cancel_button.js
@@ -1,19 +1,54 @@
(function ($) {
Drupal.behaviors.content_type_extras_cancel_button = {
attach: function(context, settings) {
-
- if($('form.node-form #edit-cancel').hasClass('cte-processed') ||
- $('form.node-form #edit-cancel--2').hasClass('cte-processed')) {
- return;
+ var cancelButton = $('form.node-form [id^="edit-cancel"]');
+
+ if (cancelButton.hasClass('cte-processed')) {
+ return;
}
else {
- $('form.node-form #edit-cancel, form.node-form #edit-cancel--2').addClass('cte-processed');
- $('form.node-form #edit-cancel, form.node-form #edit-cancel--2').click(function() {
- var answer = confirm(Drupal.t('Are you sure you want to cancel and lose all changes?'));
- if (answer) {
+ var hide_warning = settings.content_type_extras.hide_warning;
+
+ cancelButton.addClass('cte-processed');
+ cancelButton.click(function() {
+ if (hide_warning == 0) {
+ var answer = confirm(Drupal.t('Are you sure you want to cancel and lose all changes?'));
+ if (answer) {
+ cteExecuteCancel();
+ }
+ }
+ else {
+ cteExecuteCancel();
+ }
+ });
+ }
+
+ function cteExecuteCancel() {
+ $.QueryString = (function(a) {
+ if (a == "") return {};
+ var b = {};
+ for (var i = 0; i < a.length; ++i) {
+ var p=a[i].split('=');
+ if (p.length != 2) continue;
+ b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
+ }
+ return b;
+ })(window.location.search.substr(1).split('&'))
+
+ var baseUrl = document.location.origin;
+
+ if ($.QueryString["destination"]) {
+ var destination = $.QueryString["destination"];
+ $(location).attr('href', baseUrl + '/' + destination);
+ }
+ else {
+ if (settings.content_type_extras.cancel_location == 'static_path') {
+ window.location = settings.content_type_extras.location_path;
+ }
+ else {
history.go(-1);
}
- });
+ }
}
}
}
diff --git a/sites/all/modules/contrib/admin/context/context.info b/sites/all/modules/contrib/admin/context/context.info
index a980c87d..159f142a 100644
--- a/sites/all/modules/contrib/admin/context/context.info
+++ b/sites/all/modules/contrib/admin/context/context.info
@@ -8,9 +8,9 @@ files[] = tests/context.test
files[] = tests/context.conditions.test
files[] = tests/context.reactions.test
-; Information added by Drupal.org packaging script on 2015-01-06
-version = "7.x-3.6"
+; Information added by Drupal.org packaging script on 2016-05-18
+version = "7.x-3.7"
core = "7.x"
project = "context"
-datestamp = "1420573188"
+datestamp = "1463605446"
diff --git a/sites/all/modules/contrib/admin/context/context.install b/sites/all/modules/contrib/admin/context/context.install
index 0a5a145c..0d902ef5 100644
--- a/sites/all/modules/contrib/admin/context/context.install
+++ b/sites/all/modules/contrib/admin/context/context.install
@@ -103,7 +103,7 @@ function context_update_7000() {
}
}
if (empty($updated)) {
- $ret = t('No contexts requiring migration detected');
+ $ret = t('No contexts requiring migration detected.');
}
else {
$ret = t('The following contexts had theme reaction data migrated: @names', array('@names' => join(', ', $updated)));
diff --git a/sites/all/modules/contrib/admin/context/context.module b/sites/all/modules/contrib/admin/context/context.module
index 96808ddc..5c0bd5c8 100644
--- a/sites/all/modules/contrib/admin/context/context.module
+++ b/sites/all/modules/contrib/admin/context/context.module
@@ -192,11 +192,61 @@ function context_init() {
* theme('menu_link') for the menu rendering to html.
*/
function context_preprocess_menu_link(&$variables) {
- if($contexts = context_active_contexts()){
- foreach($contexts as $context){
- if((isset($context->reactions['menu']))){
- if ($variables['element']['#href'] == $context->reactions['menu']) {
- $variables['element']['#localized_options']['attributes']['class'][] = "active";
+ if ($contexts = context_active_contexts()) {
+ foreach ($contexts as $context) {
+ if (isset($context->reactions['menu'])) {
+ // In context module < v3.2 the url was a string. In version 3.3+ this is
+ // an array of urls. Implement interims BC layer.
+ //
+ // Examples:
+ // - OLD < v3.2 context reaction structure:
+ // array('menu' => 'taxonomy/term/1')
+ //
+ // - NEW 3.3+ context reaction structure:
+ // array(
+ // 'menu' => array(
+ // 0 => 'navigation:taxonomy/term/1'
+ // 1 => 'foo-menu:taxonomy/term/1'
+ // )
+ // )
+ $reactions_menu = is_array($context->reactions['menu']) ? array_values($context->reactions['menu']) : array($context->reactions['menu']);
+
+ // Get everything after the first ':' character (if found) as the url to
+ // match against element '#href'.
+ $urls = array();
+ foreach ($reactions_menu as $url) {
+ if (strpos($url, ':') !== FALSE) {
+ // Get unique menu name 'navigation' from 'navigation:taxonomy/term/1'
+ $reaction_menu = explode(':', $url);
+ $path = $reaction_menu[1];
+ $urls[$path] = $reaction_menu[0];
+ }
+ else {
+ // BC layer for menu contexts that have not re-saved. This is for
+ // urls like 'taxonomy/term/1'. We need to add a fake menu key
+ // 'bc-context-menu-layer' or the BC link get's removed by
+ // array_intersect below.
+ //
+ // @TODO: Remove BC layer in 4.x
+ $urls[$url] = 'context-reaction-menu-bc-layer';
+ }
+ }
+
+ // Filter urls by the menu name of the current link. The link reaction
+ // can be configured per menu link in specific menus and the contect
+ // reaction should not applied to other menus with the same menu link.
+ $menu_name = $variables['element']['#original_link']['menu_name'];
+ $menu_paths = array_intersect($urls, array($menu_name, 'context-reaction-menu-bc-layer'));
+ $reaction_menu_paths = array_keys($menu_paths);
+
+ // - If menu href and context reaction menu url match, add the 'active'
+ // css class to the link of this menu.
+ // - Do not add class twice on current page.
+ if (in_array($variables['element']['#href'], $reaction_menu_paths) && $variables['element']['#href'] != $_GET['q']) {
+ // Do not add the 'active' class twice in views tabs.
+ if (!in_array('active', $variables['element']['#localized_options']['attributes']['class'])) {
+ $variables['element']['#localized_options']['attributes']['class'][] = 'active';
+ }
}
}
}
diff --git a/sites/all/modules/contrib/admin/context/context.plugins.inc b/sites/all/modules/contrib/admin/context/context.plugins.inc
index a0849bb3..95d003d3 100644
--- a/sites/all/modules/contrib/admin/context/context.plugins.inc
+++ b/sites/all/modules/contrib/admin/context/context.plugins.inc
@@ -37,7 +37,7 @@ function _context_context_registry() {
'plugin' => 'context_condition_path',
),
'query_string' => array(
- 'title' => t('Query String'),
+ 'title' => t('Query string'),
'description' => t('Set this context when any of the query strings above match the page query string. Put each query string on a separate line. You can use the "*" character as a wildcard and ~ to exclude one or more query strings.'),
'plugin' => 'context_condition_query_string',
),
@@ -119,7 +119,7 @@ function _context_context_registry() {
'plugin' => 'context_reaction_template_suggestions',
),
'theme' => array(
- 'title' => t('Theme Page'),
+ 'title' => t('Theme page'),
'description' => t('Control page theme variables using context.'),
'plugin' => 'context_reaction_theme',
),
diff --git a/sites/all/modules/contrib/admin/context/context_layouts/context_layouts.info b/sites/all/modules/contrib/admin/context/context_layouts/context_layouts.info
index 5ddb2cfb..129c4cdb 100644
--- a/sites/all/modules/contrib/admin/context/context_layouts/context_layouts.info
+++ b/sites/all/modules/contrib/admin/context/context_layouts/context_layouts.info
@@ -6,9 +6,9 @@ core = 7.x
files[] = plugins/context_layouts_reaction_block.inc
-; Information added by Drupal.org packaging script on 2015-01-06
-version = "7.x-3.6"
+; Information added by Drupal.org packaging script on 2016-05-18
+version = "7.x-3.7"
core = "7.x"
project = "context"
-datestamp = "1420573188"
+datestamp = "1463605446"
diff --git a/sites/all/modules/contrib/admin/context/context_ui/context_ui.info b/sites/all/modules/contrib/admin/context/context_ui/context_ui.info
index 00066996..e6c51051 100644
--- a/sites/all/modules/contrib/admin/context/context_ui/context_ui.info
+++ b/sites/all/modules/contrib/admin/context/context_ui/context_ui.info
@@ -8,9 +8,9 @@ configure = admin/structure/context
files[] = context.module
files[] = tests/context_ui.test
-; Information added by Drupal.org packaging script on 2015-01-06
-version = "7.x-3.6"
+; Information added by Drupal.org packaging script on 2016-05-18
+version = "7.x-3.7"
core = "7.x"
project = "context"
-datestamp = "1420573188"
+datestamp = "1463605446"
diff --git a/sites/all/modules/contrib/admin/context/context_ui/context_ui.js b/sites/all/modules/contrib/admin/context/context_ui/context_ui.js
index 308164ff..56aa62a1 100644
--- a/sites/all/modules/contrib/admin/context/context_ui/context_ui.js
+++ b/sites/all/modules/contrib/admin/context/context_ui/context_ui.js
@@ -12,11 +12,11 @@ function DrupalContextPlugins(form) {
$('.context-plugin-list > li', this.form).each(function() {
var plugin = $(this).attr('class').split('context-plugin-')[1].split(' ')[0];
if ($(this).is('.disabled')) {
- $('.context-plugin-selector select option[value='+plugin+']', this.form).show();
+ $('.context-plugin-selector select option[value="'+plugin+'"]', this.form).show();
}
else {
state.push(plugin);
- $('.context-plugin-selector select option[value='+plugin+']', this.form).hide();
+ $('.context-plugin-selector select option[value="'+plugin+'"]', this.form).hide();
}
});
// Set the hidden plugin list state.
diff --git a/sites/all/modules/contrib/admin/context/context_ui/context_ui.module b/sites/all/modules/contrib/admin/context/context_ui/context_ui.module
index 2ed2aa68..d6948705 100644
--- a/sites/all/modules/contrib/admin/context/context_ui/context_ui.module
+++ b/sites/all/modules/contrib/admin/context/context_ui/context_ui.module
@@ -81,7 +81,7 @@ function context_ui_permission() {
'description' => 'Associate menus, views, blocks, etc. with different contexts to structure your site.'
);
$permissions['context ajax block access'] = array(
- 'title' => t('Access All Blocks'),
+ 'title' => t('Access all blocks'),
'description' => t('Allows users to access all rendered blocks via an AJAX callback. If you have some blocks that should not be rendered for some users but need those users to be able to use context UI, then implement hook_context_allow_ajax_block_access with the necessary logic.'),
);
return $permissions;
@@ -143,7 +143,7 @@ function context_ui_editor($form, &$form_state, $contexts) {
$form['title'] = array(
'#prefix' => '
',
- '#markup' => t('Select the Context/Layer to Edit'),
+ '#markup' => t('Select the context/layer to edit'),
'#suffix' => '
',
'#weight' => -2,
);
@@ -151,10 +151,7 @@ function context_ui_editor($form, &$form_state, $contexts) {
//add some help text to the top of the form
$form['help'] = array (
'#prefix' => '
',
- '#markup' => t('Select which context, or layer of blocks, to edit.
- Each context is configured to appear on different sets of pages so read the description carefully.
- When you are done editing click Done and save your changes.
- You may use the Stop Editing Layout link to close the editor.'),
+ '#markup' => t('Select which context, or layer of blocks, to edit. Each context is configured to appear on different sets of pages so read the description carefully. When you are done editing click Done and save your changes. You may use the Stop Editing Layout link to close the editor.'),
'#suffix' => '
";
+ $output .= '';
$output .= theme('table', array('rows' => $rows, 'attributes' => $attr));
}
return $output;
@@ -100,14 +100,13 @@ function template_preprocess_context_block_browser(&$vars) {
//add help text to tell people how to use the block browser
$help_text = array(
'#prefix' => '
',
- '#markup' => t('To add a block to the current region, simply click on the block. You may use the category filter to filter by
- block type or the search filter to find the block that you wish to add.'),
+ '#markup' => t('To add a block to the current region, simply click on the block. You may use the category filter to filter by block type or the search filter to find the block that you wish to add.'),
'#suffix' => '
',
);
diff --git a/sites/all/modules/contrib/admin/features/features.admin.inc b/sites/all/modules/contrib/admin/features/features.admin.inc
index c2cc5089..46752c89 100644
--- a/sites/all/modules/contrib/admin/features/features.admin.inc
+++ b/sites/all/modules/contrib/admin/features/features.admin.inc
@@ -88,6 +88,12 @@ function features_settings_form($form, $form_state) {
'#default_value' => variable_get('features_rebuild_on_flush', TRUE),
'#description' => t('If you have a large site with many features, you may experience lag on full cache clear. If disabled, features will rebuild only when viewing the features list or saving the modules list.'),
);
+ $form['general']['features_rebuild_modules_page'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Rebuild features on accessing modules list page'),
+ '#default_value' => variable_get('features_rebuild_modules_page', FALSE),
+ '#description' => t('If you have a large site with many features, you may experience lag on accessing the modules administration page. If disabled, features will not rebuild when viewing the modules list.'),
+ );
return system_settings_form($form);
}
@@ -109,7 +115,7 @@ function features_export_form($form, $form_state, $feature = NULL) {
$feature_name = !empty($feature->name) ? $feature->name : '';
$form = array(
- '#attributes' => array('class' => array('features-export-form')),
+ '#attributes' => array('class' => array('features-export-form', 'clearfix')),
'#feature' => isset($feature) ? $feature : NULL,
);
$form['info'] = array(
@@ -203,7 +209,7 @@ function features_export_form($form, $form_state, $feature = NULL) {
$form['advanced']['generate'] = array(
'#type' => 'submit',
'#value' => t('Generate feature'),
- '#submit' => array('features_export_build_form_submit'),
+ '#submit' => array('features_export_build_form_submit', 'features_form_rebuild'),
);
}
// build the Component Listing panel on the right
@@ -239,7 +245,7 @@ function features_export_form($form, $form_state, $feature = NULL) {
'#type' => 'submit',
'#value' => t('Download feature'),
'#weight' => 10,
- '#submit' => array('features_export_build_form_submit'),
+ '#submit' => array('features_export_build_form_submit', 'features_form_rebuild'),
);
$form['#attached']['library'][] = array('system', 'ui.dialog');
@@ -597,6 +603,7 @@ function _features_export_build($feature, &$form_state) {
$component_export['selected'][$section] = array();
}
$options = features_invoke($component, 'features_export_options');
+ drupal_alter('features_export_options', $options, $component);
if (!empty($options)) {
$exported_components = !empty($exported_features_info[$component]) ? $exported_features_info[$component] : array();
$new_components = !empty($new_features_info[$component]) ? $new_features_info[$component] : array();
@@ -755,7 +762,7 @@ function features_export_form_rebuild($form, &$form_state) {
function features_export_components_json($feature_name) {
module_load_include('inc', 'features', 'features.export');
- $export = array();
+ $export = array('features' => array());
if (!empty($_POST['items'])) {
$excluded = (!empty($_POST['excluded'])) ? $_POST['excluded'] : array();
$stub = array();
@@ -843,7 +850,7 @@ function _features_export_generate($export, $form_state, $feature = NULL) {
}
// If either update status-related keys are provided, add a project key
// corresponding to the module name.
- if (!empty($form_state['values']['version']) || !empty($form_state['values']['project_status_url'])) {
+ if (!empty($form_state['values']['version']) && !empty($form_state['values']['project_status_url'])) {
$export['project'] = $form_state['values']['module_name'];
}
if (!empty($form_state['values']['version'])) {
@@ -900,6 +907,35 @@ function features_export_build_form_submit($form, &$form_state) {
$tar = array();
$filenames = array();
+ // Copy any files if _files key is there.
+ if (!empty($files['_files'])) {
+ foreach ($files['_files'] as $file_name => $file_info) {
+ if ($generate) {
+ // See if files are in a sub directory.
+ if (strpos($file_name, '/')) {
+ $file_directory = $directory . '/' . substr($file_name, 0, strrpos($file_name, '/'));
+ if (!is_dir($file_directory)) {
+ mkdir($file_directory);
+ }
+ }
+ if (!empty($file_info['file_path'])) {
+ file_unmanaged_copy($file_info['file_path'], "{$directory}/{$file_name}", FILE_EXISTS_REPLACE);
+ }
+ elseif ($file_info['file_content']) {
+ file_put_contents("{$directory}/{$file_name}", $file_info['file_content']);
+ }
+ }
+ else {
+ if (!empty($file_info['file_path'])) {
+ print features_tar_create("{$module_name}/{$file_name}", file_get_contents($file_info['file_path']));
+ }
+ elseif ($file_info['file_content']) {
+ features_tar_create("{$directory}/{$file_name}", $file_info['file_content']);
+ }
+ }
+ }
+ unset($files['_files']);
+ }
foreach ($files as $extension => $file_contents) {
if (!in_array($extension, array('module', 'info'))) {
$extension .= '.inc';
@@ -973,28 +1009,14 @@ function features_filter_hidden($module) {
* Form constructor for the features configuration form.
*/
function features_admin_form($form, $form_state) {
+ $features = _features_get_features_list();
+ $modules = array_filter(features_get_modules(), 'features_filter_hidden');
+ $conflicts = features_get_conflicts();
+
// Load export functions to use in comparison.
module_load_include('inc', 'features', 'features.export');
- // Clear & rebuild key caches
- features_get_info(NULL, NULL, TRUE);
- features_rebuild();
-
- $modules = array_filter(features_get_modules(), 'features_filter_hidden');
- $features = array_filter(features_get_features(), 'features_filter_hidden');
- $conflicts = features_get_conflicts();
-
- foreach ($modules as $key => $module) {
- if ($module->status && !empty($module->info['dependencies'])) {
- foreach ($module->info['dependencies'] as $dependent) {
- if (isset($features[$dependent])) {
- $features[$dependent]->dependents[$key] = $module->info['name'];
- }
- }
- }
- }
-
- if ( empty($features) ) {
+ if (empty($features) ) {
$form['no_features'] = array(
'#markup' => t('No Features were found. Please use the !create_link link to create
a new Feature module, or upload an existing Feature to your modules directory.',
@@ -1073,6 +1095,7 @@ function features_admin_form($form, $form_state) {
}
$href = "admin/structure/features/{$name}";
+ $href_overridden = module_exists('diff') ? $href . '/diff' : $href;
$module_name = (user_access('administer features')) ? l($module->info['name'], $href) : $module->info['name'];
$form[$package]['status'][$name] = array(
'#type' => 'checkbox',
@@ -1102,7 +1125,7 @@ function features_admin_form($form, $form_state) {
$state .= l(t('Check'), "admin/structure/features/{$name}/status", array('attributes' => array('class' => array('admin-check'))));
$state .= theme('features_storage_link', array('storage' => FEATURES_REBUILDING, 'path' => $href));
$state .= theme('features_storage_link', array('storage' => FEATURES_NEEDS_REVIEW, 'path' => $href));
- $state .= theme('features_storage_link', array('storage' => FEATURES_OVERRIDDEN, 'path' => $href));
+ $state .= theme('features_storage_link', array('storage' => FEATURES_OVERRIDDEN, 'path' => $href_overridden));
$state .= theme('features_storage_link', array('storage' => FEATURES_DEFAULT, 'path' => $href));
}
elseif (!empty($conflicts[$name])) {
@@ -1126,7 +1149,7 @@ function features_admin_form($form, $form_state) {
// As of 7.0 beta 2 it matters where the "vertical_tabs" element lives on the
// the array. We add it late, but at the beginning of the array because that
// keeps us away from trouble.
- $form = array('packages' => array('#type' => 'vertical_tabs')) + $form;
+ $form = array_merge(array('packages' => array('#type' => 'vertical_tabs')), $form);
$form['buttons'] = array(
'#theme' => 'features_form_buttons',
@@ -1311,7 +1334,7 @@ function features_form_submit(&$form, &$form_state) {
// page callback rather than as part of the submit handler as some modules
// have includes/other directives of importance in hooks that have already
// been called in this page load.
- $form_state['redirect'] = 'admin/structure/features/cleanup/clear';
+ $form_state['redirect'] = array('admin/structure/features/cleanup', array('query' => array('token' => drupal_get_token())));
$features = $form['#features'];
if (!empty($features)) {
@@ -1328,21 +1351,26 @@ function features_form_submit(&$form, &$form_state) {
}
/**
- * Form for clearing cache after enabling a feature.
+ * Submit handler for the 'manage features' form rebuild button.
*/
-function features_cleanup_form($form, $form_state, $cache_clear = FALSE) {
- // Clear caches if we're getting a post-submit redirect that requests it.
- if ($cache_clear) {
- drupal_flush_all_caches();
+function features_form_rebuild() {
+ cache_clear_all('features:features_list', 'cache');
+}
+/**
+ * Callback for clearing cache after enabling a feature.
+ */
+function features_cleanup() {
+ if (!empty($_GET['token']) && drupal_valid_token($_GET['token'])) {
+ drupal_flush_all_caches();
// The following functions need to be run because drupal_flush_all_caches()
// runs rebuilds in the wrong order. The node type cache is rebuilt *after*
// the menu is rebuilt, meaning that the menu tree is stale in certain
// circumstances after drupal_flush_all_caches(). We rebuild again.
menu_rebuild();
- }
-
drupal_goto('admin/structure/features');
+ }
+ return MENU_NOT_FOUND;
}
/**
@@ -1587,3 +1615,42 @@ function _features_get_used($module_name = NULL) {
$features_ignore_conflicts = $old_value;
return $conflicts;
}
+
+/**
+ * Retrieves the array of features as expected on the Manage Features form.
+ * Uses caching for performance reasons if caching is enabled.
+ *
+ * @internal - This function might return cached result with outdated data,
+ * use with caution.
+ */
+function _features_get_features_list() {
+ $features = array();
+
+ $cache = cache_get('features:features_list');
+ if ($cache) {
+ $features = $cache->data;
+ }
+
+ if (empty($features)) {
+ // Clear & rebuild key caches
+ features_get_info(NULL, NULL, TRUE);
+ features_rebuild();
+
+ $modules = array_filter(features_get_modules(), 'features_filter_hidden');
+ $features = array_filter(features_get_features(), 'features_filter_hidden');
+
+ foreach ($modules as $key => $module) {
+ if ($module->status && !empty($module->info['dependencies'])) {
+ foreach ($module->info['dependencies'] as $dependent) {
+ if (isset($features[$dependent])) {
+ $features[$dependent]->dependents[$key] = $module->info['name'];
+ }
+ }
+ }
+ }
+
+ cache_set('features:features_list', $features);
+ }
+
+ return $features;
+}
diff --git a/sites/all/modules/contrib/admin/features/features.api.php b/sites/all/modules/contrib/admin/features/features.api.php
index f5984e0c..d7c7edec 100644
--- a/sites/all/modules/contrib/admin/features/features.api.php
+++ b/sites/all/modules/contrib/admin/features/features.api.php
@@ -42,7 +42,7 @@
* are declared "dynamically" or are part of a family of components.
*
* 'alter_type': What type of alter hook this hook uses. 'normal' is called
- * after the main hook is called. 'inline' is embeded within the default hook
+ * after the main hook is called. 'inline' is embedded within the default hook
* and may not be implemented by some default hooks.
* 'none' is no alter hook exists. Defaults to 'normal'
*
@@ -157,7 +157,8 @@ function hook_features_export_options() {
* of the module, e.g. the key for `hook_example` should simply be `example`
* The values in the array can also be in the form of an associative array
* with the required key of 'code' and optional key of 'args', if 'args' need
- * to be added to the hook.
+ * to be added to the hook. Alternate it can be an associative array in the
+ * same style as hook_features_export_files() to add additional files.
*/
function hook_features_export_render($module_name, $data, $export = NULL) {
$code = array();
@@ -309,11 +310,31 @@ function hook_features_pipe_COMPONENT_alter(&$pipe, $data, $export) {
* The module being exported contained in $export['module_name'].
*/
function hook_features_pipe_alter(&$pipe, $data, $export) {
- if ($export['component'] == 'node' && in_array($data, 'my-node-type')) {
+ if ($export['component'] == 'node' && in_array('my-node-type', $data)) {
$pipe['dependencies'][] = 'mymodule';
}
}
+
+/**
+ * Add extra files to the exported file.
+ *
+ * @return array
+ * An array of files, keyed by file name that will appear in feature and
+ * with either file_path key to indicate where to copy the file from or
+ * file_content key to indicate the contents of the file.
+ */
+function hook_features_export_files($module_name, $export) {
+ return array('css/main.css' => array('file_content' => 'body {background-color:blue;}'));
+}
+
+/**
+ * Alter the extra files added to the export.
+ */
+function hook_features_export_files_alter(&$files, $module_name, $export) {
+ $files['css/main.css']['file_content'] = 'body {background-color:black;}';
+}
+
/**
* @defgroup features_component_alter_hooks Feature's component alter hooks
* @{
diff --git a/sites/all/modules/contrib/admin/features/features.drush.inc b/sites/all/modules/contrib/admin/features/features.drush.inc
index c1a15ac8..696825d6 100644
--- a/sites/all/modules/contrib/admin/features/features.drush.inc
+++ b/sites/all/modules/contrib/admin/features/features.drush.inc
@@ -32,6 +32,12 @@ function features_drush_command() {
),
'drupal dependencies' => array('features'),
'aliases' => array('fl', 'features'),
+ 'outputformat' => array(
+ 'default' => 'table',
+ 'pipe-format' => 'list',
+ 'field-labels' => array('name' => 'Name', 'feature' => 'Feature', 'status' => 'Status', 'version' => 'Version', 'state' => 'State'),
+ 'output-data-type' => 'format-table',
+ ),
);
$items['features-export'] = array(
'description' => "Export a feature from your site into a module.",
@@ -43,6 +49,7 @@ function features_drush_command() {
'destination' => "Destination path (from Drupal root) of the exported feature. Defaults to '" . $path . "'.",
'version-set' => "Specify a version number for the feature.",
'version-increment' => "Increment the feature's version number.",
+ 'ignore-conflicts' => "Ignore conflicts and export all components.",
),
'drupal dependencies' => array('features'),
'aliases' => array('fe'),
@@ -72,6 +79,9 @@ function features_drush_command() {
'not-exported' => array(
'description' => 'Show only components that have not been exported.',
),
+ 'info-style' => array(
+ 'description' => 'Export components in format suitable for using in an info file.',
+ ),
),
'aliases' => array('fc'),
);
@@ -134,6 +144,18 @@ function features_drush_command() {
'aliases' => array('fd'),
);
+ $items['features-diff-all'] = array(
+ 'description' => "Show the code difference for all enabled features not in their default state.",
+ 'arguments' => array(
+ 'feature_exclude' => 'A space-delimited list of features to exclude from being reverted.',
+ ),
+ 'options' => array(
+ 'force' => "Bypass the confirmations. This is useful if you want to output all of the diffs to a log file.",
+ ),
+ 'drupal dependencies' => array('features', 'diff'),
+ 'aliases' => array('fda'),
+ );
+
return $items;
}
@@ -191,12 +213,12 @@ function drush_features_list() {
}
module_load_include('inc', 'features', 'features.export');
- $rows = array(array(dt('Name'), dt('Feature'), dt('Status'), dt('Version'), dt('State')));
// Sort the Features list before compiling the output.
$features = features_get_features(NULL, TRUE);
ksort($features);
+ $rows = array();
foreach ($features as $k => $m) {
switch (features_get_storage($m->name)) {
case FEATURES_DEFAULT:
@@ -214,16 +236,19 @@ function drush_features_list() {
($m->status == 0 && ($status == 'all' || $status == 'disabled')) ||
($m->status == 1 && ($status == 'all' || $status == 'enabled'))
) {
- $rows[] = array(
- $m->info['name'],
- $m->name,
- $m->status ? dt('Enabled') : dt('Disabled'),
- $m->info['version'],
- $storage
+ $rows[$k] = array(
+ 'name' => $m->info['name'],
+ 'feature' => $m->name,
+ 'status' => $m->status ? dt('Enabled') : dt('Disabled'),
+ 'version' => $m->info['version'],
+ 'state' => $storage
);
}
}
- drush_print_table($rows, TRUE);
+ if (version_compare(DRUSH_VERSION, '6.0', '<')) {
+ drush_print_table($rows, TRUE);
+ }
+ return $rows;
}
/**
@@ -253,10 +278,13 @@ function drush_features_components() {
elseif (drush_get_option(array('not-exported', 'o'), NULL)) {
$options['exported'] = FALSE;
}
+ if (drush_get_option(array('info-style', 'is'), NULL)) {
+ $options['info style'] = TRUE;
+ }
$filtered_components = _drush_features_component_filter($components, $args, $options);
if ($filtered_components){
- _drush_features_component_print($filtered_components);
+ _drush_features_component_print($filtered_components, $options);
}
}
@@ -290,7 +318,7 @@ function _drush_features_component_filter($all_components, $patterns = array(),
// First filter on exported state.
foreach ($all_components as $source => $components) {
foreach ($components as $name => $title) {
- $exported = sizeof($components_map[$source][$name]) > 0;
+ $exported = !empty($components_map[$source][$name]);
if ($exported) {
if ($options['exported']) {
$pool[$source][$name] = $title;
@@ -318,7 +346,13 @@ function _drush_features_component_filter($all_components, $patterns = array(),
// Rewrite * to %. Let users use both as wildcard.
$pattern = strtr($pattern, array('*' => '%'));
$sources = array();
- list($source_pattern, $component_pattern) = explode(':', $pattern, 2);
+ if (strpos($pattern, ':') !== FALSE) {
+ list($source_pattern, $component_pattern) = explode(':', $pattern, 2);
+ }
+ else {
+ $source_pattern = $pattern;
+ $component_pattern = '';
+ }
// If source is empty, use a pattern.
if ($source_pattern == '') {
$source_pattern = '%';
@@ -383,7 +417,7 @@ function _drush_features_component_filter($all_components, $patterns = array(),
return drush_set_error('', dt('Ambiguous component "!component", matches !matches', array('!component' => $component_pattern, '!matches' => join(', ', $matches))));
}
}
- if (!is_array($selected[$source])) {
+ if (empty($selected[$source])) {
$selected[$source] = array();
}
$selected[$source] += array_intersect_key($pool[$source], array_flip($matches));
@@ -404,7 +438,7 @@ function _drush_features_component_filter($all_components, $patterns = array(),
if ($options['provided by'] && $options['exported'] ) {
foreach ($selected as $source => $components) {
foreach ($components as $name => $title) {
- $exported = sizeof($components_map[$source][$name]) > 0;
+ $exported = !empty($components_map[$source][$name]);
if ($exported) {
$provided_by[$source . ':' . $name] = join(', ', $components_map[$source][$name]);
}
@@ -421,11 +455,17 @@ function _drush_features_component_filter($all_components, $patterns = array(),
/**
* Prints a list of filtered components.
*/
-function _drush_features_component_print($filtered_components) {
+function _drush_features_component_print($filtered_components, $options = array()) {
$rows = array(array(dt('Available sources')));
foreach ($filtered_components['components'] as $source => $components) {
foreach ($components as $name => $value) {
- $row = array($source .':'. $name);
+ if (!empty($options['info style'])) {
+ // Output as .info file style.
+ $row = array('features[' . $source . '][] = "' . $name . '"');
+ }
+ else {
+ $row = array($source .':'. $name);
+ }
if (isset($filtered_components['sources'][$source .':'. $name])) {
$row[] = dt('Provided by') . ': ' . $filtered_components['sources'][$source .':'. $name];
}
@@ -447,9 +487,11 @@ function drush_features_export() {
return drush_set_error('', 'No components supplied.');
}
$components = _drush_features_component_list();
- $options = array(
- 'exported' => FALSE,
- );
+ $options = array();
+
+ if (!drush_get_option('ignore-conflicts', FALSE)) {
+ $options['exported'] = FALSE;
+ }
$filtered_components = _drush_features_component_filter($components, $args, $options);
$items = $filtered_components['components'];
@@ -579,9 +621,40 @@ function _drush_features_export($info, $module_name = NULL, $directory = NULL) {
drush_op('mkdir', $directory);
}
if (is_dir($directory)) {
+ // Ensure that the export will be created in the English language.
+ // The export language must be set before flushing caches as that can
+ // result into translatables being statically cached.
+ $language = _features_export_language();
+
drupal_flush_all_caches();
$export = _drush_features_generate_export($info, $module_name);
$files = features_export_render($export, $module_name, TRUE);
+
+ // Restore the language
+ _features_export_language($language);
+
+ // Copy any files if _files key is there.
+ if (!empty($files['_files'])) {
+ foreach ($files['_files'] as $file_name => $file_info) {
+ // See if files are in a sub directory.
+ if (strpos($file_name, '/')) {
+ $file_directory = $directory . '/' . substr($file_name, 0, strrpos($file_name, '/'));
+ if (!is_dir($file_directory)) {
+ drush_op('mkdir', $file_directory);
+ }
+ }
+ if (!empty($file_info['file_path'])) {
+ drush_op('file_unmanaged_copy', $file_info['file_path'], "{$directory}/{$file_name}", FILE_EXISTS_REPLACE);
+ }
+ elseif (!empty($file_info['file_content'])) {
+ drush_op('file_put_contents', "{$directory}/{$file_name}", $file_info['file_content']);
+ }
+ else {
+ drush_log(dt("Entry for @file_name.in !module is invalid. ", array('!module' => $module_name, '@file_name' => $file_name)), 'ok');
+ }
+ }
+ unset($files['_files']);
+ }
foreach ($files as $extension => $file_contents) {
if (!in_array($extension, array('module', 'info'))) {
$extension .= '.inc';
@@ -635,7 +708,7 @@ function _drush_features_generate_export(&$info, &$module_name) {
}
else {
// Split version number parts.
- $pattern = '/([0-9]-[a-z]+([0-9])+)/';
+ $pattern = '/([0-9]-[a-z]+([0-9]+))/';
$matches = array();
preg_match($pattern, $version_minor, $matches);
$number = array_pop($matches);
@@ -747,7 +820,7 @@ function drush_features_revert() {
}
}
else {
- drush_features_list();
+ drush_print_table(drush_features_list());
return;
}
}
@@ -801,7 +874,7 @@ function drush_features_revert_all() {
*/
function drush_features_diff() {
if (!$args = func_get_args()) {
- drush_features_list();
+ drush_print_table(drush_features_list());
return;
}
$module = $args[0];
@@ -886,6 +959,62 @@ function drush_features_diff() {
}
}
+/**
+ * Diff all enabled features that are not in their default state.
+ *
+ * @param ...
+ * (Optional) A list of features to exclude from being reverted.
+ */
+function drush_features_diff_all() {
+ module_load_include('inc', 'features', 'features.export');
+ $features_to_exclude = func_get_args();
+
+ $features_to_revert = array();
+ foreach (features_get_features(NULL, TRUE) as $module) {
+ if ($module->status && !in_array($module->name, $features_to_exclude)) {
+ switch (features_get_storage($module->name)) {
+ case FEATURES_OVERRIDDEN:
+ case FEATURES_NEEDS_REVIEW:
+ case FEATURES_REBUILDABLE:
+ $features_to_diff[] = $module->name;
+ break;
+ }
+ }
+ }
+
+ if ($features_to_diff) {
+
+ // Check if the user wants to apply the force option.
+ $force = drush_get_option('force');
+
+ if($force) {
+ foreach ($features_to_diff as $module) {
+
+ drush_print(dt('Diff for !module:', array('!module' => $module)));
+
+ drush_invoke_process(drush_sitealias_get_record('@self'), 'features-diff', array($module));
+ }
+ }
+ else {
+
+ drush_print(dt('A diff will be performed for the following modules: !modules',
+ array('!modules' => implode(', ', $features_to_diff))
+ ));
+
+ if (drush_confirm(dt('Do you want to continue?'))) {
+ foreach ($features_to_diff as $module) {
+ if (drush_confirm(dt('Diff !module?', array('!module' => $module)))) {
+ drush_invoke_process(drush_sitealias_get_record('@self'), 'features-diff', array($module));
+ }
+ }
+ }
+ else {
+ return drush_user_abort('Aborting.');
+ }
+ }
+ }
+}
+
/**
* Helper function to call drush_set_error().
*
diff --git a/sites/all/modules/contrib/admin/features/features.export.inc b/sites/all/modules/contrib/admin/features/features.export.inc
index 154b26bc..5045b131 100644
--- a/sites/all/modules/contrib/admin/features/features.export.inc
+++ b/sites/all/modules/contrib/admin/features/features.export.inc
@@ -45,6 +45,9 @@ function features_populate($info, $module_name) {
* @return fully populated $export array.
*/
function _features_populate($pipe, &$export, $module_name = '', $reset = FALSE) {
+ // Ensure that the export will be created in the english language.
+ $language = _features_export_language();
+
if ($reset) {
drupal_static_reset(__FUNCTION__);
}
@@ -89,6 +92,7 @@ function _features_populate($pipe, &$export, $module_name = '', $reset = FALSE)
}
}
}
+ _features_export_language($language);
return $export;
}
@@ -295,6 +299,11 @@ function features_export_render($export, $module_name, $reset = FALSE) {
}
foreach ($hooks as $hook_name => $hook_info) {
+ // These are purely files that will be copied over.
+ if (is_array($hook_info) && (!empty($hook_info['file_path']) || !empty($hook_info['file_content']))) {
+ $code['_files'][$hook_name] = $hook_info;
+ continue;
+ }
$hook_code = is_array($hook_info) ? $hook_info['code'] : $hook_info;
$hook_args = is_array($hook_info) && !empty($hook_info['args']) ? $hook_info['args'] : '';
$hook_file = is_array($hook_info) && !empty($hook_info['file']) ? $hook_info['file'] : $file['name'];
@@ -305,7 +314,17 @@ function features_export_render($export, $module_name, $reset = FALSE) {
// Finalize strings to be written to files
$code = array_filter($code);
foreach ($code as $filename => $contents) {
- $code[$filename] = "info);
- _features_sanitize($export);
+ features_sanitize($module->info);
+ features_sanitize($export);
$compare = array('normal' => features_export_info($export), 'default' => features_export_info($module->info));
if ($compare['normal'] !== $compare['default']) {
@@ -408,8 +427,8 @@ function features_detect_overrides($module) {
if ($state != FEATURES_DEFAULT) {
$normal = features_get_normal($component, $module->name);
$default = features_get_default($component, $module->name);
- _features_sanitize($normal);
- _features_sanitize($default);
+ features_sanitize($normal, $component);
+ features_sanitize($default, $component);
$compare = array('normal' => features_var_export($normal), 'default' => features_var_export($default));
if (_features_linetrim($compare['normal']) !== _features_linetrim($compare['default'])) {
@@ -663,8 +682,7 @@ function features_get_signature($state = 'default', $module_name, $component, $r
break;
}
if (!empty($objects)) {
- $objects = (array) $objects;
- _features_sanitize($objects);
+ features_sanitize($objects, $component);
return md5(_features_linetrim(features_var_export($objects)));
}
return FALSE;
@@ -721,7 +739,7 @@ function features_get_normal($component, $module_name, $reset = FALSE) {
// Special handling for dependencies component.
if ($component === 'dependencies') {
- $cache[$module_name][$component] = isset($module->info['dependencies']) ? array_filter($module->info['dependencies'], 'module_exists') : array();
+ $cache[$module_name][$component] = isset($module->info['dependencies']) ? array_filter($module->info['dependencies'], '_features_module_exists') : array();
}
// All other components.
else {
@@ -739,6 +757,17 @@ function features_get_normal($component, $module_name, $reset = FALSE) {
return isset($cache[$module_name][$component]) ? $cache[$module_name][$component] : FALSE;
}
+/**
+ * Helper function to determine if a module is enabled
+ * @param $module
+ * This module name comes from the .info file and can have version info in it.
+ */
+function _features_module_exists($module) {
+ $parsed_dependency = drupal_parse_dependency($module);
+ $name = $parsed_dependency['name'];
+ return module_exists($name);
+}
+
/**
* Get defaults for a given module/component pair.
*/
@@ -815,6 +844,13 @@ function features_get_default($component, $module_name = NULL, $alter = TRUE, $r
/**
* Get a map of components to their providing modules.
+ *
+ * @param string $component
+ * @param string $attribute
+ * @param callable $callback
+ * @param bool $reset
+ *
+ * @return array|bool
*/
function features_get_default_map($component, $attribute = NULL, $callback = NULL, $reset = FALSE) {
$map = &drupal_static(__FUNCTION__, array());
@@ -863,6 +899,9 @@ function features_get_default_map($component, $attribute = NULL, $callback = NUL
* Retrieve an array of features/components and their current states.
*/
function features_get_component_states($features = array(), $rebuild_only = TRUE, $reset = FALSE) {
+ // Ensure that the export will be created in the English language.
+ $language = _features_export_language();
+
if ($reset) {
drupal_static_reset(__FUNCTION__);
}
@@ -873,7 +912,7 @@ function features_get_component_states($features = array(), $rebuild_only = TRUE
// Retrieve only rebuildable components if requested.
features_include();
- $components = array_keys(features_get_components());
+ $components = array_keys(features_get_components(NULL, NULL, $reset));
if ($rebuild_only) {
foreach ($components as $k => $component) {
if (!features_hook($component, 'features_rebuild')) {
@@ -956,6 +995,9 @@ function features_get_component_states($features = array(), $rebuild_only = TRUE
foreach ($return as $k => $v) {
$return[$k] = array_intersect_key($return[$k], array_flip($components));
}
+
+ _features_export_language($language);
+
return $return;
}
@@ -970,25 +1012,49 @@ function _features_linetrim($code) {
return implode("\n", $code);
}
+/**
+ * Helper function to "sanitize" an array or object.
+ * Converts everything to an array, sorts the keys, removes recursion.
+ * @param $array
+ * @param $component string name of component
+ * @param bool $remove_empty if set, remove null or empty values for assoc arrays.
+ */
+function features_sanitize(&$array, $component = NULL, $remove_empty = TRUE) {
+ $array = features_remove_recursion($array);
+ if (isset($component)) {
+ $ignore_keys = _features_get_ignore_keys($component);
+ // remove keys to be ignored
+ if (count($ignore_keys)) {
+ _features_remove_ignores($array, $ignore_keys);
+ }
+ }
+ _features_sanitize($array, $remove_empty);
+}
+
/**
* "Sanitizes" an array recursively, performing two key operations:
* - Sort an array by its keys (assoc) or values (non-assoc)
- * - Remove any null or empty values for associative arrays (array_filter()).
+ * @param bool $remove_empty if set, remove null or empty values for assoc arrays.
*/
-function _features_sanitize(&$array) {
+function _features_sanitize(&$array, $remove_empty = TRUE) {
+ if (is_object($array)) {
+ $array = get_object_vars($array);
+ }
if (is_array($array)) {
$is_assoc = _features_is_assoc($array);
if ($is_assoc) {
ksort($array, SORT_STRING);
- $array = array_filter($array);
+ if ($remove_empty) {
+ $array = array_filter($array);
+ }
}
else {
sort($array);
}
foreach ($array as $k => $v) {
- if (is_array($v)) {
+ if (is_array($v) or is_object($v)) {
_features_sanitize($array[$k]);
- if ($is_assoc && empty($array[$k])) {
+ if ($remove_empty && $is_assoc && empty($array[$k])) {
unset($array[$k]);
}
}
@@ -1010,3 +1076,92 @@ function _features_sanitize(&$array) {
function _features_is_assoc($array) {
return (is_array($array) && (0 !== count(array_diff_key($array, array_keys(array_keys($array)))) || count($array)==0));
}
+
+/**
+ * Removes recursion from an object or array.
+ *
+ * Taken from https://code.google.com/p/formaldehyde/source/browse/trunk/formaldehyde.php
+ * Also used in node_export module
+ *
+ * @param $o mixed
+ * @return mixed
+ * returns a copy of the object or array with recursion removed
+ */
+function features_remove_recursion($o) {
+ static $replace;
+ if (!isset($replace)) {
+ $replace = create_function(
+ '$m',
+ '$r="\x00{$m[1]}ecursion_features";return \'s:\'.strlen($r.$m[2]).\':"\'.$r.$m[2].\'";\';'
+ );
+ }
+ if (is_array($o) || is_object($o)) {
+ $re = '#(r|R):([0-9]+);#';
+ $serialize = serialize($o);
+ if (preg_match($re, $serialize)) {
+ $last = $pos = 0;
+ while (false !== ($pos = strpos($serialize, 's:', $pos))) {
+ $chunk = substr($serialize, $last, $pos - $last);
+ if (preg_match($re, $chunk)) {
+ $length = strlen($chunk);
+ $chunk = preg_replace_callback($re, $replace, $chunk);
+ $serialize = substr($serialize, 0, $last) . $chunk . substr($serialize, $last + ($pos - $last));
+ $pos += strlen($chunk) - $length;
+ }
+ $pos += 2;
+ $last = strpos($serialize, ':', $pos);
+ $length = substr($serialize, $pos, $last - $pos);
+ $last += 4 + $length;
+ $pos = $last;
+ }
+ $serialize = substr($serialize, 0, $last) . preg_replace_callback($re, $replace, substr($serialize, $last));
+ $o = unserialize($serialize);
+ }
+ }
+ return $o;
+}
+
+/**
+ * Helper to removes a set of keys an object/array.
+ *
+ * @param $item
+ * An object or array passed by reference.
+ * @param $ignore_keys
+ * Array of keys to be ignored. Values are the level of the key.
+ * @param $level
+ * Level of key to remove. Up to 2 levels deep because $item can still be
+ * recursive
+ */
+function _features_remove_ignores(&$item, $ignore_keys, $level = -1) {
+ $is_object = is_object($item);
+ if (!is_array($item) && !is_object($item)) {
+ return;
+ }
+ foreach ($item as $key => &$value) {
+ if (isset($ignore_keys[$key]) && ($ignore_keys[$key] == $level)) {
+ if ($is_object) {
+ unset($item->$key);
+ }
+ else {
+ unset($item[$key]);
+ }
+ }
+ elseif (($level < 2) && (is_array($value) || is_object($value))) {
+ _features_remove_ignores($value, $ignore_keys, $level+1);
+ }
+ }
+ unset($value);
+}
+
+/**
+ * Returns an array of keys to be ignored for various exportables
+ * @param $component
+ * The component to retrieve ignore_keys from.
+ */
+function _features_get_ignore_keys($component) {
+ static $cache;
+ if (!isset($cache[$component])) {
+ $cache[$component] = module_invoke_all('features_ignore', $component);
+ }
+ return $cache[$component];
+}
diff --git a/sites/all/modules/contrib/admin/features/features.info b/sites/all/modules/contrib/admin/features/features.info
index dfadcf07..d28a617b 100644
--- a/sites/all/modules/contrib/admin/features/features.info
+++ b/sites/all/modules/contrib/admin/features/features.info
@@ -3,12 +3,16 @@ description = "Provides feature management for Drupal."
core = 7.x
package = "Features"
files[] = tests/features.test
+test_dependencies[] = image
+test_dependencies[] = strongarm
+test_dependencies[] = taxonomy
+test_dependencies[] = views
configure = admin/structure/features/settings
-; Information added by Drupal.org packaging script on 2015-01-05
-version = "7.x-2.3"
+; Information added by Drupal.org packaging script on 2016-04-18
+version = "7.x-2.10"
core = "7.x"
project = "features"
-datestamp = "1420492083"
+datestamp = "1461011641"
diff --git a/sites/all/modules/contrib/admin/features/features.install b/sites/all/modules/contrib/admin/features/features.install
index aafdcc6d..008f41b1 100644
--- a/sites/all/modules/contrib/admin/features/features.install
+++ b/sites/all/modules/contrib/admin/features/features.install
@@ -5,6 +5,15 @@
* Install, update and uninstall functions for the features module.
*/
+/**
+ * Implements hook_schema().
+ */
+function features_schema() {
+ $schema['cache_features'] = drupal_get_schema_unprocessed('system', 'cache');
+ $schema['cache_features']['description'] = 'Cache table for features to store module info.';
+ return $schema;
+}
+
/**
* Implements hook_install().
*/
@@ -27,10 +36,14 @@ function features_uninstall() {
variable_del('features_ignored_orphans');
variable_del('features_feature_locked');
variable_del('features_lock_mode');
- foreach (array_keys(features_get_components()) as $component) {
- variable_del('features_admin_show_component_' . $component);
- variable_del('features_component_locked_' . $component);
- }
+
+ db_delete('variable')
+ ->condition('name', 'features_admin_show_component_%', 'LIKE')
+ ->execute();
+ db_delete('variable')
+ ->condition('name', 'features_component_locked_%', 'LIKE')
+ ->execute();
+
if (db_table_exists('menu_custom')) {
db_delete('menu_custom')
->condition('menu_name', 'features')
@@ -126,3 +139,13 @@ function features_update_6101() {
}
return array();
}
+
+/**
+ * Add {cache_features} table.
+ */
+function features_update_7200() {
+ if (!db_table_exists('cache_features')) {
+ $schema = drupal_get_schema_unprocessed('system', 'cache');
+ db_create_table('cache_features', $schema);
+ }
+}
diff --git a/sites/all/modules/contrib/admin/features/features.js b/sites/all/modules/contrib/admin/features/features.js
index 023247a4..0a4a1307 100644
--- a/sites/all/modules/contrib/admin/features/features.js
+++ b/sites/all/modules/contrib/admin/features/features.js
@@ -128,10 +128,12 @@ jQuery.fn.sortElements = (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');
+ if (matches != null) {
+ var component = matches[1];
+ var item = matches[4];
+ if ((component in moduleConflicts) && (moduleConflicts[component].indexOf(item) != -1)) {
+ $(this).parent().addClass('features-conflict');
+ }
}
}
});
@@ -290,7 +292,7 @@ jQuery.fn.sortElements = (function(){
}
// Handle component selection UI
- $('#features-export-wrapper input[type=checkbox]', context).click(function() {
+ $('#features-export-wrapper input[type=checkbox]:not(.processed)', context).addClass('processed').click(function() {
_resetTimeout();
if ($(this).hasClass('component-select')) {
moveCheckbox(this, 'added', true);
diff --git a/sites/all/modules/contrib/admin/features/features.module b/sites/all/modules/contrib/admin/features/features.module
index 5a42eb5f..3c48d713 100644
--- a/sites/all/modules/contrib/admin/features/features.module
+++ b/sites/all/modules/contrib/admin/features/features.module
@@ -84,8 +84,7 @@ function features_menu() {
$items['admin/structure/features/cleanup'] = array(
'title' => 'Cleanup',
'description' => 'Clear cache after enabling/disabling a feature.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('features_cleanup_form', 4),
+ 'page callback' => 'features_cleanup',
'type' => MENU_CALLBACK,
'file' => 'features.admin.inc',
'weight' => 1,
@@ -128,7 +127,7 @@ function features_menu() {
'description' => 'Display components of a feature.',
'page callback' => 'drupal_get_form',
'page arguments' => array('features_admin_components', 3),
- 'load arguments' => array(3, TRUE),
+ 'load arguments' => array(TRUE),
'access callback' => 'user_access',
'access arguments' => array('administer features'),
'type' => MENU_CALLBACK,
@@ -147,7 +146,7 @@ function features_menu() {
'description' => 'Recreate an existing feature.',
'page callback' => 'drupal_get_form',
'page arguments' => array('features_export_form', 3),
- 'load arguments' => array(3, TRUE),
+ 'load arguments' => array(TRUE),
'access callback' => 'user_access',
'access arguments' => array('administer features'),
'type' => MENU_LOCAL_TASK,
@@ -160,7 +159,7 @@ function features_menu() {
'description' => 'Compare default and current feature.',
'page callback' => 'features_feature_diff',
'page arguments' => array(3, 5),
- 'load arguments' => array(3, TRUE),
+ 'load arguments' => array(TRUE),
'access callback' => 'features_access_override_actions',
'access arguments' => array(3),
'type' => MENU_LOCAL_TASK,
@@ -173,7 +172,7 @@ function features_menu() {
'description' => 'Lock a feature or components.',
'page callback' => 'features_admin_lock',
'page arguments' => array(3, 5, 6),
- 'load arguments' => array(3, TRUE, TRUE),
+ 'load arguments' => array(TRUE),
'access arguments' => array('administer features'),
'type' => MENU_CALLBACK,
'file' => 'features.admin.inc',
@@ -183,7 +182,7 @@ function features_menu() {
'description' => 'Javascript status call back.',
'page callback' => 'features_feature_status',
'page arguments' => array(3),
- 'load arguments' => array(3, TRUE),
+ 'load arguments' => array(TRUE),
'access callback' => 'user_access',
'access arguments' => array('administer features'),
'type' => MENU_CALLBACK,
@@ -268,13 +267,20 @@ function features_theme() {
* Implements hook_flush_caches().
*/
function features_flush_caches() {
- if (variable_get('features_rebuild_on_flush', TRUE)) {
+ if (($modules_changed = variable_get('features_modules_changed', FALSE)) || variable_get('features_rebuild_on_flush', TRUE)) {
+ if ($modules_changed) {
+ variable_set('features_modules_changed', FALSE);
+ }
features_rebuild();
// Don't flush the modules cache during installation, for performance reasons.
if (variable_get('install_task') == 'done') {
features_get_modules(NULL, TRUE);
}
}
+
+ if (db_table_exists('cache_features')) {
+ return array('cache_features');
+ }
return array();
}
@@ -349,6 +355,15 @@ function features_modules_disabled($modules) {
* Implements hook_modules_enabled().
*/
function features_modules_enabled($modules) {
+ // Allow distributions to disable this behavior and rebuild the features
+ // manually inside a batch.
+ if (!variable_get('features_rebuild_on_module_install', TRUE)) {
+ return;
+ }
+
+ // mark modules as being changed for test in features_flush_caches
+ variable_set('features_modules_changed', TRUE);
+
// Go through all modules and gather features that can be enabled.
$items = array();
foreach ($modules as $module) {
@@ -385,7 +400,7 @@ function features_include($reset = FALSE) {
// Features provides integration on behalf of these modules.
// The features include provides handling for the feature dependencies.
// Note that ctools is placed last because it implements hooks "dynamically" for other modules.
- $modules = array('features', 'block', 'context', 'field', 'filter', 'image', 'locale', 'menu', 'node', 'taxonomy', 'user', 'views', 'ctools');
+ $modules = array('features', 'block', 'contact', 'context', 'field', 'filter', 'image', 'locale', 'menu', 'node', 'taxonomy', 'user', 'views', 'ctools');
foreach (array_filter($modules, 'module_exists') as $module) {
module_load_include('inc', 'features', "includes/features.$module");
@@ -503,7 +518,7 @@ function features_load_feature($name, $reset = FALSE) {
* Return a module 'object' including .info information.
*
* @param $name
- * The name of the module to retrieve information for. If ommitted,
+ * The name of the module to retrieve information for. If omitted,
* an array of all available modules will be returned.
* @param $reset
* Whether to reset the cache.
@@ -535,13 +550,13 @@ function features_get_components($component = NULL, $key = NULL, $reset = FALSE)
if ($reset || !isset($components) || !isset($component_by_key)) {
$components = $component_by_key = array();
- if (!$reset && ($cache = cache_get('features_api'))) {
+ if (!$reset && ($cache = cache_get('features_api', 'cache_features'))) {
$components = $cache->data;
}
else {
$components = module_invoke_all('features_api');
drupal_alter('features_api', $components);
- cache_set('features_api', $components);
+ cache_set('features_api', $components, 'cache_features');
}
foreach ($components as $component_type => $component_information) {
@@ -607,6 +622,8 @@ function features_hook($component, $hook, $reset = FALSE) {
* Clear the module info cache.
*/
function features_install_modules($modules) {
+ variable_set('features_modules_changed', TRUE);
+
module_load_include('inc', 'features', 'features.export');
$files = system_rebuild_module_data();
@@ -650,7 +667,7 @@ function features_get_features($name = NULL, $reset = FALSE) {
function features_get_info($type = 'module', $name = NULL, $reset = FALSE) {
static $cache;
if (!isset($cache)) {
- $cache = cache_get('features_module_info');
+ $cache = cache_get('features_module_info', 'cache_features');
}
if (empty($cache) || $reset) {
$data = array(
@@ -738,14 +755,14 @@ function features_get_info($type = 'module', $name = NULL, $reset = FALSE) {
$data['feature'] = $sorted;
variable_set('features_ignored_orphans', $ignored);
- cache_set("features_module_info", $data);
+ cache_set('features_module_info', $data, 'cache_features');
$cache = new stdClass();
$cache->data = $data;
}
if (!empty($name)) {
- return !empty($cache->data[$type][$name]) ? clone $cache->data[$type][$name] : array();
+ return !empty($cache->data[$type][$name]) ? clone $cache->data[$type][$name] : FALSE;
}
- return !empty($cache->data[$type]) ? $cache->data[$type] : array();
+ return !empty($cache->data[$type]) ? $cache->data[$type] : FALSE;
}
/**
@@ -892,7 +909,7 @@ function features_access_override_actions($feature) {
features_include();
module_load_include('inc', 'features', 'features.export');
- $access[$feature->name] = in_array(features_get_storage($feature->name), array(FEATURES_OVERRIDDEN, FEATURES_NEEDS_REVIEW)) && user_access('administer features');
+ $access[$feature->name] = in_array(features_get_storage($feature->name), array(FEATURES_DEFAULT, FEATURES_OVERRIDDEN, FEATURES_NEEDS_REVIEW));
}
return $access[$feature->name];
}
@@ -903,7 +920,9 @@ function features_access_override_actions($feature) {
* Implements hook_form_alter() for system_modules form().
*/
function features_form_system_modules_alter(&$form) {
- features_rebuild();
+ if (variable_get('features_rebuild_modules_page', FALSE)) {
+ features_rebuild();
+ }
}
/**
@@ -1067,6 +1086,7 @@ function features_hook_info() {
'features_api',
'features_pipe_alter',
'features_export_alter',
+ 'features_export_options_alter',
);
return array_fill_keys($hooks, array('group' => 'features'));
}
@@ -1075,6 +1095,9 @@ function features_hook_info() {
* Change vocabularies permission, from vocab id to machine name and vice versa.
*/
function _user_features_change_term_permission(&$perm, $type = 'vid') {
+ if (!module_exists('taxonomy')) {
+ return;
+ }
// Export vocabulary permissions using the machine name, instead of vocabulary
// id.
if (strpos($perm, 'edit terms in ') !== FALSE || strpos($perm, 'delete terms in ') !== FALSE) {
@@ -1186,7 +1209,6 @@ function features_feature_lock($feature, $component = NULL) {
variable_set('features_feature_locked', $locked);
}
-
/**
* Unlocks a feature or it's component.
*/
@@ -1200,3 +1222,73 @@ function features_feature_unlock($feature, $component = NULL) {
}
variable_set('features_feature_locked', $locked);
}
+
+/**
+ * Sets/Returns the current language to english to ensure a proper export.
+ */
+function _features_export_language($language = NULL) {
+ $current = $GLOBALS['language'];
+ if (isset($language)) {
+ $GLOBALS['language'] = $language;
+ }
+ elseif ($GLOBALS['language']->language != 'en') {
+ // Create the language object as language_default() does.
+ $GLOBALS['language'] = (object) array(
+ 'language' => 'en',
+ 'name' => 'English',
+ 'native' => 'English',
+ 'direction' => 0,
+ 'enabled' => 1,
+ 'plurals' => 0,
+ 'formula' => '',
+ 'domain' => '',
+ 'prefix' => '',
+ 'weight' => 0,
+ 'javascript' => '',
+ );
+ }
+ return $current;
+}
+
+/**
+ * Implements hook_features_ignore().
+ */
+function features_features_ignore($component) {
+ // Determine which keys need to be ignored for override diff for various components.
+ // Value is how many levels deep the key is.
+ $ignores = array();
+ switch ($component) {
+ case 'views_view':
+ $ignores['current_display'] = 0;
+ $ignores['display_handler'] = 0;
+ $ignores['handler'] = 2;
+ $ignores['query'] = 0;
+ $ignores['localization_plugin'] = 0;
+ // Views automatically adds these two on export to set values.
+ $ignores['api_version'] = 0;
+ $ignores['disabled'] = 0;
+ break;
+ case 'image':
+ $ignores['module'] = 0;
+ $ignores['name'] = 0;
+ $ignores['storage'] = 0;
+ // Various properties are loaded into the effect in image_styles.
+ $ignores['summary theme'] = 2;
+ $ignores['module'] = 2;
+ $ignores['label'] = 2;
+ $ignores['help'] = 2;
+ $ignores['form callback'] = 2;
+ $ignores['effect callback'] = 2;
+ $ignores['dimensions callback'] = 2;
+ break;
+ case 'field':
+ $ignores['locked'] = 1;
+ break;
+ case 'field_base':
+ $ignores['indexes'] = 0;
+ break;
+ case 'taxonomy':
+ $ignores['hierarchy'] = 0;
+ }
+ return $ignores;
+}
diff --git a/sites/all/modules/contrib/admin/features/includes/features.contact.inc b/sites/all/modules/contrib/admin/features/includes/features.contact.inc
new file mode 100644
index 00000000..af9b9193
--- /dev/null
+++ b/sites/all/modules/contrib/admin/features/includes/features.contact.inc
@@ -0,0 +1,115 @@
+ array(
+ 'name' => t('Contact categories'),
+ 'feature_source' => TRUE,
+ 'default_hook' => 'contact_categories_defaults',
+ 'default_file' => FEATURES_DEFAULTS_INCLUDED,
+ ),
+ );
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function contact_categories_features_export_options() {
+ $options = array();
+ $categories = db_select('contact', 'c')->fields('c')->execute()->fetchAll();
+ foreach ($categories as $category) {
+ $options["$category->category"] = "$category->category";
+ }
+ return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function contact_categories_features_export($data, &$export, $module_name = '') {
+ $export['dependencies']['features'] = 'features';
+ $export['dependencies']['contact'] = 'contact';
+
+ foreach ($data as $name) {
+ $export['features']['contact_categories'][$name] = $name;
+ }
+
+ return array();
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function contact_categories_features_export_render($module, $data, $export = NULL) {
+ $render = array();
+ foreach ($data as $name) {
+ $export_category = db_select('contact', 'c')
+ ->fields('c', array('cid', 'category'))
+ ->condition('category', $name, 'LIKE')
+ ->execute()
+ ->fetchAll();
+ if (isset($export_category[0]->cid) && ($category = contact_load($export_category[0]->cid))) {
+ unset($category['cid']);
+ $render[$name] = $category;
+ }
+ }
+ return array('contact_categories_defaults' => ' return ' . features_var_export($render, ' ') . ';');
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function contact_categories_features_revert($module) {
+ return contact_categories_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ */
+function contact_categories_features_rebuild($module) {
+ if ($defaults = features_get_default('contact_categories', $module)) {
+ foreach ($defaults as $default_category) {
+ $existing_categories = db_select('contact', 'c')
+ ->fields('c', array('cid', 'category'))
+ ->execute()
+ ->fetchAll();
+ if ($existing_categories) {
+ foreach ($existing_categories as $existing_category) {
+ if ($default_category['category'] == $existing_category->category) {
+ db_update('contact')
+ ->fields(
+ array(
+ 'recipients' => $default_category['recipients'],
+ 'reply' => $default_category['reply'],
+ 'weight' => $default_category['weight'],
+ 'selected' => $default_category['selected'],
+ )
+ )
+ ->condition('category', $existing_category->category, '=')
+ ->execute();
+ }
+ else {
+ db_merge('contact')
+ ->key(array('category' => $default_category['category']))
+ ->fields($default_category)
+ ->execute();
+ }
+ }
+ }
+ else {
+ db_merge('contact')
+ ->key(array('category' => $default_category['category']))
+ ->fields($default_category)
+ ->execute();
+ }
+ }
+ }
+}
diff --git a/sites/all/modules/contrib/admin/features/includes/features.field.inc b/sites/all/modules/contrib/admin/features/includes/features.field.inc
index 09104a32..849081dd 100644
--- a/sites/all/modules/contrib/admin/features/includes/features.field.inc
+++ b/sites/all/modules/contrib/admin/features/includes/features.field.inc
@@ -151,14 +151,14 @@ function field_base_features_export_render($module, $data, $export = NULL) {
foreach ($data as $identifier) {
if ($field = features_field_base_load($identifier)) {
unset($field['columns']);
- // unset($field['locked']);
+ unset($field['foreign keys']);
// Only remove the 'storage' declaration if the field is using the default
// storage type.
if ($field['storage']['type'] == variable_get('field_storage_default', 'field_sql_storage')) {
unset($field['storage']);
}
// If we still have a storage declaration here it means that a non-default
- // storage type was altered into to the field definition. And noone would
+ // storage type was altered into to the field definition. And no one would
// never need to change the 'details' key, so don't render it.
if (isset($field['storage']['details'])) {
unset($field['storage']['details']);
@@ -166,8 +166,15 @@ function field_base_features_export_render($module, $data, $export = NULL) {
_field_instance_features_export_sort($field);
$field_export = features_var_export($field, ' ');
+ $field_prefix = ' // Exported field_base: ';
$field_identifier = features_var_export($identifier);
- $code[] = " // Exported field_base: {$field_identifier}";
+ if (features_field_export_needs_wrap($field_prefix, $field_identifier)) {
+ $code[] = rtrim($field_prefix);
+ $code[] = " // {$field_identifier}.";
+ }
+ else {
+ $code[] = $field_prefix . $field_identifier . '.';
+ }
$code[] = " \$field_bases[{$field_identifier}] = {$field_export};";
$code[] = "";
}
@@ -190,8 +197,15 @@ function field_instance_features_export_render($module, $data, $export = NULL) {
if ($instance = features_field_instance_load($identifier)) {
_field_instance_features_export_sort($instance);
$field_export = features_var_export($instance, ' ');
+ $instance_prefix = ' // Exported field_instance: ';
$instance_identifier = features_var_export($identifier);
- $code[] = " // Exported field_instance: {$instance_identifier}";
+ if (features_field_export_needs_wrap($instance_prefix, $instance_identifier)) {
+ $code[] = rtrim($instance_prefix);
+ $code[] = " // {$instance_identifier}.";
+ }
+ else {
+ $code[] = $instance_prefix . $instance_identifier . '.';
+ }
$code[] = " \$field_instances[{$instance_identifier}] = {$field_export};";
$code[] = "";
@@ -260,12 +274,23 @@ function field_base_features_rebuild($module) {
// Create or update field.
if (isset($existing_fields[$field['field_name']])) {
$existing_field = $existing_fields[$field['field_name']];
- if ($field + $existing_field !== $existing_field) {
- field_update_field($field);
+ $array_diff_result = drupal_array_diff_assoc_recursive($field + $existing_field, $existing_field);
+ if (!empty($array_diff_result)) {
+ try {
+ field_update_field($field);
+ }
+ catch (FieldException $e) {
+ watchdog('features', 'Attempt to update field %label failed: %message', array('%label' => $field['field_name'], '%message' => $e->getMessage()), WATCHDOG_ERROR);
+ }
}
}
else {
- field_create_field($field);
+ try {
+ field_create_field($field);
+ }
+ catch (FieldException $e) {
+ watchdog('features', 'Attempt to create field %label failed: %message', array('%label' => $field['field_name'], '%message' => $e->getMessage()), WATCHDOG_ERROR);
+ }
$existing_fields[$field['field_name']] = $field;
}
variable_set('menu_rebuild_needed', TRUE);
@@ -395,7 +420,7 @@ function field_features_export_render($module, $data, $export = NULL) {
unset($field['field_config']['storage']);
}
// If we still have a storage declaration here it means that a non-default
- // storage type was altered into to the field definition. And noone would
+ // storage type was altered into to the field definition. And no one would
// never need to change the 'details' key, so don't render it.
if (isset($field['field_config']['storage']['details'])) {
unset($field['field_config']['storage']['details']);
@@ -469,7 +494,8 @@ function field_features_rebuild($module) {
$field_config = $field['field_config'];
if (isset($existing_fields[$field_config['field_name']])) {
$existing_field = $existing_fields[$field_config['field_name']];
- if ($field_config + $existing_field !== $existing_field) {
+ $array_diff_result = drupal_array_diff_assoc_recursive($field_config + $existing_field, $existing_field);
+ if (!empty($array_diff_result)) {
try {
field_update_field($field_config);
}
@@ -528,3 +554,24 @@ function features_field_load($identifier) {
}
return FALSE;
}
+
+/**
+ * Determine if a field export line needs to be wrapped.
+ *
+ * Drupal code standards specify that comments should wrap at 80 characters or
+ * less.
+ *
+ * @param string $prefix
+ * The prefix to be exported before the field identifier.
+ * @param string $identifier
+ * The field identifier.
+ *
+ * @return BOOL
+ * TRUE if the line should be wrapped after the prefix, else FALSE.
+ *
+ * @see https://www.drupal.org/node/1354
+ */
+function features_field_export_needs_wrap($prefix, $identifier) {
+ // Check for 79 characters, since the comment ends with a full stop.
+ return (strlen($prefix) + strlen($identifier) > 79);
+}
diff --git a/sites/all/modules/contrib/admin/features/includes/features.image.inc b/sites/all/modules/contrib/admin/features/includes/features.image.inc
index 2b5eb273..b2058b7c 100644
--- a/sites/all/modules/contrib/admin/features/includes/features.image.inc
+++ b/sites/all/modules/contrib/admin/features/includes/features.image.inc
@@ -86,16 +86,25 @@ function image_features_revert($module) {
/**
* Remove unnecessary keys for export.
*/
-function _image_features_style_sanitize(&$style, $child = FALSE) {
- $omit = $child ? array('isid', 'ieid', 'storage') : array('isid', 'ieid', 'storage', 'module');
- if (is_array($style)) {
- foreach ($style as $k => $v) {
- if (in_array($k, $omit, TRUE)) {
- unset($style[$k]);
- }
- else if (is_array($v)) {
- _image_features_style_sanitize($style[$k], TRUE);
- }
- }
+function _image_features_style_sanitize(array &$style) {
+ // Sanitize style: Don't export numeric IDs and things which get overwritten
+ // in image_styles() or are code/storage specific. The name property will be
+ // the key of the exported $style array.
+ $style = array_diff_key($style, array_flip(array(
+ 'isid',
+ 'name',
+ 'module',
+ 'storage',
+ )));
+
+ // Sanitize effects: all that needs to be kept is name, weight and data,
+ // which holds all the style-specific configuration. Other keys are assumed
+ // to belong to the definition of the effect itself, so not configuration.
+ foreach ($style['effects'] as $id => $effect) {
+ $style['effects'][$id] = array_intersect_key($effect, array_flip(array(
+ 'name',
+ 'data',
+ 'weight',
+ )));
}
}
diff --git a/sites/all/modules/contrib/admin/features/includes/features.locale.inc b/sites/all/modules/contrib/admin/features/includes/features.locale.inc
index fc27174b..258d5413 100644
--- a/sites/all/modules/contrib/admin/features/includes/features.locale.inc
+++ b/sites/all/modules/contrib/admin/features/includes/features.locale.inc
@@ -134,14 +134,15 @@ function _features_language_save($language) {
->fields(array(
'plurals' => empty($language->plurals) ? 0 : $language->plurals,
'formula' => empty($language->formula) ? '' : $language->formula,
+ 'weight' => empty($language->weight) ? 0 : $language->weight,
))
->condition('language', $language->language)
->execute();
}
// Update Existing language.
else {
- // @TODO: get properties from schema.
- $properties = array('language', 'name', 'native', 'direction', 'enabled', 'plurals', 'formula', 'domain', 'prefix', 'weight', 'javascript');
+ // Get field list from table schema.
+ $properties = drupal_schema_fields_sql('languages');
// The javascript hash is not in the imported data but should be empty
if (!isset($language->javascript)) {
$language->javascript = '';
diff --git a/sites/all/modules/contrib/admin/features/includes/features.menu.inc b/sites/all/modules/contrib/admin/features/includes/features.menu.inc
index c883e6ac..edd47514 100644
--- a/sites/all/modules/contrib/admin/features/includes/features.menu.inc
+++ b/sites/all/modules/contrib/admin/features/includes/features.menu.inc
@@ -103,7 +103,6 @@ function menu_custom_features_export_render($module, $data) {
$code[] = features_translatables_export($translatables, ' ');
}
- $code[] = '';
$code[] = ' return $menus;';
$code = implode("\n", $code);
return array('menu_default_menu_custom' => $code);
@@ -248,16 +247,16 @@ function menu_links_features_export_render($module, $data, $export = NULL) {
unset($link['plid']);
unset($link['mlid']);
- $code[] = " // Exported menu link: {$new_identifier}";
+ $code[] = " // Exported menu link: {$new_identifier}.";
$code[] = " \$menu_links['{$new_identifier}'] = ". features_var_export($link, ' ') .";";
$translatables[] = $link['link_title'];
}
}
+ $code[] = '';
if (!empty($translatables)) {
$code[] = features_translatables_export($translatables, ' ');
}
- $code[] = '';
$code[] = ' return $menu_links;';
$code = implode("\n", $code);
return array('menu_default_menu_links' => $code);
@@ -316,6 +315,7 @@ function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) {
foreach ($unordered as $link) {
$identifier = menu_links_features_identifier($link);
$ordered[$identifier] = 0;
+ $all_links[$identifier] = $link;
}
asort($ordered);
}
diff --git a/sites/all/modules/contrib/admin/features/includes/features.node.inc b/sites/all/modules/contrib/admin/features/includes/features.node.inc
index 9461778f..25a2c1cd 100644
--- a/sites/all/modules/contrib/admin/features/includes/features.node.inc
+++ b/sites/all/modules/contrib/admin/features/includes/features.node.inc
@@ -117,7 +117,7 @@ function node_features_revert($module = NULL) {
}
/**
- * Implements hook_features_disable().
+ * Implements hook_features_disable_feature().
*
* When a features module is disabled, modify any node types it provides so
* they can be deleted manually through the content types UI.
@@ -125,7 +125,7 @@ function node_features_revert($module = NULL) {
* @param $module
* Name of module that has been disabled.
*/
-function node_features_disable($module) {
+function node_features_disable_feature($module) {
if ($default_types = features_get_default('node', $module)) {
foreach ($default_types as $type_name => $type_info) {
$type_info = node_type_load($type_name);
@@ -133,22 +133,26 @@ function node_features_disable($module) {
$type_info->custom = 1;
$type_info->modified = 1;
$type_info->locked = 0;
+ $type_info->disabled = 0;
node_type_save($type_info);
}
}
}
/**
- * Implements hook_features_enable().
+ * Implements hook_features_enable_feature().
*
* When a features module is enabled, modify any node types it provides so
* they can no longer be deleted manually through the content types UI.
*
+ * Update the database cache of node types if needed.
+ *
* @param $module
* Name of module that has been enabled.
*/
-function node_features_enable($module) {
+function node_features_enable_feature($module) {
if ($default_types = features_get_default('node', $module)) {
+ $rebuild = FALSE;
foreach ($default_types as $type_name => $type_info) {
// Ensure the type exists.
if ($type_info = node_type_load($type_name)) {
@@ -156,8 +160,15 @@ function node_features_enable($module) {
$type_info->custom = 0;
$type_info->modified = 0;
$type_info->locked = 1;
+ $type_info->disabled = 0;
node_type_save($type_info);
}
+ else {
+ $rebuild = TRUE;
+ }
+ }
+ if ($rebuild) {
+ node_types_rebuild();
}
}
}
diff --git a/sites/all/modules/contrib/admin/features/tests/features.test b/sites/all/modules/contrib/admin/features/tests/features.test
index 1fa51ac2..025ef23c 100644
--- a/sites/all/modules/contrib/admin/features/tests/features.test
+++ b/sites/all/modules/contrib/admin/features/tests/features.test
@@ -218,7 +218,7 @@ class FeaturesEnableTestCase extends DrupalWebTestCase {
/**
- * Tests intergration of ctools for features.
+ * Tests integration of ctools for features.
*/
class FeaturesCtoolsIntegrationTest extends DrupalWebTestCase {
protected $profile = 'testing';
@@ -287,3 +287,43 @@ class FeaturesCtoolsIntegrationTest extends DrupalWebTestCase {
}
}
}
+
+
+/**
+ * Test detecting modules as features.
+ */
+class FeaturesDetectionTestCase extends DrupalWebTestCase {
+ protected $profile = 'testing';
+
+ /**
+ * Test info.
+ */
+ public static function getInfo() {
+ return array(
+ 'name' => t('Feature Detection tests'),
+ 'description' => t('Run tests for detecting items as features.') ,
+ 'group' => t('Features'),
+ );
+ }
+
+ /**
+ * Set up test.
+ */
+ public function setUp() {
+ parent::setUp(array(
+ 'features',
+ ));
+ }
+
+ /**
+ * Run test.
+ */
+ public function test() {
+ module_load_include('inc', 'features', 'features.export');
+ // First test that features_populate inserts the features api key.
+ $export = features_populate(array(), array(), 'features_test_empty_fake');
+ $this->assertTrue(!empty($export['features']['features_api']) && key($export['features']['features_api']) == 'api:' . FEATURES_API, 'Features API key added to new export.');
+ $this->assertTrue((bool)features_get_features('features_test'), 'Features test recognized as a feature.');
+ $this->assertFalse((bool)features_get_features('features'), 'Features module not recognized as a feature.');
+ }
+}
diff --git a/sites/all/modules/contrib/admin/features/tests/features_test/features_test.features.inc b/sites/all/modules/contrib/admin/features/tests/features_test/features_test.features.inc
index 38aaa4d4..8d0646ff 100644
--- a/sites/all/modules/contrib/admin/features/tests/features_test/features_test.features.inc
+++ b/sites/all/modules/contrib/admin/features/tests/features_test/features_test.features.inc
@@ -29,16 +29,8 @@ function features_test_image_default_styles() {
// Exported image style: features_test.
$styles['features_test'] = array(
- 'name' => 'features_test',
'effects' => array(
2 => array(
- 'label' => 'Scale',
- 'help' => 'Scaling will maintain the aspect-ratio of the original image. If only a single dimension is specified, the other dimension will be calculated.',
- 'effect callback' => 'image_scale_effect',
- 'dimensions callback' => 'image_scale_dimensions',
- 'form callback' => 'image_scale_form',
- 'summary theme' => 'image_scale_summary',
- 'module' => 'image',
'name' => 'image_scale',
'data' => array(
'width' => 100,
diff --git a/sites/all/modules/contrib/admin/features/tests/features_test/features_test.info b/sites/all/modules/contrib/admin/features/tests/features_test/features_test.info
index 21481619..04f01d33 100644
--- a/sites/all/modules/contrib/admin/features/tests/features_test/features_test.info
+++ b/sites/all/modules/contrib/admin/features/tests/features_test/features_test.info
@@ -21,9 +21,9 @@ features[user_permission][] = create features_test content
features[views_view][] = features_test
hidden = 1
-; Information added by Drupal.org packaging script on 2015-01-05
-version = "7.x-2.3"
+; Information added by Drupal.org packaging script on 2016-04-18
+version = "7.x-2.10"
core = "7.x"
project = "features"
-datestamp = "1420492083"
+datestamp = "1461011641"
diff --git a/sites/all/modules/contrib/admin/features_extra/fe_block.info b/sites/all/modules/contrib/admin/features_extra/fe_block.info
index f037e27a..375692f9 100644
--- a/sites/all/modules/contrib/admin/features_extra/fe_block.info
+++ b/sites/all/modules/contrib/admin/features_extra/fe_block.info
@@ -13,9 +13,9 @@ test_dependencies[] = blockcache_alter
files[] = tests/features_extra_test_case.test
files[] = tests/fe_block.test
-; Information added by Drupal.org packaging script on 2015-02-06
-version = "7.x-1.0-beta1+4-dev"
+; Information added by Drupal.org packaging script on 2015-08-12
+version = "7.x-1.0"
core = "7.x"
project = "features_extra"
-datestamp = "1423208167"
+datestamp = "1439376840"
diff --git a/sites/all/modules/contrib/admin/features_extra/fe_date.info b/sites/all/modules/contrib/admin/features_extra/fe_date.info
new file mode 100644
index 00000000..3204b7e4
--- /dev/null
+++ b/sites/all/modules/contrib/admin/features_extra/fe_date.info
@@ -0,0 +1,14 @@
+name = FE Date
+description = Build date format as features.
+core = 7.x
+package = Features extra
+
+dependencies[] = ctools
+dependencies[] = features
+
+; Information added by Drupal.org packaging script on 2015-08-12
+version = "7.x-1.0"
+core = "7.x"
+project = "features_extra"
+datestamp = "1439376840"
+
diff --git a/sites/all/modules/contrib/admin/features_extra/fe_date.module b/sites/all/modules/contrib/admin/features_extra/fe_date.module
new file mode 100644
index 00000000..af78e3dd
--- /dev/null
+++ b/sites/all/modules/contrib/admin/features_extra/fe_date.module
@@ -0,0 +1,345 @@
+ t('Date format types'),
+ 'feature_source' => TRUE,
+ 'default_hook' => 'date_format_types',
+ 'default_file' => FEATURES_DEFAULTS_INCLUDED_COMMON,
+ );
+
+ $components['fe_date_custom_date_formats'] = array(
+ 'name' => t('Custom date formats'),
+ 'feature_source' => TRUE,
+ 'default_hook' => 'fe_date_custom_date_formats',
+ 'default_file' => FEATURES_DEFAULTS_INCLUDED_COMMON,
+ );
+
+ if (module_exists('locale')) {
+ $components['fe_date_locale_date_format'] = array(
+ 'name' => t('Locale date format'),
+ 'feature_source' => TRUE,
+ 'default_hook' => 'fe_date_locale_date_format',
+ 'default_file' => FEATURES_DEFAULTS_INCLUDED_COMMON,
+ );
+ }
+
+ return $components;
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function fe_date_date_format_types_features_export_options() {
+ $options = array();
+ $format_types = system_get_date_types();
+ foreach ($format_types as $type => $format_type) {
+ $options[$type] = $format_type['title'];
+ }
+
+ return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function fe_date_date_format_types_features_export($data, &$export, $module_name = '') {
+ $export['dependencies']['fe_date'] = 'fe_date';
+ $pipe = array('variable' => array());
+ $map_variable = features_get_default_map('variable');
+ $map_custom_formats = features_get_default_map('fe_date_custom_date_formats');
+ $map_date_format_types = features_get_default_map('fe_date_date_format_types');
+ foreach ($data as $type) {
+ // Only add format type to export, if it is available.
+ if (system_get_date_types($type)) {
+ $variable = 'date_format_' . $type;
+
+ // Add a dependency when the variable already in a feature but not by use.
+ if (isset($map_variable[$variable]) && $map_variable[$variable] != $module_name) {
+ $export['dependencies'][$map_variable[$variable]] = $map_variable[$variable];
+ }
+ else {
+ // Add strongarm variable for given default date format for this type.
+ $pipe['variable'][$variable] = $variable;
+ }
+
+ $default_format = _fe_date_get_default_format($type);
+
+ // Add a dependency when the default date format is a custom date format
+ // and already in a feature but not by use.
+ if (isset($map_custom_formats[$default_format]) && $map_custom_formats[$default_format] != $module_name) {
+ $export['dependencies'][$map_custom_formats[$default_format]] = $map_custom_formats[$default_format];
+ }
+ else {
+ // Add custom date format for this type.
+ $pipe['fe_date_custom_date_formats'][$default_format] = $default_format;
+ }
+
+ // Add a dependency when the date_format_type already in a feature but
+ // not by use.
+ if (isset($map_date_format_types[$type]) && $map_date_format_types[$type] != $module_name) {
+ $export['dependencies'][$map_date_format_types[$type]] = $map_date_format_types[$type];
+ }
+ else {
+ $export['features']['fe_date_date_format_types'][$type] = $type;
+ }
+
+ }
+ }
+
+ return $pipe;
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function fe_date_date_format_types_features_export_render($module, $data, $export = NULL) {
+ $code = array();
+ $code[] = ' $format_types = array();';
+
+ foreach ($data as $type) {
+ if ($spec = system_get_date_types($type)) {
+ $format_export = features_var_export($spec['title'], ' ');
+ $format_identifier = features_var_export($type);
+ $code[] = " // Exported date format type: $type";
+ $code[] = " \$format_types[{$format_identifier}] = {$format_export};";
+ }
+ }
+ $code[] = ' return $format_types;';
+ $code = implode("\n", $code);
+
+ return array('date_format_types' => $code);
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function fe_date_locale_date_format_features_export_options() {
+ $options = array();
+ $format_types = system_get_date_types();
+ $languages = locale_language_list('native');
+
+ foreach ($format_types as $type => $format_type) {
+ foreach ($languages as $langcode => $language) {
+ $format = _fe_date_get_locale_date_format($type, $langcode);
+ if (!empty($format)) {
+ $options["$type::$langcode"] = "{$format_type['title']} ($language)";
+ }
+ }
+ }
+
+ return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function fe_date_locale_date_format_features_export($data, &$export, $module_name = '') {
+ $export['dependencies']['features'] = 'features';
+ $export['dependencies']['fe_date'] = 'fe_date';
+ $map_language = features_get_default_map('language');
+ $map_date_format_types = features_get_default_map('fe_date_date_format_types');
+ $map_locale_date_format = features_get_default_map('fe_date_locale_date_format');
+ $pipe = array('fe_date_date_format_types' => array(), 'language' => array());
+ foreach ($data as $name) {
+ list($type, $langcode) = explode('::', $name . '::', 3);
+ if ($format = _fe_date_get_locale_date_format($type, $langcode)) {
+ // Add a dependency when the type already in a feature but not by use
+ // or system.
+ if (isset($map_date_format_types[$type]) && !in_array($map_date_format_types[$type], array('system', $module_name))) {
+ $export['dependencies'][$map_date_format_types[$type]] = $map_date_format_types[$type];
+ }
+ else {
+ // Add date_format_type to pipe.
+ $pipe['fe_date_date_format_types'][$type] = $type;
+ }
+ // Add a dependency when the language is in a feature but not by use.
+ if (isset($map_language[$langcode]) && $map_language[$langcode] != $module_name) {
+ $export['dependencies'][$map_language[$langcode]] = $map_language[$langcode];
+ }
+ else {
+ // Add language to pipe.
+ $pipe['language'][$langcode] = $langcode;
+ }
+
+ if (isset($map_locale_date_format[$name]) && $map_locale_date_format[$name] != $module_name) {
+ $export['dependencies'][$map_locale_date_format[$name]] = $map_locale_date_format[$name];
+ }
+ else {
+ // Add format to exports.
+ $export['features']['fe_date_locale_date_format'][$name] = $name;
+ }
+ }
+ }
+
+ return $pipe;
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function fe_date_locale_date_format_features_export_render($module, $data, $export = NULL) {
+ $code = array();
+ $code[] = ' $locale_date_formats = array();';
+ $code[] = '';
+ foreach ($data as $name) {
+ list($type, $langcode) = explode('::', $name . '::', 3);
+ if ($format = _fe_date_get_locale_date_format($type, $langcode)) {
+ $var = array(
+ 'type' => $type,
+ 'format' => $format,
+ 'locales' => $langcode ? array($langcode) : array(),
+ );
+ $format_export = features_var_export($var, ' ');
+ $format_identifier = features_var_export($name);
+ $code[] = " // Exported format: $name";
+ $code[] = " \$locale_date_formats[{$format_identifier}] = {$format_export};";
+ }
+ }
+
+ $code[] = ' return $locale_date_formats;';
+ $code = implode("\n", $code);
+
+ return array('fe_date_locale_date_format' => $code);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function fe_date_locale_date_format_features_revert($module) {
+ fe_date_locale_date_format_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ *
+ * hook_date_formats() is used to define the necessary formats, but the
+ * association to the date format type is not set by using that hook. So we have
+ * to set it in the database by ourselves.
+ *
+ * @see hook_date_formats()
+ */
+function fe_date_locale_date_format_features_rebuild($module) {
+ if ($defaults = features_get_default('fe_date_locale_date_format', $module)) {
+ foreach ($defaults as $spec) {
+ foreach ($spec['locales'] as $locale) {
+ locale_date_format_save($locale, $spec['type'], $spec['format']);
+ }
+ }
+ }
+}
+
+/**
+ * Helper function to get the pure format (locale or from variable).
+ */
+function _fe_date_get_locale_date_format($type, $langcode) {
+ // Try to get a locale date format.
+ $format = system_date_format_locale($langcode, $type);
+ // If no format was found, we get the default value.
+ if (empty($format)) {
+ $format = _fe_date_get_default_format($type);
+ }
+ return $format ? $format : NULL;
+}
+
+/**
+ * Helper function to get the pure format (from variable).
+ */
+function _fe_date_get_default_format($type) {
+ // Do not use variable_get() as this may fetch an already localized variable.
+ $format = db_query('SELECT value FROM {variable} WHERE name = :name', array(':name' => 'date_format_' . $type))->fetchField();
+
+ return $format !== FALSE ? unserialize($format) : NULL;
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function fe_date_custom_date_formats_features_export_options() {
+ $formats = system_get_date_formats('custom');
+ $options = array();
+ if (!empty($formats)) {
+ foreach (array_keys($formats) as $format) {
+ $options[$format] = $format;
+ }
+ }
+
+ return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function fe_date_custom_date_formats_features_export($data, &$export, $module_name = '') {
+ $export['dependencies']['features'] = 'features';
+ $export['dependencies']['fe_date'] = 'fe_date';
+ foreach ($data as $format) {
+ $map = features_get_default_map('fe_date_custom_date_formats');
+ if (!empty($map[$format]) && $map[$format] != $module_name) {
+ $export['dependencies'][$map[$format]] = $map[$format];
+ }
+ else {
+ $export['features']['fe_date_custom_date_formats'][$format] = $format;
+ }
+ }
+
+ return array();
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function fe_date_custom_date_formats_features_export_render($module, $data, $export = NULL) {
+ $formats = system_get_date_formats('custom');
+ $code = array();
+ $code[] = ' $custom_date_formats = array();';
+ foreach ($data as $format) {
+ if (!empty($formats[$format])) {
+ $format = features_var_export($format);
+ $code[] = " \$custom_date_formats[{$format}] = {$format};";
+ }
+ }
+ $code[] = ' return $custom_date_formats;';
+ $code = implode("\n", $code);
+
+ return array('fe_date_custom_date_formats' => $code);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ */
+function fe_date_custom_date_formats_features_rebuild($module) {
+ fe_date_custom_date_formats_features_revert($module);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function fe_date_custom_date_formats_features_revert($module) {
+ if ($defaults = features_get_default('fe_date_custom_date_formats', $module)) {
+ $formats = system_get_date_formats('custom');
+ foreach ($defaults as $format) {
+ if (empty($formats[$format])) {
+ $format_data['format'] = trim($format);
+ $format_data['type'] = 'custom';
+ $format_data['locked'] = 0;
+ $format_data['is_new'] = 1;
+ system_date_format_save($format_data);
+ }
+ }
+ }
+}
diff --git a/sites/all/modules/contrib/admin/features_extra/fe_nodequeue.info b/sites/all/modules/contrib/admin/features_extra/fe_nodequeue.info
index 7468d9c1..1fe59df2 100644
--- a/sites/all/modules/contrib/admin/features_extra/fe_nodequeue.info
+++ b/sites/all/modules/contrib/admin/features_extra/fe_nodequeue.info
@@ -10,9 +10,9 @@ dependencies[] = nodequeue
files[] = tests/features_extra_test_case.test
files[] = tests/fe_nodequeue.test
-; Information added by Drupal.org packaging script on 2015-02-06
-version = "7.x-1.0-beta1+4-dev"
+; Information added by Drupal.org packaging script on 2015-08-12
+version = "7.x-1.0"
core = "7.x"
project = "features_extra"
-datestamp = "1423208167"
+datestamp = "1439376840"
diff --git a/sites/all/modules/contrib/admin/features_extra/fe_profile.info b/sites/all/modules/contrib/admin/features_extra/fe_profile.info
index 73d747b9..bd3fe261 100644
--- a/sites/all/modules/contrib/admin/features_extra/fe_profile.info
+++ b/sites/all/modules/contrib/admin/features_extra/fe_profile.info
@@ -7,9 +7,9 @@ dependencies[] = ctools
dependencies[] = features
dependencies[] = profile
-; Information added by Drupal.org packaging script on 2015-02-06
-version = "7.x-1.0-beta1+4-dev"
+; Information added by Drupal.org packaging script on 2015-08-12
+version = "7.x-1.0"
core = "7.x"
project = "features_extra"
-datestamp = "1423208167"
+datestamp = "1439376840"
diff --git a/sites/all/modules/contrib/admin/features_extra/tests/features_extra_test.info b/sites/all/modules/contrib/admin/features_extra/tests/features_extra_test.info
index b0733848..81b0fb58 100644
--- a/sites/all/modules/contrib/admin/features_extra/tests/features_extra_test.info
+++ b/sites/all/modules/contrib/admin/features_extra/tests/features_extra_test.info
@@ -14,9 +14,9 @@ features[fe_block_settings][] = block-features_extra_test_block
features[fe_nodequeue][] = features_extra_test_nodequeue
features[features_api][] = api:1
-; Information added by Drupal.org packaging script on 2015-02-06
-version = "7.x-1.0-beta1+4-dev"
+; Information added by Drupal.org packaging script on 2015-08-12
+version = "7.x-1.0"
core = "7.x"
project = "features_extra"
-datestamp = "1423208167"
+datestamp = "1439376840"
diff --git a/sites/all/modules/contrib/admin/field_permissions/CHANGELOG.txt b/sites/all/modules/contrib/admin/field_permissions/CHANGELOG.txt
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/field_permissions/LICENSE.txt b/sites/all/modules/contrib/admin/field_permissions/LICENSE.txt
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/field_permissions/README.txt b/sites/all/modules/contrib/admin/field_permissions/README.txt
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/field_permissions/field_permissions.admin.css b/sites/all/modules/contrib/admin/field_permissions/field_permissions.admin.css
old mode 100755
new mode 100644
index e6185071..61af1494
--- a/sites/all/modules/contrib/admin/field_permissions/field_permissions.admin.css
+++ b/sites/all/modules/contrib/admin/field_permissions/field_permissions.admin.css
@@ -1,4 +1,3 @@
-
/* Table cells. */
.field-permissions-cell,
.field-permissions-header {
@@ -29,20 +28,19 @@ html.js .field-permissions-tooltip {
color: #444;
background-color: #f0f0f0;
border: 1px solid #aaa;
-
/* CSS3 properties not supported by all browsers. */
-webkit-box-shadow: 2px 2px 2px #ccc;
- -khtml-box-shadow: 2px 2px 2px #ccc;
- -icab-box-shadow: 2px 2px 2px #ccc;
- -moz-box-shadow: 2px 2px 2px #ccc;
- -o-box-shadow: 2px 2px 2px #ccc;
- box-shadow: 2px 2px 2px #ccc;
+ -khtml-box-shadow: 2px 2px 2px #ccc;
+ -icab-box-shadow: 2px 2px 2px #ccc;
+ -moz-box-shadow: 2px 2px 2px #ccc;
+ -o-box-shadow: 2px 2px 2px #ccc;
+ box-shadow: 2px 2px 2px #ccc;
-webkit-border-radius: 5px;
- -khtml-border-radius: 5px;
- -icab-border-radius: 5px;
- -moz-border-radius: 5px;
- -o-border-radius: 5px;
- border-radius: 5px;
+ -khtml-border-radius: 5px;
+ -icab-border-radius: 5px;
+ -moz-border-radius: 5px;
+ -o-border-radius: 5px;
+ border-radius: 5px;
}
.field-permissions-tooltip .item-list,
#field-permissions-tooltip .item-list {
diff --git a/sites/all/modules/contrib/admin/field_permissions/field_permissions.admin.inc b/sites/all/modules/contrib/admin/field_permissions/field_permissions.admin.inc
old mode 100755
new mode 100644
index fde37306..2eeefd55
--- a/sites/all/modules/contrib/admin/field_permissions/field_permissions.admin.inc
+++ b/sites/all/modules/contrib/admin/field_permissions/field_permissions.admin.inc
@@ -8,13 +8,13 @@
/**
* Obtain the list of field permissions.
*
- * @param $field_label
+ * @param string $field_label
* The human readable name of the field to use when constructing permission
* names. Usually this will be derived from one or more of the field instance
* labels.
*/
function field_permissions_list($field_label = '') {
- return array(
+ $permissions = array(
'create' => array(
'label' => t('Create field'),
'title' => t('Create own value for field %field', array('%field' => $field_label)),
@@ -36,46 +36,47 @@ function field_permissions_list($field_label = '') {
'title' => t("View anyone's value for field %field", array('%field' => $field_label)),
),
);
+
+ drupal_alter('field_permissions_list', $permissions, $field_label);
+
+ return $permissions;
}
/**
* Returns field permissions in a format suitable for use in hook_permission().
*
- * @param $field
+ * @param array $field
* The field to return permissions for.
- * @param $label
+ * @param mixed $label
* (optional) The human readable name of the field to use when constructing
* permission names; for example, this might be the label of one of the
* corresponding field instances. If not provided, an appropriate label will
* be automatically derived from all the field's instances.
*
- * @return
+ * @return array
* An array of permission information, suitable for use in hook_permission().
*/
function field_permissions_list_field_permissions($field, $label = NULL) {
- $description = '';
-
- // If there is no preferred label, construct one from all the instance
- // labels.
if (!isset($label)) {
- $labels = array();
- foreach ($field['bundles'] as $entity_type => $bundles) {
- foreach ($bundles as $bundle_name) {
- $instance = field_info_instance($entity_type, $field['field_name'], $bundle_name);
- $labels[] = $instance['label'];
+ $label = $field['field_name'];
+ }
+ $instances = array();
+ $description = '';
+ foreach ($field['bundles'] as $entity_type => $bundles) {
+ foreach ($bundles as $bundle_name) {
+ $instance = field_info_instance($entity_type, $field['field_name'], $bundle_name);
+ $entity = entity_get_info($entity_type);
+ if (!isset($entity['bundles'][$bundle_name])) {
+ continue;
}
+ $instance_desc_tokens = array(
+ $entity['label'],
+ $entity['bundles'][$bundle_name]['label'],
+ $instance['label'],
+ );
+ $instances[] = '"' . implode(':', $instance_desc_tokens) . '"';
}
- // If all the instances have the same label, just use that. Otherwise, use
- // the field name (with the full list of instance labels as the permission
- // description).
- $labels = array_unique($labels);
- if (count($labels) == 1) {
- $label = array_shift($labels);
- }
- else {
- $label = $field['field_name'];
- $description = t('This field appears as: %instances', array('%instances' => implode(', ', $labels)));
- }
+ $description = t('This field appears as: %instances.', array('%instances' => implode(', ', $instances)));
}
$permissions = array();
@@ -91,7 +92,7 @@ function field_permissions_list_field_permissions($field, $label = NULL) {
}
/**
- * Implementation of hook_permission().
+ * Implements hook_permission().
*/
function _field_permissions_permission() {
$perms = array(
@@ -145,9 +146,7 @@ function _field_permissions_field_settings_form_alter(&$form, $form_state, $form
'#type' => 'container',
'#states' => array(
'visible' => array(
- // We must cast this to a string until http://drupal.org/node/879580 is
- // fixed.
- ':input[name="field[field_permissions][type]"]' => array('value' => (string) FIELD_PERMISSIONS_CUSTOM),
+ ':input[name="field[field_permissions][type]"]' => array('value' => FIELD_PERMISSIONS_CUSTOM),
),
),
// Custom styling for the permissions matrix on the field settings page.
@@ -156,6 +155,23 @@ function _field_permissions_field_settings_form_alter(&$form, $form_state, $form
),
);
+ $form['field']['field_permissions']['permission_warning'] = array(
+ '#type' => 'item',
+ '#markup' => '
'
+ . t('Field permissions error')
+ . ' '
+ . t('If you are seeing this message and are not seeing a table of permissions, something is wrong! See !link for more information.', array(
+ '!link' => l(t('the Field Permission documentation'), 'https://www.drupal.org/node/2802067#known-issues', array(
+ 'attributes' => array('target' => '_blank'),
+ )),
+ )) . '
',
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="field[field_permissions][type]"]' => array('value' => FIELD_PERMISSIONS_CUSTOM),
+ ),
+ ),
+ );
+
// Add the field permissions matrix itself. Wait until the #pre_render stage
// to move it to the above container, to avoid having the permissions data
// saved as part of the field record.
@@ -183,15 +199,15 @@ function _field_permissions_field_settings_form_alter(&$form, $form_state, $form
* to actually be saved. For an example submit handler, see
* _field_permissions_field_settings_form_submit().
*
- * @param $field
+ * @param array $field
* The field whose permissions will be displayed in the matrix.
- * @param $instance
+ * @param array $instance
* The field instance for which the permissions will be displayed. Although
* the permissions are per-field rather than per-instance, the instance label
* will be used to display an appropriate human-readable name for each
* permission.
*
- * @return
+ * @return array
* A form array defining the permissions matrix.
*
* @see user_admin_permissions()
@@ -327,37 +343,52 @@ function _field_permissions_field_settings_form_submit($form, &$form_state) {
* Menu callback; Field permissions overview.
*/
function field_permissions_overview() {
- drupal_add_css(drupal_get_path('module', 'field_permissions') .'/field_permissions.admin.css');
+ drupal_add_css(drupal_get_path('module', 'field_permissions') . '/field_permissions.admin.css');
- $headers = array(t('Field name'), t('Field type'), t('Entity type'), t('Used in'));
+ $headers = array(
+ t('Field name'),
+ t('Field type'),
+ t('Entity type'),
+ t('Used in'),
+ );
foreach (field_permissions_list() as $permission_type => $permission_info) {
$headers[] = array('data' => $permission_info['label'], 'class' => 'field-permissions-header');
}
$destination = drupal_get_destination();
- // Load list of field instances, types and bundles in the system.
- $instances = field_info_instances();
+ // Load list of fields, field types and bundles in the system.
$field_types = field_info_field_types();
- $bundles = field_info_bundles();
+ $bundles_info = field_info_bundles();
// Retrieve the permissions for each role.
$role_permissions = user_role_permissions(user_roles());
// Based on field_ui_fields_list() in field_ui.admin.inc.
$rows = array();
- foreach ($instances as $obj_type => $type_bundles) {
- foreach ($type_bundles as $bundle => $bundle_instances) {
- foreach ($bundle_instances as $field_name => $instance) {
+ foreach (field_info_fields() as $field_name => $field) {
+ foreach ($field['bundles'] as $entity_type => $bundles) {
+ foreach ($bundles as $bundle) {
+ // Some fields might belong to bundles that are disabled (which are not
+ // returned by field_info_bundles()).
+ // @see https://www.drupal.org/node/1351506
+ if (!isset($bundles_info[$entity_type][$bundle])) {
+ continue;
+ }
// Each field will have a row in the table.
- $field = field_info_field($field_name);
- $admin_path = _field_ui_bundle_admin_path($obj_type, $bundle);
+ if (module_exists('field_ui')) {
+ $admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
+ $field_admin_path = l($bundles_info[$entity_type][$bundle]['label'], $admin_path . '/fields/' . $field_name, array(
+ 'query' => $destination,
+ 'fragment' => 'edit-field-field-permissions-type',
+ ));
+ }
+ else {
+ $field_admin_path = $bundles_info[$entity_type][$bundle]['label'];
+ }
$rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
- $rows[$field_name]['data'][1] = t($field_types[$field['type']]['label']);
- $rows[$field_name]['data'][2] = $obj_type;
- $rows[$field_name]['data'][3][] = l($bundles[$obj_type][$bundle]['label'], $admin_path . '/fields/'. $field_name, array(
- 'query' => $destination,
- 'fragment' => 'edit-field-field-permissions-type',
- ));
+ $rows[$field_name]['data'][1] = $field_types[$field['type']]['label'];
+ $rows[$field_name]['data'][2] = $entity_type;
+ $rows[$field_name]['data'][3][] = $field_admin_path;
$rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array('');
// Append field permissions information to the report.
@@ -381,7 +412,7 @@ function field_permissions_overview() {
$all_users_have_access = isset($role_permissions[DRUPAL_ANONYMOUS_RID][$permission]) && isset($role_permissions[DRUPAL_AUTHENTICATED_RID][$permission]);
$status_class = $all_users_have_access ? 'field-permissions-status-on' : 'field-permissions-status-off';
$title = $all_users_have_access ? t('All users have this permission') : t('Not all users have this permission');
- $data = l('', 'admin/people/permissions', array(
+ $data = l(NULL, 'admin/people/permissions', array(
'attributes' => array(
'class' => array('field-permissions-status', $status_class),
'title' => $title,
@@ -416,7 +447,7 @@ function field_permissions_overview() {
// Allow external modules alter the table headers and rows.
foreach (module_implements('field_permissions_overview_alter') as $module) {
- $function = $module .'_field_permissions_overview_alter';
+ $function = $module . '_field_permissions_overview_alter';
$function($headers, $rows);
}
diff --git a/sites/all/modules/contrib/admin/field_permissions/field_permissions.admin.js b/sites/all/modules/contrib/admin/field_permissions/field_permissions.admin.js
old mode 100755
new mode 100644
index 19aae57a..76ca19da
--- a/sites/all/modules/contrib/admin/field_permissions/field_permissions.admin.js
+++ b/sites/all/modules/contrib/admin/field_permissions/field_permissions.admin.js
@@ -1,63 +1,74 @@
+/**
+ * @file
+ */
+
(function ($) {
-Drupal.behaviors.fieldPermissionsSettings = {
- attach: function (context) {
- // For user fields, we want the "Create own value for field X" permission
- // row to only be displayed when it's meaningful (i.e., when the "Display
- // on user registration form" checkbox is checked).
- var $user_register_form_checkbox, $required_field_checkbox, $create_permission_row;
- $user_register_form_checkbox = $('.form-item-instance-settings-user-register-form .form-checkbox', context);
- if ($user_register_form_checkbox.length) {
- // The "Required field" checkbox can cause the user registration checkbox
- // to change, so we need it also.
- $required_field_checkbox = $('.form-item-instance-required .form-checkbox', context);
- if ($required_field_checkbox.length) {
- // Get the permissions table row corresponding to the "Create own value
- // for field X" permission. The theme_user_admin_permissions() function
- // does not give us a good way to directly detect which row contains
- // the create permissions, so we have rely on the fact that it will be
- // the first row.
- $create_permission_row = $('table#permissions tbody tr', context).filter(':first');
- new Drupal.fieldPermissions.HideCreatePermission($user_register_form_checkbox, $required_field_checkbox, $create_permission_row);
+ Drupal.behaviors.fieldPermissionsSettings = {
+ attach: function (context) {
+ // For user fields, we want the "Create own value for field X" permission
+ // row to only be displayed when it's meaningful (i.e., when the "Display
+ // on user registration form" checkbox is checked).
+ var $user_register_form_checkbox, $required_field_checkbox, $create_permission_row;
+ $user_register_form_checkbox = $('.form-item-instance-settings-user-register-form .form-checkbox', context);
+ if ($user_register_form_checkbox.length) {
+ // The "Required field" checkbox can cause the user registration checkbox
+ // to change, so we need it also.
+ $required_field_checkbox = $('.form-item-instance-required .form-checkbox', context);
+ if ($required_field_checkbox.length) {
+ // Get the permissions table row corresponding to the "Create own value
+ // for field X" permission. The theme_user_admin_permissions() function
+ // does not give us a good way to directly detect which row contains
+ // the create permissions, so we have rely on the fact that it will be
+ // the first row.
+ $create_permission_row = $('table#permissions tbody tr', context).filter(':first');
+ new Drupal.fieldPermissions.HideCreatePermission($user_register_form_checkbox, $required_field_checkbox, $create_permission_row);
+ }
}
+
+ // Show a warning if there's no available permissions matrix.
+ $('#edit-field-field-permissions-permission-warning').toggle(!$('#permissions').length);
+
+ $('[name="field[field_permissions][type]"]').bind('change', function(option) {
+ $('#edit-field-field-permissions-permission-warning').toggle(!$('#permissions').length);
+ });
}
- }
-};
+ };
-Drupal.fieldPermissions = {};
+ Drupal.fieldPermissions = {};
-/**
+ /**
* Constructor for the HideCreatePermission object.
*
* This object hides and shows the "Create own value for field X" permission
* for user fields when it is appropriate to do so, depending on the state of
* the "Display on user registration form" and "Required field" checkboxes.
*/
-Drupal.fieldPermissions.HideCreatePermission = function ($user_register_form_checkbox, $required_field_checkbox, $create_permission_row) {
- this.$user_register_form_checkbox = $user_register_form_checkbox;
- this.$create_permission_row = $create_permission_row;
- // Start off by making sure the create permission row has the correct
- // visibility.
- this.setCreatePermissionVisibility();
- // Set the row's visibility again whenever the user registration checkbox
- // changes, or when the required field checkbox (which controls it) changes.
- $user_register_form_checkbox.bind('change', $.proxy(this.setCreatePermissionVisibility, this));
- $required_field_checkbox.bind('change', $.proxy(this.setCreatePermissionVisibility, this));
-};
+ Drupal.fieldPermissions.HideCreatePermission = function ($user_register_form_checkbox, $required_field_checkbox, $create_permission_row) {
+ this.$user_register_form_checkbox = $user_register_form_checkbox;
+ this.$create_permission_row = $create_permission_row;
+ // Start off by making sure the create permission row has the correct
+ // visibility.
+ this.setCreatePermissionVisibility();
+ // Set the row's visibility again whenever the user registration checkbox
+ // changes, or when the required field checkbox (which controls it) changes.
+ $user_register_form_checkbox.bind('change', $.proxy(this.setCreatePermissionVisibility, this));
+ $required_field_checkbox.bind('change', $.proxy(this.setCreatePermissionVisibility, this));
+ };
-/**
- * Set the correct visibility of the "Create own value for field X" permission.
- */
-Drupal.fieldPermissions.HideCreatePermission.prototype.setCreatePermissionVisibility = function () {
- // Granting permissions for "Create own value for field X" only makes sense
- // when the field is configured to appear on the user registration form, so
- // only show the row in the permissions table then.
- if (this.$user_register_form_checkbox.is(':checked')) {
- this.$create_permission_row.show();
- }
- else {
- this.$create_permission_row.hide();
- }
-};
+ /**
+ * Set the correct visibility of the "Create own value for field X" permission.
+ */
+ Drupal.fieldPermissions.HideCreatePermission.prototype.setCreatePermissionVisibility = function () {
+ // Granting permissions for "Create own value for field X" only makes sense
+ // when the field is configured to appear on the user registration form, so
+ // only show the row in the permissions table then.
+ if (this.$user_register_form_checkbox.is(':checked')) {
+ this.$create_permission_row.show();
+ }
+ else {
+ this.$create_permission_row.hide();
+ }
+ };
})(jQuery);
diff --git a/sites/all/modules/contrib/admin/field_permissions/field_permissions.api.php b/sites/all/modules/contrib/admin/field_permissions/field_permissions.api.php
new file mode 100644
index 00000000..3379c7ad
--- /dev/null
+++ b/sites/all/modules/contrib/admin/field_permissions/field_permissions.api.php
@@ -0,0 +1,85 @@
+uid.
+ * @param object $entity
+ * The entity this field belongs to.
+ */
+// @codingStandardsIgnoreStart
+function hook_field_permissions_userid_ENTITY_TYPE_alter(&$uid, $entity) {
+ // This example always assigns user 15 as the owner of an entity.
+ $uid = 15;
+}
+// @codingStandardsIgnoreEnd
+
+/**
+ * Alter the permissions handled by field_permissions module.
+ *
+ * @param array $permissions
+ * The $permissions array created by the Field permissions module.
+ * @param string $field_label
+ * The field name.
+ */
+function hook_field_permissions_list_alter(&$permissions, $field_label) {
+ $permissions += array(
+ 'view own node preview' => array(
+ 'label' => t('View own field on node preview'),
+ 'title' => t('View own value for field %field on node preview', array('%field' => $field_label)),
+ ),
+ 'view node preview' => array(
+ 'label' => t('View field on node preview'),
+ 'title' => t("View anyone's value for field %field on node preview", array('%field' => $field_label)),
+ ),
+ );
+}
+
+/**
+ * Hook invoked with custom field permissions.
+ *
+ * This hook can be used to revoke access to the field. If access is not
+ * revoked, default access of the Field permissions module will apply.
+ *
+ * @param string $op
+ * The operation to be performed. Possible values: 'edit', 'view'.
+ * @param array $field
+ * The field on which the operation is to be performed.
+ * @param string $entity_type
+ * The type of $entity; for example, 'node' or 'user'.
+ * @param object $entity
+ * (optional) The entity for the operation.
+ * @param object $account
+ * (optional) The account to check; if not given use currently logged in user.
+ *
+ * @return bool
+ * FALSE if the operation is not allowed.
+ *
+ * @see field_permissions_field_access()
+ * @see field_access()
+ */
+function hook_field_permissions_custom_field_access($op, $field, $entity_type, $entity, $account) {
+ if ($op == 'view' && $entity_type == 'node' && !empty($entity)) {
+ // Check if user has access to view this field in any entity.
+ if (!user_access('view node preview ' . $field['field_name'], $account)) {
+ return FALSE;
+ }
+
+ // If the user has permission to view entities that they own, return TRUE if
+ // they own this entity or FALSE if they don't.
+ if (user_access('view own node preview ' . $field['field_name'], $account)) {
+ return _field_permissions_entity_is_owned_by_account($entity, $account);
+ }
+ }
+
+ return TRUE;
+}
diff --git a/sites/all/modules/contrib/admin/field_permissions/field_permissions.info b/sites/all/modules/contrib/admin/field_permissions/field_permissions.info
old mode 100755
new mode 100644
index cdb9f171..0747a9cb
--- a/sites/all/modules/contrib/admin/field_permissions/field_permissions.info
+++ b/sites/all/modules/contrib/admin/field_permissions/field_permissions.info
@@ -2,14 +2,12 @@ name = Field Permissions
description = Set field-level permissions to create, update or view fields.
package = Fields
core = 7.x
-files[] = field_permissions.module
-files[] = field_permissions.admin.inc
files[] = field_permissions.test
configure = admin/reports/fields/permissions
-; Information added by drupal.org packaging script on 2012-01-25
-version = "7.x-1.0-beta2"
+; Information added by Drupal.org packaging script on 2016-10-16
+version = "7.x-1.0"
core = "7.x"
project = "field_permissions"
-datestamp = "1327510549"
+datestamp = "1476649740"
diff --git a/sites/all/modules/contrib/admin/field_permissions/field_permissions.install b/sites/all/modules/contrib/admin/field_permissions/field_permissions.install
old mode 100755
new mode 100644
index 2e3e1981..e4fac9a3
--- a/sites/all/modules/contrib/admin/field_permissions/field_permissions.install
+++ b/sites/all/modules/contrib/admin/field_permissions/field_permissions.install
@@ -16,6 +16,28 @@ function field_permissions_install() {
->execute();
}
+/**
+ * Implements hook_uninstall().
+ */
+function field_permissions_uninstall() {
+
+ // Collect all the field data that reference "field_permissions", within
+ // the field_config table.
+ //
+ $records = db_query("SELECT * FROM field_config WHERE data LIKE '%field_permissions%'");
+
+ foreach ($records as $record) {
+ $data = $record->data;
+ $data = unserialize($data);
+ unset($data['field_permissions']);
+ $data = serialize($data);
+
+ // Update the record.
+ db_query("UPDATE field_config SET data = :data WHERE id = :id",
+ array(':data' => $data, ':id' => $record->id));
+ }
+}
+
/**
* Sets a larger weight for the module so that the Field Permissions become available.
*/
diff --git a/sites/all/modules/contrib/admin/field_permissions/field_permissions.module b/sites/all/modules/contrib/admin/field_permissions/field_permissions.module
old mode 100755
new mode 100644
index bc4d1f5d..ea5667ec
--- a/sites/all/modules/contrib/admin/field_permissions/field_permissions.module
+++ b/sites/all/modules/contrib/admin/field_permissions/field_permissions.module
@@ -79,6 +79,13 @@ function field_permissions_form_field_ui_field_edit_form_alter(&$form, &$form_st
return _field_permissions_field_settings_form_alter($form, $form_state, $form_id);
}
+/**
+ * Implements hook_field_permissions_userid_ENTITY_TYPE_alter().
+ */
+function field_permissions_field_permissions_userid_field_collection_item_alter(&$uid, $entity) {
+ $uid = isset($entity->hostEntity()->uid) ? $entity->hostEntity()->uid : $uid;
+}
+
/**
* Implementation of hook_field_access().
*
@@ -124,6 +131,12 @@ function field_permissions_field_access($op, $field, $entity_type, $entity, $acc
}
// Otherwise, check access by permission.
elseif ($field['field_permissions']['type'] == FIELD_PERMISSIONS_CUSTOM) {
+ // Allow other modules to deny access first.
+ $result = module_invoke_all('field_permissions_custom_field_access', $op, $field, $entity_type, $entity, $account);
+ if (in_array(FALSE, $result)) {
+ return FALSE;
+ }
+
if (!isset($entity)) {
return field_permissions_empty_entity_access($op, $field['field_name'], $account);
}
@@ -258,5 +271,76 @@ function _field_permissions_entity_is_owned_by_account($entity, $account) {
// set (for example, if the entity type does not store a uid or does not have
// a concept of "ownership"), we need to assume that the provided user
// account does not own it.
- return isset($entity->uid) && $entity->uid == $account->uid;
+ $uid = isset($entity->uid) ? $entity->uid : FALSE;
+ if (method_exists($entity, 'entityType')) {
+ drupal_alter('field_permissions_userid_' . $entity->entityType(), $uid, $entity);
+ }
+
+ return $uid === $account->uid;
+}
+
+/**
+ * Implements hook_features_pipe_COMPONENT_alter().
+ *
+ * Add field permissions to features when exporting a field_base.
+ */
+function field_permissions_features_pipe_field_base_alter(&$pipe, $data, $export) {
+ // Validate if there are field_base components that will be exported for this
+ // feature.
+ if (isset($export['features']['field_base'])) {
+ module_load_include('inc', 'field_permissions', 'field_permissions.admin');
+ // Iterate through the exported field_base components for this feature and
+ // add the defined field permissions.
+ foreach ($export['features']['field_base'] as $field_name) {
+ $field = field_info_field($field_name);
+ if (isset($field['field_permissions']['type']) && $field['field_permissions']['type'] == FIELD_PERMISSIONS_CUSTOM) {
+ $perms = field_permissions_list_field_permissions($field, '');
+ foreach ($perms as $perm => $info) {
+ $pipe['user_permission'][] = $perm;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Implements hook_field_attach_form().
+ */
+function field_permissions_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
+ // Some fields are validated if they are #required even if field's #access
+ // property is set to false. For example: file/image fields, options fields.
+ foreach (element_children($form) as $key) {
+ if (isset($form[$key]['#access']) && !$form[$key]['#access']) {
+ _field_permissions_make_elements_non_required($form[$key]);
+ }
+ }
+}
+
+/**
+ * Sets the #required property to FALSE recursively on form elements.
+ */
+function _field_permissions_make_elements_non_required(&$elements) {
+ if (!is_array($elements)) {
+ return;
+ }
+ if (!empty($elements['#required'])) {
+ $elements['#required'] = FALSE;
+ }
+ foreach (element_children($elements) as $key) {
+ _field_permissions_make_elements_non_required($elements[$key]);
+ }
+}
+
+/**
+ * Implements hook_field_delete_field().
+ */
+function field_permissions_field_delete_field($field) {
+ // Delete any permissions related to the deleted field.
+ $all_permissions = array_keys(field_permissions_permission());
+ if (!empty($all_permissions)) {
+ db_delete('role_permission')
+ ->condition('module', 'field_permissions')
+ ->condition('permission', $all_permissions, 'NOT IN')
+ ->execute();
+ }
}
diff --git a/sites/all/modules/contrib/admin/field_permissions/field_permissions.test b/sites/all/modules/contrib/admin/field_permissions/field_permissions.test
old mode 100755
new mode 100644
index 201fa460..c5f85447
--- a/sites/all/modules/contrib/admin/field_permissions/field_permissions.test
+++ b/sites/all/modules/contrib/admin/field_permissions/field_permissions.test
@@ -26,7 +26,7 @@ class FieldPermissionsTestCase extends DrupalWebTestCase {
parent::setUp('field_ui', 'field_permissions');
// Create test user.
- $admin_permissions = array('access content', 'administer nodes', 'bypass node access', 'administer content types', 'administer taxonomy', 'administer permissions', 'create page content');
+ $admin_permissions = array('access content', 'administer nodes', 'bypass node access', 'administer content types', 'administer taxonomy', 'administer permissions', 'create page content', 'administer fields');
$this->limited_user = $this->drupalCreateUser($admin_permissions);
$all_rids = array_keys($this->limited_user->roles);
sort($all_rids);
@@ -162,11 +162,11 @@ class FieldPermissionsTestCase extends DrupalWebTestCase {
// See if we have that exposed on the permissions UI as well now.
$this->drupalGet('admin/people/permissions');
$this->assertText(t('Field Permissions'));
- $this->assertRaw(t('Create own value for field %field', array('%field' => $field_info['name'])));
- $this->assertRaw(t('Edit own value for field %field', array('%field' => $field_info['name'])));
- $this->assertRaw(t("Edit anyone's value for field %field", array('%field' => $field_info['name'])));
- $this->assertRaw(t('View own value for field %field', array('%field' => $field_info['name'])));
- $this->assertRaw(t("View anyone's value for field %field", array('%field' => $field_info['name'])));
+ $this->assertRaw(t('Create own value for field %field', array('%field' => $field_info['machine_name'])));
+ $this->assertRaw(t('Edit own value for field %field', array('%field' => $field_info['machine_name'])));
+ $this->assertRaw(t("Edit anyone's value for field %field", array('%field' => $field_info['machine_name'])));
+ $this->assertRaw(t('View own value for field %field', array('%field' => $field_info['machine_name'])));
+ $this->assertRaw(t("View anyone's value for field %field", array('%field' => $field_info['machine_name'])));
// == CREATE ===============================================================
diff --git a/sites/all/modules/contrib/admin/field_permissions/images/field_permissions.status-off.png b/sites/all/modules/contrib/admin/field_permissions/images/field_permissions.status-off.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/field_permissions/images/field_permissions.status-on.png b/sites/all/modules/contrib/admin/field_permissions/images/field_permissions.status-on.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/fpa/fpa.info b/sites/all/modules/contrib/admin/fpa/fpa.info
index ebf9d126..723283e3 100644
--- a/sites/all/modules/contrib/admin/fpa/fpa.info
+++ b/sites/all/modules/contrib/admin/fpa/fpa.info
@@ -2,9 +2,9 @@ name = "Fast Permissions Administration"
description = "Fast filtering on permissions administration form."
core = 7.x
package = Administration
-; Information added by Drupal.org packaging script on 2014-10-15
-version = "7.x-2.6+1-dev"
+; Information added by Drupal.org packaging script on 2014-08-22
+version = "7.x-2.6"
core = "7.x"
project = "fpa"
-datestamp = "1413408942"
+datestamp = "1408744435"
diff --git a/sites/all/modules/contrib/admin/fpa/fpa.theme.inc b/sites/all/modules/contrib/admin/fpa/fpa.theme.inc
index 4bdbe6a0..0e5a486d 100644
--- a/sites/all/modules/contrib/admin/fpa/fpa.theme.inc
+++ b/sites/all/modules/contrib/admin/fpa/fpa.theme.inc
@@ -519,7 +519,7 @@ function _fpa_wrapper($permissions_table, $modules, $user_roles, $actions_output
$module_item = $module_template;
$module_item[FPA_ATTR_MODULE] = $module[FPA_ATTR_MODULE];
- $module_item[FPA_ATTR_PERMISSION] = array_reduce(array_pad($module[FPA_ATTR_PERMISSION], 1, array()), 'array_merge', array());
+ $module_item[FPA_ATTR_PERMISSION] = array_reduce($module[FPA_ATTR_PERMISSION], 'array_merge', array());
// Use link for accessibility and tabability.
$options = array(
diff --git a/sites/all/modules/contrib/admin/linkit/better-autocomplete/better-autocomplete.css b/sites/all/modules/contrib/admin/linkit/better-autocomplete/better-autocomplete.css
index b8d66fab..2e2a2ab7 100644
--- a/sites/all/modules/contrib/admin/linkit/better-autocomplete/better-autocomplete.css
+++ b/sites/all/modules/contrib/admin/linkit/better-autocomplete/better-autocomplete.css
@@ -24,6 +24,9 @@
cursor: default;
background: white;
border-bottom: 1px solid #bfbfbf;
+ z-index: 10;
+ max-height: 330px;
+ box-shadow: 0 0 15px rgba(0, 0, 0, 0.5); /* Visually indicate that results are in the topmost layer */
}
/* Groups */
@@ -82,3 +85,13 @@
.better-autocomplete > .result.highlight > p {
color: white;
}
+
+/* ARIA */
+
+.better-autocomplete-aria {
+ position: absolute !important;
+ clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
+ clip: rect(1px, 1px, 1px, 1px);
+ overflow: hidden;
+ height: 1px;
+}
diff --git a/sites/all/modules/contrib/admin/linkit/better-autocomplete/jquery.better-autocomplete.js b/sites/all/modules/contrib/admin/linkit/better-autocomplete/jquery.better-autocomplete.js
index d629b096..6927450d 100644
--- a/sites/all/modules/contrib/admin/linkit/better-autocomplete/jquery.better-autocomplete.js
+++ b/sites/all/modules/contrib/admin/linkit/better-autocomplete/jquery.better-autocomplete.js
@@ -1,4 +1,3 @@
-
/**
* @fileOverview Better Autocomplete is a flexible jQuery plugin which offers
* rich text autocompletion, both from local and remote sources.
@@ -97,847 +96,863 @@
(function($) {
-$.fn.betterAutocomplete = function(method) {
+ $.fn.betterAutocomplete = function(method) {
- /*
- * Each method expects the "this" object to be a valid DOM text input node.
- * The methods "enable", "disable" and "destroy" expects an instance of a
- * BetterAutocomplete object as their first argument.
- */
- var methods = {
- init: function(resource, options, callbacks) {
- var $input = $(this),
- bac = new BetterAutocomplete($input, resource, options, callbacks);
- $input.data('better-autocomplete', bac);
- bac.enable();
- },
- enable: function(bac) {
- bac.enable();
- },
- disable: function(bac) {
- bac.disable();
- },
- destroy: function(bac) {
- bac.destroy();
- }
- }, args = Array.prototype.slice.call(arguments, 1);
-
- // Method calling logic
- this.each(function() {
- switch (method) {
- case 'init':
- methods[method].apply(this, args);
- break;
- case 'enable':
- case 'disable':
- case 'destroy':
- var bac = $(this).data('better-autocomplete');
- if (bac instanceof BetterAutocomplete) {
- methods[method].call(this, bac);
+ /*
+ * Each method expects the "this" object to be a valid DOM text input node.
+ * The methods "enable", "disable" and "destroy" expects an instance of a
+ * BetterAutocomplete object as their first argument.
+ */
+ var methods = {
+ init: function(resource, options, callbacks) {
+ var $input = $(this),
+ bac = new BetterAutocomplete($input, resource, options, callbacks);
+ $input.data('better-autocomplete', bac);
+ bac.enable();
+ },
+ enable: function(bac) {
+ bac.enable();
+ },
+ disable: function(bac) {
+ bac.disable();
+ },
+ destroy: function(bac) {
+ bac.destroy();
}
- break;
- default:
- $.error(['Method', method,
- 'does not exist in jQuery.betterAutocomplete.'].join(' '));
- }
- });
+ }, args = Array.prototype.slice.call(arguments, 1);
- // Maintain chainability
- return this;
-};
-
-/**
- * The BetterAutocomplete constructor function. Returns a BetterAutocomplete
- * instance object.
- *
- * @private @constructor
- * @name BetterAutocomplete
- *
- * @param {Object} $input
- * A single input element wrapped in jQuery.
- */
-var BetterAutocomplete = function($input, resource, options, callbacks) {
-
- var lastRenderedQuery = '',
- cache = {}, // Key-valued caching of search results
- cacheOrder = [], // Array of query strings, in the order they are added
- cacheSize = 0, // Keep count of the cache's size
- timer, // Used for options.delay
- activeRemoteCalls = [], // A flat array of query strings that are pending
- disableMouseHighlight = false, // Suppress the autotriggered mouseover event
- inputEvents = {},
- isLocal = ($.type(resource) != 'string'),
- $results = $('
').addClass('better-autocomplete'),
- hiddenResults = true, // $results are hidden
- preventBlurTimer = null; // IE bug workaround, see below in code.
-
- options = $.extend({
- charLimit: isLocal ? 1 : 3,
- delay: 350, // milliseconds
- caseSensitive: false,
- cacheLimit: isLocal ? 0 : 256, // Number of result objects
- remoteTimeout: 10000, // milliseconds
- crossOrigin: false,
- selectKeys: [9, 13], // [tab, enter]
- autoHighlight: true // Automatically highlight the topmost result
- }, options);
-
- callbacks = $.extend({}, defaultCallbacks, callbacks);
-
- callbacks.insertSuggestionList($results, $input);
-
- inputEvents.focus = function() {
- // If the blur timer is active, a redraw is redundant.
- preventBlurTimer || redraw(true);
- };
-
- inputEvents.blur = function() {
- // If the blur prevention timer is active, refocus the input, since the
- // blur event can not be cancelled.
- if (preventBlurTimer) {
- $input.focus();
- }
- else {
- // The input has already lost focus, so redraw the suggestion list.
- redraw();
- }
- };
-
- inputEvents.keydown = function(event) {
- var index = getHighlightedIndex();
- // If an arrow key is pressed and a result is highlighted
- if ($.inArray(event.keyCode, [38, 40]) >= 0 && $results.children().length > 0) {
- var newIndex,
- size = $('.result', $results).length;
- switch (event.keyCode) {
- case 38: // Up arrow
- newIndex = Math.max(0, index - 1);
- break;
- case 40: // Down arrow
- newIndex = Math.min(size - 1, index + 1);
- break;
+ // Method calling logic
+ this.each(function() {
+ switch (method) {
+ case 'init':
+ methods[method].apply(this, args);
+ break;
+ case 'enable':
+ case 'disable':
+ case 'destroy':
+ var bac = $(this).data('better-autocomplete');
+ if (bac instanceof BetterAutocomplete) {
+ methods[method].call(this, bac);
+ }
+ break;
+ default:
+ $.error(['Method', method,
+ 'does not exist in jQuery.betterAutocomplete.'].join(' '));
}
- disableMouseHighlight = true;
- setHighlighted(newIndex, 'key', true);
- return false;
- }
- // A select key has been pressed
- else if ($.inArray(event.keyCode, options.selectKeys) >= 0 &&
- !event.shiftKey && !event.ctrlKey && !event.altKey &&
- !event.metaKey) {
- select();
- return event.keyCode == 9; // Never cancel tab
- }
- };
+ });
- inputEvents.keyup = inputEvents.click = reprocess;
-
- $results.delegate('.result', {
- // When the user hovers a result with the mouse, highlight it.
- mouseenter: function() {
- if (disableMouseHighlight) {
- return;
- }
- setHighlighted($('.result', $results).index($(this)), 'mouse');
- },
- mousemove: function() {
- // Enable mouseover again.
- disableMouseHighlight = false;
- },
- mousedown: function() {
- select();
- return false;
- }
- });
-
- // Prevent blur when clicking on group titles, scrollbars etc.,
- // This event is triggered after the others because of bubbling.
- $results.mousedown(function() {
- // Bug in IE where clicking on scrollbar would trigger a blur event for the
- // input field, despite using preventDefault() on the mousedown event.
- // This workaround locks the blur event on the input for a small time.
- clearTimeout(preventBlurTimer);
- preventBlurTimer = setTimeout(function() {
- preventBlurTimer = null;
- }, 50);
- return false;
- });
-
- // If auto highlight is off, remove highlighting
- $results.mouseleave(function() {
- if (!options.autoHighlight) {
- setHighlighted(-1);
- }
- });
-
- /*
- * PUBLIC METHODS
- */
-
- /**
- * Enable this instance.
- */
- this.enable = function() {
- // Turn off the browser's autocompletion
- $input
- .attr('autocomplete', 'OFF')
- .attr('aria-autocomplete', 'list');
- $input.bind(inputEvents);
+ // Maintain chainability
+ return this;
};
/**
- * Disable this instance.
- */
- this.disable = function() {
- $input
- .removeAttr('autocomplete')
- .removeAttr('aria-autocomplete');
- $results.hide();
- $input.unbind(inputEvents);
- };
-
- /**
- * Disable and remove this instance. This instance should not be reused.
- */
- this.destroy = function() {
- $results.remove();
- $input.unbind(inputEvents);
- $input.removeData('better-autocomplete');
- };
-
- /*
- * PRIVATE METHODS
- */
-
- /**
- * Add an array of results to the cache. Internal methods always reads from
- * the cache, so this method must be invoked even when caching is not used,
- * e.g. when using local results. This method automatically clears as much of
- * the cache as required to fit within the cache limit.
+ * The BetterAutocomplete constructor function. Returns a BetterAutocomplete
+ * instance object.
*
- * @param {String} query
- * The query to set the results to.
+ * @private @constructor
+ * @name BetterAutocomplete
*
- * @param {Array[Object]} results
- * The array of results for this query.
+ * @param {Object} $input
+ * A single input element wrapped in jQuery.
*/
- var cacheResults = function(query, results) {
- cacheSize += results.length;
- // Now reduce size until it fits
- while (cacheSize > options.cacheLimit && cacheOrder.length) {
- var key = cacheOrder.shift();
- cacheSize -= cache[key].length;
- delete cache[key];
- }
- cacheOrder.push(query);
- cache[query] = results;
- };
+ var BetterAutocomplete = function($input, resource, options, callbacks) {
- /**
- * Set highlight to a specific result item
- *
- * @param {Number} index
- * The result item's index, or negative if highlight should be removed.
- *
- * @param {String} [trigger]
- * What triggered the highlight: "mouse", "key" or "auto". If index is
- * negative trigger may be omitted.
- *
- * @param {Boolean} [autoScroll]
- * (default=false) If scrolling of the results list should be automated.
- */
- var setHighlighted = function(index, trigger, autoScroll) {
- //console.log('Index: '+index)
- var prevIndex = getHighlightedIndex(),
- $resultList = $('.result', $results);
- //console.log('prevIndex: '+prevIndex)
- $resultList.removeClass('highlight');
+ var lastRenderedQuery = '',
+ cache = {}, // Key-valued caching of search results
+ cacheOrder = [], // Array of query strings, in the order they are added
+ cacheSize = 0, // Keep count of the cache's size
+ timer, // Used for options.delay
+ activeRemoteCalls = [], // A flat array of query strings that are pending
+ disableMouseHighlight = false, // Suppress the autotriggered mouseover event
+ inputEvents = {},
+ isLocal = ($.type(resource) != 'string'),
+ $results = $('
').addClass('better-autocomplete'),
+ $ariaLive = null,
+ hiddenResults = true, // $results are hidden
+ preventBlurTimer = null; // IE bug workaround, see below in code.
- if (index < 0) {
- return
- }
- $resultList.eq(index).addClass('highlight')
+ options = $.extend({
+ charLimit: isLocal ? 1 : 3,
+ delay: 350, // milliseconds
+ caseSensitive: false,
+ cacheLimit: isLocal ? 0 : 256, // Number of result objects
+ remoteTimeout: 10000, // milliseconds
+ crossOrigin: false,
+ selectKeys: [9, 13], // [tab, enter]
+ autoHighlight: true // Automatically highlight the topmost result
+ }, options);
- if (prevIndex != index) {
- var result = getResultByIndex(index);
- callbacks.highlight(result, $input, trigger);
- }
+ callbacks = $.extend({}, defaultCallbacks, callbacks);
- // Scrolling
- var up = index == 0 || index < prevIndex,
- $scrollTo = $resultList.eq(index);
+ callbacks.insertSuggestionList($results, $input);
- if (!autoScroll) {
- return;
- }
- // Scrolling up, then make sure to show the group title
- if ($scrollTo.prev().is('.group') && up) {
- $scrollTo = $scrollTo.prev();
- }
- // Is $scrollTo partly above the visible region?
- if ($scrollTo.position().top < 0) {
- $results.scrollTop($scrollTo.position().top + $results.scrollTop());
- }
- // Or is it partly below the visible region?
- else if (($scrollTo.position().top + $scrollTo.outerHeight()) >
- $results.height()) {
- $results.scrollTop($scrollTo.position().top + $results.scrollTop() +
- $scrollTo.outerHeight() - $results.height());
- }
- };
+ inputEvents.focus = function() {
+ // If the blur timer is active, a redraw is redundant.
+ preventBlurTimer || redraw(true);
+ };
- /**
- * Retrieve the index of the currently highlighted result item
- *
- * @returns {Number}
- * The result's index or -1 if no result is highlighted.
- */
- var getHighlightedIndex = function() {
- var res = $('.result.highlight', $results)
- ind= $('.result', $results).index(res);
- return ind
- };
-
- /**
- * Retrieve the result object with the specific position in the results list
- *
- * @param {Number} index
- * The index of the item in the current result list.
- *
- * @returns {Object}
- * The result object or null if index out of bounds.
- */
- var getResultByIndex = function(index) {
- var $result = $('.result', $results).eq(index);
- if (!$result.length) {
- return; // No selectable element
- }
- return $result.data('result');
- };
-
- /**
- * Select the current highlighted element, if any.
- */
- var select = function() {
- var highlighted = getHighlightedIndex(),
- result = getResultByIndex(highlighted);
- callbacks.select(result, $input);
- // Redraw again, if the callback changed focus or content
- reprocess();
- };
-
- /**
- * Fetch results asynchronously via AJAX.
- * Errors are ignored.
- *
- * @param {String} query
- * The query string.
- */
- var fetchResults = function(query) {
- // Synchronously fetch local data
- if (isLocal) {
- cacheResults(query, callbacks.queryLocalResults(query, resource,
- options.caseSensitive));
- redraw();
- }
- // Asynchronously fetch remote data
- else {
- activeRemoteCalls.push(query);
- var url = callbacks.constructURL(resource, query);
- callbacks.beginFetching($input);
- callbacks.fetchRemoteData(url, function(data) {
- var searchResults = callbacks.processRemoteData(data);
- if (!$.isArray(searchResults)) {
- searchResults = [];
- }
- cacheResults(query, searchResults);
- // Remove the query from active remote calls, since it's finished
- activeRemoteCalls = $.grep(activeRemoteCalls, function(value) {
- return value != query;
- });
- if (!activeRemoteCalls.length) {
- callbacks.finishFetching($input);
- }
- redraw();
- }, options.remoteTimeout, options.crossOrigin);
- }
- };
-
- /**
- * Reprocess the contents of the input field, fetch data and redraw if
- * necessary.
- *
- * @param {Object} [event]
- * The event that triggered the reprocessing. Not always present.
- */
- function reprocess(event) {
- // If this call was triggered by an arrow key, cancel the reprocessing.
- if ($.type(event) == 'object' && event.type == 'keyup' &&
- $.inArray(event.keyCode, [38, 40]) >= 0) {
- return;
- }
- var query = callbacks.canonicalQuery($input.val(), options.caseSensitive);
- clearTimeout(timer);
- // Indicate that timer is inactive
- timer = null;
- redraw();
- if (query.length >= options.charLimit && !$.isArray(cache[query]) &&
- $.inArray(query, activeRemoteCalls) == -1) {
- // Fetching is required
- $results.empty();
- if (isLocal) {
- fetchResults(query);
+ inputEvents.blur = function() {
+ // If the blur prevention timer is active, refocus the input, since the
+ // blur event can not be cancelled.
+ if (preventBlurTimer) {
+ $input.focus();
}
else {
- timer = setTimeout(function() {
- fetchResults(query);
- timer = null;
- }, options.delay);
+ // The input has already lost focus, so redraw the suggestion list.
+ redraw();
}
- }
- };
+ };
- /**
- * Redraws the autocomplete list based on current query and focus.
- *
- * @param {Boolean} [focus]
- * (default=false) Force to treat the input element like it's focused.
- */
- var redraw = function(focus) {
- var query = callbacks.canonicalQuery($input.val(), options.caseSensitive);
-
- // The query does not exist in db
- if (!$.isArray(cache[query])) {
- lastRenderedQuery = null;
- $results.empty();
- }
- // The query exists and is not already rendered
- else if (lastRenderedQuery !== query) {
- lastRenderedQuery = query;
- renderResults(cache[query]);
- if (options.autoHighlight && $('.result', $results).length > 0) {
- setHighlighted(0, 'auto');
- }
- }
- // Finally show/hide based on focus and emptiness
- if (($input.is(':focus') || focus) && !$results.is(':empty')) {
- $results.filter(':hidden').show() // Show if hidden
- .scrollTop($results.data('scroll-top')); // Reset the lost scrolling
- if (hiddenResults) {
- hiddenResults = false;
- callbacks.afterShow($results);
- }
- }
- else if ($results.is(':visible')) {
- // Store the scrolling position for later
- $results.data('scroll-top', $results.scrollTop())
- .hide(); // Hiding it resets it's scrollTop
- if (!hiddenResults) {
- hiddenResults = true;
- callbacks.afterHide($results);
- }
- }
- };
-
- /**
- * Regenerate the DOM content within the results list for a given set of
- * results. Heavy method, use only when necessary.
- *
- * @param {Array[Object]} results
- * An array of result objects to render.
- */
- var renderResults = function(results) {
- $results.empty();
- var groups = {}; // Key is the group name, value is the heading element.
-
- $.each(results, function(index, result) {
- if ($.type(result) != 'object') {
- return; // Continue
- }
-
- var output = callbacks.themeResult(result);
- if ($.type(output) != 'string') {
- return; // Continue
- }
-
- // Add the group if it doesn't exist
- var group = callbacks.getGroup(result);
- if ($.type(group) == 'string' && !groups[group]) {
- var $groupHeading = $('').addClass('group')
- .append($('').html(group))
- .appendTo($results);
- groups[group] = $groupHeading;
- }
-
- var $result = $('').addClass('result')
- .append(output)
- .data('result', result) // Store the result object on this DOM element
- .addClass(result.addClass);
-
- // First groupless item
- if ($.type(group) != 'string' &&
- !$results.children().first().is('.result')) {
- $results.prepend($result);
- return; // Continue
- }
- var $traverseFrom = ($.type(group) == 'string') ?
- groups[group] : $results.children().first();
- var $target = $traverseFrom.nextUntil('.group').last();
- $result.insertAfter($target.length ? $target : $traverseFrom);
- });
- };
-};
-
-/*
- * CALLBACK METHODS
- */
-
-/**
- * These callbacks are supposed to be overridden by you when you need
- * customization of the default behavior. When you are overriding a callback
- * function, it is a good idea to copy the source code from the default
- * callback function, as a skeleton.
- *
- * @name callbacks
- * @namespace
- */
-var defaultCallbacks = {
- /**
- * @lends callbacks.prototype
- */
-
- /**
- * Gets fired when the user selects a result by clicking or using the
- * keyboard to select an element.
- *
- *
Default behavior: Inserts the result's title into the
- * input field.
- *
- * @param {Object} result
- * The result object that was selected.
- *
- * @param {Object} $input
- * The input DOM element, wrapped in jQuery.
- */
- select: function(result, $input) {
- $input.val(result.title);
- },
-
- /**
- * Gets fired when the a result is highlighted. This may happen either
- * automatically or by user action.
- *
- *
Default behavior: Does nothing.
- *
- * @param {Object} result
- * The result object that was selected.
- *
- * @param {Object} $input
- * The input DOM element, wrapped in jQuery.
- *
- * @param {String} trigger
- * The event which triggered the highlighting. Must be one of the
- * following:
- *
- * "mouse": A mouseover event triggered the highlighting.
- *
- * "key": The user pressed an arrow key to navigate amongst the results.
- *
- * "auto": If options.autoHighlight is set, an automatic highlight of the
- * first result will occur each time a new result set is rendered.
- *
- */
- highlight: function(result, $input, trigger) {
- // Does nothing
- },
-
- /**
- * Given a result object, theme it to HTML.
- *
- *
Default behavior: Wraps result.title in an h4 tag, and
- * result.description in a p tag. Note that no sanitization of malicious
- * scripts is done here. Whatever is within the title/description is just
- * printed out. May contain HTML.
- *
- * @param {Object} result
- * The result object that should be rendered.
- *
- * @returns {String}
- * HTML output, will be wrapped in a list element.
- */
- themeResult: function(result) {
- var output = [];
- if ($.type(result.title) == 'string') {
- output.push('
');
- }
- return output.join('');
- },
-
- /**
- * Retrieve local results from the local resource by providing a query
- * string.
- *
- *
Default behavior: Automatically handles arrays, if the
- * data inside each element is either a plain string or a result object.
- * If it is a result object, it will match the query string against the
- * title and description property. Search is not case sensitive.
- *
- * @param {String} query
- * The query string, unescaped. May contain any UTF-8 character.
- * If case insensitive, it already is lowercased.
- *
- * @param {Object} resource
- * The resource provided in the {@link jQuery.betterAutocomplete} init
- * constructor.
- *
- * @param {Boolean} caseSensitive
- * From options.caseSensitive, the searching should be case sensitive.
- *
- * @returns {Array[Object]}
- * A flat array containing pure result objects. May be an empty array.
- */
- queryLocalResults: function(query, resource, caseSensitive) {
- if (!$.isArray(resource)) {
- // Per default Better Autocomplete only handles arrays
- return [];
- }
- var results = [];
- $.each(resource, function(i, value) {
- switch ($.type(value)) {
- case 'string': // Flat array of strings
- if ((caseSensitive ? value : value.toLowerCase())
- .indexOf(query) >= 0) {
- // Match found
- results.push({ title: value });
+ inputEvents.keydown = function(event) {
+ var index = getHighlightedIndex();
+ // If an arrow key is pressed and a result is highlighted
+ if ($.inArray(event.keyCode, [38, 40]) >= 0 && $results.children().length > 0) {
+ var newIndex,
+ size = $('.result', $results).length;
+ switch (event.keyCode) {
+ case 38: // Up arrow
+ newIndex = Math.max(-1, index - 1);
+ break;
+ case 40: // Down arrow
+ newIndex = Math.min(size - 1, index + 1);
+ break;
}
- break;
- case 'object': // Array of result objects
- if ($.type(value.title) == 'string' &&
- (caseSensitive ? value.title : value.title.toLowerCase())
- .indexOf(query) >= 0) {
- // Match found in title field
- results.push(value);
- }
- else if ($.type(value.description) == 'string' &&
- (caseSensitive ? value.description :
- value.description.toLowerCase()).indexOf(query) >= 0) {
- // Match found in description field
- results.push(value);
- }
- break;
+ disableMouseHighlight = true;
+ setHighlighted(newIndex, 'key', true);
+ return false;
}
- });
- return results;
- },
+ // A select key has been pressed
+ else if ($.inArray(event.keyCode, options.selectKeys) >= 0 &&
+ !event.shiftKey && !event.ctrlKey && !event.altKey &&
+ !event.metaKey) {
+ select();
+ return event.keyCode == 9; // Never cancel tab
+ }
+ };
- /**
- * Fetch remote result data and return it using completeCallback when
- * fetching is finished. Must be asynchronous in order to not freeze the
- * Better Autocomplete instance.
- *
- *
Default behavior: Fetches JSON data from the url, using
- * the jQuery.ajax() method. Errors are ignored.
- *
- * @param {String} url
- * The URL to fetch data from.
- *
- * @param {Function} completeCallback
- * This function must be called, even if an error occurs. It takes zero
- * or one parameter: the data that was fetched.
- *
- * @param {Number} timeout
- * The preferred timeout for the request. This callback should respect
- * the timeout.
- *
- * @param {Boolean} crossOrigin
- * True if a cross origin request should be performed.
- */
- fetchRemoteData: function(url, completeCallback, timeout, crossOrigin) {
- $.ajax({
- url: url,
- dataType: crossOrigin && !$.support.cors ? 'jsonp' : 'json',
- timeout: timeout,
- success: function(data, textStatus) {
- completeCallback(data);
+ inputEvents.keyup = inputEvents.click = reprocess;
+
+ $results.delegate('.result', {
+ // When the user hovers a result with the mouse, highlight it.
+ mouseenter: function() {
+ if (disableMouseHighlight) {
+ return;
+ }
+ setHighlighted($('.result', $results).index($(this)), 'mouse');
},
- error: function(jqXHR, textStatus, errorThrown) {
- completeCallback();
+ mousemove: function() {
+ // Enable mouseover again.
+ disableMouseHighlight = false;
+ },
+ mousedown: function() {
+ select();
+ return false;
}
});
- },
- /**
- * Process remote fetched data by extracting an array of result objects
- * from it. This callback is useful if the fetched data is not the plain
- * results array, but a more complicated object which does contain results.
- *
- *
Default behavior: If the data is defined and is an
- * array, return it. Otherwise return an empty array.
- *
- * @param {mixed} data
- * The raw data recieved from the server. Can be undefined.
- *
- * @returns {Array[Object]}
- * A flat array containing result objects. May be an empty array.
- */
- processRemoteData: function(data) {
- if ($.isArray(data)) {
- return data;
- }
- else {
- return [];
- }
- },
+ // Prevent blur when clicking on group titles, scrollbars etc.,
+ // This event is triggered after the others because of bubbling.
+ $results.mousedown(function() {
+ // Bug in IE where clicking on scrollbar would trigger a blur event for the
+ // input field, despite using preventDefault() on the mousedown event.
+ // This workaround locks the blur event on the input for a small time.
+ clearTimeout(preventBlurTimer);
+ preventBlurTimer = setTimeout(function() {
+ preventBlurTimer = null;
+ }, 50);
+ return false;
+ });
- /**
- * From a given result object, return it's group name (if any). Used for
- * grouping results together.
- *
- *
Default behavior: If the result has a "group" property
- * defined, return it.
- *
- * @param {Object} result
- * The result object.
- *
- * @returns {String}
- * The group name, may contain HTML. If no group, don't return anything.
- */
- getGroup: function(result) {
- if ($.type(result.group) == 'string') {
- return result.group;
- }
- },
+ // If auto highlight is off, remove highlighting
+ $results.mouseleave(function() {
+ if (!options.autoHighlight) {
+ setHighlighted(-1);
+ }
+ });
- /**
- * Called when remote fetching begins.
- *
- *
Default behavior: Adds the CSS class "fetching" to the
- * input field, for styling purposes.
- *
- * @param {Object} $input
- * The input DOM element, wrapped in jQuery.
- */
- beginFetching: function($input) {
- $input.addClass('fetching');
- },
+ /*
+ * PUBLIC METHODS
+ */
- /**
- * Called when fetching is finished. All active requests must finish before
- * this function is called.
- *
- *
Default behavior: Removes the "fetching" class.
- *
- * @param {Object} $input
- * The input DOM element, wrapped in jQuery.
- */
- finishFetching: function($input) {
- $input.removeClass('fetching');
- },
+ /**
+ * Enable this instance.
+ */
+ this.enable = function() {
+ // Turn off the browser's autocompletion
+ $input
+ .attr('autocomplete', 'OFF')
+ .attr('aria-autocomplete', 'list')
+ .parent()
+ .attr('role', 'application')
+ .append($('').attr({
+ 'aria-live': 'assertive',
+ 'id': $input.attr('id') + '-autocomplete-aria-live'
+ }));
+ $input.bind(inputEvents);
+ $ariaLive = $('#' + $input.attr('id') + '-autocomplete-aria-live');
+ };
- /**
- * Executed after the suggestion list has been shown.
- *
- * @param {Object} $results
- * The suggestion list UL element, wrapped in jQuery.
- *
- *
Default behavior: Does nothing.
- */
- afterShow: function($results) {},
+ /**
+ * Disable this instance.
+ */
+ this.disable = function() {
+ $input
+ .removeAttr('autocomplete')
+ .removeAttr('aria-autocomplete')
+ .parent()
+ .removeAttr('role');
+ $results.hide();
+ $ariaLive.empty();
+ $input.unbind(inputEvents);
+ };
- /**
- * Executed after the suggestion list has been hidden.
- *
- * @param {Object} $results
- * The suggestion list UL element, wrapped in jQuery.
- *
- *
Default behavior: Does nothing.
- */
- afterHide: function($results) {},
+ /**
+ * Disable and remove this instance. This instance should not be reused.
+ */
+ this.destroy = function() {
+ $results.remove();
+ $ariaLive.remove();
+ $input.unbind(inputEvents);
+ $input.removeData('better-autocomplete');
+ };
- /**
- * Construct the remote fetching URL.
- *
- *
Default behavior: Adds "?q=" or "&q=" to the
- * path. The query string is URL encoded.
- *
- * @param {String} path
- * The path given in the {@link jQuery.betterAutocomplete} constructor.
- *
- * @param {String} query
- * The raw query string. Remember to URL encode this to prevent illegal
- * character errors.
- *
- * @returns {String}
- * The URL, ready for fetching.
- */
- constructURL: function(path, query) {
- return path + (path.indexOf('?') > -1 ? '&' : '?') + 'q=' + encodeURIComponent(query);
- },
+ /*
+ * PRIVATE METHODS
+ */
- /**
- * To ease up on server load, treat similar strings the same.
- *
- *
Default behavior: Trims the query from leading and
- * trailing whitespace.
- *
- * @param {String} rawQuery
- * The user's raw input.
- *
- * @param {Boolean} caseSensitive
- * Case sensitive. Will convert to lowercase if false.
- *
- * @returns {String}
- * The canonical query associated with this string.
- */
- canonicalQuery: function(rawQuery, caseSensitive) {
- var query = $.trim(rawQuery);
- if (!caseSensitive) {
- query = query.toLowerCase();
- }
- return query;
- },
+ /**
+ * Add an array of results to the cache. Internal methods always reads from
+ * the cache, so this method must be invoked even when caching is not used,
+ * e.g. when using local results. This method automatically clears as much of
+ * the cache as required to fit within the cache limit.
+ *
+ * @param {String} query
+ * The query to set the results to.
+ *
+ * @param {Array[Object]} results
+ * The array of results for this query.
+ */
+ var cacheResults = function(query, results) {
+ cacheSize += results.length;
+ // Now reduce size until it fits
+ while (cacheSize > options.cacheLimit && cacheOrder.length) {
+ var key = cacheOrder.shift();
+ cacheSize -= cache[key].length;
+ delete cache[key];
+ }
+ cacheOrder.push(query);
+ cache[query] = results;
+ };
- /**
- * Insert the results list into the DOM and position it properly.
- *
- *
Default behavior: Inserts suggestion list directly
- * after the input element and sets an absolute position using
- * jQuery.position() for determining left/top values. Also adds a nice
- * looking box-shadow to the list.
- *
- * @param {Object} $results
- * The UL list element to insert, wrapped in jQuery.
- *
- * @param {Object} $input
- * The text input element, wrapped in jQuery.
- */
- insertSuggestionList: function($results, $input) {
- $results.width($input.outerWidth() - 2) // Subtract border width.
- .css({
- position: 'absolute',
- zIndex: 10,
- maxHeight: '330px',
- // Visually indicate that results are in the topmost layer
- boxShadow: '0 0 15px rgba(0, 0, 0, 0.5)'
- })
- .hide()
- .insertAfter($input);
- }
-};
+ /**
+ * Set highlight to a specific result item
+ *
+ * @param {Number} index
+ * The result item's index, or negative if highlight should be removed.
+ *
+ * @param {String} [trigger]
+ * What triggered the highlight: "mouse", "key" or "auto". If index is
+ * negative trigger may be omitted.
+ *
+ * @param {Boolean} [autoScroll]
+ * (default=false) If scrolling of the results list should be automated.
+ */
+ var setHighlighted = function(index, trigger, autoScroll) {
+ //console.log('Index: '+index)
+ var prevIndex = getHighlightedIndex(),
+ $resultList = $('.result', $results);
+ //console.log('prevIndex: '+prevIndex)
+ $resultList.removeClass('highlight');
-/*
- * jQuery focus selector, required by Better Autocomplete.
- *
- * @see http://stackoverflow.com/questions/967096/using-jquery-to-test-if-an-input-has-focus/2684561#2684561
- */
-var filters = $.expr[':'];
-if (!filters.focus) {
- filters.focus = function(elem) {
- return elem === document.activeElement && (elem.type || elem.href);
+ if (index < 0) {
+ return
+ }
+ $resultList.eq(index).addClass('highlight')
+
+ if (prevIndex != index) {
+ $ariaLive.html($resultList.eq(index).html());
+ var result = getResultByIndex(index);
+ callbacks.highlight(result, $input, trigger);
+ }
+
+ // Scrolling
+ var up = index == 0 || index < prevIndex,
+ $scrollTo = $resultList.eq(index);
+
+ if (!autoScroll) {
+ return;
+ }
+ // Scrolling up, then make sure to show the group title
+ if ($scrollTo.prev().is('.group') && up) {
+ $scrollTo = $scrollTo.prev();
+ }
+ // Is $scrollTo partly above the visible region?
+ if ($scrollTo.position().top < 0) {
+ $results.scrollTop($scrollTo.position().top + $results.scrollTop());
+ }
+ // Or is it partly below the visible region?
+ else if (($scrollTo.position().top + $scrollTo.outerHeight()) >
+ $results.height()) {
+ $results.scrollTop($scrollTo.position().top + $results.scrollTop() +
+ $scrollTo.outerHeight() - $results.height());
+ }
+ };
+
+ /**
+ * Retrieve the index of the currently highlighted result item
+ *
+ * @returns {Number}
+ * The result's index or -1 if no result is highlighted.
+ */
+ var getHighlightedIndex = function() {
+ var res = $('.result.highlight', $results)
+ ind= $('.result', $results).index(res);
+ return ind
+ };
+
+ /**
+ * Retrieve the result object with the specific position in the results list
+ *
+ * @param {Number} index
+ * The index of the item in the current result list.
+ *
+ * @returns {Object}
+ * The result object or null if index out of bounds.
+ */
+ var getResultByIndex = function(index) {
+ var $result = $('.result', $results).eq(index);
+ if (!$result.length) {
+ return; // No selectable element
+ }
+ return $result.data('result');
+ };
+
+ /**
+ * Select the current highlighted element, if any.
+ */
+ var select = function() {
+ var highlighted = getHighlightedIndex();
+ if(highlighted >= 0){
+ var result = getResultByIndex(highlighted);
+ callbacks.select(result, $input);
+ // Redraw again, if the callback changed focus or content
+ reprocess();
+ }
+ };
+
+ /**
+ * Fetch results asynchronously via AJAX.
+ * Errors are ignored.
+ *
+ * @param {String} query
+ * The query string.
+ */
+ var fetchResults = function(query) {
+ // Synchronously fetch local data
+ if (isLocal) {
+ cacheResults(query, callbacks.queryLocalResults(query, resource,
+ options.caseSensitive));
+ redraw();
+ }
+ // Asynchronously fetch remote data
+ else {
+ activeRemoteCalls.push(query);
+ var url = callbacks.constructURL(resource, query);
+ $ariaLive.html('Searching for matches...');
+ callbacks.beginFetching($input);
+ callbacks.fetchRemoteData(url, function(data) {
+ var searchResults = callbacks.processRemoteData(data);
+ if (!$.isArray(searchResults)) {
+ searchResults = [];
+ }
+ cacheResults(query, searchResults);
+ // Remove the query from active remote calls, since it's finished
+ activeRemoteCalls = $.grep(activeRemoteCalls, function(value) {
+ return value != query;
+ });
+ if (!activeRemoteCalls.length) {
+ callbacks.finishFetching($input);
+ }
+ redraw();
+ }, options.remoteTimeout, options.crossOrigin);
+ }
+ };
+
+ /**
+ * Reprocess the contents of the input field, fetch data and redraw if
+ * necessary.
+ *
+ * @param {Object} [event]
+ * The event that triggered the reprocessing. Not always present.
+ */
+ function reprocess(event) {
+ // If this call was triggered by an arrow key, cancel the reprocessing.
+ if ($.type(event) == 'object' && event.type == 'keyup' &&
+ $.inArray(event.keyCode, [38, 40]) >= 0) {
+ return;
+ }
+ var query = callbacks.canonicalQuery($input.val(), options.caseSensitive);
+ clearTimeout(timer);
+ // Indicate that timer is inactive
+ timer = null;
+ redraw();
+ if (query.length >= options.charLimit && !$.isArray(cache[query]) &&
+ $.inArray(query, activeRemoteCalls) == -1) {
+ // Fetching is required
+ $results.empty();
+ if (isLocal) {
+ fetchResults(query);
+ }
+ else {
+ timer = setTimeout(function() {
+ fetchResults(query);
+ timer = null;
+ }, options.delay);
+ }
+ }
+ };
+
+ /**
+ * Redraws the autocomplete list based on current query and focus.
+ *
+ * @param {Boolean} [focus]
+ * (default=false) Force to treat the input element like it's focused.
+ */
+ var redraw = function(focus) {
+ var query = callbacks.canonicalQuery($input.val(), options.caseSensitive);
+
+ // The query does not exist in db
+ if (!$.isArray(cache[query])) {
+ lastRenderedQuery = null;
+ $results.empty();
+ }
+ // The query exists and is not already rendered
+ else if (lastRenderedQuery !== query) {
+ lastRenderedQuery = query;
+ renderResults(cache[query]);
+ }
+ // Finally show/hide based on focus and emptiness
+ if (($input.is(':focus') || focus) && !$results.is(':empty')) {
+ $results.filter(':hidden').show() // Show if hidden
+ .scrollTop($results.data('scroll-top')); // Reset the lost scrolling
+ if (hiddenResults) {
+ hiddenResults = false;
+ $ariaLive.html('Autocomplete popup');
+ if (options.autoHighlight && $('.result', $results).length > 0) {
+ setHighlighted(0, 'auto');
+ }
+ callbacks.afterShow($results);
+ }
+ }
+ else if ($results.is(':visible')) {
+ // Store the scrolling position for later
+ $results.data('scroll-top', $results.scrollTop())
+ .hide(); // Hiding it resets it's scrollTop
+ if (!hiddenResults) {
+ hiddenResults = true;
+ $ariaLive.empty();
+ callbacks.afterHide($results);
+ }
+ }
+ };
+
+ /**
+ * Regenerate the DOM content within the results list for a given set of
+ * results. Heavy method, use only when necessary.
+ *
+ * @param {Array[Object]} results
+ * An array of result objects to render.
+ */
+ var renderResults = function(results) {
+ $results.empty();
+ var groups = {}; // Key is the group name, value is the heading element.
+
+ $.each(results, function(index, result) {
+ if ($.type(result) != 'object') {
+ return; // Continue
+ }
+
+ var output = callbacks.themeResult(result);
+ if ($.type(output) != 'string') {
+ return; // Continue
+ }
+
+ // Add the group if it doesn't exist
+ var group = callbacks.getGroup(result);
+ if ($.type(group) == 'string' && !groups[group]) {
+ var $groupHeading = $('').addClass('group')
+ .append($('').html(group))
+ .appendTo($results);
+ groups[group] = $groupHeading;
+ }
+
+ var $result = $('').addClass('result')
+ .append(output)
+ .data('result', result) // Store the result object on this DOM element
+ .addClass(result.addClass);
+
+ // First groupless item
+ if ($.type(group) != 'string' &&
+ !$results.children().first().is('.result')) {
+ $results.prepend($result);
+ return; // Continue
+ }
+ var $traverseFrom = ($.type(group) == 'string') ?
+ groups[group] : $results.children().first();
+ var $target = $traverseFrom.nextUntil('.group').last();
+ $result.insertAfter($target.length ? $target : $traverseFrom);
+ });
+ };
};
-}
+
+ /*
+ * CALLBACK METHODS
+ */
+
+ /**
+ * These callbacks are supposed to be overridden by you when you need
+ * customization of the default behavior. When you are overriding a callback
+ * function, it is a good idea to copy the source code from the default
+ * callback function, as a skeleton.
+ *
+ * @name callbacks
+ * @namespace
+ */
+ var defaultCallbacks = {
+ /**
+ * @lends callbacks.prototype
+ */
+
+ /**
+ * Gets fired when the user selects a result by clicking or using the
+ * keyboard to select an element.
+ *
+ *
Default behavior: Inserts the result's title into the
+ * input field.
+ *
+ * @param {Object} result
+ * The result object that was selected.
+ *
+ * @param {Object} $input
+ * The input DOM element, wrapped in jQuery.
+ */
+ select: function(result, $input) {
+ $input.val(result.title);
+ },
+
+ /**
+ * Gets fired when the a result is highlighted. This may happen either
+ * automatically or by user action.
+ *
+ *
Default behavior: Does nothing.
+ *
+ * @param {Object} result
+ * The result object that was selected.
+ *
+ * @param {Object} $input
+ * The input DOM element, wrapped in jQuery.
+ *
+ * @param {String} trigger
+ * The event which triggered the highlighting. Must be one of the
+ * following:
+ *
+ * "mouse": A mouseover event triggered the highlighting.
+ *
+ * "key": The user pressed an arrow key to navigate amongst the results.
+ *
+ * "auto": If options.autoHighlight is set, an automatic highlight of the
+ * first result will occur each time a new result set is rendered.
+ *
+ */
+ highlight: function(result, $input, trigger) {
+ // Does nothing
+ },
+
+ /**
+ * Given a result object, theme it to HTML.
+ *
+ *
Default behavior: Wraps result.title in an h4 tag, and
+ * result.description in a p tag. Note that no sanitization of malicious
+ * scripts is done here. Whatever is within the title/description is just
+ * printed out. May contain HTML.
+ *
+ * @param {Object} result
+ * The result object that should be rendered.
+ *
+ * @returns {String}
+ * HTML output, will be wrapped in a list element.
+ */
+ themeResult: function(result) {
+ var output = [];
+ if ($.type(result.title) == 'string') {
+ output.push('
');
+ }
+ return output.join('');
+ },
+
+ /**
+ * Retrieve local results from the local resource by providing a query
+ * string.
+ *
+ *
Default behavior: Automatically handles arrays, if the
+ * data inside each element is either a plain string or a result object.
+ * If it is a result object, it will match the query string against the
+ * title and description property. Search is not case sensitive.
+ *
+ * @param {String} query
+ * The query string, unescaped. May contain any UTF-8 character.
+ * If case insensitive, it already is lowercased.
+ *
+ * @param {Object} resource
+ * The resource provided in the {@link jQuery.betterAutocomplete} init
+ * constructor.
+ *
+ * @param {Boolean} caseSensitive
+ * From options.caseSensitive, the searching should be case sensitive.
+ *
+ * @returns {Array[Object]}
+ * A flat array containing pure result objects. May be an empty array.
+ */
+ queryLocalResults: function(query, resource, caseSensitive) {
+ if (!$.isArray(resource)) {
+ // Per default Better Autocomplete only handles arrays
+ return [];
+ }
+ var results = [];
+ $.each(resource, function(i, value) {
+ switch ($.type(value)) {
+ case 'string': // Flat array of strings
+ if ((caseSensitive ? value : value.toLowerCase())
+ .indexOf(query) >= 0) {
+ // Match found
+ results.push({ title: value });
+ }
+ break;
+ case 'object': // Array of result objects
+ if ($.type(value.title) == 'string' &&
+ (caseSensitive ? value.title : value.title.toLowerCase())
+ .indexOf(query) >= 0) {
+ // Match found in title field
+ results.push(value);
+ }
+ else if ($.type(value.description) == 'string' &&
+ (caseSensitive ? value.description :
+ value.description.toLowerCase()).indexOf(query) >= 0) {
+ // Match found in description field
+ results.push(value);
+ }
+ break;
+ }
+ });
+ return results;
+ },
+
+ /**
+ * Fetch remote result data and return it using completeCallback when
+ * fetching is finished. Must be asynchronous in order to not freeze the
+ * Better Autocomplete instance.
+ *
+ *
Default behavior: Fetches JSON data from the url, using
+ * the jQuery.ajax() method. Errors are ignored.
+ *
+ * @param {String} url
+ * The URL to fetch data from.
+ *
+ * @param {Function} completeCallback
+ * This function must be called, even if an error occurs. It takes zero
+ * or one parameter: the data that was fetched.
+ *
+ * @param {Number} timeout
+ * The preferred timeout for the request. This callback should respect
+ * the timeout.
+ *
+ * @param {Boolean} crossOrigin
+ * True if a cross origin request should be performed.
+ */
+ fetchRemoteData: function(url, completeCallback, timeout, crossOrigin) {
+ $.ajax({
+ url: url,
+ dataType: crossOrigin && !$.support.cors ? 'jsonp' : 'json',
+ timeout: timeout,
+ success: function(data, textStatus) {
+ completeCallback(data);
+ },
+ error: function(jqXHR, textStatus, errorThrown) {
+ completeCallback();
+ }
+ });
+ },
+
+ /**
+ * Process remote fetched data by extracting an array of result objects
+ * from it. This callback is useful if the fetched data is not the plain
+ * results array, but a more complicated object which does contain results.
+ *
+ *
Default behavior: If the data is defined and is an
+ * array, return it. Otherwise return an empty array.
+ *
+ * @param {mixed} data
+ * The raw data recieved from the server. Can be undefined.
+ *
+ * @returns {Array[Object]}
+ * A flat array containing result objects. May be an empty array.
+ */
+ processRemoteData: function(data) {
+ if ($.isArray(data)) {
+ return data;
+ }
+ else {
+ return [];
+ }
+ },
+
+ /**
+ * From a given result object, return it's group name (if any). Used for
+ * grouping results together.
+ *
+ *
Default behavior: If the result has a "group" property
+ * defined, return it.
+ *
+ * @param {Object} result
+ * The result object.
+ *
+ * @returns {String}
+ * The group name, may contain HTML. If no group, don't return anything.
+ */
+ getGroup: function(result) {
+ if ($.type(result.group) == 'string') {
+ return result.group;
+ }
+ },
+
+ /**
+ * Called when remote fetching begins.
+ *
+ *
Default behavior: Adds the CSS class "fetching" to the
+ * input field, for styling purposes.
+ *
+ * @param {Object} $input
+ * The input DOM element, wrapped in jQuery.
+ */
+ beginFetching: function($input) {
+ $input.addClass('fetching');
+ },
+
+ /**
+ * Called when fetching is finished. All active requests must finish before
+ * this function is called.
+ *
+ *
Default behavior: Removes the "fetching" class.
+ *
+ * @param {Object} $input
+ * The input DOM element, wrapped in jQuery.
+ */
+ finishFetching: function($input) {
+ $input.removeClass('fetching');
+ },
+
+ /**
+ * Executed after the suggestion list has been shown.
+ *
+ * @param {Object} $results
+ * The suggestion list UL element, wrapped in jQuery.
+ *
+ *
Default behavior: Does nothing.
+ */
+ afterShow: function($results) {},
+
+ /**
+ * Executed after the suggestion list has been hidden.
+ *
+ * @param {Object} $results
+ * The suggestion list UL element, wrapped in jQuery.
+ *
+ *
Default behavior: Adds "?q=" or "&q=" to the
+ * path. The query string is URL encoded.
+ *
+ * @param {String} path
+ * The path given in the {@link jQuery.betterAutocomplete} constructor.
+ *
+ * @param {String} query
+ * The raw query string. Remember to URL encode this to prevent illegal
+ * character errors.
+ *
+ * @returns {String}
+ * The URL, ready for fetching.
+ */
+ constructURL: function(path, query) {
+ return path + (path.indexOf('?') > -1 ? '&' : '?') + 'q=' + encodeURIComponent(query);
+ },
+
+ /**
+ * To ease up on server load, treat similar strings the same.
+ *
+ *
Default behavior: Trims the query from leading and
+ * trailing whitespace.
+ *
+ * @param {String} rawQuery
+ * The user's raw input.
+ *
+ * @param {Boolean} caseSensitive
+ * Case sensitive. Will convert to lowercase if false.
+ *
+ * @returns {String}
+ * The canonical query associated with this string.
+ */
+ canonicalQuery: function(rawQuery, caseSensitive) {
+ var query = $.trim(rawQuery);
+ if (!caseSensitive) {
+ query = query.toLowerCase();
+ }
+ return query;
+ },
+
+ /**
+ * Insert the results list into the DOM and position it properly.
+ *
+ *
Default behavior: Inserts suggestion list directly
+ * after the input element and sets an absolute position using
+ * jQuery.position() for determining left/top values. Also adds a nice
+ * looking box-shadow to the list.
+ *
+ * @param {Object} $results
+ * The UL list element to insert, wrapped in jQuery.
+ *
+ * @param {Object} $input
+ * The text input element, wrapped in jQuery.
+ */
+ insertSuggestionList: function($results, $input) {
+ $results.width($input.outerWidth() - 2) // Subtract border width.
+ .css({
+ position: 'absolute',
+ left: $input.position().left,
+ top: $input.position().top + $input.outerHeight()
+ })
+ .hide()
+ .insertAfter($input);
+ }
+ };
+
+ /*
+ * jQuery focus selector, required by Better Autocomplete.
+ *
+ * @see http://stackoverflow.com/questions/967096/using-jquery-to-test-if-an-input-has-focus/2684561#2684561
+ */
+ var filters = $.expr[':'];
+ if (!filters.focus) {
+ filters.focus = function(elem) {
+ return elem === document.activeElement && (elem.type || elem.href);
+ };
+ }
})(jQuery);
diff --git a/sites/all/modules/contrib/admin/linkit/css/linkit.css b/sites/all/modules/contrib/admin/linkit/css/linkit.css
index c928ce7f..408aafe8 100644
--- a/sites/all/modules/contrib/admin/linkit/css/linkit.css
+++ b/sites/all/modules/contrib/admin/linkit/css/linkit.css
@@ -172,6 +172,8 @@
.better-autocomplete {
background-color: transparent;
border-bottom: none;
+ box-shadow: none;
+ z-index: inherit;
}
.better-autocomplete > .result.status-ok {
background: #397928;
@@ -219,4 +221,8 @@
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
border-bottom: 1px solid #BFBFBF;
-}
\ No newline at end of file
+}
+
+.ui-dialog.ui-front.linkit-wrapper {
+ z-index: 2000;
+}
diff --git a/sites/all/modules/contrib/admin/linkit/editors/ckeditor/linkitDialog.js b/sites/all/modules/contrib/admin/linkit/editors/ckeditor/linkitDialog.js
index d9cf67aa..8ab82aa3 100644
--- a/sites/all/modules/contrib/admin/linkit/editors/ckeditor/linkitDialog.js
+++ b/sites/all/modules/contrib/admin/linkit/editors/ckeditor/linkitDialog.js
@@ -17,7 +17,7 @@ Drupal.linkit.registerDialogHelper('ckeditor', {
*/
afterInit : function () {
var editor = Drupal.settings.linkit.currentInstance.editor;
- var element = CKEDITOR.plugins.link.getSelectedLink( editor );
+ var element = CKEDITOR.plugins.link.getSelectedLink(editor);
// If we have selected a link element, lets populate the fields in the
// modal with the values from that link element.
diff --git a/sites/all/modules/contrib/admin/linkit/editors/ckeditor/plugin.js b/sites/all/modules/contrib/admin/linkit/editors/ckeditor/plugin.js
index 3fd9eb51..06ada19f 100644
--- a/sites/all/modules/contrib/admin/linkit/editors/ckeditor/plugin.js
+++ b/sites/all/modules/contrib/admin/linkit/editors/ckeditor/plugin.js
@@ -41,8 +41,20 @@
// Set the editor object.
Drupal.settings.linkit.currentInstance.editor = editor;
- // Set profile.
- Drupal.settings.linkit.currentInstance.profile = Drupal.settings.linkit.fields[editor.name].profile;
+ // Find the current input format of the field we're looking at.
+ var format = '';
+ if (Drupal.wysiwyg) { // If using the WYSIWYG module with CKEditor as the editor
+ // Note that WYSIWYG prepends "profile" to the profile name, so we use .substring() to remove the "format".
+ format = Drupal.wysiwyg.instances[editor.name].format.substring(6);
+ }
+ else if (Drupal.settings.ckeditor) { // If using the CKEditor module
+ format = Drupal.settings.ckeditor.elements[editor.name];
+ } else {
+ alert(Drupal.t('Could not find the Linkit profile.'));
+ return;
+ }
+ // Set profile based on the current text format of this field.
+ Drupal.settings.linkit.currentInstance.profile = Drupal.settings.linkit.formats[format].profile;
// Set the name of the source field.
Drupal.settings.linkit.currentInstance.source = editor.name;
// Set the source type.
@@ -108,18 +120,22 @@
// Add a shortcut. Only CKeditor version 4 has this function.
if (version >= 4) {
- editor.setKeystroke( CKEDITOR.CTRL + 76 /*L*/, 'linkit' );
+ editor.setKeystroke(CKEDITOR.CTRL + 76 /*L*/, 'linkit');
}
// Add event listener.
- editor.on( 'doubleclick', function( evt ) {
+ editor.on('doubleclick', function(evt) {
+ if (evt.data.dialog !== 'link') {
+ return;
+ }
+
// Delete the default link dialog.
delete evt.data.dialog;
- var element = CKEDITOR.plugins.link.getSelectedLink( editor ) || evt.data.element;
- if ( !element.isReadOnly() ) {
- if ( element.is( 'a' ) ) {
- editor.getSelection().selectElement( element );
+ var element = CKEDITOR.plugins.link.getSelectedLink(editor) || evt.data.element;
+ if (!element.isReadOnly()) {
+ if (element.is( 'a' )) {
+ editor.getSelection().selectElement(element);
if (version >= 4) {
editor.commands.linkit.exec();
}
@@ -131,7 +147,7 @@
});
// Register an extra fucntion, this will be used in the modal.
- editor._.linkitFnNum = CKEDITOR.tools.addFunction( insertLink, editor );
+ editor._.linkitFnNum = CKEDITOR.tools.addFunction(insertLink, editor);
}
});
@@ -150,7 +166,7 @@
var range = selection.getRanges(1)[0];
if (range.collapsed) {
var content = (Drupal.settings.linkit.currentInstance.linkContent) ? Drupal.settings.linkit.currentInstance.linkContent : data.path;
- var text = new CKEDITOR.dom.text(content , editor.document );
+ var text = new CKEDITOR.dom.text(content , editor.document);
range.insertNode(text);
range.selectNodeContents(text);
}
diff --git a/sites/all/modules/contrib/admin/linkit/editors/tinymce/editor_plugin.js b/sites/all/modules/contrib/admin/linkit/editors/tinymce/editor_plugin.js
index 3b894566..904bbcc3 100644
--- a/sites/all/modules/contrib/admin/linkit/editors/tinymce/editor_plugin.js
+++ b/sites/all/modules/contrib/admin/linkit/editors/tinymce/editor_plugin.js
@@ -17,8 +17,18 @@
// Set the editor object.
Drupal.settings.linkit.currentInstance.editor = editor;
- // Set profile.
- Drupal.settings.linkit.currentInstance.profile = Drupal.settings.linkit.fields[editor.id].profile;
+
+ // Find the current input format of the field we're looking at. Note that we get it in the form
+ // "format" so we use .substring() to remove the "format".
+ if (Drupal.wysiwyg && Drupal.wysiwyg.instances[editor.id].format) {
+ var format = Drupal.wysiwyg.instances[editor.id].format.substring(6);
+ } else {
+ alert(Drupal.t('Could not find the Linkit profile.'));
+ return;
+ }
+
+ // Set profile based on the current text format of this field.
+ Drupal.settings.linkit.currentInstance.profile = Drupal.settings.linkit.formats[format].profile;
// Set the name of the source field..
Drupal.settings.linkit.currentInstance.source = editor.id;
diff --git a/sites/all/modules/contrib/admin/linkit/js/linkit.dashboard.js b/sites/all/modules/contrib/admin/linkit/js/linkit.dashboard.js
index 3362f3c3..10265762 100644
--- a/sites/all/modules/contrib/admin/linkit/js/linkit.dashboard.js
+++ b/sites/all/modules/contrib/admin/linkit/js/linkit.dashboard.js
@@ -9,13 +9,13 @@ Drupal.behaviors.linkitDashboard = {
attach: function (context, settings) {
// Bind the insert link button.
$('.linkit-insert', context).once('linkit-insert', function() {
- $('.linkit-insert', context).click(function() {
+ $('.linkit-insert', context).click(function(event) {
+ event.preventDefault();
// Call the insertLink() function.
Drupal.linkit.getDialogHelper(Drupal.settings.linkit.currentInstance.helper).insertLink(Drupal.linkit.getLink());
// Close the dialog.
Drupal.linkit.modalClose();
- return false;
});
});
@@ -232,12 +232,11 @@ Drupal.behaviors.linkitSearch = {
$('.linkit-path-element', context).focus();
}
- }
+ };
searchElement.betterAutocomplete('init', Drupal.settings.linkit.currentInstance.autocompletePathParsed, Drupal.settings.linkit.currentInstance.autocomplete, callbacks);
});
}
};
-
-
-})(jQuery);
\ No newline at end of file
+
+})(jQuery);
diff --git a/sites/all/modules/contrib/admin/linkit/js/linkit.field.js b/sites/all/modules/contrib/admin/linkit/js/linkit.field.js
index 27ca6ba4..08b8e485 100644
--- a/sites/all/modules/contrib/admin/linkit/js/linkit.field.js
+++ b/sites/all/modules/contrib/admin/linkit/js/linkit.field.js
@@ -2,134 +2,149 @@
* @file
* Linkit field ui functions
*/
+(function($, behavior) {
+ 'use strict';
-(function ($) {
+ Drupal.behaviors[behavior] = {
+ attach: function(context, settings) {
+ // If there is no fields, just stop here.
+ if (undefined === settings.linkit || null === settings.linkit.fields) {
+ return false;
+ }
-Drupal.behaviors.linkit_field = {
- attach : function(context, settings) {
- // If there is no fields, just stop here.
+ $.each(settings.linkit.fields, function(i, instance) {
+ $('#' + instance.source, context).once(behavior, function() {
+ var element = this;
- if (settings.linkit == undefined || settings.linkit.fields == null) {
- return false;
- }
+ $('.linkit-field-' + instance.source).click(function(event) {
+ event.preventDefault();
- $.each(settings.linkit.fields, function(field_name, field) {
- $('#' + field_name, context).once('linkit_field', function() {
- $('.linkit-field-' + field_name).click(function() {
- // Set profile.
- Drupal.settings.linkit.currentInstance.profile = Drupal.settings.linkit.fields[field_name].profile;
+ // Only care about selection if the element is a textarea.
+ if ('textarea' === element.nodeName.toLowerCase()) {
+ instance.selection = Drupal.linkit.getDialogHelper('field').getSelection(element);
+ }
- // Set the name of the source field..
- Drupal.settings.linkit.currentInstance.source = field_name;
-
- // Set the source type.
- Drupal.settings.linkit.currentInstance.helper = 'field';
-
- // Only care about selection if the element is a textarea.
- if ($('textarea#' + field_name).length) {
- var selection = Drupal.linkit.getDialogHelper('field').getSelection($('#' + field_name).get(0));
- // Save the selection.
- Drupal.settings.linkit.currentInstance.selection = selection;
- }
-
- // Suppress profile changer.
- Drupal.settings.linkit.currentInstance.suppressProfileChanger = true;
-
- // Create the modal.
- Drupal.linkit.createModal();
-
- return false;
+ Drupal.settings.linkit.currentInstance = instance;
+ Drupal.linkit.createModal();
+ });
});
});
- });
- }
-};
-
-/**
- * Linkit field dialog helper.
- */
-Drupal.linkit.registerDialogHelper('field', {
- init : function() {},
- afterInit : function () {},
+ }
+ };
/**
- * Insert the link into the field.
- *
- * @param {Object} link
- * The link object.
+ * Linkit field dialog helper.
*/
- insertLink : function(data) {
- var source = $('#' + Drupal.settings.linkit.currentInstance.source),
- field_settings = Drupal.settings.linkit.fields[Drupal.settings.linkit.currentInstance.source],
+ Drupal.linkit.registerDialogHelper('field', {
+ afterInit: function() {},
- // Call the insert plugin.
- link = Drupal.linkit.getInsertPlugin(field_settings.insert_plugin).insert(data, field_settings);
+ /**
+ * Insert the link into the field.
+ *
+ * @param {Object} data
+ * The link object.
+ */
+ insertLink: function(data) {
+ var instance = Drupal.settings.linkit.currentInstance,
+ // Call the insert plugin.
+ link = Drupal.linkit.getInsertPlugin(instance.insertPlugin).insert(data, instance);
- if (typeof Drupal.settings.linkit.currentInstance.selection != 'undefined') {
- // Replace the selection and insert the link there.
- this.replaceSelection(source.get(0), Drupal.settings.linkit.currentInstance.selection, link);
- }
- else {
- // Replace the field value.
- this.replaceFieldValue(source.get(0), link);
- }
+ if (instance.hasOwnProperty('selection')) {
+ // Replace the selection and insert the link there.
+ this.replaceSelection(instance.source, instance.selection, link);
+ }
+ else if (instance.hasOwnProperty('titleField')) {
+ // The "linkContent" property will always be present when AJAX used.
+ // Otherwise, if you use simple insert without autocomplete, then this
+ // property will be undefined and title field should not be filled in.
+ //
+ // @see Drupal.behaviors.linkitSearch.attach
+ if (instance.hasOwnProperty('linkContent')) {
+ this.replaceFieldValue(instance.titleField, instance.linkContent);
+ }
- // Link field can have a title field. If they have, we populate the title
- // field with the search result title if any.
- if (typeof field_settings.title_field != 'undefined' && typeof Drupal.settings.linkit.currentInstance.linkContent != 'undefined') {
- this.replaceFieldValue($('#' + field_settings.title_field).get(0), Drupal.settings.linkit.currentInstance.linkContent);
- }
- },
+ // The "path" property will always be present after dialog was
+ // opened and contain raw URL.
+ //
+ // @see Drupal.behaviors.linkitDashboard.attach
+ this.replaceFieldValue(instance.source, data.path);
+ }
+ else {
+ // Replace the field value.
+ this.replaceFieldValue(instance.source, link);
+ }
+ },
- /**
- * Get field selection.
- */
- getSelection : function(e) {
- // Mozilla and DOM 3.0.
- if ('selectionStart' in e) {
- var l = e.selectionEnd - e.selectionStart;
- return { start: e.selectionStart, end: e.selectionEnd, length: l, text: e.value.substr(e.selectionStart, l) };
- }
- // IE.
- else if(document.selection) {
- e.focus();
- var r = document.selection.createRange(),
- tr = e.createTextRange(),
- tr2 = tr.duplicate();
- tr2.moveToBookmark(r.getBookmark());
- tr.setEndPoint('EndToStart',tr2);
+ /**
+ * Get field selection.
+ */
+ getSelection: function(element) {
+ var object = {
+ start: element.value.length,
+ end: element.value.length,
+ length: 0,
+ text: ''
+ };
- if (r == null || tr == null) {
- return { start: e.value.length, end: e.value.length, length: 0, text: '' };
+ // Mozilla and DOM 3.0.
+ if ('selectionStart' in element) {
+ var length = element.selectionEnd - element.selectionStart;
+
+ object = {
+ start: element.selectionStart,
+ end: element.selectionEnd,
+ length: length,
+ text: element.value.substr(element.selectionStart, length)
+ };
+ }
+ // IE.
+ else if (document.selection) {
+ element.focus();
+
+ var range = document.selection.createRange(),
+ textRange = element.createTextRange(),
+ textRangeDuplicate = textRange.duplicate();
+
+ textRangeDuplicate.moveToBookmark(range.getBookmark());
+ textRange.setEndPoint('EndToStart', textRangeDuplicate);
+
+ if (!(range || textRange)) {
+ return object;
}
// For some reason IE doesn't always count the \n and \r in the length.
- var text_part = r.text.replace(/[\r\n]/g,'.'),
- text_whole = e.value.replace(/[\r\n]/g,'.'),
- the_start = text_whole.indexOf(text_part, tr.text.length);
- return { start: the_start, end: the_start + text_part.length, length: text_part.length, text: r.text };
+ var text_part = range.text.replace(/[\r\n]/g, '.'),
+ text_whole = element.value.replace(/[\r\n]/g, '.'),
+ the_start = text_whole.indexOf(text_part, textRange.text.length);
+
+ object = {
+ start: the_start,
+ end: the_start + text_part.length,
+ length: text_part.length,
+ text: range.text
+ };
+ }
+
+ return object;
+ },
+
+ /**
+ * Replace the field selection.
+ */
+ replaceSelection: function(id, selection, text) {
+ var field = this.getField(id);
+ field.value = field.value.substr(0, selection.start) + text + field.value.substr(selection.end, field.value.length);
+ },
+
+ /**
+ * Replace the field value.
+ */
+ replaceFieldValue: function(id, text) {
+ this.getField(id).value = text;
+ },
+
+ getField: function(id) {
+ return document.getElementById(id);
}
- // Browser not supported.
- else {
- return { start: e.value.length, end: e.value.length, length: 0, text: '' };
- }
- },
-
- /**
- * Replace the field selection.
- */
- replaceSelection : function (e, selection, text) {
- var start_pos = selection.start;
- var end_pos = start_pos + text.length;
- e.value = e.value.substr(0, start_pos) + text + e.value.substr(selection.end, e.value.length);
- },
-
- /**
- * Replace the field value.
- */
- replaceFieldValue : function (e, text) {
- e.value = text;
- }
-});
-
-})(jQuery);
\ No newline at end of file
+ });
+})(jQuery, 'linkitField');
diff --git a/sites/all/modules/contrib/admin/linkit/js/linkit.js b/sites/all/modules/contrib/admin/linkit/js/linkit.js
index 15b120ab..7e9664e3 100644
--- a/sites/all/modules/contrib/admin/linkit/js/linkit.js
+++ b/sites/all/modules/contrib/admin/linkit/js/linkit.js
@@ -6,11 +6,15 @@
(function ($) {
// Create the Linkit namespaces.
-Drupal.linkit = Drupal.linkit || {};
+Drupal.linkit = Drupal.linkit || { 'excludeIdSelectors': {} };
Drupal.linkit.currentInstance = Drupal.linkit.currentInstance || {};
Drupal.linkit.dialogHelper = Drupal.linkit.dialogHelper || {};
Drupal.linkit.insertPlugins = Drupal.linkit.insertPlugins || {};
+// Exclude ids from ajax_html_ids during AJAX requests.
+Drupal.linkit.excludeIdSelectors.ckeditor = ['[id^="cke_"]'];
+Drupal.linkit.excludeIdSelectors.tokens = ['[id^="token-"]'];
+
/**
* Create the modal dialog.
*/
@@ -140,6 +144,12 @@ Drupal.linkit.registerDialogHelper = function(name, helper) {
/**
* Get a dialog helper.
+ *
+ * @param {String} name
+ * The name of helper.
+ *
+ * @return {Object}
+ * Dialog helper object.
*/
Drupal.linkit.getDialogHelper = function(name) {
return Drupal.linkit.dialogHelper[name];
@@ -159,4 +169,30 @@ Drupal.linkit.getInsertPlugin = function(name) {
return Drupal.linkit.insertPlugins[name];
};
+var oldBeforeSerialize = (Drupal.ajax ? Drupal.ajax.prototype.beforeSerialize : false);
+if (oldBeforeSerialize) {
+ /**
+ * Filter the ajax_html_ids list sent in AJAX requests.
+ *
+ * This avoids hitting like max_input_vars, which defaults to 1000,
+ * even with just a few active editor instances.
+ */
+ Drupal.ajax.prototype.beforeSerialize = function (element, options) {
+ var ret = oldBeforeSerialize.call(this, element, options);
+ var excludeSelectors = [];
+ $.each(Drupal.linkit.excludeIdSelectors, function () {
+ if ($.isArray(this)) {
+ excludeSelectors = excludeSelectors.concat(this);
+ }
+ });
+ if (excludeSelectors.length > 0) {
+ options.data['ajax_html_ids[]'] = [];
+ $('[id]:not(' + excludeSelectors.join(',') + ')').each(function () {
+ options.data['ajax_html_ids[]'].push(this.id);
+ });
+ }
+ return ret;
+ }
+}
+
})(jQuery);
diff --git a/sites/all/modules/contrib/admin/linkit/linkit.api.php b/sites/all/modules/contrib/admin/linkit/linkit.api.php
index 1cc59039..1477ce68 100644
--- a/sites/all/modules/contrib/admin/linkit/linkit.api.php
+++ b/sites/all/modules/contrib/admin/linkit/linkit.api.php
@@ -29,4 +29,23 @@ function hook_linkit_search_plugin_entities_alter(&$plugins) {
);
$plugins['my_custom_plugin']['handler'] = $handler;
}
-}
\ No newline at end of file
+}
+
+/**
+ * Implements hook_linkit_local_hosts_alter().
+ *
+ * The default behavior is that only the current host is considered "local",
+ * when deciding how to classify a URL. For example, if the user is on
+ * http://www.example.com, then all URLs to other hosts will not be considered
+ * for local URLs. This means that if your users edit content on a different host
+ * from the actual public-facing site, such as https://staging.example.com,
+ * then if they paste in URLs from the public site (www), none of those
+ * URLs will be considered local.
+ *
+ * Implementing this hook will allow you to alter the list (indexed array) of
+ * hosts that will be considered for internal links. Include the protocol
+ * (eg, http or https).
+ */
+function hook_linkit_local_hosts_alter(&$local_hosts) {
+ $local_hosts[] = 'http://www.example.com';
+}
diff --git a/sites/all/modules/contrib/admin/linkit/linkit.field.inc b/sites/all/modules/contrib/admin/linkit/linkit.field.inc
index e838e8b5..1f46d6c1 100644
--- a/sites/all/modules/contrib/admin/linkit/linkit.field.inc
+++ b/sites/all/modules/contrib/admin/linkit/linkit.field.inc
@@ -170,72 +170,80 @@ function linkit_field_profile_validate($element, &$form_state, $form) {
}
/**
- * Process callback.
+ * After build callback.
+ *
+ * @param array $element
+ * Form API element.
+ * @param array $form_state
+ * State of form the element belongs to.
+ *
+ * @return array
+ * Form API element with attached Linkit functionality.
*/
-function linkit_process_field_element($element, &$form_state, &$complete_form) {
+function linkit_field_element_after_build(array $element, array &$form_state) {
// Only proceed if the field is attached to an entity.
if (!isset($element['#entity_type'])) {
return $element;
}
- $field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
- if (isset($instance['settings']['linkit']['enable']) && $instance['settings']['linkit']['enable']) {
-
- // Load the profile.
- $profile = linkit_profile_load($instance['settings']['linkit']['profile']);
- if (!$profile) {
- return $element;
- }
- // Load the insert plugin for the profile.
- $insert_plugin = linkit_insert_plugin_load($profile->data['insert_plugin']['plugin']);
- if ($insert_plugin === NULL) {
- return $element;
- }
-
- // Set the field ID.
- $field_id = $element['#id'];
-
- // Special treatment for link fields.
- if ($element['#type'] == 'link_field') {
- $field_id = $element['#id'] . '-url';
- }
-
- $field_js = array(
- 'data' => array(
- 'linkit' => array(
- 'fields' => array(
- $field_id => array(
- 'profile' => $instance['settings']['linkit']['profile'],
- 'insert_plugin' => $profile->data['insert_plugin']['plugin'],
- 'url_method' => $profile->data['insert_plugin']['url_method'],
- // @TODO: Add autocomplete settings.
- ),
- ),
- ),
- ),
- 'type' => 'setting',
- );
-
-
- // Link fields can have a title field.
- if ($element['#type'] == 'link_field') {
- if (isset($instance['settings']['title']) && in_array($instance['settings']['title'], array('optional', 'required'))) {
- $field_js['data']['linkit']['fields'][$field_id]['title_field'] = $element['#id'] . '-title';
- }
- }
-
- // Attach js files and settings Linkit needs.
- $element['#attached']['library'][] = array('linkit', 'base');
- $element['#attached']['library'][] = array('linkit', 'field');
- $element['#attached']['js'][] = $insert_plugin['javascript'];
- $element['#attached']['js'][] = $field_js;
-
- $button_text = !empty($instance['settings']['linkit']['button_text']) ? $instance['settings']['linkit']['button_text'] : t('Search');
- // Add Linkit dialog button to the element suffix.
- $element['#field_suffix'] = '' . $button_text . '';
+ if (empty($instance['settings']['linkit']['enable'])) {
+ return $element;
}
+ // Load the profile.
+ /* @var \LinkitProfile $profile */
+ $profile = linkit_profile_load($instance['settings']['linkit']['profile']);
+
+ if (!$profile || !isset($profile->data['insert_plugin']['plugin'])) {
+ return $element;
+ }
+
+ // Load the insert plugin for the profile.
+ $insert_plugin = linkit_insert_plugin_load($profile->data['insert_plugin']['plugin']);
+ $js_settings = array(
+ 'helper' => 'field',
+ 'source' => $element['#id'],
+ 'profile' => $instance['settings']['linkit']['profile'],
+ 'insertPlugin' => $profile->data['insert_plugin']['plugin'],
+ );
+
+ // Special treatment for link fields.
+ if ('link_field' == $element['#type']) {
+ $js_settings['source'] = $element['url']['#id'];
+
+ // @see link_field_info()
+ // @see link_field_instance_settings_form()
+ //
+ // Link fields have a title field, but value could
+ // be changed only for those options.
+ if (in_array($instance['settings']['title'], array('optional', 'required'))) {
+ $js_settings['titleField'] = $element['title']['#id'];
+ }
+ }
+
+ // Add Linkit dialog button to the element suffix.
+ $element['#field_suffix'] = l(empty($instance['settings']['linkit']['button_text']) ? t('Search') : $instance['settings']['linkit']['button_text'], '', array(
+ 'attributes' => array(
+ 'class' => array(
+ "button",
+ "linkit-field-button",
+ "linkit-field-{$js_settings['source']}",
+ ),
+ ),
+ ));
+
+ // Attach js files and settings Linkit needs.
+ $element['#attached']['library'][] = array('linkit', 'base');
+ $element['#attached']['library'][] = array('linkit', 'field');
+ $element['#attached']['js'][] = $insert_plugin['javascript'];
+ $element['#attached']['js'][] = array(
+ 'type' => 'setting',
+ 'data' => array(
+ 'linkit' => array('fields' => array($js_settings)),
+ ),
+ );
+
return $element;
-}
\ No newline at end of file
+}
diff --git a/sites/all/modules/contrib/admin/linkit/linkit.info b/sites/all/modules/contrib/admin/linkit/linkit.info
index 4b380272..0563a9a2 100644
--- a/sites/all/modules/contrib/admin/linkit/linkit.info
+++ b/sites/all/modules/contrib/admin/linkit/linkit.info
@@ -21,11 +21,10 @@ files[] = test/linkit_search_plugin.test
files[] = test/linkit_search_plugin_node.test
files[] = test/linkit_search_plugin_user.test
files[] = test/linkit_search_plugin_taxonomy_term.test
-files[] = test/linkit_field.test
-; Information added by Drupal.org packaging script on 2015-01-06
-version = "7.x-3.3"
+; Information added by Drupal.org packaging script on 2016-01-10
+version = "7.x-3.5"
core = "7.x"
project = "linkit"
-datestamp = "1420580858"
+datestamp = "1452407341"
diff --git a/sites/all/modules/contrib/admin/linkit/linkit.install b/sites/all/modules/contrib/admin/linkit/linkit.install
index b212f8db..97bfffc4 100644
--- a/sites/all/modules/contrib/admin/linkit/linkit.install
+++ b/sites/all/modules/contrib/admin/linkit/linkit.install
@@ -111,6 +111,9 @@ function linkit_update_7300() {
)
);
+ // Make sure our schema changes are reflected in the cached schema or
+ // subsequent update hooks making use of it might fail.
+ drupal_get_schema('linkit_profiles', TRUE);
foreach ($old_profiles as $profile) {
$data = unserialize($profile->data);
@@ -209,15 +212,50 @@ function linkit_update_7301() {
}
/**
- * Set URL type to "Entity view page" to preserve current behavior.
+ * Reverted.
*/
function linkit_update_7302() {
+ // This is the broken verison of 7304
+}
+
+/**
+ * Fixed 7302. Set URL type to "Entity view page" to preserve current behavior.
+ */
+function linkit_update_7303() {
require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'linkit') . '/plugins/linkit_search/file.class.php';
$profiles = linkit_profile_load_all();
+ $show_notice = FALSE;
foreach ($profiles as $profile) {
- if (isset($profile->data['entity:file'])) {
- $profile->data['entity:file'] = LINKIT_FILE_URL_TYPE_ENTITY;
+ // If the broken 7302 has been applied, and no other changes has been made, there is not way to get the data back.
+ // Lets add the default settings instead.
+ if (isset($profile->data['entity:file']) && $profile->data['entity:file'] == LINKIT_FILE_URL_TYPE_ENTITY) {
+ $profile->data['entity:file'] = array(
+ 'result_description' => '',
+ 'bundles' => array(
+ 'image' => 0,
+ 'video' => 0,
+ 'audio' => 0,
+ 'document' => 0,
+ ),
+ 'group_by_bundle' => 0,
+ 'show_scheme' => 0,
+ 'group_by_scheme' => 0,
+ 'url_type' => 'entity',
+ 'image_extra_info' => array(
+ 'thumbnail' => 'thumbnail',
+ 'dimensions' => 'dimensions',
+ ),
+ );
ctools_export_crud_save('linkit_profiles', $profile);
+ $show_notice = TRUE;
+ }
+ else if (isset($profile->data['entity:file']) && !isset($profile->data['entity:file']['url_type'])) {
+ $profile->data['entity:file']['url_type'] = LINKIT_FILE_URL_TYPE_ENTITY;
+ ctools_export_crud_save('linkit_profiles', $profile);
+ }
+
+ if ($show_notice) {
+ return t('A previous update may have changed the settings for the "managed file" search plugin in all your linkit profiles.');
}
}
}
diff --git a/sites/all/modules/contrib/admin/linkit/linkit.module b/sites/all/modules/contrib/admin/linkit/linkit.module
index 805ba9aa..78f77043 100644
--- a/sites/all/modules/contrib/admin/linkit/linkit.module
+++ b/sites/all/modules/contrib/admin/linkit/linkit.module
@@ -326,10 +326,10 @@ function linkit_module_implements_alter(&$implementations, $hook) {
* Implements hook_element_info_alter().
*/
function linkit_element_info_alter(&$types) {
- // Append a process function for the field integration.
+ // Append a after_build function for the field integration.
foreach (linkit_get_allowed_field_elements() as $element) {
if (isset($types[$element])) {
- $types[$element]['#process'][] = 'linkit_process_field_element';
+ $types[$element]['#after_build'][] = 'linkit_field_element_after_build';
}
}
@@ -338,7 +338,7 @@ function linkit_element_info_alter(&$types) {
if (in_array('ckeditor_pre_render_text_format', $types['text_format']['#pre_render'])) {
$types['text_format']['#pre_render'][] = 'linkit_pre_render_editor_element';
// Add the linkit library for the editor.
- drupal_add_library('linkit', 'ckeditor');
+ $types['text_format']['#attached']['library'][] = array('linkit', 'ckeditor');
}
}
@@ -556,7 +556,7 @@ function linkit_dashboard_form($form, &$form_state) {
'#options' => $_profiles,
'#ajax' => array(
'callback' => 'linkit_change_profile',
- 'wrapper' => 'linkit-dashbaord-ajax-wrapper',
+ 'wrapper' => 'linkit-dashboard-ajax-wrapper',
'method' => 'replaceWith',
'effect' => 'fade',
'event' => 'click',
@@ -577,7 +577,7 @@ function linkit_dashboard_form($form, &$form_state) {
$form['linkit_container'] = array(
'#type' => 'container',
'#weight' => 100,
- '#prefix' => '
',
+ '#prefix' => '
',
'#suffix' => '
',
'#attached' => array(
'js' => array(
@@ -687,12 +687,12 @@ function linkit_autocomplete(LinkitProfile $profile) {
// Special for link to frontpage.
if (strpos($search_string, 'front') !== FALSE) {
- $results = array_merge($results, array(
+ $results[] = array(
'title' => t('Frontpage'),
'description' => 'The frontpage for this site.',
'path' => url(''),
'group' => t('System'),
- ));
+ );
}
// Let the Linkit search plugins do their job.
@@ -823,7 +823,10 @@ function linkit_parse_url($url, $parts) {
// Internal URL.
// We can not use the url_is_external() as it treats all absolute links as
// external and treats all stream wrappers as internal.
- $local_url = trim($path_info['scheme'] . '://' . $path_info['host'] . base_path(), '/') == $base_url;
+ $local_hosts = array($base_url);
+ // Give other modules a chance to add/remove/alter the local hosts.
+ drupal_alter('linkit_local_hosts', $local_hosts);
+ $local_url = in_array(trim($path_info['scheme'] . '://' . $path_info['host'] . base_path(), '/'), $local_hosts);
$local_stream_wrapper = isset($local_stream_wrappers[$path_info['scheme']]);
//@TODO: maybe file_valid_uri() ?
@@ -1041,49 +1044,53 @@ function linkit_pre_render_editor_element($element) {
static $processed = array();
if (!isset($processed[$element['#id']])) {
- // Load the first profile that is assign to this text format.
- $profile = linkit_profile_load_by_format($element['#format']);
+ global $user;
+ $all_formats = array_keys(filter_formats($user));
- // If we dont have any profile, lets just return the element.
- if (!$profile) {
- return $element;
- }
- // Set the field ID.
- if (isset($element['value']['#id'])) {
- $field_id = $element['value']['#id'];
- }
- else {
- $field_id = $element['#id'] . '-value';
+ $profiles_formats = array();
+
+ $use_imce = FALSE;
+
+ // First we need to figure out which formats that the current user can access have active Linkit profiles for them.
+ foreach ($all_formats as $format) {
+ // Load the first profile that is assigned to this text format.
+ $profile = linkit_profile_load_by_format($format);
+
+ if ($profile) {
+ if (isset($profile->data['imce']) && $profile->data['imce'] == 1) {
+ $use_imce = TRUE;
+ }
+ $profiles_formats[$format] = array('profile' => $profile->name);
+ }
}
- $field_js = array(
- 'data' => array(
- 'linkit' => array(
- 'fields' => array(
- $field_id => array(
- 'profile' => $profile->name,
- ),
+ if (!empty($profiles_formats)) {
+
+ $field_js = array(
+ 'data' => array(
+ 'linkit' => array(
+ 'formats' => $profiles_formats,
),
),
- ),
- 'type' => 'setting',
- );
+ 'type' => 'setting',
+ );
- // Configure Linkit to have an IMCE selector.
- if (module_invoke('imce', 'access') && isset($profile->data['imce']) && $profile->data['imce'] == 1) {
- $field_js['data']['linkit']['IMCEurl'] = url('imce', array('query' => array(
- 'app' => 'Linkit|sendto@Drupal.linkit.IMCECallback',
- 'absolute' => TRUE,
- )));
- // We will only serv public files with IMCE.
- $field_js['data']['linkit']['publicFilesDirectory'] = variable_get('file_public_path', conf_path() . '/files');
+ // Configure Linkit to have an IMCE selector.
+ if (module_invoke('imce', 'access') && $use_imce) {
+ $field_js['data']['linkit']['IMCEurl'] = url('imce', array('query' => array(
+ 'app' => 'Linkit|sendto@Drupal.linkit.IMCECallback',
+ 'absolute' => TRUE,
+ )));
+ // We will only serv public files with IMCE.
+ $field_js['data']['linkit']['publicFilesDirectory'] = variable_get('file_public_path', conf_path() . '/files');
+ }
+
+ // Attach the linkit_base librar
+ $element['#attached']['library'][] = array('linkit', 'base');
+ $element['#attached']['js'][] = $field_js;
+
+ $processed[$element['#id']] = TRUE;
}
-
- // Attach the linkit_base librar
- $element['#attached']['library'][] = array('linkit', 'base');
- $element['#attached']['js'][] = $field_js;
-
- $processed[$element['#id']] = TRUE;
}
return $element;
@@ -1139,14 +1146,14 @@ function linkit_get_insert_plugin_processed_path(LinkitProfile $profile, $uri, $
switch ($profile->data['insert_plugin']['url_method']) {
case LINKIT_URL_METHOD_RAW:
$path = $uri;
- break;
- case LINKIT_URL_METHOD_RAW_SLASH:
- $options['alias'] = TRUE;
- $path = url($uri, $options);
- break;
- case LINKIT_URL_METHOD_ALIAS:
- $path = url($uri, $options);
- break;
+ break;
+ case LINKIT_URL_METHOD_RAW_SLASH:
+ $options['alias'] = TRUE;
+ $path = url($uri, $options);
+ break;
+ case LINKIT_URL_METHOD_ALIAS:
+ $path = url($uri, $options);
+ break;
}
return $path;
diff --git a/sites/all/modules/contrib/admin/linkit/plugins/export_ui/linkit_profiles.inc b/sites/all/modules/contrib/admin/linkit/plugins/export_ui/linkit_profiles.inc
index b40b6fb8..e49bd07e 100644
--- a/sites/all/modules/contrib/admin/linkit/plugins/export_ui/linkit_profiles.inc
+++ b/sites/all/modules/contrib/admin/linkit/plugins/export_ui/linkit_profiles.inc
@@ -106,7 +106,6 @@ function _linkit_build_profile_type_form_fields(&$form, LinkitProfile $profile)
$form['data']['profile_type'] = array(
'#type' => 'fieldset',
'#title' => t('Profile type'),
- '#description' => t(''),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#tree' => FALSE,
@@ -143,7 +142,6 @@ function _linkit_build_profile_type_form_fields(&$form, LinkitProfile $profile)
'#empty_option' => t('- Select one or more text format- '),
'#default_value' => isset($profile->data['text_formats'])
? $profile->data['text_formats'] : array(),
- '#description' => t('.'),
'#states' => array(
'visible' => array(
// While waiting for https://drupal.org/node/879580 to be commited, we
@@ -294,7 +292,7 @@ function _linkit_build_insert_plugin_form_fields(&$form, LinkitProfile $profile)
),
LINKIT_URL_METHOD_RAW_SLASH => array(
'#description' => t('This is the default behavior, it will insert paths
- like %example_link. These will work without the need for a input filter,
+ like %example_link. These will work without the need for an input filter,
but might fail after moving a site, or on multilingual sites.',
array('%example_link' => '/node/123')),
),
@@ -307,7 +305,7 @@ function _linkit_build_insert_plugin_form_fields(&$form, LinkitProfile $profile)
$form['data']['insert_plugin']['url_method']['#options'][LINKIT_URL_METHOD_ALIAS] = t('Alias paths');
$form['data']['insert_plugin']['url_method'][LINKIT_URL_METHOD_ALIAS] = array(
'#description' => t('This will insert the alias for the result item.
- The paths will be runned thru the url() function.', array('%example_link' => 'node/123')),
+ The paths will be run through the url() function.', array('%example_link' => 'node/123')),
);
}
}
@@ -327,7 +325,7 @@ function _linkit_build_attribute_plugin_form_fields(&$form, LinkitProfile $profi
$form['data']['attribute_plugins_fieldset'] = array(
'#type' => 'fieldset',
'#title' => t('Attributes'),
- '#description' => t('Attributes is HTML attributes that will be attached to
+ '#description' => t('Attributes are HTML attributes that will be attached to
the insert plugin.'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
@@ -417,7 +415,7 @@ function _linkit_build_autocomplete_form_fields(&$form, LinkitProfile $profile)
$form['data']['autocomplete'] = array(
'#type' => 'fieldset',
'#title' => t('Autocomplete options'),
- '#description' => t('Linkit uses !bac which may be configured with focus on
+ '#description' => t('Linkit uses !bac which may be configured with a focus on
performance.', array('!bac' => l(t('Better Autocomplete'),
'https://github.com/betamos/Better-Autocomplete'))),
'#collapsible' => TRUE,
diff --git a/sites/all/modules/contrib/admin/linkit/plugins/linkit_insert/html_link/html_link.js b/sites/all/modules/contrib/admin/linkit/plugins/linkit_insert/html_link/html_link.js
index 5edc181b..fcc4c29d 100644
--- a/sites/all/modules/contrib/admin/linkit/plugins/linkit_insert/html_link/html_link.js
+++ b/sites/all/modules/contrib/admin/linkit/plugins/linkit_insert/html_link/html_link.js
@@ -2,34 +2,32 @@
* @file
* HTML Link insert plugin for Linkit.
*/
-(function ($) {
+(function($) {
+ Drupal.linkit.registerInsertPlugin('html_link', {
+ insert: function(data) {
+ var linkitInstance = Drupal.settings.linkit.currentInstance,
+ selection = linkitInstance.selection,
+ text = linkitInstance.linkContent || data.path;
-Drupal.linkit.registerInsertPlugin('html_link', {
- insert : function(data) {
- var text,
- selection = Drupal.settings.linkit.currentInstance.selection;
+ // Delete all attributes that are empty.
+ for (var attr in data.attributes) {
+ if (data.attributes.hasOwnProperty(attr)) {
+ delete data.attributes[attr];
+ }
+ }
- // Delete all attributes that are empty.
- for (name in data.attributes) {
- (data.attributes[name]) ? null : delete data.attributes[name];
+ if (selection && selection.text.length >= 1) {
+ text = selection.text;
+ }
+
+ // Use document.createElement as it is mush fasten then $(').
+ return $(document.createElement('a'))
+ .attr(data.attributes)
+ .attr('href', data.path)
+ .html(text)
+ // Convert the element to a string.
+ .get(0)
+ .outerHTML;
}
-
- if (typeof selection != 'undefined' &&
- selection.text.length >= 1) {
- text = selection.text;
- }
- else {
- text = Drupal.settings.linkit.currentInstance.linkContent;
- }
-
- // Use document.createElement as it is mush fasten then $(').
- return $(document.createElement('a'))
- .attr(data.attributes)
- .attr('href', data.path)
- .html(text)
- // Convert the element to a string.
- .get(0).outerHTML;
- }
-});
-
-})(jQuery);
\ No newline at end of file
+ });
+})(jQuery);
diff --git a/sites/all/modules/contrib/admin/linkit/plugins/linkit_search/entity.class.php b/sites/all/modules/contrib/admin/linkit/plugins/linkit_search/entity.class.php
index daa51958..853f6f58 100644
--- a/sites/all/modules/contrib/admin/linkit/plugins/linkit_search/entity.class.php
+++ b/sites/all/modules/contrib/admin/linkit/plugins/linkit_search/entity.class.php
@@ -5,7 +5,7 @@
*/
/**
- * Reprecents a Linkit entity search plugin.
+ * Represents a Linkit entity search plugin.
*/
class LinkitSearchPluginEntity extends LinkitSearchPlugin {
@@ -97,13 +97,13 @@ class LinkitSearchPluginEntity extends LinkitSearchPlugin {
* The entity label, or FALSE if not found.
*/
function createLabel($entity) {
- return check_plain(entity_label($this->plugin['entity_type'], $entity));
+ return filter_xss(entity_label($this->plugin['entity_type'], $entity));
}
/**
* Create a search row description.
*
- * If there is a "result_description", run it thro token_replace.
+ * If there is a "result_description", run it through token_replace.
*
* @param object $data
* An entity object that will be used in the token_place function.
@@ -145,7 +145,7 @@ class LinkitSearchPluginEntity extends LinkitSearchPlugin {
$options['language'] = $languages[$entity->language];
}
}
- // Process the uri with the insert pluing.
+ // Process the uri with the insert plugin.
$path = linkit_get_insert_plugin_processed_path($this->profile, $uri['path'], $options);
return $path;
}
@@ -175,7 +175,7 @@ class LinkitSearchPluginEntity extends LinkitSearchPlugin {
}
/**
- * Create a row class to appaned to the search result row.
+ * Create a row class to append to the search result row.
*
* @param $entity
* The entity object.
@@ -194,7 +194,7 @@ class LinkitSearchPluginEntity extends LinkitSearchPlugin {
$this->query = new EntityFieldQuery();
$this->query->entityCondition('entity_type', $this->plugin['entity_type']);
- // Add the default sort on the enity label.
+ // Add the default sort on the entity label.
$this->query->propertyOrderBy($this->entity_field_label, 'ASC');
}
@@ -240,7 +240,7 @@ class LinkitSearchPluginEntity extends LinkitSearchPlugin {
$entities = entity_load($this->plugin['entity_type'], $ids);
foreach ($entities AS $entity) {
- // Check the access againt the definded entity access callback.
+ // Check the access against the defined entity access callback.
if (entity_access('view', $this->plugin['entity_type'], $entity) === FALSE) {
continue;
}
@@ -276,7 +276,7 @@ class LinkitSearchPluginEntity extends LinkitSearchPlugin {
// Get supported tokens for the entity type.
$tokens = linkit_extract_tokens($this->plugin['entity_type']);
- // A short description in within the search result for each row.
+ // A short description within the search result for each row.
$form[$this->plugin['name']]['result_description'] = array(
'#title' => t('Result description'),
'#type' => 'textfield',
@@ -286,7 +286,7 @@ class LinkitSearchPluginEntity extends LinkitSearchPlugin {
'#description' => t('Available tokens: %tokens.', array('%tokens' => implode(', ', $tokens))),
);
- // If the token module is installed, lets make some fancy stuff with the
+ // If the token module is installed, lets do some fancy stuff with the
// token chooser.
if (module_exists('token')) {
// Unset the regular description if token module is enabled.
@@ -295,17 +295,15 @@ class LinkitSearchPluginEntity extends LinkitSearchPlugin {
// Display the user documentation of placeholders.
$form[$this->plugin['name']]['token_help'] = array(
'#title' => t('Replacement patterns'),
- '#type' => 'fieldset',
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
+ '#type' => 'markup',
);
$form[$this->plugin['name']]['token_help']['help'] = array(
- '#theme' => 'token_tree',
+ '#theme' => 'token_tree_link',
'#token_types' => array($this->plugin['entity_type']),
);
}
- // If there is bundles, add some default settings features.
+ // If there are bundles, add some default settings features.
if (count($this->entity_info['bundles']) > 1) {
$bundles = array();
// Extract the bundle data.
@@ -331,4 +329,4 @@ class LinkitSearchPluginEntity extends LinkitSearchPlugin {
}
return $form;
}
-}
\ No newline at end of file
+}
diff --git a/sites/all/modules/contrib/admin/linkit/plugins/linkit_search/node.class.php b/sites/all/modules/contrib/admin/linkit/plugins/linkit_search/node.class.php
index 3853f121..69f1f658 100644
--- a/sites/all/modules/contrib/admin/linkit/plugins/linkit_search/node.class.php
+++ b/sites/all/modules/contrib/admin/linkit/plugins/linkit_search/node.class.php
@@ -43,7 +43,7 @@ class LinkitSearchPluginNode extends LinkitSearchPluginEntity {
'#title' => t('Include unpublished nodes'),
'#type' => 'checkbox',
'#default_value' => isset($this->conf['include_unpublished']) ? $this->conf['include_unpublished'] : 0,
- '#description' => t('In order to see unpublished nodes, the user most also have permissions to do so. '),
+ '#description' => t('In order to see unpublished nodes, the user must also have permissions to do so. '),
);
return $form;
diff --git a/sites/all/modules/contrib/admin/linkit/test/linkit_profile.test b/sites/all/modules/contrib/admin/linkit/test/linkit_profile.test
index 4fcc8857..0d71ce4f 100644
--- a/sites/all/modules/contrib/admin/linkit/test/linkit_profile.test
+++ b/sites/all/modules/contrib/admin/linkit/test/linkit_profile.test
@@ -16,7 +16,6 @@ class LinkitProfileUICRUDTestCase extends LinkitTestCase {
'name' => 'test_profile',
'admin_title' => 'Test Profile',
'admin_description' => 'This is a description for the Test Profile.',
- 'profile_type' => LINKIT_PROFILE_TYPE_EDITOR,
);
/**
@@ -32,6 +31,7 @@ class LinkitProfileUICRUDTestCase extends LinkitTestCase {
function setUp($extra_modules = array()) {
parent::setUp($extra_modules);
+ $this->profile_defaults['profile_type'] = LINKIT_PROFILE_TYPE_EDITOR;
}
/**
diff --git a/sites/all/modules/contrib/admin/module_filter/CHANGELOG.txt b/sites/all/modules/contrib/admin/module_filter/CHANGELOG.txt
old mode 100755
new mode 100644
index 218bc30a..c5c66703
--- a/sites/all/modules/contrib/admin/module_filter/CHANGELOG.txt
+++ b/sites/all/modules/contrib/admin/module_filter/CHANGELOG.txt
@@ -1,50 +1,182 @@
-Module Filter 7.x-1.8, 2013-08-08
+Module Filter 7.x-2.x, 2015-02-20
---------------------------------
+Simplifying the table rows by hiding version and requirements until a
+ particular description is clicked.
+
+
+Module Filter 7.x-2.x, 2014-09-01
+---------------------------------
+#2235553 by greenSkin: Fixed latest jquery_update breaks module filter.
+#2304687 by mpdonadio: Fixed Remove hardcoded operations.
+#2293029 by topsitemakers: Fixed Take header offset into account when selecting
+ a tab.
+#2290213 by topsitemakers: Minor typo in description - "has no affect" -> "has
+ no effect".
+
+
+Module Filter 7.x-2.0-alpha2, 2013-12-06
+----------------------------------------
+#2141743, #2141743 by greenSkin: Fixed issues related to the new dynamically
+ positioned tabs and using the dynamically positioned save button.
+
+
+Module Filter 7.x-2.0-alpha1, 2013-11-18
+----------------------------------------
+by greenSkin: Tabs now should always be visible while scrolling large lists of
+ modules.
+#1854348 by alexweber, greenSkin: Make filter textfield wider on modules page
+ when viewing as tabs.
+by greenSkin: Fixed what was suppose to be a call to variable_set().
+#1370492 by greenSkin: Remember selected tab after modules form submit.
by greenSkin: Changed the title for the 'module_filter_dynamic_save_position'
checkbox to make it clearer what it does.
-#1933384 by kaidjohnson: Fixed jQuery UI button breaks functionality.
-#1166414 by greenSkin: Fixed module filter + tabs disabled = broken modules
- page.
-
-
-Module Filter 7.x-1.7, 2012-07-05
----------------------------------
+#1166414 by greenSkin: Fixed broken submit when tabs are disabled. We no longer
+ reroute the theme of the system modules page unless tabs are enabled.
+by greenSkin: Fixed issue on Available updates page where the update state
+ would not be remembered.
+by greenSkin: Fixed 7200 update to rebuild the theme registry at the same time
+ as rebuilding the menu.
+by greenSkin: Fixed issue relating to row coloring when enabling/disabling
+ modules via switch due to recent fix for jQuery Update module.
+by greenSkin: Added functionality to show recently enabled/disabled modules.
+#1710230 by littlekoala, greenSkin: Fixed On | Off buttons does not change
+ state with jquery_update() module active.
+by greenSkin: Added description to filter textfield on permissions page.
+by greenSkin: Added filter to user permissions page.
+by greenSkin: Fixed styling when JavaScript is disabled.
+by greenSkin: Fixed compatiblility with page_actions.
+#1351184 klonos, greenSkin: Added support for update_advanced "Ignored from
+ settings".
+#1149978 by good_man, greenSkin: Added RTL Styling for tabs and toggle switch.
+by greenSkin: Hide toggle switch when JavaScript is disabled.
+by greenSkin: Added support for ctools dropbutton as well as views styling for
+ ctools dropbutton.
+by greenSkin: Improved hash validation.
+by greenSkin: Added ability for tabs to be disabled. Direct use case is when
+ the "New" tab contains zero new modules.
+by greenSkin: Added title to "New" tab link that helps to describe the criteria
+ of a "new" module.
+#1320796 by greenSkin: Added some validation checks before trying to select a
+ tab in case the tab does not actually exist.
+#1429248 by klonos, greenSkin: Fixed Modules page table header overlaps
+ admin_menu().
+#1494694 by greenSkin: Added Let me decide if I want the cursor to focus on the
+ search box or not.
+#1515256 by catmat, greenSkin: Fixed Tabbed theme may remove functional
+ content.
+by greenSkin: Integrated dynamic positioning of the save button back in, but
+ if the module page_actions is enabled we let it handle the save button. See
+ issue #1424994.
+by greenSkin: Clicking on module name now affects the toggle switch.
+by greenSkin: Do not render the switch for incompatible modules.
#1033012 by greenSkin: Hide incompatible module rows when the 'Unavailable'
checkbox is unchecked.
-#1170388 by greenSkin: Fixed conflict with Overlay module. Added class
- "overlay-exclude" to tab links.
+by greenSkin: Performance tweak to counting the number of enabled modules.
+by greenSkin: Base new modules on the filectime of their .info file.
+#1424034 by greenSkin: Now adds the jquery.cookie.js file when needed.
+by greenSkin: Removed tweaks to the save configuration button in favor
+ http://drupal.org/project/page_actions.
+by greenSkin: Updated hook_uninstall to del all Module Filter variables.
+by greenSkin: No longer including machine name in the tab summary of modules to
+ enable/disable.
+by greenSkin: Made switches honor disabled checkboxes. A disabled switch can
+ not be turned on or off.
+by greenSkin: Added setting to toggle between using the switch or checkbox for
+ enabling/disabling modules.
+by greenSkin: Centered enable switch.
+by greenSkin: Moved couple styles to be applied via JavaScript instead of CSS
+ so they get applied once the initial loading has finished.
+by greenSkin: Implemented a "switch" look instead of checkboxes.
+by greenSkin: Remember last selected state on "Available updates" page.
+by greenSkin: Switched to using filectime() rather than filemtime() for
+ determining new modules.
+#1354134 by klonos, greenSkin: Module list now formats correctly in core
+ "Garland" theme.
+#1354134 by klonos, greenSkin: Module list now formats correctly in core
+ "Garland" theme.
#1124218 by jyee, greenSkin: Suppress form submission when hitting the enter
key while the filter input is focused.
-
-
-Module Filter 7.x-1.6, 2011-09-15
----------------------------------
-#1241662 by Niklas Fiekas: Sort modules by display name.
+by greenSkin: Simplified filter rules for updates page. Instead of checkboxes,
+ now using radios.
+by greenSkin: Fixed "All" tab to be selected by default when the page is first
+ loaded.
+#1350124 by greenSkin: Fixed filtering on package tab.
+by greenSkin: Added the "All" tab back. Added a "New" tab that lists modules
+ installed within the last week.
+by greenSkin: Fixed "No Results" not showing within selected tabs.
+#1259876 by greenSkin: Filter criteria remembered after save.
+by greenSkin: Remove deprecated function moduleGetID() from JavaScript code.
+by greenSkin: Filter now uses OR instead of AND when filtering multiply
+ queries.
+#1288590 by greenSkin: Fixed Drupal.settings.moduleFilter.enabledCounts[id] is
+ undefined.
+#1344214 by eMPee584: Fixed Notice: Undefined index: #default_value in
+ theme_module_filter_system_modules_tabs().
+#1170388 by greenSkin: Fixed confict with Overlay module. Added class
+ "overlay-exclude" to tab links. Added setting to toggle the use of a URL
+ fragment when selecting tabs.
+by greenSkin: Added README.txt.
+by greenSkin: Fixed table row striping.
+by greenSkin: Fixed regular expression to not require an operator be at the
+ beginning. Make filter queries filter with AND instead of OR. Each query will
+ further filter the list rather than potentially add to it.
+by greenSkin: Spruced up the regular expression for splitting query strings.
+by greenSkin: Added "description:" operator.
+by greenSkin: Added operator support to filter. Added "requires:" and
+ "requiredBy:" operators.
+by greenSkin: Filter now processes multiple queries separated by spaces. Use
+ quotes for a single query that includes space(s).
+by greenSkin: Fixed not updating the index when a module is enabled/disabled.
+by greenSkin: Fixed visual aid for enabling/disabling modules. Previously had
+ failed to remove +/- from tab summary.
+by Kiphaas7, greenSkin: Tabs can now be configured to hide when they contain
+ no results.
+by Kiphaas7, greenSkin: Added result info to tabs. When a filter is performed,
+ a count per tab is displayed of the number of visible results for that tab.
+by greenSkin: Now more descriptive of what modules are being enabled/disabled.
+by greenSkin: Moved module operation links to below "Requires" and
+ "Required by" section.
+by greenSkin: Added a suggest class to tabs when their module is hovered.
+by greenSkin: Distinguished difference between tab ID and hash.
+by greenSkin: Only alter the menu item 'admin/reports/updates' if it first
+ exists.
+by greenSkin: Added update to force a menu rebuild. This is needed to let
+ Module Filter alter the Update Status menu item in order to provide our
+ filter on its page.
#1254140 by greenSkin: No longer return anything in hook_update_7100.
-by greenSkin: Fixed bug with visual aids sometimes not updating correctly.
-
-
-Module Filter 7.x-1.5, 2011-08-16
----------------------------------
-by greenSkin: Brought the 7.x branch current with the 6.x branch features.
-
-
-Module Filter 7.x-1.3, 2011-03-07
----------------------------------
-by realityloop: Updated CHANGELOG.txt
-
-
-Module Filter 7.x-1.2, 2011-03-07
----------------------------------
-by realityloop: Changed placement of Submit buttons for other languages
-
-
-Module Filter 7.x-1.1, 2011-03-07
----------------------------------
-by realityloop: first commit via git, broke the release somehow :/
-
-
-Module Filter 7.x-1.0, 2011-01-04
----------------------------------
-by realityloop: Fixed Undefined index error.
-by greenSkin: Removed unused .css and .js files.
+#1257860 by greenSkin: Added filter to update status report.
+by greenSkin: Moved hiding of the inputs wrapper to css rather than a style
+ attribute.
+by greenSkin: Added missing semi-colons in JavaScript.
+by greenSkin: Changed hook comment from using "Implementation of" to
+ "Implements".
+by greenSkin: Fixed showing all modules by default when no hash is present.
+by greenSkin: Turned off autocomplete for filter textfield.
+by greenSkin: Now using "all" for hash when no tab is selected.
+by greenSkin: Implemented visual aids (displays number of modules being
+ enabled/disabled as well as coloring the modules row accordingly).
+by greenSkin: Implemented the enabled count (displays the number of enabled
+ modules of total for a package.
+by greenSkin: Updated tabs setting description.
+by greenSkin: Added missing period.
+by greenSkin: Made dynamic save position default to on. Updated element title
+ on admin page and removed "DEVELOPMENTAL" from description.
+by greenSkin: Improved fixed-top positioning when toolbar is enabled.
+by greenSkin: Added fixed classes for submit button wrapper.
+by greenSkin: Changed module-filter-tabs from a class to an id.
+by greenSkin: Fixed filter on modules page when tabs are disabled.
+by greenSkin: Set min-height to #module-filter-modules.
+by greenSkin: Implemented module_filter element and using attached js and css
+ more.
+by greenSkin: Filter input and checkboxes can now have their default values set
+ based on query params.
+by greenSkin: Tabs now use URL fragments.
+by greenSkin: Fixed regular expression used to determine tab ID.
+by greenSkin: Tabs have been re-written and are functioning.
+by greenSkin: Added Module Filter to "Administration" package.
+by greenSkin: Improved filtering performance.
+by greenSkin: New filter code.
+by greenSkin: Initial tab layout modified. Modules are all in one table but
+ look like they are in packages. All JavaScript has to do on load now is
+ remove the package name and header rows from tbody then sort the rows.
+by greenSkin: Modified the menu item's description.
diff --git a/sites/all/modules/contrib/admin/module_filter/LICENSE.txt b/sites/all/modules/contrib/admin/module_filter/LICENSE.txt
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/module_filter/README.txt b/sites/all/modules/contrib/admin/module_filter/README.txt
new file mode 100644
index 00000000..0bc967ab
--- /dev/null
+++ b/sites/all/modules/contrib/admin/module_filter/README.txt
@@ -0,0 +1,107 @@
+Description
+-----------
+This module provides a method for filtering modules on the modules page as well
+as for filtering projects on the update status report.
+
+The supplied filter is simpler than using your browsers find feature which
+searches the entire page. The provided filter will filter modules/projects that
+do not meet your input.
+
+Along with the filter textfield there are additional
+checkboxes that help to narrow the search more. The modules page contains four
+checkboxes: Enabled, Disabled, Required, and Unavailable. While the first two
+are self-explanatory, the latter two can take an explanation. The Required
+checkbox affects visibility of modules that are enabled and have other
+module(s) that require it also enabled. The Unavailable checkbox affects
+visibility of modules that are disabled and depend on module(s) that are
+missing.
+
+The update status report filter also contains four checkboxes: Up-to-Date,
+Update availabe, Security update, and Unknown. These directly affect the
+visibilty of each project; whether it is up-to-date, there is an update
+available, a security update is available, or the status is unknown.
+
+Installation
+------------
+To install this module, do the following:
+
+1. Extract the tar ball that you downloaded from Drupal.org.
+
+2. Upload the entire directory and all its contents to your modules directory.
+
+Configuration
+-------------
+To enable and configure this module do the following:
+
+1. Go to Admin -> Modules, and enable Module Filter.
+
+2. Go to Admin -> Configuration -> User interface -> Module filter, and make
+ any necessary configuration changes.
+
+Tabs
+----
+By default Module Filter alters the modules page into tabs (Can be disabled on
+configuration page). In the tabs view, each package is converted to a vertical
+tab rather than a fieldset which greatly increases the ability to browse them.
+
+There are several benefits to using the tabs view over the standard view for
+the modules page. I've listed the key benefits below as well as additional
+information that pertains to each.
+
+1. The increased ease of browsing between packages.
+
+2. Allows all modules to be listed alphabetically outside of their package,
+ making it all the easier to find the module by name rather than package it
+ happens to be in.
+
+3. The operations for a module are moved within the description column giving
+ the description more "elbow room".
+
+4. Filtering is restricted to within the active tab or globally when no tab is
+ selected. By default no tab is selected which will list all modules. When a
+ tab is active and you want to get back to the 'all' state click on the
+ active tab to deselect it.
+
+5. The number of enabled modules per tab is shown on the active tab. (Can be
+ disabled on configuration page)
+
+6. Nice visual aids become available showing what modules are to be
+ enabled/disabled and the number of matching modules in each tab when
+ filtering. (Can be disabled on configuration page)
+
+7. The save configuration button becomes more accessible, either staying at
+ the bottom of the window when the tabs exceed past the bottom and at the
+ top when scrolling past the tabs. (Can be disabled on configuration page)
+
+8. When filtering, tabs that do not contain matches can be hidden. (Can be
+ enabled on configuration page)
+
+9. Tab states are remembered like individual pages allowing you to move
+ forward and backward within your selections via your browsers
+ forward/backward buttons.
+
+10. When viewing all modules (no active tab) and mousing over modules it's tab
+ becomes highlighted to signify which tab it belongs to.
+
+Filter operators
+----------------
+The modules page's filter has three filter operators available. Filter
+operators allow alternative filtering techniques. A filter operator is applied
+by typing within the filter textfield 'operator:' (where operator is the
+operator type) followed immediately with the string to pass to the operator
+function (e.g. 'requires:block'). The available operators are:
+
+description:
+ Filter based on a module's description.
+
+requiredBy:
+ Filter based on what a module is required by.
+
+requires:
+ Filter based on what a module requires.
+
+Multiple filters (or queries) can be applied by space delimiting. For example,
+the filter string 'description:ctools views' would filter down to modules with
+"ctools" in the description and "views" within the module's name. To pass a
+space within a single query wrap it within double quotes (e.g. 'requires:"chaos
+tools"' or '"bulk export"').
diff --git a/sites/all/modules/contrib/admin/module_filter/css/dynamic_position.css b/sites/all/modules/contrib/admin/module_filter/css/dynamic_position.css
new file mode 100644
index 00000000..bc3b3e76
--- /dev/null
+++ b/sites/all/modules/contrib/admin/module_filter/css/dynamic_position.css
@@ -0,0 +1,23 @@
+html.js #module-filter-submit {
+ background-color: #F6F6F6;
+ width: 239px;
+ border: 1px solid #ccc;
+ border-top: 0;
+}
+html.js #module-filter-submit .form-actions {
+ text-align: center;
+ margin: 0;
+}
+html.js #module-filter-submit input {
+ margin: 2em 0 1em;
+}
+html.js #module-filter-submit.fixed {
+ position: fixed;
+ border-top: 1px solid #ccc;
+}
+html.js #module-filter-submit.fixed-top {
+ top: 0;
+}
+html.js #module-filter-submit.fixed-bottom {
+ bottom: 0;
+}
diff --git a/sites/all/modules/contrib/admin/module_filter/css/module_filter.css b/sites/all/modules/contrib/admin/module_filter/css/module_filter.css
old mode 100755
new mode 100644
index d2353ba0..19d113fb
--- a/sites/all/modules/contrib/admin/module_filter/css/module_filter.css
+++ b/sites/all/modules/contrib/admin/module_filter/css/module_filter.css
@@ -1,4 +1,20 @@
-
+.module-filter-inputs-wrapper {
+ display: none;
+}
+.module-filter-clear {
+ display: inline;
+ position: relative;
+}
+.module-filter-clear a {
+ margin-left: 5px;
+ font-size: 11px;
+ position: absolute;
+}
#module-filter-show-wrapper .form-item {
display: inline;
}
+.module-filter-no-results {
+ text-align: center;
+ text-transform: uppercase;
+ color: #888;
+}
diff --git a/sites/all/modules/contrib/admin/module_filter/css/module_filter_tab-rtl.css b/sites/all/modules/contrib/admin/module_filter/css/module_filter_tab-rtl.css
new file mode 100644
index 00000000..b70f6ef0
--- /dev/null
+++ b/sites/all/modules/contrib/admin/module_filter/css/module_filter_tab-rtl.css
@@ -0,0 +1,54 @@
+#module-filter-tabs {
+ float: right;
+}
+#module-filter-tabs li.selected a,
+#module-filter-tabs li.selected a:hover,
+#module-filter-tabs li.selected a:focus,
+#module-filter-tabs li.selected a:active {
+ background-color: #fff;
+ margin-left: -1px;
+ margin-right: 0;
+}
+.admin-operations {
+ float: left;
+}
+#module-filter-modules {
+ margin-right: 240px;
+}
+html.js .toggle-enable {
+ background-image: -webkit-gradient(linear, 100% 0%, 0% 0%, color-stop(50%, red), color-stop(50%, orange), color-stop(100%, orange));
+ background-image: -moz-linear-gradient(right, red 50%, orange 50%, orange 100%);
+ background-image: linear-gradient(right, red 50%, orange 50%, orange 100%);
+}
+html.js .toggle-enable.enabled {
+ background-image: -webkit-gradient(linear, 100% 0%, 0% 0%, color-stop(50%, orange), color-stop(50%, green), color-stop(100%, green));
+ background-image: -moz-linear-gradient(right, orange 50%, green 50%, green 100%);
+ background-image: linear-gradient(right, orange 50%, green 50%, green 100%);
+}
+html.js .toggle-enable.disabled {
+ background: #ccc;
+ border-color: #ddd;
+ cursor: auto;
+}
+html.js .toggle-enable.disabled div {
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #FEFEFE), color-stop(100%, #EEEEEE));
+ background-image: -moz-linear-gradient(top, #FEFEFE 0%, #EEEEEE 100%);
+ background-image: linear-gradient(top, #FEFEFE 0%, #EEEEEE 100%);
+}
+html.js .toggle-enable div {
+ -webkit-transition: right 0.2s;
+ -mox-transition: right 0.2s;
+ -o-transition: right 0.2s;
+ transition: right 0.2s;
+}
+html.js .toggle-enable div:before {
+ content: "ON";
+ left: -24px;
+}
+html.js .toggle-enable div:after {
+ content: "OFF";
+ left: -24px;
+}
+html.js .toggle-enable.off div {
+ right: 24px;
+}
diff --git a/sites/all/modules/contrib/admin/module_filter/css/module_filter_tab.css b/sites/all/modules/contrib/admin/module_filter/css/module_filter_tab.css
old mode 100755
new mode 100644
index 47e73370..2607a617
--- a/sites/all/modules/contrib/admin/module_filter/css/module_filter_tab.css
+++ b/sites/all/modules/contrib/admin/module_filter/css/module_filter_tab.css
@@ -1,136 +1,262 @@
+.sticky-header {
+ z-index: 1;
+}
-#module-filter-wrapper .form-item {
- border: 0px none;
+#module-filter-tabs {
+ float: left;
+}
+#module-filter-tabs ul {
+ width: 239px;
+ list-style: none;
+ list-style-image: none;
+ background-color: #ddd;
+ border: 1px solid #ccc;
+ border-top: none;
+ margin: 0;
+ padding: 0;
+ line-height: 1;
+}
+#module-filter-tabs li {
+ background: #eee;
+ border-top: 1px solid #ccc;
+ padding: 0;
+ margin: 0;
+ min-width: 0;
+}
+#module-filter-tabs li#new-tab {
+ margin-bottom: 10px;
+ border-bottom: 1px solid #ccc;
+}
+#module-filter-tabs li.disabled,
+#module-filter-tabs li#new-tab.disabled {
+ pointer-events: none;
+ cursor: default;
+ background: #ccc;
+ border-top-color: #bbb;
+ border-bottom-color: #bbb;
+}
+#module-filter-tabs li.disabled a,
+#module-filter-tabs li.disabled span {
+ color: #999;
+}
+#module-filter-tabs li.suggest {
+ background: #F9F9F9;
+}
+#module-filter-tabs li a {
+ display: block;
+ text-decoration: none;
+ padding: 10px;
+}
+#module-filter-tabs li a span.result-info {
+ float: right;
+ font-size: 10px;
+ color: #999;
+ margin-top: 3px;
+}
+#module-filter-tabs li a span.visual-aid {
+ font-size: 8px;
+/* float: right;*/
+}
+#module-filter-tabs li span.visual-aid {
+ font-weight: bold;
+}
+#module-filter-tabs li a span.enabling {
+ color: green;
+}
+#module-filter-tabs li a span.disabling {
+ color: red;
+}
+#module-filter-tabs li strong {
+ font-size: 0.923em;
+}
+#module-filter-tabs li a:hover,
+#module-filter-tabs li a:focus {
+ outline: 1px dotted;
+ background: #d5d5d5;
+ text-decoration: none;
+ outline: 0;
+}
+#module-filter-tabs li.selected a,
+#module-filter-tabs li.selected a:hover,
+#module-filter-tabs li.selected a:focus,
+#module-filter-tabs li.selected a:active {
+ background-color: #fff;
+ margin-right: -1px;
+}
+#module-filter-tabs li .summary {
+ display: block;
+ margin-bottom: 0;
+ color: #666;
+ font-size: 0.846em;
+ padding-top: 0.4em;
+}
+#module-filter-tabs li .summary .count {
+ display: none;
+}
+#module-filter-tabs li.selected .summary .count {
+ display: block;
+}
+html.js #module-filter-submit input {
+ margin: 2em 2em 1em;
+}
+html.js .module-filter-inputs-wrapper {
+ text-align: center;
+}
+html.js .module-filter-inputs-wrapper .form-item {
margin: 0;
padding: 9px;
}
-#module-filter-wrapper .form-item:after {
-/* display: block;*/
- clear: none;
+html.js .module-filter-inputs-wrapper label {
+ display: inline;
}
-#module-filter-left {
- float: left;
- background-color: #F6F6F6;
- border: 1px solid #D6DBDE;
- margin-right: -1px;
- width: 185px;
+html.js .module-filter-inputs-wrapper input[name="module_filter[name]"] {
+ width: 80%;
}
-#module-filter-left ul {
- margin: 0px;
- padding: 0px;
- list-style: none;
+html.js #module-filter-show-wrapper {
+ margin-bottom: 1em;
}
-#module-filter-left ul li {
- background: #EFEFEF none repeat scroll 0 0;;
- border-bottom: 1px solid #D6DBDE;
- margin: 0px;
- padding: 0px;
- list-style-image: none;
+html.js #module-filter-modules {
+ margin-left: 240px;
+ border: 1px solid #ccc;
}
-#module-filter-left ul li.active {
- margin-right: -1px;
- width: 186px;
- background-color: #FFFFFF;
- position: relative;
+#module-filter-modules table {
+ border-top: none;
+ border-right: none;
+ border-left: none;
}
-#module-filter-left ul li a {
- color: #777777;
- display: block;
- padding: 0.5em;
- line-height: 100%;
- font-size: 90%;
- outline: none;
-}
-#module-filter-left ul li.active a {
- background-color: #FFFFFF;
- color: #000000;
- font-weight: bold;
-}
-#module-filter-left ul li a:hover {
- background-color: #F6F6F6;
- text-decoration: none;
-}
-#module-filter-left ul li.active a:hover {
- background-color: #FFFFFF;
-}
-#module-filter-left ul li a span.visual-aid {
- font-size: 8px;
- float: right;
-}
-#module-filter-left ul li a span.enabling {
- color: green;
-}
-#module-filter-left ul li a span.disabling {
- color: red;
- margin-left: 5px;
-}
-#module-filter-left ul li a span.counts {
- font-weight: normal;
- display: none;
- font-size: 0.8em;
- color: #333333;
- padding: 2px 0 0;
-}
-#module-filter-left ul li.active a span.counts {
- display: block;
-}
-#module-filter-submit {
+html.js #module-filter-modules table {
margin: 0;
+ border-bottom: none;
}
-#module-filter-submit .form-actions {
- text-align: center;
+html.js #module-filter-modules table tr,
+html.js #module-filter-modules table td {
+ border-left: 0;
+ border-right: 0;
}
-#module-filter-submit input.form-submit {
- margin: 1em 0 0;
+#module-filter-modules table thead {
+ display: none;
}
-#module-filter-submit.fixed {
- position: fixed;
- background-color: #F6F6F6;
- border: 1px solid #D6DBDE;
- margin-left: -1px;
- width: 185px;
+#module-filter-modules table tr.admin-package-title,
+#module-filter-modules table tr.admin-package-title td {
+ border: none !important;
+ border-top: 1px solid #ccc !important;
+ background-color: transparent !important;
+ padding: 10px 0 0;
}
-#module-filter-submit.fixed-top {
- top: 0;
+#module-filter-modules table tr.admin-package-title.first,
+#module-filter-modules table tr.admin-package-title.first td {
+ border-top: none !important;
}
-#module-filter-submit.fixed-bottom {
- bottom: 0;
+#module-filter-modules table tr.admin-package-header td {
+ border: 1px solid #ccc;
+ text-transform: uppercase;
+ background: #E1E2DC;
+ font-weight: normal;
+ padding: 3px 10px;
}
-#module-filter-right {
- display: block;
-}
-#module-filter-squeeze {
- margin-left: 186px;
- background-color: #FFFFFF;
- border: 1px solid #D6DBDE;
- height: auto !important;
-}
-.form-item-module-filter-name {
- text-align: center;
-}
-.form-item-module-filter-name label {
- display: inline;
-}
-#module-filter-show-wrapper .form-checkboxes {
- text-align: center;
-}
-#module-filter-show-wrapper .form-item:after {
- display: inline;
-}
-table.package {
- margin: 1em 0;
-}
-table.package,
-table.package thead,
-table.package tbody,
-table.package tbody tr,
-table.package td:last-child {
- border-right: 0 none;
- border-left: 0 none;
-}
-table.package tr.enabling {
+#module-filter-modules table tr.enabling {
background-color: #dfd;
}
-table.package tr.disabling {
+#module-filter-modules table tr.disabling {
background-color: #fcc;
}
+#module-filter-modules span.module-machine-name {
+ font-size: 0.9em;
+ font-weight: normal;
+}
+.admin-version {
+ white-space: nowrap;
+}
+.admin-operations {
+ float: right;
+}
+.admin-operations a.module-link {
+ display: inline;
+}
+
+html.js .toggle-enable {
+ margin: auto;
+ position: relative;
+ width: 50px;
+ overflow: hidden;
+ height: 18px;
+ line-height: 18px;
+ font-size: 11px;
+ text-align: center;
+ cursor: pointer;
+ border: 1px solid #ccc;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ -khtml-border-radius: 3px;
+ border-radius: 3px;
+ -moz-box-shadow: 0 0 10px rgba(0,0,0,0.50) inset;
+ -webkit-box-shadow: 0 0 10px rgba(0,0,0,0.50) inset;
+ box-shadow: 0 0 10px rgba(0,0,0,0.50) inset;
+ background-clip: padding-box;
+ background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, color-stop(50%, red), color-stop(50%, orange), color-stop(100%, orange));
+ background-image: -moz-linear-gradient(left, red 50%, orange 50%, orange 100%);
+ background-image: linear-gradient(left, red 50%, orange 50%, orange 100%);
+}
+html.js .toggle-enable.enabled {
+ background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, color-stop(50%, orange), color-stop(50%, green), color-stop(100%, green));
+ background-image: -moz-linear-gradient(left, orange 50%, green 50%, green 100%);
+ background-image: linear-gradient(left, orange 50%, green 50%, green 100%);
+}
+html.js .toggle-enable.disabled {
+ background: #ccc;
+ border-color: #ddd;
+ cursor: auto;
+}
+html.js .toggle-enable div {
+ position: relative;
+ color: #777;
+ width: 26px;
+ -moz-border-radius: 2px;
+ -webkit-border-radius: 2px;
+ -khtml-border-radius: 2px;
+ border-radius: 2px;
+ background: white;
+ text-shadow: 1px 1px 0 white;
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #FEFEFE), color-stop(100%, #EAEAEA));
+ background-image: -moz-linear-gradient(top, #FEFEFE 0%, #EAEAEA 100%);
+ background-image: linear-gradient(top, #FEFEFE 0%, #EAEAEA 100%);
+ -webkit-transition: left 0.2s;
+ -mox-transition: left 0.2s;
+ -o-transition: left 0.2s;
+ transition: left 0.2s;
+}
+html.js .toggle-enable.disabled div {
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #FEFEFE), color-stop(100%, #EEEEEE));
+ background-image: -moz-linear-gradient(top, #FEFEFE 0%, #EEEEEE 100%);
+ background-image: linear-gradient(top, #FEFEFE 0%, #EEEEEE 100%);
+}
+html.js .toggle-enable div:after,
+html.js .toggle-enable div:before {
+ color: white;
+ text-shadow: none;
+ width: 25px;
+ position: absolute;
+ top: 0;
+ font-size: 9px;
+ font-weight: bold;
+}
+html.js .toggle-enable div:before {
+ content: "OFF";
+ left: -24px;
+}
+html.js .toggle-enable div:after {
+ content: "ON";
+ right: -24px;
+}
+html.js .toggle-enable.off div {
+ left: 24px;
+}
+
+#module-filter-tabs.top-fixed {
+ position: fixed;
+ top: 0;
+}
+#module-filter-tabs.bottom-fixed {
+ position: fixed;
+ bottom: 0;
+}
diff --git a/sites/all/modules/contrib/admin/module_filter/css/modules.css b/sites/all/modules/contrib/admin/module_filter/css/modules.css
new file mode 100644
index 00000000..91fa7418
--- /dev/null
+++ b/sites/all/modules/contrib/admin/module_filter/css/modules.css
@@ -0,0 +1,47 @@
+#system-modules table {
+ table-layout: fixed;
+}
+#system-modules th.checkbox {
+ width: 8%;
+}
+#system-modules th.name {
+ width: 25%;
+}
+#system-modules th.links {
+ width: 15%;
+}
+#system-modules td {
+ vertical-align: top;
+}
+#system-modules .expand.inner {
+ background: transparent url(/misc/menu-collapsed.png) left 0.6em no-repeat;
+ margin-left: -12px;
+ padding-left: 12px;
+}
+#system-modules .expanded.expand.inner {
+ background: transparent url(/misc/menu-expanded.png) left 0.6em no-repeat;
+}
+#system-modules .description {
+ cursor: pointer;
+}
+#system-modules .description .inner {
+ overflow: hidden; /* truncates descriptions if too long */
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+#system-modules .description .requirements,
+#system-modules .description .links {
+ display: none;
+}
+#system-modules .description .expanded.inner {
+ overflow: visible;
+ white-space: normal;
+}
+#system-modules .description .expanded .requirements,
+#system-modules .description .expanded .links {
+ display: block;
+}
+#system-modules .requirements {
+ padding: 5px 0;
+ max-width: 490px;
+}
diff --git a/sites/all/modules/contrib/admin/module_filter/css/update_status.css b/sites/all/modules/contrib/admin/module_filter/css/update_status.css
new file mode 100644
index 00000000..c0bee443
--- /dev/null
+++ b/sites/all/modules/contrib/admin/module_filter/css/update_status.css
@@ -0,0 +1,18 @@
+#module-filter-update-status-form {
+ float: right;
+}
+.module-filter-inputs-wrapper label {
+ display: inline;
+}
+.module-filter-inputs-wrapper .form-item-module-filter-name {
+ margin-bottom: 0;
+ padding-bottom: 0;
+ text-align: right;
+}
+#module-filter-show-wrapper .form-item {
+ padding: 5px;
+}
+p.module-filter-no-results {
+ clear: both;
+ padding-top: 30px;
+}
diff --git a/sites/all/modules/contrib/admin/module_filter/js/dynamic_position.js b/sites/all/modules/contrib/admin/module_filter/js/dynamic_position.js
old mode 100755
new mode 100644
index 10c66b4f..41c57312
--- a/sites/all/modules/contrib/admin/module_filter/js/dynamic_position.js
+++ b/sites/all/modules/contrib/admin/module_filter/js/dynamic_position.js
@@ -1,33 +1,48 @@
(function($) {
- Drupal.behaviors.moduleFilterDynamicPosition = {
- attach: function() {
- $(window).scroll(function() {
+
+Drupal.behaviors.moduleFilterDynamicPosition = {
+ attach: function(context) {
+ var $window = $(window);
+
+ $('#module-filter-wrapper', context).once('dynamic-position', function() {
+ // Move the submit button just below the tabs.
+ $('#module-filter-tabs').append($('#module-filter-submit'));
+
+ var positionSubmit = function() {
+ var $tabs = $('#module-filter-tabs');
+ var $submit = $('#module-filter-submit', $tabs);
+
// Vertical movement.
- var top = $('#module-filter-tabs').offset().top;
- var bottom = top + $('#module-filter-tabs').height();
- var windowHeight = $(window).height();
- if (((bottom - windowHeight) > ($(window).scrollTop() - $('#module-filter-submit').height())) && $(window).scrollTop() + windowHeight - $('#module-filter-submit').height() - $('#all-tab').height() > top) {
- $('#module-filter-submit').removeClass('fixed-top').addClass('fixed fixed-bottom');
+ var bottom = $tabs.offset().top + $tabs.outerHeight();
+ if ($submit.hasClass('fixed-bottom')) {
+ bottom += $submit.height();
}
- else if (bottom < $(window).scrollTop()) {
- $('#module-filter-submit').removeClass('fixed-bottom').addClass('fixed fixed-top');
+ if (bottom >= $window.height() + $window.scrollTop()) {
+ $submit.addClass('fixed fixed-bottom');
+ $tabs.css('padding-bottom', $submit.height());
}
else {
- $('#module-filter-submit').removeClass('fixed fixed-bottom fixed-top');
+ $submit.removeClass('fixed fixed-bottom');
+ $tabs.css('padding-bottom', 0);
}
// Horizontal movement.
- if ($('#module-filter-submit').hasClass('fixed-bottom') || $('#module-filter-submit').hasClass('fixed-top')) {
- var left = $('#module-filter-tabs').offset().left - $(window).scrollLeft();
- if (left != $('#module-filter-submit').offset().left - $(window).scrollLeft()) {
- $('#module-filter-submit').css('left', left);
+ if ($submit.hasClass('fixed-bottom') || $submit.hasClass('fixed-top')) {
+ var left = $tabs.offset().left - $window.scrollLeft();
+ if (left != $submit.offset().left - $window.scrollLeft()) {
+ $submit.css('left', left);
}
}
- });
- $(window).trigger('scroll');
- $(window).resize(function() {
- $(window).trigger('scroll');
- });
- }
+ };
+
+ // Control the positioning.
+ $window.scroll(positionSubmit);
+ $window.resize(positionSubmit);
+ var moduleFilter = $('input[name="module_filter[name]"]').data('moduleFilter');
+ moduleFilter.element.bind('moduleFilter:adjustHeight', positionSubmit);
+ moduleFilter.adjustHeight();
+ });
}
+};
+
})(jQuery);
diff --git a/sites/all/modules/contrib/admin/module_filter/js/module_filter.js b/sites/all/modules/contrib/admin/module_filter/js/module_filter.js
old mode 100755
new mode 100644
index 49f6b7a0..d5f53287
--- a/sites/all/modules/contrib/admin/module_filter/js/module_filter.js
+++ b/sites/all/modules/contrib/admin/module_filter/js/module_filter.js
@@ -1,120 +1,271 @@
-
(function ($) {
- var moduleFilterTimeOut;
- var moduleFilterTextFilter = '';
- Drupal.behaviors.moduleFilter = {
- attach: function() {
- $("#module-filter-wrapper").show();
- $('input[name="module_filter[name]"]').focus();
- $('input[name="module_filter[name]"]').keyup(function(e) {
- switch (e.which) {
- case 13:
- if (moduleFilterTimeOut) {
- clearTimeout(moduleFilterTimeOut);
- }
+Drupal.ModuleFilter = {};
- moduleFilter(moduleFilterTextFilter);
- break;
- default:
- if (moduleFilterTextFilter != $(this).val()) {
- moduleFilterTextFilter = this.value;
- if (moduleFilterTimeOut) {
- clearTimeout(moduleFilterTimeOut);
- }
+Drupal.ModuleFilter.explode = function(string) {
+ var queryArray = string.match(/([a-zA-Z]+\:(\w+|"[^"]+")*)|\w+|"[^"]+"/g);
+ if (!queryArray) {
+ queryArray = new Array();
+ }
+ var i = queryArray.length;
+ while (i--) {
+ queryArray[i] = queryArray[i].replace(/"/g, "");
+ }
+ return queryArray;
+};
- moduleFilterTimeOut = setTimeout('moduleFilter("' + moduleFilterTextFilter + '")', 500);
- }
- break;
+Drupal.ModuleFilter.getState = function(key) {
+ if (!Drupal.ModuleFilter.state) {
+ Drupal.ModuleFilter.state = {};
+ var cookie = $.cookie('DrupalModuleFilter');
+ var query = cookie ? cookie.split('&') : [];
+ if (query) {
+ for (var i in query) {
+ // Extra check to avoid js errors in Chrome, IE and Safari when
+ // combined with JS like twitter's widget.js.
+ // See http://drupal.org/node/798764.
+ if (typeof(query[i]) == 'string' && query[i].indexOf('=') != -1) {
+ var values = query[i].split('=');
+ if (values.length === 2) {
+ Drupal.ModuleFilter.state[values[0]] = values[1];
+ }
}
- });
- $('input[name="module_filter[name]"]').keypress(function(e) {
- if (e.which == 13) e.preventDefault();
- });
-
- $('#edit-module-filter-show-enabled').change(function() {
- moduleFilter($('input[name="module_filter[name]"]').val());
- });
- $('#edit-module-filter-show-disabled').change(function() {
- moduleFilter($('input[name="module_filter[name]"]').val());
- });
- $('#edit-module-filter-show-required').change(function() {
- moduleFilter($('input[name="module_filter[name]"]').val());
- });
- $('#edit-module-filter-show-unavailable').change(function() {
- moduleFilter($('input[name="module_filter[name]"]').val());
- });
+ }
}
}
+ return Drupal.ModuleFilter.state[key] ? Drupal.ModuleFilter.state[key] : false;
+};
- moduleFilter = function(string) {
- stringLowerCase = string.toLowerCase();
+Drupal.ModuleFilter.setState = function(key, value) {
+ var existing = Drupal.ModuleFilter.getState(key);
+ if (existing != value) {
+ Drupal.ModuleFilter.state[key] = value;
+ var query = [];
+ for (var i in Drupal.ModuleFilter.state) {
+ query.push(i + '=' + Drupal.ModuleFilter.state[i]);
+ }
+ $.cookie('DrupalModuleFilter', query.join('&'), { expires: 7, path: '/' });
+ }
+};
- $("fieldset table tbody tr td label strong").each(function(i) {
- var $row = $(this).parents('tr');
- var module = $(this).text();
- var moduleLowerCase = module.toLowerCase();
- var $fieldset = $row.parents('fieldset');
+Drupal.ModuleFilter.Filter = function(element, selector, options) {
+ var self = this;
- if (string != '') {
- if ($fieldset.hasClass('collapsed')) {
- $fieldset.removeClass('collapsed');
+ this.element = element;
+ this.text = $(this.element).val();
+
+ this.settings = Drupal.settings.moduleFilter;
+
+ this.selector = selector;
+
+ this.options = $.extend({
+ delay: 500,
+ striping: false,
+ childSelector: null,
+ empty: Drupal.t('No results'),
+ rules: new Array()
+ }, options);
+ if (this.options.wrapper == undefined) {
+ this.options.wrapper = $(self.selector).parent();
+ }
+
+ // Add clear button.
+ this.element.after('
';
+ }
+}
diff --git a/sites/all/modules/contrib/admin/nodeformcols/nfcbiblio.info b/sites/all/modules/contrib/admin/nodeformcols/nfcbiblio.info
index 71b112a5..4e4bd005 100644
--- a/sites/all/modules/contrib/admin/nodeformcols/nfcbiblio.info
+++ b/sites/all/modules/contrib/admin/nodeformcols/nfcbiblio.info
@@ -5,9 +5,9 @@ dependencies[] = biblio
core = 7.x
package = Node form columns
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.x-1.0"
+; Information added by Drupal.org packaging script on 2016-09-16
+version = "7.x-1.1"
core = "7.x"
project = "nodeformcols"
-datestamp = "1389798806"
+datestamp = "1474036440"
diff --git a/sites/all/modules/contrib/admin/nodeformcols/nfcbiblio.module b/sites/all/modules/contrib/admin/nodeformcols/nfcbiblio.module
index e5502c53..b7dcad38 100644
--- a/sites/all/modules/contrib/admin/nodeformcols/nfcbiblio.module
+++ b/sites/all/modules/contrib/admin/nodeformcols/nfcbiblio.module
@@ -19,7 +19,7 @@ function nfcbiblio_nodeformcols_variants_alter(&$variants, $type) {
WHERE tid >= :tid
AND visible = :visible
ORDER BY weight ASC', array(':tid' => 0, ':visible' => 1));
- while ($option = db_fetch_object($res)) {
+ while ($option = $res->fetchObject()) {
$variants[$option->tid] = $option->name;
}
}
@@ -35,8 +35,8 @@ function _nfcbiblio_top_visible_type() {
return db_query_range("SELECT tid
FROM {biblio_types}
WHERE visible = :visible
- AND tid> = :tid>
- ORDER BY weight ASC", array(':visible' => 1, ':tid>' => 0))->fetchField();
+ AND tid >= :tid
+ ORDER BY weight ASC", 0, 1, array(':visible' => 1, ':tid' => 0))->fetchField();
}
/**
diff --git a/sites/all/modules/contrib/admin/nodeformcols/nfccaptcha.info b/sites/all/modules/contrib/admin/nodeformcols/nfccaptcha.info
index e0323c7b..73067437 100644
--- a/sites/all/modules/contrib/admin/nodeformcols/nfccaptcha.info
+++ b/sites/all/modules/contrib/admin/nodeformcols/nfccaptcha.info
@@ -5,9 +5,9 @@ dependencies[] = captcha
core = 7.x
package = Node form columns
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.x-1.0"
+; Information added by Drupal.org packaging script on 2016-09-16
+version = "7.x-1.1"
core = "7.x"
project = "nodeformcols"
-datestamp = "1389798806"
+datestamp = "1474036440"
diff --git a/sites/all/modules/contrib/admin/nodeformcols/nodeformcols.admin.inc b/sites/all/modules/contrib/admin/nodeformcols/nodeformcols.admin.inc
index 79d422b8..05dc54cc 100644
--- a/sites/all/modules/contrib/admin/nodeformcols/nodeformcols.admin.inc
+++ b/sites/all/modules/contrib/admin/nodeformcols/nodeformcols.admin.inc
@@ -21,6 +21,20 @@ function _nodeformcols_get_node_type_form($type) {
);
$fs += form_state_defaults();
$nf = drupal_retrieve_form($nfid, $fs);
+ // Add in field_groups if they exist.
+ if (module_exists('field_group') && !empty($nf['#groups'])) {
+ foreach ($nf['#groups'] as $group) {
+ $group_title = $group->label . ' (' . t('Field group') . ')';
+ $nf[$group->group_name] = array(
+ '#group' => $group,
+ '#weight' => $group->weight,
+ '#title' => $group_title,
+ );
+ foreach ($nf['#groups'][$group->group_name]->children as $group_field) {
+ unset($nf[$group_field]);
+ }
+ }
+ }
drupal_prepare_form($nfid, $nf, $fs);
drupal_process_form($nfid, $nf, $fs);
return $nf;
@@ -35,8 +49,10 @@ function nodeformcols_update_placements($type, $variant, &$placements) {
$field = $form[$key];
if (
substr($key, 0, 8) == 'section_' ||
+ // Exclude hidden fields.
(isset($field['#type']) && in_array($field['#type'], array('value', 'hidden', 'token'))) ||
- (isset($field['#type'], $field['#group']) && $field['#type'] === 'fieldset')
+ // Exclude the vertical tabs.
+ (isset($field['#group']) && $field['#group'] == 'additional_settings')
) {
// Remove placements that meet exclusion rules.
if (isset($placements[$key])) {
@@ -128,7 +144,7 @@ function nodeformcols_configuration_form($form, $form_state, $node_type, $varian
$form['variant'] = array(
'#type' => 'item',
'#title' => t('Select a form variant'),
- '#value' => theme('links', array('links' => $variant_links)),
+ '#markup' => theme('links', array('links' => $variant_links)),
);
}
diff --git a/sites/all/modules/contrib/admin/nodeformcols/nodeformcols.info b/sites/all/modules/contrib/admin/nodeformcols/nodeformcols.info
index 720563a0..c0585e9a 100644
--- a/sites/all/modules/contrib/admin/nodeformcols/nodeformcols.info
+++ b/sites/all/modules/contrib/admin/nodeformcols/nodeformcols.info
@@ -3,9 +3,9 @@ description = Separates the node forms into two columns and a footer.
core = 7.x
package = Node form columns
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.x-1.0"
+; Information added by Drupal.org packaging script on 2016-09-16
+version = "7.x-1.1"
core = "7.x"
project = "nodeformcols"
-datestamp = "1389798806"
+datestamp = "1474036440"
diff --git a/sites/all/modules/contrib/admin/nodeformcols/nodeformcols.module b/sites/all/modules/contrib/admin/nodeformcols/nodeformcols.module
index 793edcf1..245e5aa7 100644
--- a/sites/all/modules/contrib/admin/nodeformcols/nodeformcols.module
+++ b/sites/all/modules/contrib/admin/nodeformcols/nodeformcols.module
@@ -160,8 +160,8 @@ function template_preprocess_node_form(&$aVars) {
}
}
- foreach ($has_elements as $name => $has) {
- if ($has) {
+ foreach ($regions as $name => $data) {
+ if (!empty($has_elements[$name])) {
$class[] = 'node-form-has-region-' . $name;
$form['nodeformcols_region_' . $name] = $regions[$name];
}
@@ -191,8 +191,8 @@ function nodeformcols_node_type_update($info) {
$base = 'nodeformscols_field_placements_' . $info->old_type;
$new_base = 'nodeformscols_field_placements_' . $info->type;
$result = db_select('variable')
- ->condition('name', $base . '%', 'LIKE')
->fields('variable', array('name'))
+ ->condition('name', $base . '%', 'LIKE')
->execute();
foreach ($result as $row) {
$value = variable_get($row->name, NULL);
diff --git a/sites/all/modules/contrib/admin/redirect/LICENSE.txt b/sites/all/modules/contrib/admin/redirect/LICENSE.txt
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/redirect/README.txt b/sites/all/modules/contrib/admin/redirect/README.txt
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/redirect/redirect.admin.inc b/sites/all/modules/contrib/admin/redirect/redirect.admin.inc
old mode 100755
new mode 100644
index 3d70ebf4..1e804383
--- a/sites/all/modules/contrib/admin/redirect/redirect.admin.inc
+++ b/sites/all/modules/contrib/admin/redirect/redirect.admin.inc
@@ -18,6 +18,7 @@ function redirect_list_form($form, &$form_state) {
$header = array(
'source' => array('data' => t('From'), 'field' => 'source', 'sort' => 'asc'),
'redirect' => array('data' => t('To'), 'field' => 'redirect'),
+ 'status' => array('data' => t('Status'), 'field' => 'status'),
'status_code' => array('data' => t('Type'), 'field' => 'status_code'),
'language' => array('data' => t('Language'), 'field' => 'language'),
'count' => array('data' => t('Count'), 'field' => 'count'),
@@ -84,6 +85,7 @@ function redirect_list_form($form, &$form_state) {
drupal_alter('redirect_url', $redirect->redirect, $redirect->redirect_options);
$row['source'] = l($source_url, $redirect->source, $redirect->source_options);
$row['redirect'] = l($redirect_url, $redirect->redirect, $redirect->redirect_options);
+ $row['status'] = $redirect->status ? t('Enabled') : t('Disabled');
$row['status_code'] = $redirect->status_code ? $redirect->status_code : t('Default (@default)', array('@default' => $default_status_code));
$row['language'] = module_invoke('locale', 'language_name', $redirect->language);
$row['count'] = $redirect->count;
@@ -262,6 +264,10 @@ function redirect_list_form_operations_submit($form, &$form_state) {
}
call_user_func_array($function, $args);
+ // We display the number of redirects the user selected, regardless of
+ // how many redirects actually changed status. Eg. if 1 enabled and 1
+ // disabled redirects are checked for being enabled, we'll still display
+ // "Enabled 1 redirect."
$count = count($form_state['values']['rids']);
watchdog('redirect', '@action @count redirects.', array('@action' => $operation['action_past'], '@count' => $count));
drupal_set_message(format_plural(count($rids), '@action @count redirect.', '@action @count redirects.', array('@action' => $operation['action_past'], '@count' => $count)));
@@ -336,6 +342,10 @@ function redirect_edit_form($form, &$form_state, $redirect = NULL) {
'#type' => 'value',
'#value' => $redirect->hash,
);
+ $form['uid'] = array(
+ '#type' => 'value',
+ '#value' => $redirect->uid,
+ );
$form['source'] = array(
'#type' => 'textfield',
@@ -361,6 +371,7 @@ function redirect_edit_form($form, &$form_state, $redirect = NULL) {
'#description' => t('Enter an internal Drupal path, path alias, or complete external URL (like http://example.com/) to redirect to. Use %front to redirect to the front page.', array('%front' => '')),
'#element_validate' => array('redirect_element_validate_redirect'),
);
+
$form['redirect_options'] = array(
'#type' => 'value',
'#value' => $redirect->redirect_options,
@@ -373,6 +384,14 @@ function redirect_edit_form($form, &$form_state, $redirect = NULL) {
'#value' => $redirect->language,
);
+ $form['status'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Enabled'),
+ '#description' => t('If this box is checked, this redirect will be enabled.'),
+ '#default_value' => $redirect->status,
+ '#required' => FALSE,
+ );
+
$form['advanced'] = array(
'#type' => 'fieldset',
'#title' => t('Advanced options'),
@@ -465,7 +484,7 @@ function redirect_element_validate_redirect($element, &$form_state) {
// Normalize the path.
$value = drupal_get_normal_path($value, $form_state['values']['language']);
- if (!valid_url($value) && !valid_url($value, TRUE) && $value != '' && $value != '') {
+ if (!valid_url($value) && !valid_url($value, TRUE) && $value != '' && $value != '' && !file_exists($value)) {
form_error($element, t('The redirect path %value is not valid.', array('%value' => $value)));
}
@@ -520,10 +539,13 @@ function redirect_edit_form_validate($form, &$form_state) {
$redirect = (object) $form_state['values'];
if (empty($form_state['values']['override'])) {
- if ($existing = redirect_load_by_source($redirect->source, $redirect->language)) {
+ // Find out if any (disabled or enabled) redirect with this source already
+ // exists.
+ if ($existing = redirect_load_by_source($redirect->source, $redirect->language, array(), FALSE)) {
if ($redirect->rid != $existing->rid && $redirect->language == $existing->language) {
- // The "from" path should not conflict with another redirect
- $form_state['storage']['override_messages']['redirect-conflict'] = t('The base source path %source is already being redirected. Do you want to edit the existing redirect?', array('%source' => $redirect->source, '@edit-page' => url('admin/config/search/redirect/edit/'. $existing->rid)));
+ // The "from" path should not conflict with another (disabled or
+ // enabled) redirect.
+ $form_state['storage']['override_messages']['redirect-conflict'] = t('A redirect already exists for the source path %source. Do you want to edit the existing redirect?', array('%source' => $redirect->source, '@edit-page' => url('admin/config/search/redirect/edit/'. $existing->rid)));
$form_state['rebuild'] = TRUE;
}
}
@@ -621,7 +643,7 @@ function redirect_settings_form($form, &$form_state) {
'#type' => 'checkbox',
'#title' => t('Allow redirects to be saved into the page cache.'),
'#default_value' => variable_get('redirect_page_cache', 0),
- '#description' => t('This feature requires Cache pages for anonymous users to be enabled and the %variable variable to be TRUE.', array('@performance' => url('admin/config/development/performance'), '%variable' => "\$conf['page_cache_invoke_hooks']")),
+ '#description' => t('This feature requires Cache pages for anonymous users to be enabled and the %variable variable to be true (currently set to @value).', array('@performance' => url('admin/config/development/performance'), '%variable' => "\$conf['page_cache_invoke_hooks']", '@value' => var_export(variable_get('page_cache_invoke_hooks', TRUE), TRUE))),
'#disabled' => !variable_get('cache', 0) || !variable_get('page_cache_invoke_hooks', TRUE),
);
$form['redirect_purge_inactive'] = array(
@@ -629,7 +651,7 @@ function redirect_settings_form($form, &$form_state) {
'#title' => t('Delete redirects that have not been accessed for'),
'#default_value' => variable_get('redirect_purge_inactive', 0),
'#options' => array(0 => t('Never (do not discard)')) + drupal_map_assoc(array(604800, 1209600, 1814400, 2592000, 5184000, 7776000, 10368000, 15552000, 31536000), 'format_interval'),
- '#description' => t('Only redirects managaged by the redirect module itself will be deleted. Redirects managed by other modules will be left alone.'),
+ '#description' => t('Only redirects managed by the redirect module itself will be deleted. Redirects managed by other modules will be left alone.'),
'#disabled' => variable_get('redirect_page_cache', 0) && !variable_get('page_cache_invoke_hooks', TRUE),
);
@@ -814,6 +836,7 @@ function redirect_list_table($redirects, $header) {
$header = array_intersect_key(array(
'source' => array('data' => t('From'), 'field' => 'source', 'sort' => 'asc'),
'redirect' => array('data' => t('To'), 'field' => 'redirect'),
+ 'status' => array('data' => t('Status'), 'field' => 'status'),
'status_code' => array('data' => t('Type'), 'field' => 'status_code'),
'language' => array('data' => t('Language'), 'field' => 'language'),
'count' => array('data' => t('Count'), 'field' => 'count'),
@@ -834,6 +857,7 @@ function redirect_list_table($redirects, $header) {
$redirect_url = redirect_url($redirect->redirect, array_merge($redirect->redirect_options, array('alias' => TRUE)));
$row['data']['source'] = l($source_url, $redirect->source, $redirect->source_options);
$row['data']['redirect'] = l($redirect_url, $redirect->redirect, $redirect->redirect_options);
+ $row['data']['status'] = $redirect->status ? t('Enabled') : t('Disabled');
$row['data']['status_code'] = $redirect->status_code ? $redirect->status_code : t('Default (@default)', array('@default' => $default_status_code));
$row['data']['language'] = module_invoke('locale', 'language_name', $redirect->language);
$row['data']['count'] = $redirect->count;
@@ -852,6 +876,12 @@ function redirect_list_table($redirects, $header) {
$row['class'][] = 'warning';
$row['title'] = t('This redirect overrides an existing internal path.');
}
+ if ($redirect->status) {
+ $row['class'][] = 'redirect-enabled';
+ }
+ else {
+ $row['class'][] = 'redirect-disabled';
+ }
$operations = array();
if (redirect_access('update', $redirect)) {
diff --git a/sites/all/modules/contrib/admin/redirect/redirect.admin.js b/sites/all/modules/contrib/admin/redirect/redirect.admin.js
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/redirect/redirect.api.php b/sites/all/modules/contrib/admin/redirect/redirect.api.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/redirect/redirect.controller.inc b/sites/all/modules/contrib/admin/redirect/redirect.controller.inc
new file mode 100755
index 00000000..2d289b1e
--- /dev/null
+++ b/sites/all/modules/contrib/admin/redirect/redirect.controller.inc
@@ -0,0 +1,20 @@
+ $redirect) {
+ $redirects[$key]->source_options = unserialize($redirect->source_options);
+ $redirects[$key]->redirect_options = unserialize($redirect->redirect_options);
+ }
+ parent::attachLoad($redirects, $revision_id);
+ }
+}
diff --git a/sites/all/modules/contrib/admin/redirect/redirect.drush.inc b/sites/all/modules/contrib/admin/redirect/redirect.drush.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/redirect/redirect.generate.inc b/sites/all/modules/contrib/admin/redirect/redirect.generate.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/redirect/redirect.info b/sites/all/modules/contrib/admin/redirect/redirect.info
old mode 100755
new mode 100644
index b87b4e8f..b04e0a38
--- a/sites/all/modules/contrib/admin/redirect/redirect.info
+++ b/sites/all/modules/contrib/admin/redirect/redirect.info
@@ -1,9 +1,7 @@
name = Redirect
description = Allows users to redirect from old URLs to new URLs.
core = 7.x
-files[] = redirect.module
-files[] = redirect.admin.inc
-files[] = redirect.install
+files[] = redirect.controller.inc
files[] = redirect.test
files[] = views/redirect.views.inc
;files[] = views/redirect_handler_field_redirect_type.inc
@@ -15,9 +13,9 @@ files[] = views/redirect_handler_field_redirect_link_edit.inc
files[] = views/redirect_handler_field_redirect_link_delete.inc
configure = admin/config/search/redirect/settings
-; Information added by drupal.org packaging script on 2012-09-18
-version = "7.x-1.0-rc1"
+; Information added by Drupal.org packaging script on 2015-07-08
+version = "7.x-1.0-rc3"
core = "7.x"
project = "redirect"
-datestamp = "1347989995"
+datestamp = "1436393342"
diff --git a/sites/all/modules/contrib/admin/redirect/redirect.install b/sites/all/modules/contrib/admin/redirect/redirect.install
old mode 100755
new mode 100644
index fa67aaa5..a8fea019
--- a/sites/all/modules/contrib/admin/redirect/redirect.install
+++ b/sites/all/modules/contrib/admin/redirect/redirect.install
@@ -86,7 +86,14 @@ function redirect_schema() {
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
- 'description' => 'The timestamp of when the redirect was last accessed.'
+ 'description' => 'The timestamp of when the redirect was last accessed.',
+ ),
+ 'status' => array(
+ 'type' => 'int',
+ 'size' => 'small',
+ 'not null' => TRUE,
+ 'default' => 1,
+ 'description' => 'Boolean indicating whether the redirect is enabled (visible to non-administrators).',
),
),
'primary key' => array('rid'),
@@ -95,7 +102,11 @@ function redirect_schema() {
),
'indexes' => array(
'expires' => array('type', 'access'),
- 'source_language' => array('source', 'language'),
+ 'status_source_language' => array(
+ 'status',
+ 'source',
+ 'language',
+ ),
),
);
@@ -263,6 +274,58 @@ function redirect_update_7000(&$sandbox) {
}
}
+/**
+ * Rebuild the registry and clear the entity info cache.
+ */
+function redirect_update_7100() {
+ if (!class_exists('RedirectController')) {
+ registry_rebuild();
+ entity_info_cache_clear();
+ }
+}
+
+/**
+ * Add status field.
+ */
+function redirect_update_7101() {
+ db_add_field('redirect', 'status', array(
+ 'type' => 'int',
+ 'size' => 'small',
+ 'not null' => TRUE,
+ 'default' => 1,
+ 'description' => 'Boolean indicating whether the redirect is enabled (visible to non-administrators).',
+ ));
+ db_drop_index('redirect', 'source_language');
+ db_add_index('redirect', 'status_source_language', array(
+ 'status',
+ 'source',
+ 'language',
+ ));
+}
+
+/**
+ * Disable redirects that could cause infinite loops.
+ */
+function redirect_update_7102() {
+ $rids = db_query("SELECT r.rid FROM {redirect} r INNER JOIN {url_alias} u ON r.source = u.alias AND r.redirect = u.source AND r.language = u.language")->fetchCol();
+ if ($rids) {
+ // Disable redirects
+ $count = db_update('redirect')
+ ->fields(array('status' => 0))
+ ->condition('rid', $rids)
+ ->execute();
+
+ $disabled_redirects_message = format_plural($count,
+ '1 circular redirect causing infinite loop was disabled.',
+ '@count circular redirects causing infinite loop were disabled.');
+
+ return $disabled_redirects_message;
+ }
+ else {
+ return t('No circular redirects were found that could cause infinite loops.');
+ }
+}
+
/**
* Migrate a path redirect redirect to a redirect redirect.
*/
@@ -315,6 +378,7 @@ function _redirect_migrate_path_redirect_redirect($old_redirect) {
'redirect_options' => serialize($redirect->redirect_options),
'language' => $redirect->language,
'status_code' => $redirect->status_code,
+ 'status' => 1,
'count' => 0,
'access' => $old_redirect->last_used,
))
diff --git a/sites/all/modules/contrib/admin/redirect/redirect.js b/sites/all/modules/contrib/admin/redirect/redirect.js
old mode 100755
new mode 100644
index c59785d6..fedbaede
--- a/sites/all/modules/contrib/admin/redirect/redirect.js
+++ b/sites/all/modules/contrib/admin/redirect/redirect.js
@@ -4,12 +4,23 @@
Drupal.behaviors.redirectFieldsetSummaries = {
attach: function (context) {
$('fieldset.redirect-list', context).drupalSetSummary(function (context) {
- if ($('table.redirect-list tbody td.empty', context).size()) {
+ if ($('table.redirect-list tbody td.empty', context).length) {
return Drupal.t('No redirects');
}
else {
- var redirects = $('table.redirect-list tbody tr').size();
- return Drupal.formatPlural(redirects, '1 redirect', '@count redirects');
+ var enabled_redirects = $('table.redirect-list tbody tr.redirect-enabled', context).length;
+ var disabled_redirects = $('table.redirect-list tbody tr.redirect-disabled', context).length;
+ var text = '';
+ if (enabled_redirects > 0) {
+ var text = Drupal.formatPlural(enabled_redirects, '1 enabled redirect', '@count enabled redirects');
+ }
+ if (disabled_redirects > 0) {
+ if (text.length > 0) {
+ text = text + ' ';
+ }
+ text = text + Drupal.formatPlural(disabled_redirects, '1 disabled redirect', '@count disabled redirects');
+ }
+ return text;
}
});
}
diff --git a/sites/all/modules/contrib/admin/redirect/redirect.module b/sites/all/modules/contrib/admin/redirect/redirect.module
old mode 100755
new mode 100644
index 9f7a256f..993eeed0
--- a/sites/all/modules/contrib/admin/redirect/redirect.module
+++ b/sites/all/modules/contrib/admin/redirect/redirect.module
@@ -46,24 +46,6 @@ function redirect_entity_info() {
return $info;
}
-/**
- * Controller class for redirects.
- *
- * This extends the DrupalDefaultEntityController class, adding required
- * special handling for redirect objects.
- */
-class RedirectController extends DrupalDefaultEntityController {
-
- protected function attachLoad(&$redirects, $revision_id = FALSE) {
- // Unserialize the URL option fields.
- foreach ($redirects as $key => $redirect) {
- $redirects[$key]->source_options = unserialize($redirect->source_options);
- $redirects[$key]->redirect_options = unserialize($redirect->redirect_options);
- }
- parent::attachLoad($redirects, $revision_id);
- }
-}
-
/**
* Implements hook_hook_info().
*/
@@ -245,11 +227,12 @@ function redirect_url_inbound_alter(&$path, $original_path, $path_language) {
}
// Redirect to canonical URLs.
- if ($path && variable_get('redirect_canonical', 1)) {
- $alias = drupal_get_path_alias($path, $path_language);
- if ($alias != $path && $alias != $original_path) {
+ // Commented out per https://www.drupal.org/node/2048137.
+ //if ($path && variable_get('redirect_canonical', 1)) {
+ //$alias = drupal_get_path_alias($path, $path_language);
+ //if ($alias != $path && $alias != $original_path) {
//return redirect_redirect(array('redirect' => $alias, 'type' => 'global'));
- }
+ //}
// Redirect from default entity paths to the proper entity path.
//if ($path_entity = redirect_load_entity_from_path($path)) {
@@ -259,7 +242,7 @@ function redirect_url_inbound_alter(&$path, $original_path, $path_language) {
// }
// }
//}
- }
+ //}
}
/**
@@ -394,6 +377,8 @@ function redirect_path_update(array $path) {
}
if (!empty($path['original']['pid']) && $path['original']['pid'] == $path['pid'] && $path['original']['alias'] != $path['alias']) {
+ // Disable all redirects having the same source as this alias.
+ redirect_disable_by_path($path['alias'], $path['language']);
$redirect = new stdClass();
redirect_object_prepare($redirect);
$redirect->source = $path['original']['alias'];
@@ -401,9 +386,25 @@ function redirect_path_update(array $path) {
$redirect->language = $path['original']['language'];
// Check if the redirect exists before saving.
$hash = redirect_hash($redirect);
- if (!redirect_load_by_hash($hash)) {
+ $existing = redirect_load_by_hash($hash);
+ if (!$existing) {
redirect_save($redirect);
}
+ // If the existing redirect is disabled, re-enable it.
+ elseif (isset($existing->status) && $existing->status == 0) {
+ $existing->status = 1;
+ redirect_save($existing);
+ }
+ }
+}
+
+/**
+ * Implements hook_path_insert().
+ */
+function redirect_path_insert(array $path) {
+ if (!empty($path['alias'])) {
+ // Disable all redirects having the same source as this alias.
+ redirect_disable_by_path($path['alias'], $path['language']);
}
}
@@ -542,24 +543,26 @@ function redirect_load_by_hash($hash, $reset = FALSE) {
}
/**
- * Load multiple URL redirects from the database by {redirect}.source.
+ * Fetches multiple URL redirect IDs from the database by {redirect}.source.
*
* @param $source
* The source of the URL redirect.
+ * @param $language
+ * Language of the source URL.
+ * @param $enabled_only
+ * Boolean that indicates whether to only load enabled redirects.
*
- * @return
- * An array of URL redirect objects indexed by redirect IDs.
- *
- * @see redirect_load_multiple()
- * @see _redirect_uasort()
- * @see redirect_compare_array_recursive()
- *
- * @ingroup redirect_api
+ * @return array
+ * An indexed array of IDs, or an empty array if there is no result set.
*/
-function redirect_load_by_source($source, $language = LANGUAGE_NONE, array $query = array()) {
+function redirect_fetch_rids_by_path($source, $language, $enabled_only = FALSE) {
// Run a case-insensitive query for matching RIDs first.
$rid_query = db_select('redirect');
$rid_query->addField('redirect', 'rid');
+ // Prevent errors if redirect_update_7101() has not yet been run.
+ if ($enabled_only && db_field_exists('redirect', 'status')) {
+ $rid_query->condition('status', 1);
+ }
if ($source != variable_get('site_frontpage', 'node')) {
$rid_query->condition('source', db_like($source), 'LIKE');
}
@@ -571,7 +574,33 @@ function redirect_load_by_source($source, $language = LANGUAGE_NONE, array $quer
}
$rid_query->condition('language', array($language, LANGUAGE_NONE));
$rids = $rid_query->execute()->fetchCol();
+ return $rids;
+}
+
+/**
+ * Load multiple URL redirects from the database by {redirect}.source.
+ *
+ * @param $source
+ * The source of the URL redirect.
+ * @param $language
+ * Language of the source URL.
+ * @param $query
+ * Array of URL query parameters.
+ * @param $enabled_only
+ * Boolean that indicates whether to only load enabled redirects.
+ *
+ * @return
+ * The first matched URL redirect object, or FALSE if there aren't any.
+ *
+ * @see redirect_load_multiple()
+ * @see _redirect_uasort()
+ * @see redirect_compare_array_recursive()
+ *
+ * @ingroup redirect_api
+ */
+function redirect_load_by_source($source, $language = LANGUAGE_NONE, array $query = array(), $enabled_only = TRUE) {
+ $rids = redirect_fetch_rids_by_path($source, $language, $enabled_only);
if ($rids && $redirects = redirect_load_multiple($rids)) {
// Narrow down the list of candidates.
foreach ($redirects as $rid => $redirect) {
@@ -700,11 +729,11 @@ function redirect_validate($redirect, $form, &$form_state) {
redirect_hash($redirect);
if ($existing = redirect_load_by_hash($redirect->hash)) {
if ($redirect->rid != $existing->rid) {
- form_set_error('source', t('The source path %source is already being redirected. Do you want to edit the existing redirect?', array('%source' => redirect_url($redirect->source, $redirect->source_options), '@edit-page' => url('admin/config/search/redirect/edit/'. $existing->rid))));
+ form_set_error('source', t('A redirect already exists for the source path %source. Do you want to edit the existing redirect?', array('%source' => redirect_url($redirect->source, $redirect->source_options), '@edit-page' => url('admin/config/search/redirect/edit/'. $existing->rid))));
}
}
- // Allow other modules to validate the SSH public key.
+ // Allow other modules to validate the redirect.
foreach (module_implements('redirect_validate') as $module) {
$function = $module . '_redirect_validate';
$function($redirect, $form, $form_state);
@@ -723,6 +752,7 @@ function redirect_object_prepare($redirect, $defaults = array()) {
'count' => 0,
'access' => 0,
'hash' => '',
+ 'status' => 1,
);
foreach ($defaults as $key => $default) {
@@ -865,6 +895,28 @@ function redirect_delete_by_path($path) {
}
}
+/**
+ * Disable any redirects associated with a path.
+ *
+ * Given a source like 'node/1' this function will delete any redirects that
+ * have that specific source.
+ *
+ * @param $path
+ * An string with an internal Drupal path.
+ *
+ * @param @langauge
+ * The langcode of the path.
+ *
+ * @ingroup redirect_api
+ */
+function redirect_disable_by_path($path, $language) {
+ $rids = redirect_fetch_rids_by_path($path, $language, FALSE);
+
+ if ($rids) {
+ return redirect_change_status_multiple($rids, 0);
+ }
+}
+
/**
* Delete an entity URL alias and any of its sub-paths.
*
@@ -879,7 +931,8 @@ function redirect_delete_by_path($path) {
* @ingroup redirect_api
*/
function redirect_delete_by_entity_path($entity_type, $entity) {
- if ($uri = entity_uri($entity_type, $entity)) {
+ $uri = entity_uri($entity_type, $entity);
+ if (!empty($uri['path'])) {
redirect_delete_by_path($uri['path']);
}
@@ -893,6 +946,48 @@ function redirect_delete_by_entity_path($entity_type, $entity) {
//}
}
+/**
+ * Change the status of multiple URL redirects.
+ *
+ * @param array $rids
+ * An array of redirect IDs to disable.
+ * @param int|string $status
+ * The status to set the redirect to: either disabled (0) or enabled (1).
+ *
+ * @ingroup redirect_api
+ */
+function redirect_change_status_multiple(array $rids, $status) {
+ if ($status !== 0 && $status !== 1 && $status !== '0' && $status !== '1') {
+ watchdog('Cannot change redirect status to %status', array('%status' => $status));
+ drupal_set_message(t('Cannot change redirect status to %status', array('%status' => $status)));
+ return;
+ }
+ if (!empty($rids)) {
+ $redirects = redirect_load_multiple($rids, array(), TRUE);
+
+ foreach ($redirects as $rid => $redirect) {
+ if (isset($redirect->status) && $redirect->status == $status) {
+ // We no-op if the redirect is not actually changing status.
+ // So if a disabled redirect is disabled, neither redirect_save() is
+ // triggered, nor do we log any message.
+ continue;
+ }
+
+ $redirect->status = $status;
+ redirect_save($redirect);
+
+ if ($status) {
+ $redirect_link = l($redirect->redirect, $redirect->redirect) . '=> ' . l($redirect->source, $redirect->source);
+ watchdog('redirect', 'Enabled redirect: !redirect_source_link', array('!redirect_link' => $redirect_link));
+ }
+ else {
+ $redirect_link = l($redirect->redirect, $redirect->redirect) . '=> ' . l($redirect->source, $redirect->source);
+ watchdog('redirect', 'Disabled redirect: !redirect_source_link', array('!redirect_link' => $redirect_link));
+ }
+ }
+ }
+}
+
/**
* Delete multiple URL redirects.
*
@@ -947,10 +1042,15 @@ function redirect_purge_inactive_redirects(array $types = array('redirect'), $in
$interval = variable_get('redirect_purge_inactive', 0);
}
- if (!$interval || !variable_get('redirect_page_cache', 0) || !variable_get('page_cache_invoke_hooks', TRUE)) {
+ if (!$interval) {
+ return FALSE;
+ }
+
+ if (variable_get('redirect_page_cache', 0) && !variable_get('page_cache_invoke_hooks', TRUE)) {
// If serving redirects from the page cache is enabled and hooks are not
// executed during page caching, then we cannot track when a redirect is
// used. Therefore, we cannot remove unused redirects.
+ watchdog('redirect', 'Due to existing settings, could not track when a redirect is used, so could not remove unused redirects.');
return FALSE;
}
@@ -979,17 +1079,6 @@ function redirect_purge_inactive_redirects(array $types = array('redirect'), $in
* @ingroup redirect_api
*/
function redirect_redirect($redirect = NULL) {
- // First check if we're in an infinite loop.
- $session_id = session_id();
- if (flood_is_allowed('redirection', 5, 15, $session_id ? $session_id : NULL)) {
- flood_register_event('redirection', 60, $session_id ? $session_id : NULL);
- }
- else {
- watchdog('redirect', 'Infinite loop stopped.');
- drupal_set_message('Oops, looks like this request tried to create an infinite loop. We do not allow such things here. We are a professional website!');
- return FALSE;
- }
-
if (!isset($redirect)) {
$redirect = new stdClass();
}
@@ -1017,6 +1106,10 @@ function redirect_redirect($redirect = NULL) {
// Continue if the redirect has not been disabled by hook_redirect_alter().
if (isset($redirect->redirect) && isset($redirect->callback) && $redirect->redirect !== FALSE && function_exists($redirect->callback)) {
+ // Prevent circular redirects.
+ if ($GLOBALS['base_root'] . request_uri() == url($redirect->redirect, array('absolute' => TRUE) + $redirect->redirect_options)) {
+ return FALSE;
+ }
// Perform the actual redirect.
$callback = $redirect->callback;
$callback($redirect);
@@ -1150,7 +1243,7 @@ function redirect_can_redirect() {
$path = current_path();
$can_redirect = TRUE;
- if ($_SERVER['SCRIPT_NAME'] != $GLOBALS['base_path'] . 'index.php') {
+ if (!preg_match('/index\.php$/', $_SERVER['SCRIPT_NAME'])) {
// Do not redirect if the root script is not /index.php.
$can_redirect = FALSE;
}
@@ -1162,7 +1255,7 @@ function redirect_can_redirect() {
// If this is a command line request (Drush, etc), skip processing.
$can_redirect = FALSE;
}
- elseif (variable_get('maintenance_mode', 0) || defined('MAINTENANCE_MODE')) {
+ elseif ((variable_get('maintenance_mode', 0) || defined('MAINTENANCE_MODE')) && !user_access('access site in maintenance mode')) {
// Do not redirect in offline or maintenance mode.
$can_redirect = FALSE;
}
@@ -1176,7 +1269,7 @@ function redirect_can_redirect() {
}
/**
- * Compare tha all values and associations in one array match another array.
+ * Compare that all values and associations in one array match another array.
*
* We cannot use array_diff_assoc() here because we need to be recursive.
*
@@ -1457,7 +1550,7 @@ function redirect_field_attach_form($entity_type, $entity, &$form, &$form_state,
}
$uri = entity_uri($entity_type, $entity);
- if (empty($uri)) {
+ if (empty($uri['path'])) {
// If the entity has no source path, then we cannot lookup the existing
// redirects.
return;
@@ -1467,7 +1560,6 @@ function redirect_field_attach_form($entity_type, $entity, &$form, &$form_state,
$form['redirect'] = array(
'#type' => 'fieldset',
'#title' => t('URL redirects'),
- '#description' => t('The following are a list of URL redirects that point to this @entitytype.', array('@entitytype' => drupal_strtolower($info['label']))),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#access' => user_access('administer redirects'),
@@ -1483,13 +1575,6 @@ function redirect_field_attach_form($entity_type, $entity, &$form, &$form_state,
}
}
- // We don't have to put our include in $form_state['build_info']['files']
- // since the build array will already be cached.
- module_load_include('inc', 'redirect', 'redirect.admin');
- $redirects = redirect_load_multiple(FALSE, array('redirect' => $uri['path']));
- $header = array('source', 'status_code', 'language', 'count', 'access', 'operations');
- $form['redirect'] += redirect_list_table($redirects, $header);
-
$redirect = array(
'redirect' => $uri['path'],
'redirect_options' => array_diff_key($uri['options'], array('entity_type' => '', 'entity' => '')),
@@ -1508,6 +1593,13 @@ function redirect_field_attach_form($entity_type, $entity, &$form, &$form_state,
'query' => array_filter($redirect) + drupal_get_destination(),
);
}
+
+ // We don't have to put our include in $form_state['build_info']['files']
+ // since the build array will already be cached.
+ module_load_include('inc', 'redirect', 'redirect.admin');
+ $redirects = redirect_load_multiple(FALSE, array('redirect' => $uri['path']));
+ $header = array('source', 'status', 'status_code', 'language', 'count', 'access', 'operations');
+ $form['redirect'] += redirect_list_table($redirects, $header);
}
/**
@@ -1516,8 +1608,8 @@ function redirect_field_attach_form($entity_type, $entity, &$form, &$form_state,
function redirect_field_extra_fields() {
$entity_info = entity_get_info();
foreach (array_keys($entity_info) as $entity_type) {
- if ($entity_type == 'comment') {
- // The comment entity type supports URIs, but they're not real.
+ if (!redirect_entity_type_supports_redirects($entity_type)) {
+ // Redirect is explicitly disabled for this entity type.
continue;
}
foreach (array_keys($entity_info[$entity_type]['bundles']) as $bundle) {
@@ -1564,5 +1656,19 @@ function redirect_redirect_operations() {
'callback' => 'redirect_delete_multiple',
'confirm' => TRUE,
);
+ $operations['disable'] = array(
+ 'action' => t('Disable'),
+ 'action_past' => t('Disabled'),
+ 'callback' => 'redirect_change_status_multiple',
+ 'callback arguments' => array(0),
+ 'confirm' => TRUE,
+ );
+ $operations['enable'] = array(
+ 'action' => t('Enable'),
+ 'action_past' => t('Enabled'),
+ 'callback' => 'redirect_change_status_multiple',
+ 'callback arguments' => array(1),
+ 'confirm' => TRUE,
+ );
return $operations;
}
diff --git a/sites/all/modules/contrib/admin/redirect/redirect.test b/sites/all/modules/contrib/admin/redirect/redirect.test
old mode 100755
new mode 100644
index 1c237f83..33c6d23d
--- a/sites/all/modules/contrib/admin/redirect/redirect.test
+++ b/sites/all/modules/contrib/admin/redirect/redirect.test
@@ -229,16 +229,59 @@ class RedirectFunctionalTest extends RedirectTestHelper {
$node = $this->drupalCreateNode(array('type' => 'article', 'path' => array('alias' => 'first-alias')));
// Change the node's alias will create an automatic redirect from 'first-alias' to the node.
- $this->drupalPost("node/{$node->nid}/edit", array('path[alias]' => 'second-alias'), 'Save');
- //$redirect = redirect_load_by_source('first-alias');
- //$this->assertRedirect($redirect);
+ $this->drupalPost("node/{$node->nid}/edit", array('path[alias]' => 'second-alias'), t('Save'));
+ $this->drupalGet('first-alias');
+ $this->assertText($node->title);
- $this->drupalPost("node/{$node->nid}/edit", array('path[alias]' => 'first-alias'), 'Save');
- //$redirect = redirect_load_by_source('second-alias');
- //$this->assertRedirect($redirect);
+ $this->drupalPost("node/{$node->nid}/edit", array('path[alias]' => 'first-alias'), t('Save'));
+ $this->assertResponse(200, "Changing node's alias back to 'first-alias' does not break page load with a circular redirect.");
+ $this->assertNoText('Infinite redirect loop prevented.');
+ $this->drupalGet('second-alias');
+ $this->assertText($node->title);
- $this->drupalPost("node/{$node->nid}/edit", array('path[alias]' => 'second-alias'), 'Save');
- //$redirect = redirect_load_by_source('first-alias');
- //$this->assertRedirect($redirect);
+ $this->drupalPost("node/{$node->nid}/edit", array('path[alias]' => 'second-alias'), t('Save'));
+ $this->assertResponse(200, "Changing node's alias back to 'second-alias' does not break page load with a circular redirect.");
+ $this->assertNoText('Infinite redirect loop prevented.');
+ // Check that first-alias redirect has been re-enabled.
+ $this->drupalGet('first-alias');
+ $this->assertText($node->title);
+ }
+
+ function testPathAddOverwriteRedirects() {
+ // Create an initial article node with a path alias.
+ $first_node = $this->drupalCreateNode(array('type' => 'article', 'path' => array('alias' => 'first-alias')));
+ // Change the node's alias will create an automatic redirect from 'first-alias' to the node.
+ $this->drupalPost("node/{$first_node->nid}/edit", array('path[alias]' => 'second-alias'), t('Save'));
+
+ // Now create a second article node with the same alias as the redirect
+ // created above.
+ $second_node = $this->drupalCreateNode(array('type' => 'article', 'path' => array('alias' => 'first-alias')));
+
+ // Visit the path 'first-alias' which should be an alias for $second_node.
+ $this->drupalGet('first-alias');
+ $this->assertNoText($first_node->title, 'Adding a new path alias that matches an existing redirect disables the redirect.');
+ $this->assertText($second_node->title, 'Adding a new path alias that matches an existing redirect disables the redirect.');
+ }
+
+ function testDisableEnableRedirect() {
+ // Add a new redirect.
+ $redirect = $this->addRedirect('redirect', 'node');
+ // Check that it is enabled.
+ $this->assertEqual($redirect->status, 1);
+
+ // Disable the redirect.
+ $edit = array('status' => FALSE);
+ $this->drupalPost("admin/config/search/redirect/edit/{$redirect->rid}", $edit, t('Save'));
+ $redirect = redirect_load($redirect->rid);
+ // Check that it has been disabled.
+ $this->assertEqual($redirect->status, 0);
+ $this->drupalGet("admin/config/search/redirect/edit/{$redirect->rid}");
+ $this->assertNoFieldChecked('edit-status', 'status is unchecked');
+ $this->assertNoRedirect($redirect);
+
+ // Re-enable the redirect.
+ $edit = array('status' => 1);
+ $this->drupalPost("admin/config/search/redirect/edit/{$redirect->rid}", $edit, t('Save'));
+ $this->assertRedirect($redirect);
}
}
diff --git a/sites/all/modules/contrib/admin/redirect/views/redirect.views.inc b/sites/all/modules/contrib/admin/redirect/views/redirect.views.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/redirect/views/redirect.views_default.inc b/sites/all/modules/contrib/admin/redirect/views/redirect.views_default.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/redirect/views/redirect_handler_field_redirect_link_delete.inc b/sites/all/modules/contrib/admin/redirect/views/redirect_handler_field_redirect_link_delete.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/redirect/views/redirect_handler_field_redirect_link_edit.inc b/sites/all/modules/contrib/admin/redirect/views/redirect_handler_field_redirect_link_edit.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/redirect/views/redirect_handler_field_redirect_operations.inc b/sites/all/modules/contrib/admin/redirect/views/redirect_handler_field_redirect_operations.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/redirect/views/redirect_handler_field_redirect_redirect.inc b/sites/all/modules/contrib/admin/redirect/views/redirect_handler_field_redirect_redirect.inc
old mode 100755
new mode 100644
index a5adb9eb..09930c80
--- a/sites/all/modules/contrib/admin/redirect/views/redirect_handler_field_redirect_redirect.inc
+++ b/sites/all/modules/contrib/admin/redirect/views/redirect_handler_field_redirect_redirect.inc
@@ -45,11 +45,6 @@ class redirect_handler_field_redirect_redirect extends views_handler_field {
);
}
- function query() {
- $this->ensure_my_table();
- $this->add_additional_fields();
- }
-
function render($values) {
$redirect = $values->{$this->aliases['redirect']};
$redirect_options = unserialize($values->{$this->aliases['redirect_options']});
diff --git a/sites/all/modules/contrib/admin/redirect/views/redirect_handler_field_redirect_source.inc b/sites/all/modules/contrib/admin/redirect/views/redirect_handler_field_redirect_source.inc
old mode 100755
new mode 100644
index 318f1bdb..b462d9a9
--- a/sites/all/modules/contrib/admin/redirect/views/redirect_handler_field_redirect_source.inc
+++ b/sites/all/modules/contrib/admin/redirect/views/redirect_handler_field_redirect_source.inc
@@ -45,11 +45,6 @@ class redirect_handler_field_redirect_source extends views_handler_field {
);
}
- function query() {
- $this->ensure_my_table();
- $this->add_additional_fields();
- }
-
function render($values) {
$source = $values->{$this->aliases['source']};
$source_options = unserialize($values->{$this->aliases['source_options']});
diff --git a/sites/all/modules/contrib/admin/redirect/views/redirect_handler_filter_redirect_type.inc b/sites/all/modules/contrib/admin/redirect/views/redirect_handler_filter_redirect_type.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/redirect/views/redirects.view b/sites/all/modules/contrib/admin/redirect/views/redirects.view
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/rules/includes/rules.core.inc b/sites/all/modules/contrib/admin/rules/includes/rules.core.inc
index 5dbc332d..559d1cff 100644
--- a/sites/all/modules/contrib/admin/rules/includes/rules.core.inc
+++ b/sites/all/modules/contrib/admin/rules/includes/rules.core.inc
@@ -1124,7 +1124,8 @@ abstract class RulesPlugin extends RulesExtendable {
elseif ($this->plugin == 'reaction rule') {
// Clear event sets cached for evaluation.
cache_clear_all('event_', 'cache_rules', TRUE);
- variable_del('rules_event_whitelist');
+ // Clear event whitelist for rebuild.
+ cache_clear_all('rules_event_whitelist', 'cache_rules', TRUE);
}
drupal_static_reset('rules_get_cache');
drupal_static_reset('rules_config_update_dirty_flag');
diff --git a/sites/all/modules/contrib/admin/rules/includes/rules.plugins.inc b/sites/all/modules/contrib/admin/rules/includes/rules.plugins.inc
index 85b72964..90b306d7 100644
--- a/sites/all/modules/contrib/admin/rules/includes/rules.plugins.inc
+++ b/sites/all/modules/contrib/admin/rules/includes/rules.plugins.inc
@@ -809,7 +809,7 @@ class RulesEventSet extends RulesRuleSet {
}
// Cache a whitelist of configured events so we can use it to speed up later
// calls. See rules_invoke_event().
- variable_set('rules_event_whitelist', array_flip(array_keys($sets)));
+ rules_set_cache('rules_event_whitelist', array_flip(array_keys($sets)));
}
protected function stateVariables($element = NULL) {
diff --git a/sites/all/modules/contrib/admin/rules/rules.info b/sites/all/modules/contrib/admin/rules/rules.info
index 407c5992..0a744d5f 100644
--- a/sites/all/modules/contrib/admin/rules/rules.info
+++ b/sites/all/modules/contrib/admin/rules/rules.info
@@ -22,9 +22,9 @@ files[] = ui/ui.plugins.inc
dependencies[] = entity_token
dependencies[] = entity
-; Information added by Drupal.org packaging script on 2015-01-08
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-03-16
+version = "7.x-2.9"
core = "7.x"
project = "rules"
-datestamp = "1420734780"
+datestamp = "1426527210"
diff --git a/sites/all/modules/contrib/admin/rules/rules.install b/sites/all/modules/contrib/admin/rules/rules.install
index d7401635..8485df3b 100644
--- a/sites/all/modules/contrib/admin/rules/rules.install
+++ b/sites/all/modules/contrib/admin/rules/rules.install
@@ -508,3 +508,21 @@ function rules_update_7213() {
}
}
}
+
+/**
+ * Switch out the rules_event_whitelist variable for a cache equivalent.
+ */
+function rules_update_7214() {
+ // Set new event_whitelist cache cid.
+ rules_set_cache('rules_event_whitelist', variable_get('rules_event_whitelist', array()));
+ // Delete old conf variable.
+ variable_del('rules_event_whitelist');
+ // Avoid any missing class errors.
+ registry_rebuild();
+ // Clear and rebuild Rules caches.
+ // See: rules_admin_settings_cache_rebuild_submit.
+ rules_clear_cache();
+ rules_get_cache();
+ _rules_rebuild_component_cache();
+ RulesEventSet::rebuildEventCache();
+}
diff --git a/sites/all/modules/contrib/admin/rules/rules.module b/sites/all/modules/contrib/admin/rules/rules.module
index 017bb5be..719852c4 100644
--- a/sites/all/modules/contrib/admin/rules/rules.module
+++ b/sites/all/modules/contrib/admin/rules/rules.module
@@ -8,10 +8,44 @@
// hook_init().
require_once dirname(__FILE__) . '/modules/events.inc';
+/**
+ * Implements hook_module_implements_alter().
+ */
+function rules_module_implements_alter(&$implementations, $hook) {
+ // Ensures the invocation of hook_menu_get_item_alter() triggers
+ // rules_menu_get_item_alter() first so the rules invocation is ready for all
+ // sub-sequent hook implementations.
+ if ($hook == 'menu_get_item_alter' && array_key_exists('rules', $implementations)) {
+ $group = $implementations['rules'];
+ unset($implementations['rules']);
+ $implementations = array_merge(array('rules' => $group), $implementations);
+ }
+}
+
+/**
+ * Implements hook_menu_get_item_alter().
+ */
+function rules_menu_get_item_alter() {
+ // Make sure that event invocation is enabled before menu items are loaded.
+ // But make sure later calls to menu_get_item() won't automatically re-enabled
+ // the rules invocation.
+ // Example: modules that implement hook_entity_ENTITY_TYPE_load() might want
+ // to invoke Rules events in that load hook, which is also invoked for menu
+ // item loading. Since this can happen even before hook_init() we need to make
+ // sure that firing Rules events is enabled at that point. A typical use case
+ // for this is Drupal Commerce with commerce_cart_commerce_order_load().
+ if (!drupal_static('rules_init', FALSE)) {
+ rules_event_invocation_enabled(TRUE);
+ }
+}
+
/**
* Implements hook_init().
*/
function rules_init() {
+ // See rules_menu_get_item_alter().
+ $rules_init = &drupal_static(__FUNCTION__, FALSE);
+ $rules_init = TRUE;
// Enable event invocation once hook_init() was invoked for Rules.
rules_event_invocation_enabled(TRUE);
rules_invoke_event('init');
@@ -352,7 +386,7 @@ function &rules_get_cache($cid = 'data') {
$cache[$cid] = FALSE;
_rules_rebuild_component_cache();
}
- elseif (strpos($cid, 'event_') === 0) {
+ elseif (strpos($cid, 'event_') === 0 || $cid == 'rules_event_whitelist') {
$cache[$cid] = FALSE;
RulesEventSet::rebuildEventCache();
}
@@ -447,7 +481,6 @@ function rules_flush_caches() {
*/
function rules_clear_cache() {
cache_clear_all('*', 'cache_rules', TRUE);
- variable_del('rules_event_whitelist');
drupal_static_reset('rules_get_cache');
drupal_static_reset('rules_fetch_data');
drupal_static_reset('rules_config_update_dirty_flag');
@@ -984,17 +1017,16 @@ function rules_invoke_all() {
* @see rules_invoke_event_by_args()
*/
function rules_invoke_event() {
- global $conf;
-
$args = func_get_args();
$event_name = $args[0];
unset($args[0]);
// We maintain a whitelist of configured events to reduces the number of cache
- // reads. We access it directly via the global $conf as this is fast without
- // having to introduce another static cache. Then, if the whitelist is unset,
- // we ignore it so cache rebuilding is triggered.
- if (rules_event_invocation_enabled() && (!isset($conf['rules_event_whitelist']) || isset($conf['rules_event_whitelist'][$event_name])) && $event = rules_get_cache('event_' . $event_name)) {
- $event->executeByArgs($args);
+ // reads. If the whitelist is empty we proceed and it is rebuilt.
+ if (rules_event_invocation_enabled()) {
+ $whitelist = rules_get_cache('rules_event_whitelist');
+ if ((empty($whitelist) || isset($whitelist[$event_name])) && $event = rules_get_cache('event_' . $event_name)) {
+ $event->executeByArgs($args);
+ }
}
}
@@ -1016,14 +1048,13 @@ function rules_invoke_event() {
* @see rules_invoke_event()
*/
function rules_invoke_event_by_args($event_name, $args = array()) {
- global $conf;
-
// We maintain a whitelist of configured events to reduces the number of cache
- // reads. We access it directly via the global $conf as this is fast without
- // having to introduce another static cache. Then, if the whitelist is unset,
- // we ignore it so cache rebuilding is triggered.
- if (rules_event_invocation_enabled() && (!isset($conf['rules_event_whitelist']) || isset($conf['rules_event_whitelist'][$event_name])) && $event = rules_get_cache('event_' . $event_name)) {
- $event->executeByArgs($args);
+ // reads. If the whitelist is empty we proceed and it is rebuilt.
+ if (rules_event_invocation_enabled()) {
+ $whitelist = rules_get_cache('rules_event_whitelist');
+ if ((empty($whitelist) || isset($whitelist[$event_name])) && $event = rules_get_cache('event_' . $event_name)) {
+ $event->executeByArgs($args);
+ }
}
}
diff --git a/sites/all/modules/contrib/admin/rules/rules_admin/rules_admin.info b/sites/all/modules/contrib/admin/rules/rules_admin/rules_admin.info
index 29c8bced..350c0e3a 100644
--- a/sites/all/modules/contrib/admin/rules/rules_admin/rules_admin.info
+++ b/sites/all/modules/contrib/admin/rules/rules_admin/rules_admin.info
@@ -6,9 +6,9 @@ files[] = rules_admin.module
files[] = rules_admin.inc
dependencies[] = rules
-; Information added by Drupal.org packaging script on 2015-01-08
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-03-16
+version = "7.x-2.9"
core = "7.x"
project = "rules"
-datestamp = "1420734780"
+datestamp = "1426527210"
diff --git a/sites/all/modules/contrib/admin/rules/rules_i18n/rules_i18n.info b/sites/all/modules/contrib/admin/rules/rules_i18n/rules_i18n.info
index 35548248..297650e7 100644
--- a/sites/all/modules/contrib/admin/rules/rules_i18n/rules_i18n.info
+++ b/sites/all/modules/contrib/admin/rules/rules_i18n/rules_i18n.info
@@ -7,9 +7,9 @@ core = 7.x
files[] = rules_i18n.i18n.inc
files[] = rules_i18n.rules.inc
files[] = rules_i18n.test
-; Information added by Drupal.org packaging script on 2015-01-08
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-03-16
+version = "7.x-2.9"
core = "7.x"
project = "rules"
-datestamp = "1420734780"
+datestamp = "1426527210"
diff --git a/sites/all/modules/contrib/admin/rules/rules_scheduler/rules_scheduler.info b/sites/all/modules/contrib/admin/rules/rules_scheduler/rules_scheduler.info
index e972f012..accdf0bc 100644
--- a/sites/all/modules/contrib/admin/rules/rules_scheduler/rules_scheduler.info
+++ b/sites/all/modules/contrib/admin/rules/rules_scheduler/rules_scheduler.info
@@ -13,9 +13,9 @@ files[] = includes/rules_scheduler.views_default.inc
files[] = includes/rules_scheduler.views.inc
files[] = includes/rules_scheduler_views_filter.inc
-; Information added by Drupal.org packaging script on 2015-01-08
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-03-16
+version = "7.x-2.9"
core = "7.x"
project = "rules"
-datestamp = "1420734780"
+datestamp = "1426527210"
diff --git a/sites/all/modules/contrib/admin/rules/rules_scheduler/tests/rules_scheduler_test.info b/sites/all/modules/contrib/admin/rules/rules_scheduler/tests/rules_scheduler_test.info
index c6a4e8e3..3ce5f836 100644
--- a/sites/all/modules/contrib/admin/rules/rules_scheduler/tests/rules_scheduler_test.info
+++ b/sites/all/modules/contrib/admin/rules/rules_scheduler/tests/rules_scheduler_test.info
@@ -5,9 +5,9 @@ core = 7.x
files[] = rules_scheduler_test.inc
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-01-08
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-03-16
+version = "7.x-2.9"
core = "7.x"
project = "rules"
-datestamp = "1420734780"
+datestamp = "1426527210"
diff --git a/sites/all/modules/contrib/admin/rules/tests/rules.test b/sites/all/modules/contrib/admin/rules/tests/rules.test
index 20f1c9d6..3b034e8e 100644
--- a/sites/all/modules/contrib/admin/rules/tests/rules.test
+++ b/sites/all/modules/contrib/admin/rules/tests/rules.test
@@ -2099,3 +2099,50 @@ class RulesEventDispatcherTestCase extends DrupalWebTestCase {
}
}
}
+
+/**
+ * Test early bootstrap Rules invocation.
+ */
+class RulesInvocationEnabledTestCase extends DrupalWebTestCase {
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getInfo() {
+ return array(
+ 'name' => 'Rules invocation enabled',
+ 'description' => 'Tests that Rules events are enabled during menu item loads.',
+ 'group' => 'Rules',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setUp() {
+ parent::setUp('dblog', 'rules', 'rules_test', 'rules_test_invocation');
+ }
+
+ /**
+ * Tests that a Rules event is triggered on node menu item loading.
+ *
+ * @see rules_test_invocation_node_load()
+ */
+ public function testInvocationOnNodeMenuLoading() {
+ // Create a test node.
+ $node = $this->drupalCreateNode(array('title' => 'Test'));
+ // Enable Rules logging on the INFO level so that entries are written to
+ // dblog.
+ variable_set('rules_log_errors', RulesLog::INFO);
+ // Create an empty rule that will fire in our node load hook.
+ $rule = rules_reaction_rule();
+ $rule->event('rules_test_event');
+ $rule->save('test_rule');
+
+ // Visit the node page which should trigger the load hook.
+ $this->drupalGet('node/' . $node->nid);
+ $result = db_query("SELECT * FROM {watchdog} WHERE type = 'rules' AND message = 'Reacting on event %label.'")->fetch();
+ $this->assertFalse(empty($result), 'Rules event was triggered and logged.');
+ }
+
+}
diff --git a/sites/all/modules/contrib/admin/rules/tests/rules_test.info b/sites/all/modules/contrib/admin/rules/tests/rules_test.info
index 011df760..b06516c1 100644
--- a/sites/all/modules/contrib/admin/rules/tests/rules_test.info
+++ b/sites/all/modules/contrib/admin/rules/tests/rules_test.info
@@ -6,9 +6,9 @@ files[] = rules_test.rules.inc
files[] = rules_test.rules_defaults.inc
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-01-08
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-03-16
+version = "7.x-2.9"
core = "7.x"
project = "rules"
-datestamp = "1420734780"
+datestamp = "1426527210"
diff --git a/sites/all/modules/contrib/admin/rules/tests/rules_test_invocation.info b/sites/all/modules/contrib/admin/rules/tests/rules_test_invocation.info
new file mode 100644
index 00000000..51aea33e
--- /dev/null
+++ b/sites/all/modules/contrib/admin/rules/tests/rules_test_invocation.info
@@ -0,0 +1,12 @@
+name = "Rules Test invocation"
+description = "Helper module to test Rules invocations."
+package = Testing
+core = 7.x
+hidden = TRUE
+
+; Information added by Drupal.org packaging script on 2015-03-16
+version = "7.x-2.9"
+core = "7.x"
+project = "rules"
+datestamp = "1426527210"
+
diff --git a/sites/all/modules/contrib/admin/rules/tests/rules_test_invocation.module b/sites/all/modules/contrib/admin/rules/tests/rules_test_invocation.module
new file mode 100644
index 00000000..5664c5ea
--- /dev/null
+++ b/sites/all/modules/contrib/admin/rules/tests/rules_test_invocation.module
@@ -0,0 +1,13 @@
+ t('A test token with colons in the name'),
+ 'description' => NULL,
+ );
+
+ return $info;
+}
diff --git a/sites/all/modules/contrib/admin/token/token.css b/sites/all/modules/contrib/admin/token/token.css
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/token/token.drush.inc b/sites/all/modules/contrib/admin/token/token.drush.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/token/token.info b/sites/all/modules/contrib/admin/token/token.info
old mode 100755
new mode 100644
index 43fced19..a9efec27
--- a/sites/all/modules/contrib/admin/token/token.info
+++ b/sites/all/modules/contrib/admin/token/token.info
@@ -3,9 +3,9 @@ description = Provides a user interface for the Token API and some missing core
core = 7.x
files[] = token.test
-; Information added by drupal.org packaging script on 2013-02-24
-version = "7.x-1.5"
+; Information added by Drupal.org packaging script on 2015-02-28
+version = "7.x-1.6"
core = "7.x"
project = "token"
-datestamp = "1361665026"
+datestamp = "1425149060"
diff --git a/sites/all/modules/contrib/admin/token/token.install b/sites/all/modules/contrib/admin/token/token.install
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/token/token.js b/sites/all/modules/contrib/admin/token/token.js
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/admin/token/token.module b/sites/all/modules/contrib/admin/token/token.module
old mode 100755
new mode 100644
index 88bcc609..269f3765
--- a/sites/all/modules/contrib/admin/token/token.module
+++ b/sites/all/modules/contrib/admin/token/token.module
@@ -180,7 +180,7 @@ function token_theme() {
'text' => NULL,
'options' => array(),
'dialog' => TRUE,
- ),
+ ) + $info['token_tree']['variables'],
'file' => 'token.pages.inc',
);
@@ -273,8 +273,8 @@ function token_form_block_admin_configure_alter(&$form, $form_state) {
* Implements hook_widget_form_alter().
*/
function token_field_widget_form_alter(&$element, &$form_state, $context) {
- if (!empty($element['#description']) && is_string($element['#description'])) {
- $element['#description'] = filter_xss_admin(token_replace($element['#description']));
+ if (!empty($element['#description']) && !empty($context['instance']['description'])) {
+ $element['#description'] = filter_xss_admin(token_replace($context['instance']['description']));
}
}
@@ -412,12 +412,18 @@ function token_get_entity_mapping($value_type = 'token', $value = NULL, $fallbac
*/
function token_entity_info_alter(&$info) {
foreach (array_keys($info) as $entity_type) {
- // Add a token view mode if it does not already exist.
- if (!empty($info[$entity_type]['view modes']) && !isset($info[$entity_type]['view modes']['token'])) {
- $info[$entity_type]['view modes']['token'] = array(
- 'label' => t('Tokens'),
- 'custom settings' => FALSE,
- );
+ // Add a token view mode if it does not already exist. Only work with
+ // fieldable entities.
+ if (!empty($info[$entity_type]['fieldable'])) {
+ if (!isset($info[$entity_type])) {
+ $info[$entity_type]['view modes'] = array();
+ }
+ if (!isset($info[$entity_type]['view modes']['token'])) {
+ $info[$entity_type]['view modes']['token'] = array(
+ 'label' => t('Tokens'),
+ 'custom settings' => FALSE,
+ );
+ }
}
if (!empty($info[$entity_type]['token type'])) {
@@ -647,6 +653,10 @@ function token_get_invalid_tokens($type, $tokens) {
$invalid_tokens = array();
foreach ($tokens as $token => $full_token) {
+ if (isset($token_info['tokens'][$type][$token])) {
+ continue;
+ }
+
// Split token up if it has chains.
$parts = explode(':', $token, 2);
diff --git a/sites/all/modules/contrib/admin/token/token.pages.inc b/sites/all/modules/contrib/admin/token/token.pages.inc
old mode 100755
new mode 100644
index 2341a9f9..f7615475
--- a/sites/all/modules/contrib/admin/token/token.pages.inc
+++ b/sites/all/modules/contrib/admin/token/token.pages.inc
@@ -19,7 +19,12 @@ function theme_token_tree_link($variables) {
}
$info = token_theme();
- $variables['options']['query']['options'] = array_intersect_key($variables, $info['token_tree']['variables']);
+ $tree_variables = array_intersect_key($variables, $info['token_tree']['variables']);
+ $tree_variables = drupal_array_diff_assoc_recursive($tree_variables, $info['token_tree']['variables']);
+ if (!isset($variables['options']['query']['options'])) {
+ $variables['options']['query']['options'] = array();
+ }
+ $variables['options']['query']['options'] += $tree_variables;
// We should never pass the dialog option to theme_token_tree(). It is only
// used for this function.
diff --git a/sites/all/modules/contrib/admin/token/token.test b/sites/all/modules/contrib/admin/token/token.test
old mode 100755
new mode 100644
index 59fa6457..cd09e15b
--- a/sites/all/modules/contrib/admin/token/token.test
+++ b/sites/all/modules/contrib/admin/token/token.test
@@ -137,6 +137,7 @@ class TokenUnitTestCase extends TokenTestHelper {
'[node:created:short]',
'[node:created:custom:invalid]',
'[node:created:custom:mm-YYYY]',
+ '[node:colons:in:name]',
'[site:name]',
'[site:slogan]',
'[current-date:short]',
@@ -147,6 +148,7 @@ class TokenUnitTestCase extends TokenTestHelper {
'[node:title:invalid]',
'[node:created:invalid]',
'[node:created:short:invalid]',
+ '[node:colons:in:name:invalid]',
'[invalid:title]',
'[site:invalid]',
'[user:ip-address]',
@@ -166,6 +168,7 @@ class TokenUnitTestCase extends TokenTestHelper {
'[node:created:short]',
'[node:created:custom:invalid]',
'[node:created:custom:mm-YYYY]',
+ '[node:colons:in:name]',
'[site:name]',
'[site:slogan]',
'[user:uid]',
@@ -176,6 +179,7 @@ class TokenUnitTestCase extends TokenTestHelper {
'[node:title:invalid]',
'[node:created:invalid]',
'[node:created:short:invalid]',
+ '[node:colons:in:name:invalid]',
'[invalid:title]',
'[site:invalid]',
'[user:ip-address]',
diff --git a/sites/all/modules/contrib/admin/token/token.tokens.inc b/sites/all/modules/contrib/admin/token/token.tokens.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/content/pathauto/API.txt b/sites/all/modules/contrib/content/pathauto/API.txt
deleted file mode 100755
index e585cd48..00000000
--- a/sites/all/modules/contrib/content/pathauto/API.txt
+++ /dev/null
@@ -1,149 +0,0 @@
-This document explains how to provide "Pathauto integration" in a
-module. You need this if you would like to provide additional tokens
-or if your module has paths and you wish to have them automatically
-aliased. The simplest integration is just to provide tokens so we
-cover that first. More advanced integration requires an
-implementation of hook_pathauto to provide a settings form.
-
-It may be helpful to review some examples of integration from the
-pathauto_node.inc, pathauto_taxonomy.inc, and pathauto_user.inc files.
-
-
-==================
-1 - Providing additional tokens
-==================
-
-If all you want is to enable tokens for your module you will simply
-need to implement two functions:
-
- hook_token_values
- hook_token_list
-
-See the token.module and it's API.txt for more information about this
-process.
-
-If the token is intended to generate a path expected to contain slashes,
-the token name must end in 'path', 'path-raw' or 'alias'. This indicates to
-Pathauto that the slashes should not be removed from the replacement value.
-
-When an object is created (whether it is a node or a user or a
-taxonomy term) the data that Pathauto hands to the token_values in the
-$object is in a specific format. This is the format that most people
-write code to handle. However, during edits and bulk updates the data
-may be in a totally different format. So, if you are writing a
-hook_token_values implementation to add special tokens, be sure to
-test creation, edit, and bulk update cases to make sure your code will
-handle it.
-
-==================
-2 - Settings hook - To create aliases for your module
-==================
-You must implement hook_pathauto($op), where $op is always (at this
-time) 'settings'. Return an object (NOT an array) containing the
-following members, which will be used by pathauto to build a group
-of settings for your module and define the variables for saving your
-settings:
-
-module - The name of your module (e.g., 'node')
-groupheader - The translated label for the settings group (e.g.,
- t('Content path settings')
-patterndescr - The translated label for the default pattern (e.g.,
- t('Default path pattern (applies to all content types with blank patterns below)')
-patterndefault - A translated default pattern (e.g., t('[cat]/[title].html'))
-token_type - The token type (e.g. 'node', 'user') that can be used.
-patternitems - For modules which need to express multiple patterns
- (for example, the node module supports a separate pattern for each
- content type), an array whose keys consist of identifiers for each
- pattern (e.g., the content type name) and values consist of the
- translated label for the pattern
-bulkname - For modules which support a bulk update operation, the
- translated label for the action (e.g., t('Bulk update content paths'))
-bulkdescr - For modules which support a bulk update operation, a
- translated, more thorough description of what the operation will do
- (e.g., t('Generate aliases for all existing content items which do not already have aliases.'))
-
-
-==================
-2 - $alias = pathauto_create_alias($module, $op, $placeholders, $src, $type=NULL)
-==================
-
-At the appropriate time (usually when a new item is being created for
-which a generated alias is desired), call pathauto_create_alias() to
-generate and create the alias. See the user, taxonomy, and nodeapi hook
-implementations in pathauto.module for examples.
-
-$module - The name of your module (e.g., 'node')
-$op - Operation being performed on the item ('insert', 'update', or
- 'bulkupdate')
-$placeholders - An array whose keys consist of the translated placeholders
- which appear in patterns and values are the "clean" values to be
- substituted into the pattern. Call pathauto_cleanstring() on any
- values which you do not know to be purely alphanumeric, to substitute
- any non-alphanumerics with the user's designated separator. Note that
- if the pattern has multiple slash-separated components (e.g., [term:path]),
- pathauto_cleanstring() should be called for each component, not the
- complete string.
- Example: $placeholders[t('[title]')] = pathauto_cleanstring($node->title);
-$src - The "real" URI of the content to be aliased (e.g., "node/$node->nid")
-$type - For modules which provided patternitems in hook_autopath(),
- the relevant identifier for the specific item to be aliased (e.g.,
- $node->type)
-
-pathauto_create_alias() returns the alias that was created.
-
-
-==================
-3 - Bulk update function
-==================
-
-If a module supports bulk updating of aliases, it must provide a
-function of this form, to be called by pathauto when the corresponding
-checkbox is selected and the settings page submitted:
-
-function _pathauto_bulkupdate()
-
-The function should iterate over the content items controlled by the
-module, calling pathauto_create_alias() for each one. It is
-recommended that the function report on its success (e.g., with a
-count of created aliases) via drupal_set_message().
-
-
-==================
-4 - Bulk delete hook_path_alias_types()
-==================
-
-For modules that create new types of pages that can be aliased with pathauto, a
-hook implementation is needed to allow the user to delete them all at once.
-
-function hook_path_alias_types()
-
-This hook returns an array whose keys match the beginning of the source paths
-(e.g.: "node/", "user/", etc.) and whose values describe the type of page (e.g.:
-"content", "users"). Like all displayed strings, these descriptionsshould be
-localized with t(). Use % to match interior pieces of a path; "user/%/track". This
-is a database wildcard, so be careful.
-
-
-==================
-Modules that extend node and/or taxonomy
-==================
-
-NOTE: this is basically not true any more. If you feel you need this file an issue.
-
-Many contributed Drupal modules extend the core node and taxonomy
-modules. To extend pathauto patterns to support their extensions, they
-may implement the pathauto_node and pathauto_taxonomy hooks.
-
-To do so, implement the function _pathauto_node (or _taxonomy),
-accepting the arguments $op and $node (or $term). Two operations are
-supported:
-
-$op = 'placeholders' - return an array keyed on placeholder strings
-(e.g., t('[eventyyyy]')) valued with descriptions (e.g. t('The year the
-event starts.')).
-$op = 'values' - return an array keyed on placeholder strings, valued
-with the "clean" actual value for the passed node or category (e.g.,
-pathauto_cleanstring(date('M', $eventstart)));
-
-See contrib/pathauto_node_event.inc for an example of extending node
-patterns.
diff --git a/sites/all/modules/contrib/content/pathauto/INSTALL.txt b/sites/all/modules/contrib/content/pathauto/INSTALL.txt
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/content/pathauto/LICENSE.txt b/sites/all/modules/contrib/content/pathauto/LICENSE.txt
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/content/pathauto/README.txt b/sites/all/modules/contrib/content/pathauto/README.txt
old mode 100755
new mode 100644
index 4c458a14..fc56959d
--- a/sites/all/modules/contrib/content/pathauto/README.txt
+++ b/sites/all/modules/contrib/content/pathauto/README.txt
@@ -1,48 +1,49 @@
-Please read this file and also the INSTALL.txt.
+Please read this file and also the INSTALL.txt.
They contain answers to many common questions.
If you are developing for this module, the API.txt may be interesting.
If you are upgrading, check the CHANGELOG.txt for major changes.
-**Description:
-The Pathauto module provides support functions for other modules to
-automatically generate aliases based on appropriate criteria, with a
+** Description:
+The Pathauto module provides support functions for other modules to
+automatically generate aliases based on appropriate criteria, with a
central settings path for site administrators.
Implementations are provided for core entity types: content, taxonomy terms,
-and users (including blogs and tracker pages).
+and users (including blogs and forum pages).
-Pathauto also provides a way to delete large numbers of aliases. This feature
-is available at Administer > Site building > URL aliases > Delete aliases
+Pathauto also provides a way to delete large numbers of aliases. This feature
+is available at Administer > Configuration > Search and metadata > URL aliases
+> Delete aliases.
-**Benefits:
+** Benefits:
Besides making the page address more reflective of its content than
-"node/138", it's important to know that modern search engines give
-heavy weight to search terms which appear in a page's URL. By
-automatically using keywords based directly on the page content in the URL,
+"node/138", it's important to know that modern search engines give
+heavy weight to search terms which appear in a page's URL. By
+automatically using keywords based directly on the page content in the URL,
relevant search engine hits for your page can be significantly
enhanced.
-**Installation AND Upgrades:
+** Installation AND Upgrades:
See the INSTALL.txt file.
-**Notices:
+** Notices:
Pathauto just adds URL aliases to content, users, and taxonomy terms.
-Because it's an alias, the standard Drupal URL (for example node/123 or
-taxonomy/term/1) will still function as normal. If you have external links
-to your site pointing to standard Drupal URLs, or hardcoded links in a module,
+Because it's an alias, the standard Drupal URL (for example node/123 or
+taxonomy/term/1) will still function as normal. If you have external links
+to your site pointing to standard Drupal URLs, or hardcoded links in a module,
template, content or menu which point to standard Drupal URLs it will bypass
the alias set by Pathauto.
-There are reasons you might not want two URLs for the same content on your
-site. If this applies to you, please note that you will need to update any
-hard coded links in your content or blocks.
+There are reasons you might not want two URLs for the same content on your
+site. If this applies to you, please note that you will need to update any
+hard coded links in your content or blocks.
If you use the "system path" (i.e. node/10) for menu items and settings like
that, Drupal will replace it with the url_alias.
-For external links, you might want to consider the Path Redirect or
-Global Redirect modules, which allow you to set forwarding either per item or
-across the site to your aliased URLs.
+For external links, you might want to consider the Path Redirect or
+Global Redirect modules, which allow you to set forwarding either per item or
+across the site to your aliased URLs.
URLs (not) Getting Replaced With Aliases:
Please bear in mind that only URLs passed through Drupal's l() or url()
@@ -54,41 +55,27 @@ Drupal API instead:
* 'href="'. url("node/$node->nid") .'"' or
* l("Your link title", "node/$node->nid")
-See http://api.drupal.org/api/HEAD/function/url and
+See http://api.drupal.org/api/HEAD/function/url and
http://api.drupal.org/api/HEAD/function/l for more information.
** Disabling Pathauto for a specific content type (or taxonomy)
-When the pattern for a content type is left blank, the default pattern will be
-used. But if the default pattern is also blank, Pathauto will be disabled
+When the pattern for a content type is left blank, the default pattern will be
+used. But if the default pattern is also blank, Pathauto will be disabled
for that content type.
-** Bulk Updates Must be Run Multiple Times:
-As of 5.x-2.x Pathauto now performs bulk updates in a manner which is more
-likely to succeed on large sites. The drawback is that it needs to be run
-multiple times. If you want to reduce the number of times that you need to
-run Pathauto you can increase the "Maximum number of objects to alias in a
-bulk update:" setting under General Settings.
-
-**WYSIWYG Conflicts - FCKEditor, TinyMCE, etc.
-If you use a WYSIWYG editor, please disable it for the Pathauto admin page.
-Failure to do so may cause errors about "preg_replace" problems due to the
-tag being added to the "strings to replace". See http://drupal.org/node/175772
-
-**Credits:
+** Credits:
The original module combined the functionality of Mike Ryan's autopath with
Tommy Sundstrom's path_automatic.
Significant enhancements were contributed by jdmquin @ www.bcdems.net.
-Matt England added the tracker support.
+Matt England added the tracker support (tracker support has been removed in
+recent changes).
Other suggestions and patches contributed by the Drupal community.
-Current maintainers:
- Greg Knaddison - http://growingventuresolutions.com
+Current maintainers:
+ Dave Reid - http://www.davereid.net
+ Greg Knaddison - http://www.knaddison.com
Mike Ryan - http://mikeryan.name
Frederik 'Freso' S. Olesen - http://freso.dk
-
-**Changes:
-See the CHANGELOG.txt file.
-
diff --git a/sites/all/modules/contrib/content/pathauto/pathauto.admin.inc b/sites/all/modules/contrib/content/pathauto/pathauto.admin.inc
old mode 100755
new mode 100644
index 9030f487..b2103867
--- a/sites/all/modules/contrib/content/pathauto/pathauto.admin.inc
+++ b/sites/all/modules/contrib/content/pathauto/pathauto.admin.inc
@@ -64,17 +64,11 @@ function pathauto_patterns_form($form, $form_state) {
}
}
- // Display the user documentation of placeholders supported by
- // this module, as a description on the last pattern
+ // Show the token help relevant to this pattern type.
$form[$module]['token_help'] = array(
- '#title' => t('Replacement patterns'),
- '#type' => 'fieldset',
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- );
- $form[$module]['token_help']['help'] = array(
'#theme' => 'token_tree',
'#token_types' => array($settings->token_type),
+ '#dialog' => TRUE,
);
}
@@ -144,7 +138,7 @@ function pathauto_settings_form($form) {
$description = t('What should Pathauto do when updating an existing content item which already has an alias?');
if (module_exists('redirect')) {
- $description .= ' ' . t('The Redirect module settings affect whether a redirect is created when an alias is deleted.', array('!url' => url('admin/config/search/redirect')));
+ $description .= ' ' . t('The Redirect module settings affect whether a redirect is created when an alias is deleted.', array('!url' => url('admin/config/search/redirect/settings')));
}
else {
$description .= ' ' . t('Considering installing the Redirect module to get redirects when your aliases change.', array('!url' => 'http://drupal.org/project/redirect'));
@@ -165,7 +159,7 @@ function pathauto_settings_form($form) {
'#type' => 'checkbox',
'#title' => t('Transliterate prior to creating alias'),
'#default_value' => variable_get('pathauto_transliterate', FALSE) && module_exists('transliteration'),
- '#description' => t('When a pattern includes certain characters (such as those with accents) should Pathauto attempt to transliterate them into the ASCII-96 alphabet? Transliteration is handled by the Transliteration module.'),
+ '#description' => t('When a pattern includes certain characters (such as those with accents) should Pathauto attempt to transliterate them into the US-ASCII alphabet? Transliteration is handled by the Transliteration module.'),
'#access' => module_exists('transliteration'),
);
diff --git a/sites/all/modules/contrib/content/pathauto/pathauto.api.php b/sites/all/modules/contrib/content/pathauto/pathauto.api.php
old mode 100755
new mode 100644
index 41f11543..4c921888
--- a/sites/all/modules/contrib/content/pathauto/pathauto.api.php
+++ b/sites/all/modules/contrib/content/pathauto/pathauto.api.php
@@ -1,17 +1,171 @@
$type) {
+ $settings['patternitems'][$file_type] = t('Pattern for all @file_type paths.', array('@file_type' => $type->label));
+ }
+ return (object) $settings;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * Determine if a possible URL alias would conflict with any existing paths.
+ *
+ * Returning TRUE from this function will trigger pathauto_alias_uniquify() to
+ * generate a similar URL alias with a suffix to avoid conflicts.
+ *
+ * @param string $alias
+ * The potential URL alias.
+ * @param string $source
+ * The source path for the alias (e.g. 'node/1').
+ * @param string $langcode
+ * The language code for the alias (e.g. 'en').
+ *
+ * @return bool
+ * TRUE if $alias conflicts with an existing, reserved path, or FALSE/NULL if
+ * it does not match any reserved paths.
+ *
+ * @see pathauto_alias_uniquify()
+ */
+function hook_pathauto_is_alias_reserved($alias, $source, $langcode) {
+ // Check our module's list of paths and return TRUE if $alias matches any of
+ // them.
+ return (bool) db_query("SELECT 1 FROM {mytable} WHERE path = :path", array(':path' => $alias))->fetchField();
+}
+
+/**
+ * Alter the pattern to be used before an alias is generated by Pathauto.
+ *
+ * This hook will only be called if a default pattern is configured (on
+ * admin/config/search/path/patterns).
+ *
+ * @param string $pattern
+ * The alias pattern for Pathauto to pass to token_replace() to generate the
+ * URL alias.
+ * @param array $context
+ * An associative array of additional options, with the following elements:
+ * - 'module': The module or entity type being aliased.
+ * - 'op': A string with the operation being performed on the object being
+ * aliased. Can be either 'insert', 'update', 'return', or 'bulkupdate'.
+ * - 'source': A string of the source path for the alias (e.g. 'node/1').
+ * - 'data': An array of keyed objects to pass to token_replace().
+ * - 'type': The sub-type or bundle of the object being aliased.
+ * - 'language': A string of the language code for the alias (e.g. 'en').
+ * This can be altered by reference.
+ */
+function hook_pathauto_pattern_alter(&$pattern, array $context) {
+ // Switch out any [node:created:*] tokens with [node:updated:*] on update.
+ if ($context['module'] == 'node' && ($context['op'] == 'update')) {
+ $pattern = preg_replace('/\[node:created(\:[^]]*)?\]/', '[node:updated$1]', $pattern);
+ }
}
/**
diff --git a/sites/all/modules/contrib/content/pathauto/pathauto.inc b/sites/all/modules/contrib/content/pathauto/pathauto.inc
old mode 100755
new mode 100644
index 9f98eec3..9699aa08
--- a/sites/all/modules/contrib/content/pathauto/pathauto.inc
+++ b/sites/all/modules/contrib/content/pathauto/pathauto.inc
@@ -59,30 +59,27 @@ define('PATHAUTO_PUNCTUATION_DO_NOTHING', 2);
* A string alias.
* @param $source
* A string that is the internal path.
- * @param $language
+ * @param $langcode
* A string indicating the path's language.
- * @return
+ *
+ * @return bool
* TRUE if an alias exists, FALSE if not.
+ *
+ * @deprecated Use path_pathauto_is_alias_reserved() instead.
*/
-function _pathauto_alias_exists($alias, $source, $language = LANGUAGE_NONE) {
- $pid = db_query_range("SELECT pid FROM {url_alias} WHERE source <> :source AND alias = :alias AND language IN (:language, :language_none) ORDER BY language DESC, pid DESC", 0, 1, array(
- ':source' => $source,
- ':alias' => $alias,
- ':language' => $language,
- ':language_none' => LANGUAGE_NONE,
- ))->fetchField();
-
- return !empty($pid);
+function _pathauto_alias_exists($alias, $source, $langcode = LANGUAGE_NONE) {
+ return path_pathauto_is_alias_reserved($alias, $source, $langcode);
}
/**
* Fetches an existing URL alias given a path and optional language.
*
- * @param $source
+ * @param string $source
* An internal Drupal path.
- * @param $language
+ * @param string $language
* An optional language code to look up the path in.
- * @return
+ *
+ * @return bool|array
* FALSE if no alias was found or an associative array containing the
* following keys:
* - pid: Unique path alias identifier.
@@ -111,12 +108,17 @@ function _pathauto_existing_alias_data($source, $language = LANGUAGE_NONE) {
* This function should *not* be called on URL alias or path strings because it
* is assumed that they are already clean.
*
- * @param $string
+ * @param string $string
* A string to clean.
- * @return
+ * @param array $options
+ * (optional) A keyed array of settings and flags to control the Pathauto
+ * clean string replacement process. Supported options are:
+ * - langcode: A language code to be used when translating strings.
+ *
+ * @return string
* The cleaned string.
*/
-function pathauto_cleanstring($string) {
+function pathauto_cleanstring($string, array $options = array()) {
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static_fast;
if (!isset($drupal_static_fast)) {
@@ -161,6 +163,7 @@ function pathauto_cleanstring($string) {
if ($ignore_words_regex) {
$cache['ignore_words_regex'] = '\b' . $ignore_words_regex . '\b';
if (function_exists('mb_eregi_replace')) {
+ mb_regex_encoding('UTF-8');
$cache['ignore_words_callback'] = 'mb_eregi_replace';
}
else {
@@ -170,15 +173,23 @@ function pathauto_cleanstring($string) {
}
}
- // Empty strings do not need any proccessing.
+ // Empty strings do not need any processing.
if ($string === '' || $string === NULL) {
return '';
}
+ $langcode = NULL;
+ if (!empty($options['language']->language)) {
+ $langcode = $options['language']->language;
+ }
+ elseif (!empty($options['langcode'])) {
+ $langcode = $options['langcode'];
+ }
+
// Check if the string has already been processed, and if so return the
// cached result.
- if (isset($cache['strings'][$string])) {
- return $cache['strings'][$string];
+ if (isset($cache['strings'][$langcode][$string])) {
+ return $cache['strings'][$langcode][$string];
}
// Remove all HTML tags from the string.
@@ -186,7 +197,10 @@ function pathauto_cleanstring($string) {
// Optionally transliterate (by running through the Transliteration module)
if ($cache['transliterate']) {
- $output = transliteration_get($output);
+ // If the reduce strings to letters and numbers is enabled, don't bother
+ // replacing unknown characters with a question mark. Use an empty string
+ // instead.
+ $output = transliteration_get($output, $cache['reduce_ascii'] ? '' : '?', $langcode);
}
// Replace or drop punctuation based on user settings
@@ -220,7 +234,7 @@ function pathauto_cleanstring($string) {
$output = truncate_utf8($output, $cache['maxlength'], TRUE);
// Cache this result in the static array.
- $cache['strings'][$string] = $output;
+ $cache['strings'][$langcode][$string] = $output;
return $output;
}
@@ -228,11 +242,12 @@ function pathauto_cleanstring($string) {
/**
* Trims duplicate, leading, and trailing separators from a string.
*
- * @param $string
+ * @param string $string
* The string to clean path separators from.
- * @param $separator
+ * @param string $separator
* The path separator to use when cleaning.
- * @return
+ *
+ * @return string
* The cleaned version of the string.
*
* @see pathauto_cleanstring()
@@ -250,21 +265,20 @@ function _pathauto_clean_separators($string, $separator = NULL) {
$output = $string;
- // Clean duplicate or trailing separators.
if (strlen($separator)) {
- // Escape the separator.
- $seppattern = preg_quote($separator, '/');
-
// Trim any leading or trailing separators.
- $output = preg_replace("/^$seppattern+|$seppattern+$/", '', $output);
+ $output = trim($output, $separator);
- // Replace trailing separators around slashes.
- if ($separator !== '/') {
- $output = preg_replace("/$seppattern+\/|\/$seppattern+/", "/", $output);
- }
+ // Escape the separator for use in regular expressions.
+ $seppattern = preg_quote($separator, '/');
// Replace multiple separators with a single one.
$output = preg_replace("/$seppattern+/", $separator, $output);
+
+ // Replace trailing separators around slashes.
+ if ($separator !== '/') {
+ $output = preg_replace("/\/+$seppattern\/+|$seppattern\/+|\/+$seppattern/", "/", $output);
+ }
}
return $output;
@@ -278,9 +292,10 @@ function _pathauto_clean_separators($string, $separator = NULL) {
* - Trim duplicate, leading, and trailing separators.
* - Shorten to a desired length and logical position based on word boundaries.
*
- * @param $alias
+ * @param string $alias
* A string with the URL alias to clean up.
- * @return
+ *
+ * @return string
* The cleaned URL alias.
*/
function pathauto_clean_alias($alias) {
@@ -294,12 +309,15 @@ function pathauto_clean_alias($alias) {
$output = $alias;
- // Trim duplicate, leading, and trailing back-slashes.
- $output = _pathauto_clean_separators($output, '/');
-
- // Trim duplicate, leading, and trailing separators.
+ // Trim duplicate, leading, and trailing separators. Do this before cleaning
+ // backslashes since a pattern like "[token1]/[token2]-[token3]/[token4]"
+ // could end up like "value1/-/value2" and if backslashes were cleaned first
+ // this would result in a duplicate blackslash.
$output = _pathauto_clean_separators($output);
+ // Trim duplicate, leading, and trailing backslashes.
+ $output = _pathauto_clean_separators($output, '/');
+
// Shorten to a logical place based on word boundaries.
$output = truncate_utf8($output, $cache['maxlength'], TRUE);
@@ -328,8 +346,10 @@ function pathauto_clean_alias($alias) {
* (e.g., $node->type).
* @param $language
* A string specify the path's language.
- * @return
- * The alias that was created.
+ *
+ * @return array|null|false
+ * The alias array that was created, NULL if an empty alias was generated, or
+ * FALSE if the alias generation was not possible.
*
* @see _pathauto_set_alias()
* @see token_replace()
@@ -337,20 +357,32 @@ function pathauto_clean_alias($alias) {
function pathauto_create_alias($module, $op, $source, $data, $type = NULL, $language = LANGUAGE_NONE) {
// Retrieve and apply the pattern for this content type.
$pattern = pathauto_pattern_load_by_entity($module, $type, $language);
+
+ // Allow other modules to alter the pattern.
+ $context = array(
+ 'module' => $module,
+ 'op' => $op,
+ 'source' => $source,
+ 'data' => $data,
+ 'type' => $type,
+ 'language' => &$language,
+ );
+ drupal_alter('pathauto_pattern', $pattern, $context);
+
if (empty($pattern)) {
// No pattern? Do nothing (otherwise we may blow away existing aliases...)
- return '';
+ return FALSE;
}
// Special handling when updating an item which is already aliased.
$existing_alias = NULL;
- if ($op == 'update' || $op == 'bulkupdate') {
+ if ($op != 'insert') {
if ($existing_alias = _pathauto_existing_alias_data($source, $language)) {
switch (variable_get('pathauto_update_action', PATHAUTO_UPDATE_ACTION_DELETE)) {
case PATHAUTO_UPDATE_ACTION_NO_NEW:
// If an alias already exists, and the update action is set to do nothing,
// then gosh-darn it, do nothing.
- return '';
+ return FALSE;
}
}
}
@@ -369,26 +401,19 @@ function pathauto_create_alias($module, $op, $source, $data, $type = NULL, $lang
// @see token_scan()
$pattern_tokens_removed = preg_replace('/\[[^\s\]:]*:[^\s\]]*\]/', '', $pattern);
if ($alias === $pattern_tokens_removed) {
- return '';
+ return;
}
$alias = pathauto_clean_alias($alias);
// Allow other modules to alter the alias.
- $context = array(
- 'module' => $module,
- 'op' => $op,
- 'source' => &$source,
- 'data' => $data,
- 'type' => $type,
- 'language' => &$language,
- 'pattern' => $pattern,
- );
+ $context['source'] = &$source;
+ $context['pattern'] = $pattern;
drupal_alter('pathauto_alias', $alias, $context);
// If we have arrived at an empty string, discontinue.
if (!drupal_strlen($alias)) {
- return '';
+ return;
}
// If the alias already exists, generate a new, hopefully unique, variant.
@@ -432,7 +457,7 @@ function pathauto_create_alias($module, $op, $source, $data, $type = NULL, $lang
* A string with a language code.
*/
function pathauto_alias_uniquify(&$alias, $source, $langcode) {
- if (!_pathauto_alias_exists($alias, $source, $langcode)) {
+ if (!pathauto_is_alias_reserved($alias, $source, $langcode)) {
return;
}
@@ -445,9 +470,9 @@ function pathauto_alias_uniquify(&$alias, $source, $langcode) {
do {
// Append an incrementing numeric suffix until we find a unique alias.
$unique_suffix = $separator . $i;
- $alias = truncate_utf8($original_alias, $maxlength - drupal_strlen($unique_suffix, TRUE)) . $unique_suffix;
+ $alias = truncate_utf8($original_alias, $maxlength - drupal_strlen($unique_suffix), TRUE) . $unique_suffix;
$i++;
- } while (_pathauto_alias_exists($alias, $source, $langcode));
+ } while (pathauto_is_alias_reserved($alias, $source, $langcode));
}
/**
@@ -463,7 +488,7 @@ function pathauto_alias_uniquify(&$alias, $source, $langcode) {
function _pathauto_path_is_callback($path) {
// We need to use a try/catch here because of a core bug which will throw an
// exception if $path is something like 'node/foo/bar'.
- // @todo Remove when http://drupal.org/node/1302158 is fixed in core.
+ // @todo Remove when http://drupal.org/node/1003788 is fixed in core.
try {
$menu = menu_get_item($path);
}
@@ -498,26 +523,19 @@ function _pathauto_path_is_callback($path) {
* An optional string with the operation being performed.
*
* @return
- * The saved path from path_save() or NULL if the path was not saved.
+ * The saved path from path_save() or FALSE if the path was not saved.
*
* @see path_save()
*/
function _pathauto_set_alias(array $path, $existing_alias = NULL, $op = NULL) {
$verbose = _pathauto_verbose(NULL, $op);
- // Alert users that an existing callback cannot be overridden automatically
- if (_pathauto_path_is_callback($path['alias'])) {
- if ($verbose) {
- _pathauto_verbose(t('Ignoring alias %alias due to existing path conflict.', array('%alias' => $path['alias'])));
- }
- return;
- }
// Alert users if they are trying to create an alias that is the same as the internal path
if ($path['source'] == $path['alias']) {
if ($verbose) {
_pathauto_verbose(t('Ignoring alias %alias because it is the same as the internal path.', array('%alias' => $path['alias'])));
}
- return;
+ return FALSE;
}
// Skip replacing the current alias with an identical alias
@@ -529,7 +547,7 @@ function _pathauto_set_alias(array $path, $existing_alias = NULL, $op = NULL) {
switch (variable_get('pathauto_update_action', PATHAUTO_UPDATE_ACTION_DELETE)) {
case PATHAUTO_UPDATE_ACTION_NO_NEW:
// Do not create the alias.
- return;
+ return FALSE;
case PATHAUTO_UPDATE_ACTION_LEAVE:
// Create a new alias instead of overwriting the existing by leaving
// $path['pid'] empty.
@@ -605,7 +623,7 @@ function pathauto_clean_token_values(&$replacements, $data = array(), $options =
foreach ($replacements as $token => $value) {
// Only clean non-path tokens.
if (!preg_match('/(path|alias|url|url-brief)\]$/', $token)) {
- $replacements[$token] = pathauto_cleanstring($value);
+ $replacements[$token] = pathauto_cleanstring($value, $options);
}
}
}
diff --git a/sites/all/modules/contrib/content/pathauto/pathauto.info b/sites/all/modules/contrib/content/pathauto/pathauto.info
old mode 100755
new mode 100644
index 1488faa0..9a73e491
--- a/sites/all/modules/contrib/content/pathauto/pathauto.info
+++ b/sites/all/modules/contrib/content/pathauto/pathauto.info
@@ -3,13 +3,14 @@ description = Provides a mechanism for modules to automatically generate aliases
dependencies[] = path
dependencies[] = token
core = 7.x
+files[] = pathauto.migrate.inc
files[] = pathauto.test
configure = admin/config/search/path/patterns
recommends[] = redirect
-; Information added by drupal.org packaging script on 2012-08-09
-version = "7.x-1.2"
+; Information added by Drupal.org packaging script on 2015-10-07
+version = "7.x-1.3"
core = "7.x"
project = "pathauto"
-datestamp = "1344525185"
+datestamp = "1444232655"
diff --git a/sites/all/modules/contrib/content/pathauto/pathauto.install b/sites/all/modules/contrib/content/pathauto/pathauto.install
old mode 100755
new mode 100644
index cd5211cb..62a4ed24
--- a/sites/all/modules/contrib/content/pathauto/pathauto.install
+++ b/sites/all/modules/contrib/content/pathauto/pathauto.install
@@ -7,19 +7,59 @@
* @ingroup pathauto
*/
+/**
+ * Implements hook_schema().
+ */
+function pathauto_schema() {
+ $schema['pathauto_state'] = array(
+ 'description' => 'The status of each entity alias (whether it was automatically generated or not).',
+ 'fields' => array(
+ 'entity_type' => array(
+ 'type' => 'varchar',
+ 'length' => 32,
+ 'not null' => TRUE,
+ 'description' => 'An entity type.',
+ ),
+ 'entity_id' => array(
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'description' => 'An entity ID.',
+ ),
+ 'pathauto' => array(
+ 'type' => 'int',
+ 'size' => 'tiny',
+ 'not null' => TRUE,
+ 'default' => 0,
+ 'description' => 'The automatic alias status of the entity.',
+ ),
+ ),
+ 'primary key' => array('entity_type', 'entity_id'),
+ );
+
+ return $schema;
+}
+
+
/**
* Implements hook_install().
*/
function pathauto_install() {
// Set some default variables necessary for the module to perform.
- variable_set('pathauto_node_pattern', 'content/[node:title]');
- variable_set('pathauto_taxonomy_term_pattern', '[term:vocabulary]/[term:name]');
- variable_set('pathauto_forum_pattern', '[term:vocabulary]/[term:name]');
- variable_set('pathauto_user_pattern', 'users/[user:name]');
- variable_set('pathauto_blog_pattern', 'blogs/[user:name]');
-
- // Set the default separator character to replace instead of remove (default).
- variable_set('pathauto_punctuation_hyphen', 1);
+ $defaults = array(
+ 'pathauto_node_pattern' => 'content/[node:title]',
+ 'pathauto_taxonomy_term_pattern' => '[term:vocabulary]/[term:name]',
+ 'pathauto_forum_pattern' => '[term:vocabulary]/[term:name]',
+ 'pathauto_user_pattern' => 'users/[user:name]',
+ 'pathauto_blog_pattern' => 'blogs/[user:name]',
+ // Set hyphen character to replace instead of remove.
+ 'pathauto_punctuation_hyphen' => 1,
+ );
+ foreach ($defaults as $variable => $default) {
+ if (variable_get($variable) === NULL) {
+ variable_set($variable, $default);
+ }
+ }
// Set the weight to 1
db_update('system')
@@ -38,6 +78,23 @@ function pathauto_uninstall() {
cache_clear_all('variables', 'cache');
}
+/**
+ * Implements hook_requirements().
+ */
+function pathauto_requirements($phase) {
+ $requirements = array();
+ $t = get_t();
+ if ($phase == 'runtime' && module_exists('pathauto_persist')) {
+ $requirements['pathauto'] = array(
+ 'title' => $t('Pathauto Persist'),
+ 'value' => $t('Enabled'),
+ 'description' => $t('Pathauto Persist is installed and enabled. As Pathauto Persist has been merged into Pathauto, the Pathauto Persist module can be safely disabled and removed. All Pathauto Persist settings have been migrated to the Pathauto implementation.'),
+ 'severity' => REQUIREMENT_INFO,
+ );
+ }
+ return $requirements;
+}
+
/**
* Remove the unsupported user/%/contact and user/%/tracker pattern variables.
*/
@@ -168,6 +225,55 @@ function pathauto_update_7005() {
return 'Your Pathauto taxonomy and forum patterns have been corrected. You may wish to regenerate your taxonomy and forum term URL aliases.';
}
+/**
+ * Create pathauto_state table, using data from pathauto_persist if it exists.
+ */
+function pathauto_update_7006() {
+ if (!db_table_exists('pathauto_state')) {
+
+ $schema['pathauto_state'] = array(
+ 'description' => 'The status of each entity alias (whether it was automatically generated or not).',
+ 'fields' => array(
+ 'entity_type' => array(
+ 'type' => 'varchar',
+ 'length' => 32,
+ 'not null' => TRUE,
+ 'description' => 'The entity type.',
+ ),
+ 'entity_id' => array(
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'description' => 'The entity ID.',
+ ),
+ 'pathauto' => array(
+ 'type' => 'int',
+ 'size' => 'tiny',
+ 'not null' => TRUE,
+ 'default' => 0,
+ 'description' => 'The automatic alias status of the entity.',
+ ),
+ ),
+ 'primary key' => array('entity_type', 'entity_id'),
+ );
+
+ if (db_table_exists('pathauto_persist')) {
+ // Rename pathauto_persist's table, then create a new empty one just so
+ // that we can cleanly disable that module.
+ db_rename_table('pathauto_persist', 'pathauto_state');
+ db_create_table('pathauto_persist', $schema['pathauto_state']);
+ // Disable the module and inform the user.
+ if (module_exists('pathauto_persist')) {
+ module_disable(array('pathauto_persist'));
+ }
+ return t('The Pathauto Persist module and all of its data has been merged into Pathauto. The Pathauto Persist module has been disabled and can be safely uninstalled.');
+ }
+ else {
+ db_create_table('pathauto_state', $schema['pathauto_state']);
+ }
+ }
+}
+
/**
* Build a list of Drupal 6 tokens and their Drupal 7 token names.
*/
diff --git a/sites/all/modules/contrib/content/pathauto/pathauto.js b/sites/all/modules/contrib/content/pathauto/pathauto.js
old mode 100755
new mode 100644
index be49cd63..52dcf12d
--- a/sites/all/modules/contrib/content/pathauto/pathauto.js
+++ b/sites/all/modules/contrib/content/pathauto/pathauto.js
@@ -3,13 +3,13 @@
Drupal.behaviors.pathFieldsetSummaries = {
attach: function (context) {
$('fieldset.path-form', context).drupalSetSummary(function (context) {
- var path = $('.form-item-path-alias input').val();
- var automatic = $('.form-item-path-pathauto input').attr('checked');
+ var path = $('.form-item-path-alias input', context).val();
+ var automatic = $('.form-item-path-pathauto input', context).attr('checked');
if (automatic) {
return Drupal.t('Automatic alias');
}
- if (path) {
+ else if (path) {
return Drupal.t('Alias: @alias', { '@alias': path });
}
else {
diff --git a/sites/all/modules/contrib/content/pathauto/pathauto.migrate.inc b/sites/all/modules/contrib/content/pathauto/pathauto.migrate.inc
new file mode 100644
index 00000000..bbb9f297
--- /dev/null
+++ b/sites/all/modules/contrib/content/pathauto/pathauto.migrate.inc
@@ -0,0 +1,56 @@
+registerTypes(array('entity'));
+ }
+
+ /**
+ * Make the destination field visible.
+ */
+ public function fields() {
+ return array(
+ 'pathauto' => t('Pathauto: Perform aliasing (set to 0 to prevent alias generation during migration'),
+ );
+ }
+
+ public function prepare($entity, stdClass $row) {
+ if (isset($entity->pathauto)) {
+ if (!isset($entity->path)) {
+ $entity->path = array();
+ }
+ elseif (is_string($entity->path)) {
+ // If MigratePathEntityHandler->prepare() hasn't run yet, support
+ // the alias (set as $entity->path as a string) being formatted properly
+ // in the path alias array.
+ $path = $entity->path;
+ $entity->path = array();
+ $entity->path['alias'] = $path;
+ }
+ $entity->path['pathauto'] = $entity->pathauto;
+ if (!isset($entity->path['alias'])) {
+ $entity->path['alias'] = '';
+ }
+ unset($entity->pathauto);
+ }
+ }
+}
+
+/*
+ * Implementation of hook_migrate_api().
+ */
+function pathauto_migrate_api() {
+ $api = array(
+ 'api' => 2,
+ 'destination handlers' => array('PathautoMigrationHandler'),
+ );
+ return $api;
+}
diff --git a/sites/all/modules/contrib/content/pathauto/pathauto.module b/sites/all/modules/contrib/content/pathauto/pathauto.module
old mode 100755
new mode 100644
index dffc2928..63058209
--- a/sites/all/modules/contrib/content/pathauto/pathauto.module
+++ b/sites/all/modules/contrib/content/pathauto/pathauto.module
@@ -26,30 +26,14 @@ define('PATHAUTO_IGNORE_WORDS', 'a, an, as, at, before, but, by, for, from, is,
* Implements hook_hook_info().
*/
function pathauto_hook_info() {
- $info['pathauto'] = array('group' => 'pathauto');
- $info['path_alias_types'] = array('group' => 'pathauto');
- return $info;
-}
-
-/**
- * Implements hook_module_implements_alter().
- *
- * Adds pathauto support for core modules.
- */
-function pathauto_module_implements_alter(&$implementations, $hook) {
- $hooks = pathauto_hook_info();
- if (isset($hooks[$hook])) {
- $modules = array('node', 'taxonomy', 'user', 'forum', 'blog');
- foreach ($modules as $module) {
- if (module_exists($module)) {
- $implementations[$module] = TRUE;
- }
- }
- // Move pathauto.module to get included first since it is responsible for
- // other modules.
- unset($implementations['pathauto']);
- $implementations = array_merge(array('pathauto' => 'pathauto'), $implementations);
- }
+ $hooks = array(
+ 'pathauto',
+ 'path_alias_types',
+ 'pathauto_pattern_alter',
+ 'pathauto_alias_alter',
+ 'pathauto_is_alias_reserved',
+ );
+ return array_fill_keys($hooks, array('group' => 'pathauto'));
}
/**
@@ -67,6 +51,9 @@ function pathauto_help($path, $arg) {
$output .= '
' . t('The maximum alias length and maximum component length values default to 100 and have a limit of @max from Pathauto. This length is limited by the length of the "alias" column of the url_alias database table. The default database schema for this column is @max. If you set a length that is equal to that of the one set in the "alias" column it will cause problems in situations where the system needs to append additional words to the aliased URL. You should enter a value that is the length of the "alias" column minus the length of any strings that might get added to the end of the URL. The length of strings that might get added to the end of your URLs depends on which modules you have enabled and on your Pathauto settings. The recommended and default value is 100.', array('@max' => _pathauto_get_schema_alias_maxlength())) . '
' . t('Bulk generation will only generate URL aliases for items that currently have no aliases. This is typically used when installing Pathauto on a site that has existing un-aliased content that needs to be aliased in bulk.') . '
';
+ return $output;
}
}
@@ -109,7 +96,7 @@ function pathauto_menu() {
'file' => 'pathauto.admin.inc',
);
$items['admin/config/search/path/update_bulk'] = array(
- 'title' => 'Bulk update',
+ 'title' => 'Bulk generate',
'page callback' => 'drupal_get_form',
'page arguments' => array('pathauto_bulk_update_form'),
'access arguments' => array('administer url aliases'),
@@ -295,9 +282,19 @@ function pathauto_field_attach_form($entity_type, $entity, &$form, &$form_state,
if (!empty($id)) {
module_load_include('inc', 'pathauto');
$uri = entity_uri($entity_type, $entity);
- $path = drupal_get_path_alias($uri['path'], $langcode);
$pathauto_alias = pathauto_create_alias($entity_type, 'return', $uri['path'], array($entity_type => $entity), $bundle, $langcode);
- $entity->path['pathauto'] = ($path != $uri['path'] && $path == $pathauto_alias);
+ if ($pathauto_alias === FALSE) {
+ // If Pathauto is not going to be able to generate an alias, then we
+ // should not bother to show the checkbox since it wouldn't do anything.
+ // Note that if a pattern does apply, but all the tokens currently
+ // evaluate to empty strings, then $pathauto_alias would equal null and
+ // not false.
+ return;
+ }
+ else {
+ $path = drupal_get_path_alias($uri['path'], $langcode);
+ $entity->path['pathauto'] = ($path != $uri['path'] && $path == $pathauto_alias);
+ }
}
else {
$entity->path['pathauto'] = TRUE;
@@ -341,10 +338,54 @@ function pathauto_field_attach_form($entity_type, $entity, &$form, &$form_state,
}
}
+/**
+ * Implements hook_entity_load().
+ */
+function pathauto_entity_load($entities, $entity_type) {
+ // Statically cache which entity types have data in the pathauto_state
+ // table to avoid unnecessary queries for entities that would not have any
+ // data anyway.
+ static $loadable_types;
+ if (!isset($loadable_types)) {
+ $loadable_types = &drupal_static(__FUNCTION__);
+ if (!isset($loadable_types)) {
+ // Prevent errors if pathauto_update_7006() has not yet been run.
+ if (!db_table_exists('pathauto_state')) {
+ $loadable_types = array();
+ }
+ else {
+ $loadable_types = db_query("SELECT DISTINCT entity_type FROM {pathauto_state}")->fetchCol();
+ }
+ }
+ }
+
+ // Check if this entity type has loadable records.
+ if (!in_array($entity_type, $loadable_types)) {
+ return;
+ }
+
+ $states = pathauto_entity_state_load_multiple($entity_type, array_keys($entities));
+ foreach ($states as $id => $state) {
+ if (!isset($entities[$id]->path)) {
+ $entities[$id]->path = array();
+ }
+
+ if (is_array($entities[$id]->path) && !isset($entities[$id]->path['pathauto'])) {
+ $entities[$id]->path['pathauto'] = $state;
+ }
+ }
+}
+
/**
* Implements hook_entity_presave().
*/
-function pathauto_entity_presave($entity, $type) {
+function pathauto_entity_presave($entity, $entity_type) {
+ if (isset($entity->path['pathauto']) && is_array($entity->path)) {
+ // We must set an empty alias string for the path to prevent saving an
+ // alias.
+ $entity->path += array('alias' => '');
+ }
+
// About to be saved (before insert/update)
if (!empty($entity->path['pathauto']) && isset($entity->path['old_alias'])
&& $entity->path['alias'] == '' && $entity->path['old_alias'] != '') {
@@ -366,6 +407,109 @@ function pathauto_entity_presave($entity, $type) {
}
}
+/**
+ * Implements hook_entity_insert().
+ */
+function pathauto_entity_insert($entity, $entity_type) {
+ if (isset($entity->path['pathauto'])) {
+ pathauto_entity_state_save($entity_type, $entity, $entity->path['pathauto']);
+ }
+}
+
+/**
+ * Implements hook_entity_update().
+ */
+function pathauto_entity_update($entity, $entity_type) {
+ if (isset($entity->path['pathauto'])) {
+ pathauto_entity_state_save($entity_type, $entity, $entity->path['pathauto']);
+ }
+}
+
+/**
+ * Implements hook_entity_delete().
+ */
+function pathauto_entity_delete($entity, $entity_type) {
+ if (isset($entity->path['pathauto'])) {
+ pathauto_entity_state_delete($entity_type, $entity);
+ }
+}
+
+/**
+ * Load a pathauto state for an entity.
+ *
+ * @param string $entity_type
+ * An entity type.
+ * @param int $entity_id
+ * An entity ID.
+ *
+ * @return bool
+ * A value that evaluates to TRUE if Pathauto should control this entity's
+ * path. A value that evaluates to FALSE if Pathauto should not manage the
+ * entity's path.
+ */
+function pathauto_entity_state_load($entity_type, $entity_id) {
+ $pathauto_state = pathauto_entity_state_load_multiple($entity_type, array($entity_id));
+ return !empty($pathauto_state) ? reset($pathauto_state) : FALSE;
+}
+
+/**
+ * Load a pathauto state for multiple entities.
+ *
+ * @param string $entity_type
+ * The entity type.
+ * @param int[] $entity_ids
+ * The array of entity IDs.
+ *
+ * @return bool[]
+ * An array of Pathauto states keyed by entity ID.
+ */
+function pathauto_entity_state_load_multiple($entity_type, $entity_ids) {
+ return db_query("SELECT entity_id, pathauto FROM {pathauto_state} WHERE entity_type = :entity_type AND entity_id IN (:entity_ids)", array(':entity_type' => $entity_type, ':entity_ids' => $entity_ids))->fetchAllKeyed();
+}
+
+/**
+ * Save the pathauto state for an entity.
+ *
+ * @param string $entity_type
+ * The entity type.
+ * @param object $entity
+ * The entity object.
+ * @param bool $pathauto_state
+ * A value that evaluates to TRUE means that Pathauto should keep controlling
+ * this entity's path in the future. A value that evaluates to FALSE means
+ * that Pathauto should not manage the entity's path.
+ */
+function pathauto_entity_state_save($entity_type, $entity, $pathauto_state) {
+ list($entity_id) = entity_extract_ids($entity_type, $entity);
+ db_merge('pathauto_state')
+ ->key(array(
+ 'entity_type' => $entity_type,
+ 'entity_id' => $entity_id,
+ ))
+ ->fields(array(
+ 'pathauto' => $pathauto_state ? 1 : 0,
+ ))
+ ->execute();
+ drupal_static_reset('pathauto_entity_load');
+}
+
+/**
+ * Delete the pathauto state for an entity.
+ *
+ * @param string $entity_type
+ * The entity type.
+ * @param object $entity
+ * The entity object.
+ */
+function pathauto_entity_state_delete($entity_type, $entity) {
+ list($entity_id) = entity_extract_ids($entity_type, $entity);
+ db_delete('pathauto_state')
+ ->condition('entity_type', $entity_type)
+ ->condition('entity_id', $entity_id)
+ ->execute();
+ drupal_static_reset('pathauto_entity_load');
+}
+
/**
* Implements hook_action_info().
*/
@@ -374,16 +518,19 @@ function pathauto_action_info() {
'type' => 'node',
'label' => t('Update node alias'),
'configurable' => FALSE,
+ 'triggers' => array(),
);
$info['pathauto_taxonomy_term_update_action'] = array(
'type' => 'taxonomy_term',
'label' => t('Update taxonomy term alias'),
'configurable' => FALSE,
+ 'triggers' => array(),
);
$info['pathauto_user_update_action'] = array(
'type' => 'user',
'label' => t('Update user alias'),
'configurable' => FALSE,
+ 'triggers' => array(),
);
return $info;
@@ -393,7 +540,7 @@ function pathauto_action_info() {
* Returns the language code of the given entity.
*
* Backward compatibility layer to ensure that installations running an older
- * version of core where entity_language() is not avilable do not break.
+ * version of core where entity_language() is not available do not break.
*
* @param string $entity_type
* An entity type.
@@ -417,6 +564,46 @@ function pathauto_entity_language($entity_type, $entity, $check_language_propert
return !empty($langcode) ? $langcode : LANGUAGE_NONE;
}
+function pathauto_is_alias_reserved($alias, $source, $langcode = LANGUAGE_NONE) {
+ foreach (module_implements('pathauto_is_alias_reserved') as $module) {
+ $result = module_invoke($module, 'pathauto_is_alias_reserved', $alias, $source, $langcode);
+ if (!empty($result)) {
+ // As soon as the first module says that an alias is in fact reserved,
+ // then there is no point in checking the rest of the modules.
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ * Implements hook_pathauto_is_alias_reserved() on behalf of path.module.
+ */
+function path_pathauto_is_alias_reserved($alias, $source, $langcode) {
+ // For language neutral content, we need to make sure the alias doesn't
+ // collide with any existing aliases. For localized content, just make sure
+ // it doesn't collide with same language or language neutral aliases.
+ $query = db_select('url_alias', 'ua')
+ ->fields('ua', array('pid'))
+ ->condition('source', $source, '<>')
+ ->condition('alias', $alias);
+
+ if ($langcode != LANGUAGE_NONE) {
+ $query->condition('language', array($langcode, LANGUAGE_NONE), 'IN');
+ }
+
+ return $query->execute()->rowCount() > 0;
+}
+
+/**
+ * Implements hook_pathauto_is_alias_reserved().
+ */
+function pathauto_pathauto_is_alias_reserved($alias, $source, $langcode) {
+ module_load_include('inc', 'pathauto');
+ return _pathauto_path_is_callback($alias);
+}
+
if (!function_exists('path_field_extra_fields')) {
/**
* Implements hook_field_extra_fields() on behalf of path.module.
@@ -459,6 +646,47 @@ function path_field_extra_fields() {
* @{
*/
+/**
+ * Implements hook_path_alias_types() on behalf of node module.
+ */
+function node_path_alias_types() {
+ return array('node/' => t('Content'));
+}
+
+/**
+ * Implements hook_pathauto() on behalf of node module.
+ */
+function node_pathauto($op) {
+ if ($op == 'settings') {
+ $settings = array();
+ $settings['module'] = 'node';
+ $settings['token_type'] = 'node';
+ $settings['groupheader'] = t('Content paths');
+ $settings['patterndescr'] = t('Default path pattern (applies to all content types with blank patterns below)');
+ $settings['patterndefault'] = 'content/[node:title]';
+ $settings['batch_update_callback'] = 'node_pathauto_bulk_update_batch_process';
+ $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto.pathauto.inc';
+
+ $languages = array();
+ if (module_exists('locale')) {
+ $languages = array(LANGUAGE_NONE => t('language neutral')) + locale_language_list('name');
+ }
+
+ foreach (node_type_get_names() as $node_type => $node_name) {
+ if (count($languages) && variable_get('language_content_type_' . $node_type, 0)) {
+ $settings['patternitems'][$node_type] = t('Default path pattern for @node_type (applies to all @node_type content types with blank patterns below)', array('@node_type' => $node_name));
+ foreach ($languages as $lang_code => $lang_name) {
+ $settings['patternitems'][$node_type . '_' . $lang_code] = t('Pattern for all @language @node_type paths', array('@node_type' => $node_name, '@language' => $lang_name));
+ }
+ }
+ else {
+ $settings['patternitems'][$node_type] = t('Pattern for all @node_type paths', array('@node_type' => $node_name));
+ }
+ }
+ return (object) $settings;
+ }
+}
+
/**
* Implements hook_node_insert().
*/
@@ -517,20 +745,20 @@ function pathauto_node_operations() {
*/
function pathauto_node_update_alias(stdClass $node, $op, array $options = array()) {
// Skip processing if the user has disabled pathauto for the node.
- if (isset($node->path['pathauto']) && empty($node->path['pathauto'])) {
- return;
+ if (isset($node->path['pathauto']) && empty($node->path['pathauto']) && empty($options['force'])) {
+ return FALSE;
}
$options += array('language' => pathauto_entity_language('node', $node));
// Skip processing if the node has no pattern.
if (!pathauto_pattern_load_by_entity('node', $node->type, $options['language'])) {
- return;
+ return FALSE;
}
module_load_include('inc', 'pathauto');
$uri = entity_uri('node', $node);
- pathauto_create_alias('node', $op, $uri['path'], array('node' => $node), $node->type, $options['language']);
+ return pathauto_create_alias('node', $op, $uri['path'], array('node' => $node), $node->type, $options['language']);
}
/**
@@ -573,6 +801,42 @@ function pathauto_node_update_action($node, $context = array()) {
* @{
*/
+/**
+ * Implements hook_path_alias_types() on behalf of taxonomy module.
+ */
+function taxonomy_path_alias_types() {
+ return array('taxonomy/term/' => t('Taxonomy terms'));
+}
+
+/**
+ * Implements hook_pathauto() on behalf of taxonomy module.
+ */
+function taxonomy_pathauto($op) {
+ if ($op == 'settings') {
+ $settings = array();
+ $settings['module'] = 'taxonomy_term';
+ $settings['token_type'] = 'term';
+ $settings['groupheader'] = t('Taxonomy term paths');
+ $settings['patterndescr'] = t('Default path pattern (applies to all vocabularies with blank patterns below)');
+ $settings['patterndefault'] = '[term:vocabulary]/[term:name]';
+ $settings['batch_update_callback'] = 'taxonomy_pathauto_bulk_update_batch_process';
+ $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto.pathauto.inc';
+
+ $vocabularies = taxonomy_get_vocabularies();
+ if (count($vocabularies)) {
+ $settings['patternitems'] = array();
+ foreach ($vocabularies as $vid => $vocabulary) {
+ if ($vid == variable_get('forum_nav_vocabulary', '')) {
+ // Skip the forum vocabulary.
+ continue;
+ }
+ $settings['patternitems'][$vocabulary->machine_name] = t('Pattern for all %vocab-name paths', array('%vocab-name' => $vocabulary->name));
+ }
+ }
+ return (object) $settings;
+ }
+}
+
/**
* Implements hook_taxonomy_term_insert().
*/
@@ -617,8 +881,8 @@ function pathauto_form_taxonomy_form_term_alter(&$form, $form_state) {
*/
function pathauto_taxonomy_term_update_alias(stdClass $term, $op, array $options = array()) {
// Skip processing if the user has disabled pathauto for the term.
- if (isset($term->path['pathauto']) && empty($term->path['pathauto'])) {
- return;
+ if (isset($term->path['pathauto']) && empty($term->path['pathauto']) && empty($options['force'])) {
+ return FALSE;
}
$module = 'taxonomy_term';
@@ -627,7 +891,7 @@ function pathauto_taxonomy_term_update_alias(stdClass $term, $op, array $options
$module = 'forum';
}
else {
- return;
+ return FALSE;
}
}
@@ -644,21 +908,22 @@ function pathauto_taxonomy_term_update_alias(stdClass $term, $op, array $options
// Skip processing if the term has no pattern.
if (!pathauto_pattern_load_by_entity($module, $term->vocabulary_machine_name)) {
- return;
+ return FALSE;
}
module_load_include('inc', 'pathauto');
$uri = entity_uri('taxonomy_term', $term);
- pathauto_create_alias($module, $op, $uri['path'], array('term' => $term), $term->vocabulary_machine_name, $options['language']);
+ $result = pathauto_create_alias($module, $op, $uri['path'], array('term' => $term), $term->vocabulary_machine_name, $options['language']);
if (!empty($options['alias children'])) {
// For all children generate new aliases.
- $options['alias children'] = FALSE;
unset($options['language']);
- foreach (taxonomy_get_tree($term->vid, $term->tid) as $subterm) {
+ foreach (taxonomy_get_children($term->tid, $term->vid) as $subterm) {
pathauto_taxonomy_term_update_alias($subterm, $op, $options);
}
}
+
+ return $result;
}
/**
@@ -696,11 +961,68 @@ function pathauto_taxonomy_term_update_action($term, $context = array()) {
* @} End of "name pathauto_taxonomy".
*/
+/**
+ * @name pathauto_forum Pathauto integration for the core forum module.
+ * @{
+ */
+
+/**
+ * Implements hook_path_alias_types() on behalf of forum module.
+ */
+function forum_path_alias_types() {
+ return array('forum/' => t('Forums'));
+}
+
+/**
+ * Implements hook_pathauto() for forum module.
+ */
+function forum_pathauto($op) {
+ if ($op == 'settings') {
+ $settings = array();
+ $settings['module'] = 'forum';
+ $settings['token_type'] = 'term';
+ $settings['groupheader'] = t('Forum paths');
+ $settings['patterndescr'] = t('Pattern for forums and forum containers');
+ $settings['patterndefault'] = '[term:vocabulary]/[term:name]';
+ $settings['batch_update_callback'] = 'forum_pathauto_bulk_update_batch_process';
+ $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto.pathauto.inc';
+ return (object) $settings;
+ }
+}
+
+/**
+ * @} End of "name pathauto_forum".
+ */
+
/**
* @name pathauto_user Pathauto integration for the core user and blog modules.
* @{
*/
+/**
+ * Implements hook_path_alias_types() on behalf of user module.
+ */
+function user_path_alias_types() {
+ return array('user/' => t('Users'));
+}
+
+/**
+ * Implements hook_pathauto() on behalf of user module.
+ */
+function user_pathauto($op) {
+ if ($op == 'settings') {
+ $settings = array();
+ $settings['module'] = 'user';
+ $settings['token_type'] = 'user';
+ $settings['groupheader'] = t('User paths');
+ $settings['patterndescr'] = t('Pattern for user account page paths');
+ $settings['patterndefault'] = 'users/[user:name]';
+ $settings['batch_update_callback'] = 'user_pathauto_bulk_update_batch_process';
+ $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto.pathauto.inc';
+ return (object) $settings;
+ }
+}
+
/**
* Implements hook_user_insert().
*/
@@ -748,8 +1070,8 @@ function pathauto_user_operations() {
*/
function pathauto_user_update_alias(stdClass $account, $op, array $options = array()) {
// Skip processing if the user has disabled pathauto for the account.
- if (isset($account->path['pathauto']) && empty($account->path['pathauto'])) {
- return;
+ if (isset($account->path['pathauto']) && empty($account->path['pathauto']) && empty($options['force'])) {
+ return FALSE;
}
$options += array(
@@ -761,17 +1083,19 @@ function pathauto_user_update_alias(stdClass $account, $op, array $options = arr
// Skip processing if the account has no pattern.
if (!pathauto_pattern_load_by_entity('user', '', $options['language'])) {
- return;
+ return FALSE;
}
module_load_include('inc', 'pathauto');
$uri = entity_uri('user', $account);
- pathauto_create_alias('user', $op, $uri['path'], array('user' => $account), NULL, $options['language']);
+ $return = pathauto_create_alias('user', $op, $uri['path'], array('user' => $account), NULL, $options['language']);
// Because blogs are also associated with users, also generate the blog paths.
if (!empty($options['alias blog'])) {
pathauto_blog_update_alias($account, $op, $options);
}
+
+ return $return;
}
/**
@@ -805,6 +1129,39 @@ function pathauto_user_update_action($account, $context = array()) {
pathauto_user_update_alias($account, 'bulkupdate', array('message' => TRUE));
}
+/**
+ * @} End of "name pathauto_user".
+ */
+
+/**
+ * @name pathauto_blog Pathauto integration for the core blog module.
+ * @{
+ */
+
+/**
+ * Implements hook_path_alias_types() on behalf of blog module.
+ */
+function blog_path_alias_types() {
+ return array('blog/' => t('User blogs'));
+}
+
+/**
+ * Implements hook_pathauto() on behalf of blog module.
+ */
+function blog_pathauto($op) {
+ if ($op == 'settings') {
+ $settings = array();
+ $settings['module'] = 'blog';
+ $settings['token_type'] = 'user';
+ $settings['groupheader'] = t('Blog paths');
+ $settings['patterndescr'] = t('Pattern for blog page paths');
+ $settings['patterndefault'] = 'blogs/[user:name]';
+ $settings['batch_update_callback'] = 'blog_pathauto_bulk_update_batch_process';
+ $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto.pathauto.inc';
+ return (object) $settings;
+ }
+}
+
/**
* Update the blog URL aliases for an individual user account.
*
@@ -819,7 +1176,7 @@ function pathauto_user_update_action($account, $context = array()) {
function pathauto_blog_update_alias(stdClass $account, $op, array $options = array()) {
// Skip processing if the blog has no pattern.
if (!pathauto_pattern_load_by_entity('blog')) {
- return;
+ return FALSE;
}
$options += array(
@@ -828,7 +1185,7 @@ function pathauto_blog_update_alias(stdClass $account, $op, array $options = arr
module_load_include('inc', 'pathauto');
if (node_access('create', 'blog', $account)) {
- pathauto_create_alias('blog', $op, "blog/{$account->uid}", array('user' => $account), NULL, $options['language']);
+ return pathauto_create_alias('blog', $op, "blog/{$account->uid}", array('user' => $account), NULL, $options['language']);
}
else {
pathauto_path_delete_all("blog/{$account->uid}");
@@ -836,5 +1193,30 @@ function pathauto_blog_update_alias(stdClass $account, $op, array $options = arr
}
/**
- * @} End of "name pathauto_user".
+ * @} End of "name pathauto_blog".
*/
+
+/**
+ * Implements hook_features_pipe_COMPONENT_alter().
+ */
+function pathauto_features_pipe_node_alter(&$pipe, $data, $export) {
+ foreach ($data as $node_type) {
+ $pipe['variable'][] = "pathauto_node_{$node_type}_pattern";
+ if (module_exists('locale')) {
+ $langcodes = array_keys(locale_language_list('name'));
+ $langcodes[] = LANGUAGE_NONE;
+ foreach ($langcodes as $langcode) {
+ $pipe['variable'][] = "pathauto_node_{$node_type}_{$langcode}_pattern";
+ }
+ }
+ }
+}
+
+/**
+ * Implements hook_features_pipe_COMPONENT_alter().
+ */
+function pathauto_features_pipe_taxonomy_alter(&$pipe, $data, $export) {
+ foreach ($data as $vocabulary) {
+ $pipe['variable'][] = "pathauto_taxonomy_term_{$vocabulary}_pattern";
+ }
+}
diff --git a/sites/all/modules/contrib/content/pathauto/pathauto.pathauto.inc b/sites/all/modules/contrib/content/pathauto/pathauto.pathauto.inc
old mode 100755
new mode 100644
index 28d3ce09..23df259c
--- a/sites/all/modules/contrib/content/pathauto/pathauto.pathauto.inc
+++ b/sites/all/modules/contrib/content/pathauto/pathauto.pathauto.inc
@@ -7,79 +7,6 @@
* @ingroup pathauto
*/
-/**
- * Implements hook_path_alias_types().
- *
- * Used primarily by the bulk delete form.
- */
-function pathauto_path_alias_types() {
- $objects['user/'] = t('Users');
- $objects['node/'] = t('Content');
- if (module_exists('blog')) {
- $objects['blog/'] = t('User blogs');
- }
- if (module_exists('taxonomy')) {
- $objects['taxonomy/term/'] = t('Taxonomy terms');
- }
- if (module_exists('forum')) {
- $objects['forum/'] = t('Forums');
- }
- return $objects;
-}
-
-/**
- * Implements hook_pathauto().
- *
- * This function is empty so that the other core module implementations can be
- * defined in this file. This is because in pathauto_module_implements_alter()
- * we add pathauto to be included first. The module system then peforms a
- * check on any subsequent run if this function still exists. If this does not
- * exist, than this file will not get included and the core implementations
- * will never get run.
- *
- * @see pathauto_module_implements_alter().
- */
-function pathauto_pathauto() {
- // Empty hook; see the above comment.
-}
-
-/**
- * Implements hook_pathauto().
- */
-function node_pathauto($op) {
- switch ($op) {
- case 'settings':
- $settings = array();
- $settings['module'] = 'node';
- $settings['token_type'] = 'node';
- $settings['groupheader'] = t('Content paths');
- $settings['patterndescr'] = t('Default path pattern (applies to all content types with blank patterns below)');
- $settings['patterndefault'] = 'content/[node:title]';
- $settings['batch_update_callback'] = 'node_pathauto_bulk_update_batch_process';
- $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto.pathauto.inc';
-
- $languages = array();
- if (module_exists('locale')) {
- $languages = array(LANGUAGE_NONE => t('language neutral')) + locale_language_list('name');
- }
-
- foreach (node_type_get_names() as $node_type => $node_name) {
- if (count($languages) && variable_get('language_content_type_' . $node_type, 0)) {
- $settings['patternitems'][$node_type] = t('Default path pattern for @node_type (applies to all @node_type content types with blank patterns below)', array('@node_type' => $node_name));
- foreach ($languages as $lang_code => $lang_name) {
- $settings['patternitems'][$node_type . '_' . $lang_code] = t('Pattern for all @language @node_type paths', array('@node_type' => $node_name, '@language' => $lang_name));
- }
- }
- else {
- $settings['patternitems'][$node_type] = t('Pattern for all @node_type paths', array('@node_type' => $node_name));
- }
- }
- return (object) $settings;
- default:
- break;
- }
-}
-
/**
* Batch processing callback; Generate aliases for nodes.
*/
@@ -122,38 +49,6 @@ function node_pathauto_bulk_update_batch_process(&$context) {
}
}
-/**
- * Implements hook_pathauto().
- */
-function taxonomy_pathauto($op) {
- switch ($op) {
- case 'settings':
- $settings = array();
- $settings['module'] = 'taxonomy_term';
- $settings['token_type'] = 'term';
- $settings['groupheader'] = t('Taxonomy term paths');
- $settings['patterndescr'] = t('Default path pattern (applies to all vocabularies with blank patterns below)');
- $settings['patterndefault'] = '[term:vocabulary]/[term:name]';
- $settings['batch_update_callback'] = 'taxonomy_pathauto_bulk_update_batch_process';
- $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto.pathauto.inc';
-
- $vocabularies = taxonomy_get_vocabularies();
- if (count($vocabularies)) {
- $settings['patternitems'] = array();
- foreach ($vocabularies as $vid => $vocabulary) {
- if ($vid == variable_get('forum_nav_vocabulary', '')) {
- // Skip the forum vocabulary.
- continue;
- }
- $settings['patternitems'][$vocabulary->machine_name] = t('Pattern for all %vocab-name paths', array('%vocab-name' => $vocabulary->name));
- }
- }
- return (object) $settings;
- default:
- break;
- }
-}
-
/**
* Batch processing callback; Generate aliases for taxonomy terms.
*/
@@ -200,26 +95,6 @@ function taxonomy_pathauto_bulk_update_batch_process(&$context) {
}
}
-/**
- * Implements hook_pathauto() for forum module.
- */
-function forum_pathauto($op) {
- switch ($op) {
- case 'settings':
- $settings = array();
- $settings['module'] = 'forum';
- $settings['token_type'] = 'term';
- $settings['groupheader'] = t('Forum paths');
- $settings['patterndescr'] = t('Pattern for forums and forum containers');
- $settings['patterndefault'] = '[term:vocabulary]/[term:name]';
- $settings['batch_update_callback'] = 'forum_pathauto_bulk_update_batch_process';
- $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto.pathauto.inc';
- return (object) $settings;
- default:
- break;
- }
-}
-
/**
* Batch processing callback; Generate aliases for forums.
*/
@@ -263,26 +138,6 @@ function forum_pathauto_bulk_update_batch_process(&$context) {
}
}
-/**
- * Implements hook_pathauto().
- */
-function user_pathauto($op) {
- switch ($op) {
- case 'settings':
- $settings = array();
- $settings['module'] = 'user';
- $settings['token_type'] = 'user';
- $settings['groupheader'] = t('User paths');
- $settings['patterndescr'] = t('Pattern for user account page paths');
- $settings['patterndefault'] = 'users/[user:name]';
- $settings['batch_update_callback'] = 'user_pathauto_bulk_update_batch_process';
- $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto.pathauto.inc';
- return (object) $settings;
- default:
- break;
- }
-}
-
/**
* Batch processing callback; Generate aliases for users.
*/
@@ -325,26 +180,6 @@ function user_pathauto_bulk_update_batch_process(&$context) {
}
}
-/**
- * Implements hook_pathauto().
- */
-function blog_pathauto($op) {
- switch ($op) {
- case 'settings':
- $settings = array();
- $settings['module'] = 'blog';
- $settings['token_type'] = 'user';
- $settings['groupheader'] = t('Blog paths');
- $settings['patterndescr'] = t('Pattern for blog page paths');
- $settings['patterndefault'] = 'blogs/[user:name]';
- $settings['batch_update_callback'] = 'blog_pathauto_bulk_update_batch_process';
- $settings['batch_file'] = drupal_get_path('module', 'pathauto') . '/pathauto.pathauto.inc';
- return (object) $settings;
- default:
- break;
- }
-}
-
/**
* Batch processing callback; Generate aliases for blogs.
*/
diff --git a/sites/all/modules/contrib/content/pathauto/pathauto.test b/sites/all/modules/contrib/content/pathauto/pathauto.test
old mode 100755
new mode 100644
index 6fa096e8..298f8822
--- a/sites/all/modules/contrib/content/pathauto/pathauto.test
+++ b/sites/all/modules/contrib/content/pathauto/pathauto.test
@@ -55,9 +55,13 @@ class PathautoTestHelper extends DrupalWebTestCase {
$this->assertEntityAlias($entity_type, $entity, $uri['path'], $language);
}
- function assertNoEntityAliasExists($entity_type, $entity) {
+ function assertNoEntityAliasExists($entity_type, $entity, $alias = NULL) {
$uri = entity_uri($entity_type, $entity);
- $this->assertNoAliasExists(array('source' => $uri['path']));
+ $path = array('source' => $uri['path']);
+ if (!empty($alias)) {
+ $path['alias'] = $alias;
+ }
+ $this->assertNoAliasExists($path);
}
function assertAlias($source, $expected_alias, $language = LANGUAGE_NONE) {
@@ -192,6 +196,23 @@ class PathautoUnitTestCase extends PathautoTestHelper {
}
}
+ /**
+ * Test pathauto_clean_alias().
+ */
+ function testCleanAlias() {
+ $tests = array();
+ $tests['one/two/three'] = 'one/two/three';
+ $tests['/one/two/three/'] = 'one/two/three';
+ $tests['one//two///three'] = 'one/two/three';
+ $tests['one/two--three/-/--/-/--/four---five'] = 'one/two-three/four-five';
+ $tests['one/-//three--/four'] = 'one/three/four';
+ foreach ($tests as $input => $expected) {
+ $output = pathauto_clean_alias($input);
+ $this->assertEqual($output, $expected, t("pathauto_clean_alias('@input') expected '@expected', actual '@output'", array('@input' => $input, '@expected' => $expected, '@output' => $output)));
+ }
+
+ }
+
/**
* Test pathauto_path_delete_multiple().
*/
@@ -244,7 +265,7 @@ class PathautoUnitTestCase extends PathautoTestHelper {
$node->title = 'Fifth title';
pathauto_node_update($node);
$this->assertEntityAlias('node', $node, 'content/fourth-title');
- $this->assertNoAliasExists(array('alias' => 'content/fith-title'));
+ $this->assertNoAliasExists(array('alias' => 'content/fifth-title'));
// Test PATHAUTO_UPDATE_ACTION_NO_NEW with unaliased node and 'update'.
$this->deleteAllAliases();
@@ -289,6 +310,40 @@ class PathautoUnitTestCase extends PathautoTestHelper {
$this->assertEntityAlias('taxonomy_term', $term2, 'My Crazy/Alias/child-term');
}
+ /**
+ * Test using fields for path structures.
+ */
+ function testParentChildPathTokens() {
+ // First create a field which will be used to create the path. It must
+ // begin with a letter.
+ $fieldname = 'a' . drupal_strtolower($this->randomName());
+ field_create_field(array('field_name' => $fieldname, 'type' => 'text'));
+ field_create_instance(array('field_name' => $fieldname, 'entity_type' => 'taxonomy_term', 'bundle' => 'tags'));
+
+ // Make the path pattern of a field use the value of this field appended
+ // to the parent taxonomy term's pattern if there is one.
+ variable_set('pathauto_taxonomy_term_tags_pattern', '[term:parents:join-path]/[term:' . $fieldname . ']');
+
+ // Start by creating a parent term.
+ $parent = new stdClass();
+ $parent->$fieldname = array(LANGUAGE_NONE => array(array('value' => $parent->name = $this->randomName())));
+ $parent->vid = 1;
+ taxonomy_term_save($parent);
+
+ // Create the child term.
+ $child = new stdClass();
+ $child->name = $this->randomName();
+ $child->$fieldname = array(LANGUAGE_NONE => array(array('value' => $child->name = $this->randomName())));
+ $child->vid = 1;
+ $child->parent = $parent->tid;
+ taxonomy_term_save($child);
+ $this->assertEntityAlias('taxonomy_term', $child, drupal_strtolower($parent->name . '/' . $child->name));
+
+ // Re-saving the parent term should not modify the child term's alias.
+ taxonomy_term_save($parent);
+ $this->assertEntityAlias('taxonomy_term', $child, drupal_strtolower($parent->name . '/' . $child->name));
+ }
+
function testEntityBundleRenamingDeleting() {
// Create a vocabulary and test that it's pattern variable works.
$vocab = $this->addVocabulary(array('machine_name' => 'old_name'));
@@ -315,17 +370,17 @@ class PathautoUnitTestCase extends PathautoTestHelper {
// Check that Pathauto does not create an alias of '/admin'.
$node = $this->drupalCreateNode(array('title' => 'Admin', 'type' => 'page'));
- $this->assertNoEntityAlias('node', $node);
+ $this->assertEntityAlias('node', $node, 'admin-0');
// Check that Pathauto does not create an alias of '/modules'.
$node->title = 'Modules';
node_save($node);
- $this->assertNoEntityAlias('node', $node);
+ $this->assertEntityAlias('node', $node, 'modules-0');
// Check that Pathauto does not create an alias of '/index.php'.
$node->title = 'index.php';
node_save($node);
- $this->assertNoEntityAlias('node', $node);
+ $this->assertEntityAlias('node', $node, 'index.php-0');
// Check that a safe value gets an automatic alias. This is also a control
// to ensure the above tests work properly.
@@ -333,6 +388,18 @@ class PathautoUnitTestCase extends PathautoTestHelper {
node_save($node);
$this->assertEntityAlias('node', $node, 'safe-value');
}
+
+ function testPathAliasUniquifyWordsafe() {
+ variable_set('pathauto_max_length', 25);
+
+ $node_1 = $this->drupalCreateNode(array('title' => 'thequick brownfox jumpedover thelazydog', 'type' => 'page'));
+ $node_2 = $this->drupalCreateNode(array('title' => 'thequick brownfox jumpedover thelazydog', 'type' => 'page'));
+
+ // Check that pathauto_alias_uniquify is calling truncate_utf8 with $wordsafe param set to TRUE.
+ // If it doesn't path alias result would be content/thequick-brownf-0
+ $this->assertEntityAlias('node', $node_1, 'content/thequick-brownfox');
+ $this->assertEntityAlias('node', $node_2, 'content/thequick-0');
+ }
}
/**
@@ -408,13 +475,23 @@ class PathautoFunctionalTestCase extends PathautoFunctionalTestHelper {
$this->drupalGet($automatic_alias);
$this->assertText($title, 'Node accessible through automatic alias.');
+ // Disable the update action. The checkbox should not be visible.
+ variable_set('pathauto_update_action', 0);
+ $this->drupalGet("node/{$node->nid}/edit");
+ $this->assertNoFieldById('edit-path-pathauto');
+
+ // Reset the update action back to default. The checkbox should be visible.
+ variable_del('pathauto_update_action');
+ $this->drupalGet("node/{$node->nid}/edit");
+ $this->assertFieldChecked('edit-path-pathauto');
+
// Manually set the node's alias.
$manual_alias = 'content/' . $node->nid;
$edit = array(
'path[pathauto]' => FALSE,
'path[alias]' => $manual_alias,
);
- $this->drupalPost("node/{$node->nid}/edit", $edit, t('Save'));
+ $this->drupalPost(NULL, $edit, t('Save'));
$this->assertText("Basic page $title has been updated.");
// Check that the automatic alias checkbox is now unchecked by default.
@@ -449,6 +526,26 @@ class PathautoFunctionalTestCase extends PathautoFunctionalTestHelper {
$this->assertNoFieldById('edit-path-pathauto');
$this->assertFieldByName('path[alias]', '');
$this->assertNoEntityAlias('node', $node);
+
+ // Set the page pattern to use only tokens so we can test the checkbox
+ // behavior if none of the tokens have a value currently.
+ variable_set('pathauto_node_page_pattern', '[node:title]');
+
+ // Create a node with an empty title. The Pathauto checkbox should still be
+ // visible but unchecked.
+ $node = $this->drupalCreateNode(array('type' => 'page', 'title' => ''));
+ $this->drupalGet('node/' . $node->nid . '/edit');
+ $this->assertNoFieldChecked('edit-path-pathauto');
+ $this->assertFieldByName('path[alias]', '');
+ $this->assertNoEntityAlias('node', $node);
+
+ $edit = array();
+ $edit['title'] = 'Valid title';
+ $edit['path[pathauto]'] = TRUE;
+ $this->drupalPost(NULL, $edit, t('Save'));
+ $this->drupalGet('node/' . $node->nid . '/edit');
+ $this->assertFieldChecked('edit-path-pathauto');
+ $this->assertFieldByName('path[alias]', 'valid-title');
}
/**
@@ -472,6 +569,83 @@ class PathautoFunctionalTestCase extends PathautoFunctionalTestHelper {
$this->assertEntityAlias('node', $node2, 'node/' . $node2->nid);
}
+ /**
+ * @todo Merge this with existing node test methods?
+ */
+ public function testNodeState() {
+ $nodeNoAliasUser = $this->drupalCreateUser(array('bypass node access'));
+ $nodeAliasUser = $this->drupalCreateUser(array('bypass node access', 'create url aliases'));
+
+ $node = $this->drupalCreateNode(array(
+ 'title' => 'Node version one',
+ 'type' => 'page',
+ 'path' => array(
+ 'pathauto' => FALSE,
+ ),
+ ));
+
+ $this->assertNoEntityAlias('node', $node);
+
+ // Set a manual path alias for the node.
+ $node->path['alias'] = 'test-alias';
+ node_save($node);
+
+ // Ensure that the pathauto field was saved to the database.
+ $node = node_load($node->nid, NULL, TRUE);
+ $this->assertFalse($node->path['pathauto']);
+
+ // Ensure that the manual path alias was saved and an automatic alias was not generated.
+ $this->assertEntityAlias('node', $node, 'test-alias');
+ $this->assertNoEntityAliasExists('node', $node, 'content/node-version-one');
+
+ // Save the node as a user who does not have access to path fieldset.
+ $this->drupalLogin($nodeNoAliasUser);
+ $this->drupalGet('node/' . $node->nid . '/edit');
+ $this->assertNoFieldByName('path[pathauto]');
+
+ $edit = array('title' => 'Node version two');
+ $this->drupalPost(NULL, $edit, 'Save');
+ $this->assertText('Basic page Node version two has been updated.');
+
+ $this->assertEntityAlias('node', $node, 'test-alias');
+ $this->assertNoEntityAliasExists('node', $node, 'content/node-version-one');
+ $this->assertNoEntityAliasExists('node', $node, 'content/node-version-two');
+
+ // Load the edit node page and check that the Pathauto checkbox is unchecked.
+ $this->drupalLogin($nodeAliasUser);
+ $this->drupalGet('node/' . $node->nid . '/edit');
+ $this->assertNoFieldChecked('edit-path-pathauto');
+
+ // Edit the manual alias and save the node.
+ $edit = array(
+ 'title' => 'Node version three',
+ 'path[alias]' => 'manually-edited-alias',
+ );
+ $this->drupalPost(NULL, $edit, 'Save');
+ $this->assertText('Basic page Node version three has been updated.');
+
+ $this->assertEntityAlias('node', $node, 'manually-edited-alias');
+ $this->assertNoEntityAliasExists('node', $node, 'test-alias');
+ $this->assertNoEntityAliasExists('node', $node, 'content/node-version-one');
+ $this->assertNoEntityAliasExists('node', $node, 'content/node-version-two');
+ $this->assertNoEntityAliasExists('node', $node, 'content/node-version-three');
+
+ // Programatically save the node with an automatic alias.
+ $node = node_load($node->nid, NULL, TRUE);
+ $node->path['pathauto'] = TRUE;
+ node_save($node);
+
+ // Ensure that the pathauto field was saved to the database.
+ $node = node_load($node->nid, NULL, TRUE);
+ $this->assertTrue($node->path['pathauto']);
+
+ $this->assertEntityAlias('node', $node, 'content/node-version-three');
+ $this->assertNoEntityAliasExists('node', $node, 'manually-edited-alias');
+ $this->assertNoEntityAliasExists('node', $node, 'test-alias');
+ $this->assertNoEntityAliasExists('node', $node, 'content/node-version-one');
+ $this->assertNoEntityAliasExists('node', $node, 'content/node-version-two');
+ }
+
/**
* Basic functional testing of Pathauto with taxonomy terms.
*/
@@ -672,6 +846,14 @@ class PathautoLocaleTestCase extends PathautoFunctionalTestHelper {
$this->assertEntityAlias('node', $node, 'content/english-node-0', 'en');
$this->assertEntityAlias('node', $node, 'french-node', 'fr');
$this->assertAliasExists(array('pid' => $english_alias['pid'], 'alias' => 'content/english-node-0'));
+
+ // Create a new node with the same title as before but without
+ // specifying a language.
+ $node = $this->drupalCreateNode(array('title' => 'English node'));
+
+ // Check that the new node had a unique alias generated with the '-1'
+ // suffix.
+ $this->assertEntityAlias('node', $node, 'content/english-node-1');
}
}
@@ -718,11 +900,11 @@ class PathautoBulkUpdateTestCase extends PathautoFunctionalTestHelper {
// Add a new node.
$new_node = $this->drupalCreateNode(array('path' => array('alias' => '', 'pathauto' => FALSE)));
- // Run the update again which should only run against the new node.
+ // Run the update again which should not run against any nodes.
$this->drupalPost('admin/config/search/path/update_bulk', $edit, t('Update'));
- $this->assertText('Generated 1 URL alias.'); // 1 node + 0 users
+ $this->assertText('No new URL aliases to generate.');
- $this->assertEntityAliasExists('node', $new_node);
+ $this->assertNoEntityAliasExists('node', $new_node);
}
}
diff --git a/sites/all/modules/contrib/content/pathauto/pathauto.tokens.inc b/sites/all/modules/contrib/content/pathauto/pathauto.tokens.inc
old mode 100755
new mode 100644
index a0f0b49b..dabcaa88
--- a/sites/all/modules/contrib/content/pathauto/pathauto.tokens.inc
+++ b/sites/all/modules/contrib/content/pathauto/pathauto.tokens.inc
@@ -35,7 +35,7 @@ function pathauto_tokens($type, $tokens, array $data = array(), array $options =
$values = array();
foreach (element_children($array) as $key) {
$value = is_array($array[$key]) ? render($array[$key]) : (string) $array[$key];
- $value = pathauto_cleanstring($value);
+ $value = pathauto_cleanstring($value, $options);
$values[] = $value;
}
$replacements[$original] = implode('/', $values);
diff --git a/sites/all/modules/contrib/dev/ctools/bulk_export/bulk_export.info b/sites/all/modules/contrib/dev/ctools/bulk_export/bulk_export.info
index 1e9031d7..22dc566a 100644
--- a/sites/all/modules/contrib/dev/ctools/bulk_export/bulk_export.info
+++ b/sites/all/modules/contrib/dev/ctools/bulk_export/bulk_export.info
@@ -6,9 +6,9 @@ package = Chaos tool suite
version = CTOOLS_MODULE_VERSION
-; Information added by Drupal.org packaging script on 2015-01-28
-version = "7.x-1.6"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
core = "7.x"
project = "ctools"
-datestamp = "1422471484"
+datestamp = "1479787162"
diff --git a/sites/all/modules/contrib/dev/ctools/css/button.css b/sites/all/modules/contrib/dev/ctools/css/button.css
index 15e484be..ead8f8ef 100644
--- a/sites/all/modules/contrib/dev/ctools/css/button.css
+++ b/sites/all/modules/contrib/dev/ctools/css/button.css
@@ -19,6 +19,7 @@
.ctools-button-processed .ctools-content ul {
list-style-image: none;
list-style-type: none;
+ margin-left: 0;
}
.ctools-button-processed li {
diff --git a/sites/all/modules/contrib/dev/ctools/css/modal-rtl.css b/sites/all/modules/contrib/dev/ctools/css/modal-rtl.css
new file mode 100644
index 00000000..5231b9fe
--- /dev/null
+++ b/sites/all/modules/contrib/dev/ctools/css/modal-rtl.css
@@ -0,0 +1,60 @@
+div.ctools-modal-content {
+ text-align: right;
+}
+
+div.ctools-modal-content .modal-header {
+ background-color: #2385c2;
+ padding: 0 1em 0 .25em;
+}
+
+div.ctools-modal-content a.close {
+ color: white;
+ float: left;
+}
+
+/** modal forms CSS **/
+div.ctools-modal-content .form-item label {
+ float: right;
+}
+
+div.ctools-modal-content .form-item .description {
+ clear: right;
+}
+
+div.ctools-modal-content .form-item .description .tips {
+ margin-left: 0;
+ margin-right: 2em;
+}
+
+div.ctools-modal-content fieldset,
+div.ctools-modal-content .form-radios,
+div.ctools-modal-content .form-checkboxes {
+ clear: right;
+}
+
+div.ctools-modal-content .resizable-textarea {
+ margin-left: 5em;
+ margin-right: 15em;
+}
+
+div.ctools-modal-content .container-inline .form-item {
+ margin-right: 0;
+ margin-left: 2em;
+}
+
+div.ctools-modal-content label.hidden-options {
+ background-position: left;
+ padding-right: 0;
+ padding-left: 12px;
+}
+
+div.ctools-modal-content label.expanded-options {
+ background-position: left;
+ padding-right: 0;
+ padding-left: 16px;
+}
+
+div.ctools-modal-content .dependent-options {
+ padding-left: 0;
+ padding-right: 30px;
+}
diff --git a/sites/all/modules/contrib/dev/ctools/ctools.api.php b/sites/all/modules/contrib/dev/ctools/ctools.api.php
index a7ab7839..f328a7ca 100644
--- a/sites/all/modules/contrib/dev/ctools/ctools.api.php
+++ b/sites/all/modules/contrib/dev/ctools/ctools.api.php
@@ -199,7 +199,10 @@ function hook_ctools_render_alter(&$info, &$page, &$context) {
* or categories or to rename content on specific sites.
*/
function hook_ctools_content_subtype_alter($subtype, $plugin) {
- $subtype['render last'] = TRUE;
+ // Force a particular subtype of a particular plugin to render last.
+ if ($plugin['module'] == 'some_plugin_module' && $plugin['name'] == 'some_plugin_name' && $subtype['subtype_id'] == 'my_subtype_id') {
+ $subtype['render last'] = TRUE;
+ }
}
/**
diff --git a/sites/all/modules/contrib/dev/ctools/ctools.info b/sites/all/modules/contrib/dev/ctools/ctools.info
index bd2e3c1d..3a2d031e 100644
--- a/sites/all/modules/contrib/dev/ctools/ctools.info
+++ b/sites/all/modules/contrib/dev/ctools/ctools.info
@@ -2,16 +2,23 @@ name = Chaos tools
description = A library of helpful tools by Merlin of Chaos.
core = 7.x
package = Chaos tool suite
-version = CTOOLS_MODULE_VERSION
files[] = includes/context.inc
files[] = includes/css-cache.inc
files[] = includes/math-expr.inc
files[] = includes/stylizer.inc
-files[] = tests/css_cache.test
-; Information added by Drupal.org packaging script on 2015-01-28
-version = "7.x-1.6"
+; Tests.
+files[] = tests/context.test
+files[] = tests/css.test
+files[] = tests/css_cache.test
+files[] = tests/ctools.plugins.test
+files[] = tests/math_expression.test
+files[] = tests/math_expression_stack.test
+files[] = tests/object_cache.test
+
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
core = "7.x"
project = "ctools"
-datestamp = "1422471484"
+datestamp = "1479787162"
diff --git a/sites/all/modules/contrib/dev/ctools/ctools.module b/sites/all/modules/contrib/dev/ctools/ctools.module
index c37b96f6..78ac26bc 100644
--- a/sites/all/modules/contrib/dev/ctools/ctools.module
+++ b/sites/all/modules/contrib/dev/ctools/ctools.module
@@ -9,7 +9,7 @@
* must be implemented in the module file.
*/
-define('CTOOLS_API_VERSION', '2.0.8');
+define('CTOOLS_API_VERSION', '2.0.9');
/**
* The current working ctools version.
@@ -23,7 +23,7 @@ define('CTOOLS_API_VERSION', '2.0.8');
* ; Requires CTools v7.x-1.4 or newer.
* dependencies[] = ctools (>=1.4)
*/
-define('CTOOLS_MODULE_VERSION', '7.x-1.6');
+define('CTOOLS_MODULE_VERSION', '7.x-1.11');
/**
* Test the CTools API version.
@@ -617,6 +617,27 @@ function ctools_registry_files_alter(&$files, $indexed_modules) {
return _ctools_registry_files_alter($files, $indexed_modules);
}
+// -----------------------------------------------------------------------
+// FAPI hooks that must be in the .module file.
+
+/**
+ * Alter the comment form to get a little more control over it.
+ */
+function ctools_form_comment_form_alter(&$form, &$form_state) {
+ if (!empty($form_state['ctools comment alter'])) {
+ // Force the form to post back to wherever we are.
+ $form['#action'] = url($_GET['q'], array('fragment' => 'comment-form'));
+ if (empty($form['#submit'])) {
+ $form['#submit'] = array('comment_form_submit');
+ }
+ $form['#submit'][] = 'ctools_node_comment_form_submit';
+ }
+}
+
+function ctools_node_comment_form_submit(&$form, &$form_state) {
+ $form_state['redirect'][0] = $_GET['q'];
+}
+
// -----------------------------------------------------------------------
// CTools hook implementations.
@@ -737,6 +758,12 @@ function ctools_process(&$variables, $hook) {
$variables['classes_array'] = array_diff($variables['classes_array'], $remove_classes);
}
+ // Update the classes within the attributes array to match the classes array
+ if (isset($variables['attributes_array']['class'])) {
+ $variables['attributes_array']['class'] = array_unique(array_merge($variables['classes_array'], $variables['attributes_array']['class']));
+ $variables['attributes'] = $variables['attributes_array'] ? drupal_attributes($variables['attributes_array']) : '';
+ }
+
// Since this runs after template_process(), we need to re-implode the
// classes array.
$variables['classes'] = implode(' ', $variables['classes_array']);
@@ -1018,3 +1045,50 @@ function ctools_ctools_entity_context_alter(&$plugin, &$entity, $plugin_id) {
}
}
}
+
+/**
+ * Implements hook_field_create_field().
+ */
+function ctools_field_create_field($field) {
+ ctools_flush_field_caches();
+}
+
+/**
+ * Implements hook_field_create_instance().
+ */
+function ctools_field_create_instance($instance) {
+ ctools_flush_field_caches();
+}
+/**
+ * Implements hook_field_delete_field().
+ */
+function ctools_field_delete_field($field) {
+ ctools_flush_field_caches();
+}
+/**
+ * Implements hook_field_delete_instance().
+ */
+function ctools_field_delete_instance($instance) {
+ ctools_flush_field_caches();
+}
+/**
+ * Implements hook_field_update_field().
+ */
+function ctools_field_update_field($field, $prior_field, $has_data) {
+ ctools_flush_field_caches();
+}
+
+/**
+ * Implements hook_field_update_instance().
+ */
+function ctools_field_update_instance($instance, $prior_instance) {
+ ctools_flush_field_caches();
+}
+
+/**
+ * Clear field related caches.
+ */
+function ctools_flush_field_caches() {
+ // Clear caches of 'Entity field' content type plugin.
+ cache_clear_all('ctools_entity_field_content_type_content_types', 'cache');
+}
diff --git a/sites/all/modules/contrib/dev/ctools/ctools_access_ruleset/ctools_access_ruleset.info b/sites/all/modules/contrib/dev/ctools/ctools_access_ruleset/ctools_access_ruleset.info
index 2180cec1..bfa17834 100644
--- a/sites/all/modules/contrib/dev/ctools/ctools_access_ruleset/ctools_access_ruleset.info
+++ b/sites/all/modules/contrib/dev/ctools/ctools_access_ruleset/ctools_access_ruleset.info
@@ -5,9 +5,9 @@ package = Chaos tool suite
version = CTOOLS_MODULE_VERSION
dependencies[] = ctools
-; Information added by Drupal.org packaging script on 2015-01-28
-version = "7.x-1.6"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
core = "7.x"
project = "ctools"
-datestamp = "1422471484"
+datestamp = "1479787162"
diff --git a/sites/all/modules/contrib/dev/ctools/ctools_ajax_sample/ctools_ajax_sample.info b/sites/all/modules/contrib/dev/ctools/ctools_ajax_sample/ctools_ajax_sample.info
index 009662fa..52126d51 100644
--- a/sites/all/modules/contrib/dev/ctools/ctools_ajax_sample/ctools_ajax_sample.info
+++ b/sites/all/modules/contrib/dev/ctools/ctools_ajax_sample/ctools_ajax_sample.info
@@ -5,9 +5,9 @@ version = CTOOLS_MODULE_VERSION
dependencies[] = ctools
core = 7.x
-; Information added by Drupal.org packaging script on 2015-01-28
-version = "7.x-1.6"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
core = "7.x"
project = "ctools"
-datestamp = "1422471484"
+datestamp = "1479787162"
diff --git a/sites/all/modules/contrib/dev/ctools/ctools_ajax_sample/ctools_ajax_sample.module b/sites/all/modules/contrib/dev/ctools/ctools_ajax_sample/ctools_ajax_sample.module
index 2a30c2a5..4638ac34 100644
--- a/sites/all/modules/contrib/dev/ctools/ctools_ajax_sample/ctools_ajax_sample.module
+++ b/sites/all/modules/contrib/dev/ctools/ctools_ajax_sample/ctools_ajax_sample.module
@@ -524,7 +524,7 @@ function ctools_ajax_sample_wizard_next(&$form_state) {
}
/**
- * Handle the 'finish' click on teh add/edit pane form wizard.
+ * Handle the 'finish' click on the add/edit pane form wizard.
*
* All we need to do is set a flag so the return can handle adding
* the pane.
diff --git a/sites/all/modules/contrib/dev/ctools/ctools_custom_content/ctools_custom_content.info b/sites/all/modules/contrib/dev/ctools/ctools_custom_content/ctools_custom_content.info
index b991d610..ee2d2d1e 100644
--- a/sites/all/modules/contrib/dev/ctools/ctools_custom_content/ctools_custom_content.info
+++ b/sites/all/modules/contrib/dev/ctools/ctools_custom_content/ctools_custom_content.info
@@ -5,9 +5,9 @@ package = Chaos tool suite
version = CTOOLS_MODULE_VERSION
dependencies[] = ctools
-; Information added by Drupal.org packaging script on 2015-01-28
-version = "7.x-1.6"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
core = "7.x"
project = "ctools"
-datestamp = "1422471484"
+datestamp = "1479787162"
diff --git a/sites/all/modules/contrib/dev/ctools/ctools_custom_content/plugins/export_ui/ctools_custom_content_ui.class.php b/sites/all/modules/contrib/dev/ctools/ctools_custom_content/plugins/export_ui/ctools_custom_content_ui.class.php
index 56fe4b21..b22b0610 100644
--- a/sites/all/modules/contrib/dev/ctools/ctools_custom_content/plugins/export_ui/ctools_custom_content_ui.class.php
+++ b/sites/all/modules/contrib/dev/ctools/ctools_custom_content/plugins/export_ui/ctools_custom_content_ui.class.php
@@ -23,6 +23,22 @@ class ctools_custom_content_ui extends ctools_export_ui {
'#title' => t('Title'),
);
+ $form['title_heading'] = array(
+ '#title' => t('Title heading'),
+ '#type' => 'select',
+ '#default_value' => isset($form_state['item']->settings['title_heading']) ? $form_state['item']->settings['title_heading'] : 'h2',
+ '#options' => array(
+ 'h1' => t('h1'),
+ 'h2' => t('h2'),
+ 'h3' => t('h3'),
+ 'h4' => t('h4'),
+ 'h5' => t('h5'),
+ 'h6' => t('h6'),
+ 'div' => t('div'),
+ 'span' => t('span'),
+ ),
+ );
+
$form['body'] = array(
'#type' => 'text_format',
'#title' => t('Body'),
@@ -43,6 +59,7 @@ class ctools_custom_content_ui extends ctools_export_ui {
// Since items in our settings are not in the schema, we have to do these manually:
$form_state['item']->settings['title'] = $form_state['values']['title'];
+ $form_state['item']->settings['title_heading'] = $form_state['values']['title_heading'];
$form_state['item']->settings['body'] = $form_state['values']['body']['value'];
$form_state['item']->settings['format'] = $form_state['values']['body']['format'];
$form_state['item']->settings['substitute'] = $form_state['values']['substitute'];
diff --git a/sites/all/modules/contrib/dev/ctools/ctools_plugin_example/ctools_plugin_example.info b/sites/all/modules/contrib/dev/ctools/ctools_plugin_example/ctools_plugin_example.info
index f526be6b..337e699d 100644
--- a/sites/all/modules/contrib/dev/ctools/ctools_plugin_example/ctools_plugin_example.info
+++ b/sites/all/modules/contrib/dev/ctools/ctools_plugin_example/ctools_plugin_example.info
@@ -8,9 +8,9 @@ dependencies[] = page_manager
dependencies[] = advanced_help
core = 7.x
-; Information added by Drupal.org packaging script on 2015-01-28
-version = "7.x-1.6"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
core = "7.x"
project = "ctools"
-datestamp = "1422471484"
+datestamp = "1479787162"
diff --git a/sites/all/modules/contrib/dev/ctools/drush/ctools.drush.inc b/sites/all/modules/contrib/dev/ctools/drush/ctools.drush.inc
index 1862dbe9..0342c734 100644
--- a/sites/all/modules/contrib/dev/ctools/drush/ctools.drush.inc
+++ b/sites/all/modules/contrib/dev/ctools/drush/ctools.drush.inc
@@ -64,7 +64,7 @@ function ctools_drush_command() {
'machine names' => 'Space separated list of exportables you want to view.',
),
'options' => array(
- 'indent' => 'The string to use for indentation when dispalying the exportable export code. Defaults to \'\'.',
+ 'indent' => 'The string to use for indentation when displaying the exportable export code. Defaults to \'\'.',
'no-colour' => 'Remove any colour formatting from export string output. Ideal if you are sending the output of this command to a file.',
'module' => $module_text,
'all' => $all_text,
diff --git a/sites/all/modules/contrib/dev/ctools/includes/content.inc b/sites/all/modules/contrib/dev/ctools/includes/content.inc
index b4660b43..6490d8d5 100644
--- a/sites/all/modules/contrib/dev/ctools/includes/content.inc
+++ b/sites/all/modules/contrib/dev/ctools/includes/content.inc
@@ -155,6 +155,11 @@ function ctools_content_get_subtypes($type) {
// Walk through the subtypes and ensure minimal settings are
// retained.
foreach ($subtypes as $id => $subtype) {
+ // Ensure that the 'subtype_id' value exists.
+ if (!isset($subtype['subtype_id'])) {
+ $subtype['subtype_id'] = $id;
+ }
+
// Use exact name since this is a modify by reference.
ctools_content_prepare_subtype($subtypes[$id], $plugin);
}
@@ -217,6 +222,7 @@ function ctools_content_prepare_subtype(&$subtype, $plugin) {
}
}
+ // Trigger hook_ctools_content_subtype_alter().
drupal_alter('ctools_content_subtype', $subtype, $plugin);
}
@@ -241,8 +247,8 @@ function ctools_content_prepare_subtype(&$subtype, $plugin) {
* Any incoming content, if this display is a wrapper.
*
* @return
- * The content as rendered by the plugin. This content should be an array
- * with the following possible keys:
+ * The content as rendered by the plugin, or NULL.
+ * This content should be an object with the following possible properties:
* - title: The safe to render title of the content.
* - title_heading: The title heading.
* - content: The safe to render HTML content.
@@ -341,7 +347,16 @@ function ctools_content_editable($type, $subtype, $conf) {
return FALSE;
}
- if ($function = ctools_plugin_get_function($subtype, 'check editable')) {
+ $function = FALSE;
+
+ if (!empty($subtype['check editable'])) {
+ $function = ctools_plugin_get_function($subtype, 'check editable');
+ }
+ elseif (!empty($type['check editable'])) {
+ $function = ctools_plugin_get_function($type, 'check editable');
+ }
+
+ if ($function) {
return $function($type, $subtype, $conf);
}
diff --git a/sites/all/modules/contrib/dev/ctools/includes/content.menu.inc b/sites/all/modules/contrib/dev/ctools/includes/content.menu.inc
index ba32cb50..f7f93406 100644
--- a/sites/all/modules/contrib/dev/ctools/includes/content.menu.inc
+++ b/sites/all/modules/contrib/dev/ctools/includes/content.menu.inc
@@ -23,12 +23,13 @@ function ctools_content_menu(&$items) {
/**
* Helper function for autocompletion of entity titles.
*/
-function ctools_content_autocomplete_entity($type, $string = '') {
+function ctools_content_autocomplete_entity($entity_type, $string = '') {
if ($string != '') {
- global $user;
- $entity_info = entity_get_info($type);
- if ($type == 'node') {
- $entity_info['entity keys']['bundle field'] = 'type';
+ $entity_info = entity_get_info($entity_type);
+
+ if (!module_exists('entity')) {
+ module_load_include('inc', 'ctools', 'includes/entity-access');
+ _ctools_entity_access($entity_info, $entity_type);
}
// We must query all ids, because if every one of the 10 don't have access
@@ -42,25 +43,19 @@ function ctools_content_autocomplete_entity($type, $string = '') {
// If an ID match was found, use that ID rather than the whole string.
if ($match) {
$entity_id = $preg_matches[1];
- $entity = entity_load($type, array($entity_id));
-
- // Format results in an array so later we could add attributes to the
- // autocomplete text that is returned.
- $results = array($entity_id => array(
- 'label' => $entity[$entity_id]->$entity_info['entity keys']['label'],
- ));
+ $results = _ctools_getReferencableEntities($entity_type, $entity_info, $entity_id, '=', 1);
}
else {
- $results = _ctools_getReferencableEntities($type, $entity_info, $string, 'LIKE', 10);
+ // We cannot find results if the entity doesn't have a label to search.
+ if (!isset($entity_info['entity keys']['label'])) {
+ drupal_json_output(array("[id: NULL]" => '' . t('Entity Type !entity_type does not support autocomplete search.', array('!entity_type' => $entity_type)) . ''));
+ return;
+ }
+ $results = _ctools_getReferencableEntities($entity_type, $entity_info, $string, 'LIKE', 10);
}
- foreach($results as $entity_id => $result) {
- if (!$entity_info['entity keys']['label']) {
- $matches["[id: $entity_id]"] = '' . $entity_id . '';
- }
- else {
- $matches[$result['label'] . " [id: $entity_id]"] = '' . check_plain($result['label']) . '';
- $matches[$result['label'] . " [id: $entity_id]"] .= isset($result['bundle field']) ? ' (' . check_plain($result['bundle field']) . ')' : '';
- }
+ foreach ($results as $entity_id => $result) {
+ $matches[$result['label'] . " [id: $entity_id]"] = '' . check_plain($result['label']) . '';
+ $matches[$result['label'] . " [id: $entity_id]"] .= isset($result['bundle']) ? ' (' . check_plain($result['bundle']) . ')' : '';
}
drupal_json_output($matches);
@@ -73,53 +68,53 @@ function ctools_content_autocomplete_entity($type, $string = '') {
*/
function _ctools_buildQuery($entity_type, $entity_info, $match = NULL, $match_operator = 'CONTAINS') {
$base_table = $entity_info['base table'];
- $query = db_select($base_table)
- ->fields($base_table, array($entity_info['entity keys']['id']));
+ $label_key = $entity_info['entity keys']['label'];
+ $query = db_select($base_table)
+ ->fields($base_table, array($entity_info['entity keys']['id']));
- if (isset($match)) {
- if (isset($entity_info['entity keys']['label'])) {
- $query->condition($base_table .'.'. $entity_info['entity keys']['label'], '%' . $match . '%' , $match_operator);
- }
- }
-
- // Add a label to the query, if the label exists
- if (isset($entity_info['entity keys']['label'])) {
- $query->fields($base_table, array($entity_info['entity keys']['label']));
- }
-
- // Add bundle field to the query, if it exists.
- if (isset($entity_info['entity keys']['bundle field'])) {
- $query->fields($base_table, array($entity_info['entity keys']['bundle field']));
- }
-
- // Add a generic entity access tag to the query.
- $query->addTag('ctools');
-
- if($entity_type == 'comment') {
- // Adding the 'comment_access' tag is sadly insufficient for comments: core
- // requires us to also know about the concept of 'published' and
- // 'unpublished'.
- if (!user_access('administer comments')) {
- $query->condition('comment.status', COMMENT_PUBLISHED);
- }
- // Join to a node if the user does not have node access bypass permissions
- // to obey node published permissions
- if (!user_access('bypass node access') && !count(module_implements('node_grants'))) {
- $node_alias = $query->innerJoin('node', 'n', '%alias.nid = comment.nid');
- $query->condition($node_alias . '.status', NODE_PUBLISHED);
- }
- $query->addTag('node_access');
+ if (isset($match)) {
+ if (isset($label_key)) {
+ $query->condition($base_table . '.' . $label_key, '%' . $match . '%', $match_operator);
}
+ // This should never happen, but double check just in case.
else {
- $query->addTag($entity_type . '_access');
+ return array();
+ }
+ }
+ // Add a generic entity access tag to the query.
+ $query->addTag('ctools');
+
+ // We have to perform two checks. First check is a query alter (with tags)
+ // in an attempt to only return results that have access. However, this is
+ // not full-proof since entities many not implement hook_access query tag.
+ // This is why we have a second check after entity load, before we display
+ // the label of an entity.
+ if ($entity_type == 'comment') {
+ // Adding the 'comment_access' tag is sadly insufficient for comments: core
+ // requires us to also know about the concept of 'published' and
+ // 'unpublished'.
+ if (!user_access('administer comments')) {
+ $query->condition('comment.status', COMMENT_PUBLISHED);
}
- // Add the sort option.
- if(isset($entity_info['entity keys']['label'])) {
- $query->orderBy($base_table .'.'. $entity_info['entity keys']['label'], 'ASC');
+ // Join to a node if the user does not have node access bypass permissions
+ // to obey node published permissions
+ if (!user_access('bypass node access')) {
+ $node_alias = $query->innerJoin('node', 'n', '%alias.nid = comment.nid');
+ $query->condition($node_alias . '.status', NODE_PUBLISHED);
}
+ $query->addTag('node_access');
+ }
+ else {
+ $query->addTag($entity_type . '_access');
+ }
- return $query;
+ // Add the sort option.
+ if (isset($label_key)) {
+ $query->orderBy($base_table . '.' . $label_key, 'ASC');
+ }
+
+ return $query;
}
/**
@@ -127,23 +122,58 @@ function _ctools_buildQuery($entity_type, $entity_info, $match = NULL, $match_op
* Entity Reference module.
*/
function _ctools_getReferencableEntities($entity_type, $entity_info, $match = NULL, $match_operator = 'LIKE', $limit = 0) {
+ global $user;
+ $account = $user;
$options = array();
-
- $query = _ctools_buildQuery($entity_type, $entity_info, $match, $match_operator);
- if ($limit > 0) {
- $query->range(0, $limit);
- }
-
- $results = $query->execute();
-
- if (!empty($results)) {
- foreach ($results as $record) {
- $options[$record->{$entity_info['entity keys']['id']}] = array(
- 'label' => isset($entity_info['entity keys']['label']) ? check_plain($record->{$entity_info['entity keys']['label']}) : $record->{$entity_info['entity keys']['id']},
- 'bundle field' => isset($entity_info['entity keys']['bundle field']) ? check_plain($record->{$entity_info['entity keys']['bundle field']}) : '',
- );
+ // We're an entity ID, return the id
+ if (is_numeric($match) && $match_operator == '=') {
+ if ($entity = array_shift(entity_load($entity_type, array($match)))) {
+ if (isset($entity_info['access callback']) && function_exists($entity_info['access callback'])) {
+ if ($entity_info['access callback']('view', $entity, $account, $entity_type)) {
+ $label = entity_label($entity_type, $entity);
+ return array(
+ $match => array(
+ 'label' => !empty($label) ? $label : $entity->{$entity_info['entity keys']['id']},
+ 'bundle' => !empty($entity_info['entity keys']['bundle']) ? check_plain($entity->{$entity_info['entity keys']['bundle']}) : NULL,
+ ),
+ );
+ }
+ }
}
+ // If you don't have access, or an access callback or a valid entity, just
+ // Return back the Entity ID.
+ return array(
+ $match => array(
+ 'label' => $match,
+ 'bundle' => NULL,
+ ),
+ );
}
- return $options;
-}
\ No newline at end of file
+ // We have matches, build a query to fetch the result.
+ if ($query = _ctools_buildQuery($entity_type, $entity_info, $match, $match_operator)) {
+ if ($limit > 0) {
+ $query->range(0, $limit);
+ }
+
+ $results = $query->execute();
+
+ if (!empty($results)) {
+ foreach ($results as $record) {
+ $entities = entity_load($entity_type, array($record->{$entity_info['entity keys']['id']}));
+ $entity = array_shift($entities);
+ if (isset($entity_info['access callback']) && function_exists($entity_info['access callback'])) {
+ if ($entity_info['access callback']('view', $entity, $account, $entity_type)) {
+ $label = entity_label($entity_type, $entity);
+ $options[$record->{$entity_info['entity keys']['id']}] = array(
+ 'label' => !empty($label) ? $label : $entity->{$entity_info['entity keys']['id']},
+ 'bundle' => !empty($entity_info['entity keys']['bundle']) ? check_plain($entity->{$entity_info['entity keys']['bundle']}) : NULL,
+ );
+ }
+ }
+ }
+ }
+ return $options;
+ }
+ return array();
+}
diff --git a/sites/all/modules/contrib/dev/ctools/includes/context-access-admin.inc b/sites/all/modules/contrib/dev/ctools/includes/context-access-admin.inc
index 76643cf6..ea2a7c81 100644
--- a/sites/all/modules/contrib/dev/ctools/includes/context-access-admin.inc
+++ b/sites/all/modules/contrib/dev/ctools/includes/context-access-admin.inc
@@ -367,7 +367,6 @@ function ctools_access_ajax_edit($fragment = NULL, $id = NULL) {
'contexts' => $contexts,
'title' => t('Edit criteria'),
'ajax' => TRUE,
- 'ajax' => TRUE,
'modal' => TRUE,
'modal return' => TRUE,
);
diff --git a/sites/all/modules/contrib/dev/ctools/includes/context-admin.inc b/sites/all/modules/contrib/dev/ctools/includes/context-admin.inc
index 2d8c8f97..821a5b32 100644
--- a/sites/all/modules/contrib/dev/ctools/includes/context-admin.inc
+++ b/sites/all/modules/contrib/dev/ctools/includes/context-admin.inc
@@ -376,11 +376,11 @@ function ctools_context_ajax_item_add($mechanism = NULL, $type = NULL, $cache_ke
'path' => "ctools/context/ajax/add/$mechanism/$type/$cache_key/$name/%step",
'show cancel' => TRUE,
'default form' => 'ctools_edit_context_form_defaults',
- 'auto caching' => TRUE,
+ 'auto cache' => TRUE,
'cache mechanism' => $mechanism,
'cache key' => $cache_key,
// This is stating what the cache will be referred to in $form_state
- 'cache storage' => 'object',
+ 'cache location' => 'object',
);
if ($type == 'requiredcontext') {
@@ -561,11 +561,11 @@ function ctools_context_ajax_item_edit($mechanism = NULL, $type = NULL, $cache_k
'path' => "ctools/context/ajax/configure/$mechanism/$type/$cache_key/$position/%step",
'show cancel' => TRUE,
'default form' => 'ctools_edit_context_form_defaults',
- 'auto caching' => TRUE,
+ 'auto cache' => TRUE,
'cache mechanism' => $mechanism,
'cache key' => $cache_key,
// This is stating what the cache will be referred to in $form_state
- 'cache storage' => 'object',
+ 'cache location' => 'object',
);
if ($type == 'requiredcontext') {
@@ -736,6 +736,15 @@ function ctools_edit_context_form_defaults($form, &$form_state) {
'#default_value' => $conf['keyword'],
);
+ if ($type_info['key'] == 'requiredcontexts') {
+ $form['optional'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Context is optional'),
+ '#default_value' => !empty($form_state['conf']['optional']),
+ '#description' => t('This context need not be present for the component to function.'),
+ );
+ }
+
$form['#submit'][] = 'ctools_edit_context_form_defaults_submit';
return $form;
@@ -752,6 +761,9 @@ function ctools_edit_context_form_defaults_submit(&$form, &$form_state) {
$form_state['conf']['default'] = $form_state['values']['default'];
$form_state['conf']['title'] = $form_state['values']['title'];
}
+ if ($form_state['type info']['key'] == 'requiredcontexts') {
+ $form_state['conf']['optional'] = $form_state['values']['optional'];
+ }
$form_state['conf']['identifier'] = $form_state['values']['identifier'];
$form_state['conf']['keyword'] = $form_state['values']['keyword'];
diff --git a/sites/all/modules/contrib/dev/ctools/includes/context.inc b/sites/all/modules/contrib/dev/ctools/includes/context.inc
index 6628b5f9..a532f657 100644
--- a/sites/all/modules/contrib/dev/ctools/includes/context.inc
+++ b/sites/all/modules/contrib/dev/ctools/includes/context.inc
@@ -42,7 +42,7 @@ class ctools_context {
var $restrictions = array();
var $empty = FALSE;
- function ctools_context($type = 'none', $data = NULL) {
+ function __construct($type = 'none', $data = NULL) {
$this->type = $type;
$this->data = $data;
$this->title = t('Unknown context');
@@ -119,7 +119,7 @@ class ctools_context_required {
* @param ...
* One or more keywords to use for matching which contexts are allowed.
*/
- function ctools_context_required($title) {
+ function __construct($title) {
$args = func_get_args();
$this->title = array_shift($args);
@@ -204,10 +204,6 @@ class ctools_context_required {
*/
class ctools_context_optional extends ctools_context_required {
var $required = FALSE;
- function ctools_context_optional() {
- $args = func_get_args();
- call_user_func_array(array($this, 'ctools_context_required'), $args);
- }
/**
* Add the 'empty' context which is possible for optional
@@ -216,7 +212,7 @@ class ctools_context_optional extends ctools_context_required {
$context = new ctools_context('any');
$context->title = t('No context');
$context->identifier = t('No context');
- $contexts = array_merge(array('empty' => $context), $contexts);
+ $contexts['empty'] = $context;
}
function filter($contexts) {
@@ -680,14 +676,19 @@ function ctools_context_keyword_substitute($string, $keywords, $contexts, $conve
}
}
- if (empty($context_keywords[$context]) || !empty($context_keywords[$context]->empty)) {
- $keywords['%' . $keyword] = '';
- }
- else if (!empty($converter)) {
- $keywords['%' . $keyword] = ctools_context_convert_context($context_keywords[$context], $converter, $converter_options);
+ if (!isset($context_keywords[$context])) {
+ $keywords['%' . $keyword] = '%' . $keyword;
}
else {
- $keywords['%' . $keyword] = $context_keywords[$keyword]->title;
+ if (empty($context_keywords[$context]) || !empty($context_keywords[$context]->empty)) {
+ $keywords['%' . $keyword] = '';
+ }
+ else if (!empty($converter)) {
+ $keywords['%' . $keyword] = ctools_context_convert_context($context_keywords[$context], $converter, $converter_options);
+ }
+ else {
+ $keywords['%' . $keyword] = $context_keywords[$keyword]->title;
+ }
}
}
}
@@ -1163,7 +1164,7 @@ function ctools_context_match_required_contexts($required, $contexts) {
}
foreach ($required as $r) {
- $context = clone(array_shift($contexts));
+ $context = clone array_shift($contexts);
$context->identifier = $r['identifier'];
$context->page_title = isset($r['title']) ? $r['title'] : '';
$context->keyword = $r['keyword'];
@@ -1505,7 +1506,7 @@ function ctools_access($settings, $contexts = array()) {
return TRUE;
}
else if (!$pass && $settings['logic'] == 'and') {
- // Fail if 'and' and htis rule failed.
+ // Fail if 'and' and this rule failed.
return FALSE;
}
}
diff --git a/sites/all/modules/contrib/dev/ctools/includes/css.inc b/sites/all/modules/contrib/dev/ctools/includes/css.inc
index 9813a872..8cf5ed40 100644
--- a/sites/all/modules/contrib/dev/ctools/includes/css.inc
+++ b/sites/all/modules/contrib/dev/ctools/includes/css.inc
@@ -172,10 +172,12 @@ function ctools_css_cache($css, $filter = TRUE) {
// @todo Is this slow? Does it matter if it is?
$filename = $path . '/' . md5($css) . '.css';
- // This will do renames if the file already exists, ensuring we don't
- // accidentally overwrite other files who share the same md5. Yes this
- // is a very miniscule chance but it's safe.
- $filename = file_unmanaged_save_data($css, $filename);
+ // Generally md5 is considered unique enough to sign file downloads.
+ // So this replaces already existing files based on the assumption that two
+ // files with the same hash are identical content wise.
+ // If we rename, the cache folder can potentially fill up with thousands of
+ // files with the same content.
+ $filename = file_unmanaged_save_data($css, $filename, FILE_EXISTS_REPLACE);
return $filename;
}
diff --git a/sites/all/modules/contrib/dev/ctools/includes/entity-access.inc b/sites/all/modules/contrib/dev/ctools/includes/entity-access.inc
new file mode 100644
index 00000000..972cf13b
--- /dev/null
+++ b/sites/all/modules/contrib/dev/ctools/includes/entity-access.inc
@@ -0,0 +1,150 @@
+nid);
+ if ($node->vid !== $default_revision->vid) {
+ return _node_revision_access($node, $op, $account);
+ }
+ else {
+ return node_access($op, $node, $account);
+ }
+ }
+ // No node is provided. Check for access to all nodes.
+ if (user_access('bypass node access', $account)) {
+ return TRUE;
+ }
+ if (!user_access('access content', $account)) {
+ return FALSE;
+ }
+ if ($op == 'view' && node_access_view_all_nodes($account)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Access callback for the user entity.
+ */
+function ctools_metadata_user_access($op, $entity = NULL, $account = NULL, $entity_type) {
+ $account = isset($account) ? $account : $GLOBALS['user'];
+ // Grant access to the users own user account and to the anonymous one.
+ if (isset($entity) && $op != 'delete' && (($entity->uid == $account->uid && $entity->uid) || (!$entity->uid && $op == 'view'))) {
+ return TRUE;
+ }
+ if (user_access('administer users', $account) || user_access('access user profiles', $account) && $op == 'view' && $entity->status) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Access callback for the comment entity.
+ */
+function ctools_metadata_comment_access($op, $entity = NULL, $account = NULL) {
+ // When determining access to a comment, if comment has an associated node,
+ // the user must be able to view the node in order to access the comment.
+ if (isset($entity->nid)) {
+ if (!node_access('view', node_load($entity->nid), $account)) {
+ return FALSE;
+ }
+ }
+
+ // Comment administrators are allowed to perform all operations on all
+ // comments.
+ if (user_access('administer comments', $account)) {
+ return TRUE;
+ }
+
+ // Unpublished comments can never be accessed by non-admins.
+ if (isset($entity->status) && $entity->status == COMMENT_NOT_PUBLISHED) {
+ return FALSE;
+ }
+
+ if (user_access('access comments', $account) && $op == 'view') {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Access callback for the taxonomy entities.
+ */
+function ctools_metadata_taxonomy_access($op, $entity = NULL, $account = NULL, $entity_type) {
+ if ($entity_type == 'taxonomy_vocabulary') {
+ return user_access('administer taxonomy', $account);
+ }
+ if (user_access('administer taxonomy', $account) || user_access('access content', $account) && $op == 'view') {
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/sites/all/modules/contrib/dev/ctools/includes/export.inc b/sites/all/modules/contrib/dev/ctools/includes/export.inc
index 0b85c2ef..a64ce672 100644
--- a/sites/all/modules/contrib/dev/ctools/includes/export.inc
+++ b/sites/all/modules/contrib/dev/ctools/includes/export.inc
@@ -902,7 +902,8 @@ function ctools_export_object($table, $object, $indent = '', $identifier = NULL,
$output = $indent . '$' . $identifier . ' = new ' . get_class($object) . "();\n";
if ($schema['export']['can disable']) {
- $output .= $indent . '$' . $identifier . '->disabled = FALSE; /* Edit this to true to make a default ' . $identifier . ' disabled initially */' . "\n";
+ $disabled = !isset($object->disabled) || $object->disabled != TRUE ? 'FALSE' : 'TRUE';
+ $output .= $indent . '$' . $identifier . '->disabled = ' . $disabled . '; /* Edit this to true to make a default ' . $identifier . ' disabled initially */' . "\n";
}
if (!empty($schema['export']['api']['current_version'])) {
$output .= $indent . '$' . $identifier . '->api_version = ' . $schema['export']['api']['current_version'] . ";\n";
@@ -1227,7 +1228,7 @@ function ctools_export_default_to_hook_code($schema, $table, $names, $name) {
$output .= " \${$export['identifier']}s = array();\n\n";
foreach ($objects as $object) {
$output .= ctools_export_crud_export($table, $object, ' ');
- $output .= " \${$export['identifier']}s['" . check_plain($object->$export['key']) . "'] = \${$export['identifier']};\n\n";
+ $output .= " \${$export['identifier']}s['" . check_plain($object->{$export['key']}) . "'] = \${$export['identifier']};\n\n";
}
$output .= " return \${$export['identifier']}s;\n";
$output .= "}\n";
diff --git a/sites/all/modules/contrib/dev/ctools/includes/fields.inc b/sites/all/modules/contrib/dev/ctools/includes/fields.inc
index f379f5e9..cbc2dac2 100644
--- a/sites/all/modules/contrib/dev/ctools/includes/fields.inc
+++ b/sites/all/modules/contrib/dev/ctools/includes/fields.inc
@@ -137,7 +137,7 @@ function ctools_fields_get_field_formatter_settings_form($field, $formatter_type
*/
function ctools_fields_get_field_formatter_info($fields) {
$info = array();
- $field_info = module_invoke_all('field_formatter_info');
+ $field_info = field_info_formatter_types();
foreach ($fields as $field) {
foreach ($field_info as $format_name => $formatter_info) {
if (in_array($field['type'], $formatter_info['field types'])) {
@@ -145,7 +145,6 @@ function ctools_fields_get_field_formatter_info($fields) {
}
}
}
- drupal_alter('field_formatter_info', $info);
return $info;
}
diff --git a/sites/all/modules/contrib/dev/ctools/includes/jump-menu.inc b/sites/all/modules/contrib/dev/ctools/includes/jump-menu.inc
index a5f99aa3..51f45982 100644
--- a/sites/all/modules/contrib/dev/ctools/includes/jump-menu.inc
+++ b/sites/all/modules/contrib/dev/ctools/includes/jump-menu.inc
@@ -51,7 +51,7 @@ function ctools_jump_menu($form, &$form_state, $select, $options = array()) {
'hide' => TRUE,
);
- ctools_add_js('jump-menu');
+ $form['#attached']['js'][] = ctools_attach_js('jump-menu');
if (!empty($options['choose'])) {
$select = array('' => $options['choose']) + $select;
diff --git a/sites/all/modules/contrib/dev/ctools/includes/math-expr.inc b/sites/all/modules/contrib/dev/ctools/includes/math-expr.inc
index beffb93c..3105ec52 100644
--- a/sites/all/modules/contrib/dev/ctools/includes/math-expr.inc
+++ b/sites/all/modules/contrib/dev/ctools/includes/math-expr.inc
@@ -99,7 +99,7 @@ class ctools_math_expr {
'sqrt','abs','ln','log',
'time', 'ceil', 'floor', 'min', 'max', 'round');
- function ctools_math_expr() {
+ function __construct() {
// make the variables a little more accurate
$this->v['pi'] = pi();
$this->v['e'] = exp(1);
@@ -271,7 +271,7 @@ class ctools_math_expr {
} elseif (in_array($op, $ops) and !$expecting_op) {
return $this->trigger("unexpected operator '$op'");
} else { // I don't even want to know what you did to get here
- return $this->trigger("an unexpected error occured");
+ return $this->trigger("an unexpected error occurred");
}
if ($index == strlen($expr)) {
if (in_array($op, $ops)) { // did we end with an operator? bad.
diff --git a/sites/all/modules/contrib/dev/ctools/includes/modal.inc b/sites/all/modules/contrib/dev/ctools/includes/modal.inc
index ee969aba..fc990159 100644
--- a/sites/all/modules/contrib/dev/ctools/includes/modal.inc
+++ b/sites/all/modules/contrib/dev/ctools/includes/modal.inc
@@ -66,6 +66,7 @@ function ctools_modal_add_js() {
drupal_add_library('system', 'jquery.form');
drupal_add_library('system', 'drupal.progress');
drupal_add_library('system', 'drupal.ajax');
+ drupal_add_library('system', 'ui');
ctools_add_js('modal');
ctools_add_css('modal');
diff --git a/sites/all/modules/contrib/dev/ctools/includes/plugins.inc b/sites/all/modules/contrib/dev/ctools/includes/plugins.inc
index eadb68f7..d524f746 100644
--- a/sites/all/modules/contrib/dev/ctools/includes/plugins.inc
+++ b/sites/all/modules/contrib/dev/ctools/includes/plugins.inc
@@ -79,7 +79,9 @@ function ctools_plugin_api_info($owner, $api, $minimum_version, $current_version
}
// Only process if version is between minimum and current, inclusive.
- if (version_compare($version, $minimum_version, '>=') && version_compare($version, $current_version, '<=')) {
+ if (($version == $minimum_version) || ($version == $current_version)
+ || (version_compare($version, $minimum_version, '>=')
+ && version_compare($version, $current_version, '<='))) {
if (!isset($info['path'])) {
$info['path'] = drupal_get_path('module', $module);
}
@@ -110,7 +112,7 @@ function ctools_plugin_api_info($owner, $api, $minimum_version, $current_version
}
// Allow other modules to hook in.
- drupal_alter($hook, $cache[$owner][$api]);
+ drupal_alter($hook, $cache[$owner][$api], $owner, $api);
}
return $cache[$owner][$api];
@@ -198,22 +200,22 @@ function ctools_plugin_api_get_hook($owner, $api) {
/**
* Fetch a group of plugins by name.
*
- * @param $module
- * The name of the module that utilizes this plugin system. It will be
- * used to call hook_ctools_plugin_$plugin() to get more data about the plugin.
- * @param $type
+ * @param string $module
+ * The name of the module that utilizes this plugin system. It will be used to
+ * get more data about the plugin as defined on hook_ctools_plugin_type().
+ * @param string $type
* The type identifier of the plugin.
- * @param $id
+ * @param string $id
* If specified, return only information about plugin with this identifier.
* The system will do its utmost to load only plugins with this id.
*
- * @return
- * An array of information arrays about the plugins received. The contents
- * of the array are specific to the plugin.
+ * @return array
+ * An array of information arrays about the plugins received. The contents of
+ * the array are specific to the plugin.
*/
function ctools_get_plugins($module, $type, $id = NULL) {
// Store local caches of plugins and plugin info so we don't have to do full
- // lookups everytime.
+ // lookups every time.
static $drupal_static_fast;
if (!isset($drupal_static_fast)) {
$drupal_static_fast['plugins'] = &drupal_static('ctools_plugins', array());
@@ -222,10 +224,14 @@ function ctools_get_plugins($module, $type, $id = NULL) {
$info = ctools_plugin_get_plugin_type_info();
- // Bail out noisily if an invalid module/type combination is requested.
if (!isset($info[$module][$type])) {
- watchdog('ctools', 'Invalid plugin module/type combination requested: module @module and type @type', array('@module' => $module, '@type' => $type), WATCHDOG_ERROR);
- return array();
+ // If we don't find the plugin we attempt a cache rebuild before bailing out
+ $info = ctools_plugin_get_plugin_type_info(TRUE);
+ // Bail out noisily if an invalid module/type combination is requested.
+ if (!isset($info[$module][$type])) {
+ watchdog('ctools', 'Invalid plugin module/type combination requested: module @module and type @type', array('@module' => $module, '@type' => $type), WATCHDOG_ERROR);
+ return array();
+ }
}
// Make sure our plugins array is populated.
@@ -233,8 +239,8 @@ function ctools_get_plugins($module, $type, $id = NULL) {
$plugins[$module][$type] = array();
}
- // Attempt to shortcut this whole piece of code if we already have
- // the requested plugin:
+ // Attempt to shortcut this whole piece of code if we already have the
+ // requested plugin:
if ($id && array_key_exists($id, $plugins[$module][$type])) {
return $plugins[$module][$type][$id];
}
@@ -269,8 +275,8 @@ function ctools_get_plugins($module, $type, $id = NULL) {
$plugins[$module][$type] = ctools_plugin_load_hooks($info[$module][$type]);
}
- // Then see if we should load all files. We only do this if we
- // want a list of all plugins or there was a cache miss.
+ // Then see if we should load all files. We only do this if we want a list of
+ // all plugins or there was a cache miss.
if (empty($setup[$module][$type]) && ($build_cache || !$id)) {
$setup[$module][$type] = TRUE;
$plugins[$module][$type] = array_merge($plugins[$module][$type], ctools_plugin_load_includes($info[$module][$type]));
@@ -294,8 +300,8 @@ function ctools_get_plugins($module, $type, $id = NULL) {
}
- // If we were told earlier that this is cacheable and the cache was
- // empty, give something back.
+ // If we were told earlier that this is cacheable and the cache was empty,
+ // give something back.
if ($build_cache) {
cache_set("plugins:$module:$type", $plugins[$module][$type], $info[$module][$type]['cache table']);
}
@@ -472,7 +478,7 @@ function ctools_plugin_load_includes($info, $filename = NULL) {
}
else {
- require_once DRUPAL_ROOT . '/' . $file->uri;
+ include_once DRUPAL_ROOT . '/' . $file->uri;
// .inc files have a special format for the hook identifier.
// For example, 'foo.inc' in the module 'mogul' using the plugin
// whose hook is named 'borg_type' should have a function named (deep breath)
diff --git a/sites/all/modules/contrib/dev/ctools/includes/stylizer.inc b/sites/all/modules/contrib/dev/ctools/includes/stylizer.inc
index 9fdc81d7..5bc8450c 100644
--- a/sites/all/modules/contrib/dev/ctools/includes/stylizer.inc
+++ b/sites/all/modules/contrib/dev/ctools/includes/stylizer.inc
@@ -500,7 +500,7 @@ class ctools_stylizer_image_processor {
$palette[$luminosity_input]['green'] = $green;
$palette[$luminosity_input]['blue'] = $blue;
- // Now we complete the palette, first we'll do it tothe black, and then to
+ // Now we complete the palette, first we'll do it to the black, and then to
// the white.
// From input to black
diff --git a/sites/all/modules/contrib/dev/ctools/includes/uuid.inc b/sites/all/modules/contrib/dev/ctools/includes/uuid.inc
index b0567d34..13897f1f 100644
--- a/sites/all/modules/contrib/dev/ctools/includes/uuid.inc
+++ b/sites/all/modules/contrib/dev/ctools/includes/uuid.inc
@@ -9,7 +9,9 @@
/**
* Pattern for detecting a valid UUID.
*/
-define('UUID_PATTERN', '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}');
+if (!defined('UUID_PATTERN')) {
+ define('UUID_PATTERN', '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}');
+}
/**
* Generates a UUID using the Windows internal GUID generator.
@@ -25,7 +27,8 @@ function _ctools_uuid_generate_com() {
* Generates an universally unique identifier using the PECL extension.
*/
function _ctools_uuid_generate_pecl() {
- return uuid_create(UUID_TYPE_DEFAULT);
+ $uuid_type = UUID_TYPE_DEFAULT;
+ return uuid_create($uuid_type);
}
/**
diff --git a/sites/all/modules/contrib/dev/ctools/js/auto-submit.js b/sites/all/modules/contrib/dev/ctools/js/auto-submit.js
index a3e9aa42..b658577a 100644
--- a/sites/all/modules/contrib/dev/ctools/js/auto-submit.js
+++ b/sites/all/modules/contrib/dev/ctools/js/auto-submit.js
@@ -36,9 +36,11 @@ 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();
+ if ($.contains(document.body, this)) {
+ var $this = $(this);
+ if (!$this.hasClass('ctools-ajaxing')) {
+ $this.find('.ctools-auto-submit-click').click();
+ }
}
}
diff --git a/sites/all/modules/contrib/dev/ctools/js/dependent.js b/sites/all/modules/contrib/dev/ctools/js/dependent.js
index f74ec81b..a60fc120 100644
--- a/sites/all/modules/contrib/dev/ctools/js/dependent.js
+++ b/sites/all/modules/contrib/dev/ctools/js/dependent.js
@@ -97,7 +97,13 @@
else {
switch ($(trigger).attr('type')) {
case 'checkbox':
- var val = $(trigger).attr('checked') ? true : false;
+ // **This check determines if using a jQuery version 1.7 or newer which requires the use of the prop function instead of the attr function when not called on an attribute
+ if ($().prop) {
+ var val = $(trigger).prop('checked') ? true : false;
+ }
+ else {
+ var val = $(trigger).attr('checked') ? true : false;
+ }
if (val) {
$(trigger).siblings('label').removeClass('hidden-options').addClass('expanded-options');
@@ -148,34 +154,41 @@
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();
+ var $original = $('#' + id);
+ if ($original.is('fieldset') || $original.is('textarea')) {
+ continue;
}
+ var object = $original.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);
+ // **This check determines if using a jQuery version 1.7 or newer which requires the use of the prop function instead of the attr function when not called on an attribute
+ if (typeof $().prop == 'function') {
+ object.prop('disabled', false);
+ object.addClass('dependent-options');
+ object.children().prop('disabled', false);
+ }
+ else {
+ 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);
+ // **This check determines if using a jQuery version 1.7 or newer which requires the use of the prop function instead of the attr function when not called on an attribute
+ if (typeof $().prop == 'function') {
+ object.prop('disabled', true);
+ object.children().prop('disabled', true);
+ }
+ else {
+ object.attr('disabled', true);
+ object.children().attr('disabled', true);
+ }
}
}
else {
diff --git a/sites/all/modules/contrib/dev/ctools/js/modal.js b/sites/all/modules/contrib/dev/ctools/js/modal.js
index 37908cf3..634595f8 100644
--- a/sites/all/modules/contrib/dev/ctools/js/modal.js
+++ b/sites/all/modules/contrib/dev/ctools/js/modal.js
@@ -48,7 +48,8 @@
modalOptions: {
opacity: .55,
background: '#fff'
- }
+ },
+ modalClass: 'default'
};
var settings = {};
@@ -97,8 +98,8 @@
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);
- $('#modalContent .modal-content').html(Drupal.theme(settings.throbberTheme));
+ 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() {
@@ -120,18 +121,18 @@
*/
Drupal.theme.prototype.CToolsModalDialog = function () {
var html = ''
- html += '
';
return html;
}
@@ -141,11 +142,11 @@
*/
Drupal.theme.prototype.CToolsModalThrobber = function () {
var html = '';
- html += '
';
- html += '
';
- html += Drupal.CTools.Modal.currentSettings.throbber;
- html += '
';
+ html += '
';
+ html += '
';
+ html += Drupal.CTools.Modal.currentSettings.throbber;
html += '
';
+ html += '
';
return html;
};
@@ -264,7 +265,10 @@
}
// An empty event means we were triggered via .click() and
// in jquery 1.4 this won't trigger a submit.
- if (event.bubbles == undefined) {
+ // We also have to check jQuery version to prevent
+ // IE8 + jQuery 1.4.4 to break on other events
+ // bound to the submit button.
+ if (jQuery.fn.jquery === '1.4' && typeof event.bubbles === "undefined") {
$(this.form).trigger('submit');
return false;
}
@@ -299,6 +303,17 @@
// 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();
+ }
}
/**
@@ -349,8 +364,9 @@
* @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) {
+ 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';
@@ -402,9 +418,56 @@
if( docHeight < winHeight ) docHeight = winHeight;
// Create our divs
- $('body').append('
' + $(content).html() + '
');
+ $('body').append('
' + $(content).html() + '
');
- // Keyboard and focus event handler ensures focus stays on modal elements only
+ // 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
@@ -428,7 +491,7 @@
return true;
}
else {
- $('#modalContent').focus();
+ getTabbableElements()[0].focus();
}
event.preventDefault();
@@ -436,6 +499,59 @@
$('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);
@@ -457,12 +573,19 @@
$(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'));
@@ -478,12 +601,19 @@
// 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 resize of the window
- modalContentResize = function(){
+ // Move and resize the modalBackdrop and modalContent on window resize.
+ modalContentResize = function(){
- // position code lifted from http://www.quirksmode.org/viewport/compatibility.html
+ // 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
@@ -509,8 +639,6 @@
modalContent.css('top', mdcTop + 'px').css('left', mdcLeft + 'px').show();
};
$(window).bind('resize', modalContentResize);
-
- $('#modalContent').focus();
};
/**
@@ -533,7 +661,9 @@
$(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.
diff --git a/sites/all/modules/contrib/dev/ctools/js/states-show.js b/sites/all/modules/contrib/dev/ctools/js/states-show.js
new file mode 100644
index 00000000..88df5841
--- /dev/null
+++ b/sites/all/modules/contrib/dev/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/contrib/dev/ctools/js/stylizer.js b/sites/all/modules/contrib/dev/ctools/js/stylizer.js
index 16d6c49d..12ab7204 100644
--- a/sites/all/modules/contrib/dev/ctools/js/stylizer.js
+++ b/sites/all/modules/contrib/dev/ctools/js/stylizer.js
@@ -5,7 +5,7 @@
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()) {
+ if ($('#ctools_stylizer_color_scheme_form .color-form.Stylizer-processed').size()) {
return;
}
diff --git a/sites/all/modules/contrib/dev/ctools/page_manager/help/getting-started.html b/sites/all/modules/contrib/dev/ctools/page_manager/help/getting-started.html
index 4e4f24ae..6a75a370 100644
--- a/sites/all/modules/contrib/dev/ctools/page_manager/help/getting-started.html
+++ b/sites/all/modules/contrib/dev/ctools/page_manager/help/getting-started.html
@@ -4,7 +4,7 @@ Note: this page is currently very preliminary. Please visit ' . $task['name'] . '__',
+ '#field_prefix' => '' . $form_state['task_name'] . '__',
'#field_suffix' => '',
);
}
@@ -1466,7 +1466,7 @@ function page_manager_handler_add_form($form, $form_state, $features = array())
* Check if handler's machine-name is unique
*/
function page_manager_handler_check_machine_name($name, $element, $form_state) {
- $name = $form_state['task']['name'] . '__' . $name;
+ $name = $form_state['task_name'] . '__' . $name;
return count(ctools_export_load_object('page_manager_handlers', 'names', array($name)));
}
@@ -1542,25 +1542,42 @@ function page_manager_handler_import_submit(&$form, &$form_state) {
* Rearrange the order of variants.
*/
function page_manager_handler_rearrange($form, &$form_state) {
+ ctools_include('context-task-handler');
$page = $form_state['page'];
$form['handlers'] = array('#tree' => TRUE);
+ // Get the number of variants to be displayed in order to set the delta
+ // to the proper value. This fixes problems in previous versions with sorting
+ // large numbers of variants.
+ $delta = count($page->handler_info)/2 + 1;
+
foreach ($page->handler_info as $id => $info) {
if ($info['changed'] & PAGE_MANAGER_CHANGED_DELETED) {
continue;
}
$handler = $page->handlers[$id];
$plugin = page_manager_get_task_handler($handler->handler);
-
+ $object = ctools_context_handler_get_task_object($page->task, $page->subtask, $handler);
+ $display = new stdClass();
+ $display->context = ctools_context_load_contexts($object, TRUE);
+ $content = page_manager_get_handler_title($plugin, $handler, $page->task, $page->subtask_id);
+ $access = ctools_access_group_summary(!empty($handler->conf['access']) ? $handler->conf['access'] : array(), $display->context);
+ if ($access) {
+ $access = t('This panel will be selected if @conditions.', array('@conditions' => $access));
+ }
+ else {
+ $access = t('This panel will always be selected.');
+ }
+ $content .= '
';
+}
+
/** @} End of addtogroup themeable */
diff --git a/sites/all/modules/contrib/fields/date/date_admin.inc b/sites/all/modules/contrib/fields/date/date_admin.inc
index 0e32fc5a..13da42ef 100644
--- a/sites/all/modules/contrib/fields/date/date_admin.inc
+++ b/sites/all/modules/contrib/fields/date/date_admin.inc
@@ -74,6 +74,12 @@ function date_default_formatter_settings_form($field, $instance, $view_mode, $fo
'#description' => t('Identify specific start and/or end dates in the format YYYY-MM-DDTHH:MM:SS, or leave blank for all available dates.'),
);
+ $form['show_remaining_days'] = array(
+ '#title' => t('Show remaining days'),
+ '#type' => 'checkbox',
+ '#default_value' => $settings['show_remaining_days'],
+ '#weight' => 0,
+ );
return $form;
}
@@ -127,9 +133,11 @@ function date_default_formatter_settings_summary($field, $instance, $view_mode)
case 'date_plain':
$format = t('Plain');
break;
+
case 'format_interval':
$format = t('Interval');
break;
+
default:
if (!empty($format_types[$settings['format_type']])) {
$format = $format_types[$settings['format_type']];
@@ -148,7 +156,9 @@ function date_default_formatter_settings_summary($field, $instance, $view_mode)
'value' => t('Display Start date only'),
'value2' => t('Display End date only'),
);
- $summary[] = $options[$settings['fromto']];
+ if (isset($options[$settings['fromto']])) {
+ $summary[] = $options[$settings['fromto']];
+ }
}
if (array_key_exists('multiple_number', $settings) && !empty($field['cardinality'])) {
@@ -159,6 +169,10 @@ function date_default_formatter_settings_summary($field, $instance, $view_mode)
));
}
+ if (array_key_exists('show_remaining_days', $settings)) {
+ $summary[] = t('Show remaining days: @value', array('@value' => ($settings['show_remaining_days'] ? 'yes' : 'no')));
+ }
+
return $summary;
}
@@ -191,7 +205,11 @@ function _date_field_instance_settings_form($field, $instance) {
'#type' => 'select',
'#title' => t('Default date'),
'#default_value' => $settings['default_value'],
- '#options' => array('blank' => t('No default value'), 'now' => t('Now'), 'strtotime' => t('Relative')),
+ '#options' => array(
+ 'blank' => t('No default value'),
+ 'now' => t('Now'),
+ 'strtotime' => t('Relative'),
+ ),
'#weight' => 1,
'#fieldset' => 'default_values',
);
@@ -204,8 +222,11 @@ function _date_field_instance_settings_form($field, $instance) {
'#default_value' => $settings['default_value_code'],
'#states' => array(
'visible' => array(
- ':input[name="instance[settings][default_value]"]' => array('value' => 'strtotime')),
+ ':input[name="instance[settings][default_value]"]' => array(
+ 'value' => 'strtotime',
+ ),
),
+ ),
'#weight' => 1.1,
'#fieldset' => 'default_values',
);
@@ -213,7 +234,12 @@ function _date_field_instance_settings_form($field, $instance) {
'#type' => !empty($field['settings']['todate']) ? 'select' : 'hidden',
'#title' => t('Default end date'),
'#default_value' => $settings['default_value2'],
- '#options' => array('same' => t('Same as Default date'), 'blank' => t('No default value'), 'now' => t('Now'), 'strtotime' => t('Relative')),
+ '#options' => array(
+ 'same' => t('Same as Default date'),
+ 'blank' => t('No default value'),
+ 'now' => t('Now'),
+ 'strtotime' => t('Relative'),
+ ),
'#weight' => 2,
'#fieldset' => 'default_values',
);
@@ -224,8 +250,11 @@ function _date_field_instance_settings_form($field, $instance) {
'#default_value' => $settings['default_value_code2'],
'#states' => array(
'visible' => array(
- ':input[name="instance[settings][default_value2]"]' => array('value' => 'strtotime')),
+ ':input[name="instance[settings][default_value2]"]' => array(
+ 'value' => 'strtotime',
+ ),
),
+ ),
'#weight' => 2.1,
'#fieldset' => 'default_values',
);
@@ -284,6 +313,7 @@ function _date_field_widget_settings_form($field, $instance) {
$formats = drupal_map_assoc($formats);
}
$now = date_example_date();
+ $options['site-wide'] = t('Short date format: @date', array('@date' => date_format_date($now, 'short')));
foreach ($formats as $f) {
$options[$f] = date_format_date($now, 'custom', $f);
}
@@ -369,11 +399,18 @@ function _date_field_widget_settings_form($field, $instance) {
'#weight' => 9,
);
if (in_array($widget['type'], array('date_select'))) {
- $options = array('above' => t('Above'), 'within' => t('Within'), 'none' => t('None'));
+ $options = array(
+ 'above' => t('Above'),
+ 'within' => t('Within'),
+ 'none' => t('None'),
+ );
$description = t("The location of date part labels, like 'Year', 'Month', or 'Day' . 'Above' displays the label as titles above each date part. 'Within' inserts the label as the first option in the select list and in blank textfields. 'None' doesn't visually label any of the date parts. Theme functions like 'date_part_label_year' and 'date_part_label_month' control label text.");
}
else {
- $options = array('above' => t('Above'), 'none' => t('None'));
+ $options = array(
+ 'above' => t('Above'),
+ 'none' => t('None'),
+ );
$description = t("The location of date part labels, like 'Year', 'Month', or 'Day' . 'Above' displays the label as titles above each date part. 'None' doesn't visually label any of the date parts. Theme functions like 'date_part_label_year' and 'date_part_label_month' control label text.");
}
$form['advanced']['label_position'] = array(
@@ -403,6 +440,13 @@ function _date_field_widget_settings_form($field, $instance) {
}
}
+ $form['advanced']['no_fieldset'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Render as a regular field'),
+ '#default_value' => !empty($settings['no_fieldset']),
+ '#description' => t('Whether to render this field as a regular field instead of a fieldset. The date field elements are wrapped in a fieldset by default, and may not display well without it.'),
+ );
+
$context = array(
'field' => $field,
'instance' => $instance,
@@ -470,7 +514,9 @@ function _date_field_settings_form($field, $instance, $has_data) {
'#title' => t('Date attributes to collect'),
'#default_value' => $granularity,
'#options' => $options,
- '#attributes' => array('class' => array('container-inline')),
+ '#attributes' => array(
+ 'class' => array('container-inline'),
+ ),
'#description' => $description,
'year' => $checkbox_year,
);
@@ -528,7 +574,9 @@ function _date_field_settings_form($field, $instance, $has_data) {
'#weight' => 11,
'#states' => array(
'visible' => array(
- 'input[name="field[settings][cache_enabled]"]' => array('checked' => TRUE),
+ 'input[name="field[settings][cache_enabled]"]' => array(
+ 'checked' => TRUE,
+ ),
),
),
);
@@ -600,7 +648,7 @@ function date_timezone_handling_options() {
'site' => t("Site's time zone"),
'date' => t("Date's time zone"),
'user' => t("User's time zone"),
- 'utc' => 'UTC',
+ 'utc' => 'UTC',
'none' => t('No time zone conversion'),
);
}
diff --git a/sites/all/modules/contrib/fields/date/date_all_day/date_all_day.info b/sites/all/modules/contrib/fields/date/date_all_day/date_all_day.info
index 8eeb7325..df773e41 100644
--- a/sites/all/modules/contrib/fields/date/date_all_day/date_all_day.info
+++ b/sites/all/modules/contrib/fields/date/date_all_day/date_all_day.info
@@ -5,9 +5,9 @@ dependencies[] = date
package = Date/Time
core = 7.x
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-09-08
+version = "7.x-2.9"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1441727353"
diff --git a/sites/all/modules/contrib/fields/date/date_all_day/date_all_day.module b/sites/all/modules/contrib/fields/date/date_all_day/date_all_day.module
index 93fc61ba..e79bc944 100644
--- a/sites/all/modules/contrib/fields/date/date_all_day/date_all_day.module
+++ b/sites/all/modules/contrib/fields/date/date_all_day/date_all_day.module
@@ -31,11 +31,11 @@ function date_all_day_theme() {
'format' => NULL,
'entity_type' => NULL,
'entity' => NULL,
- 'view' => NULL
- )
+ 'view' => NULL,
+ ),
),
'date_all_day_label' => array(
- 'variables' => array()
+ 'variables' => array(),
),
);
@@ -91,14 +91,29 @@ function date_all_day_date_formatter_dates_alter(&$dates, $context) {
/**
* Adjust start/end date format to account for 'all day' .
*
- * @param array $field, the field definition for this date field.
- * @param string $which, which value to return, 'date1' or 'date2' .
- * @param object $date1, a date/time object for the 'start' date.
- * @param object $date2, a date/time object for the 'end' date.
- * @param string $format
- * @param object $entity, the node this date comes from (may be incomplete, always contains nid).
- * @param object $view, the view this node comes from, if applicable.
- * @return formatted date.
+ * @params array $field
+ * The field definition for this date field.
+ *
+ * @params string $which
+ * Which value to return, 'date1' or 'date2'.
+ *
+ * @params object $date1
+ * A date/time object for the 'start' date.
+ *
+ * @params object $date2
+ * A date/time object for the 'end' date.
+ *
+ * @params string $format
+ * A date/time format
+ *
+ * @params object $entity
+ * The node this date comes from (may be incomplete, always contains nid).
+ *
+ * @params object $view
+ * The view this node comes from, if applicable.
+ *
+ * @return string
+ * Formatted date.
*/
function theme_date_all_day($vars) {
$field = $vars['field'];
@@ -135,23 +150,32 @@ function theme_date_all_day($vars) {
}
return trim(date_format_date($$which, 'custom', $format) . $suffix);
-
}
/**
* Theme the way an 'all day' label will look.
*/
function theme_date_all_day_label() {
- return '(' . t('All day', array(), array('context' => 'datetime')) .')';
+ return '(' . t('All day', array(), array('context' => 'datetime')) . ')';
}
/**
* Determine if a Start/End date combination qualify as 'All day'.
*
- * @param array $field, the field definition for this date field.
- * @param object $date1, a date/time object for the 'Start' date.
- * @param object $date2, a date/time object for the 'End' date.
- * @return TRUE or FALSE.
+ * @param array $field
+ * The field definition for this date field.
+ *
+ * @param array $instance
+ * The field instance for this date field.
+ *
+ * @param object $date1
+ * A date/time object for the 'Start' date.
+ *
+ * @param object $date2
+ * A date/time object for the 'End' date.
+ *
+ * @return bool
+ * TRUE or FALSE.
*/
function date_all_day_field($field, $instance, $date1, $date2 = NULL) {
if (empty($date1) || !is_object($date1)) {
@@ -167,7 +191,6 @@ function date_all_day_field($field, $instance, $date1, $date2 = NULL) {
$granularity = date_granularity_precision($field['settings']['granularity']);
$increment = isset($instance['widget']['settings']['increment']) ? $instance['widget']['settings']['increment'] : 1;
return date_is_all_day(date_format($date1, DATE_FORMAT_DATETIME), date_format($date2, DATE_FORMAT_DATETIME), $granularity, $increment);
-
}
/**
@@ -222,7 +245,8 @@ function date_all_day_date_combo_process_alter(&$element, &$form_state, $context
function date_all_day_date_text_process_alter(&$element, &$form_state, $context) {
$all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
if ($all_day_id != '') {
- // All Day handling on text dates works only if the user leaves the time out of the input value.
+ // All Day handling on text dates works only
+ // if the user leaves the time out of the input value.
// There is no element to hide or show.
}
}
@@ -234,10 +258,11 @@ function date_all_day_date_text_process_alter(&$element, &$form_state, $context)
*/
function date_all_day_date_select_process_alter(&$element, &$form_state, $context) {
- // Hide or show this element in reaction to the all_day status for this element.
+ // Hide or show this element in reaction
+ // to the all_day status for this element.
$all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
if ($all_day_id != '') {
- foreach(array('hour', 'minute', 'second', 'ampm') as $field) {
+ foreach (array('hour', 'minute', 'second', 'ampm') as $field) {
if (array_key_exists($field, $element)) {
$element[$field]['#states'] = array(
'visible' => array(
@@ -255,7 +280,8 @@ function date_all_day_date_select_process_alter(&$element, &$form_state, $contex
*/
function date_all_day_date_popup_process_alter(&$element, &$form_state, $context) {
- // Hide or show this element in reaction to the all_day status for this element.
+ // Hide or show this element in reaction to
+ // the all_day status for this element.
$all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
if ($all_day_id != '' && array_key_exists('time', $element)) {
$element['time']['#states'] = array(
@@ -272,7 +298,8 @@ function date_all_day_date_popup_process_alter(&$element, &$form_state, $context
* of the date_select validation gets fired.
*/
function date_all_day_date_text_pre_validate_alter(&$element, &$form_state, &$input) {
- // Let Date module massage the format for all day values so they will pass validation.
+ // Let Date module massage the format for all day
+ // values so they will pass validation.
// The All day flag, if used, actually exists on the parent element.
date_all_day_value($element, $form_state);
}
@@ -284,7 +311,8 @@ function date_all_day_date_text_pre_validate_alter(&$element, &$form_state, &$in
* of the date_select validation gets fired.
*/
function date_all_day_date_select_pre_validate_alter(&$element, &$form_state, &$input) {
- // Let Date module massage the format for all day values so they will pass validation.
+ // Let Date module massage the format for all
+ // day values so they will pass validation.
// The All day flag, if used, actually exists on the parent element.
date_all_day_value($element, $form_state);
}
@@ -296,13 +324,16 @@ function date_all_day_date_select_pre_validate_alter(&$element, &$form_state, &$
* of the date_popup validation gets fired.
*/
function date_all_day_date_popup_pre_validate_alter(&$element, &$form_state, &$input) {
- // Let Date module massage the format for all day values so they will pass validation.
+ // Let Date module massage the format for all
+ // day values so they will pass validation.
// The All day flag, if used, actually exists on the parent element.
date_all_day_value($element, $form_state);
}
/**
- * A helper function to check if the all day flag is set on the parent of an
+ * A helper function date_all_day_value().
+ *
+ * To check if the all day flag is set on the parent of an
* element, and adjust the date_format accordingly so the missing time will
* not cause validation errors.
*/
@@ -332,7 +363,8 @@ function date_all_day_date_combo_pre_validate_alter(&$element, &$form_state, $co
$field = $context['field'];
// If we have an all day flag on this date and the time is empty,
- // change the format to match the input value so we don't get validation errors.
+ // change the format to match the input value
+ // so we don't get validation errors.
$element['#date_is_all_day'] = TRUE;
$element['value']['#date_format'] = date_part_format('date', $element['value']['#date_format']);
if (!empty($field['settings']['todate'])) {
@@ -344,29 +376,29 @@ function date_all_day_date_combo_pre_validate_alter(&$element, &$form_state, $co
/**
* Implements hook_date_combo_validate_date_start_alter().
*
- * This hook lets us alter the local date objects created by the date_combo validation
- * before they are converted back to the database timezone and stored.
+ * This hook lets us alter the local date objects
+ * created by the date_combo validation before they are
+ * converted back to the database timezone and stored.
*/
function date_all_day_date_combo_validate_date_start_alter(&$date, &$form_state, $context) {
-
- // If this is an 'All day' value, set the time to midnight.
- if (!empty($context['element']['#date_is_all_day'])) {
- $date->setTime(0, 0, 0);
- }
+ // If this is an 'All day' value, set the time to midnight.
+ if (!empty($context['element']['#date_is_all_day'])) {
+ $date->setTime(0, 0, 0);
+ }
}
/**
* Implements hook_date_combo_validate_date_end_alter().
*
- * This hook lets us alter the local date objects created by the date_combo validation
- * before they are converted back to the database timezone and stored.
+ * This hook lets us alter the local date objects
+ * created by the date_combo validation before
+ * they are converted back to the database timezone and stored.
*/
function date_all_day_date_combo_validate_date_end_alter(&$date, &$form_state, $context) {
-
- // If this is an 'All day' value, set the time to midnight.
- if (!empty($context['element']['#date_is_all_day'])) {
- $date->setTime(0, 0, 0);
- }
+ // If this is an 'All day' value, set the time to midnight.
+ if (!empty($context['element']['#date_is_all_day'])) {
+ $date->setTime(0, 0, 0);
+ }
}
/**
diff --git a/sites/all/modules/contrib/fields/date/date_api/date.css b/sites/all/modules/contrib/fields/date/date_api/date.css
index 9b72ecdb..e47a2ae2 100644
--- a/sites/all/modules/contrib/fields/date/date_api/date.css
+++ b/sites/all/modules/contrib/fields/date/date_api/date.css
@@ -15,9 +15,11 @@
.container-inline-date > .form-item {
display: inline-block;
margin-right: 0.5em; /* LTR */
- margin-bottom: 10px;
vertical-align: top;
}
+fieldset.date-combo .container-inline-date > .form-item {
+ margin-bottom: 10px;
+}
.container-inline-date .form-item .form-item {
float: left; /* LTR */
}
@@ -52,9 +54,11 @@
/* The exposed Views form doesn't need some of these styles */
.container-inline-date .date-padding {
- padding: 10px;
float: left;
}
+fieldset.date-combo .container-inline-date .date-padding {
+ padding: 10px;
+}
.views-exposed-form .container-inline-date .date-padding {
padding: 0;
}
@@ -116,7 +120,7 @@ span.date-display-end {
}
/* Add space between the date and time portions of the date_select widget. */
-.form-type-date-select .form-type-select[class$=hour] {
+.form-type-date-select .form-type-select[class*=hour] {
margin-left: .75em; /* LTR */
}
@@ -173,6 +177,10 @@ div.date-calendar-day span.year {
padding: 2px;
}
+.date-form-element-content-multiline {
+ padding: 10px;
+ border: 1px solid #CCC;
+}
/* Admin styling */
.form-item.form-item-instance-widget-settings-input-format-custom,
.form-item.form-item-field-settings-enddate-required {
diff --git a/sites/all/modules/contrib/fields/date/date_api/date_api.admin.inc b/sites/all/modules/contrib/fields/date/date_api/date_api.admin.inc
index 966b1a42..3c706aeb 100644
--- a/sites/all/modules/contrib/fields/date/date_api/date_api.admin.inc
+++ b/sites/all/modules/contrib/fields/date/date_api/date_api.admin.inc
@@ -10,112 +10,112 @@
*/
function _date_timezone_replacement($old) {
$replace = array(
- 'Brazil/Acre' => 'America/Rio_Branco',
- 'Brazil/DeNoronha' => 'America/Noronha',
- 'Brazil/East' => 'America/Recife',
- 'Brazil/West' => 'America/Manaus',
- 'Canada/Atlantic' => 'America/Halifax',
- 'Canada/Central' => 'America/Winnipeg',
- 'Canada/East-Saskatchewan' => 'America/Regina',
- 'Canada/Eastern' => 'America/Toronto',
- 'Canada/Mountain' => 'America/Edmonton',
- 'Canada/Newfoundland' => 'America/St_Johns',
- 'Canada/Pacific' => 'America/Vancouver',
- 'Canada/Saskatchewan' => 'America/Regina',
- 'Canada/Yukon' => 'America/Whitehorse',
- 'CET' => 'Europe/Berlin',
- 'Chile/Continental' => 'America/Santiago',
- 'Chile/EasterIsland' => 'Pacific/Easter',
- 'CST6CDT' => 'America/Chicago',
- 'Cuba' => 'America/Havana',
- 'EET' => 'Europe/Bucharest',
- 'Egypt' => 'Africa/Cairo',
- 'Eire' => 'Europe/Belfast',
- 'EST' => 'America/New_York',
- 'EST5EDT' => 'America/New_York',
- 'GB' => 'Europe/London',
- 'GB-Eire' => 'Europe/Belfast',
- 'Etc/GMT' => 'UTC',
- 'Etc/GMT+0' => 'UTC',
- 'Etc/GMT+1' => 'UTC',
- 'Etc/GMT+10' => 'UTC',
- 'Etc/GMT+11' => 'UTC',
- 'Etc/GMT+12' => 'UTC',
- 'Etc/GMT+2' => 'UTC',
- 'Etc/GMT+3' => 'UTC',
- 'Etc/GMT+4' => 'UTC',
- 'Etc/GMT+5' => 'UTC',
- 'Etc/GMT+6' => 'UTC',
- 'Etc/GMT+7' => 'UTC',
- 'Etc/GMT+8' => 'UTC',
- 'Etc/GMT+9' => 'UTC',
- 'Etc/GMT-0' => 'UTC',
- 'Etc/GMT-1' => 'UTC',
- 'Etc/GMT-10' => 'UTC',
- 'Etc/GMT-11' => 'UTC',
- 'Etc/GMT-12' => 'UTC',
- 'Etc/GMT-13' => 'UTC',
- 'Etc/GMT-14' => 'UTC',
- 'Etc/GMT-2' => 'UTC',
- 'Etc/GMT-3' => 'UTC',
- 'Etc/GMT-4' => 'UTC',
- 'Etc/GMT-5' => 'UTC',
- 'Etc/GMT-6' => 'UTC',
- 'Etc/GMT-7' => 'UTC',
- 'Etc/GMT-8' => 'UTC',
- 'Etc/GMT-9' => 'UTC',
- 'Etc/GMT0' => 'UTC',
- 'Etc/Greenwich' => 'UTC',
- 'Etc/UCT' => 'UTC',
- 'Etc/Universal' => 'UTC',
- 'Etc/UTC' => 'UTC',
- 'Etc/Zulu' => 'UTC',
- 'Factory' => 'UTC',
- 'GMT' => 'UTC',
- 'GMT+0' => 'UTC',
- 'GMT-0' => 'UTC',
- 'GMT0' => 'UTC',
- 'Hongkong' => 'Asia/Hong_Kong',
- 'HST' => 'Pacific/Honolulu',
- 'Iceland' => 'Atlantic/Reykjavik',
- 'Iran' => 'Asia/Tehran',
- 'Israel' => 'Asia/Tel_Aviv',
- 'Jamaica' => 'America/Jamaica',
- 'Japan' => 'Asia/Tokyo',
- 'Kwajalein' => 'Pacific/Kwajalein',
- 'Libya' => 'Africa/Tunis',
- 'MET' => 'Europe/Budapest',
- 'Mexico/BajaNorte' => 'America/Tijuana',
- 'Mexico/BajaSur' => 'America/Mazatlan',
- 'Mexico/General' => 'America/Mexico_City',
- 'MST' => 'America/Boise',
- 'MST7MDT' => 'America/Boise',
- 'Navajo' => 'America/Phoenix',
- 'NZ' => 'Pacific/Auckland',
- 'NZ-CHAT' => 'Pacific/Chatham',
- 'Poland' => 'Europe/Warsaw',
- 'Portugal' => 'Europe/Lisbon',
- 'PRC' => 'Asia/Chongqing',
- 'PST8PDT' => 'America/Los_Angeles',
- 'ROC' => 'Asia/Taipei',
- 'ROK' => 'Asia/Seoul',
- 'Singapore' => 'Asia/Singapore',
- 'Turkey' => 'Europe/Istanbul',
- 'US/Alaska' => 'America/Anchorage',
- 'US/Aleutian' => 'America/Adak',
- 'US/Arizona' => 'America/Phoenix',
- 'US/Central' => 'America/Chicago',
- 'US/East-Indiana' => 'America/Indianapolis',
- 'US/Eastern' => 'America/New_York',
- 'US/Hawaii' => 'Pacific/Honolulu',
- 'US/Indiana-Starke' => 'America/Indiana/Knox',
- 'US/Michigan' => 'America/Detroit',
- 'US/Mountain' => 'America/Boise',
- 'US/Pacific' => 'America/Los_Angeles',
- 'US/Pacific-New' => 'America/Los_Angeles',
- 'US/Samoa' => 'Pacific/Samoa',
- 'W-SU' => 'Europe/Moscow',
- 'WET' => 'Europe/Paris',
+ 'Brazil/Acre' => 'America/Rio_Branco',
+ 'Brazil/DeNoronha' => 'America/Noronha',
+ 'Brazil/East' => 'America/Recife',
+ 'Brazil/West' => 'America/Manaus',
+ 'Canada/Atlantic' => 'America/Halifax',
+ 'Canada/Central' => 'America/Winnipeg',
+ 'Canada/East-Saskatchewan' => 'America/Regina',
+ 'Canada/Eastern' => 'America/Toronto',
+ 'Canada/Mountain' => 'America/Edmonton',
+ 'Canada/Newfoundland' => 'America/St_Johns',
+ 'Canada/Pacific' => 'America/Vancouver',
+ 'Canada/Saskatchewan' => 'America/Regina',
+ 'Canada/Yukon' => 'America/Whitehorse',
+ 'CET' => 'Europe/Berlin',
+ 'Chile/Continental' => 'America/Santiago',
+ 'Chile/EasterIsland' => 'Pacific/Easter',
+ 'CST6CDT' => 'America/Chicago',
+ 'Cuba' => 'America/Havana',
+ 'EET' => 'Europe/Bucharest',
+ 'Egypt' => 'Africa/Cairo',
+ 'Eire' => 'Europe/Belfast',
+ 'EST' => 'America/New_York',
+ 'EST5EDT' => 'America/New_York',
+ 'GB' => 'Europe/London',
+ 'GB-Eire' => 'Europe/Belfast',
+ 'Etc/GMT' => 'UTC',
+ 'Etc/GMT+0' => 'UTC',
+ 'Etc/GMT+1' => 'UTC',
+ 'Etc/GMT+10' => 'UTC',
+ 'Etc/GMT+11' => 'UTC',
+ 'Etc/GMT+12' => 'UTC',
+ 'Etc/GMT+2' => 'UTC',
+ 'Etc/GMT+3' => 'UTC',
+ 'Etc/GMT+4' => 'UTC',
+ 'Etc/GMT+5' => 'UTC',
+ 'Etc/GMT+6' => 'UTC',
+ 'Etc/GMT+7' => 'UTC',
+ 'Etc/GMT+8' => 'UTC',
+ 'Etc/GMT+9' => 'UTC',
+ 'Etc/GMT-0' => 'UTC',
+ 'Etc/GMT-1' => 'UTC',
+ 'Etc/GMT-10' => 'UTC',
+ 'Etc/GMT-11' => 'UTC',
+ 'Etc/GMT-12' => 'UTC',
+ 'Etc/GMT-13' => 'UTC',
+ 'Etc/GMT-14' => 'UTC',
+ 'Etc/GMT-2' => 'UTC',
+ 'Etc/GMT-3' => 'UTC',
+ 'Etc/GMT-4' => 'UTC',
+ 'Etc/GMT-5' => 'UTC',
+ 'Etc/GMT-6' => 'UTC',
+ 'Etc/GMT-7' => 'UTC',
+ 'Etc/GMT-8' => 'UTC',
+ 'Etc/GMT-9' => 'UTC',
+ 'Etc/GMT0' => 'UTC',
+ 'Etc/Greenwich' => 'UTC',
+ 'Etc/UCT' => 'UTC',
+ 'Etc/Universal' => 'UTC',
+ 'Etc/UTC' => 'UTC',
+ 'Etc/Zulu' => 'UTC',
+ 'Factory' => 'UTC',
+ 'GMT' => 'UTC',
+ 'GMT+0' => 'UTC',
+ 'GMT-0' => 'UTC',
+ 'GMT0' => 'UTC',
+ 'Hongkong' => 'Asia/Hong_Kong',
+ 'HST' => 'Pacific/Honolulu',
+ 'Iceland' => 'Atlantic/Reykjavik',
+ 'Iran' => 'Asia/Tehran',
+ 'Israel' => 'Asia/Tel_Aviv',
+ 'Jamaica' => 'America/Jamaica',
+ 'Japan' => 'Asia/Tokyo',
+ 'Kwajalein' => 'Pacific/Kwajalein',
+ 'Libya' => 'Africa/Tunis',
+ 'MET' => 'Europe/Budapest',
+ 'Mexico/BajaNorte' => 'America/Tijuana',
+ 'Mexico/BajaSur' => 'America/Mazatlan',
+ 'Mexico/General' => 'America/Mexico_City',
+ 'MST' => 'America/Boise',
+ 'MST7MDT' => 'America/Boise',
+ 'Navajo' => 'America/Phoenix',
+ 'NZ' => 'Pacific/Auckland',
+ 'NZ-CHAT' => 'Pacific/Chatham',
+ 'Poland' => 'Europe/Warsaw',
+ 'Portugal' => 'Europe/Lisbon',
+ 'PRC' => 'Asia/Chongqing',
+ 'PST8PDT' => 'America/Los_Angeles',
+ 'ROC' => 'Asia/Taipei',
+ 'ROK' => 'Asia/Seoul',
+ 'Singapore' => 'Asia/Singapore',
+ 'Turkey' => 'Europe/Istanbul',
+ 'US/Alaska' => 'America/Anchorage',
+ 'US/Aleutian' => 'America/Adak',
+ 'US/Arizona' => 'America/Phoenix',
+ 'US/Central' => 'America/Chicago',
+ 'US/East-Indiana' => 'America/Indianapolis',
+ 'US/Eastern' => 'America/New_York',
+ 'US/Hawaii' => 'Pacific/Honolulu',
+ 'US/Indiana-Starke' => 'America/Indiana/Knox',
+ 'US/Michigan' => 'America/Detroit',
+ 'US/Mountain' => 'America/Boise',
+ 'US/Pacific' => 'America/Los_Angeles',
+ 'US/Pacific-New' => 'America/Los_Angeles',
+ 'US/Samoa' => 'Pacific/Samoa',
+ 'W-SU' => 'Europe/Moscow',
+ 'WET' => 'Europe/Paris',
);
if (array_key_exists($old, $replace)) {
return $replace[$old];
diff --git a/sites/all/modules/contrib/fields/date/date_api/date_api.info b/sites/all/modules/contrib/fields/date/date_api/date_api.info
index 3ca86e65..40fbb056 100644
--- a/sites/all/modules/contrib/fields/date/date_api/date_api.info
+++ b/sites/all/modules/contrib/fields/date/date_api/date_api.info
@@ -9,9 +9,9 @@ stylesheets[all][] = date.css
files[] = date_api.module
files[] = date_api_sql.inc
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-09-08
+version = "7.x-2.9"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1441727353"
diff --git a/sites/all/modules/contrib/fields/date/date_api/date_api.install b/sites/all/modules/contrib/fields/date/date_api/date_api.install
index ce5b746d..d5a68bbd 100644
--- a/sites/all/modules/contrib/fields/date/date_api/date_api.install
+++ b/sites/all/modules/contrib/fields/date/date_api/date_api.install
@@ -96,7 +96,7 @@ function date_api_uninstall() {
'date_php_min_year',
'date_db_tz_support',
'date_api_use_iso8601',
- );
+ );
foreach ($variables as $variable) {
variable_del($variable);
}
@@ -118,8 +118,9 @@ function date_api_update_last_removed() {
}
/**
- * Move old date format data to new date format tables, and delete the old
- * tables. Insert only values that don't already exist in the new tables, in
+ * Move old date format to new date format tables,and delete the old tables.
+ *
+ * Insert only values that don't already exist in the new tables, in
* case new version of those custom values have already been created.
*/
function date_api_update_7000() {
diff --git a/sites/all/modules/contrib/fields/date/date_api/date_api.module b/sites/all/modules/contrib/fields/date/date_api/date_api.module
index b1be6e5f..2a973ccf 100644
--- a/sites/all/modules/contrib/fields/date/date_api/date_api.module
+++ b/sites/all/modules/contrib/fields/date/date_api/date_api.module
@@ -59,16 +59,16 @@ function date_help($path, $arg) {
}
if (module_exists('date_tools')) {
- $output .= '
Date Tools
' . t('Dates and calendars can be complicated to set up. The !date_wizard makes it easy to create a simple date content type and with a date field. ', array('!date_wizard' => l(t('Date wizard'), 'admin/config/date/tools/date_wizard')));
+ $output .= '
Date Tools
' . t('Dates and calendars can be complicated to set up. The !date_wizard makes it easy to create a simple date content type and with a date field.', array('!date_wizard' => l(t('Date wizard'), 'admin/config/date/tools/date_wizard')));
}
else {
- $output .= '
Date Tools
' . t('Dates and calendars can be complicated to set up. If you enable the Date Tools module, it provides a Date Wizard that makes it easy to create a simple date content type with a date field. ');
+ $output .= '
Date Tools
' . t('Dates and calendars can be complicated to set up. If you enable the Date Tools module, it provides a Date Wizard that makes it easy to create a simple date content type with a date field.');
}
$output .= '
More Information
' . t('Complete documentation for the Date and Date API modules is available at http://drupal.org/node/92460.', array('@link' => 'http://drupal.org/node/262062')) . '
';
return $output;
- break;
+
}
}
@@ -101,7 +101,7 @@ function date_api_status() {
$value = variable_get('date_format_medium');
if (isset($value)) {
$now = date_now();
- $success_messages[] = $t('The medium date format type has been set to to @value. You may find it helpful to add new format types like Date, Time, Month, or Year, with appropriate formats, at Date and time settings.', array('@value' => $now->format($value), '@regional_date_time' => url('admin/config/regional/date-time')));
+ $success_messages[] = $t('The medium date format type has been set to @value. You may find it helpful to add new format types like Date, Time, Month, or Year, with appropriate formats, at Date and time settings.', array('@value' => $now->format($value), '@regional_date_time' => url('admin/config/regional/date-time')));
}
else {
$error_messages[] = $t('The Date API requires that you set up the system date formats to function correctly.', array('@regional_date_time' => url('admin/config/regional/date-time')));
@@ -143,7 +143,15 @@ function date_api_menu() {
class DateObject extends DateTime {
public $granularity = array();
public $errors = array();
- protected static $allgranularity = array('year', 'month', 'day', 'hour', 'minute', 'second', 'timezone');
+ protected static $allgranularity = array(
+ 'year',
+ 'month',
+ 'day',
+ 'hour',
+ 'minute',
+ 'second',
+ 'timezone'
+ );
private $serializedTime;
private $serializedTimezone;
@@ -402,7 +410,7 @@ class DateObject extends DateTime {
* A single date part.
*/
public function removeGranularity($g) {
- if ($key = array_search($g, $this->granularity)) {
+ if (($key = array_search($g, $this->granularity)) !== FALSE) {
unset($this->granularity[$key]);
}
}
@@ -458,23 +466,35 @@ class DateObject extends DateTime {
$true = $this->hasGranularity() && (!$granularity || $flexible || $this->hasGranularity($granularity));
if (!$true && $granularity) {
foreach ((array) $granularity as $part) {
- if (!$this->hasGranularity($part) && in_array($part, array('second', 'minute', 'hour', 'day', 'month', 'year'))) {
+ if (!$this->hasGranularity($part) && in_array($part, array(
+ 'second',
+ 'minute',
+ 'hour',
+ 'day',
+ 'month',
+ 'year')
+ )) {
switch ($part) {
case 'second':
$this->errors[$part] = t('The second is missing.');
break;
+
case 'minute':
$this->errors[$part] = t('The minute is missing.');
break;
+
case 'hour':
$this->errors[$part] = t('The hour is missing.');
break;
+
case 'day':
$this->errors[$part] = t('The day is missing.');
break;
+
case 'month':
$this->errors[$part] = t('The month is missing.');
break;
+
case 'year':
$this->errors[$part] = t('The year is missing.');
break;
@@ -537,7 +557,14 @@ class DateObject extends DateTime {
$temp = date_parse($time);
// Special case for 'now'.
if ($time == 'now') {
- $this->granularity = array('year', 'month', 'day', 'hour', 'minute', 'second');
+ $this->granularity = array(
+ 'year',
+ 'month',
+ 'day',
+ 'hour',
+ 'minute',
+ 'second',
+ );
}
else {
// This PHP date_parse() method currently doesn't have resolution down to
@@ -600,7 +627,14 @@ class DateObject extends DateTime {
return FALSE;
}
$this->granularity = array();
- $final_date = array('hour' => 0, 'minute' => 0, 'second' => 0, 'month' => 1, 'day' => 1, 'year' => 0);
+ $final_date = array(
+ 'hour' => 0,
+ 'minute' => 0,
+ 'second' => 0,
+ 'month' => 1,
+ 'day' => 1,
+ 'year' => 0,
+ );
foreach ($letters as $i => $letter) {
$value = $values[$i];
switch ($letter) {
@@ -609,21 +643,25 @@ class DateObject extends DateTime {
$final_date['day'] = intval($value);
$this->addGranularity('day');
break;
+
case 'n':
case 'm':
$final_date['month'] = intval($value);
$this->addGranularity('month');
break;
+
case 'F':
$array_month_long = array_flip(date_month_names());
$final_date['month'] = array_key_exists($value, $array_month_long) ? $array_month_long[$value] : -1;
$this->addGranularity('month');
break;
+
case 'M':
$array_month = array_flip(date_month_names_abbr());
$final_date['month'] = array_key_exists($value, $array_month) ? $array_month[$value] : -1;
$this->addGranularity('month');
break;
+
case 'Y':
$final_date['year'] = $value;
$this->addGranularity('year');
@@ -631,16 +669,19 @@ class DateObject extends DateTime {
$this->errors['year'] = t('The year is invalid. Please check that entry includes four digits.');
}
break;
+
case 'y':
$year = $value;
// If no century, we add the current one ("06" => "2006").
$final_date['year'] = str_pad($year, 4, substr(date("Y"), 0, 2), STR_PAD_LEFT);
$this->addGranularity('year');
break;
+
case 'a':
case 'A':
$ampm = strtolower($value);
break;
+
case 'g':
case 'h':
case 'G':
@@ -648,14 +689,17 @@ class DateObject extends DateTime {
$final_date['hour'] = intval($value);
$this->addGranularity('hour');
break;
+
case 'i':
$final_date['minute'] = intval($value);
$this->addGranularity('minute');
break;
+
case 's':
$final_date['second'] = intval($value);
$this->addGranularity('second');
break;
+
case 'U':
parent::__construct($value, $tz ? $tz : new DateTimeZone("UTC"));
$this->addGranularity('year');
@@ -665,7 +709,7 @@ class DateObject extends DateTime {
$this->addGranularity('minute');
$this->addGranularity('second');
return $this;
- break;
+
}
}
if (isset($ampm) && $ampm == 'pm' && $final_date['hour'] < 12) {
@@ -758,10 +802,24 @@ class DateObject extends DateTime {
// date or we will get date slippage, i.e. a value of 2011-00-00 will get
// interpreted as November of 2010 by PHP.
if ($full) {
- $arr += array('year' => 0, 'month' => 1, 'day' => 1, 'hour' => 0, 'minute' => 0, 'second' => 0);
+ $arr += array(
+ 'year' => 0,
+ 'month' => 1,
+ 'day' => 1,
+ 'hour' => 0,
+ 'minute' => 0,
+ 'second' => 0,
+ );
}
else {
- $arr += array('year' => '', 'month' => '', 'day' => '', 'hour' => '', 'minute' => '', 'second' => '');
+ $arr += array(
+ 'year' => '',
+ 'month' => '',
+ 'day' => '',
+ 'hour' => '',
+ 'minute' => '',
+ 'second' => '',
+ );
}
$datetime = '';
if ($arr['year'] !== '') {
@@ -839,28 +897,27 @@ class DateObject extends DateTime {
case 'year':
$fallback = $now->format('Y');
return !is_int($value) || empty($value) || $value < variable_get('date_min_year', 1) || $value > variable_get('date_max_year', 4000) ? $fallback : $value;
- break;
+
case 'month':
$fallback = $default == 'first' ? 1 : $now->format('n');
return !is_int($value) || empty($value) || $value <= 0 || $value > 12 ? $fallback : $value;
- break;
+
case 'day':
$fallback = $default == 'first' ? 1 : $now->format('j');
$max_day = isset($year) && isset($month) ? date_days_in_month($year, $month) : 31;
return !is_int($value) || empty($value) || $value <= 0 || $value > $max_day ? $fallback : $value;
- break;
+
case 'hour':
$fallback = $default == 'first' ? 0 : $now->format('G');
return !is_int($value) || $value < 0 || $value > 23 ? $fallback : $value;
- break;
+
case 'minute':
$fallback = $default == 'first' ? 0 : $now->format('i');
return !is_int($value) || $value < 0 || $value > 59 ? $fallback : $value;
- break;
+
case 'second':
$fallback = $default == 'first' ? 0 : $now->format('s');
return !is_int($value) || $value < 0 || $value > 59 ? $fallback : $value;
- break;
}
}
@@ -898,18 +955,23 @@ class DateObject extends DateTime {
case 'year':
$errors['year'] = t('The year is invalid.');
break;
+
case 'month':
$errors['month'] = t('The month is invalid.');
break;
+
case 'day':
$errors['day'] = t('The day is invalid.');
break;
+
case 'hour':
$errors['hour'] = t('The hour is invalid.');
break;
+
case 'minute':
$errors['minute'] = t('The minute is invalid.');
break;
+
case 'second':
$errors['second'] = t('The second is invalid.');
break;
@@ -929,7 +991,7 @@ class DateObject extends DateTime {
* The stop date.
* @param string $measure
* (optional) A granularity date part. Defaults to 'seconds'.
- * @param boolean $absolute
+ * @param bool $absolute
* (optional) Indicate whether the absolute value of the difference should
* be returned or if the sign should be retained. Defaults to TRUE.
*/
@@ -955,10 +1017,13 @@ class DateObject extends DateTime {
// The easy cases first.
case 'seconds':
return $diff;
+
case 'minutes':
return $diff / 60;
+
case 'hours':
return $diff / 3600;
+
case 'years':
return $year_diff;
@@ -1013,7 +1078,7 @@ class DateObject extends DateTime {
$sign = ($year_diff < 0) ? -1 : 1;
for ($i = 1; $i <= abs($year_diff); $i++) {
- date_modify($date1, (($sign > 0) ? '+': '-').'1 year');
+ date_modify($date1, (($sign > 0) ? '+' : '-') . '1 year');
$week_diff += (date_iso_weeks_in_year($date1) * $sign);
}
return $week_diff;
@@ -1060,10 +1125,13 @@ function date_type_format($type) {
switch ($type) {
case DATE_ISO:
return DATE_FORMAT_ISO;
+
case DATE_UNIX:
return DATE_FORMAT_UNIX;
+
case DATE_DATETIME:
return DATE_FORMAT_DATETIME;
+
case DATE_ICAL:
return DATE_FORMAT_ICAL;
}
@@ -1119,7 +1187,7 @@ function date_month_names($required = FALSE) {
}
/**
- * Constructs a translated array of month name abbreviations
+ * Constructs a translated array of month name abbreviations.
*
* @param bool $required
* (optional) If FALSE, the returned array will include a blank value.
@@ -1211,9 +1279,11 @@ function date_week_days_abbr($required = FALSE, $refresh = TRUE, $length = 3) {
case 1:
$context = 'day_abbr1';
break;
+
case 2:
$context = 'day_abbr2';
break;
+
default:
$context = '';
break;
@@ -1248,10 +1318,10 @@ function date_week_days_ordered($weekdays) {
/**
* Constructs an array of years.
*
- * @param int $min
- * The minimum year in the array.
- * @param int $max
- * The maximum year in the array.
+ * @param int $start
+ * The start year in the array.
+ * @param int $end
+ * The end year in the array.
* @param bool $required
* (optional) If FALSE, the returned array will include a blank value.
* Defaults to FALSE.
@@ -1259,16 +1329,16 @@ function date_week_days_ordered($weekdays) {
* @return array
* An array of years in the selected range.
*/
-function date_years($min = 0, $max = 0, $required = FALSE) {
+function date_years($start = 0, $end = 0, $required = FALSE) {
// Ensure $min and $max are valid values.
- if (empty($min)) {
- $min = intval(date('Y', REQUEST_TIME) - 3);
+ if (empty($start)) {
+ $start = intval(date('Y', REQUEST_TIME) - 3);
}
- if (empty($max)) {
- $max = intval(date('Y', REQUEST_TIME) + 3);
+ if (empty($end)) {
+ $end = intval(date('Y', REQUEST_TIME) + 3);
}
$none = array(0 => '');
- return !$required ? $none + drupal_map_assoc(range($min, $max)) : drupal_map_assoc(range($min, $max));
+ return !$required ? $none + drupal_map_assoc(range($start, $end)) : drupal_map_assoc(range($start, $end));
}
/**
@@ -1474,7 +1544,14 @@ function date_granularity_names() {
* An array of date parts.
*/
function date_granularity_sorted($granularity) {
- return array_intersect(array('year', 'month', 'day', 'hour', 'minute', 'second'), $granularity);
+ return array_intersect(array(
+ 'year',
+ 'month',
+ 'day',
+ 'hour',
+ 'minute',
+ 'second',
+ ), $granularity);
}
/**
@@ -1492,14 +1569,19 @@ function date_granularity_array_from_precision($precision) {
switch ($precision) {
case 'year':
return array_slice($granularity_array, -6, 1);
+
case 'month':
return array_slice($granularity_array, -6, 2);
+
case 'day':
return array_slice($granularity_array, -6, 3);
+
case 'hour':
return array_slice($granularity_array, -6, 4);
+
case 'minute':
return array_slice($granularity_array, -6, 5);
+
default:
return $granularity_array;
}
@@ -1533,14 +1615,19 @@ function date_granularity_format($granularity) {
switch ($granularity) {
case 'year':
return substr($format, 0, 1);
+
case 'month':
return substr($format, 0, 3);
+
case 'day':
return substr($format, 0, 5);
+
case 'hour';
return substr($format, 0, 7);
+
case 'minute':
return substr($format, 0, 9);
+
default:
return $format;
}
@@ -1657,40 +1744,51 @@ function date_format_date($date, $type = 'medium', $format = '', $langcode = NUL
case 'l':
$datestring .= t($date->format('l'), array(), array('context' => '', 'langcode' => $langcode));
break;
+
case 'D':
$datestring .= t($date->format('D'), array(), array('context' => '', 'langcode' => $langcode));
break;
+
case 'F':
$datestring .= t($date->format('F'), array(), array('context' => 'Long month name', 'langcode' => $langcode));
break;
+
case 'M':
$datestring .= t($date->format('M'), array(), array('langcode' => $langcode));
break;
+
case 'A':
case 'a':
$datestring .= t($date->format($c), array(), array('context' => 'ampm', 'langcode' => $langcode));
break;
+
// The timezone name translations can use t().
case 'e':
case 'T':
$datestring .= t($date->format($c));
break;
+
// Remaining date parts need no translation.
case 'O':
$datestring .= sprintf('%s%02d%02d', (date_offset_get($date) < 0 ? '-' : '+'), abs(date_offset_get($date) / 3600), abs(date_offset_get($date) % 3600) / 60);
break;
+
case 'P':
$datestring .= sprintf('%s%02d:%02d', (date_offset_get($date) < 0 ? '-' : '+'), abs(date_offset_get($date) / 3600), abs(date_offset_get($date) % 3600) / 60);
break;
+
case 'Z':
$datestring .= date_offset_get($date);
break;
+
case '\\':
$datestring .= $format[++$i];
break;
+
case 'r':
- $datestring .= date_format_date($date, 'custom', 'D, d M Y H:i:s O', $langcode);
+ $datestring .= date_format_date($date, 'custom', 'D, d M Y H:i:s O', 'en');
break;
+
default:
if (strpos('BdcgGhHiIjLmnNosStTuUwWYyz', $c) !== FALSE) {
$datestring .= $date->format($c);
@@ -1739,8 +1837,8 @@ function date_format_interval($date, $granularity = 2, $display_ago = TRUE) {
* (optional) Optionally force time to a specific timezone, defaults to user
* timezone, if set, otherwise site timezone. Defaults to NULL.
*
- * @param boolean $reset [optional]
- * Static cache reset
+ * @param bool $reset
+ * (optional) Static cache reset.
*
* @return object
* The current time as a date object.
@@ -1831,7 +1929,7 @@ function date_days_in_month($year, $month) {
* @param mixed $date
* (optional) The current date object, or a date string. Defaults to NULL.
*
- * @return integer
+ * @return int
* The number of days in the year.
*/
function date_days_in_year($date = NULL) {
@@ -1860,7 +1958,7 @@ function date_days_in_year($date = NULL) {
* @param mixed $date
* (optional) The current date object, or a date string. Defaults to NULL.
*
- * @return integer
+ * @return int
* The number of ISO weeks in a year.
*/
function date_iso_weeks_in_year($date = NULL) {
@@ -1952,7 +2050,7 @@ function date_week_range($week, $year) {
// Move forwards to the last day of the week.
$max_date = clone($min_date);
- date_modify($max_date, '+7 days');
+ date_modify($max_date, '+6 days');
if (date_format($min_date, 'Y') != $year) {
$min_date = new DateObject($year . '-01-01 00:00:00');
@@ -1986,7 +2084,7 @@ function date_iso_week_range($week, $year) {
// Move forwards to the last day of the week.
$max_date = clone($min_date);
- date_modify($max_date, '+7 days');
+ date_modify($max_date, '+6 days');
return array($min_date, $max_date);
}
@@ -2094,7 +2192,8 @@ function date_has_time($granularity) {
if (!is_array($granularity)) {
$granularity = array();
}
- return (bool) count(array_intersect($granularity, array('hour', 'minute', 'second')));
+ $options = array('hour', 'minute', 'second');
+ return (bool) count(array_intersect($granularity, $options));
}
/**
@@ -2110,7 +2209,8 @@ function date_has_date($granularity) {
if (!is_array($granularity)) {
$granularity = array();
}
- return (bool) count(array_intersect($granularity, array('year', 'month', 'day')));
+ $options = array('year', 'month', 'day');
+ return (bool) count(array_intersect($granularity, $options));
}
/**
@@ -2128,8 +2228,10 @@ function date_part_format($part, $format) {
switch ($part) {
case 'date':
return date_limit_format($format, array('year', 'month', 'day'));
+
case 'time':
return date_limit_format($format, array('hour', 'minute', 'second'));
+
default:
return date_limit_format($format, array($part));
}
@@ -2157,7 +2259,7 @@ function date_limit_format($format, $granularity) {
$drupal_static_fast['formats'] = &drupal_static(__FUNCTION__);
}
$formats = &$drupal_static_fast['formats'];
- $format_granularity_cid = $format .'|'. implode(',', $granularity);
+ $format_granularity_cid = $format . '|' . implode(',', $granularity);
if (isset($formats[$format_granularity_cid])) {
return $formats[$format_granularity_cid];
}
@@ -2191,21 +2293,27 @@ function date_limit_format($format, $granularity) {
case 'year':
$regex[] = '([\-/\.,:]?\s?(? "$path/theme",
);
return array(
- 'date_nav_title' => $base + array('variables' => array('granularity' => NULL, 'view' => NULL, 'link' => NULL, 'format' => NULL)),
+ 'date_nav_title' => $base + array(
+ 'variables' => array(
+ 'granularity' => NULL, 'view' => NULL, 'link' => NULL, 'format' => NULL
+ ),
+ ),
'date_timezone' => $base + array('render element' => 'element'),
'date_select' => $base + array('render element' => 'element'),
'date_text' => $base + array('render element' => 'element'),
@@ -2355,7 +2481,11 @@ function date_api_theme($existing, $type, $theme, $path) {
'date_part_label_time' => $base + array('variables' => array('date_part' => NULL, 'element' => NULL)),
'date_views_filter_form' => $base + array('template' => 'date-views-filter-form', 'render element' => 'form'),
'date_calendar_day' => $base + array('variables' => array('date' => NULL)),
- 'date_time_ago' => $base + array('variables' => array('start_date' => NULL, 'end_date' => NULL, 'interval' => NULL)),
+ 'date_time_ago' => $base + array(
+ 'variables' => array(
+ 'start_date' => NULL, 'end_date' => NULL, 'interval' => NULL
+ ),
+ ),
);
}
@@ -2375,9 +2505,11 @@ function date_get_timezone($handling, $timezone = '') {
case 'date':
$timezone = !empty($timezone) ? $timezone : date_default_timezone();
break;
+
case 'utc':
$timezone = 'UTC';
break;
+
default:
$timezone = date_default_timezone();
}
@@ -2404,6 +2536,7 @@ function date_get_timezone_db($handling, $timezone = NULL) {
// These handling modes all convert to UTC before storing in the DB.
$timezone = 'UTC';
break;
+
case ('date'):
if ($timezone == NULL) {
// This shouldn't happen, since it's meaning is undefined. But we need
@@ -2411,6 +2544,7 @@ function date_get_timezone_db($handling, $timezone = NULL) {
$timezone = date_default_timezone();
}
break;
+
case ('none'):
default:
$timezone = date_default_timezone();
@@ -2465,12 +2599,12 @@ function date_order() {
* TRUE if the date range is valid, FALSE otherwise.
*/
function date_range_valid($string) {
- $matches = preg_match('@^(\-[0-9]+|[0-9]{4}):([\+|\-][0-9]+|[0-9]{4})$@', $string);
+ $matches = preg_match('@^([\+\-][0-9]+|[0-9]{4}):([\+\-][0-9]+|[0-9]{4})$@', $string);
return $matches < 1 ? FALSE : TRUE;
}
/**
- * Splits a string like -3:+3 or 2001:2010 into an array of min and max years.
+ * Splits a string like -3:+3 or 2001:2010 into an array of start and end years.
*
* Center the range around the current year, if any, but expand it far
* enough so it will pick up the year value in the field in case
@@ -2482,45 +2616,44 @@ function date_range_valid($string) {
* (optional) A date object. Defaults to NULL.
*
* @return array
- * A numerically indexed array, containing a minimum and maximum year.
+ * A numerically indexed array, containing a start and end year.
*/
function date_range_years($string, $date = NULL) {
$this_year = date_format(date_now(), 'Y');
- list($min_year, $max_year) = explode(':', $string);
+ list($start_year, $end_year) = explode(':', $string);
// Valid patterns would be -5:+5, 0:+1, 2008:2010.
- $plus_pattern = '@[\+|\-][0-9]{1,4}@';
+ $plus_pattern = '@[\+\-][0-9]{1,4}@';
$year_pattern = '@^[0-9]{4}@';
- if (!preg_match($year_pattern, $min_year, $matches)) {
- if (preg_match($plus_pattern, $min_year, $matches)) {
- $min_year = $this_year + $matches[0];
+ if (!preg_match($year_pattern, $start_year, $matches)) {
+ if (preg_match($plus_pattern, $start_year, $matches)) {
+ $start_year = $this_year + $matches[0];
}
else {
- $min_year = $this_year;
+ $start_year = $this_year;
}
}
- if (!preg_match($year_pattern, $max_year, $matches)) {
- if (preg_match($plus_pattern, $max_year, $matches)) {
- $max_year = $this_year + $matches[0];
+ if (!preg_match($year_pattern, $end_year, $matches)) {
+ if (preg_match($plus_pattern, $end_year, $matches)) {
+ $end_year = $this_year + $matches[0];
}
else {
- $max_year = $this_year;
+ $end_year = $this_year;
}
}
- // We expect the $min year to be less than the $max year.
- // Some custom values for -99:+99 might not obey that.
- if ($min_year > $max_year) {
- $temp = $max_year;
- $max_year = $min_year;
- $min_year = $temp;
- }
// If there is a current value, stretch the range to include it.
$value_year = is_object($date) ? $date->format('Y') : '';
if (!empty($value_year)) {
- $min_year = min($value_year, $min_year);
- $max_year = max($value_year, $max_year);
+ if ($start_year <= $end_year) {
+ $start_year = min($value_year, $start_year);
+ $end_year = max($value_year, $end_year);
+ }
+ else {
+ $start_year = max($value_year, $start_year);
+ $end_year = min($value_year, $end_year);
+ }
}
- return array($min_year, $max_year);
+ return array($start_year, $end_year);
}
/**
@@ -2680,6 +2813,7 @@ function date_is_all_day($string1, $string2, $granularity = 'second', $increment
|| ($hour2 == 23 && in_array($min2, array($max_minutes, 59)) && in_array($sec2, array($max_seconds, 59)))
|| ($hour1 == 0 && $hour2 == 0 && $min1 == 0 && $min2 == 0 && $sec1 == 0 && $sec2 == 0);
break;
+
case 'minute':
$min_match = $time1 == '00:00:00'
|| ($hour1 == 0 && $min1 == 0);
@@ -2687,6 +2821,7 @@ function date_is_all_day($string1, $string2, $granularity = 'second', $increment
|| ($hour2 == 23 && in_array($min2, array($max_minutes, 59)))
|| ($hour1 == 0 && $hour2 == 0 && $min1 == 0 && $min2 == 0);
break;
+
case 'hour':
$min_match = $time1 == '00:00:00'
|| ($hour1 == 0);
@@ -2694,6 +2829,7 @@ function date_is_all_day($string1, $string2, $granularity = 'second', $increment
|| ($hour2 == 23)
|| ($hour1 == 0 && $hour2 == 0);
break;
+
default:
$min_match = TRUE;
$max_match = FALSE;
@@ -2754,15 +2890,21 @@ function date_is_date($date) {
}
/**
- * This function will replace ISO values that have the pattern 9999-00-00T00:00:00
- * with a pattern like 9999-01-01T00:00:00, to match the behavior of non-ISO
- * dates and ensure that date objects created from this value contain a valid month
- * and day. Without this fix, the ISO date '2020-00-00T00:00:00' would be created as
+ * Replace specific ISO values using patterns.
+ *
+ * Function will replace ISO values that have the pattern 9999-00-00T00:00:00
+ * with a pattern like 9999-01-01T00:00:00, to match the behavior of non-ISO dates
+ * and ensure that date objects created from this value contain a valid month
+ * and day.
+ * Without this fix, the ISO date '2020-00-00T00:00:00' would be created as
* November 30, 2019 (the previous day in the previous month).
*
* @param string $iso_string
* An ISO string that needs to be made into a complete, valid date.
*
+ * @return mixed|string
+ * replaced value, or incoming value.
+ *
* @TODO Expand on this to work with all sorts of partial ISO dates.
*/
function date_make_iso_valid($iso_string) {
diff --git a/sites/all/modules/contrib/fields/date/date_api/date_api_elements.inc b/sites/all/modules/contrib/fields/date/date_api/date_api_elements.inc
index 57e41615..fc91205c 100644
--- a/sites/all/modules/contrib/fields/date/date_api/date_api_elements.inc
+++ b/sites/all/modules/contrib/fields/date/date_api/date_api_elements.inc
@@ -116,15 +116,19 @@ function date_default_date($element) {
case 16:
$format = 'Y-m-d H:i';
break;
+
case 13:
$format = 'Y-m-d H';
break;
+
case 10:
$format = 'Y-m-d';
break;
+
case 7:
$format = 'Y-m';
break;
+
case 4:
$format = 'Y';
break;
@@ -170,7 +174,7 @@ function date_year_range_element_process($element, &$form_state, $form) {
$element['#attached']['js'][] = drupal_get_path('module', 'date_api') . '/date_year_range.js';
$context = array(
- 'form' => $form,
+ 'form' => $form,
);
drupal_alter('date_year_range_process', $element, $form_state, $context);
@@ -256,7 +260,7 @@ function date_timezone_element_process($element, &$form_state, $form) {
}
$context = array(
- 'form' => $form,
+ 'form' => $form,
);
drupal_alter('date_timezone_process', $element, $form_state, $context);
@@ -264,7 +268,7 @@ function date_timezone_element_process($element, &$form_state, $form) {
}
/**
- * Validation for timezone input
+ * Validation for timezone input.
*
* Move the timezone value from the nested field back to the original field.
*/
@@ -307,7 +311,6 @@ function date_text_element_value_callback($element, $input = FALSE, &$form_state
*
* The exact parts displayed in the field are those in #date_granularity.
* The display of each part comes from #date_format.
- *
*/
function date_text_element_process($element, &$form_state, $form) {
if (date_hidden_element($element)) {
@@ -323,9 +326,18 @@ function date_text_element_process($element, &$form_state, $form) {
$now = date_example_date();
$element['date']['#title'] = t('Date');
$element['date']['#title_display'] = 'invisible';
- $element['date']['#description'] = ' ' . t('Format: @date', array('@date' => date_format_date(date_example_date(), 'custom', $element['#date_format'])));
+ $element['date']['#description'] = ' ' . t('Format: @date', array(
+ '@date' => date_format_date(date_example_date(), 'custom', $element['#date_format']
+ )));
$element['date']['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
+ // Make changes if instance is set to be rendered as a regular field.
+ if (!empty($element['#instance']['widget']['settings']['no_fieldset']) && $element['#field']['cardinality'] == 1) {
+ $element['date']['#title'] = check_plain($element['#instance']['label']);
+ $element['date']['#title_display'] = $element['#title_display'];
+ $element['date']['#required'] = $element['#required'];
+ }
+
// Keep the system from creating an error message for the sub-element.
// We'll set our own message on the parent element.
// $element['date']['#required'] = $element['#required'];
@@ -341,7 +353,7 @@ function date_text_element_process($element, &$form_state, $form) {
}
$context = array(
- 'form' => $form,
+ 'form' => $form,
);
drupal_alter('date_text_process', $element, $form_state, $context);
@@ -349,12 +361,11 @@ function date_text_element_process($element, &$form_state, $form) {
}
/**
- * Validation for text input.
+ * Validation for text input.
*
* When used as a Views widget, the validation step always gets triggered,
* even with no form submission. Before form submission $element['#value']
* contains a string, after submission it contains an array.
- *
*/
function date_text_validate($element, &$form_state) {
if (date_hidden_element($element)) {
@@ -367,6 +378,11 @@ function date_text_validate($element, &$form_state) {
$input_exists = NULL;
$input = drupal_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
+ // Trim extra spacing off user input of text fields.
+ if (isset($input['date'])) {
+ $input['date'] = trim($input['date']);
+ }
+
drupal_alter('date_text_pre_validate', $element, $form_state, $input);
$label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
@@ -421,7 +437,14 @@ function date_text_input_date($element, $input) {
* Element value callback for date_select element.
*/
function date_select_element_value_callback($element, $input = FALSE, &$form_state = array()) {
- $return = array('year' => '', 'month' => '', 'day' => '', 'hour' => '', 'minute' => '', 'second' => '');
+ $return = array(
+ 'year' => '',
+ 'month' => '',
+ 'day' => '',
+ 'hour' => '',
+ 'minute' => '',
+ 'second' => '',
+ );
$date = NULL;
if ($input !== FALSE) {
$return = $input;
@@ -431,7 +454,14 @@ function date_select_element_value_callback($element, $input = FALSE, &$form_sta
$date = date_default_date($element);
}
$granularity = date_format_order($element['#date_format']);
- $formats = array('year' => 'Y', 'month' => 'n', 'day' => 'j', 'hour' => 'H', 'minute' => 'i', 'second' => 's');
+ $formats = array(
+ 'year' => 'Y',
+ 'month' => 'n',
+ 'day' => 'j',
+ 'hour' => 'H',
+ 'minute' => 'i',
+ 'second' => 's',
+ );
foreach ($granularity as $field) {
if ($field != 'timezone') {
$return[$field] = date_is_date($date) ? $date->format($formats[$field]) : '';
@@ -449,7 +479,6 @@ function date_select_element_value_callback($element, $input = FALSE, &$form_sta
*
* The exact parts displayed in the field are those in #date_granularity.
* The display of each part comes from ['#date_settings']['format'].
- *
*/
function date_select_element_process($element, &$form_state, $form) {
if (date_hidden_element($element)) {
@@ -473,7 +502,14 @@ function date_select_element_process($element, &$form_state, $form) {
// Store a hidden value for all date parts not in the current display.
$granularity = date_format_order($element['#date_format']);
- $formats = array('year' => 'Y', 'month' => 'n', 'day' => 'j', 'hour' => 'H', 'minute' => 'i', 'second' => 's');
+ $formats = array(
+ 'year' => 'Y',
+ 'month' => 'n',
+ 'day' => 'j',
+ 'hour' => 'H',
+ 'minute' => 'i',
+ 'second' => 's',
+ );
foreach (date_nongranularity($granularity) as $field) {
if ($field != 'timezone') {
$element[$field] = array(
@@ -490,7 +526,7 @@ function date_select_element_process($element, &$form_state, $form) {
}
$context = array(
- 'form' => $form,
+ 'form' => $form,
);
drupal_alter('date_select_process', $element, $form_state, $context);
@@ -521,7 +557,7 @@ function date_parts_element($element, $date, $format) {
$sub_element = array('#granularity' => $granularity);
$order = array_flip($granularity);
- $hours_format = strpos(strtolower($element['#date_format']), 'a') ? 'g': 'G';
+ $hours_format = strpos(strtolower($element['#date_format']), 'a') ? 'g' : 'G';
$month_function = strpos($element['#date_format'], 'F') !== FALSE ? 'date_month_names' : 'date_month_names_abbr';
$count = 0;
$increment = min(intval($element['#date_increment']), 1);
@@ -539,26 +575,29 @@ function date_parts_element($element, $date, $format) {
switch ($field) {
case 'year':
$range = date_range_years($element['#date_year_range'], $date);
- $min_year = $range[0];
- $max_year = $range[1];
+ $start_year = $range[0];
+ $end_year = $range[1];
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('Y') : '';
if ($part_type == 'select') {
- $sub_element[$field]['#options'] = drupal_map_assoc(date_years($min_year, $max_year, $part_required));
+ $sub_element[$field]['#options'] = drupal_map_assoc(date_years($start_year, $end_year, $part_required));
}
break;
+
case 'month':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('n') : '';
if ($part_type == 'select') {
$sub_element[$field]['#options'] = $month_function($part_required);
}
break;
+
case 'day':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('j') : '';
if ($part_type == 'select') {
$sub_element[$field]['#options'] = drupal_map_assoc(date_days($part_required));
}
break;
+
case 'hour':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format($hours_format) : '';
if ($part_type == 'select') {
@@ -566,6 +605,7 @@ function date_parts_element($element, $date, $format) {
}
$sub_element[$field]['#prefix'] = theme('date_part_hour_prefix', $element);
break;
+
case 'minute':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('i') : '';
if ($part_type == 'select') {
@@ -573,6 +613,7 @@ function date_parts_element($element, $date, $format) {
}
$sub_element[$field]['#prefix'] = theme('date_part_minsec_prefix', $element);
break;
+
case 'second':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('s') : '';
if ($part_type == 'select') {
diff --git a/sites/all/modules/contrib/fields/date/date_api/date_api_ical.inc b/sites/all/modules/contrib/fields/date/date_api/date_api_ical.inc
index 2ca484e7..4911298c 100644
--- a/sites/all/modules/contrib/fields/date/date_api/date_api_ical.inc
+++ b/sites/all/modules/contrib/fields/date/date_api/date_api_ical.inc
@@ -181,6 +181,7 @@ function date_ical_parse($icaldatafolded = array()) {
$parent[array_pop($parents)][] = array_pop($subgroups);
}
break;
+
// Add the timezones in with their index their TZID.
case 'VTIMEZONE':
$subgroup = end($subgroups);
@@ -196,6 +197,7 @@ function date_ical_parse($icaldatafolded = array()) {
array_pop($subgroups);
array_pop($parents);
break;
+
// Do some fun stuff with durations and all_day events and then append
// to parent.
case 'VEVENT':
@@ -222,9 +224,9 @@ function date_ical_parse($icaldatafolded = array()) {
// assumes the end date is inclusive.
if (!empty($subgroup['DTEND']) && (!empty($subgroup['DTEND']['all_day']))) {
// Make the end date one day earlier.
- $date = new DateObject ($subgroup['DTEND']['datetime'] . ' 00:00:00', $subgroup['DTEND']['tz']);
+ $date = new DateObject($subgroup['DTEND']['datetime'] . ' 00:00:00', $subgroup['DTEND']['tz']);
date_modify($date, '-1 day');
- $subgroup['DTEND']['datetime'] = date_format($date, 'Y-m-d');
+ $subgroup['DTEND']['datetime'] = date_format($date, 'Y-m-d');
}
// If a start datetime is defined AND there is no definition for
// the end datetime THEN make the end datetime equal the start
@@ -239,7 +241,7 @@ function date_ical_parse($icaldatafolded = array()) {
if (!empty($subgroup['DTSTART']['all_day'])) {
$subgroup['all_day'] = TRUE;
}
- // Add this element to the parent as an array under the
+ // Add this element to the parent as an array under the.
prev($subgroups);
$parent = &$subgroups[key($subgroups)];
@@ -264,12 +266,13 @@ function date_ical_parse($icaldatafolded = array()) {
$field = !empty($matches[2]) ? $matches[2] : '';
$data = !empty($matches[3]) ? $matches[3] : '';
$parse_result = '';
+
switch ($name) {
// Keep blank lines out of the results.
case '':
break;
- // Lots of properties have date values that must be parsed out.
+ // Lots of properties have date values that must be parsed out.
case 'CREATED':
case 'LAST-MODIFIED':
case 'DTSTART':
@@ -317,9 +320,9 @@ function date_ical_parse($icaldatafolded = array()) {
$parse_result = date_ical_parse_location($field, $data);
break;
- // For all other properties, just store the property and the value.
- // This can be expanded on in the future if other properties should
- // be given special treatment.
+ // For all other properties, just store the property and the value.
+ // This can be expanded on in the future if other properties should
+ // be given special treatment.
default:
$parse_result = $data;
break;
@@ -360,7 +363,7 @@ function date_ical_parse($icaldatafolded = array()) {
* has no timezone; the ical specs say no timezone
* conversion should be done if no timezone info is
* supplied
- * @todo
+ * @todo
* Another option for dates is the format PROPERTY;VALUE=PERIOD:XXXX. The
* period may include a duration, or a date and a duration, or two dates, so
* would have to be split into parts and run through date_ical_parse_date()
@@ -401,6 +404,7 @@ function date_ical_parse_date($field, $data) {
// Date.
$datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
break;
+
case 'DATE-TIME':
preg_match(DATE_REGEX_ICAL_DATETIME, $data, $regs);
// Date.
@@ -519,12 +523,12 @@ function date_ical_parse_duration(&$subgroup, $field = 'DURATION') {
$data = $items['DATA'];
preg_match('/^P(\d{1,4}[Y])?(\d{1,2}[M])?(\d{1,2}[W])?(\d{1,2}[D])?([T]{0,1})?(\d{1,2}[H])?(\d{1,2}[M])?(\d{1,2}[S])?/', $data, $duration);
$items['year'] = isset($duration[1]) ? str_replace('Y', '', $duration[1]) : '';
- $items['month'] = isset($duration[2]) ?str_replace('M', '', $duration[2]) : '';
- $items['week'] = isset($duration[3]) ?str_replace('W', '', $duration[3]) : '';
- $items['day'] = isset($duration[4]) ?str_replace('D', '', $duration[4]) : '';
- $items['hour'] = isset($duration[6]) ?str_replace('H', '', $duration[6]) : '';
- $items['minute'] = isset($duration[7]) ?str_replace('M', '', $duration[7]) : '';
- $items['second'] = isset($duration[8]) ?str_replace('S', '', $duration[8]) : '';
+ $items['month'] = isset($duration[2]) ? str_replace('M', '', $duration[2]) : '';
+ $items['week'] = isset($duration[3]) ? str_replace('W', '', $duration[3]) : '';
+ $items['day'] = isset($duration[4]) ? str_replace('D', '', $duration[4]) : '';
+ $items['hour'] = isset($duration[6]) ? str_replace('H', '', $duration[6]) : '';
+ $items['minute'] = isset($duration[7]) ? str_replace('M', '', $duration[7]) : '';
+ $items['second'] = isset($duration[8]) ? str_replace('S', '', $duration[8]) : '';
$start_date = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['datetime'] : date_format(date_now(), DATE_FORMAT_ISO);
$timezone = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['tz'] : variable_get('date_default_timezone');
if (empty($timezone)) {
@@ -542,7 +546,7 @@ function date_ical_parse_duration(&$subgroup, $field = 'DURATION') {
'datetime' => date_format($date2, DATE_FORMAT_DATETIME),
'all_day' => isset($subgroup['DTSTART']['all_day']) ? $subgroup['DTSTART']['all_day'] : 0,
'tz' => $timezone,
- );
+ );
$duration = date_format($date2, 'U') - date_format($date, 'U');
$subgroup['DURATION'] = array('DATA' => $data, 'DURATION' => $duration);
}
@@ -631,7 +635,6 @@ function date_ical_date($ical_date, $to_tz = FALSE) {
*
* @return string
* Escaped text
- *
*/
function date_ical_escape_text($text) {
$text = drupal_html_to_text($text);
@@ -693,14 +696,14 @@ function date_ical_escape_text($text) {
* )
*/
function date_api_ical_build_rrule($form_values) {
- $RRULE = '';
+ $rrule = '';
if (empty($form_values) || !is_array($form_values)) {
- return $RRULE;
+ return $rrule;
}
// Grab the RRULE data and put them into iCal RRULE format.
- $RRULE .= 'RRULE:FREQ=' . (!array_key_exists('FREQ', $form_values) ? 'DAILY' : $form_values['FREQ']);
- $RRULE .= ';INTERVAL=' . (!array_key_exists('INTERVAL', $form_values) ? 1 : $form_values['INTERVAL']);
+ $rrule .= 'RRULE:FREQ=' . (!array_key_exists('FREQ', $form_values) ? 'DAILY' : $form_values['FREQ']);
+ $rrule .= ';INTERVAL=' . (!array_key_exists('INTERVAL', $form_values) ? 1 : $form_values['INTERVAL']);
// Unset the empty 'All' values.
if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY'])) {
@@ -713,14 +716,14 @@ function date_api_ical_build_rrule($form_values) {
unset($form_values['BYMONTHDAY']['']);
}
- if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY']) && $BYDAY = implode(",", $form_values['BYDAY'])) {
- $RRULE .= ';BYDAY=' . $BYDAY;
+ if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY']) && $byday = implode(",", $form_values['BYDAY'])) {
+ $rrule .= ';BYDAY=' . $byday;
}
- if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH']) && $BYMONTH = implode(",", $form_values['BYMONTH'])) {
- $RRULE .= ';BYMONTH=' . $BYMONTH;
+ if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH']) && $bymonth = implode(",", $form_values['BYMONTH'])) {
+ $rrule .= ';BYMONTH=' . $bymonth;
}
- if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY']) && $BYMONTHDAY = implode(",", $form_values['BYMONTHDAY'])) {
- $RRULE .= ';BYMONTHDAY=' . $BYMONTHDAY;
+ if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY']) && $bymonthday = implode(",", $form_values['BYMONTHDAY'])) {
+ $rrule .= ';BYMONTHDAY=' . $bymonthday;
}
// The UNTIL date is supposed to always be expressed in UTC.
// The input date values may already have been converted to a date object on a
@@ -731,8 +734,17 @@ function date_api_ical_build_rrule($form_values) {
if (!is_object($form_values['UNTIL']['datetime'])) {
// If this is a date without time, give it time.
if (strlen($form_values['UNTIL']['datetime']) < 11) {
+ $granularity_options = drupal_map_assoc(array(
+ 'year',
+ 'month',
+ 'day',
+ 'hour',
+ 'minute',
+ 'second',
+ ));
+
$form_values['UNTIL']['datetime'] .= ' 23:59:59';
- $form_values['UNTIL']['granularity'] = serialize(drupal_map_assoc(array('year', 'month', 'day', 'hour', 'minute', 'second')));
+ $form_values['UNTIL']['granularity'] = serialize($granularity_options);
$form_values['UNTIL']['all_day'] = FALSE;
}
$until = date_ical_date($form_values['UNTIL'], 'UTC');
@@ -740,21 +752,21 @@ function date_api_ical_build_rrule($form_values) {
else {
$until = $form_values['UNTIL']['datetime'];
}
- $RRULE .= ';UNTIL=' . date_format($until, DATE_FORMAT_ICAL) . 'Z';
+ $rrule .= ';UNTIL=' . date_format($until, DATE_FORMAT_ICAL) . 'Z';
}
// Our form doesn't allow a value for COUNT, but it may be needed by
// modules using the API, so add it to the rule.
if (array_key_exists('COUNT', $form_values)) {
- $RRULE .= ';COUNT=' . $form_values['COUNT'];
+ $rrule .= ';COUNT=' . $form_values['COUNT'];
}
// iCal rules presume the week starts on Monday unless otherwise specified,
// so we'll specify it.
if (array_key_exists('WKST', $form_values)) {
- $RRULE .= ';WKST=' . $form_values['WKST'];
+ $rrule .= ';WKST=' . $form_values['WKST'];
}
else {
- $RRULE .= ';WKST=' . date_repeat_dow2day(variable_get('date_first_day', 0));
+ $rrule .= ';WKST=' . date_repeat_dow2day(variable_get('date_first_day', 0));
}
// Exceptions dates go last, on their own line.
@@ -765,7 +777,7 @@ function date_api_ical_build_rrule($form_values) {
foreach ($form_values['EXDATE'] as $value) {
if (!empty($value['datetime'])) {
$date = !is_object($value['datetime']) ? date_ical_date($value, 'UTC') : $value['datetime'];
- $ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z': '';
+ $ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z' : '';
if (!empty($ex_date)) {
$ex_dates[] = $ex_date;
}
@@ -773,11 +785,11 @@ function date_api_ical_build_rrule($form_values) {
}
if (!empty($ex_dates)) {
sort($ex_dates);
- $RRULE .= chr(13) . chr(10) . 'EXDATE:' . implode(',', $ex_dates);
+ $rrule .= chr(13) . chr(10) . 'EXDATE:' . implode(',', $ex_dates);
}
}
elseif (!empty($form_values['EXDATE'])) {
- $RRULE .= chr(13) . chr(10) . 'EXDATE:' . $form_values['EXDATE'];
+ $rrule .= chr(13) . chr(10) . 'EXDATE:' . $form_values['EXDATE'];
}
// Exceptions dates go last, on their own line.
@@ -785,19 +797,19 @@ function date_api_ical_build_rrule($form_values) {
$ex_dates = array();
foreach ($form_values['RDATE'] as $value) {
$date = !is_object($value['datetime']) ? date_ical_date($value, 'UTC') : $value['datetime'];
- $ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z': '';
+ $ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z' : '';
if (!empty($ex_date)) {
$ex_dates[] = $ex_date;
}
}
if (!empty($ex_dates)) {
sort($ex_dates);
- $RRULE .= chr(13) . chr(10) . 'RDATE:' . implode(',', $ex_dates);
+ $rrule .= chr(13) . chr(10) . 'RDATE:' . implode(',', $ex_dates);
}
}
elseif (!empty($form_values['RDATE'])) {
- $RRULE .= chr(13) . chr(10) . 'RDATE:' . $form_values['RDATE'];
+ $rrule .= chr(13) . chr(10) . 'RDATE:' . $form_values['RDATE'];
}
- return $RRULE;
+ return $rrule;
}
diff --git a/sites/all/modules/contrib/fields/date/date_api/date_api_sql.inc b/sites/all/modules/contrib/fields/date/date_api/date_api_sql.inc
index e02f0507..a95ca4ef 100644
--- a/sites/all/modules/contrib/fields/date/date_api/date_api_sql.inc
+++ b/sites/all/modules/contrib/fields/date/date_api/date_api_sql.inc
@@ -23,13 +23,14 @@ function date_sql_concat($array) {
switch (Database::getConnection()->databaseType()) {
case 'mysql':
return "CONCAT(" . implode(",", $array) . ")";
+
case 'pgsql':
return implode(" || ", $array);
}
}
/**
- * Helper function to do cross-database NULL replacements
+ * Helper function to do cross-database NULL replacements.
*
* @param array $array
* An array of values to test for NULL values.
@@ -61,6 +62,7 @@ function date_sql_pad($str, $size = 2, $pad = '0', $side = 'l') {
switch ($side) {
case 'r':
return "RPAD($str, $size, '$pad')";
+
default:
return "LPAD($str, $size, '$pad')";
}
@@ -69,6 +71,7 @@ function date_sql_pad($str, $size = 2, $pad = '0', $side = 'l') {
/**
* A class to manipulate date SQL.
*/
+// @codingStandardsIgnoreStart
class date_sql_handler {
var $db_type = NULL;
var $date_type = DATE_DATETIME;
@@ -86,7 +89,7 @@ class date_sql_handler {
/**
* The object constuctor.
*/
- function __construct($date_type = DATE_DATETIME, $local_timezone = NULL, $offset = '+00:00') {
+ public function __construct($date_type = DATE_DATETIME, $local_timezone = NULL, $offset = '+00:00') {
$this->db_type = Database::getConnection()->databaseType();
$this->date_type = $date_type;
$this->db_timezone = 'UTC';
@@ -97,7 +100,7 @@ class date_sql_handler {
/**
* See if the db has timezone name support.
*/
- function db_tz_support($reset = FALSE) {
+ public function db_tz_support($reset = FALSE) {
$has_support = variable_get('date_db_tz_support', -1);
if ($has_support == -1 || $reset) {
$has_support = FALSE;
@@ -108,6 +111,7 @@ class date_sql_handler {
$has_support = TRUE;
}
break;
+
case 'pgsql':
$test = db_query("SELECT '2008-02-15 12:00:00 UTC' AT TIME ZONE 'US/Central'")->fetchField();
if ($test == '2008-02-15 06:00:00') {
@@ -136,7 +140,7 @@ class date_sql_handler {
* set a fixed offset, not a timezone, so any value other than
* '+00:00' should be used with caution.
*/
- function set_db_timezone($offset = '+00:00') {
+ public function set_db_timezone($offset = '+00:00') {
static $already_set = FALSE;
$type = Database::getConnection()->databaseType();
if (!$already_set) {
@@ -144,9 +148,11 @@ class date_sql_handler {
case 'mysql':
db_query("SET @@session.time_zone = '$offset'");
break;
+
case 'pgsql':
db_query("SET TIME ZONE INTERVAL '$offset' HOUR TO MINUTE");
break;
+
case 'sqlsrv':
// Issue #1201342, This is the wrong way to set the timezone, this
// still needs to be fixed. In the meantime, commenting this out makes
@@ -161,7 +167,7 @@ class date_sql_handler {
/**
* Return timezone offset for the date being processed.
*/
- function get_offset($comp_date = NULL) {
+ public function get_offset($comp_date = NULL) {
if (!empty($this->db_timezone) && !empty($this->local_timezone)) {
if ($this->db_timezone != $this->local_timezone) {
if (empty($comp_date)) {
@@ -199,47 +205,57 @@ class date_sql_handler {
case DATE_UNIX:
$field = "FROM_UNIXTIME($field)";
break;
+
case DATE_ISO:
$field = "STR_TO_DATE($field, '%Y-%m-%dT%T')";
break;
+
case DATE_DATETIME:
break;
}
break;
+
case 'pgsql':
switch ($this->date_type) {
case DATE_UNIX:
$field = "$field::ABSTIME";
break;
+
case DATE_ISO:
$field = "TO_DATE($field, 'FMYYYY-FMMM-FMDDTFMHH24:FMMI:FMSS')";
break;
+
case DATE_DATETIME:
break;
}
break;
+
case 'sqlite':
switch ($this->date_type) {
case DATE_UNIX:
$field = "datetime($field, 'unixepoch')";
break;
+
case DATE_ISO:
case DATE_DATETIME:
$field = "datetime($field)";
break;
}
break;
+
case 'sqlsrv':
switch ($this->date_type) {
case DATE_UNIX:
$field = "DATEADD(s, $field, '19700101 00:00:00:000')";
break;
+
case DATE_ISO:
case DATE_DATETIME:
$field = "CAST($field as smalldatetime)";
break;
}
break;
+
break;
}
// Adjust the resulting value to the right timezone/offset.
@@ -254,10 +270,13 @@ class date_sql_handler {
switch ($this->db_type) {
case 'mysql':
return "ADDTIME($field, SEC_TO_TIME($offset))";
+
case 'pgsql':
- return "($field + INTERVAL '$offset SECONDS')";;
+ return "($field + INTERVAL '$offset SECONDS')";
+
case 'sqlite':
return "datetime($field, '$offset seconds')";
+
case 'sqlsrv':
return "DATEADD(second, $offset, $field)";
}
@@ -285,6 +304,7 @@ class date_sql_handler {
switch ($direction) {
case 'ADD':
return "DATE_ADD($field, INTERVAL $count $granularity)";
+
case 'SUB':
return "DATE_SUB($field, INTERVAL $count $granularity)";
}
@@ -294,6 +314,7 @@ class date_sql_handler {
switch ($direction) {
case 'ADD':
return "($field + INTERVAL '$count $granularity')";
+
case 'SUB':
return "($field - INTERVAL '$count $granularity')";
}
@@ -302,6 +323,7 @@ class date_sql_handler {
switch ($direction) {
case 'ADD':
return "datetime($field, '+$count $granularity')";
+
case 'SUB':
return "datetime($field, '-$count $granularity')";
}
@@ -352,6 +374,7 @@ class date_sql_handler {
switch ($this->db_type) {
case 'mysql':
return "CONVERT_TZ($field, $db_zone, $localzone)";
+
case 'pgsql':
// WITH TIME ZONE assumes the date is using the system
// timezone, which should have been set to UTC.
@@ -395,6 +418,7 @@ class date_sql_handler {
);
$format = strtr($format, $replace);
return "DATE_FORMAT($field, '$format')";
+
case 'pgsql':
$replace = array(
'Y' => 'YYYY',
@@ -421,6 +445,7 @@ class date_sql_handler {
);
$format = strtr($format, $replace);
return "TO_CHAR($field, '$format')";
+
case 'sqlite':
$replace = array(
// 4 digit year number.
@@ -460,6 +485,7 @@ class date_sql_handler {
);
$format = strtr($format, $replace);
return "strftime('$format', $field)";
+
case 'sqlsrv':
$replace = array(
// 4 digit year number.
@@ -528,18 +554,25 @@ class date_sql_handler {
switch (strtoupper($extract_type)) {
case 'DATE':
return $field;
+
case 'YEAR':
return "EXTRACT(YEAR FROM($field))";
+
case 'MONTH':
return "EXTRACT(MONTH FROM($field))";
+
case 'DAY':
return "EXTRACT(DAY FROM($field))";
+
case 'HOUR':
return "EXTRACT(HOUR FROM($field))";
+
case 'MINUTE':
return "EXTRACT(MINUTE FROM($field))";
+
case 'SECOND':
return "EXTRACT(SECOND FROM($field))";
+
// ISO week number for date.
case 'WEEK':
switch ($this->db_type) {
@@ -547,6 +580,7 @@ class date_sql_handler {
// WEEK using arg 3 in MySQl should return the same value as
// Postgres EXTRACT.
return "WEEK($field, 3)";
+
case 'pgsql':
return "EXTRACT(WEEK FROM($field))";
}
@@ -556,6 +590,7 @@ class date_sql_handler {
// MySQL returns 1 for Sunday through 7 for Saturday, PHP date
// functions and Postgres use 0 for Sunday and 6 for Saturday.
return "INTEGER(DAYOFWEEK($field) - 1)";
+
case 'pgsql':
return "EXTRACT(DOW FROM($field))";
}
@@ -563,6 +598,7 @@ class date_sql_handler {
switch ($this->db_type) {
case 'mysql':
return "DAYOFYEAR($field)";
+
case 'pgsql':
return "EXTRACT(DOY FROM($field))";
}
@@ -775,8 +811,7 @@ class date_sql_handler {
}
/**
- * Create a complete datetime value out of an
- * incomplete array of selected values.
+ * Create a complete date/time value out of an incomplete array of values.
*
* For example, array('year' => 2008, 'month' => 05) will fill
* in the day, hour, minute and second with the earliest possible
@@ -795,9 +830,11 @@ class date_sql_handler {
case 'empty_min':
case 'min':
return date_format($dates[0], 'Y-m-d H:i:s');
+
case 'empty_max':
case 'max':
return date_format($dates[1], 'Y-m-d H:i:s');
+
default:
return;
}
@@ -840,7 +877,7 @@ class date_sql_handler {
}
/**
- * A function to test the validity of various date parts
+ * A function to test the validity of various date parts.
*/
function part_is_valid($value, $type) {
if (!preg_match('/^[0-9]*$/', $value)) {
@@ -856,16 +893,19 @@ class date_sql_handler {
return FALSE;
}
break;
+
case 'month':
if ($value < 0 || $value > 12) {
return FALSE;
}
break;
+
case 'day':
if ($value < 0 || $value > 31) {
return FALSE;
}
break;
+
case 'week':
if ($value < 0 || $value > 53) {
return FALSE;
@@ -890,26 +930,36 @@ class date_sql_handler {
$formats['display'] = 'Y';
$formats['sql'] = 'Y';
break;
+
case 'month':
$formats['display'] = date_limit_format($short, array('year', 'month'));
$formats['sql'] = 'Y-m';
break;
+
case 'day':
- $formats['display'] = date_limit_format($short, array('year', 'month', 'day'));
+ $args = array('year', 'month', 'day');
+ $formats['display'] = date_limit_format($short, $args);
$formats['sql'] = 'Y-m-d';
break;
+
case 'hour':
- $formats['display'] = date_limit_format($short, array('year', 'month', 'day', 'hour'));
+ $args = array('year', 'month', 'day', 'hour');
+ $formats['display'] = date_limit_format($short, $args);
$formats['sql'] = 'Y-m-d\TH';
break;
+
case 'minute':
- $formats['display'] = date_limit_format($short, array('year', 'month', 'day', 'hour', 'minute'));
+ $args = array('year', 'month', 'day', 'hour', 'minute');
+ $formats['display'] = date_limit_format($short, $args);
$formats['sql'] = 'Y-m-d\TH:i';
break;
+
case 'second':
- $formats['display'] = date_limit_format($short, array('year', 'month', 'day', 'hour', 'minute', 'second'));
+ $args = array('year', 'month', 'day', 'hour', 'minute', 'second');
+ $formats['display'] = date_limit_format($short, $args);
$formats['sql'] = 'Y-m-d\TH:i:s';
break;
+
case 'week':
$formats['display'] = 'F j Y (W)';
$formats['sql'] = 'Y-\WW';
@@ -927,7 +977,7 @@ class date_sql_handler {
'#type' => 'radios',
'#default_value' => $granularity,
'#options' => $this->date_parts(),
- );
+ );
return $form;
}
@@ -1030,7 +1080,6 @@ class date_sql_handler {
$direction = $results[1];
$count = $results[2];
$item = $results[3];
-
$replace = array(
'now' => '@',
'+' => 'P',
@@ -1051,14 +1100,27 @@ class date_sql_handler {
'second' => 'S',
' ' => '',
' ' => '',
- );
- $prefix = in_array($item, array('hours', 'hour', 'minutes', 'minute', 'seconds', 'second')) ? 'T' : '';
- return $prefix . strtr($direction, $replace) . $count . strtr($item, $replace);
+ );
+ $args = array('hours', 'hour', 'minutes', 'minute', 'seconds', 'second');
+ if (in_array($item, $args)) {
+ $prefix = 'T';
+ }
+ else {
+ $prefix = '';
+ }
+ $return = $prefix;
+ $return .= strtr($direction, $replace);
+ $return .= $count;
+ $return .= strtr($item, $replace);
+
+ return $return;
}
/**
- * Use the parsed values from the ISO argument to determine the
- * granularity of this period.
+ * Granularity arguments handler.
+ *
+ * Use the parsed values from the ISO argument
+ * to determine the granularity of this period.
*/
function arg_granularity($arg) {
$granularity = '';
@@ -1137,8 +1199,9 @@ class date_sql_handler {
}
return array($min_date, $max_date);
}
- // Intercept invalid info and fall back to the current date.
+ // Intercept invalid info and fall back to the current date.
$now = date_now();
return array($now, $now);
}
}
+// @codingStandardsIgnoreEnd
diff --git a/sites/all/modules/contrib/fields/date/date_api/theme/theme.inc b/sites/all/modules/contrib/fields/date/date_api/theme/theme.inc
index 032e3e93..a6aef230 100644
--- a/sites/all/modules/contrib/fields/date/date_api/theme/theme.inc
+++ b/sites/all/modules/contrib/fields/date/date_api/theme/theme.inc
@@ -206,24 +206,31 @@ function theme_date_time_ago($variables) {
$now = date_format(date_now(), DATE_FORMAT_UNIX);
$start = date_format($start_date, DATE_FORMAT_UNIX);
- // will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence)
+ // Will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence).
$time_diff = $now - $start;
// Uses the same options used by Views format_interval.
switch ($display) {
case 'raw time ago':
return format_interval($time_diff, $interval);
+
case 'time ago':
return t('%time ago', array('%time' => format_interval($time_diff, $interval)));
+
case 'raw time hence':
return format_interval(-$time_diff, $interval);
+
case 'time hence':
return t('%time hence', array('%time' => format_interval(-$time_diff, $interval)));
+
case 'raw time span':
return ($time_diff < 0 ? '-' : '') . format_interval(abs($time_diff), $interval);
+
case 'inverse time span':
return ($time_diff > 0 ? '-' : '') . format_interval(abs($time_diff), $interval);
+
case 'time span':
return t(($time_diff < 0 ? '%time hence' : '%time ago'), array('%time' => format_interval(abs($time_diff), $interval)));
+
}
}
diff --git a/sites/all/modules/contrib/fields/date/date_context/date_context.info b/sites/all/modules/contrib/fields/date/date_context/date_context.info
index 1d8a551d..c521dd26 100644
--- a/sites/all/modules/contrib/fields/date/date_context/date_context.info
+++ b/sites/all/modules/contrib/fields/date/date_context/date_context.info
@@ -8,9 +8,9 @@ dependencies[] = context
files[] = date_context.module
files[] = plugins/date_context_date_condition.inc
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-09-08
+version = "7.x-2.9"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1441727353"
diff --git a/sites/all/modules/contrib/fields/date/date_context/date_context.module b/sites/all/modules/contrib/fields/date/date_context/date_context.module
index 44e975ac..9b568e15 100644
--- a/sites/all/modules/contrib/fields/date/date_context/date_context.module
+++ b/sites/all/modules/contrib/fields/date/date_context/date_context.module
@@ -1,5 +1,8 @@
execute()
@@ -8,8 +11,6 @@
* Cache the date processing, perhaps cache the formatted, timezone-adjusted
* date strings for each entity (would have to be cached differently for each
* timezone, based on the tz_handling method for the date).
- *
- * Add an option to set/not set the context on forms vs views.
*/
/**
@@ -22,7 +23,7 @@ function date_context_context_node_condition_alter($node, $op) {
}
/**
- * Implements hook_context_plugins()
+ * Implements hook_context_plugins().
*/
function date_context_context_plugins() {
$plugins = array();
@@ -38,7 +39,7 @@ function date_context_context_plugins() {
}
/**
- * Implements hook_context_registry()
+ * Implements hook_context_registry().
*/
function date_context_context_registry() {
return array(
@@ -51,4 +52,3 @@ function date_context_context_registry() {
),
);
}
-
diff --git a/sites/all/modules/contrib/fields/date/date_context/plugins/date_context_date_condition.inc b/sites/all/modules/contrib/fields/date/date_context/plugins/date_context_date_condition.inc
index 573b0354..97c18b47 100644
--- a/sites/all/modules/contrib/fields/date/date_context/plugins/date_context_date_condition.inc
+++ b/sites/all/modules/contrib/fields/date/date_context/plugins/date_context_date_condition.inc
@@ -1,10 +1,20 @@
$field) {
@@ -15,10 +25,13 @@ class date_context_date_condition extends context_condition_node {
return $values;
}
- function options_form($context) {
+ /**
+ * {@inheritdoc}
+ */
+ public function options_form($context) {
$defaults = $this->fetch_from_context($context, 'options');
$options = array(
- '<' => t('Is less than'),
+ '<' => t('Is less than'),
'<=' => t('Is less than or equal to'),
'>=' => t('Is greater than or equal to'),
'>' => t('Is greater than'),
@@ -27,6 +40,8 @@ class date_context_date_condition extends context_condition_node {
'empty' => t('Is empty'),
'not empty' => t('Is not Empty'),
);
+ $dependency_options = array('<', '<=', '>', '>=', '=', '!=');
+
$form['operation'] = array(
'#title' => t('Operation'),
'#type' => 'select',
@@ -41,12 +56,15 @@ class date_context_date_condition extends context_condition_node {
'#description' => t("The value the field should contain to meet the condition. This can either be an absolute date in ISO format (YYYY-MM-DDTHH:MM:SS) or a relative string like '12AM today'. Examples: 2011-12-31T00:00:00, now, now +1 day, 12AM today, Monday next week. More examples of relative date formats in the PHP documentation.", array('@relative_format' => 'http://www.php.net/manual/en/datetime.formats.relative.php')),
'#default_value' => isset($defaults['value']) ? $defaults['value'] : '',
'#process' => array('ctools_dependent_process'),
- '#dependency' => array('edit-conditions-plugins-date-context-date-condition-options-operation' => array('<', '<=', '>', '>=', '=', '!=')),
+ '#dependency' => array('edit-conditions-plugins-date-context-date-condition-options-operation' => $dependency_options),
);
return $form;
}
- function execute($entity, $op) {
+ /**
+ * {@inheritdoc}
+ */
+ public function execute($entity, $op) {
if (in_array($op, array('view', 'form'))) {
foreach ($this->get_contexts() as $context) {
$options = $this->fetch_from_context($context, 'options');
@@ -91,32 +109,37 @@ class date_context_date_condition extends context_condition_node {
str_replace('now', 'today', $options['value']);
$date = date_create($options['value'], date_default_timezone_object());
$compdate = $date->format(DATE_FORMAT_DATETIME);
- switch($options['operation']) {
+ switch ($options['operation']) {
case '=':
if ($date2 >= $compdate && $date1 <= $compdate) {
$this->condition_met($context, $field_name);
}
break;
+
case '>':
if ($date1 > $compdate) {
$this->condition_met($context, $field_name);
}
break;
+
case '>=':
if ($date1 >= $compdate) {
$this->condition_met($context, $field_name);
}
break;
+
case '<':
if ($date2 < $compdate) {
$this->condition_met($context, $field_name);
}
break;
+
case '<=':
if ($date2 <= $compdate) {
$this->condition_met($context, $field_name);
}
break;
+
case '!=':
if ($date1 < $compdate || $date2 > $compdate) {
$this->condition_met($context, $field_name);
@@ -130,3 +153,4 @@ class date_context_date_condition extends context_condition_node {
}
}
}
+// @codingStandardsIgnoreEnd
diff --git a/sites/all/modules/contrib/fields/date/date_elements.inc b/sites/all/modules/contrib/fields/date/date_elements.inc
index 6908d967..83697153 100644
--- a/sites/all/modules/contrib/fields/date/date_elements.inc
+++ b/sites/all/modules/contrib/fields/date/date_elements.inc
@@ -40,7 +40,6 @@
*
* - In the field's submission processing, the new date values, which are in
* the local timezone, are converted back to their UTC values and stored.
- *
*/
function date_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $base) {
@@ -87,7 +86,7 @@ function date_field_widget_form(&$form, &$form_state, $field, $instance, $langco
}
module_load_include('inc', 'date_api', 'date_api_elements');
- $timezone = date_get_timezone($field['settings']['tz_handling'], isset($items[0]['timezone']) ? $items[0]['timezone'] : date_default_timezone());
+ $timezone = date_get_timezone($field['settings']['tz_handling'], isset($items[$delta]['timezone']) ? $items[$delta]['timezone'] : date_default_timezone());
// TODO see if there's a way to keep the timezone element from ever being
// nested as array('timezone' => 'timezone' => value)). After struggling
@@ -122,7 +121,13 @@ function date_field_widget_form(&$form, &$form_state, $field, $instance, $langco
'#weight' => $instance['widget']['weight'] + 1,
'#attributes' => array('class' => array('date-no-float')),
'#date_label_position' => $instance['widget']['settings']['label_position'],
- );
+ );
+ }
+
+ // Make changes if instance is set to be rendered as a regular field.
+ if (!empty($instance['widget']['settings']['no_fieldset'])) {
+ $element['#title'] = check_plain($instance['label']);
+ $element['#theme_wrappers'] = ($field['cardinality'] == 1) ? array('date_form_element') : array();
}
return $element;
@@ -148,6 +153,7 @@ function date_local_date($item, $timezone, $field, $instance, $part = 'value') {
// @TODO Figure out how to replace date_fuzzy_datetime() function.
// Special case for ISO dates to create a valid date object for formatting.
// Is this still needed?
+ // @codingStandardsIgnoreStart
/*
if ($field['type'] == DATE_ISO) {
$value = date_fuzzy_datetime($value);
@@ -157,6 +163,7 @@ function date_local_date($item, $timezone, $field, $instance, $part = 'value') {
$value = date_convert($value, $field['type'], DATE_DATETIME, $db_timezone);
}
*/
+ // @codingStandardsIgnoreEnd
$date = new DateObject($value, date_get_timezone_db($field['settings']['tz_handling']));
$date->limitGranularity($field['settings']['granularity']);
@@ -193,8 +200,7 @@ function date_default_value($field, $instance, $langcode) {
}
/**
- * Helper function for the date default value callback to set
- * either 'value' or 'value2' to its default value.
+ * Helper function for the date default value callback to set either 'value' or 'value2' to its default value.
*/
function date_default_value_part($item, $field, $instance, $langcode, $part = 'value') {
$timezone = date_get_timezone($field['settings']['tz_handling']);
@@ -241,7 +247,6 @@ function date_default_value_part($item, $field, $instance, $langcode, $part = 'v
* Process an individual date element.
*/
function date_combo_element_process($element, &$form_state, $form) {
-
if (date_hidden_element($element)) {
// A hidden value for a new entity that had its end date set to blank
// will not get processed later to populate the end date, so set it here.
@@ -296,6 +301,7 @@ function date_combo_element_process($element, &$form_state, $form) {
// Blank out the end date for optional end dates that match the start date,
// except when this is a new node that has default values that should be honored.
if (!$date_is_default && $field['settings']['todate'] != 'required'
+ && is_array($element['#default_value'])
&& !empty($element['#default_value'][$to_field])
&& $element['#default_value'][$to_field] == $element['#default_value'][$from_field]) {
unset($element['#default_value'][$to_field]);
@@ -329,9 +335,9 @@ function date_combo_element_process($element, &$form_state, $form) {
'#date_increment' => $instance['widget']['settings']['increment'],
'#date_year_range' => $instance['widget']['settings']['year_range'],
'#date_label_position' => $instance['widget']['settings']['label_position'],
- );
+ );
- $description = !empty($element['#description']) ? t($element['#description']) : '';
+ $description = !empty($element['#description']) ? t($element['#description']) : '';
unset($element['#description']);
// Give this element the right type, using a Date API
@@ -347,11 +353,13 @@ function date_combo_element_process($element, &$form_state, $form) {
$element['#attached']['js'][] = drupal_get_path('module', 'date') . '/date.js';
$element[$from_field]['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
break;
+
case 'date_popup':
$element[$from_field]['#type'] = 'date_popup';
$element[$from_field]['#theme_wrappers'] = array('date_popup');
$element[$from_field]['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
break;
+
default:
$element[$from_field]['#type'] = 'date_text';
$element[$from_field]['#theme_wrappers'] = array('date_text');
@@ -380,8 +388,11 @@ function date_combo_element_process($element, &$form_state, $form) {
if ($field['settings']['todate'] == 'optional') {
$element[$to_field]['#states'] = array(
'visible' => array(
- 'input[name="' . $show_id . '"]' => array('checked' => TRUE),
- ));
+ 'input[name="' . $show_id . '"]' => array(
+ 'checked' => TRUE,
+ ),
+ ),
+ );
}
}
else {
@@ -404,16 +415,27 @@ function date_combo_element_process($element, &$form_state, $form) {
$element[$from_field]['#date_title'] = t('@field_name', array('@field_name' => $instance['label']));
}
+ // Make changes if instance is set to be rendered as a regular field.
+ if (!empty($instance['widget']['settings']['no_fieldset'])) {
+ unset($element[$from_field]['#description']);
+ if (!empty($field['settings']['todate']) && isset($element['#description'])) {
+ $element['#description'] .= ' ' . t("Empty 'End date' values will use the 'Start date' values.") . '';
+ }
+ }
+
$context = array(
- 'field' => $field,
- 'instance' => $instance,
- 'form' => $form,
+ 'field' => $field,
+ 'instance' => $instance,
+ 'form' => $form,
);
drupal_alter('date_combo_process', $element, $form_state, $context);
return $element;
}
+/**
+ * Empty a date element.
+ */
function date_element_empty($element, &$form_state) {
$item = array();
$item['value'] = NULL;
@@ -428,6 +450,7 @@ function date_element_empty($element, &$form_state) {
/**
* Validate and update a combo element.
+ *
* Don't try this if there were errors before reaching this point.
*/
function date_combo_validate($element, &$form_state) {
@@ -444,6 +467,10 @@ function date_combo_validate($element, &$form_state) {
$delta = $element['#delta'];
$langcode = $element['#language'];
+ // Related issue: https://drupal.org/node/2279831.
+ if (!is_array($element['#field_parents'])) {
+ $element['#field_parents'] = array();
+ }
$form_values = drupal_array_get_nested_value($form_state['values'], $element['#field_parents']);
$form_input = drupal_array_get_nested_value($form_state['input'], $element['#field_parents']);
diff --git a/sites/all/modules/contrib/fields/date/date_migrate/date_migrate.info b/sites/all/modules/contrib/fields/date/date_migrate/date_migrate.info
index 69012711..b3a6bba6 100644
--- a/sites/all/modules/contrib/fields/date/date_migrate/date_migrate.info
+++ b/sites/all/modules/contrib/fields/date/date_migrate/date_migrate.info
@@ -4,9 +4,9 @@ core = 7.x
package = Date/Time
hidden = TRUE
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-09-08
+version = "7.x-2.9"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1441727353"
diff --git a/sites/all/modules/contrib/fields/date/date_migrate/date_migrate_example/date_migrate_example.info b/sites/all/modules/contrib/fields/date/date_migrate/date_migrate_example/date_migrate_example.info
index 7223b763..6d79df40 100644
--- a/sites/all/modules/contrib/fields/date/date_migrate/date_migrate_example/date_migrate_example.info
+++ b/sites/all/modules/contrib/fields/date/date_migrate/date_migrate_example/date_migrate_example.info
@@ -20,9 +20,9 @@ package = "Features"
project = "date_migrate_example"
version = "7.x-2.0"
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-09-08
+version = "7.x-2.9"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1441727353"
diff --git a/sites/all/modules/contrib/fields/date/date_migrate/date_migrate_example/date_migrate_example.migrate.inc b/sites/all/modules/contrib/fields/date/date_migrate/date_migrate_example/date_migrate_example.migrate.inc
index e11dea66..216e1c54 100644
--- a/sites/all/modules/contrib/fields/date/date_migrate/date_migrate_example/date_migrate_example.migrate.inc
+++ b/sites/all/modules/contrib/fields/date/date_migrate/date_migrate_example/date_migrate_example.migrate.inc
@@ -47,8 +47,8 @@ class DateExampleMigration extends XMLMigration {
$xml_folder = drupal_get_path('module', 'date_migrate_example');
$items_url = $xml_folder . '/date_migrate_example.xml';
$item_xpath = '/source_data/item';
- $item_ID_xpath = 'id';
- $items_class = new MigrateItemsXML($items_url, $item_xpath, $item_ID_xpath);
+ $item_id_xpath = 'id';
+ $items_class = new MigrateItemsXML($items_url, $item_xpath, $item_id_xpath);
$this->source = new MigrateSourceMultiItems($items_class, $fields);
$this->destination = new MigrateDestinationNode('date_migrate_example');
@@ -78,7 +78,7 @@ class DateExampleMigration extends XMLMigration {
$this->addFieldMapping('field_datestamp_range:to', 'datestamp_range_to');
// You can specify a timezone to be applied to all values going into the
- // field (Tokyo is UTC+9, no DST)
+ // field (Tokyo is UTC+9, no DST).
$this->addFieldMapping('field_datetime', 'datetime')
->xpath('datetime');
$this->addFieldMapping('field_datetime:timezone')
@@ -107,25 +107,25 @@ class DateExampleMigration extends XMLMigration {
// The date range field can have multiple values.
$current_row->date_range_from = array();
foreach ($current_row->xml->date_range as $range) {
- $current_row->date_range_from[] = (string)$range->from[0];
- $current_row->date_range_to[] = (string)$range->to[0];
+ $current_row->date_range_from[] = (string) $range->from[0];
+ $current_row->date_range_to[] = (string) $range->to[0];
}
- $current_row->datestamp_range_from =
- (string) $current_row->xml->datestamp_range->from[0];
- $current_row->datestamp_range_to =
- (string) $current_row->xml->datestamp_range->to[0];
+ $current_row->datestamp_range_from
+ = (string) $current_row->xml->datestamp_range->from[0];
+ $current_row->datestamp_range_to
+ = (string) $current_row->xml->datestamp_range->to[0];
- $current_row->datetime_range_from =
- (string) $current_row->xml->datetime_range->from[0];
- $current_row->datetime_range_to =
- (string) $current_row->xml->datetime_range->to[0];
- $current_row->datetime_range_timezone =
- (string) $current_row->xml->datetime_range->timezone[0];
+ $current_row->datetime_range_from
+ = (string) $current_row->xml->datetime_range->from[0];
+ $current_row->datetime_range_to
+ = (string) $current_row->xml->datetime_range->to[0];
+ $current_row->datetime_range_timezone
+ = (string) $current_row->xml->datetime_range->timezone[0];
- $current_row->date_repeat =
- (string) $current_row->xml->date_repeat->date[0];
- $current_row->date_repeat_rrule =
- (string) $current_row->xml->date_repeat->rule[0];
+ $current_row->date_repeat
+ = (string) $current_row->xml->date_repeat->date[0];
+ $current_row->date_repeat_rrule
+ = (string) $current_row->xml->date_repeat->rule[0];
}
}
diff --git a/sites/all/modules/contrib/fields/date/date_popup/date_popup.info b/sites/all/modules/contrib/fields/date/date_popup/date_popup.info
index 271e1c68..500c7ffb 100644
--- a/sites/all/modules/contrib/fields/date/date_popup/date_popup.info
+++ b/sites/all/modules/contrib/fields/date/date_popup/date_popup.info
@@ -7,9 +7,9 @@ configure = admin/config/date/date_popup
stylesheets[all][] = themes/datepicker.1.7.css
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-09-08
+version = "7.x-2.9"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1441727353"
diff --git a/sites/all/modules/contrib/fields/date/date_popup/date_popup.install b/sites/all/modules/contrib/fields/date/date_popup/date_popup.install
index 790a514a..e13a4f5a 100644
--- a/sites/all/modules/contrib/fields/date/date_popup/date_popup.install
+++ b/sites/all/modules/contrib/fields/date/date_popup/date_popup.install
@@ -5,6 +5,7 @@
* Install, update and uninstall functions for the Date Popup module.
*/
+// @codingStandardsIgnoreStart
/**
* Implements hook_install().
*/
@@ -17,6 +18,7 @@ function date_popup_install() {
function date_popup_uninstall() {
}
+// @codingStandardsIgnoreEnd
/**
* Implements hook_enable().
diff --git a/sites/all/modules/contrib/fields/date/date_popup/date_popup.js b/sites/all/modules/contrib/fields/date/date_popup/date_popup.js
index 1847f84f..bbf25e2d 100644
--- a/sites/all/modules/contrib/fields/date/date_popup/date_popup.js
+++ b/sites/all/modules/contrib/fields/date/date_popup/date_popup.js
@@ -1,62 +1,65 @@
/**
* Attaches the calendar behavior to all required fields
*/
-(function ($) {
-Drupal.behaviors.date_popup = {
- attach: function (context) {
- for (var id in Drupal.settings.datePopup) {
- $('#'+ id).bind('focus', Drupal.settings.datePopup[id], function(e) {
- if (!$(this).hasClass('date-popup-init')) {
- var datePopup = e.data;
- // Explicitely filter the methods we accept.
- switch (datePopup.func) {
- case 'datepicker':
- $(this)
- .datepicker(datePopup.settings)
- .addClass('date-popup-init')
- $(this).click(function(){
- $(this).focus();
- });
- break;
+(function($) {
+ function makeFocusHandler(e) {
+ if (!$(this).hasClass('date-popup-init')) {
+ var datePopup = e.data;
+ // Explicitely filter the methods we accept.
+ switch (datePopup.func) {
+ case 'datepicker':
+ $(this)
+ .datepicker(datePopup.settings)
+ .addClass('date-popup-init');
+ $(this).click(function(){
+ $(this).focus();
+ });
+ break;
- case 'timeEntry':
- $(this)
- .timeEntry(datePopup.settings)
- .addClass('date-popup-init')
- $(this).click(function(){
- $(this).focus();
- });
- break;
- case 'timepicker':
- // Translate the PHP date format into the style the timepicker uses.
- datePopup.settings.timeFormat = datePopup.settings.timeFormat
- // 12-hour, leading zero,
- .replace('h', 'hh')
- // 12-hour, no leading zero.
- .replace('g', 'h')
- // 24-hour, leading zero.
- .replace('H', 'HH')
- // 24-hour, no leading zero.
- .replace('G', 'H')
- // AM/PM.
- .replace('A', 'p')
- // Minutes with leading zero.
- .replace('i', 'mm')
- // Seconds with leading zero.
- .replace('s', 'ss');
+ case 'timeEntry':
+ $(this)
+ .timeEntry(datePopup.settings)
+ .addClass('date-popup-init');
+ $(this).click(function(){
+ $(this).focus();
+ });
+ break;
- datePopup.settings.startTime = new Date(datePopup.settings.startTime);
- $(this)
- .timepicker(datePopup.settings)
- .addClass('date-popup-init');
- $(this).click(function(){
- $(this).focus();
- });
- break;
- }
+ case 'timepicker':
+ // Translate the PHP date format into the style the timepicker uses.
+ datePopup.settings.timeFormat = datePopup.settings.timeFormat
+ // 12-hour, leading zero,
+ .replace('h', 'hh')
+ // 12-hour, no leading zero.
+ .replace('g', 'h')
+ // 24-hour, leading zero.
+ .replace('H', 'HH')
+ // 24-hour, no leading zero.
+ .replace('G', 'H')
+ // AM/PM.
+ .replace('A', 'p')
+ // Minutes with leading zero.
+ .replace('i', 'mm')
+ // Seconds with leading zero.
+ .replace('s', 'ss');
+
+ datePopup.settings.startTime = new Date(datePopup.settings.startTime);
+ $(this)
+ .timepicker(datePopup.settings)
+ .addClass('date-popup-init');
+ $(this).click(function(){
+ $(this).focus();
+ });
+ break;
}
- });
+ }
}
- }
-};
+
+ Drupal.behaviors.date_popup = {
+ attach: function (context) {
+ for (var id in Drupal.settings.datePopup) {
+ $('#'+ id).bind('focus', Drupal.settings.datePopup[id], makeFocusHandler);
+ }
+ }
+ };
})(jQuery);
diff --git a/sites/all/modules/contrib/fields/date/date_popup/date_popup.module b/sites/all/modules/contrib/fields/date/date_popup/date_popup.module
index a2d0ebb1..e91cc8a7 100644
--- a/sites/all/modules/contrib/fields/date/date_popup/date_popup.module
+++ b/sites/all/modules/contrib/fields/date/date_popup/date_popup.module
@@ -16,7 +16,6 @@
* If no time elements are included in the format string, only the date
* textfield will be created. If no date elements are included in the format
* string, only the time textfield, will be created.
- *
*/
/**
@@ -44,7 +43,7 @@ function date_popup_add() {
/**
* Get the location of the Willington Vega timepicker library.
*
- * @return
+ * @return string
* The location of the library, or FALSE if the library isn't installed.
*/
function date_popup_get_wvega_path() {
@@ -94,9 +93,11 @@ function date_popup_library() {
}
/**
- * Create a unique CSS id name and output a single inline JS block for
- * each startup function to call and settings array to pass it. This
- * used to create a unique CSS class for each unique combination of
+ * Create a unique CSS id name and output a single inline JS block.
+ *
+ * For each startup function to call and settings array to pass it.
+ *
+ * This used to create a unique CSS class for each unique combination of
* function and settings, but using classes requires a DOM traversal
* and is much slower than an id lookup. The new approach returns to
* requiring a duplicate copy of the settings/code for every element
@@ -104,17 +105,20 @@ function date_popup_library() {
* putting the ids for each unique function/settings combo into
* Drupal.settings and searching for each listed id.
*
- * @param $pfx
+ * @param string $id
* The CSS class prefix to search the DOM for.
* TODO : unused ?
- * @param $func
- * The jQuery function to invoke on each DOM element containing the
- * returned CSS class.
- * @param $settings
+ *
+ * @param string $func
+ * The jQuery function to invoke on each DOM element
+ * containing the returned CSS class.
+ *
+ * @param array $settings
* The settings array to pass to the jQuery function.
+ *
* @returns
- * The CSS id to assign to the element that should have
- * $func($settings) invoked on it.
+ * The CSS id to assign to the element that should have $func($settings)
+ * invoked on it.
*/
function date_popup_js_settings_id($id, $func, $settings) {
static $js_added = FALSE;
@@ -123,14 +127,15 @@ function date_popup_js_settings_id($id, $func, $settings) {
// Make sure popup date selector grid is in correct year.
if (!empty($settings['yearRange'])) {
$parts = explode(':', $settings['yearRange']);
- // Set the default date to 0 or the lowest bound if the date ranges do not include the current year
- // Necessary for the datepicker to render and select dates correctly
- $defaultDate = ($parts[0] > 0 || 0 > $parts[1]) ? $parts[0] : 0;
- $settings += array('defaultDate' => (string) $defaultDate . 'y');
+ // Set the default date to 0 or the lowest bound if
+ // the date ranges do not include the current year.
+ // Necessary for the datepicker to render and select dates correctly.
+ $default_date = ($parts[0] > 0 || 0 > $parts[1]) ? $parts[0] : 0;
+ $settings += array('defaultDate' => (string) $default_date . 'y');
}
if (!$js_added) {
- drupal_add_js(drupal_get_path('module', 'date_popup') .'/date_popup.js');
+ drupal_add_js(drupal_get_path('module', 'date_popup') . '/date_popup.js');
$js_added = TRUE;
}
@@ -140,29 +145,35 @@ function date_popup_js_settings_id($id, $func, $settings) {
$id_count[$id] = 0;
}
-// It looks like we need the additional id_count for this to
-// work correctly when there are multiple values.
-// $return_id = "$id-$func-popup";
- $return_id = "$id-$func-popup-". $id_count[$id]++;
+ // It looks like we need the additional id_count for this to
+ // work correctly when there are multiple values.
+ // $return_id = "$id-$func-popup";
+ $return_id = "$id-$func-popup-" . $id_count[$id]++;
$js_settings['datePopup'][$return_id] = array(
'func' => $func,
- 'settings' => $settings
+ 'settings' => $settings,
);
drupal_add_js($js_settings, 'setting');
return $return_id;
}
+/**
+ * Date popup theme handler.
+ */
function date_popup_theme() {
return array(
- 'date_popup' => array('render element' => 'element'),
- );
+ 'date_popup' => array(
+ 'render element' => 'element',
+ ),
+ );
}
/**
* Implements hook_element_info().
*
* Set the #type to date_popup and fill the element #default_value with
- * a date adjusted to the proper local timezone in datetime format (YYYY-MM-DD HH:MM:SS).
+ * a date adjusted to the proper local timezone in datetime format
+ * (YYYY-MM-DD HH:MM:SS).
*
* The element will create two textfields, one for the date and one for the
* time. The date textfield will include a jQuery popup calendar date picker,
@@ -218,20 +229,32 @@ function date_popup_element_info() {
return $type;
}
+/**
+ * Date popup date granularity.
+ */
function date_popup_date_granularity($element) {
$granularity = date_format_order($element['#date_format']);
return array_intersect($granularity, array('month', 'day', 'year'));
}
+/**
+ * Date popup time granularity.
+ */
function date_popup_time_granularity($element) {
$granularity = date_format_order($element['#date_format']);
return array_intersect($granularity, array('hour', 'minute', 'second'));
}
+/**
+ * Date popup date format.
+ */
function date_popup_date_format($element) {
return (date_limit_format($element['#date_format'], date_popup_date_granularity($element)));
}
+/**
+ * Date popup time format.
+ */
function date_popup_time_format($element) {
return date_popup_format_to_popup_time(date_limit_format($element['#date_format'], date_popup_time_granularity($element)), $element['#timepicker']);
}
@@ -239,6 +262,7 @@ function date_popup_time_format($element) {
/**
* Element value callback for date_popup element.
*/
+// @codingStandardsIgnoreStart
function date_popup_element_value_callback($element, $input = FALSE, &$form_state) {
$granularity = date_format_order($element['#date_format']);
$has_time = date_has_time($granularity);
@@ -266,9 +290,11 @@ function date_popup_element_value_callback($element, $input = FALSE, &$form_stat
return $return;
}
+// @codingStandardsIgnoreEnd
/**
* Javascript popup element processing.
+ *
* Add popup attributes to $element.
*/
function date_popup_element_process($element, &$form_state, $form) {
@@ -284,7 +310,9 @@ function date_popup_element_process($element, &$form_state, $form) {
if (!empty($element['#ajax'])) {
$element['#ajax'] += array(
- 'trigger_as' => array('name' =>$element['#name']),
+ 'trigger_as' => array(
+ 'name' => $element['#name'],
+ ),
'event' => 'change',
);
}
@@ -292,6 +320,18 @@ function date_popup_element_process($element, &$form_state, $form) {
$element['date'] = date_popup_process_date_part($element);
$element['time'] = date_popup_process_time_part($element);
+ // Make changes if instance is set to be rendered as a regular field.
+ if (!empty($element['#instance']['widget']['settings']['no_fieldset']) && $element['#field']['cardinality'] == 1) {
+ if (!empty($element['date']) && empty($element['time'])) {
+ $element['date']['#title'] = check_plain($element['#instance']['label']);
+ $element['date']['#required'] = $element['#required'];
+ }
+ elseif (empty($element['date']) && !empty($element['time'])) {
+ $element['time']['#title'] = check_plain($element['#instance']['label']);
+ $element['time']['#required'] = $element['#required'];
+ }
+ }
+
if (isset($element['#element_validate'])) {
array_push($element['#element_validate'], 'date_popup_validate');
}
@@ -300,7 +340,7 @@ function date_popup_element_process($element, &$form_state, $form) {
}
$context = array(
- 'form' => $form,
+ 'form' => $form,
);
drupal_alter('date_popup_process', $element, $form_state, $context);
@@ -313,13 +353,22 @@ function date_popup_element_process($element, &$form_state, $form) {
function date_popup_process_date_part(&$element) {
$granularity = date_format_order($element['#date_format']);
$date_granularity = date_popup_date_granularity($element);
- if (empty($date_granularity)) return array();
+ if (empty($date_granularity)) {
+ return array();
+ }
// The datepicker can't handle zero or negative values like 0:+1
// even though the Date API can handle them, so rework the value
// we pass to the datepicker to use defaults it can accept (such as +0:+1)
// date_range_string() adds the necessary +/- signs to the range string.
$this_year = date_format(date_now(), 'Y');
+ // When used as a Views exposed filter widget, $element['#value'] contains an array instead an string.
+ // Fill the 'date' string in this case.
+ $mock = NULL;
+ $callback_values = date_popup_element_value_callback($element, FALSE, $mock);
+ if (!isset($element['#value']['date']) && isset($callback_values['date'])) {
+ $element['#value']['date'] = $callback_values['date'];
+ }
$date = '';
if (!empty($element['#value']['date'])) {
$date = new DateObject($element['#value']['date'], $element['#date_timezone'], date_popup_date_format($element));
@@ -336,8 +385,9 @@ function date_popup_process_date_part(&$element) {
'closeAtTop' => FALSE,
'speed' => 'immediate',
'firstDay' => intval(variable_get('date_first_day', 0)),
- //'buttonImage' => base_path() . drupal_get_path('module', 'date_api') ."/images/calendar.png",
- //'buttonImageOnly' => TRUE,
+ // 'buttonImage' => base_path()
+ // . drupal_get_path('module', 'date_api') ."/images/calendar.png",
+ // 'buttonImageOnly' => TRUE,
'dateFormat' => date_popup_format_to_popup(date_popup_date_format($element), 'datepicker'),
'yearRange' => $year_range,
// Custom setting, will be expanded in Drupal.behaviors.date_popup()
@@ -347,26 +397,33 @@ function date_popup_process_date_part(&$element) {
// Create a unique id for each set of custom settings.
$id = date_popup_js_settings_id($element['#id'], 'datepicker', $settings);
- // Manually build this element and set the value - this will prevent corrupting
- // the parent value
+ // Manually build this element and set the value -
+ // this will prevent corrupting the parent value.
$parents = array_merge($element['#parents'], array('date'));
$sub_element = array(
'#type' => 'textfield',
'#title' => theme('date_part_label_date', array('part_type' => 'date', 'element' => $element)),
'#title_display' => $element['#date_label_position'] == 'above' ? 'before' : 'invisible',
- '#default_value' => $element['#value']['date'],
+ '#default_value' => date_format_date($date, 'custom', date_popup_date_format($element)),
'#id' => $id,
'#input' => FALSE,
'#size' => !empty($element['#size']) ? $element['#size'] : 20,
'#maxlength' => !empty($element['#maxlength']) ? $element['#maxlength'] : 30,
'#attributes' => $element['#attributes'],
'#parents' => $parents,
- '#name' => array_shift($parents) . '['. implode('][', $parents) .']',
+ '#name' => array_shift($parents) . '[' . implode('][', $parents) . ']',
'#ajax' => !empty($element['#ajax']) ? $element['#ajax'] : FALSE,
);
$sub_element['#value'] = $sub_element['#default_value'];
- // TODO, figure out exactly when we want this description. In many places it is not desired.
- $sub_element['#description'] = ' '. t('E.g., @date', array('@date' => date_format_date(date_example_date(), 'custom', date_popup_date_format($element))));
+ // TODO, figure out exactly when we want this description.
+ // In many places it is not desired.
+ $sub_element['#description'] = ' ' . t('E.g., @date', array(
+ '@date' => date_format_date(
+ date_example_date(),
+ 'custom',
+ date_popup_date_format($element)
+ ),
+ ));
return $sub_element;
}
@@ -377,7 +434,17 @@ function date_popup_process_date_part(&$element) {
function date_popup_process_time_part(&$element) {
$granularity = date_format_order($element['#date_format']);
$has_time = date_has_time($granularity);
- if (empty($has_time)) return array();
+ if (empty($has_time)) {
+ return array();
+ }
+
+ // When used as a Views exposed filter widget, $element['#value'] contains an array instead an string.
+ // Fill the 'time' string in this case.
+ $mock = NULL;
+ $callback_values = date_popup_element_value_callback($element, FALSE, $mock);
+ if (!isset($element['#value']['time']) && isset($callback_values['time'])) {
+ $element['#value']['time'] = $callback_values['time'];
+ }
switch ($element['#timepicker']) {
case 'default':
@@ -385,10 +452,14 @@ function date_popup_process_time_part(&$element) {
$settings = array(
'show24Hours' => strpos($element['#date_format'], 'H') !== FALSE ? TRUE : FALSE,
'showSeconds' => (in_array('second', $granularity) ? TRUE : FALSE),
- 'timeSteps' => array(1, intval($element['#date_increment']), (in_array('second', $granularity) ? $element['#date_increment'] : 0)),
+ 'timeSteps' => array(
+ 1,
+ intval($element['#date_increment']),
+ (in_array('second', $granularity) ? $element['#date_increment'] : 0),
+ ),
'spinnerImage' => '',
'fromTo' => isset($fromto),
- );
+ );
if (strpos($element['#date_format'], 'a') !== FALSE) {
// Then we are using lowercase am/pm.
$settings['ampmNames'] = array('am', 'pm');
@@ -397,9 +468,11 @@ function date_popup_process_time_part(&$element) {
$settings['ampmPrefix'] = ' ';
}
break;
+
case 'wvega':
$func = 'timepicker';
- $time_granularity = array_intersect($granularity, array('hour', 'minute', 'second'));
+ $grans = array('hour', 'minute', 'second');
+ $time_granularity = array_intersect($granularity, $grans);
$format = date_popup_format_to_popup_time(date_limit_format($element['#date_format'], $time_granularity), 'wvega');
// The first value in the dropdown list should be the same as the element
// default_value, but it needs to be in JS format (i.e. milliseconds since
@@ -414,6 +487,7 @@ function date_popup_process_time_part(&$element) {
'scrollbar' => TRUE,
);
break;
+
default:
$func = '';
$settings = array();
@@ -423,8 +497,8 @@ function date_popup_process_time_part(&$element) {
// Create a unique id for each set of custom settings.
$id = date_popup_js_settings_id($element['#id'], $func, $settings);
- // Manually build this element and set the value - this will prevent corrupting
- // the parent value
+ // Manually build this element and set the value -
+ // this will prevent corrupting the parent value.
$parents = array_merge($element['#parents'], array('time'));
$sub_element = array(
'#type' => 'textfield',
@@ -436,16 +510,22 @@ function date_popup_process_time_part(&$element) {
'#maxlength' => 10,
'#attributes' => $element['#attributes'],
'#parents' => $parents,
- '#name' => array_shift($parents) . '['. implode('][', $parents) .']',
+ '#name' => array_shift($parents) . '[' . implode('][', $parents) . ']',
'#ajax' => !empty($element['#ajax']) ? $element['#ajax'] : FALSE,
);
$sub_element['#value'] = $sub_element['#default_value'];
- // TODO, figure out exactly when we want this description. In many places it is not desired.
+ // TODO, figure out exactly when we want this description.
+ // In many places it is not desired.
$example_date = date_now();
date_increment_round($example_date, $element['#date_increment']);
- $sub_element['#description'] = t('E.g., @date', array('@date' => date_format_date($example_date, 'custom', date_popup_time_format($element))));
+ $sub_element['#description'] = t('E.g., @date', array(
+ '@date' => date_format_date(
+ $example_date,
+ 'custom',
+ date_popup_time_format($element)
+ )));
return ($sub_element);
}
@@ -456,7 +536,6 @@ function date_popup_process_time_part(&$element) {
* When used as a Views widget, the validation step always gets triggered,
* even with no form submission. Before form submission $element['#value']
* contains a string, after submission it contains an array.
- *
*/
function date_popup_validate($element, &$form_state) {
@@ -473,6 +552,11 @@ function date_popup_validate($element, &$form_state) {
$input_exists = NULL;
$input = drupal_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
+ // If the date is a string, it is not considered valid and can cause problems
+ // later on, so just exit out now.
+ if (is_string($input)) {
+ return;
+ }
drupal_alter('date_popup_pre_validate', $element, $form_state, $input);
@@ -481,9 +565,15 @@ function date_popup_validate($element, &$form_state) {
$time_granularity = date_popup_time_granularity($element);
$has_time = date_has_time($granularity);
- $label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
- $label = t($label);
-
+ // @codingStandardsIgnoreStart
+ $label = '';
+ if (!empty($element['#date_title'])) {
+ $label = t($element['#date_title']);
+ }
+ elseif (!empty($element['#title'])) {
+ $label = t($element['#title']);
+ }
+ // @codingStandardsIgnoreEnd
$date = date_popup_input_date($element, $input);
// If the date has errors, display them.
@@ -517,7 +607,7 @@ function date_popup_validate($element, &$form_state) {
/**
* Helper function for extracting a date value out of user input.
*
- * @param autocomplete
+ * @param bool $auto_complete
* Should we add a time value to complete the date if there is no time?
* Useful anytime the time value is optional.
*/
@@ -532,8 +622,8 @@ function date_popup_input_date($element, $input, $auto_complete = FALSE) {
$format = date_popup_date_format($element);
$format .= $has_time ? ' ' . date_popup_time_format($element) : '';
- $datetime = $input['date'];
- $datetime .= $has_time ? ' ' . $input['time'] : '';
+ $datetime = trim($input['date']);
+ $datetime .= $has_time ? ' ' . trim($input['time']) : '';
$date = new DateObject($datetime, $element['#date_timezone'], $format);
if (is_object($date)) {
$date->limitGranularity($granularity);
@@ -552,7 +642,7 @@ function date_popup_time_formats($with_seconds = FALSE) {
return array(
'H:i:s',
'h:i:sA',
- );
+ );
}
/**
@@ -561,8 +651,17 @@ function date_popup_time_formats($with_seconds = FALSE) {
* TODO Remove any formats not supported by the widget, if any.
*/
function date_popup_formats() {
- $formats = str_replace('i', 'i:s', array_keys(system_get_date_formats('short')));
+ // Load short date formats.
+ $formats = system_get_date_formats('short');
+
+ // Load custom date formats.
+ if ($formats_custom = system_get_date_formats('custom')) {
+ $formats = array_merge($formats, $formats_custom);
+ }
+
+ $formats = str_replace('i', 'i:s', array_keys($formats));
$formats = drupal_map_assoc($formats);
+
return $formats;
}
@@ -570,7 +669,8 @@ function date_popup_formats() {
* Recreate a date format string so it has the values popup expects.
*
* @param string $format
- * a normal date format string, like Y-m-d
+ * A normal date format string, like Y-m-d
+ *
* @return string
* A format string in popup format, like YMD-, for the
* earlier 'calendar' version, or m/d/Y for the later 'datepicker'
@@ -588,15 +688,34 @@ function date_popup_format_to_popup($format) {
* Recreate a time format string so it has the values popup expects.
*
* @param string $format
- * a normal time format string, like h:i (a)
+ * A normal time format string, like h:i (a)
+ *
* @return string
- * a format string that the popup can accept like h:i a
+ * A format string that the popup can accept like h:i a
*/
function date_popup_format_to_popup_time($format, $timepicker = NULL) {
if (empty($format)) {
$format = 'H:i';
}
- $format = str_replace(array('/', '-', ' .', ',', 'F', 'M', 'l', 'z', 'w', 'W', 'd', 'j', 'm', 'n', 'y', 'Y'), '', $format);
+ $symbols = array(
+ '/',
+ '-',
+ ' .',
+ ',',
+ 'F',
+ 'M',
+ 'l',
+ 'z',
+ 'w',
+ 'W',
+ 'd',
+ 'j',
+ 'm',
+ 'n',
+ 'y',
+ 'Y',
+ );
+ $format = str_replace($symbols, '', $format);
$format = strtr($format, date_popup_timepicker_format_replacements($timepicker));
return $format;
}
@@ -605,9 +724,10 @@ function date_popup_format_to_popup_time($format, $timepicker = NULL) {
* Reconstruct popup format string into normal format string.
*
* @param string $format
- * a string in popup format, like YMD-
+ * A string in popup format, like YMD-
+ *
* @return string
- * a normal date format string, like Y-m-d
+ * A normal date format string, like Y-m-d
*/
function date_popup_popup_to_format($format) {
$replace = array_flip(date_popup_datepicker_format_replacements());
@@ -621,22 +741,21 @@ function date_popup_popup_to_format($format) {
* This function returns a map of format replacements required to change any
* input format into one that the given timepicker can support.
*
- * @param $timepicker
+ * @param string $timepicker
* The time entry plugin being used: either 'wvega' or 'default'.
- * @return
+ *
+ * @return array
* A map of replacements.
*/
function date_popup_timepicker_format_replacements($timepicker = 'default') {
switch ($timepicker) {
case 'wvega':
- return array(
- 'a' => 'A', // The wvega timepicker only supports uppercase AM/PM.
- );
+ // The wvega timepicker only supports uppercase AM/PM.
+ return array('a' => 'A');
+
default:
- return array(
- 'G' => 'H', // The default timeEntry plugin requires leading zeros.
- 'g' => 'h',
- );
+ // The default timeEntry plugin requires leading zeros.
+ return array('G' => 'H', 'g' => 'h');
}
}
@@ -645,16 +764,16 @@ function date_popup_timepicker_format_replacements($timepicker = 'default') {
*/
function date_popup_datepicker_format_replacements() {
return array(
- 'd' => 'dd',
- 'j' => 'd',
- 'l' => 'DD',
- 'D' => 'D',
- 'm' => 'mm',
- 'n' => 'm',
- 'F' => 'MM',
- 'M' => 'M',
- 'Y' => 'yy',
- 'y' => 'y',
+ 'd' => 'dd',
+ 'j' => 'd',
+ 'l' => 'DD',
+ 'D' => 'D',
+ 'm' => 'mm',
+ 'n' => 'm',
+ 'F' => 'MM',
+ 'M' => 'M',
+ 'Y' => 'yy',
+ 'y' => 'y',
);
}
@@ -667,16 +786,18 @@ function theme_date_popup($vars) {
$element = $vars['element'];
$attributes = !empty($element['#wrapper_attributes']) ? $element['#wrapper_attributes'] : array('class' => array());
$attributes['class'][] = 'container-inline-date';
- // If there is no description, the floating date elements need some extra padding below them.
+ // If there is no description, the floating date
+ // elements need some extra padding below them.
$wrapper_attributes = array('class' => array('date-padding'));
if (empty($element['date']['#description'])) {
$wrapper_attributes['class'][] = 'clearfix';
}
- // Add an wrapper to mimic the way a single value field works, for ease in using #states.
+ // Add an wrapper to mimic the way a single value field works,
+ // for ease in using #states.
if (isset($element['#children'])) {
- $element['#children'] = '
The Date Popup calendar includes some css for IE6 that breaks css validation. Since IE 6 is now superceded by IE 7, 8, and 9, the special css for IE 6 has been removed from the regular css used by the Date Popup. If you find you need that css after all, you can add it back in your theme. Look at the way the Garland theme adds special IE-only css in in its page.tpl.php file. The css you need is:
') .'
' . $css .'
';
+ $form['#suffix'] = t('
The Date Popup calendar includes some css for IE6 that breaks css validation. Since IE 6 is now superceded by IE 7, 8, and 9, the special css for IE 6 has been removed from the regular css used by the Date Popup. If you find you need that css after all, you can add it back in your theme. Look at the way the Garland theme adds special IE-only css in in its page.tpl.php file. The css you need is:
',
);
- $YEARLY_on_the_BYDAY_of_BYMONTH['BYMONTH'] = array(
+ $yearly_on_the_byday_of_bymonth['BYMONTH'] = array(
'#type' => 'checkboxes',
'#title' => t('Bymonth', array(), array('context' => 'Date repeat')),
'#title_display' => 'invisible',
- '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'YEARLY' && $YEARLY_day_month_default === 'BYDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
+ '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'YEARLY' && $yearly_day_month_default === 'BYDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
'#options' => date_month_names_abbr(TRUE),
'#attributes' => array('class' => array('container-inline')),
'#multiple' => TRUE,
@@ -465,13 +470,13 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
),
),
'#attributes' => array('class' => array('date-repeat-radios clearfix')),
- '#default_value' => $YEARLY_day_month_default,
+ '#default_value' => $yearly_day_month_default,
'#options' => array(
'BYMONTHDAY_BYMONTH' => t('On day ... of ...'),
'BYDAY_BYMONTH' => t('On the ... of ...'),
),
- 'BYMONTHDAY_BYMONTH_child' => $YEARLY_on_day_BYMONTHDAY_of_BYMONTH,
- 'BYDAY_BYMONTH_child' => $YEARLY_on_the_BYDAY_of_BYMONTH,
+ 'BYMONTHDAY_BYMONTH_child' => $yearly_on_day_bymonthday_of_bymonth,
+ 'BYDAY_BYMONTH_child' => $yearly_on_the_byday_of_bymonth,
'#div_classes' => array(
'date-repeat-radios-item date-clear clearfix bymonthday-bymonth',
'date-repeat-radios-item date-clear clearfix byday-bymonth',
@@ -482,7 +487,7 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
$count_form_element = array(
'#type' => 'textfield',
'#title' => t('Count', array(), array('context' => 'Date repeat')),
- '#default_value' => $COUNT,
+ '#default_value' => $count,
'#element_validate' => array('element_validate_integer_positive'),
'#attributes' => array('placeholder' => array('#')),
'#prefix' => $prefix,
@@ -499,21 +504,26 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
'#type' => $element['#date_repeat_widget'],
'#title' => t('Until', array(), array('context' => 'Date repeat')),
'#title_display' => 'invisible',
- '#default_value' => $UNTIL,
- '#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
+ '#default_value' => $until,
+ '#date_format' => !empty($element['#date_format']) ?
+ date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
'#date_timezone' => $timezone,
'#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
'#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
- '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
+ '#date_label_position' => !empty($element['#date_label_position']) ?
+ $element['#date_label_position'] : 'within',
'#date_flexible' => 0,
),
'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
'all_day' => array('#type' => 'hidden', '#value' => 1),
- 'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
+ 'granularity' => array(
+ '#type' => 'hidden',
+ '#value' => serialize(array('year', 'month', 'day')),
+ ),
);
$range_of_repeat_default = 'COUNT';
- if (!empty($UNTIL)) {
+ if (!empty($until)) {
$range_of_repeat_default = 'UNTIL';
}
$element['range_of_repeat'] = array(
@@ -528,7 +538,7 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'NONE'),
),
),
- '#default_value' => $range_of_repeat_default,
+ '#default_value' => $range_of_repeat_default,
'#options' => array(
'COUNT' => t('Count'),
'UNTIL' => t('Until'),
@@ -544,7 +554,8 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
$parents = $element['#array_parents'];
$instance = implode('-', $parents);
- // Make sure this will work right either in the normal form or in an ajax callback from the 'Add more' button.
+ // Make sure this will work right either in the normal
+ // form or in an ajax callback from the 'Add more' button.
if (empty($form_state['num_exceptions'][$instance])) {
$form_state['num_exceptions'][$instance] = count($exceptions);
}
@@ -576,33 +587,48 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
),
),
);
- for ($i = 0; $i < max($form_state['num_exceptions'][$instance], 1) ; $i++) {
- $EXCEPT = '';
+ for ($i = 0; $i < max($form_state['num_exceptions'][$instance], 1); $i++) {
+ $except = '';
if (!empty($exceptions[$i]['datetime'])) {
$ex_date = new DateObject($exceptions[$i]['datetime'], $exceptions[$i]['tz']);
date_timezone_set($ex_date, timezone_open($timezone));
- $EXCEPT = date_format($ex_date, DATE_FORMAT_DATETIME);
+ $except = date_format($ex_date, DATE_FORMAT_DATETIME);
+ }
+ $date_format = 'Y-m-d';
+ if (!empty($element['#date_format'])) {
+ $grans = array('year', 'month', 'day');
+ $date_format = date_limit_format($element['#date_format'], $grans);
}
$element['exceptions']['EXDATE'][$i] = array(
'#tree' => TRUE,
'datetime' => array(
'#name' => 'exceptions|' . $instance,
'#type' => $element['#date_repeat_widget'],
- '#default_value' => $EXCEPT,
- '#date_timezone' => !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone(),
- '#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
+ '#default_value' => $except,
+ '#date_timezone' => !empty($element['#date_timezone']) ?
+ $element['#date_timezone'] : date_default_timezone(),
+ '#date_format' => $date_format,
'#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
'#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
'#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
'#date_flexible' => 0,
- ),
- 'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
- 'all_day' => array('#type' => 'hidden', '#value' => 1),
- 'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
- );
+ ),
+ 'tz' => array(
+ '#type' => 'hidden',
+ '#value' => $element['#date_timezone'],
+ ),
+ 'all_day' => array(
+ '#type' => 'hidden',
+ '#value' => 1,
+ ),
+ 'granularity' => array(
+ '#type' => 'hidden',
+ '#value' => serialize(array('year', 'month', 'day')),
+ ),
+ );
}
- // collect additions in the same way as exceptions - implements RDATE.
+ // Collect additions in the same way as exceptions - implements RDATE.
if (empty($form_state['num_additions'][$instance])) {
$form_state['num_additions'][$instance] = count($additions);
}
@@ -634,30 +660,45 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
),
),
);
- for ($i = 0; $i < max($form_state['num_additions'][$instance], 1) ; $i++) {
- $RDATE = '';
+ for ($i = 0; $i < max($form_state['num_additions'][$instance], 1); $i++) {
+ $r_date = '';
if (!empty($additions[$i]['datetime'])) {
$rdate = new DateObject($additions[$i]['datetime'], $additions[$i]['tz']);
date_timezone_set($rdate, timezone_open($timezone));
- $RDATE = date_format($rdate, DATE_FORMAT_DATETIME);
+ $r_date = date_format($rdate, DATE_FORMAT_DATETIME);
+ }
+ $date_format = 'Y-m-d';
+ if (!empty($element['#date_format'])) {
+ $grans = array('year', 'month', 'day');
+ $date_format = date_limit_format($element['#date_format'], $grans);
}
$element['additions']['RDATE'][$i] = array(
'#tree' => TRUE,
'datetime' => array(
'#type' => $element['#date_repeat_widget'],
'#name' => 'additions|' . $instance,
- '#default_value' => $RDATE,
- '#date_timezone' => !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone(),
- '#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
+ '#default_value' => $r_date,
+ '#date_timezone' => !empty($element['#date_timezone']) ?
+ $element['#date_timezone'] : date_default_timezone(),
+ '#date_format' => $date_format,
'#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
'#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
'#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
'#date_flexible' => 0,
- ),
- 'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
- 'all_day' => array('#type' => 'hidden', '#value' => 1),
- 'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
- );
+ ),
+ 'tz' => array(
+ '#type' => 'hidden',
+ '#value' => $element['#date_timezone'],
+ ),
+ 'all_day' => array(
+ '#type' => 'hidden',
+ '#value' => 1,
+ ),
+ 'granularity' => array(
+ '#type' => 'hidden',
+ '#value' => serialize(array('year', 'month', 'day')),
+ ),
+ );
}
$element['exceptions']['exceptions_add'] = array(
@@ -687,6 +728,9 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
return $element;
}
+/**
+ * Add callback to date repeat.
+ */
function date_repeat_add_exception_callback($form, &$form_state) {
$parents = $form_state['triggering_element']['#array_parents'];
$button_key = array_pop($parents);
@@ -694,6 +738,9 @@ function date_repeat_add_exception_callback($form, &$form_state) {
return $element;
}
+/**
+ * Add addition callback to date repeat.
+ */
function date_repeat_add_addition_callback($form, &$form_state) {
$parents = $form_state['triggering_element']['#array_parents'];
$button_key = array_pop($parents);
@@ -701,6 +748,9 @@ function date_repeat_add_addition_callback($form, &$form_state) {
return $element;
}
+/**
+ * Add exception to date repeat.
+ */
function date_repeat_add_exception($form, &$form_state) {
$parents = $form_state['triggering_element']['#array_parents'];
$instance = implode('-', array_slice($parents, 0, count($parents) - 2));
@@ -708,6 +758,9 @@ function date_repeat_add_exception($form, &$form_state) {
$form_state['rebuild'] = TRUE;
}
+/**
+ * Add addition to date repeat.
+ */
function date_repeat_add_addition($form, &$form_state) {
$parents = $form_state['triggering_element']['#array_parents'];
$instance = implode('-', array_slice($parents, 0, count($parents) - 2));
@@ -723,8 +776,14 @@ function date_repeat_merge($form_values, $element) {
return $form_values;
}
if (array_key_exists('exceptions', $form_values) || array_key_exists('additions', $form_values)) {
- if (!array_key_exists('exceptions', $form_values)) $form_values['exceptions'] = array();
- if (!array_key_exists('additions', $form_values)) $form_values['additions'] = array();
+ if (!array_key_exists('exceptions', $form_values)) {
+ $form_values['exceptions'] = array();
+ }
+
+ if (!array_key_exists('additions', $form_values)) {
+ $form_values['additions'] = array();
+ }
+
$form_values = array_merge($form_values, (array) $form_values['exceptions'], (array) $form_values['additions']);
unset($form_values['exceptions']);
unset($form_values['additions']);
@@ -738,18 +797,22 @@ function date_repeat_merge($form_values, $element) {
case 'INTERVAL':
$form_values['INTERVAL'] = $form_values['daily']['INTERVAL_child'];
break;
+
case 'every_weekday':
$form_values['BYDAY'] = array('MO', 'TU', 'WE', 'TH', 'FR');
break;
+
case 'every_mo_we_fr':
$form_values['BYDAY'] = array('MO', 'WE', 'FR');
break;
+
case 'every_tu_th':
$form_values['BYDAY'] = array('TU', 'TH');
break;
}
}
break;
+
case 'WEEKLY':
if (array_key_exists('weekly', $form_values)) {
$form_values = array_merge($form_values, (array) $form_values['weekly']);
@@ -758,12 +821,14 @@ function date_repeat_merge($form_values, $element) {
}
}
break;
+
case 'MONTHLY':
if (array_key_exists('monthly', $form_values)) {
switch ($form_values['monthly']['day_month']) {
case 'BYMONTHDAY_BYMONTH':
$form_values['monthly'] = array_merge($form_values['monthly'], (array) $form_values['monthly']['BYMONTHDAY_BYMONTH_child']);
break;
+
case 'BYDAY_BYMONTH':
$form_values['monthly']['BYDAY_BYMONTH_child']['BYDAY'] = $form_values['monthly']['BYDAY_BYMONTH_child']['BYDAY_COUNT'] . $form_values['monthly']['BYDAY_BYMONTH_child']['BYDAY_DAY'];
$form_values['monthly'] = array_merge($form_values['monthly'], (array) $form_values['monthly']['BYDAY_BYMONTH_child']);
@@ -783,12 +848,14 @@ function date_repeat_merge($form_values, $element) {
}
}
break;
+
case 'YEARLY':
if (array_key_exists('yearly', $form_values)) {
switch ($form_values['yearly']['day_month']) {
case 'BYMONTHDAY_BYMONTH':
$form_values['yearly'] = array_merge($form_values['yearly'], (array) $form_values['yearly']['BYMONTHDAY_BYMONTH_child']);
break;
+
case 'BYDAY_BYMONTH':
$form_values['yearly']['BYDAY_BYMONTH_child']['BYDAY'] = $form_values['yearly']['BYDAY_BYMONTH_child']['BYDAY_COUNT'] . $form_values['yearly']['BYDAY_BYMONTH_child']['BYDAY_DAY'];
$form_values['yearly'] = array_merge($form_values['yearly'], (array) $form_values['yearly']['BYDAY_BYMONTH_child']);
@@ -808,6 +875,7 @@ function date_repeat_merge($form_values, $element) {
}
}
break;
+
default:
break;
}
@@ -823,6 +891,7 @@ function date_repeat_merge($form_values, $element) {
case 'COUNT':
$form_values['COUNT'] = $form_values['count_child'];
break;
+
case 'UNTIL':
$form_values['UNTIL'] = $form_values['until_child'];
break;
@@ -832,14 +901,23 @@ function date_repeat_merge($form_values, $element) {
unset($form_values['count_child']);
unset($form_values['until_child']);
- if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY'])) unset($form_values['BYDAY']['']);
- if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH'])) unset($form_values['BYMONTH']['']);
- if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY'])) unset($form_values['BYMONTHDAY']['']);
+ if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY'])) {
+ unset($form_values['BYDAY']['']);
+ }
+
+ if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH'])) {
+ unset($form_values['BYMONTH']['']);
+ }
+
+ if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY'])) {
+ unset($form_values['BYMONTHDAY']['']);
+ }
if (array_key_exists('UNTIL', $form_values) && is_array($form_values['UNTIL']['datetime'])) {
$function = $element['#date_repeat_widget'] . '_input_date';
$until_element = $element;
- $until_element['#date_format'] = !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d';
+ $until_element['#date_format'] = !empty($element['#date_format']) ?
+ date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d';
$date = $function($until_element, $form_values['UNTIL']['datetime']);
$form_values['UNTIL']['datetime'] = is_object($date) ? $date->format(DATE_FORMAT_DATETIME) : '';
}
@@ -849,9 +927,14 @@ function date_repeat_merge($form_values, $element) {
if (array_key_exists('EXDATE', $form_values) && is_array($form_values['EXDATE'])) {
$function = $element['#date_repeat_widget'] . '_input_date';
$exdate_element = $element;
+ $date_format = 'Y-m-d';
+ if (!empty($element['#date_format'])) {
+ $grans = array('year', 'month', 'day');
+ $date_format = date_limit_format($element['#date_format'], $grans);
+ }
foreach ($form_values['EXDATE'] as $delta => $value) {
if (is_array($value['datetime'])) {
- $exdate_element['#date_format'] = !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d';
+ $exdate_element['#date_format'] = $date_format;
$date = $function($exdate_element, $form_values['EXDATE'][$delta]['datetime']);
$form_values['EXDATE'][$delta]['datetime'] = is_object($date) ? $date->format(DATE_FORMAT_DATETIME) : '';
}
@@ -864,9 +947,14 @@ function date_repeat_merge($form_values, $element) {
if (array_key_exists('RDATE', $form_values) && is_array($form_values['RDATE'])) {
$function = $element['#date_repeat_widget'] . '_input_date';
$rdate_element = $element;
+ $date_format = 'Y-m-d';
+ if (!empty($element['#date_format'])) {
+ $grans = array('year', 'month', 'day');
+ $date_format = date_limit_format($element['#date_format'], $grans);
+ }
foreach ($form_values['RDATE'] as $delta => $value) {
if (is_array($value['datetime'])) {
- $rdate_element['#date_format'] = !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d';
+ $rdate_element['#date_format'] = $date_format;
$date = $function($rdate_element, $form_values['RDATE'][$delta]['datetime']);
$form_values['RDATE'][$delta]['datetime'] = is_object($date) ? $date->format(DATE_FORMAT_DATETIME) : '';
}
@@ -910,7 +998,7 @@ function date_repeat_rrule_validate($element, &$form_state) {
}
/**
- * Theme the exception list as a table so the buttons line up
+ * Theme the exception list as a table so the buttons line up.
*/
function theme_date_repeat_current_exceptions($vars) {
$rows = $vars['rows'];
@@ -920,11 +1008,14 @@ function theme_date_repeat_current_exceptions($vars) {
$rows_info[] = array(drupal_render($value['action']), drupal_render($value['display']));
}
}
- return theme('table', array('header' => array(t('Delete'), t('Current exceptions')), 'rows' => $rows_info));
+ return theme('table', array(
+ 'header' => array(t('Delete'), t('Current exceptions')),
+ 'rows' => $rows_info)
+ );
}
- /**
- * Theme the exception list as a table so the buttons line up
+/**
+ * Theme the exception list as a table so the buttons line up.
*/
function theme_date_repeat_current_additions($rows = array()) {
$rows_info = array();
@@ -933,7 +1024,10 @@ function theme_date_repeat_current_additions($rows = array()) {
$rows_info[] = array(drupal_render($value['action']), drupal_render($value['display']));
}
}
- return theme('table', array('header' => array(t('Delete'), t('Current additions')), 'rows' => $rows_info));
+ return theme('table', array(
+ 'header' => array(t('Delete'), t('Current additions')),
+ 'rows' => $rows_info)
+ );
}
/**
@@ -943,7 +1037,13 @@ function theme_date_repeat_rrule($vars) {
$element = $vars['element'];
$id = drupal_html_id('repeat-settings-fieldset');
$parents = $element['#parents'];
- $selector = "{$parents[0]}[{$parents[1]}][{$parents[2]}][show_repeat_settings]";
+
+ $selector = $parents[0];
+ for ($i = 1; $i < count($parents) - 1; $i++) {
+ $selector .= '[' . $parents[$i] . ']';
+ }
+ $selector .= '[show_repeat_settings]';
+
$fieldset = array(
'#type' => 'item',
'#title' => t('Repeat settings'),
@@ -960,6 +1060,9 @@ function theme_date_repeat_rrule($vars) {
return drupal_render($fieldset);
}
+/**
+ * Filter non zero values.
+ */
function date_repeat_filter_non_zero_value($value) {
return $value !== 0;
}
diff --git a/sites/all/modules/contrib/fields/date/date_repeat_field/date_repeat_field.devel_generate.inc b/sites/all/modules/contrib/fields/date/date_repeat_field/date_repeat_field.devel_generate.inc
index 3880e8b4..51c3708b 100644
--- a/sites/all/modules/contrib/fields/date/date_repeat_field/date_repeat_field.devel_generate.inc
+++ b/sites/all/modules/contrib/fields/date/date_repeat_field/date_repeat_field.devel_generate.inc
@@ -1,5 +1,5 @@
'Repeats',
- 'page callback' => 'date_repeat_field_page',
- 'page arguments' => array($entity_type, $count),
- 'access callback' => 'date_repeat_field_show',
- 'access arguments' => array($entity_type, $count),
- 'type' => MENU_LOCAL_TASK,
- 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+ 'title' => 'Repeats',
+ 'page callback' => 'date_repeat_field_page',
+ 'page arguments' => array($entity_type, $count),
+ 'access callback' => 'date_repeat_field_show',
+ 'access arguments' => array($entity_type, $count),
+ 'type' => MENU_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
);
}
}
@@ -91,13 +91,13 @@ function date_repeat_field_menu() {
else {
$path = $entity_type . '/%' . $entity_type;
$items[$path . '/repeats'] = array(
- 'title' => 'Repeats',
- 'page callback' => 'date_repeat_field_page',
- 'page arguments' => array($entity_type, 1),
- 'access callback' => 'date_repeat_field_show',
- 'access arguments' => array($entity_type, 1),
- 'type' => MENU_LOCAL_TASK,
- 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+ 'title' => 'Repeats',
+ 'page callback' => 'date_repeat_field_page',
+ 'page arguments' => array($entity_type, 1),
+ 'access callback' => 'date_repeat_field_show',
+ 'access arguments' => array($entity_type, 1),
+ 'type' => MENU_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
);
}
}
@@ -108,10 +108,12 @@ function date_repeat_field_menu() {
* Implements hook_permission().
*/
function date_repeat_field_permission() {
- return array('view date repeats' => array(
- 'title' => t('View Repeating Dates'),
- 'description' => t('Allow user to see a page with all the times a date repeats.'),
- ));
+ return array(
+ 'view date repeats' => array(
+ 'title' => t('View Repeating Dates'),
+ 'description' => t('Allow user to see a page with all the times a date repeats.'),
+ ),
+ );
}
/**
@@ -195,6 +197,9 @@ function date_repeat_field_bundles() {
return $values;
}
+/**
+ * Check field is repeat.
+ */
function date_is_repeat_field($field, $instance = NULL) {
if (is_string($field)) {
$field = field_info_field($field);
@@ -215,7 +220,7 @@ function date_is_repeat_field($field, $instance = NULL) {
}
}
-/*
+/**
* Implements hook_date_field_insert_alter().
*/
function date_repeat_field_date_field_insert_alter(&$items, $context) {
@@ -239,7 +244,7 @@ function date_repeat_field_date_field_insert_alter(&$items, $context) {
}
}
-/*
+/**
* Implements hook_date_field_update_alter().
*/
function date_repeat_field_date_field_update_alter(&$items, $context) {
@@ -279,6 +284,13 @@ function date_repeat_field_field_widget_form_alter(&$element, &$form_state, $con
'#suffix' => '',
'#default_value' => isset($items[$delta]['rrule']) && !empty($items[$delta]['rrule']) ? 1 : 0,
);
+
+ // Make changes if instance is set to be rendered as a regular field.
+ if (!empty($instance['widget']['settings']['no_fieldset'])) {
+ $element['#title'] = check_plain($instance['label']);
+ $element['#description'] = field_filter_xss($instance['description']);
+ $element['#theme_wrappers'] = array('date_form_element');
+ }
}
}
}
@@ -340,13 +352,14 @@ function date_repeat_field_widget_validate($element, &$form_state) {
// The RRULE has already been created by this point, so go back
// to the posted values to see if this was filled out.
$error_field_base = implode('][', $element['#parents']);
- $error_field_until = $error_field_base . '][rrule][until_child][datetime][';
+ $error_field_until = $error_field_base . '][rrule][until_child][datetime][';
if (!empty($item['rrule']) && $rrule_values['range_of_repeat'] === 'UNTIL' && empty($rrule_values['UNTIL']['datetime'])) {
switch ($instance['widget']['type']) {
case 'date_text':
case 'date_popup':
form_set_error($error_field_until . 'date', t("Missing value in 'Range of repeat'. (UNTIL).", array(), array('context' => 'Date repeat')));
break;
+
case 'date_select':
form_set_error($error_field_until . 'year', t("Missing value in 'Range of repeat': Year (UNTIL)", array(), array('context' => 'Date repeat')));
form_set_error($error_field_until . 'month', t("Missing value in 'Range of repeat': Month (UNTIL)", array(), array('context' => 'Date repeat')));
@@ -382,8 +395,9 @@ function date_repeat_field_widget_validate($element, &$form_state) {
// We only collect a date for UNTIL, but we need it to be inclusive,
// so force it to a full datetime element at the last possible second of the day.
if (!empty($rrule_values['UNTIL'])) {
+ $gran = array('year', 'month', 'day', 'hour', 'minute', 'second');
$rrule_values['UNTIL']['datetime'] .= ' 23:59:59';
- $rrule_values['UNTIL']['granularity'] = serialize(drupal_map_assoc(array('year', 'month', 'day', 'hour', 'minute', 'second')));
+ $rrule_values['UNTIL']['granularity'] = serialize(drupal_map_assoc($gran));
$rrule_values['UNTIL']['all_day'] = 0;
}
$value = date_repeat_build_dates($rrule, $rrule_values, $field, $item);
@@ -418,9 +432,10 @@ function date_repeat_after_build(&$element, &$form_state) {
* Pass in either the RRULE or the $form_values array for the RRULE,
* whichever is missing will be created when needed.
*/
+// @codingStandardsIgnoreStart
function date_repeat_build_dates($rrule = NULL, $rrule_values = NULL, $field, $item) {
-
- include_once(DRUPAL_ROOT . '/' . drupal_get_path('module', 'date_api') . '/date_api_ical.inc');
+// @codingStandardsIgnoreEnd
+ include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'date_api') . '/date_api_ical.inc';
$field_name = $field['field_name'];
if (empty($rrule)) {
@@ -497,8 +512,9 @@ function date_repeat_build_dates($rrule = NULL, $rrule_values = NULL, $field, $i
'offset2' => date_offset_get($date_end),
'timezone' => $timezone,
'rrule' => $rrule,
- );
+ );
}
+
return $value;
}
@@ -681,9 +697,8 @@ function date_repeat_field_date_field_widget_settings_form_alter(&$form, $contex
'#title' => t('Repeat display', array(), array('context' => 'Date repeat')),
'#description' => t("Should the repeat options form start out expanded or collapsed? Set to 'Collapsed' to make those options less obtrusive.", array(), array('context' => 'Date repeat')),
'#fieldset' => 'date_format',
- );
+ );
}
-
}
/**
diff --git a/sites/all/modules/contrib/fields/date/date_tools/date_tools.change_type.inc b/sites/all/modules/contrib/fields/date/date_tools/date_tools.change_type.inc
index cad2cafd..041c5dea 100644
--- a/sites/all/modules/contrib/fields/date/date_tools/date_tools.change_type.inc
+++ b/sites/all/modules/contrib/fields/date/date_tools/date_tools.change_type.inc
@@ -28,10 +28,14 @@ function date_tools_change_type_form() {
// Get the available date fields.
foreach ($fields as $field_name => $field) {
if ($field['type'] == 'date' || $field['type'] == 'datestamp' || $field['type'] == 'datetime') {
- $date_options[$labels[$field['type']]][$field_name] = t('Field @label (@field_name)', array('@label' => $field['widget']['label'], '@field_name' => $field_name, '@type' => $labels[$field['type']]));
+ $date_options[$labels[$field['type']]][$field_name] = t('Field @label (@field_name)', array(
+ '@label' => $field['widget']['label'],
+ '@field_name' => $field_name,
+ '@type' => $labels[$field['type']]
+ ));
}
}
- if (sizeof($date_options) < 1) {
+ if (count($date_options) < 1) {
drupal_set_message(t('There are no date fields in this database.'));
return $form;
}
@@ -142,26 +146,31 @@ function date_tools_change_type_form_submit($form, &$form_state) {
case 'datestamp':
$new_columns[] = $date_handler->sql_format('U', $db_field) . ' AS ' . $info['column'];
break;
+
case 'datetime':
$new_columns[] = $date_handler->sql_format('Y-m-d H:i:s', $db_field) . ' AS ' . $info['column'];
break;
}
break;
+
case 'datestamp':
switch ($new_type) {
case 'date':
$new_columns[] = $date_handler->sql_format('Y-m-d/TH:i:s', $db_field) . ' AS ' . $info['column'];
break;
+
case 'datetime':
$new_columns[] = $date_handler->sql_format('Y-m-d H:i:s', $db_field) . ' AS ' . $info['column'];
break;
}
break;
+
case 'datetime':
switch ($new_type) {
case 'date':
$new_columns[] = $date_handler->sql_format('Y-m-d/TH:i:s', $db_field) . ' AS ' . $info['column'];
break;
+
case 'datestamp':
$new_columns[] = $date_handler->sql_format('U', $db_field) . ' AS ' . $info['column'];
break;
@@ -178,5 +187,9 @@ function date_tools_change_type_form_submit($form, &$form_state) {
db_query($sql);
db_query("DROP TABLE {" . $temp_table . "}");
- drupal_set_message(t('The field @field_name has been changed from @old_type to @new_type.', array('@field_name' => $field['widget']['label'], '@old_type' => $labels[$old_type], '@new_type' => $labels[$new_type])));
+ drupal_set_message(t('The field @field_name has been changed from @old_type to @new_type.', array(
+ '@field_name' => $field['widget']['label'],
+ '@old_type' => $labels[$old_type],
+ '@new_type' => $labels[$new_type]
+ )));
}
diff --git a/sites/all/modules/contrib/fields/date/date_tools/date_tools.info b/sites/all/modules/contrib/fields/date/date_tools/date_tools.info
index dbcff7d9..3ec02859 100644
--- a/sites/all/modules/contrib/fields/date/date_tools/date_tools.info
+++ b/sites/all/modules/contrib/fields/date/date_tools/date_tools.info
@@ -6,9 +6,9 @@ core = 7.x
configure = admin/config/date/tools
files[] = tests/date_tools.test
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-09-08
+version = "7.x-2.9"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1441727353"
diff --git a/sites/all/modules/contrib/fields/date/date_tools/date_tools.module b/sites/all/modules/contrib/fields/date/date_tools/date_tools.module
index a7ac5f1e..997808df 100644
--- a/sites/all/modules/contrib/fields/date/date_tools/date_tools.module
+++ b/sites/all/modules/contrib/fields/date/date_tools/date_tools.module
@@ -31,7 +31,7 @@ function date_tools_help($section, $arg) {
*/
function date_tools_permission() {
return array(
- 'administer date tools' => array(
+ 'administer date tools' => array(
'title' => t('Administer date tools'),
),
);
@@ -68,6 +68,7 @@ function date_tools_menu() {
'file' => 'date_tools.wizard.inc',
);
+ // @codingStandardsIgnoreStart
/**
$items['admin/config/date/tools/change'] = array(
'title' => 'Change type',
@@ -79,18 +80,18 @@ function date_tools_menu() {
'file' => 'date_tools.change_type.inc',
);
*/
+ // @codingStandardsIgnoreEnd
return $items;
}
/**
- * Main Date Tools page
+ * Main Date Tools page.
*/
function date_tools_page() {
$content = '';
- $content .= t('Dates and calendars can be complicated to set up. The !date_wizard makes it easy to create a simple date content type and related calendar. ', array('!date_wizard' => l(t('Date wizard'), 'admin/config/date/tools/date_wizard')));
-
+ $content .= t('Dates and calendars can be complicated to set up. The !date_wizard makes it easy to create a simple date content type and related calendar.', array('!date_wizard' => l(t('Date wizard'), 'admin/config/date/tools/date_wizard')));
return $content;
}
diff --git a/sites/all/modules/contrib/fields/date/date_tools/date_tools.wizard.inc b/sites/all/modules/contrib/fields/date/date_tools/date_tools.wizard.inc
index 14bc2759..94a130a4 100644
--- a/sites/all/modules/contrib/fields/date/date_tools/date_tools.wizard.inc
+++ b/sites/all/modules/contrib/fields/date/date_tools/date_tools.wizard.inc
@@ -6,6 +6,8 @@
*/
/**
+ * Implements hook_form().
+ *
* @todo.
*/
function date_tools_wizard_form() {
@@ -59,7 +61,10 @@ function date_tools_wizard_form() {
$form['field']['repeat'] = array(
'#type' => 'select',
'#default_value' => 0,
- '#options' => array(0 => t('No'), 1 => t('Yes')),
+ '#options' => array(
+ 0 => t('No'),
+ 1 => t('Yes'),
+ ),
'#title' => t('Show repeating date options'),
'#access' => module_exists('date_repeat_field'),
);
@@ -72,7 +77,11 @@ function date_tools_wizard_form() {
$form['field']['advanced']['todate'] = array(
'#type' => 'select',
'#default_value' => 'optional',
- '#options' => array('' => t('Never'), 'optional' => t('Optional'), 'required' => t('Required')),
+ '#options' => array(
+ '' => t('Never'),
+ 'optional' => t('Optional'),
+ 'required' => t('Required'),
+ ),
'#title' => t('End Date'),
'#description' => t("Display a matching second date field as a 'End date'."),
);
@@ -106,7 +115,10 @@ function date_tools_wizard_form() {
$form['calendar'] = array(
'#type' => 'select',
'#default_value' => module_exists('calendar'),
- '#options' => array(0 => t('No'), 1 => t('Yes')),
+ '#options' => array(
+ 0 => t('No'),
+ 1 => t('Yes'),
+ ),
'#title' => t('Create a calendar for this date field'),
'#access' => module_exists('calendar'),
);
@@ -119,13 +131,26 @@ function date_tools_wizard_form() {
}
/**
+ * Form validate.
+ *
* @todo.
*/
function date_tools_wizard_form_validate(&$form, &$form_state) {
$bundle = $form_state['values']['bundle'];
$field_name = 'field_' . $form_state['values']['field_name'];
- $existing_type = db_query("SELECT type FROM {node_type} WHERE type=:bundle", array(':bundle' => $bundle))->fetchField();
- $existing_instance = db_query("SELECT field_name FROM {field_config_instance} WHERE field_name=:field_name AND bundle=:bundle AND entity_type=:entity_type", array(':field_name' => $field_name, ':bundle' => $bundle, ':entity_type' => 'node'))->fetchField();
+
+ $args = array(
+ ':field_name' => $field_name,
+ ':bundle' => $bundle,
+ ':entity_type' => 'node',
+ );
+
+ $query = "SELECT type FROM {node_type} WHERE type=:bundle";
+ $existing_type = db_query($query, array(':bundle' => $args[':bundle']))->fetchField();
+
+ $query = "SELECT field_name FROM {field_config_instance} WHERE field_name=:field_name AND bundle=:bundle AND entity_type=:entity_type";
+ $existing_instance = db_query($query, $args)->fetchField();
+
if ($existing_type) {
drupal_set_message(t('This content type name already exists, adding new field to existing content type.'));
}
@@ -147,6 +172,8 @@ function date_tools_wizard_form_validate(&$form, &$form_state) {
}
/**
+ * Form submit.
+ *
* @todo.
*/
function date_tools_wizard_form_submit(&$form, &$form_state) {
@@ -161,6 +188,8 @@ function date_tools_wizard_form_submit(&$form, &$form_state) {
}
/**
+ * Wizard build.
+ *
* @todo.
*/
function date_tools_wizard_build($form_values) {
@@ -201,7 +230,7 @@ function date_tools_wizard_build($form_values) {
'timezone_db' => date_get_timezone_db($tz_handling),
'repeat' => $repeat,
'todate' => !empty($todate) ? $todate : 'optional',
- ),
+ ),
);
$instance = array(
'entity_type' => 'node',
@@ -275,6 +304,8 @@ function date_tools_wizard_build($form_values) {
}
/**
+ * Includes handler.
+ *
* @todo.
*/
function date_tools_wizard_include() {
@@ -285,6 +316,8 @@ function date_tools_wizard_include() {
}
/**
+ * Implements hook_field_types().
+ *
* @todo.
*/
function date_tools_wizard_field_types() {
@@ -296,6 +329,7 @@ function date_tools_wizard_field_types() {
}
/**
+ * Implements hook_widget_types().
* @todo.
*/
function date_tools_wizard_widget_types() {
@@ -309,6 +343,8 @@ function date_tools_wizard_widget_types() {
}
/**
+ * Tz handler.
+ *
* @todo.
*/
function date_tools_wizard_tz_handling() {
@@ -317,6 +353,8 @@ function date_tools_wizard_tz_handling() {
}
/**
+ * Create date tools wizard content type.
+ *
* @todo.
*/
function date_tools_wizard_create_content_type($name, $bundle, $description, $type_settings = array()) {
@@ -332,8 +370,7 @@ function date_tools_wizard_create_content_type($name, $bundle, $description, $ty
'body_label' => 'Body',
'min_word_count' => '0',
'help' => '',
- 'node_options' =>
- array(
+ 'node_options' => array(
'status' => 1,
'promote' => 1,
'sticky' => 0,
@@ -374,8 +411,10 @@ function date_tools_wizard_create_content_type($name, $bundle, $description, $ty
'weight' => -4,
'module' => 'text',
),
- 'settings' => array('display_summary' => TRUE),
- 'display' => array(
+ 'settings' => array(
+ 'display_summary' => TRUE,
+ ),
+ 'display' => array(
'default' => array(
'label' => 'hidden',
'type' => 'text_default',
diff --git a/sites/all/modules/contrib/fields/date/date_views/date_views.info b/sites/all/modules/contrib/fields/date/date_views/date_views.info
index 0f2d7ec3..663efd35 100644
--- a/sites/all/modules/contrib/fields/date/date_views/date_views.info
+++ b/sites/all/modules/contrib/fields/date/date_views/date_views.info
@@ -12,9 +12,9 @@ files[] = includes/date_views_filter_handler_simple.inc
files[] = includes/date_views.views.inc
files[] = includes/date_views_plugin_pager.inc
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2015-09-08
+version = "7.x-2.9"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1441727353"
diff --git a/sites/all/modules/contrib/fields/date/date_views/date_views.install b/sites/all/modules/contrib/fields/date/date_views/date_views.install
index c9697b2d..e1d2e3ef 100644
--- a/sites/all/modules/contrib/fields/date/date_views/date_views.install
+++ b/sites/all/modules/contrib/fields/date/date_views/date_views.install
@@ -28,3 +28,27 @@ function date_views_uninstall() {
variable_del('date_views_week_format_with_year');
variable_del('date_views_week_format_without_year');
}
+
+/**
+ * Set default date views variables.
+ */
+function date_views_update_7200() {
+ if (!variable_get('date_views_month_format_with_year', FALSE)) {
+ variable_set('date_views_month_format_with_year', 'F Y');
+ }
+ if (!variable_get('date_views_month_format_without_year', FALSE)) {
+ variable_set('date_views_month_format_without_year', 'F');
+ }
+ if (!variable_get('date_views_day_format_with_year', FALSE)) {
+ variable_set('date_views_day_format_with_year', 'l, F j, Y');
+ }
+ if (!variable_get('date_views_day_format_without_year', FALSE)) {
+ variable_set('date_views_day_format_without_year', 'l, F j');
+ }
+ if (!variable_get('date_views_week_format_with_year', FALSE)) {
+ variable_set('date_views_week_format_with_year', 'F j, Y');
+ }
+ if (!variable_get('date_views_week_format_without_year', FALSE)) {
+ variable_set('date_views_week_format_without_year', 'F j');
+ }
+}
diff --git a/sites/all/modules/contrib/fields/date/date_views/date_views.module b/sites/all/modules/contrib/fields/date/date_views/date_views.module
index 04bad091..c050e56e 100644
--- a/sites/all/modules/contrib/fields/date/date_views/date_views.module
+++ b/sites/all/modules/contrib/fields/date/date_views/date_views.module
@@ -1,5 +1,9 @@
'Configure settings for date views.',
'page callback' => 'drupal_get_form',
'page arguments' => array('date_views_settings'),
- 'access arguments' => array('administer site configuration '),
+ 'access arguments' => array('administer site configuration'),
'type' => MENU_LOCAL_TASK,
);
@@ -86,13 +90,30 @@ function date_views_theme() {
'file' => 'theme.inc',
'path' => "$path/theme",
);
- return array(
- 'date_nav_title' => $base + array('variables' => array('granularity' => NULL, 'view' => NULL, 'link' => NULL, 'format' => NULL)),
- 'date_views_filter_form' => $base + array('template' => 'date-views-filter-form', 'render element' => 'form'),
- 'date_calendar_day' => $base + array('variables' => array('date' => NULL)),
+ return array(
+ 'date_nav_title' => $base + array(
+ 'variables' => array(
+ 'granularity' => NULL,
+ 'view' => NULL,
+ 'link' => NULL,
+ 'format' => NULL,
+ ),
+ ),
+ 'date_views_filter_form' => $base + array(
+ 'template' => 'date-views-filter-form',
+ 'render element' => 'form',
+ ),
+ 'date_calendar_day' => $base + array(
+ 'variables' => array(
+ 'date' => NULL,
+ ),
+ ),
'date_views_pager' => $base + array(
- 'variables' => array('plugin' => NULL, 'input' => NULL),
+ 'variables' => array(
+ 'plugin' => NULL,
+ 'input' => NULL,
+ ),
// Register a pattern so that it can work like all views templates.
'pattern' => 'date_views_pager__',
'template' => 'date-views-pager',
@@ -100,6 +121,9 @@ function date_views_theme() {
);
}
+/**
+ * Implements hook_views_api().
+ */
function date_views_views_api() {
return array(
'api' => 3,
@@ -119,7 +143,7 @@ function date_views_views_fetch_fields($base, $type) {
}
/**
- * Identify all potential date/timestamp fields and cache the data.
+ * Identify all potential date/timestamp fields and cache the data.
*/
function date_views_fields($base = 'node', $reset = FALSE) {
static $fields = array();
@@ -141,8 +165,8 @@ function date_views_fields($base = 'node', $reset = FALSE) {
/**
* Implements hook_date_views_entities().
- * Map extra Views tables to the entity that holds its date fields,
- * needed for Views tables other than the primary tables identified in entity_info().
+ *
+ * Map extra Views tables to the entity that holds its date fields, needed for Views tables other than the primary tables identified in entity_info().
*/
function date_views_date_views_extra_tables() {
return array(
@@ -151,14 +175,13 @@ function date_views_date_views_extra_tables() {
}
/**
- * Helper function to map entity types to the Views base table they use,
- * to make it easier to infer the entity type from a base table.
+ * Helper function to map entity types to the Views base table they use, to make it easier to infer the entity type from a base table.
*
- * Views has a new handler called views_handler_field_entity() that loads
- * entities, and you can use something like the following to get the
- * entity type from a view, but not all our base tables contain the
- * entity information we need, (i.e. revisions) so it won't work here
- * and we resort to creating information from entity_get_info().
+ * Views has a new handler called views_handler_field_entity() that loads entities.
+ *
+ * And you can use something like the following to get the entity type from a view, but not all our base tables contain the entity information we need, (i.e. revisions).
+ *
+ * So it won't work here and we resort to creating information from entity_get_info().
*
* // A method to get the entity type for a base table.
* $table_data = views_fetch_data($base_table);
@@ -193,11 +216,7 @@ function date_views_base_tables() {
/**
* Implements hook_date_views_fields().
*
- * All modules that create custom fields that use the
- * 'views_handler_field_date' handler can provide
- * additional information here about the type of
- * date they create so the date can be used by
- * the Date API views date argument and date filter.
+ * All modules that create custom fields that use the 'views_handler_field_date' handler can provide additional information here about the type of date they create so the date can be used by the Date API views date argument and date filter.
*/
function date_views_date_views_fields($field) {
$values = array(
@@ -263,12 +282,15 @@ function date_pager_url($view, $date_type = NULL, $date_arg = NULL, $force_view_
case 'year':
$args[$pos] = date_pad($view->date_info->year, 4);
break;
+
case 'week':
$args[$pos] = date_pad($view->date_info->year, 4) . '-W' . date_pad($view->date_info->week);
break;
+
case 'day':
$args[$pos] = date_pad($view->date_info->year, 4) . '-' . date_pad($view->date_info->month) . '-' . date_pad($view->date_info->day);
break;
+
default:
$args[$pos] = date_pad($view->date_info->year, 4) . '-' . date_pad($view->date_info->month);
break;
@@ -298,9 +320,14 @@ function date_pager_url($view, $date_type = NULL, $date_arg = NULL, $force_view_
// if they use exposed filters.
return url($view->get_url($args), array(
'query' => date_views_querystring($view),
- 'absolute' => $absolute));
+ 'absolute' => $absolute,
+ )
+ );
}
+/**
+ * Identifier of a date block.
+ */
function date_block_identifier($view) {
if (!empty($view->block_identifier)) {
return $view->block_identifier;
@@ -311,12 +338,9 @@ function date_block_identifier($view) {
/**
* Implements hook_field_views_data_alter().
*
- * Create a Views field for each date column we care about
- * to supplement the generic 'entity_id' and 'revision_id'
- * fields that are automatically created.
+ * Create a Views field for each date column we care about to supplement the generic 'entity_id' and 'revision_id' fields that are automatically created.
*
- * Also use friendlier labels to distinguish the start date
- * and end date in listings (for fields that use both).
+ * Also use friendlier labels to distinguish the start date and end date in listings (for fields that use both).
*/
function date_views_field_views_data_alter(&$result, $field, $module) {
if ($module == 'date') {
@@ -336,8 +360,8 @@ function date_views_field_views_data_alter(&$result, $field, $module) {
$result[$table][$column]['field']['is date'] = TRUE;
// Not sure yet if we still need a custom field handler in D7 now that custom formatters are available.
// Might still need it to handle grouping of multiple value dates.
- //$result[$table][$column]['field']['handler'] = 'date_handler_field_date';
- //$result[$table][$column]['field']['add fields to query'] = TRUE;
+ // $result[$table][$column]['field']['handler'] = 'date_handler_field_date';
+ // $result[$table][$column]['field']['add fields to query'] = TRUE;
}
// For filters, arguments, and sorts, determine if this column is for
@@ -395,12 +419,25 @@ function date_views_field_views_data_alter(&$result, $field, $module) {
// translatable string. This is a hack to get it to appear right
// before 'end date' in the listing (i.e., in a non-alphabetical,
// but more user friendly, order).
- $result[$table][$column]['title'] = t('@label - start date (!name)', array('@label' => $label, '!name' => $field['field_name']));
- $result[$table][$column]['title short'] = t('@label - start date', array('@label' => $label));
+ $result[$table][$column]['title'] = t('@label - start date (!name)', array(
+ '@label' => $label,
+ '!name' => $field['field_name'],
+ ));
+ $result[$table][$column]['title short'] = t('@label - start date', array(
+ '@label' => $label,
+ ));
break;
+
case 'value2':
- $result[$table][$column]['title'] = t('@label - end date (!name:!column)', array('@label' => $label, '!name' => $field['field_name'], '!column' => $this_column));
- $result[$table][$column]['title short'] = t('@label - end date:!column', array('@label' => $label, '!column' => $this_column));
+ $result[$table][$column]['title'] = t('@label - end date (!name:!column)', array(
+ '@label' => $label,
+ '!name' => $field['field_name'],
+ '!column' => $this_column,
+ ));
+ $result[$table][$column]['title short'] = t('@label - end date:!column', array(
+ '@label' => $label,
+ '!column' => $this_column,
+ ));
break;
}
}
@@ -421,18 +458,15 @@ function date_views_form_views_ui_edit_form_alter(&$form, &$form_state, $form_id
}
/**
- * The instanceof function makes this work for any handler that was derived
- * from 'views_handler_filter_date' or 'views_handler_argument_date',
- * which includes core date fields like the node updated field.
+ * The instanceof function makes this work for any handler that was derived from 'views_handler_filter_date' or 'views_handler_argument_date', which includes core date fields like the node updated field.
*
- * The test for $handler->min_date tells us that this is an argument that
- * not only is derived from the views date handler but also has been processed
- * by the Date Views filter or argument code.
-*/
+ * The test for $handler->min_date tells us that this is an argument that not only is derived from the views date handler but also has been processed by the Date Views filter or argument code.
+ */
function date_views_handler_is_date($handler, $type = 'argument') {
switch ($type) {
case 'filter':
return $handler instanceof views_handler_filter_date && !empty($handler->min_date);
+
case 'argument':
return $handler instanceof views_handler_argument_date && !empty($handler->min_date);
}
@@ -441,8 +475,8 @@ function date_views_handler_is_date($handler, $type = 'argument') {
/**
* Validation hook for exposed filters that use the select widget.
- * This is to ensure the the user completes all parts of the date
- * not just some parts. Only needed for the select widget.
+ *
+ * This is to ensure the the user completes all parts of the date not just some parts. Only needed for the select widget.
*/
function date_views_select_validate(&$form, &$form_state) {
// If there are no values just return.
@@ -453,7 +487,7 @@ function date_views_select_validate(&$form, &$form_state) {
$filled = array();
$value = drupal_array_get_nested_value($form_state['input'], $form['#parents']);
foreach ($granularity as $part) {
- if (!empty($value['value'][$part])) {
+ if (isset($value['value']) && is_numeric($value['value'][$part])) {
$filled[] = $part;
}
}
@@ -464,18 +498,23 @@ function date_views_select_validate(&$form, &$form_state) {
case 'year':
form_error($form['value'][$part], t('Please choose a year.'), $form_state);
break;
+
case 'month':
form_error($form['value'][$part], t('Please choose a month.'), $form_state);
break;
+
case 'day':
form_error($form['value'][$part], t('Please choose a day.'), $form_state);
break;
+
case 'hour':
form_error($form['value'][$part], t('Please choose an hour.'), $form_state);
break;
+
case 'minute':
form_error($form['value'][$part], t('Please choose a minute.'), $form_state);
break;
+
case 'second':
form_error($form['value'][$part], t('Please choose a second.'), $form_state);
break;
@@ -487,8 +526,7 @@ function date_views_select_validate(&$form, &$form_state) {
/**
* Implements hook_date_formatter_view_alter().
*
- * If we are displaying a date from a view, see if we have information about
- * which multiple value to display. If so, set the date_id in the entity.
+ * If we are displaying a date from a view, see if we have information about which multiple value to display. If so, set the date_id in the entity.
*/
function date_views_date_formatter_pre_view_alter(&$entity, &$variables) {
// Some views have no row index.
@@ -501,4 +539,4 @@ function date_views_date_formatter_pre_view_alter(&$entity, &$variables) {
$entity->date_id = 'date.' . $date_item->$date_id . '.' . $field['field_name'] . '.' . $date_item->$date_delta . '.0';
}
}
-}
\ No newline at end of file
+}
diff --git a/sites/all/modules/contrib/fields/date/date_views/includes/date_plugin_display_attachment.inc b/sites/all/modules/contrib/fields/date/date_views/includes/date_plugin_display_attachment.inc
index 94371f76..779f4d1f 100644
--- a/sites/all/modules/contrib/fields/date/date_views/includes/date_plugin_display_attachment.inc
+++ b/sites/all/modules/contrib/fields/date/date_views/includes/date_plugin_display_attachment.inc
@@ -1,6 +1,7 @@
'date_views', // This just tells our themes are elsewhere.
+ // This just tells our themes are elsewhere.
+ 'module' => 'date_views',
'display' => array(
// Display plugin for date navigation.
'date_nav' => array(
@@ -83,7 +85,7 @@ function date_views_views_plugins() {
}
/**
- * Implements hook_views_data()
+ * Implements hook_views_data().
*/
function date_views_views_data() {
$data = array();
@@ -95,12 +97,12 @@ function date_views_views_data() {
$data[$base_table]['date_argument'] = array(
'group' => t('Date'),
'title' => t('Date (!base_table)', array('!base_table' => $base_table)),
- 'help' => t('Filter any Views !base_table date field by a date argument, using any common ISO date/period format (i.e. YYYY, YYYY-MM, YYYY-MM-DD, YYYY-W99, YYYY-MM-DD--P3M, P90D, etc). ', array('!base_table' => $base_table)),
+ 'help' => t('Filter any Views !base_table date field by a date argument, using any common ISO date/period format (i.e. YYYY, YYYY-MM, YYYY-MM-DD, YYYY-W99, YYYY-MM-DD--P3M, P90D, etc).', array('!base_table' => $base_table)),
'argument' => array(
'handler' => 'date_views_argument_handler',
'empty field name' => t('Undated'),
'is date' => TRUE,
- //'skip base' => $base_table,
+ // 'skip base' => $base_table,
),
);
// The flexible date filter.
@@ -112,7 +114,7 @@ function date_views_views_data() {
'handler' => 'date_views_filter_handler',
'empty field name' => t('Undated'),
'is date' => TRUE,
- //'skip base' => $base_table,
+ // 'skip base' => $base_table,
),
);
}
@@ -140,8 +142,9 @@ function date_views_views_data_alter(&$data) {
}
/**
- * Central function for setting up the right timezone values
- * in the SQL date handler.
+ * Central function for setting up the right timezone values.
+ *
+ * In the SQL date handler.
*
* The date handler will use this information to decide if the
* database value needs a timezone conversion.
@@ -152,30 +155,45 @@ function date_views_views_data_alter(&$data) {
*/
function date_views_set_timezone(&$date_handler, &$view, $field) {
switch ($field['tz_handling']) {
- case 'date' :
+ case 'date':
$date_handler->db_timezone = 'UTC';
$date_handler->local_timezone_field = $field['timezone_field'];
$date_handler->offset_field = $field['offset_field'];
break;
+
case 'none':
$date_handler->db_timezone = date_default_timezone();
$date_handler->local_timezone = date_default_timezone();
break;
+
case 'utc':
$date_handler->db_timezone = 'UTC';
$date_handler->local_timezone = 'UTC';
break;
- default :
+
+ default:
$date_handler->db_timezone = 'UTC';
$date_handler->local_timezone = date_default_timezone();
break;
}
}
+/**
+ * Helper function to generate a query string.
+ *
+ * @param object $view
+ * A View object.
+ *
+ * @param array $extra_params
+ * An extra parameters.
+ *
+ * @return null/string
+ * Return a query or NULL.
+ */
function date_views_querystring($view, $extra_params = array()) {
$query_params = array_merge($_GET, $extra_params);
// Allow NULL params to be removed from the query string.
- foreach ($extra_params AS $key => $value) {
+ foreach ($extra_params as $key => $value) {
if (!isset($value)) {
unset($query_params[$key]);
}
diff --git a/sites/all/modules/contrib/fields/date/date_views/includes/date_views_argument_handler.inc b/sites/all/modules/contrib/fields/date/date_views/includes/date_views_argument_handler.inc
index 61aeafc1..20eedff0 100644
--- a/sites/all/modules/contrib/fields/date/date_views/includes/date_views_argument_handler.inc
+++ b/sites/all/modules/contrib/fields/date/date_views/includes/date_views_argument_handler.inc
@@ -3,12 +3,14 @@
* @file
* Date API views argument handler.
* This argument combines multiple date arguments into a single argument
- * where all fields are controlled by the same date and can be combined with either AND or OR.
+ * where all fields are controlled by the same date and can be combined
+ * with either AND or OR.
*/
/**
* Date API argument handler.
*/
+// @codingStandardsIgnoreStart
class date_views_argument_handler extends date_views_argument_handler_simple {
/**
@@ -198,3 +200,4 @@ class date_views_argument_handler extends date_views_argument_handler_simple {
}
}
+// @codingStandardsIgnoreEnd
diff --git a/sites/all/modules/contrib/fields/date/date_views/includes/date_views_argument_handler_simple.inc b/sites/all/modules/contrib/fields/date/date_views/includes/date_views_argument_handler_simple.inc
index 35f88e00..2839b959 100644
--- a/sites/all/modules/contrib/fields/date/date_views/includes/date_views_argument_handler_simple.inc
+++ b/sites/all/modules/contrib/fields/date/date_views/includes/date_views_argument_handler_simple.inc
@@ -7,11 +7,13 @@
/**
* Date API argument handler.
*/
+// @codingStandardsIgnoreStart
class date_views_argument_handler_simple extends views_handler_argument_date {
/**
- * Get granularity and use it to create the formula and a format
- * for the results.
+ * Get granularity.
+ *
+ * Use it to create the formula and a format for the results.
*/
function init(&$view, &$options) {
parent::init($view, $options);
@@ -29,12 +31,14 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
$this->date_handler->local_timezone = date_get_timezone($field['settings']['tz_handling']);
}
$this->date_handler->granularity = $this->options['granularity'];
- // This value needs to be initialized so it exists even if the query doesn't run.
+ // This value needs to be initialized so
+ // it exists even if the query doesn't run.
$this->date_handler->placeholders = array();
$this->format = $this->date_handler->views_formats($this->date_handler->granularity, 'display');
$this->sql_format = $this->date_handler->views_formats($this->date_handler->granularity, 'sql');
- // $this->arg_format is the format the parent date handler will use to create a default argument.
+ // $this->arg_format is the format the parent date
+ // handler will use to create a default argument.
$this->arg_format = $this->format();
// Identify the base table for this field.
@@ -43,6 +47,9 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
}
+ /**
+ * {@inheritdoc}
+ */
function format() {
if (!empty($this->options['granularity'])) {
return $this->date_handler->views_formats($this->options['granularity']);
@@ -53,8 +60,9 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
}
/**
- * Set the empty argument value to the current date,
- * formatted appropriately for this argument.
+ * Set the empty argument value to the current date.
+ *
+ * Formatted appropriately for this argument.
*/
function get_default_argument($raw = FALSE) {
$is_default = FALSE;
@@ -85,6 +93,7 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
$options = parent::option_definition();
$options['year_range'] = array('default' => '-3:+3');
$options['granularity'] = array('default' => 'month');
+ $options['granularity_reset'] = array('default' => FALSE);
$options['default_argument_type']['default'] = 'date';
$options['add_delta'] = array('default' => '');
$options['use_fromto'] = array('default' => '');
@@ -116,7 +125,9 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
'#attributes' => array('class' => array('dependent-options')),
'#states' => array(
'visible' => array(
- ':input[name="options[default_action]"]' => array('value' => 'summary')
+ ':input[name="options[default_action]"]' => array(
+ 'value' => 'summary',
+ ),
),
),
);
@@ -129,23 +140,37 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
'#attributes' => array('class' => array('dependent-options')),
'#states' => array(
'visible' => array(
- ':input[name="options[title_format]"]' => array('value' => 'custom')
+ ':input[name="options[title_format]"]' => array(
+ 'value' => 'custom',
+ ),
),
),
);
+ // Get default granularity options
$options = $this->date_handler->date_parts();
- unset($options['second'], $options['minute']);
- $options += array('week' => t('Week', array(), array('context' => 'datetime')));
+ // Add the 'week' option.
+ $options += array(
+ 'week' => t('Week', array(), array(
+ 'context' => 'datetime',
+ )),
+ );
+
$form['granularity'] = array(
'#title' => t('Granularity'),
'#type' => 'radios',
'#options' => $options,
'#default_value' => $this->options['granularity'],
- '#multiple' => TRUE,
'#description' => t("Select the type of date value to be used in defaults, summaries, and navigation. For example, a granularity of 'month' will set the default date to the current month, summarize by month in summary views, and link to the next and previous month when using date navigation."),
);
+ $form['granularity_reset'] = array(
+ '#title' => t('Use granularity from argument value'),
+ '#type' => 'checkbox',
+ '#default_value' => $this->options['granularity_reset'],
+ '#description' => t("If the granularity of argument value is different from selected, use it from argument value."),
+ );
+
$form['year_range'] = array(
'#title' => t('Date year range'),
'#type' => 'textfield',
@@ -172,16 +197,18 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
'#default_value' => $this->options['add_delta'],
'#options' => array('' => t('No'), 'yes' => t('Yes')),
'#description' => t('Add an identifier to the view to show which multiple value date fields meet the filter criteria. Note: This option may introduce duplicate values into the view. Required when using multiple value fields in a Calendar or any time you want the node view of multiple value dates to display only the values that match the view filters.'),
- // Only let mere mortals tweak this setting for multi-value fields
+ // Only let mere mortals tweak this setting for multi-value fields.
'#access' => $access,
);
-
}
+ /**
+ * {@inheritdoc}
+ */
function options_validate(&$form, &$form_state) {
// It is very important to call the parent function here:
parent::options_validate($form, $form_state);
- if (!preg_match('/^(?:\-[0-9]{1,4}|[0-9]{4}):(?:[\+|\-][0-9]{1,4}|[0-9]{4})$/', $form_state['values']['options']['year_range'])) {
+ if (!preg_match('/^(?:\-[0-9]{1,4}|[0-9]{4}):(?:[\+\-][0-9]{1,4}|[0-9]{4})$/', $form_state['values']['options']['year_range'])) {
form_error($form['year_range'], t('Date year range must be in the format -9:+9, 2005:2010, -9:2010, or 2005:+9'));
}
}
@@ -209,14 +236,15 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
$format = !empty($this->options['title_format_custom']) && !empty($this->options['title_format_custom']) ? $this->options['title_format_custom'] : $this->date_handler->views_formats($this->options['granularity'], 'display');
$range = $this->date_handler->arg_range($this->argument);
return date_format_date($range[0], 'custom', $format);
- }
+ }
/**
- * Provide the argument to use to link from the summary to the next level;
- * this will be called once per row of a summary, and used as part of
+ * Provide the argument to use to link from the summary to the next level.
+ *
+ * This will be called once per row of a summary, and used as part of
* $view->get_url().
*
- * @param $data
+ * @param object $data
* The query results for the row.
*/
function summary_argument($data) {
@@ -234,10 +262,11 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
*/
function summary_query() {
- // @TODO The summary values are computed by the database. Unless the database has
- // built-in timezone handling it will use a fixed offset, which will not be
- // right for all dates. The only way I can see to make this work right is to
- // store the offset for each date in the database so it can be added to the base
+ // @TODO The summary values are computed by the database.
+ // Unless the database has built-in timezone handling it will use
+ // a fixed offset, which will not be right for all dates.
+ // The only way I can see to make this work right is to store the offset
+ // for each date in the database so it can be added to the base
// date value before the database formats the result. Because this is a huge
// architectural change, it won't go in until we start a new branch.
$this->formula = $this->date_handler->sql_format($this->sql_format, $this->date_handler->sql_field("***table***.$this->real_field"));
@@ -245,7 +274,8 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
// Now that our table is secure, get our formula.
$formula = $this->get_formula();
- // Add the field, give it an alias that does NOT match the actual field name or grouping won't work right.
+ // Add the field, give it an alias that does NOT match the actual
+ // field name or grouping won't work right.
$this->base_alias = $this->name_alias = $this->query->add_field(NULL, $formula, $this->field . '_summary');
$this->query->set_count_field(NULL, $formula, $this->field);
@@ -254,20 +284,22 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
/**
* Inject a test for valid date range before the regular query.
+ *
* Override the parent query to be able to control the $group.
*/
function query($group_by = FALSE) {
- // @TODO Not doing anything with $group_by yet, need to figure out what has to be done.
+ // @TODO Not doing anything with $group_by yet,
+ // need to figure out what has to be done.
if ($this->date_forbid()) {
return;
}
// See if we need to reset granularity based on an argument value.
- // Make sure we don't try to reset to some bogus value if someone has typed in an unexpected argument.
- $granularity = $this->date_handler->arg_granularity($this->argument);
- if (!empty($granularity)) {
+ // Make sure we don't try to reset to some bogus value if someone has
+ // typed in an unexpected argument.
+ if ($this->options['granularity_reset'] && $granularity = $this->date_handler->arg_granularity($this->argument)) {
$this->date_handler->granularity = $granularity;
$this->format = $this->date_handler->views_formats($this->date_handler->granularity, 'display');
$this->sql_format = $this->date_handler->views_formats($this->date_handler->granularity, 'sql');
@@ -276,7 +308,8 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
$this->ensure_my_table();
$group = !empty($this->options['date_group']) ? $this->options['date_group'] : 0;
- // If requested, add the delta field to the view so we can later find the value that matched our query.
+ // If requested, add the delta field to the view so
+ // we can later find the value that matched our query.
if (!empty($this->options['add_delta']) && (substr($this->real_field, -6) == '_value' || substr($this->real_field, -7) == '_value2')) {
$this->query->add_field($this->table_alias, 'delta');
$real_field_name = str_replace(array('_value', '_value2'), '', $this->real_field);
@@ -291,7 +324,8 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
$view_max_placeholder = $this->placeholder();
$this->date_handler->placeholders = array($view_min_placeholder => $view_min, $view_max_placeholder => $view_max);
- // Are we comparing this field only or the Start/End date range to the view criteria?
+ // Are we comparing this field only or the Start/End date range
+ // to the view criteria?
if (!empty($this->options['use_fromto'])) {
// The simple case, match the field to the view range.
@@ -302,10 +336,14 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
}
else {
- // Look for the intersection of the range of the date field with the range of the view.
- // Get the Start/End values for this field. Retrieve using the original table name.
- // Swap the current table name (adjusted for relationships) into the query.
- // @TODO We may be able to use Views substitutions here, investigate that later.
+ // Look for the intersection of the range
+ // of the date field with the range of the view.
+ // Get the Start/End values for this field.
+ // Retrieve using the original table name.
+ // Swap the current table name (adjusted for relationships)
+ // into the query.
+ // @TODO We may be able to use Views substitutions here,
+ // investigate that later.
$fields = date_views_fields($this->base_table);
$fields = $fields['name'];
$fromto = $fields[$this->original_table . '.' . $this->real_field]['fromto'];
@@ -321,7 +359,10 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
}
/**
- * Add a callback to determine if we have moved outside the valid date range for this argument.
+ * Add a callback.
+ *
+ * To determine if we have moved outside
+ * the valid date range for this argument.
*/
function date_forbid() {
if (empty($this->argument)) {
@@ -343,3 +384,4 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
}
}
+// @codingStandardsIgnoreEnd
diff --git a/sites/all/modules/contrib/fields/date/date_views/includes/date_views_fields.inc b/sites/all/modules/contrib/fields/date/date_views/includes/date_views_fields.inc
index a002b088..d497ef60 100644
--- a/sites/all/modules/contrib/fields/date/date_views/includes/date_views_fields.inc
+++ b/sites/all/modules/contrib/fields/date/date_views/includes/date_views_fields.inc
@@ -5,13 +5,11 @@
*/
/**
- * Identify all potential date/timestamp fields.
+ * Identify all potential date/timestamp fields.
*
- * @return
- * array with fieldname, type, and table.
- * @see
- * date_views_date_views_fields() which implements
- * the hook_date_views_fields() for the core date fields.
+ * @return array
+ * An array with fieldname, type, and table.
+ * @see date_views_date_views_fields()
*/
function _date_views_fields($base = 'node') {
@@ -60,7 +58,7 @@ function _date_views_fields($base = 'node') {
$handler = views_get_handler($table_name, $field_name, 'filter');
$handler_name = $handler->definition['handler'];
- // We don't care about anything but date handlers
+ // We don't care about anything but date handlers.
if (empty($handler->definition['is date'])) {
continue;
}
@@ -72,14 +70,17 @@ function _date_views_fields($base = 'node') {
$field = field_info_field($handler->definition['field_name']);
$is_field = TRUE;
switch ($field['type']) {
- case 'date':
+ case 'date':
$sql_type = DATE_ISO;
break;
+
case 'datestamp':
break;
+
case 'datetime':
$sql_type = DATE_DATETIME;
break;
+
default:
// If this is not a date field, nothing more to do.
continue;
@@ -88,7 +89,8 @@ function _date_views_fields($base = 'node') {
$revision = in_array($base, array('node_revision')) ? FIELD_LOAD_REVISION : FIELD_LOAD_CURRENT;
$db_info = date_api_database_info($field, $revision);
$name = $table_name . "." . $field_name;
- $granularity = !empty($field['granularity']) ? $field['granularity'] : array('year', 'month', 'day', 'hour', 'minute', 'second');
+ $grans = array('year', 'month', 'day', 'hour', 'minute', 'second');
+ $granularity = !empty($field['granularity']) ? $field['granularity'] : $grans;
$fromto = array(
$table_name . '.' . $db_info['columns'][$table_name]['value'],
diff --git a/sites/all/modules/contrib/fields/date/date_views/includes/date_views_filter_handler.inc b/sites/all/modules/contrib/fields/date/date_views/includes/date_views_filter_handler.inc
index 0cfc7fcc..f761dfa0 100644
--- a/sites/all/modules/contrib/fields/date/date_views/includes/date_views_filter_handler.inc
+++ b/sites/all/modules/contrib/fields/date/date_views/includes/date_views_filter_handler.inc
@@ -3,9 +3,11 @@
* @file
* A flexible, configurable date filter.
* This filter combines multiple date filters into a single filter
- * where all fields are controlled by the same date and can be combined with either AND or OR.
+ * where all fields are controlled by the same date and can be combined
+ * with either AND or OR.
*/
+// @codingStandardsIgnoreStart
class date_views_filter_handler extends date_views_filter_handler_simple {
function init(&$view, &$options) {
parent::init($view, $options);
@@ -64,6 +66,9 @@ class date_views_filter_handler extends date_views_filter_handler_simple {
if ($field['table_name'] != $this->table || !empty($this->relationship)) {
$this->related_table_alias = $this->query->ensure_table($field['table_name'], $this->relationship);
}
+ else {
+ $this->related_table_alias = null;
+ }
$table_alias = !empty($this->related_table_alias) ? $this->related_table_alias : $field['table_name'];
$field_name = $table_alias . '.' . $field['field_name'];
@@ -179,3 +184,4 @@ class date_views_filter_handler extends date_views_filter_handler_simple {
}
}
}
+// @codingStandardsIgnoreEnd
diff --git a/sites/all/modules/contrib/fields/date/date_views/includes/date_views_filter_handler_simple.inc b/sites/all/modules/contrib/fields/date/date_views/includes/date_views_filter_handler_simple.inc
index d41f30b6..4fa4c409 100644
--- a/sites/all/modules/contrib/fields/date/date_views/includes/date_views_filter_handler_simple.inc
+++ b/sites/all/modules/contrib/fields/date/date_views/includes/date_views_filter_handler_simple.inc
@@ -1,9 +1,11 @@
$operator_values);
}
if (!isset($form_state['input'][$identifier][$prefix])) {
- $form_state['input'][$identifier][$prefix] = $this->value[$prefix];
+ // Ensure these exist.
+ foreach ($granularity as $key) {
+ $form_state['input'][$identifier][$prefix][$key] = NULL;
+ }
}
}
else {
@@ -530,3 +535,4 @@ class date_views_filter_handler_simple extends views_handler_filter_date {
}
}
+// @codingStandardsIgnoreEnd
diff --git a/sites/all/modules/contrib/fields/date/date_views/includes/date_views_plugin_pager.inc b/sites/all/modules/contrib/fields/date/date_views/includes/date_views_plugin_pager.inc
index f9594a72..5caca4e5 100644
--- a/sites/all/modules/contrib/fields/date/date_views/includes/date_views_plugin_pager.inc
+++ b/sites/all/modules/contrib/fields/date/date_views/includes/date_views_plugin_pager.inc
@@ -2,50 +2,74 @@
/**
* @file
* Date pager.
- * Works with a Date argument, the argument filters the view and the pager provides back/next navigation.
+ * Works with a Date argument, the argument filters
+ * the view and the pager provides back/next navigation.
*
* USER NOTES:
*
* To use this, add a pager to a view, and choose the option to 'Page by date'.
* There are several settings:
- * - The pager id: Set an id to be used as the identifier in the url for pager values, defaults to 'date'.
- * - Pager position: Choose whether to display the date pager above, below, or both above and below the content.
- * - Link format: Choose whether the pager links will be in the simple 'calendar/2011-12' format or the
- * more complex 'calendar/?date=2011-12' pager format. The second one is more likely to work correctly
- * if the pager is used in blocks and panels.
+ * - The pager id: Set an id to be used as the identifier
+ * in the url for pager values, defaults to 'date'.
+ * - Pager position: Choose whether to display the date
+ * pager above, below, or both above and below the content.
+ * - Link format: Choose whether the pager links will be in t
+ * he simple 'calendar/2011-12' format or the
+ * more complex 'calendar/?date=2011-12' pager format.
+ * The second one is more likely to work correctly
+ * if the pager is used in blocks and panels.
*
- * The pager works in combination with a Date argument and it will use the date fields and granularity
- * set in that argument to create its back/next links. If the view has no Date argument, the pager can
- * do nothing. The argument can either be a 'Date' argument that lets you select one or more date fields
- * in the argument, or the simple 'Content' argument for an individual date field. It must be an
+ * The pager works in combination with a Date argument
+ * and it will use the date fields and granularity
+ * set in that argument to create its back/next links.
+ * If the view has no Date argument, the pager can
+ * do nothing. The argument can either be a 'Date' argument
+ * that lets you select one or more date fields
+ * in the argument, or the simple 'Content' argument for an
+ * individual date field. It must be an
* argument that uses the date argument handler.
*
* DEVELOPER NOTES
*
- * The pager could technically create a query of its own rather than depending on the date argument to
- * set the query, but it has only a limited set of tools to work with because it is a plugin, not a handler:
- * it has no knowledge about relationships, it cannot use the ensure_my_table() function,
- * plugins are not even invoked in pre_query(), so can't do anything there.
+ * The pager could technically create a query of its own rather
+ * than depending on the date argument to
+ * set the query, but it has only a limited set of tools to work
+ * with because it is a plugin, not a handler:
+ * it has no knowledge about relationships, it cannot use the
+ * ensure_my_table() function, plugins are not even invoked in pre_query(),
+ * so can't do anything there.
*
- * My conclusion was that the date pager simply is not powerful enough to create its own queries for
- * date fields, which require very complex queries. Instead, we can combine this with a date argument and
- * let the argument create the query and let the pager just provide the back/next links. If there is no
+ * My conclusion was that the date pager simply
+ * is not powerful enough to create its own queries for
+ * date fields, which require very complex queries.
+ * Instead, we can combine this with a date argument and
+ * let the argument create the query and let the pager
+ * just provide the back/next links. If there is no
* date argument, the pager will do nothing.
*
- * There are still other problems. The pager is not even initialized until after all the handlers
- * have created their queries, so it has no chance to alter values ahead of that. And the argument
- * has no knowledge of the pager, so it can't check for pager values before the query is created.
+ * There are still other problems. The pager is not even
+ * initialized until after all the handlers
+ * have created their queries, so it has no chance
+ * to alter values ahead of that. And the argument
+ * has no knowledge of the pager, so it can't check
+ * for pager values before the query is created.
*
- * The solution used here is to let the argument create the original query. The pager query
- * runs after that, so the pager checks to see if there is a pager value that needs to be used in the query.
- * The date argument has identified the placeholders it used in the query. So if a change is needed,
- * we can swap the pager value into the query created by the date argument and adjust the
- * $view->date_info values set by the argument accordingly so the theme will pick up the new information.
+ * The solution used here is to let the argument create
+ * the original query. The pager query
+ * runs after that, so the pager checks to see
+ * if there is a pager value that needs to be used in the query.
+ * The date argument has identified the placeholders
+ * it used in the query. So if a change is needed,
+ * we can swap the pager value into the query created
+ * by the date argument and adjust the
+ * $view->date_info values set by the argument accordingly
+ * so the theme will pick up the new information.
*/
/**
* Example plugin to handle paging by month.
*/
+// @codingStandardsIgnoreStart
class date_views_plugin_pager extends views_plugin_pager {
/**
@@ -79,6 +103,7 @@ class date_views_plugin_pager extends views_plugin_pager {
$options['link_format'] = array('default' => 'pager');
$options['date_argument'] = array('default' => 'Unknown');
$options['granularity'] = array('default' => 'Unknown');
+ $options['skip_empty_pages'] = array('default' => FALSE);
return $options;
}
@@ -110,6 +135,12 @@ class date_views_plugin_pager extends views_plugin_pager {
'#default_value' => $this->options['link_format'],
'#required' => TRUE,
);
+ $form['skip_empty_pages'] = array(
+ '#title' => t('Skip empty pages'),
+ '#type' => 'checkbox',
+ '#description' => t('When selected, the pager will not display pages with no result for the given date. This causes a slight performance degradation because two additional queries need to be executed.'),
+ '#default_value' => $this->options['skip_empty_pages'],
+ );
$form['date_argument']['#type'] = 'hidden';
$form['date_argument']['#value'] = $this->options['date_argument'];
$form['granularity']['#type'] = 'hidden';
@@ -150,13 +181,7 @@ class date_views_plugin_pager extends views_plugin_pager {
// Reset values set by argument if pager requires it.
if (!empty($value)) {
- $argument->argument = $value;
- $argument->date_range = $argument->date_handler->arg_range($value);
- $argument->min_date = $argument->date_range[0];
- $argument->max_date = $argument->date_range[1];
- // $argument->is_default works correctly for normal arguments, but does not
- // work correctly if we are swapping in a new value from the pager.
- $argument->is_default = FALSE;
+ $this->set_argument_value($argument, $value);
}
// The pager value might move us into a forbidden range, so test it.
@@ -164,13 +189,102 @@ class date_views_plugin_pager extends views_plugin_pager {
$this->view->build_info['fail'] = TRUE;
return;
}
-
- if (empty($this->view->date_info)) $this->view->date_info = new stdClass();
+ // Write date_info to store information to be used
+ // in the theming functions.
+ if (empty($this->view->date_info)) {
+ $this->view->date_info = new stdClass();
+ }
$this->view->date_info->granularity = $argument->date_handler->granularity;
$format = $this->view->date_info->granularity == 'week' ? DATE_FORMAT_DATETIME : $argument->sql_format;
$this->view->date_info->placeholders = isset($argument->placeholders) ? $argument->placeholders : $argument->date_handler->placeholders;
$this->view->date_info->date_arg = $argument->argument;
$this->view->date_info->date_arg_pos = $i;
+ $this->view->date_info->limit = $argument->limit;
+ $this->view->date_info->url = $this->view->get_url();
+ $this->view->date_info->pager_id = $this->options['date_id'];
+ $this->view->date_info->date_pager_position = $this->options['pager_position'];
+ $this->view->date_info->date_pager_format = $this->options['link_format'];
+ $this->view->date_info->skip_empty_pages = $this->options['skip_empty_pages'] == 1;
+ // Execute two additional queries to find
+ // the previous and next page with values.
+ if ($this->view->date_info->skip_empty_pages) {
+ $q = clone $argument->query;
+ $field = $argument->table_alias . '.' . $argument->real_field;
+ $fieldsql = $date_handler->sql_field($field);
+ $fieldsql = $date_handler->sql_format($format, $fieldsql);
+ $q->clear_fields();
+ $q->orderby = array();
+ $q->set_distinct(TRUE, TRUE);
+ // Date limits of this argument.
+ $datelimits = $argument->date_handler->arg_range($argument->limit[0] . '--' . $argument->limit[1]);
+ // Find the first two dates between the minimum date
+ // and the upper bound of the current value.
+ $q->add_orderby(NULL, $fieldsql, 'DESC', 'date');
+ $this->set_argument_placeholders($this->view->date_info->placeholders, $datelimits[0], $argument->max_date, $q, $format);
+
+ $compiledquery = $q->query();
+ $compiledquery->range(0, 2);
+ $results = $compiledquery->execute()->fetchCol(0);
+
+ $prevdate = array_shift($results);
+ $prevdatealt = array_shift($results);
+ // Find the first two dates between the lower bound
+ // of the current value and the maximum date.
+ $q->add_orderby(NULL, $fieldsql, 'ASC', 'date');
+ $this->set_argument_placeholders($this->view->date_info->placeholders, $argument->min_date, $datelimits[1], $q, $format);
+
+ $compiledquery = $q->query();
+ $compiledquery->range(0, 2);
+ $results = $compiledquery->execute()->fetchCol(0);
+
+ $nextdate = array_shift($results);
+ $nextdatealt = array_shift($results);
+
+ // Set the default value of the query to $prevfirst or $nextfirst
+ // when there is no value and $prevsecond or $nextsecond is set.
+ if (empty($value)) {
+ // @Todo find out which of $prevdate or $nextdate is closest to the
+ // default argument date value and choose that one.
+ if ($prevdate && $prevdatealt) {
+ $this->set_argument_value($argument, $prevdate);
+ $value = $prevdate;
+ $prevdate = $prevdatealt;
+ // If the first next date is the same as the first previous date,
+ // move to the following next date.
+ if ($value == $nextdate) {
+ $nextdate = $nextdatealt;
+ $nextdatealt = NULL;
+ }
+ }
+ elseif ($nextdate && $nextdatealt) {
+ $this->set_argument_value($argument, $nextdate);
+ $value = $nextdate;
+ $nextdate = $nextdatealt;
+ // If the first previous date is the same as the first next date,
+ // move to the following previous date.
+ if ($value == $prevdate) {
+ $prevdate = $prevdatealt;
+ $prevdatealt = NULL;
+ }
+ }
+ }
+ else {
+ // $prevdate and $nextdate are the same as $value, so move to
+ // the next values.
+ $prevdate = $prevdatealt;
+ $nextdate = $nextdatealt;
+ }
+
+ $this->view->date_info->prev_date = $prevdate ? new DateObject($prevdate, NULL, $format) : NULL;
+ $this->view->date_info->next_date = $nextdate ? new DateObject($nextdate, NULL, $format) : NULL;
+ }
+ else {
+ $this->view->date_info->prev_date = clone($argument->min_date);
+ date_modify($this->view->date_info->prev_date, '-1 ' . $argument->date_handler->granularity);
+ $this->view->date_info->next_date = clone($argument->max_date);
+ date_modify($this->view->date_info->next_date, '+1 ' . $argument->date_handler->granularity);
+ }
+ // Write the date_info properties that depend on the current value.
$this->view->date_info->year = date_format($argument->min_date, 'Y');
$this->view->date_info->month = date_format($argument->min_date, 'n');;
$this->view->date_info->day = date_format($argument->min_date, 'j');
@@ -178,11 +292,6 @@ class date_views_plugin_pager extends views_plugin_pager {
$this->view->date_info->date_range = $argument->date_range;
$this->view->date_info->min_date = $argument->min_date;
$this->view->date_info->max_date = $argument->max_date;
- $this->view->date_info->limit = $argument->limit;
- $this->view->date_info->url = $this->view->get_url();
- $this->view->date_info->pager_id = $this->options['date_id'];
- $this->view->date_info->date_pager_position = $this->options['pager_position'];
- $this->view->date_info->date_pager_format = $this->options['link_format'];
}
$i++;
}
@@ -191,20 +300,33 @@ class date_views_plugin_pager extends views_plugin_pager {
// If there is pager input and the argument has set the placeholders,
// swap the pager value in for the placeholder set by the argument.
if (!empty($value) && !empty($this->view->date_info->placeholders)) {
- $placeholders = $this->view->date_info->placeholders;
- $count = count($placeholders);
- foreach ($this->view->query->where as $group => $data) {
- foreach ($data['conditions'] as $delta => $condition) {
- if (array_key_exists('value', $condition) && is_array($condition['value'])) {
- foreach ($condition['value'] as $placeholder => $placeholder_value) {
- if (array_key_exists($placeholder, $placeholders)) {
- // If we didn't get a match, this is a > $min < $max query that uses the view
- // min and max dates as placeholders.
- $date = ($count == 2) ? $this->view->date_info->min_date : $this->view->date_info->max_date;
- $next_placeholder = array_shift($placeholders);
- $this->view->query->where[$group]['conditions'][$delta]['value'][$placeholder] = $date->format($format);
- $count--;
- }
+ $this->set_argument_placeholders($this->view->date_info->placeholders, $this->view->date_info->min_date, $this->view->date_info->max_date, $this->view->query, $format);
+ }
+ }
+
+ function set_argument_value($argument, $value) {
+ $argument->argument = $value;
+ $argument->date_range = $argument->date_handler->arg_range($value);
+ $argument->min_date = $argument->date_range[0];
+ $argument->max_date = $argument->date_range[1];
+ // $argument->is_default works correctly for normal arguments, but does not
+ // work correctly if we are swapping in a new value from the pager.
+ $argument->is_default = FALSE;
+ }
+
+ function set_argument_placeholders($placeholders, $mindate, $maxdate, $query, $format) {
+ $count = count($placeholders);
+ foreach ($query->where as $group => $data) {
+ foreach ($data['conditions'] as $delta => $condition) {
+ if (array_key_exists('value', $condition) && is_array($condition['value'])) {
+ foreach ($condition['value'] as $placeholder => $placeholder_value) {
+ if (array_key_exists($placeholder, $placeholders)) {
+ // If we didn't get a match, this is a > $min < $max query that uses the view
+ // min and max dates as placeholders.
+ $date = ($count == 2) ? $mindate : $maxdate;
+ $next_placeholder = array_shift($placeholders);
+ $query->where[$group]['conditions'][$delta]['value'][$placeholder] = $date->format($format);
+ $count--;
}
}
}
@@ -230,4 +352,5 @@ class date_views_plugin_pager extends views_plugin_pager {
$pager_theme = views_theme_functions('date_views_pager', $this->view, $this->display);
return theme($pager_theme, array('plugin' => $this, 'input' => $input));
}
-}
\ No newline at end of file
+}
+// @codingStandardsIgnoreEnd
diff --git a/sites/all/modules/contrib/fields/date/date_views/theme/date-views-pager.tpl.php b/sites/all/modules/contrib/fields/date/date_views/theme/date-views-pager.tpl.php
index b12c2e1c..ac8cfb4e 100644
--- a/sites/all/modules/contrib/fields/date/date_views/theme/date-views-pager.tpl.php
+++ b/sites/all/modules/contrib/fields/date/date_views/theme/date-views-pager.tpl.php
@@ -27,8 +27,10 @@
* be used in the l() function, including rel=nofollow.
*/
?>
-
-
';
@@ -1861,8 +1930,10 @@ function field_group_attach_groups(&$element, $view_mode, $form_state = array())
// Create a lookup array.
$group_children = array();
foreach ($element['#groups'] as $group_name => $group) {
- foreach ($group->children as $child) {
- $group_children[$child] = $group_name;
+ if (!empty($group->children)) {
+ foreach ($group->children as $child) {
+ $group_children[$child] = $group_name;
+ }
}
}
$element['#group_children'] = $group_children;
@@ -1951,9 +2022,12 @@ function field_group_fields_nest(&$element, &$vars = NULL) {
// Create all groups and keep a flat list of references to these groups.
$group_references = array();
foreach ($element['#fieldgroups'] as $group_name => $group) {
- // Construct own weight, as some fields (for example preprocess fields) don't have weight set.
- $element[$group_name] = array();
- $group_references[$group_name] = &$element[$group_name];
+ // check for any erroneous groups from other modules
+ if (is_string($group_name)) {
+ // Construct own weight, as some fields (for example preprocess fields) don't have weight set.
+ $element[$group_name] = array();
+ $group_references[$group_name] = &$element[$group_name];
+ }
}
// Loop through all form children looking for those that are supposed to be
@@ -2167,3 +2241,37 @@ function _field_group_get_default_formatter_settings($format_type, $mode) {
);
}
+/**
+ * Callback to bulk export field groups.
+ */
+function field_group_field_group_to_hook_code($data, $module) {
+ ctools_include('export');
+ $schema = ctools_export_get_schema('field_group');
+ $export = $schema['export'];
+
+ $translatables = array();
+ $objects = ctools_export_load_object('field_group', 'names', array_values($data));
+ $code = "/**\n";
+ $code .= " * Implements hook_{$export['default hook']}()\n";
+ $code .= " */\n";
+ $code .= "function " . $module . "_{$export['default hook']}() {\n";
+ $code .= " \${$export['identifier']}s = array();\n\n";
+ foreach ($objects as $object) {
+ $code .= ctools_export_object('field_group', $object, ' ');
+ $code .= " \${$export['identifier']}s['" . check_plain($object->$export['key']) . "'] = \${$export['identifier']};\n\n";
+ if (!empty($object->data['label'])) {
+ $translatables[] = $object->data['label'];
+ }
+ if (!empty($object->data['description'])) {
+ $translatables[] = $object->data['description'];
+ }
+ }
+
+ if (!empty($translatables)) {
+ $code .= features_translatables_export($translatables, ' ') . "\n";
+ }
+
+ $code .= " return \${$export['identifier']}s;";
+ $code .= "}\n";
+ return $code;
+}
diff --git a/sites/all/modules/contrib/fields/field_group/multipage/multipage.js b/sites/all/modules/contrib/fields/field_group/multipage/multipage.js
index 5314031e..b5f4d08e 100644
--- a/sites/all/modules/contrib/fields/field_group/multipage/multipage.js
+++ b/sites/all/modules/contrib/fields/field_group/multipage/multipage.js
@@ -82,14 +82,14 @@ Drupal.multipageControl = function (settings) {
var controls = Drupal.theme('multipage', settings);
$.extend(self, settings, controls);
- this.nextLink.click(function () {
+ this.nextLink.click(function (e) {
+ e.preventDefault();
self.nextPage();
- return false;
});
- this.previousLink.click(function () {
+ this.previousLink.click(function (e) {
+ e.preventDefault();
self.previousPage();
- return false;
});
/*
diff --git a/sites/all/modules/contrib/fields/field_group/tests/field_group.display.test b/sites/all/modules/contrib/fields/field_group/tests/field_group.display.test
index 5b823851..6058522c 100644
--- a/sites/all/modules/contrib/fields/field_group/tests/field_group.display.test
+++ b/sites/all/modules/contrib/fields/field_group/tests/field_group.display.test
@@ -16,7 +16,7 @@ class GroupDisplayTestCase extends DrupalWebTestCase {
return array(
'name' => 'Display tests',
'description' => 'Test the field group display.',
- 'group' => 'Field group',
+ 'group' => 'Field Group',
);
}
@@ -209,7 +209,6 @@ class GroupDisplayTestCase extends DrupalWebTestCase {
),
);
$first_tab = $this->createGroup('default', $data);
- $first_tab_id = 'node_article_full_' . $first_tab->group_name;
$data = array(
'label' => 'Tab 2',
@@ -228,7 +227,6 @@ class GroupDisplayTestCase extends DrupalWebTestCase {
),
);
$second_tab = $this->createGroup('default', $data);
- $second_tab_id = 'node_article_full_' . $first_tab->group_name;
$data = array(
'label' => 'Tabs',
@@ -258,8 +256,8 @@ class GroupDisplayTestCase extends DrupalWebTestCase {
$this->assertRaw('class="collapsible collapsed test-class-2', t('Second tab is default collapsed'));
// Test if correctly nested
- $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//fieldset[contains(@id, '$first_tab_id')]", NULL, 'First tab is displayed as child of the wrapper.');
- $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//fieldset[contains(@id, '$second_tab_id')]", NULL, 'Second tab is displayed as child of the wrapper.');
+ $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//fieldset[contains(@class, 'test-class')]", NULL, 'First tab is displayed as child of the wrapper.');
+ $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//fieldset[contains(@class, 'test-class-2')]", NULL, 'Second tab is displayed as child of the wrapper.');
}
@@ -285,7 +283,7 @@ class GroupDisplayTestCase extends DrupalWebTestCase {
),
);
$first_tab = $this->createGroup('default', $data);
- $first_tab_id = 'node_article_full_' . $first_tab->group_name;
+ $first_tab_id = 'edit-' . $first_tab->group_name;
$data = array(
'label' => 'Tab 2',
@@ -304,7 +302,7 @@ class GroupDisplayTestCase extends DrupalWebTestCase {
),
);
$second_tab = $this->createGroup('default', $data);
- $second_tab_id = 'node_article_full_' . $first_tab->group_name;
+ $second_tab_id = 'edit-' . $second_tab->group_name;
$data = array(
'label' => 'Tabs',
diff --git a/sites/all/modules/contrib/fields/field_group/tests/field_group_test.info b/sites/all/modules/contrib/fields/field_group/tests/field_group_test.info
index 006a7f31..4c99162d 100644
--- a/sites/all/modules/contrib/fields/field_group/tests/field_group_test.info
+++ b/sites/all/modules/contrib/fields/field_group/tests/field_group_test.info
@@ -5,9 +5,9 @@ package = Fields
hidden = TRUE
-; Information added by Drupal.org packaging script on 2014-06-04
-version = "7.x-1.4"
+; Information added by Drupal.org packaging script on 2016-01-05
+version = "7.x-1.5"
core = "7.x"
project = "field_group"
-datestamp = "1401918529"
+datestamp = "1452033709"
diff --git a/sites/all/modules/contrib/fields/link/README.txt b/sites/all/modules/contrib/fields/link/README.txt
new file mode 100644
index 00000000..387cc594
--- /dev/null
+++ b/sites/all/modules/contrib/fields/link/README.txt
@@ -0,0 +1,33 @@
+Module description
+------------------
+The link module can be count to the top 50 modules in Drupal installations and provides a standard custom content field for links. With this module links can be added easily to any content types and profiles and include advanced validating and different ways of storing internal or external links and URLs. It also supports additional link text title, site wide tokens for titles and title attributes, target attributes, css class attribution, static repeating values, input conversion, and many more.
+
+Requirements / Dependencies
+---------------------------
+1. Drupal 6: Custom content module (CCK)
+2. Drupal 7: Fields API is provided already by core [no dependencies].
+3. Drupal 8: Link module is in core now. No module installation needed. Yay! Don't forget to activate it. It's deactivated by default.
+
+INFO Since some misleading user reports we need to clarify here - Link module is NOT about to add links to any menus or the navigation nor primary/secondary menu. This can be done with default menu module (part of Drupal core). The Link module provides an additional custom field for storing and validating links to be added with any content type, which means another input block additional to your text-body, title, image and any other input you can make on new content creation.
+
+Installation
+------------
+1. Drop the entire link module directory into your 'sites/all/modules' folder
+2. Enable the module from the Administration area modules page (admin/build/modules)
+3. Create or Edit a content-type and add a new field of type link (admin/content/types in D6, admin/structure/types in D7)
+
+Configuration
+-------------
+Configuration is only slightly more complicated than a text field. Link text titles for URLs can be made required, set as instead of URL, optional (default), or left out entirely. If no link text title is provided, the trimmed version of the complete URL will be displayed. The target attribute should be set to "_blank", "top", or left out completely (checkboxes provide info). The rel=nofollow attribute prevents the link from being followed by certain search engines. More info at Wikipedia (http://en.wikipedia.org/wiki/Spam_in_blogs#rel.3D.22nofollow.22).
+
+Example
+-------
+If you were to create a field named 'My New Link', the default display of the link would be:
";
container = document.createElement("div");
- container.style.cssText = vb + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
+ container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
body.insertBefore( container, body.firstChild );
// Construct the test element
@@ -1548,7 +1569,7 @@ jQuery.support = (function() {
// display:none (it is still safe to use offsets if a parent element is
// hidden; don safety goggles and see bug #4512 for more information).
// (only IE 8 fails this test)
- div.innerHTML = "
t
";
+ div.innerHTML = "
t
";
tds = div.getElementsByTagName( "td" );
isSupported = ( tds[ 0 ].offsetHeight === 0 );
@@ -1559,28 +1580,44 @@ jQuery.support = (function() {
// (IE <= 8 fail this test)
support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
- // Figure out if the W3C box model works as expected
- div.innerHTML = "";
- div.style.width = div.style.paddingLeft = "1px";
- jQuery.boxModel = support.boxModel = div.offsetWidth === 2;
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. For more
+ // info see bug #3333
+ // Fails in WebKit before Feb 2011 nightlies
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ if ( window.getComputedStyle ) {
+ div.innerHTML = "";
+ marginDiv = document.createElement( "div" );
+ marginDiv.style.width = "0";
+ marginDiv.style.marginRight = "0";
+ div.style.width = "2px";
+ div.appendChild( marginDiv );
+ support.reliableMarginRight =
+ ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
+ }
if ( typeof div.style.zoom !== "undefined" ) {
// Check if natively block-level elements act like inline-block
// elements when setting their display to 'inline' and giving
// them layout
// (IE < 8 does this)
+ div.innerHTML = "";
+ div.style.width = div.style.padding = "1px";
+ div.style.border = 0;
+ div.style.overflow = "hidden";
div.style.display = "inline";
div.style.zoom = 1;
- support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
// Check if elements with layout shrink-wrap their children
// (IE 6 does this)
- div.style.display = "";
- div.innerHTML = "";
- support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
+ div.style.display = "block";
+ div.style.overflow = "visible";
+ div.innerHTML = "";
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
}
- div.style.cssText = ptlm + vb;
+ div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility;
div.innerHTML = html;
outer = div.firstChild;
@@ -1605,8 +1642,17 @@ jQuery.support = (function() {
offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
+ if ( window.getComputedStyle ) {
+ div.style.marginTop = "1%";
+ support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%";
+ }
+
+ if ( typeof container.style.zoom !== "undefined" ) {
+ container.style.zoom = 1;
+ }
+
body.removeChild( container );
- div = container = null;
+ marginDiv = div = container = null;
jQuery.extend( support, offsetSupport );
});
@@ -1863,62 +1909,70 @@ jQuery.extend({
jQuery.fn.extend({
data: function( key, value ) {
- var parts, attr, name,
+ var parts, part, attr, name, l,
+ elem = this[0],
+ i = 0,
data = null;
- if ( typeof key === "undefined" ) {
+ // Gets all values
+ if ( key === undefined ) {
if ( this.length ) {
- data = jQuery.data( this[0] );
+ data = jQuery.data( elem );
- if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) {
- attr = this[0].attributes;
- for ( var i = 0, l = attr.length; i < l; i++ ) {
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ attr = elem.attributes;
+ for ( l = attr.length; i < l; i++ ) {
name = attr[i].name;
if ( name.indexOf( "data-" ) === 0 ) {
name = jQuery.camelCase( name.substring(5) );
- dataAttr( this[0], name, data[ name ] );
+ dataAttr( elem, name, data[ name ] );
}
}
- jQuery._data( this[0], "parsedAttrs", true );
+ jQuery._data( elem, "parsedAttrs", true );
}
}
return data;
+ }
- } else if ( typeof key === "object" ) {
+ // Sets multiple values
+ if ( typeof key === "object" ) {
return this.each(function() {
jQuery.data( this, key );
});
}
- parts = key.split(".");
+ parts = key.split( ".", 2 );
parts[1] = parts[1] ? "." + parts[1] : "";
+ part = parts[1] + "!";
- if ( value === undefined ) {
- data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+ return jQuery.access( this, function( value ) {
- // Try to fetch any internally stored data first
- if ( data === undefined && this.length ) {
- data = jQuery.data( this[0], key );
- data = dataAttr( this[0], key, data );
+ if ( value === undefined ) {
+ data = this.triggerHandler( "getData" + part, [ parts[0] ] );
+
+ // Try to fetch any internally stored data first
+ if ( data === undefined && elem ) {
+ data = jQuery.data( elem, key );
+ data = dataAttr( elem, key, data );
+ }
+
+ return data === undefined && parts[1] ?
+ this.data( parts[0] ) :
+ data;
}
- return data === undefined && parts[1] ?
- this.data( parts[0] ) :
- data;
+ parts[1] = value;
+ this.each(function() {
+ var self = jQuery( this );
- } else {
- return this.each(function() {
- var self = jQuery( this ),
- args = [ parts[0], value ];
-
- self.triggerHandler( "setData" + parts[1] + "!", args );
+ self.triggerHandler( "setData" + part, parts );
jQuery.data( this, key, value );
- self.triggerHandler( "changeData" + parts[1] + "!", args );
+ self.triggerHandler( "changeData" + part, parts );
});
- }
+ }, null, value, arguments.length > 1, null, false );
},
removeData: function( key ) {
@@ -1942,7 +1996,7 @@ function dataAttr( elem, key, data ) {
data = data === "true" ? true :
data === "false" ? false :
data === "null" ? null :
- jQuery.isNumeric( data ) ? parseFloat( data ) :
+ jQuery.isNumeric( data ) ? +data :
rbrace.test( data ) ? jQuery.parseJSON( data ) :
data;
} catch( e ) {}
@@ -2077,21 +2131,27 @@ jQuery.extend({
jQuery.fn.extend({
queue: function( type, data ) {
+ var setter = 2;
+
if ( typeof type !== "string" ) {
data = type;
type = "fx";
+ setter--;
}
- if ( data === undefined ) {
+ if ( arguments.length < setter ) {
return jQuery.queue( this[0], type );
}
- return this.each(function() {
- var queue = jQuery.queue( this, type, data );
- if ( type === "fx" && queue[0] !== "inprogress" ) {
- jQuery.dequeue( this, type );
- }
- });
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
},
dequeue: function( type ) {
return this.each(function() {
@@ -2145,7 +2205,7 @@ jQuery.fn.extend({
}
}
resolve();
- return defer.promise();
+ return defer.promise( object );
}
});
@@ -2164,7 +2224,7 @@ var rclass = /[\n\t\r]/g,
jQuery.fn.extend({
attr: function( name, value ) {
- return jQuery.access( this, name, value, true, jQuery.attr );
+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
},
removeAttr: function( name ) {
@@ -2174,7 +2234,7 @@ jQuery.fn.extend({
},
prop: function( name, value ) {
- return jQuery.access( this, name, value, true, jQuery.prop );
+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
},
removeProp: function( name ) {
@@ -2314,7 +2374,7 @@ jQuery.fn.extend({
if ( !arguments.length ) {
if ( elem ) {
- hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
return ret;
@@ -2358,7 +2418,7 @@ jQuery.fn.extend({
});
}
- hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ];
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
// If set returns undefined, fall back to normal setting
if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
@@ -2504,7 +2564,7 @@ jQuery.extend({
},
removeAttr: function( elem, value ) {
- var propName, attrNames, name, l,
+ var propName, attrNames, name, l, isBool,
i = 0;
if ( value && elem.nodeType === 1 ) {
@@ -2516,13 +2576,17 @@ jQuery.extend({
if ( name ) {
propName = jQuery.propFix[ name ] || name;
+ isBool = rboolean.test( name );
// See #9699 for explanation of this approach (setting first, then removal)
- jQuery.attr( elem, name, "" );
+ // Do not do this for boolean attributes (see #10870)
+ if ( !isBool ) {
+ jQuery.attr( elem, name, "" );
+ }
elem.removeAttribute( getSetAttribute ? name : propName );
// Set corresponding property to false for boolean attributes
- if ( rboolean.test( name ) && propName in elem ) {
+ if ( isBool && propName in elem ) {
elem[ propName ] = false;
}
}
@@ -2676,7 +2740,8 @@ if ( !getSetAttribute ) {
fixSpecified = {
name: true,
- id: true
+ id: true,
+ coords: true
};
// Use this for any attribute in IE6/7
@@ -2806,7 +2871,7 @@ jQuery.each([ "radio", "checkbox" ], function() {
var rformElems = /^(?:textarea|input|select)$/i,
rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
- rhoverHack = /\bhover(\.\S+)?\b/,
+ rhoverHack = /(?:^|\s)hover(\.\S+)?\b/,
rkeyEvent = /^key/,
rmouseEvent = /^(?:mouse|contextmenu)|click/,
rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
@@ -2854,6 +2919,7 @@ jQuery.event = {
if ( handler.handler ) {
handleObjIn = handler;
handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
}
// Make sure that the handler has a unique ID, used to find/remove it later
@@ -2905,7 +2971,7 @@ jQuery.event = {
handler: handler,
guid: handler.guid,
selector: selector,
- quick: quickParse( selector ),
+ quick: selector && quickParse( selector ),
namespace: namespaces.join(".")
}, handleObjIn );
@@ -3194,6 +3260,7 @@ jQuery.event = {
delegateCount = handlers.delegateCount,
args = [].slice.call( arguments, 0 ),
run_all = !event.exclusive && !event.namespace,
+ special = jQuery.event.special[ event.type ] || {},
handlerQueue = [],
i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;
@@ -3201,34 +3268,43 @@ jQuery.event = {
args[0] = event;
event.delegateTarget = this;
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
// Determine handlers that should run if there are delegated events
- // Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861)
- if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) {
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && !(event.button && event.type === "click") ) {
// Pregenerate a single jQuery object for reuse with .is()
jqcur = jQuery(this);
jqcur.context = this.ownerDocument || this;
for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
- selMatch = {};
- matches = [];
- jqcur[0] = cur;
- for ( i = 0; i < delegateCount; i++ ) {
- handleObj = handlers[ i ];
- sel = handleObj.selector;
- if ( selMatch[ sel ] === undefined ) {
- selMatch[ sel ] = (
- handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )
- );
+ // Don't process events on disabled elements (#6911, #8165)
+ if ( cur.disabled !== true ) {
+ selMatch = {};
+ matches = [];
+ jqcur[0] = cur;
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+ sel = handleObj.selector;
+
+ if ( selMatch[ sel ] === undefined ) {
+ selMatch[ sel ] = (
+ handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )
+ );
+ }
+ if ( selMatch[ sel ] ) {
+ matches.push( handleObj );
+ }
}
- if ( selMatch[ sel ] ) {
- matches.push( handleObj );
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, matches: matches });
}
}
- if ( matches.length ) {
- handlerQueue.push({ elem: cur, matches: matches });
- }
}
}
@@ -3266,6 +3342,11 @@ jQuery.event = {
}
}
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
return event.result;
},
@@ -3557,16 +3638,23 @@ if ( !jQuery.support.submitBubbles ) {
form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
if ( form && !form._submit_attached ) {
jQuery.event.add( form, "submit._submit", function( event ) {
- // If form was submitted by the user, bubble the event up the tree
- if ( this.parentNode && !event.isTrigger ) {
- jQuery.event.simulate( "submit", this.parentNode, event, true );
- }
+ event._submit_bubble = true;
});
form._submit_attached = true;
}
});
// return undefined since we don't need an event listener
},
+
+ postDispatch: function( event ) {
+ // If form was submitted by the user, bubble the event up the tree
+ if ( event._submit_bubble ) {
+ delete event._submit_bubble;
+ if ( this.parentNode && !event.isTrigger ) {
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
+ }
+ }
+ },
teardown: function() {
// Only need this for delegated form submit events
@@ -3671,9 +3759,9 @@ jQuery.fn.extend({
// Types can be a map of types/handlers
if ( typeof types === "object" ) {
// ( types-Object, selector, data )
- if ( typeof selector !== "string" ) {
+ if ( typeof selector !== "string" ) { // && selector != null
// ( types-Object, data )
- data = selector;
+ data = data || selector;
selector = undefined;
}
for ( type in types ) {
@@ -3719,14 +3807,14 @@ jQuery.fn.extend({
});
},
one: function( types, selector, data, fn ) {
- return this.on.call( this, types, selector, data, fn, 1 );
+ return this.on( types, selector, data, fn, 1 );
},
off: function( types, selector, fn ) {
if ( types && types.preventDefault && types.handleObj ) {
// ( event ) dispatched jQuery.Event
var handleObj = types.handleObj;
jQuery( types.delegateTarget ).off(
- handleObj.namespace? handleObj.type + "." + handleObj.namespace : handleObj.type,
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
handleObj.selector,
handleObj.handler
);
@@ -3885,7 +3973,7 @@ var Sizzle = function( selector, context, results, seed ) {
if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
return [];
}
-
+
if ( !selector || typeof selector !== "string" ) {
return results;
}
@@ -3895,7 +3983,7 @@ var Sizzle = function( selector, context, results, seed ) {
contextXML = Sizzle.isXML( context ),
parts = [],
soFar = selector;
-
+
// Reset the position of the chunker regexp (start from head)
do {
chunker.exec( "" );
@@ -3903,9 +3991,9 @@ var Sizzle = function( selector, context, results, seed ) {
if ( m ) {
soFar = m[3];
-
+
parts.push( m[1] );
-
+
if ( m[2] ) {
extra = m[3];
break;
@@ -3929,7 +4017,7 @@ var Sizzle = function( selector, context, results, seed ) {
if ( Expr.relative[ selector ] ) {
selector += parts.shift();
}
-
+
set = posProcess( selector, set, seed );
}
}
@@ -4057,7 +4145,7 @@ Sizzle.find = function( expr, context, isXML ) {
for ( i = 0, len = Expr.order.length; i < len; i++ ) {
type = Expr.order[i];
-
+
if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
left = match[1];
match.splice( 1, 1 );
@@ -4189,7 +4277,7 @@ var getText = Sizzle.getText = function( elem ) {
ret = "";
if ( nodeType ) {
- if ( nodeType === 1 || nodeType === 9 ) {
+ if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
// Use textContent || innerText for elements
if ( typeof elem.textContent === 'string' ) {
return elem.textContent;
@@ -4429,7 +4517,7 @@ var Expr = Sizzle.selectors = {
ATTR: function( match, curLoop, inplace, result, not, isXML ) {
var name = match[1] = match[1].replace( rBackslash, "" );
-
+
if ( !isXML && Expr.attrMap[name] ) {
match[1] = Expr.attrMap[name];
}
@@ -4463,7 +4551,7 @@ var Expr = Sizzle.selectors = {
} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
return true;
}
-
+
return match;
},
@@ -4473,7 +4561,7 @@ var Expr = Sizzle.selectors = {
return match;
}
},
-
+
filters: {
enabled: function( elem ) {
return elem.disabled === false && elem.type !== "hidden";
@@ -4486,14 +4574,14 @@ var Expr = Sizzle.selectors = {
checked: function( elem ) {
return elem.checked === true;
},
-
+
selected: function( elem ) {
// Accessing this property makes selected-by-default
// options in Safari work properly
if ( elem.parentNode ) {
elem.parentNode.selectedIndex;
}
-
+
return elem.selected === true;
},
@@ -4515,7 +4603,7 @@ var Expr = Sizzle.selectors = {
text: function( elem ) {
var attr = elem.getAttribute( "type" ), type = elem.type;
- // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
// use getAttribute instead to test this case
return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
},
@@ -4633,22 +4721,23 @@ var Expr = Sizzle.selectors = {
switch ( type ) {
case "only":
case "first":
- while ( (node = node.previousSibling) ) {
- if ( node.nodeType === 1 ) {
- return false;
+ while ( (node = node.previousSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
}
}
- if ( type === "first" ) {
- return true;
+ if ( type === "first" ) {
+ return true;
}
node = elem;
+ /* falls through */
case "last":
- while ( (node = node.nextSibling) ) {
- if ( node.nodeType === 1 ) {
- return false;
+ while ( (node = node.nextSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
}
}
@@ -4661,22 +4750,22 @@ var Expr = Sizzle.selectors = {
if ( first === 1 && last === 0 ) {
return true;
}
-
+
doneName = match[0];
parent = elem.parentNode;
-
+
if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
count = 0;
-
+
for ( node = parent.firstChild; node; node = node.nextSibling ) {
if ( node.nodeType === 1 ) {
node.nodeIndex = ++count;
}
- }
+ }
parent[ expando ] = doneName;
}
-
+
diff = elem.nodeIndex - last;
if ( first === 0 ) {
@@ -4695,7 +4784,7 @@ var Expr = Sizzle.selectors = {
TAG: function( elem, match ) {
return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
},
-
+
CLASS: function( elem, match ) {
return (" " + (elem.className || elem.getAttribute("class")) + " ")
.indexOf( match ) > -1;
@@ -4757,6 +4846,9 @@ for ( var type in Expr.match ) {
Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
}
+// Expose origPOS
+// "global" as in regardless of relation to brackets/parens
+Expr.match.globalPOS = origPOS;
var makeArray = function( array, results ) {
array = Array.prototype.slice.call( array, 0 );
@@ -4765,7 +4857,7 @@ var makeArray = function( array, results ) {
results.push.apply( results, array );
return results;
}
-
+
return array;
};
@@ -4997,7 +5089,7 @@ if ( document.querySelectorAll ) {
if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
return;
}
-
+
Sizzle = function( query, context, extra, seed ) {
context = context || document;
@@ -5006,24 +5098,24 @@ if ( document.querySelectorAll ) {
if ( !seed && !Sizzle.isXML(context) ) {
// See if we find a selector to speed up
var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
-
+
if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
// Speed-up: Sizzle("TAG")
if ( match[1] ) {
return makeArray( context.getElementsByTagName( query ), extra );
-
+
// Speed-up: Sizzle(".CLASS")
} else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
return makeArray( context.getElementsByClassName( match[2] ), extra );
}
}
-
+
if ( context.nodeType === 9 ) {
// Speed-up: Sizzle("body")
// The body element only exists once, optimize finding it
if ( query === "body" && context.body ) {
return makeArray( [ context.body ], extra );
-
+
// Speed-up: Sizzle("#ID")
} else if ( match && match[3] ) {
var elem = context.getElementById( match[3] );
@@ -5036,12 +5128,12 @@ if ( document.querySelectorAll ) {
if ( elem.id === match[3] ) {
return makeArray( [ elem ], extra );
}
-
+
} else {
return makeArray( [], extra );
}
}
-
+
try {
return makeArray( context.querySelectorAll(query), extra );
} catch(qsaError) {}
@@ -5079,7 +5171,7 @@ if ( document.querySelectorAll ) {
}
}
}
-
+
return oldSizzle(query, context, extra, seed);
};
@@ -5106,7 +5198,7 @@ if ( document.querySelectorAll ) {
// This should fail with an exception
// Gecko does not error, returns false instead
matches.call( document.documentElement, "[test!='']:sizzle" );
-
+
} catch( pseudoError ) {
pseudoWorks = true;
}
@@ -5116,7 +5208,7 @@ if ( document.querySelectorAll ) {
expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
if ( !Sizzle.isXML( node ) ) {
- try {
+ try {
if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
var ret = matches.call( node, expr );
@@ -5153,7 +5245,7 @@ if ( document.querySelectorAll ) {
if ( div.getElementsByClassName("e").length === 1 ) {
return;
}
-
+
Expr.order.splice(1, 0, "CLASS");
Expr.find.CLASS = function( match, context, isXML ) {
if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
@@ -5204,7 +5296,7 @@ function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
if ( elem ) {
var match = false;
-
+
elem = elem[dir];
while ( elem ) {
@@ -5257,7 +5349,7 @@ if ( document.documentElement.contains ) {
Sizzle.isXML = function( elem ) {
// documentElement is verified for cases where it doesn't yet exist
- // (such as loading iframes in IE - #4833)
+ // (such as loading iframes in IE - #4833)
var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
return documentElement ? documentElement.nodeName !== "HTML" : false;
@@ -5307,7 +5399,7 @@ var runtil = /Until$/,
rmultiselector = /,/,
isSimple = /^.[^:#\[\.,]*$/,
slice = Array.prototype.slice,
- POS = jQuery.expr.match.POS,
+ POS = jQuery.expr.match.globalPOS,
// methods guaranteed to produce a unique set when starting from a unique set
guaranteedUnique = {
children: true,
@@ -5374,11 +5466,11 @@ jQuery.fn.extend({
},
is: function( selector ) {
- return !!selector && (
+ return !!selector && (
typeof selector === "string" ?
// If this is a positional selector, check membership in the returned set
// so $("p:first").is("p:last") won't return true for a doc with two "p".
- POS.test( selector ) ?
+ POS.test( selector ) ?
jQuery( selector, this.context ).index( this[0] ) >= 0 :
jQuery.filter( selector, this ).length > 0 :
this.filter( selector ).length > 0 );
@@ -5386,7 +5478,7 @@ jQuery.fn.extend({
closest: function( selectors, context ) {
var ret = [], i, l, cur = this[0];
-
+
// Array (deprecated as of jQuery 1.7)
if ( jQuery.isArray( selectors ) ) {
var level = 1;
@@ -5505,7 +5597,7 @@ jQuery.each({
return jQuery.dir( elem, "previousSibling", until );
},
siblings: function( elem ) {
- return jQuery.sibling( elem.parentNode.firstChild, elem );
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
},
children: function( elem ) {
return jQuery.sibling( elem.firstChild );
@@ -5639,7 +5731,7 @@ function createSafeFragment( document ) {
return safeFrag;
}
-var nodeNames = "abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|" +
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
rleadingWhitespace = /^\s+/,
@@ -5649,7 +5741,7 @@ var nodeNames = "abbr|article|aside|audio|canvas|datalist|details|figcaption|fig
rhtml = /<|?\w+;/,
rnoInnerhtml = /<(?:script|style)/i,
rnocache = /<(?:script|object|embed|option|style)/i,
- rnoshimcache = new RegExp("<(?:" + nodeNames + ")", "i"),
+ rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
// checked="checked" or checked
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
rscriptType = /\/(java|ecma)script/i,
@@ -5676,20 +5768,12 @@ if ( !jQuery.support.htmlSerialize ) {
}
jQuery.fn.extend({
- text: function( text ) {
- if ( jQuery.isFunction(text) ) {
- return this.each(function(i) {
- var self = jQuery( this );
-
- self.text( text.call(this, i, self.text()) );
- });
- }
-
- if ( typeof text !== "object" && text !== undefined ) {
- return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
- }
-
- return jQuery.text( this );
+ text: function( value ) {
+ return jQuery.access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+ }, null, value, arguments.length );
},
wrapAll: function( html ) {
@@ -5841,44 +5925,44 @@ jQuery.fn.extend({
},
html: function( value ) {
- if ( value === undefined ) {
- return this[0] && this[0].nodeType === 1 ?
- this[0].innerHTML.replace(rinlinejQuery, "") :
- null;
+ return jQuery.access( this, function( value ) {
+ var elem = this[0] || {},
+ i = 0,
+ l = this.length;
- // See if we can take a shortcut and just use innerHTML
- } else if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
- (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
- !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
-
- value = value.replace(rxhtmlTag, "<$1>$2>");
-
- try {
- for ( var i = 0, l = this.length; i < l; i++ ) {
- // Remove element nodes and prevent memory leaks
- if ( this[i].nodeType === 1 ) {
- jQuery.cleanData( this[i].getElementsByTagName("*") );
- this[i].innerHTML = value;
- }
- }
-
- // If using innerHTML throws an exception, use the fallback method
- } catch(e) {
- this.empty().append( value );
+ if ( value === undefined ) {
+ return elem.nodeType === 1 ?
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
+ null;
}
- } else if ( jQuery.isFunction( value ) ) {
- this.each(function(i){
- var self = jQuery( this );
- self.html( value.call(this, i, self.html()) );
- });
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+ !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
- } else {
- this.empty().append( value );
- }
+ value = value.replace( rxhtmlTag, "<$1>$2>" );
- return this;
+ try {
+ for (; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ elem = this[i] || {};
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName( "*" ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch(e) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
},
replaceWith: function( value ) {
@@ -5981,7 +6065,23 @@ jQuery.fn.extend({
}
if ( scripts.length ) {
- jQuery.each( scripts, evalScript );
+ jQuery.each( scripts, function( i, elem ) {
+ if ( elem.src ) {
+ jQuery.ajax({
+ type: "GET",
+ global: false,
+ url: elem.src,
+ async: false,
+ dataType: "script"
+ });
+ } else {
+ jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+ });
}
}
@@ -6013,7 +6113,7 @@ function cloneCopyEvent( src, dest ) {
for ( type in events ) {
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
- jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
+ jQuery.event.add( dest, type, events[ type ][ i ] );
}
}
}
@@ -6075,11 +6175,20 @@ function cloneFixAttributes( src, dest ) {
// cloning other types of input fields
} else if ( nodeName === "input" || nodeName === "textarea" ) {
dest.defaultValue = src.defaultValue;
+
+ // IE blanks contents when cloning scripts
+ } else if ( nodeName === "script" && dest.text !== src.text ) {
+ dest.text = src.text;
}
// Event data gets referenced instead of copied if the expando
// gets copied too
dest.removeAttribute( jQuery.expando );
+
+ // Clear flags for bubbling special change/submit events, they must
+ // be reattached when the newly cloned events are first activated
+ dest.removeAttribute( "_submit_attached" );
+ dest.removeAttribute( "_change_attached" );
}
jQuery.buildFragment = function( args, nodes, scripts ) {
@@ -6204,7 +6313,7 @@ jQuery.extend({
destElements,
i,
// IE<=8 does not properly clone detached, unknown element nodes
- clone = jQuery.support.html5Clone || !rnoshimcache.test( "<" + elem.nodeName ) ?
+ clone = jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ?
elem.cloneNode( true ) :
shimCloneNode( elem );
@@ -6254,7 +6363,8 @@ jQuery.extend({
},
clean: function( elems, context, fragment, scripts ) {
- var checkScriptType;
+ var checkScriptType, script, j,
+ ret = [];
context = context || document;
@@ -6263,8 +6373,6 @@ jQuery.extend({
context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
}
- var ret = [], j;
-
for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
if ( typeof elem === "number" ) {
elem += "";
@@ -6286,7 +6394,9 @@ jQuery.extend({
var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),
wrap = wrapMap[ tag ] || wrapMap._default,
depth = wrap[0],
- div = context.createElement("div");
+ div = context.createElement("div"),
+ safeChildNodes = safeFragment.childNodes,
+ remove;
// Append wrapper element to unknown element safe doc fragment
if ( context === document ) {
@@ -6331,6 +6441,21 @@ jQuery.extend({
}
elem = div.childNodes;
+
+ // Clear elements from DocumentFragment (safeFragment or otherwise)
+ // to avoid hoarding elements. Fixes #11356
+ if ( div ) {
+ div.parentNode.removeChild( div );
+
+ // Guard against -1 index exceptions in FF3.6
+ if ( safeChildNodes.length > 0 ) {
+ remove = safeChildNodes[ safeChildNodes.length - 1 ];
+
+ if ( remove && remove.parentNode ) {
+ remove.parentNode.removeChild( remove );
+ }
+ }
+ }
}
}
@@ -6359,16 +6484,17 @@ jQuery.extend({
return !elem.type || rscriptType.test( elem.type );
};
for ( i = 0; ret[i]; i++ ) {
- if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
- scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
+ script = ret[i];
+ if ( scripts && jQuery.nodeName( script, "script" ) && (!script.type || rscriptType.test( script.type )) ) {
+ scripts.push( script.parentNode ? script.parentNode.removeChild( script ) : script );
} else {
- if ( ret[i].nodeType === 1 ) {
- var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType );
+ if ( script.nodeType === 1 ) {
+ var jsTags = jQuery.grep( script.getElementsByTagName( "script" ), checkScriptType );
ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
}
- fragment.appendChild( ret[i] );
+ fragment.appendChild( script );
}
}
}
@@ -6422,22 +6548,6 @@ jQuery.extend({
}
});
-function evalScript( i, elem ) {
- if ( elem.src ) {
- jQuery.ajax({
- url: elem.src,
- async: false,
- dataType: "script"
- });
- } else {
- jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
- }
-
- if ( elem.parentNode ) {
- elem.parentNode.removeChild( elem );
- }
-}
-
@@ -6445,29 +6555,27 @@ var ralpha = /alpha\([^)]*\)/i,
ropacity = /opacity=([^)]*)/,
// fixed for IE9, see #8346
rupper = /([A-Z]|^ms)/g,
- rnumpx = /^-?\d+(?:px)?$/i,
- rnum = /^-?\d/,
+ rnum = /^[\-+]?(?:\d*\.)?\d+$/i,
+ rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,
rrelNum = /^([\-+])=([\-+.\de]+)/,
+ rmargin = /^margin/,
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
- cssWidth = [ "Left", "Right" ],
- cssHeight = [ "Top", "Bottom" ],
+
+ // order is important!
+ cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+
curCSS,
getComputedStyle,
currentStyle;
jQuery.fn.css = function( name, value ) {
- // Setting 'undefined' is a no-op
- if ( arguments.length === 2 && value === undefined ) {
- return this;
- }
-
- return jQuery.access( this, name, value, true, function( elem, name, value ) {
+ return jQuery.access( this, function( elem, name, value ) {
return value !== undefined ?
jQuery.style( elem, name, value ) :
jQuery.css( elem, name );
- });
+ }, name, value, arguments.length > 1 );
};
jQuery.extend({
@@ -6478,7 +6586,7 @@ jQuery.extend({
get: function( elem, computed ) {
if ( computed ) {
// We should always get a number back from opacity
- var ret = curCSS( elem, "opacity", "opacity" );
+ var ret = curCSS( elem, "opacity" );
return ret === "" ? "1" : ret;
} else {
@@ -6586,56 +6694,174 @@ jQuery.extend({
// A method for quickly swapping in/out CSS properties to get correct calculations
swap: function( elem, options, callback ) {
- var old = {};
+ var old = {},
+ ret, name;
// Remember the old values, and insert the new ones
- for ( var name in options ) {
+ for ( name in options ) {
old[ name ] = elem.style[ name ];
elem.style[ name ] = options[ name ];
}
- callback.call( elem );
+ ret = callback.call( elem );
// Revert the old values
for ( name in options ) {
elem.style[ name ] = old[ name ];
}
+
+ return ret;
}
});
-// DEPRECATED, Use jQuery.css() instead
+// DEPRECATED in 1.3, Use jQuery.css() instead
jQuery.curCSS = jQuery.css;
-jQuery.each(["height", "width"], function( i, name ) {
+if ( document.defaultView && document.defaultView.getComputedStyle ) {
+ getComputedStyle = function( elem, name ) {
+ var ret, defaultView, computedStyle, width,
+ style = elem.style;
+
+ name = name.replace( rupper, "-$1" ).toLowerCase();
+
+ if ( (defaultView = elem.ownerDocument.defaultView) &&
+ (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
+
+ ret = computedStyle.getPropertyValue( name );
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // WebKit uses "computed value (percentage if specified)" instead of "used value" for margins
+ // which is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( !jQuery.support.pixelMargin && computedStyle && rmargin.test( name ) && rnumnonpx.test( ret ) ) {
+ width = style.width;
+ style.width = ret;
+ ret = computedStyle.width;
+ style.width = width;
+ }
+
+ return ret;
+ };
+}
+
+if ( document.documentElement.currentStyle ) {
+ currentStyle = function( elem, name ) {
+ var left, rsLeft, uncomputed,
+ ret = elem.currentStyle && elem.currentStyle[ name ],
+ style = elem.style;
+
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret == null && style && (uncomputed = style[ name ]) ) {
+ ret = uncomputed;
+ }
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ if ( rnumnonpx.test( ret ) ) {
+
+ // Remember the original values
+ left = style.left;
+ rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : ret;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = rsLeft;
+ }
+ }
+
+ return ret === "" ? "auto" : ret;
+ };
+}
+
+curCSS = getComputedStyle || currentStyle;
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property
+ var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ i = name === "width" ? 1 : 0,
+ len = 4;
+
+ if ( val > 0 ) {
+ if ( extra !== "border" ) {
+ for ( ; i < len; i += 2 ) {
+ if ( !extra ) {
+ val -= parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
+ }
+ if ( extra === "margin" ) {
+ val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ] ) ) || 0;
+ } else {
+ val -= parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+ }
+ }
+ }
+
+ return val + "px";
+ }
+
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+
+ // Add padding, border, margin
+ if ( extra ) {
+ for ( ; i < len; i += 2 ) {
+ val += parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
+ if ( extra !== "padding" ) {
+ val += parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+ }
+ if ( extra === "margin" ) {
+ val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ]) ) || 0;
+ }
+ }
+ }
+
+ return val + "px";
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
jQuery.cssHooks[ name ] = {
get: function( elem, computed, extra ) {
- var val;
-
if ( computed ) {
if ( elem.offsetWidth !== 0 ) {
- return getWH( elem, name, extra );
+ return getWidthOrHeight( elem, name, extra );
} else {
- jQuery.swap( elem, cssShow, function() {
- val = getWH( elem, name, extra );
+ return jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
});
}
-
- return val;
}
},
set: function( elem, value ) {
- if ( rnumpx.test( value ) ) {
- // ignore negative width and height values #1599
- value = parseFloat( value );
-
- if ( value >= 0 ) {
- return value + "px";
- }
-
- } else {
- return value;
- }
+ return rnum.test( value ) ?
+ value + "px" :
+ value;
}
};
});
@@ -6689,130 +6915,18 @@ jQuery(function() {
get: function( elem, computed ) {
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
// Work around by temporarily setting element display to inline-block
- var ret;
- jQuery.swap( elem, { "display": "inline-block" }, function() {
+ return jQuery.swap( elem, { "display": "inline-block" }, function() {
if ( computed ) {
- ret = curCSS( elem, "margin-right", "marginRight" );
+ return curCSS( elem, "margin-right" );
} else {
- ret = elem.style.marginRight;
+ return elem.style.marginRight;
}
});
- return ret;
}
};
}
});
-if ( document.defaultView && document.defaultView.getComputedStyle ) {
- getComputedStyle = function( elem, name ) {
- var ret, defaultView, computedStyle;
-
- name = name.replace( rupper, "-$1" ).toLowerCase();
-
- if ( (defaultView = elem.ownerDocument.defaultView) &&
- (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
- ret = computedStyle.getPropertyValue( name );
- if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
- ret = jQuery.style( elem, name );
- }
- }
-
- return ret;
- };
-}
-
-if ( document.documentElement.currentStyle ) {
- currentStyle = function( elem, name ) {
- var left, rsLeft, uncomputed,
- ret = elem.currentStyle && elem.currentStyle[ name ],
- style = elem.style;
-
- // Avoid setting ret to empty string here
- // so we don't default to auto
- if ( ret === null && style && (uncomputed = style[ name ]) ) {
- ret = uncomputed;
- }
-
- // From the awesome hack by Dean Edwards
- // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
-
- // If we're not dealing with a regular pixel number
- // but a number that has a weird ending, we need to convert it to pixels
- if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
-
- // Remember the original values
- left = style.left;
- rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
-
- // Put in the new values to get a computed value out
- if ( rsLeft ) {
- elem.runtimeStyle.left = elem.currentStyle.left;
- }
- style.left = name === "fontSize" ? "1em" : ( ret || 0 );
- ret = style.pixelLeft + "px";
-
- // Revert the changed values
- style.left = left;
- if ( rsLeft ) {
- elem.runtimeStyle.left = rsLeft;
- }
- }
-
- return ret === "" ? "auto" : ret;
- };
-}
-
-curCSS = getComputedStyle || currentStyle;
-
-function getWH( elem, name, extra ) {
-
- // Start with offset property
- var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
- which = name === "width" ? cssWidth : cssHeight,
- i = 0,
- len = which.length;
-
- if ( val > 0 ) {
- if ( extra !== "border" ) {
- for ( ; i < len; i++ ) {
- if ( !extra ) {
- val -= parseFloat( jQuery.css( elem, "padding" + which[ i ] ) ) || 0;
- }
- if ( extra === "margin" ) {
- val += parseFloat( jQuery.css( elem, extra + which[ i ] ) ) || 0;
- } else {
- val -= parseFloat( jQuery.css( elem, "border" + which[ i ] + "Width" ) ) || 0;
- }
- }
- }
-
- return val + "px";
- }
-
- // Fall back to computed then uncomputed css if necessary
- val = curCSS( elem, name, name );
- if ( val < 0 || val == null ) {
- val = elem.style[ name ] || 0;
- }
- // Normalize "", auto, and prepare for extra
- val = parseFloat( val ) || 0;
-
- // Add padding, border, margin
- if ( extra ) {
- for ( ; i < len; i++ ) {
- val += parseFloat( jQuery.css( elem, "padding" + which[ i ] ) ) || 0;
- if ( extra !== "padding" ) {
- val += parseFloat( jQuery.css( elem, "border" + which[ i ] + "Width" ) ) || 0;
- }
- if ( extra === "margin" ) {
- val += parseFloat( jQuery.css( elem, extra + which[ i ] ) ) || 0;
- }
- }
- }
-
- return val + "px";
-}
-
if ( jQuery.expr && jQuery.expr.filters ) {
jQuery.expr.filters.hidden = function( elem ) {
var width = elem.offsetWidth,
@@ -6826,6 +6940,31 @@ if ( jQuery.expr && jQuery.expr.filters ) {
};
}
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i,
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ],
+ expanded = {};
+
+ for ( i = 0; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+});
+
@@ -7144,7 +7283,7 @@ jQuery.extend({
isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
global: true,
type: "GET",
- contentType: "application/x-www-form-urlencoded",
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
processData: true,
async: true,
/*
@@ -7470,7 +7609,7 @@ jQuery.extend({
// Apply prefilters
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
- // If request was aborted inside a prefiler, stop there
+ // If request was aborted inside a prefilter, stop there
if ( state === 2 ) {
return false;
}
@@ -7643,11 +7782,11 @@ function buildParams( prefix, obj, traditional, add ) {
// a server error. Possible fixes are to modify rack's
// deserialization algorithm or to provide an option or flag
// to force array serialization to be shallow.
- buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add );
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
}
});
- } else if ( !traditional && obj != null && typeof obj === "object" ) {
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
// Serialize object item.
for ( var name in obj ) {
buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
@@ -7843,8 +7982,7 @@ jQuery.ajaxSetup({
// Detect, normalize options and install callbacks for jsonp requests
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
- var inspectData = s.contentType === "application/x-www-form-urlencoded" &&
- ( typeof s.data === "string" );
+ var inspectData = ( typeof s.data === "string" ) && /^application\/x\-www\-form\-urlencoded/.test( s.contentType );
if ( s.dataTypes[ 0 ] === "jsonp" ||
s.jsonp !== false && ( jsre.test( s.url ) ||
@@ -8145,7 +8283,13 @@ if ( jQuery.support.ajax ) {
if ( xml && xml.documentElement /* #4958 */ ) {
responses.xml = xml;
}
- responses.text = xhr.responseText;
+
+ // When requesting binary data, IE6-9 will throw an exception
+ // on any attempt to access responseText (#11426)
+ try {
+ responses.text = xhr.responseText;
+ } catch( _ ) {
+ }
// Firefox throws an exception when accessing
// statusText for faulty cross-domain requests
@@ -8253,7 +8397,8 @@ jQuery.fn.extend({
// Set elements which have been overridden with display: none
// in a stylesheet to whatever the default browser style is
// for such an element
- if ( display === "" && jQuery.css(elem, "display") === "none" ) {
+ if ( (display === "" && jQuery.css(elem, "display") === "none") ||
+ !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
}
}
@@ -8357,24 +8502,37 @@ jQuery.fn.extend({
var opt = jQuery.extend( {}, optall ),
isElement = this.nodeType === 1,
hidden = isElement && jQuery(this).is(":hidden"),
- name, val, p, e,
+ name, val, p, e, hooks, replace,
parts, start, end, unit,
method;
// will store per property easing and be used to determine when an animation is complete
opt.animatedProperties = {};
+ // first pass over propertys to expand / normalize
for ( p in prop ) {
-
- // property name normalization
name = jQuery.camelCase( p );
if ( p !== name ) {
prop[ name ] = prop[ p ];
delete prop[ p ];
}
- val = prop[ name ];
+ if ( ( hooks = jQuery.cssHooks[ name ] ) && "expand" in hooks ) {
+ replace = hooks.expand( prop[ name ] );
+ delete prop[ name ];
+ // not quite $.extend, this wont overwrite keys already present.
+ // also - reusing 'p' from above because we have the correct "name"
+ for ( p in replace ) {
+ if ( ! ( p in prop ) ) {
+ prop[ p ] = replace[ p ];
+ }
+ }
+ }
+ }
+
+ for ( name in prop ) {
+ val = prop[ name ];
// easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
if ( jQuery.isArray( val ) ) {
opt.animatedProperties[ name ] = val[ 1 ];
@@ -8601,11 +8759,11 @@ jQuery.extend({
},
easing: {
- linear: function( p, n, firstNum, diff ) {
- return firstNum + diff * p;
+ linear: function( p ) {
+ return p;
},
- swing: function( p, n, firstNum, diff ) {
- return ( ( -Math.cos( p*Math.PI ) / 2 ) + 0.5 ) * diff + firstNum;
+ swing: function( p ) {
+ return ( -Math.cos( p*Math.PI ) / 2 ) + 0.5;
}
},
@@ -8663,8 +8821,12 @@ jQuery.fx.prototype = {
t.queue = this.options.queue;
t.elem = this.elem;
t.saveState = function() {
- if ( self.options.hide && jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
- jQuery._data( self.elem, "fxshow" + self.prop, self.start );
+ if ( jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
+ if ( self.options.hide ) {
+ jQuery._data( self.elem, "fxshow" + self.prop, self.start );
+ } else if ( self.options.show ) {
+ jQuery._data( self.elem, "fxshow" + self.prop, self.end );
+ }
}
};
@@ -8831,12 +8993,14 @@ jQuery.extend( jQuery.fx, {
}
});
-// Adds width/height step functions
-// Do not set anything below 0
-jQuery.each([ "width", "height" ], function( i, prop ) {
- jQuery.fx.step[ prop ] = function( fx ) {
- jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );
- };
+// Ensure props that can't be negative don't go there on undershoot easing
+jQuery.each( fxAttrs.concat.apply( [], fxAttrs ), function( i, prop ) {
+ // exclude marginTop, marginLeft, marginBottom and marginRight from this list
+ if ( prop.indexOf( "margin" ) ) {
+ jQuery.fx.step[ prop ] = function( fx ) {
+ jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );
+ };
+ }
});
if ( jQuery.expr && jQuery.expr.filters ) {
@@ -8873,7 +9037,7 @@ function defaultDisplay( nodeName ) {
// document to it; WebKit & Firefox won't allow reusing the iframe document.
if ( !iframeDoc || !iframe.createElement ) {
iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
- iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "" : "" ) + "" );
+ iframeDoc.write( ( jQuery.support.boxModel ? "" : "" ) + "" );
iframeDoc.close();
}
@@ -8895,41 +9059,23 @@ function defaultDisplay( nodeName ) {
-var rtable = /^t(?:able|d|h)$/i,
+var getOffset,
+ rtable = /^t(?:able|d|h)$/i,
rroot = /^(?:body|html)$/i;
if ( "getBoundingClientRect" in document.documentElement ) {
- jQuery.fn.offset = function( options ) {
- var elem = this[0], box;
-
- if ( options ) {
- return this.each(function( i ) {
- jQuery.offset.setOffset( this, options, i );
- });
- }
-
- if ( !elem || !elem.ownerDocument ) {
- return null;
- }
-
- if ( elem === elem.ownerDocument.body ) {
- return jQuery.offset.bodyOffset( elem );
- }
-
+ getOffset = function( elem, doc, docElem, box ) {
try {
box = elem.getBoundingClientRect();
} catch(e) {}
- var doc = elem.ownerDocument,
- docElem = doc.documentElement;
-
// Make sure we're not dealing with a disconnected DOM node
if ( !box || !jQuery.contains( docElem, elem ) ) {
return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
}
var body = doc.body,
- win = getWindow(doc),
+ win = getWindow( doc ),
clientTop = docElem.clientTop || body.clientTop || 0,
clientLeft = docElem.clientLeft || body.clientLeft || 0,
scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop,
@@ -8941,28 +9087,10 @@ if ( "getBoundingClientRect" in document.documentElement ) {
};
} else {
- jQuery.fn.offset = function( options ) {
- var elem = this[0];
-
- if ( options ) {
- return this.each(function( i ) {
- jQuery.offset.setOffset( this, options, i );
- });
- }
-
- if ( !elem || !elem.ownerDocument ) {
- return null;
- }
-
- if ( elem === elem.ownerDocument.body ) {
- return jQuery.offset.bodyOffset( elem );
- }
-
+ getOffset = function( elem, doc, docElem ) {
var computedStyle,
offsetParent = elem.offsetParent,
prevOffsetParent = elem,
- doc = elem.ownerDocument,
- docElem = doc.documentElement,
body = doc.body,
defaultView = doc.defaultView,
prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
@@ -9013,6 +9141,29 @@ if ( "getBoundingClientRect" in document.documentElement ) {
};
}
+jQuery.fn.offset = function( options ) {
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ var elem = this[0],
+ doc = elem && elem.ownerDocument;
+
+ if ( !doc ) {
+ return null;
+ }
+
+ if ( elem === doc.body ) {
+ return jQuery.offset.bodyOffset( elem );
+ }
+
+ return getOffset( elem, doc, doc.documentElement );
+};
+
jQuery.offset = {
bodyOffset: function( body ) {
@@ -9118,42 +9269,30 @@ jQuery.fn.extend({
// Create scrollLeft and scrollTop methods
-jQuery.each( ["Left", "Top"], function( i, name ) {
- var method = "scroll" + name;
+jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
+ var top = /Y/.test( prop );
jQuery.fn[ method ] = function( val ) {
- var elem, win;
+ return jQuery.access( this, function( elem, method, val ) {
+ var win = getWindow( elem );
- if ( val === undefined ) {
- elem = this[ 0 ];
-
- if ( !elem ) {
- return null;
+ if ( val === undefined ) {
+ return win ? (prop in win) ? win[ prop ] :
+ jQuery.support.boxModel && win.document.documentElement[ method ] ||
+ win.document.body[ method ] :
+ elem[ method ];
}
- win = getWindow( elem );
-
- // Return the scroll offset
- return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
- jQuery.support.boxModel && win.document.documentElement[ method ] ||
- win.document.body[ method ] :
- elem[ method ];
- }
-
- // Set the scroll offset
- return this.each(function() {
- win = getWindow( this );
-
if ( win ) {
win.scrollTo(
- !i ? val : jQuery( win ).scrollLeft(),
- i ? val : jQuery( win ).scrollTop()
+ !top ? val : jQuery( win ).scrollLeft(),
+ top ? val : jQuery( win ).scrollTop()
);
} else {
- this[ method ] = val;
+ elem[ method ] = val;
}
- });
+ }, method, val, arguments.length, null );
};
});
@@ -9169,9 +9308,10 @@ function getWindow( elem ) {
// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
-jQuery.each([ "Height", "Width" ], function( i, name ) {
-
- var type = name.toLowerCase();
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ var clientProp = "client" + name,
+ scrollProp = "scroll" + name,
+ offsetProp = "offset" + name;
// innerHeight and innerWidth
jQuery.fn[ "inner" + name ] = function() {
@@ -9193,50 +9333,48 @@ jQuery.each([ "Height", "Width" ], function( i, name ) {
null;
};
- jQuery.fn[ type ] = function( size ) {
- // Get window width or height
- var elem = this[0];
- if ( !elem ) {
- return size == null ? null : this;
- }
+ jQuery.fn[ type ] = function( value ) {
+ return jQuery.access( this, function( elem, type, value ) {
+ var doc, docElemProp, orig, ret;
- if ( jQuery.isFunction( size ) ) {
- return this.each(function( i ) {
- var self = jQuery( this );
- self[ type ]( size.call( this, i, self[ type ]() ) );
- });
- }
+ if ( jQuery.isWindow( elem ) ) {
+ // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
+ doc = elem.document;
+ docElemProp = doc.documentElement[ clientProp ];
+ return jQuery.support.boxModel && docElemProp ||
+ doc.body && doc.body[ clientProp ] || docElemProp;
+ }
- if ( jQuery.isWindow( elem ) ) {
- // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
- // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
- var docElemProp = elem.document.documentElement[ "client" + name ],
- body = elem.document.body;
- return elem.document.compatMode === "CSS1Compat" && docElemProp ||
- body && body[ "client" + name ] || docElemProp;
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+ doc = elem.documentElement;
- // Get document width or height
- } else if ( elem.nodeType === 9 ) {
- // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
- return Math.max(
- elem.documentElement["client" + name],
- elem.body["scroll" + name], elem.documentElement["scroll" + name],
- elem.body["offset" + name], elem.documentElement["offset" + name]
- );
+ // when a window > document, IE6 reports a offset[Width/Height] > client[Width/Height]
+ // so we can't use max, as it'll choose the incorrect offset[Width/Height]
+ // instead we use the correct client[Width/Height]
+ // support:IE6
+ if ( doc[ clientProp ] >= doc[ scrollProp ] ) {
+ return doc[ clientProp ];
+ }
- // Get or set width or height on the element
- } else if ( size === undefined ) {
- var orig = jQuery.css( elem, type ),
+ return Math.max(
+ elem.body[ scrollProp ], doc[ scrollProp ],
+ elem.body[ offsetProp ], doc[ offsetProp ]
+ );
+ }
+
+ // Get width or height on the element
+ if ( value === undefined ) {
+ orig = jQuery.css( elem, type );
ret = parseFloat( orig );
+ return jQuery.isNumeric( ret ) ? ret : orig;
+ }
- return jQuery.isNumeric( ret ) ? ret : orig;
-
- // Set the width or height on the element (default to pixels if value is unitless)
- } else {
- return this.css( type, typeof size === "string" ? size : size + "px" );
- }
+ // Set the width or height on the element
+ jQuery( elem ).css( type, value );
+ }, type, value, arguments.length, null );
};
-
});
diff --git a/sites/all/modules/contrib/js/jquery_update/replace/jquery/1.7/jquery.min.js b/sites/all/modules/contrib/js/jquery_update/replace/jquery/1.7/jquery.min.js
index 198b3ff0..cf226874 100644
--- a/sites/all/modules/contrib/js/jquery_update/replace/jquery/1.7/jquery.min.js
+++ b/sites/all/modules/contrib/js/jquery_update/replace/jquery/1.7/jquery.min.js
@@ -1,4 +1,4 @@
-/*! jQuery v1.7.1 jquery.com | jquery.org/license */
-(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, duration }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val,
- tooltip: "[no tooltip available]"
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
- }
-
- moduleFilterHtml += "";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = document.getElementById( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = document.getElementById( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigCheckboxesContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( 'span' );
- moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } );
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-addEvent( window, "load", QUnit.load );
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will surpress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not surpressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds. ",
- "",
- passed,
- " assertions of ",
- config.stats.all,
- " passed, ",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case '\'':
- return ''';
- case '"':
- return '"';
- case '<':
- return '<';
- case '>':
- return '>';
- case '&':
- return '&';
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[ prop ] = b[ prop ];
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- // Standards-based browsers
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- // IE
- } else {
- elem.attachEvent( "on" + type, fn );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not neccecarily
- elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set );
-}
-
-function id( name ) {
- return !!( typeof document !== "undefined" && document && document.getElementById ) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- loop = true;// dont rewalk array
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object": function( b, a ) {
- var i, j, loop,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
- // track reference to avoid circular references
- parents.push( a );
-
- for ( i in a ) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- if ( parents[j] === a[i] ) {
- // don't go down the same path twice
- loop = true;
- }
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv( a[i], b[i] ) ) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? " " : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this._depth_ + (extra||0) ).join(chr);
- },
- up: function( a ) {
- this._depth_ += a || 1;
- },
- down: function( a ) {
- this._depth_ -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// for CommonJS enviroments, export everything
-if ( typeof exports !== "undefined" ) {
- extend( exports, QUnit );
-}
-
-// get at whatever the global object is, like window in browsers
-}( (function() {return this;}.call()) ));
diff --git a/sites/all/modules/contrib/localisation/entity_translation/CHANGELOG.txt b/sites/all/modules/contrib/localisation/entity_translation/CHANGELOG.txt
index 54cddea7..35bc9398 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/CHANGELOG.txt
+++ b/sites/all/modules/contrib/localisation/entity_translation/CHANGELOG.txt
@@ -3,6 +3,36 @@ Entity Translation 7.x-1.x, xxxx-xx-xx
--------------------------------------
+Entity Translation 7.x-1.0-beta5, 2016-05-08
+--------------------------------------------
+#929402 by das-peter, bastnic, kristiaanvandeneynde, brockfanning, greenjuls,
+ make77, steinmb: Added support for migrate module.
+#1291388 by Jax, poiu, plach: Added support for multilingual core search.
+#2339315 by loopduplicate, gnucifer, plopesc, james.williams: Fixed Source
+ language prepopulated values should be also included in $form_state['field'].
+#2648062 by brunoric, cebasqueira, lucasr, mmchristoph: Fixed Fatal error: Call
+ to a member function getFormLanguage() on a non-object.
+#S156840 by HelenaEksler, plach: Fixed XSS vulnerability in the translation
+ form page title.
+#2444203 by Leksat, badrange, attiks: Show fallback information on the translation
+ overview.
+#2458393 by catch, plach, douggreen: Fixed unindexed query in
+ EntityTranslationDefaultHandler::loadMultiple().
+#2462909 by GeduR: Misspelling translation exists help in views handler
+ definition.
+#2166157 by rsmylski, ciss: entity translation handler id for new entities not
+ unique enough - can cause infinite/circular child reference.
+#2452279 by GeduR: Duplicated variable $language in
+ entity_translation_edit_access().
+#2423661 by marcoscano: Module api documentation has wrong example ("path sets"
+ instead of "path schemes").
+#2305547 by das-peter: Fixed undefined index name.
+#1989084 by jsacksick, candelas: Fixed and validation.
+#2203801 by idflood: Impossible to update taxonomy term after enabling
+ i18n_taxonomy.
+#2415189 by catch: Translation deletion bypasses entity saving.
+
+
Entity Translation 7.x-1.0-beta4, 2015-01-23
--------------------------------------------
#2396103 by plach: Fixed [DATA LOSS] Translations deleted.
diff --git a/sites/all/modules/contrib/localisation/entity_translation/entity_translation.admin.inc b/sites/all/modules/contrib/localisation/entity_translation/entity_translation.admin.inc
index 380560d2..3bdf410a 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/entity_translation.admin.inc
+++ b/sites/all/modules/contrib/localisation/entity_translation/entity_translation.admin.inc
@@ -18,6 +18,18 @@ function entity_translation_admin_form($form, $form_state) {
'#default_value' => variable_get('locale_field_language_fallback', TRUE),
);
+ $form['entity_translation_show_fallback_on_overview_pages'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Show fallback statuses on overview pages'),
+ '#description' => t('Enable to the show fallback information on the entity overview pages.'),
+ '#default_value' => variable_get('entity_translation_show_fallback_on_overview_pages', FALSE),
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="locale_field_language_fallback"]' => array('checked' => TRUE),
+ ),
+ ),
+ );
+
$form['entity_translation_shared_labels'] = array(
'#type' => 'checkbox',
'#title' => t('Display shared labels'),
@@ -219,8 +231,7 @@ function entity_translation_overview($entity_type, $entity, $callback = NULL) {
// languages.
if ($handler->initOriginalTranslation()) {
// FIXME!
- field_attach_presave($entity_type, $entity);
- field_attach_update($entity_type, $entity);
+ entity_translation_entity_save($entity_type, $entity);
}
$header = array(t('Language'), t('Source language'), t('Translation'), t('Status'), t('Operations'));
@@ -236,6 +247,8 @@ function entity_translation_overview($entity_type, $entity, $callback = NULL) {
$links = EntityTranslationDefaultHandler::languageSwitchLinks($path);
}
+ $show_fallback = variable_get('locale_field_language_fallback', TRUE) && variable_get('entity_translation_show_fallback_on_overview_pages', FALSE);
+
foreach ($languages as $language) {
$classes = array();
$options = array();
@@ -305,6 +318,18 @@ function entity_translation_overview($entity_type, $entity, $callback = NULL) {
$classes[] = $translatable ? '' : 'non-traslatable';
}
$status = t('Not translated');
+ // Show fallback information if required.
+ if ($show_fallback) {
+ $language_fallback_candidates = _entity_translation_language_fallback_get_candidates($language);
+ $fallback_candidates = array_intersect_key(drupal_map_assoc($language_fallback_candidates), $translations->data);
+ $fallback_langcode = reset($fallback_candidates);
+ if ($fallback_langcode !== FALSE) {
+ $status = t('Fallback from @language', array('@language' => $languages[$fallback_langcode]->name));
+ $label = _entity_translation_label($entity_type, $entity, $fallback_langcode);
+ $link = isset($links->links[$langcode]['href']) ? $links->links[$langcode] : array('href' => $path, 'language' => $langcode);
+ $row_title = l($label, $link['href'], $link);
+ }
+ }
}
$rows[] = array(
'data' => array($language_name, $source_name, $row_title, $status, implode(" | ", $options)),
@@ -420,8 +445,7 @@ function entity_translation_delete_confirm_submit($form, &$form_state) {
// Remove the translation entry and the related fields.
$handler->removeTranslation($langcode);
- field_attach_presave($entity_type, $entity);
- field_attach_update($entity_type, $entity);
+ entity_translation_entity_save($entity_type, $entity);
$form_state['redirect'] = $handler->getTranslatePath();
}
@@ -654,8 +678,7 @@ function _entity_translation_update_field($entity_type, $entity, $field_name) {
// otherwise any stored empty field value would be deleted. If this happens
// the range queries would be messed up.
if ($empty < count($entity->{$field_name})) {
- field_attach_presave($entity_type, $entity);
- field_attach_update($entity_type, $entity);
+ entity_translation_entity_save($entity_type, $entity);
}
}
@@ -671,3 +694,36 @@ function entity_translation_translatable_batch_done($success, $results, $operati
drupal_set_message(t("Something went wrong while processing data. Some nodes may appear to have lost fields."));
}
}
+
+/**
+ * Returns language fallback candidates for a certain language.
+ *
+ * @param object $language
+ * Drupal language object.
+ *
+ * @return array
+ * An array of language codes in the fallback order.
+ */
+function _entity_translation_language_fallback_get_candidates($language) {
+ // Save original fallback candidates.
+ $language_fallback_original = drupal_static('language_fallback_get_candidates');
+ // Replace all global languages with the given one. We need this because the
+ // language_fallback_get_candidates() does not take the $language parameter,
+ // however other modules (like language_fallback) may use current language(s)
+ // when they alter the language fallback candidates.
+ $languages_original = array();
+ foreach (language_types() as $language_type) {
+ $languages_original[$language_type] = $GLOBALS[$language_type];
+ $GLOBALS[$language_type] = $language;
+ }
+ // Clear static cache, so that fallback candidates are recalculated.
+ drupal_static_reset('language_fallback_get_candidates');
+ $language_fallback_candidates = language_fallback_get_candidates();
+ // Restore original data.
+ $language_fallback =& drupal_static('language_fallback_get_candidates');
+ $language_fallback = $language_fallback_original;
+ foreach ($languages_original as $language_type => $_language) {
+ $GLOBALS[$language_type] = $_language;
+ }
+ return $language_fallback_candidates;
+}
diff --git a/sites/all/modules/contrib/localisation/entity_translation/entity_translation.api.php b/sites/all/modules/contrib/localisation/entity_translation/entity_translation.api.php
index a336afd5..2eb8262d 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/entity_translation.api.php
+++ b/sites/all/modules/contrib/localisation/entity_translation/entity_translation.api.php
@@ -91,7 +91,7 @@ function hook_entity_info() {
'translation' => array(
'entity_translation' => array(
'class' => 'EntityTranslationCustomEntityHandler',
- 'path sets' => array(
+ 'path schemes' => array(
'default' => array(
'base path' => 'custom_entity_2/%custom_entity',
'path wildcard' => '%custom_entity',
diff --git a/sites/all/modules/contrib/localisation/entity_translation/entity_translation.info b/sites/all/modules/contrib/localisation/entity_translation/entity_translation.info
index c020cc0a..3ad2f868 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/entity_translation.info
+++ b/sites/all/modules/contrib/localisation/entity_translation/entity_translation.info
@@ -11,6 +11,7 @@ files[] = includes/translation.handler.comment.inc
files[] = includes/translation.handler.node.inc
files[] = includes/translation.handler.taxonomy_term.inc
files[] = includes/translation.handler.user.inc
+files[] = includes/translation.migrate.inc
files[] = tests/entity_translation.test
@@ -22,9 +23,9 @@ files[] = views/entity_translation_handler_filter_language.inc
files[] = views/entity_translation_handler_filter_translation_exists.inc
files[] = views/entity_translation_handler_field_field.inc
-; Information added by Drupal.org packaging script on 2015-01-22
-version = "7.x-1.0-beta4"
+; Information added by Drupal.org packaging script on 2016-05-07
+version = "7.x-1.0-beta5"
core = "7.x"
project = "entity_translation"
-datestamp = "1421971088"
+datestamp = "1462661041"
diff --git a/sites/all/modules/contrib/localisation/entity_translation/entity_translation.migrate.inc b/sites/all/modules/contrib/localisation/entity_translation/entity_translation.migrate.inc
new file mode 100644
index 00000000..21ae1ad4
--- /dev/null
+++ b/sites/all/modules/contrib/localisation/entity_translation/entity_translation.migrate.inc
@@ -0,0 +1,17 @@
+ 2,
+ 'destination handlers' => array('MigrateTranslationEntityHandler'),
+ );
+ return $api;
+}
diff --git a/sites/all/modules/contrib/localisation/entity_translation/entity_translation.module b/sites/all/modules/contrib/localisation/entity_translation/entity_translation.module
index 236d4880..947caff6 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/entity_translation.module
+++ b/sites/all/modules/contrib/localisation/entity_translation/entity_translation.module
@@ -567,7 +567,7 @@ function entity_translation_edit_access() {
}
$translations = $handler->getTranslations();
- $langcode = $langcode = entity_translation_get_existing_language($entity_type, $entity, $langcode);
+ $langcode = entity_translation_get_existing_language($entity_type, $entity, $langcode);
// The user must be explicitly allowed to access the original values if
// workflow permissions are enabled.
@@ -1274,10 +1274,14 @@ function entity_translation_field_attach_form($entity_type, $entity, &$form, &$f
function entity_translation_prepare_element($element, &$form_state) {
static $drupal_static_fast;
if (!isset($drupal_static_fast)) {
- $drupal_static_fast['source_forms'] = &drupal_static(__FUNCTION__, array());
+ $drupal_static_fast = &drupal_static(__FUNCTION__, array(
+ 'source_forms' => array(),
+ 'source_form_states' => array(),
+ ));
}
$source_forms = &$drupal_static_fast['source_forms'];
+ $source_form_states = &$drupal_static_fast['source_form_states'];
$form = $form_state['complete form'];
$build_id = $form['#build_id'];
$source = $element['#source'];
@@ -1294,9 +1298,11 @@ function entity_translation_prepare_element($element, &$form_state) {
$source_form_state = $form_state;
field_attach_form($entity_type, $element['#entity'], $source_form, $source_form_state, $source);
$source_forms[$build_id][$source][$entity_type][$id] = &$source_form;
+ $source_form_states[$build_id][$source][$entity_type][$id] = &$source_form_state;
}
$source_form = &$source_forms[$build_id][$source][$entity_type][$id];
+ $source_form_state = $source_form_states[$build_id][$source][$entity_type][$id];
$langcode = $element['#language'];
$field_name = $element['#field_name'];
@@ -1307,12 +1313,42 @@ function entity_translation_prepare_element($element, &$form_state) {
if (isset($source_form[$field_name][$source])) {
$element[$langcode] = $source_form[$field_name][$source];
entity_translation_form_element_language_replace($element, $source, $langcode);
+ entity_translation_form_element_state_replace($element, $source_form[$field_name], $field_name, $source_form_state, $form_state);
unset($element[$element['#previous']]);
}
return $element;
}
+/**
+ * Helper function. Sets the right values in $form_state['field'] when using
+ * source language values as defaults.
+ */
+function entity_translation_form_element_state_replace($element, $source_element, $field_name, $source_form_state, &$form_state) {
+ if (isset($source_element['#language'])) {
+ $source = $source_element['#language'];
+
+ // Iterate through the form structure recursively.
+ foreach (element_children($element) as $key) {
+ if (isset($source_element[$key])) {
+ entity_translation_form_element_state_replace($element[$key], $source_element[$key], $key, $source_form_state, $form_state);
+ }
+ elseif (isset($source_element[$source])) {
+ entity_translation_form_element_state_replace($element[$key], $source_element[$source], $key, $source_form_state, $form_state);
+ }
+ }
+
+ if (isset($source_element[$source]['#field_parents'])) {
+ $source_parents = $source_element[$source]['#field_parents'];
+ $langcode = $element['#language'];
+ $parents = $element[$langcode]['#field_parents'];
+ $source_state = field_form_get_state($source_parents, $field_name, $source, $source_form_state);
+ drupal_alter('entity_translation_source_field_state', $source_state);
+ field_form_set_state($parents, $field_name, $langcode, $form_state, $source_state);
+ }
+ }
+}
+
/**
* Helper function. Recursively replaces the source language with the given one.
*/
@@ -1799,6 +1835,9 @@ function entity_translation_settings($entity_type, $bundle) {
*/
function entity_translation_language($entity_type, $entity) {
$handler = entity_translation_get_handler($entity_type, $entity);
+ if (empty($handler)) {
+ return LANGUAGE_NONE;
+ }
$langcode = $handler->getFormLanguage();
return !empty($langcode) ? $langcode : $handler->getLanguage();
}
@@ -2019,3 +2058,23 @@ function path_entity_translation_delete($entity_type, $entity, $langcode) {
$handler = entity_translation_get_handler($entity_type, $entity);
path_delete(array('source' => $handler->getViewPath(), 'language' => $langcode));
}
+
+/**
+ * Wrapper for entity_save().
+ *
+ * @param $entity_type
+ * The entity type.
+ * @param $entity
+ * The entity object.
+ */
+function entity_translation_entity_save($entity_type, $entity) {
+ // Entity module isn't required, but use it if it's available.
+ if (module_exists('entity')) {
+ entity_save($entity_type, $entity);
+ }
+ // Fall back to field_attach_* functions otherwise.
+ else {
+ field_attach_presave($entity_type, $entity);
+ field_attach_update($entity_type, $entity);
+ }
+}
diff --git a/sites/all/modules/contrib/localisation/entity_translation/entity_translation.node.inc b/sites/all/modules/contrib/localisation/entity_translation/entity_translation.node.inc
index 6ec40626..40d0f5d4 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/entity_translation.node.inc
+++ b/sites/all/modules/contrib/localisation/entity_translation/entity_translation.node.inc
@@ -249,3 +249,24 @@ function entity_translation_query_comment_filter_alter(QueryAlterableInterface $
}
}
}
+
+/**
+ * Implements hook_node_update_index().
+ *
+ * Add translated node content to search index.
+ */
+function entity_translation_node_update_index($node) {
+ $text = '';
+ $langcodes = array_keys(language_list());
+ $translations = entity_translation_get_handler('node', $node)->getTranslations();
+ foreach ($langcodes as $langcode) {
+ // Skip the default language (already indexed by search.module).
+ if ($GLOBALS[LANGUAGE_TYPE_CONTENT]->language != $langcode && isset($translations->data[$langcode])) {
+ // Render the node in each language.
+ node_build_content($node, 'search_index', $langcode);
+ $rendered = drupal_render($node->content);
+ $text .= '
' . check_plain($node->title) . '
' . $rendered;
+ }
+ }
+ return $text;
+}
diff --git a/sites/all/modules/contrib/localisation/entity_translation/entity_translation_i18n_menu/entity_translation_i18n_menu.info b/sites/all/modules/contrib/localisation/entity_translation/entity_translation_i18n_menu/entity_translation_i18n_menu.info
index 40c2501a..3e8602db 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/entity_translation_i18n_menu/entity_translation_i18n_menu.info
+++ b/sites/all/modules/contrib/localisation/entity_translation/entity_translation_i18n_menu/entity_translation_i18n_menu.info
@@ -7,9 +7,9 @@ dependencies[] = i18n
dependencies[] = i18n_menu
files[] = entity_translation_i18n_menu.test
-; Information added by Drupal.org packaging script on 2015-01-22
-version = "7.x-1.0-beta4"
+; Information added by Drupal.org packaging script on 2016-05-07
+version = "7.x-1.0-beta5"
core = "7.x"
project = "entity_translation"
-datestamp = "1421971088"
+datestamp = "1462661041"
diff --git a/sites/all/modules/contrib/localisation/entity_translation/entity_translation_i18n_menu/entity_translation_i18n_menu.module b/sites/all/modules/contrib/localisation/entity_translation/entity_translation_i18n_menu/entity_translation_i18n_menu.module
index 60203693..572f0e05 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/entity_translation_i18n_menu/entity_translation_i18n_menu.module
+++ b/sites/all/modules/contrib/localisation/entity_translation/entity_translation_i18n_menu/entity_translation_i18n_menu.module
@@ -196,8 +196,8 @@ function entity_translation_i18n_menu_form_menu_edit_item_validate($form, &$form
$item = $form_state['values'];
// Localizable menu items should not be created when a translation set for the
- // same path already exists.
- if ($item['language'] == LANGUAGE_NONE) {
+ // same path already exists (exluding special paths starting by <).
+ if ($item['language'] == LANGUAGE_NONE && strpos($item['link_path'], '<') !== 0) {
$count = db_select('menu_links', 'ml')
->condition('ml.link_path', $item['link_path'])
->condition('ml.i18n_tsid', 0, '<>')
diff --git a/sites/all/modules/contrib/localisation/entity_translation/entity_translation_upgrade/entity_translation_upgrade.info b/sites/all/modules/contrib/localisation/entity_translation/entity_translation_upgrade/entity_translation_upgrade.info
index a228c423..8ed343d8 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/entity_translation_upgrade/entity_translation_upgrade.info
+++ b/sites/all/modules/contrib/localisation/entity_translation/entity_translation_upgrade/entity_translation_upgrade.info
@@ -4,9 +4,9 @@ package = Multilingual - Entity Translation
core = 7.x
dependencies[] = entity_translation
-; Information added by Drupal.org packaging script on 2015-01-22
-version = "7.x-1.0-beta4"
+; Information added by Drupal.org packaging script on 2016-05-07
+version = "7.x-1.0-beta5"
core = "7.x"
project = "entity_translation"
-datestamp = "1421971088"
+datestamp = "1462661041"
diff --git a/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler.inc b/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler.inc
index cc0f6f3b..0e24de4e 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler.inc
+++ b/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler.inc
@@ -441,10 +441,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
$query->condition('revision_id', $revisions_ids, 'IN');
}
- $results = $query
- ->orderBy('entity_id')
- ->orderBy('created')
- ->execute();
+ $results = $query->execute();
foreach ($results as $row) {
$id = $row->entity_id;
@@ -1615,9 +1612,12 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
/**
* Returns the title to be used for the entity form page.
+ *
+ * This may contain HTML markup and thus needs to be sanitized, since it will
+ * be used as page title as-is.
*/
protected function entityFormTitle() {
- return $this->getLabel();
+ return check_plain($this->getLabel());
}
/**
diff --git a/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler.node.inc b/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler.node.inc
index fee63554..d967ada6 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler.node.inc
+++ b/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler.node.inc
@@ -92,7 +92,9 @@ class EntityTranslationNodeHandler extends EntityTranslationDefaultHandler {
if (!$this->isTranslationForm()) {
// Inherit entity authoring information for the original values.
- $values['name'] = $form_state['values']['name'];
+ if (isset($form_state['values']['name'])) {
+ $values['name'] = $form_state['values']['name'];
+ }
if (!empty($form_state['values']['date'])) {
$values['created'] = $form_state['values']['date'];
}
diff --git a/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler.taxonomy_term.inc b/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler.taxonomy_term.inc
index 800e1068..0432bc02 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler.taxonomy_term.inc
+++ b/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler.taxonomy_term.inc
@@ -15,6 +15,22 @@ class EntityTranslationTaxonomyTermHandler extends EntityTranslationDefaultHandl
parent::__construct('taxonomy_term', $entity_info, $entity);
}
+ /**
+ * @see EntityTranslationDefaultHandler::getLanguage()
+ */
+ public function getLanguage() {
+ if (isset($this->entity->vid) && module_exists('i18n_taxonomy')) {
+ $mode = i18n_taxonomy_vocabulary_mode($this->entity->vid);
+ if ($mode == I18N_MODE_NONE) {
+ $translations = $this->getTranslations();
+ if (!empty($translations->original)) {
+ return $translations->original;
+ }
+ }
+ }
+ return parent::getLanguage();
+ }
+
/**
* @see EntityTranslationDefaultHandler::entityForm()
*/
diff --git a/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler_factory.inc b/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler_factory.inc
index bdbcf9be..b3819c2c 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler_factory.inc
+++ b/sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler_factory.inc
@@ -112,9 +112,10 @@ class EntityTranslationHandlerFactory {
*/
public function getHandlerId($entity_type, $entity) {
if (!isset($entity->entity_translation_handler_id)) {
- list($id, $revision_id) = entity_extract_ids($entity_type, $entity);
+ list($id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
$revision_id = isset($revision_id) ? $revision_id : 0;
- $entity->entity_translation_handler_id = $entity_type . '-' . (!empty($id) ? 'eid-' . $id . '-' . $revision_id : 'new-' . self::$newId++);
+ $bundle = isset($bundle) ? $bundle : $entity_type;
+ $entity->entity_translation_handler_id = $entity_type . '-' . $bundle . '-' . (!empty($id) ? 'eid-' . $id . '-' . $revision_id : 'new-' . self::$newId++);
}
return $entity->entity_translation_handler_id;
}
diff --git a/sites/all/modules/contrib/localisation/entity_translation/includes/translation.migrate.inc b/sites/all/modules/contrib/localisation/entity_translation/includes/translation.migrate.inc
new file mode 100644
index 00000000..b3853069
--- /dev/null
+++ b/sites/all/modules/contrib/localisation/entity_translation/includes/translation.migrate.inc
@@ -0,0 +1,86 @@
+registerTypes(array('entity'));
+ }
+
+ /**
+ * Handles Entity Translations.
+ *
+ * @param stdClass $entity
+ * @param stdClass $sourceRow
+ */
+ public function prepare($entity, stdClass $row) {
+ $migration = Migration::currentMigration();
+ $entity_type = $migration->getDestination()->getEntityType();
+
+ // Only continue if the entity type + bundle combination is enabled for
+ // entity_translation.
+ if (entity_translation_enabled($entity_type, $entity)) {
+ // Get the entity_translation handler and load any existing translations.
+ $handler = entity_translation_get_handler($entity_type, $entity);
+ $handler->loadTranslations();
+ $original_language = $handler->getLanguage();
+
+ // Get the bundle of the entity.
+ list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+
+ // We need to get all of the possible translations to create. So we look
+ // for any translatable fields.
+ $translatable_fields = array();
+ foreach (field_info_instances($entity_type, $bundle) as $instance) {
+ $field_name = $instance['field_name'];
+ $field = field_info_field($field_name);
+
+ if ($field['translatable']) {
+ $translatable_fields[] = $field_name;
+ }
+ }
+
+ // In those fields we look for translated values to build out an array
+ // of languages we need to set translations for.
+ $translate_languages = array();
+ foreach ($translatable_fields as $translatable_field) {
+ if (!empty($entity->{$translatable_field})) {
+ $field_languages = array_keys($entity->{$translatable_field});
+ foreach ($field_languages as $field_language) {
+ $translate_languages[$field_language] = $field_language;
+ }
+ }
+ }
+
+ // Remove the LANGUAGE_NONE results.
+ unset($translate_languages[LANGUAGE_NONE]);
+
+ // Remove the original language.
+ unset($translate_languages[$original_language]);
+
+ // Anything we're left with is a translation that should be set.
+ foreach ($translate_languages as $translate_language) {
+ if (!isset($entity->translations->data[$translate_language])) {
+ // Add the new translation and store it.
+ $handler->setTranslation(array(
+ 'translate' => 0,
+ 'status' => 1,
+ 'language' => $translate_language,
+ 'source' => $original_language,
+ 'uid' => (empty($entity->uid)) ? 0 : $entity->uid,
+ 'changed' => (empty($entity->changed)) ? REQUEST_TIME : $entity->changed,
+ 'created' => (empty($entity->created)) ? REQUEST_TIME : $entity->created,
+ ));
+ }
+ }
+ }
+ }
+}
diff --git a/sites/all/modules/contrib/localisation/entity_translation/tests/entity_translation_test.info b/sites/all/modules/contrib/localisation/entity_translation/tests/entity_translation_test.info
index 3ae19cbe..7539437f 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/tests/entity_translation_test.info
+++ b/sites/all/modules/contrib/localisation/entity_translation/tests/entity_translation_test.info
@@ -6,9 +6,9 @@ hidden = TRUE
dependencies[] = entity_translation
files[] = entity_translation_test.module
-; Information added by Drupal.org packaging script on 2015-01-22
-version = "7.x-1.0-beta4"
+; Information added by Drupal.org packaging script on 2016-05-07
+version = "7.x-1.0-beta5"
core = "7.x"
project = "entity_translation"
-datestamp = "1421971088"
+datestamp = "1462661041"
diff --git a/sites/all/modules/contrib/localisation/entity_translation/views/entity_translation.views.inc b/sites/all/modules/contrib/localisation/entity_translation/views/entity_translation.views.inc
index e6b5cf8a..3ff3deec 100644
--- a/sites/all/modules/contrib/localisation/entity_translation/views/entity_translation.views.inc
+++ b/sites/all/modules/contrib/localisation/entity_translation/views/entity_translation.views.inc
@@ -182,7 +182,7 @@ function entity_translation_views_data() {
);
$data['entity_translation']['translation_exists'] = array(
'title' => t('Translation exists'),
- 'help' => t('Link to translation overview page.'),
+ 'help' => t('Determines if a translation exists for a particular translation.'),
'filter' => array(
'handler' => 'entity_translation_handler_filter_translation_exists',
),
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n.info b/sites/all/modules/contrib/localisation/i18n/i18n.info
index d4f5c430..882e650f 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n.info
@@ -8,9 +8,9 @@ files[] = i18n_object.inc
files[] = i18n.test
configure = admin/config/regional/i18n
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n.test b/sites/all/modules/contrib/localisation/i18n/i18n.test
index 491d7ef7..2a82e17a 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n.test
+++ b/sites/all/modules/contrib/localisation/i18n/i18n.test
@@ -11,7 +11,7 @@ class Drupali18nTestCase extends DrupalWebTestCase {
function setUpLanguages($admin_permissions = array()) {
// Setup admin user.
- $this->admin_user = $this->drupalCreateUser(array_merge(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer blocks', 'access administration pages', 'translate interface'), $admin_permissions));
+ $this->admin_user = $this->drupalCreateUser(array_merge(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer fields', 'administer blocks', 'access administration pages', 'translate interface'), $admin_permissions));
$this->drupalLogin($this->admin_user);
@@ -362,6 +362,7 @@ class Drupali18nTestCase extends DrupalWebTestCase {
function resetCaches() {
drupal_static_reset('locale_url_outbound_alter');
drupal_static_reset('language_list');
+ drupal_language_initialize();
}
/**
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_block/i18n_block.info b/sites/all/modules/contrib/localisation/i18n/i18n_block/i18n_block.info
index 0e599035..725e30c6 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_block/i18n_block.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_block/i18n_block.info
@@ -8,9 +8,9 @@ files[] = i18n_block.inc
files[] = i18n_block.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_contact/i18n_contact.info b/sites/all/modules/contrib/localisation/i18n/i18n_contact/i18n_contact.info
index 7bad71d2..15f84d8d 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_contact/i18n_contact.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_contact/i18n_contact.info
@@ -5,9 +5,9 @@ dependencies[] = i18n_string
package = Multilingual - Internationalization
core = 7.x
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_field/i18n_field.info b/sites/all/modules/contrib/localisation/i18n/i18n_field/i18n_field.info
index 552eb392..6554eb18 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_field/i18n_field.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_field/i18n_field.info
@@ -6,9 +6,9 @@ package = Multilingual - Internationalization
core = 7.x
files[] = i18n_field.inc
files[] = i18n_field.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_forum/i18n_forum.info b/sites/all/modules/contrib/localisation/i18n/i18n_forum/i18n_forum.info
index afd96583..972dff16 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_forum/i18n_forum.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_forum/i18n_forum.info
@@ -7,9 +7,9 @@ package = Multilingual - Internationalization
core = 7.x
files[] = i18n_forum.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_menu/i18n_menu.info b/sites/all/modules/contrib/localisation/i18n/i18n_menu/i18n_menu.info
index 7a6821c7..05e7d9cd 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_menu/i18n_menu.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_menu/i18n_menu.info
@@ -10,9 +10,9 @@ core = 7.x
files[] = i18n_menu.inc
files[] = i18n_menu.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_menu/i18n_menu.module b/sites/all/modules/contrib/localisation/i18n/i18n_menu/i18n_menu.module
index 8bcf6796..fecb6106 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_menu/i18n_menu.module
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_menu/i18n_menu.module
@@ -180,6 +180,7 @@ function i18n_menu_menu_link_alter(&$item) {
// We just make sure every link has a valid language property.
if (!i18n_object_langcode($item)) {
$item['language'] = LANGUAGE_NONE;
+ $item['i18n_tsid'] = 0;
}
}
@@ -515,9 +516,11 @@ function _i18n_menu_link_description($link, $langcode = NULL) {
* Check whether this link is to be processed by i18n_menu and start processing.
*/
function _i18n_menu_link_process(&$link) {
- // Only visible links that have a language property and haven't been processed
- // before. We also check that they belong to a menu with language options.
- if (empty($link['i18n_menu']) && !empty($link['language']) && !empty($link['access']) && empty($link['hidden']) && i18n_menu_mode($link['menu_name'])) {
+ // Only links that have a language property and haven't been processed before.
+ // We also translate links marked as hidden because core breadcrumbs ignore
+ // that flag and excluding them would basically interfere with core behaviour.
+ // We also check that they belong to a menu with language options.
+ if (empty($link['i18n_menu']) && !empty($link['language']) && !empty($link['access']) && i18n_menu_mode($link['menu_name'])) {
// Mark so it won't be processed twice.
$link['i18n_menu'] = TRUE;
// Skip if administering this menu or this menu item.
@@ -588,7 +591,7 @@ function _i18n_menu_link_localizable_properties($link) {
// If the title callback is 't' and the link title matches the router title
// it will be localized by core, not by i18n_menu.
if (!$router ||
- (empty($router['title_callback']) || $router['title_callback'] != 't') ||
+ (empty($router['title_callback']) || ($router['title_callback'] != 't' || !empty($link['customized']))) ||
(empty($router['title']) || $router['title'] != $link['link_title'])
) {
$props[] = 'title';
@@ -597,7 +600,7 @@ function _i18n_menu_link_localizable_properties($link) {
if (!empty($link['options']['attributes']['title'])) {
// If the description matches the router description, it will be localized
// by core.
- if (!$router || empty($router['description']) || $router['description'] != $link['options']['attributes']['title']) {
+ if (!$router || empty($router['description']) || ($router['description'] != $link['options']['attributes']['title']) || !empty($link['customized'])) {
$props[] = 'description';
}
}
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_node/i18n_node.info b/sites/all/modules/contrib/localisation/i18n/i18n_node/i18n_node.info
index 4522510e..a637f0db 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_node/i18n_node.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_node/i18n_node.info
@@ -9,9 +9,9 @@ configure = admin/config/regional/i18n/node
files[]=i18n_node.test
files[]=i18n_node.variable.inc
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_path/i18n_path.info b/sites/all/modules/contrib/localisation/i18n/i18n_path/i18n_path.info
index 10f62e7c..30c8c3b9 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_path/i18n_path.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_path/i18n_path.info
@@ -6,9 +6,9 @@ core = 7.x
files[] = i18n_path.inc
files[] = i18n_path.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_redirect/i18n_redirect.info b/sites/all/modules/contrib/localisation/i18n/i18n_redirect/i18n_redirect.info
index 6f6ee43d..ad48edb7 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_redirect/i18n_redirect.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_redirect/i18n_redirect.info
@@ -4,9 +4,9 @@ dependencies[] = i18n
package = Multilingual - Internationalization
core = 7.x
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_select/i18n_select.info b/sites/all/modules/contrib/localisation/i18n/i18n_select/i18n_select.info
index 7c47197f..d24b3767 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_select/i18n_select.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_select/i18n_select.info
@@ -6,9 +6,9 @@ core = 7.x
configure = admin/config/regional/i18n/select
files[] = i18n_select.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_select/i18n_select.module b/sites/all/modules/contrib/localisation/i18n/i18n_select/i18n_select.module
index bcba5782..9063fe9d 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_select/i18n_select.module
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_select/i18n_select.module
@@ -82,11 +82,11 @@ function i18n_select_mode($type = NULL) {
}
/**
- * Check current path to enable selection
+ * Check current path to enable selection.
*
- * This works pretty much like block visibility
+ * This works pretty much like block visibility.
*
- * @return boolean
+ * @return bool
* TRUE if content selection should be enabled for this page.
*/
function i18n_select_page() {
@@ -100,8 +100,11 @@ function i18n_select_page() {
// with different case. Ex: /Page, /page, /PAGE.
$pages = drupal_strtolower($pages);
if ($visibility < I18N_SELECT_PAGE_PHP) {
- // Convert the Drupal path to lowercase
- $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));
+ // @see views_ajax()
+ // @see I18NSelectAdminViewsAjax::testViewsAjaxWithoutSkippingTags()
+ $path = isset($_REQUEST['view_path']) ? $_REQUEST['view_path'] : $_GET['q'];
+ // Convert the Drupal path to lowercase.
+ $path = drupal_strtolower(drupal_get_path_alias($path));
// Compare the lowercase internal and lowercase path alias (if any).
$page_match = drupal_match_path($path, $pages);
if ($path != $_GET['q']) {
@@ -109,8 +112,8 @@ function i18n_select_page() {
}
// When $visibility has a value of 0 (I18N_SELECT_PAGE_NOTLISTED),
// the block is displayed on all pages except those listed in $pages.
- // When set to 1 (I18N_SELECT_PAGE_LISTED), it is displayed only on those
- // pages listed in $pages.
+ // When set to 1 (I18N_SELECT_PAGE_LISTED), it is displayed only on
+ // those pages listed in $pages.
$mode = !($visibility xor $page_match);
}
elseif (module_exists('php')) {
@@ -121,7 +124,7 @@ function i18n_select_page() {
}
}
else {
- // No pages defined, still respect the setting (unlike blocks)
+ // No pages defined, still respect the setting (unlike blocks).
$mode = $visibility == I18N_SELECT_PAGE_NOTLISTED;
}
}
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_select/i18n_select.test b/sites/all/modules/contrib/localisation/i18n/i18n_select/i18n_select.test
index b46fb986..5af85431 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_select/i18n_select.test
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_select/i18n_select.test
@@ -84,3 +84,87 @@ class i18nSelectTestCase extends Drupali18nTestCase {
}
}
}
+
+/**
+ * Test case for AJAX queries on "views/ajax" when view on admin page.
+ */
+class I18NSelectAdminViewsAjax extends Drupali18nTestCase {
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getInfo() {
+ return array(
+ 'name' => t('I18N select Admin Views (AJAX)'),
+ 'group' => 'Internationalization',
+ 'description' => t('Test AJAX requests to the "views/ajax" when view located on "admin/*" and list of skipping tags is empty.'),
+ // Skip this test when "admin_views" module does not exists.
+ 'dependencies' => array('admin_views'),
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp('translation', 'i18n_variable', 'i18n_select', 'admin_views');
+ parent::setUpLanguages(array('access content overview'));
+ parent::setUpContentTranslation();
+ }
+
+ /**
+ * Test AJAX of a view without skipping tags for selection.
+ *
+ * @see i18n_select_page()
+ */
+ public function testViewsAjaxWithoutSkippingTags() {
+ // If this variable will have the "views" value then this test will not
+ // have sense. For instance, we want apply language selection filter
+ // for views and remove "views" from "i18n_select_skip_tags" variable.
+ // In this case all AJAX for views, on administration part of the site,
+ // will be broken because the "i18n_select_page()" function will work
+ // with "views/ajax" path instead of, for example, "admin/content".
+ variable_set('i18n_select_skip_tags', '');
+
+ // Create one hundred of nodes.
+ for ($i = 1; $i <= 100; $i++) {
+ // Create every second node on Spanish language and
+ // every first - on English.
+ $node = $this->createNode('page', "Node $i", '', $i % 2 ? $this->default_language : $this->secondary_language);
+
+ // Update "changed" in order to sort the content by updating date. In
+ // other case all nodes will be with the same date and not arranged in
+ // order.
+ db_update('node')
+ ->fields(array('changed' => strtotime("+ $i minute")))
+ ->condition('nid', $node->nid)
+ ->execute();
+ }
+
+ $this->drupalGet('admin/content');
+
+ // Check that latest node exists at the top.
+ $this->assertText('Node 100');
+ // Check that our page contains fifty nodes (the latest must be 51).
+ $this->assertNoText('Node 50');
+
+ // Test $_REQUEST['view_path']. There's no form to submit to, so
+ // drupalPost() won't work here. This just tests a direct $_POST
+ // request instead.
+ $this->curlExec(array(
+ CURLOPT_URL => $this->getAbsoluteUrl('views/ajax'),
+ CURLOPT_POST => TRUE,
+ CURLOPT_POSTFIELDS => http_build_query(array(
+ 'page' => 1,
+ 'view_path' => 'admin/content',
+ 'view_name' => 'admin_views_node',
+ 'view_display_id' => 'system_1',
+ )),
+ ));
+
+ // Check that we are successfully switched to a new page of content.
+ $this->assertText('Node 50');
+ $this->assertNoText('Node 100');
+ }
+
+}
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_string/i18n_string.info b/sites/all/modules/contrib/localisation/i18n/i18n_string/i18n_string.info
index 301a54ec..64ab698e 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_string/i18n_string.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_string/i18n_string.info
@@ -10,9 +10,9 @@ files[] = i18n_string.inc
files[] = i18n_string.test
configure = admin/config/regional/i18n/strings
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_string/i18n_string.install b/sites/all/modules/contrib/localisation/i18n/i18n_string/i18n_string.install
index 100d7c04..30e8cd26 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_string/i18n_string.install
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_string/i18n_string.install
@@ -29,7 +29,9 @@ function i18n_string_install() {
i18n_string_update_7001();
}
// Create new index in {locales_source}, performance improvement in sites with i18n.
- db_add_index('locales_source', 'textgroup_context', array('textgroup', 'context'));
+ if (!db_index_exists('locales_source', 'textgroup_context')) {
+ db_add_index('locales_source', 'textgroup_context', array('textgroup', array('context', 50)));
+ }
}
/**
@@ -106,7 +108,7 @@ function i18n_string_schema() {
),
'primary key' => array('lid'),
'indexes' => array(
- 'group_context' => array('textgroup', 'context'),
+ 'group_context' => array('textgroup', array('context', 50)),
),
);
return $schema;
@@ -238,7 +240,9 @@ function i18n_string_update_7001() {
* Create new index in {locales_source}, performance improvement in sites with i18n.
*/
function i18n_string_update_7002() {
- db_add_index('locales_source', 'textgroup_context', array('textgroup', 'context'));
+ if (!db_index_exists('locales_source', 'textgroup_context')) {
+ db_add_index('locales_source', 'textgroup_context', array('textgroup', array('context', 50)));
+ }
}
@@ -269,4 +273,4 @@ function i18n_string_update_7002() {
* Node type
* nodetype:type:[type]:[property] -> node:type:[type]:[property]
* Property names: title -> title_label
- */
\ No newline at end of file
+ */
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_string/i18n_string.test b/sites/all/modules/contrib/localisation/i18n/i18n_string/i18n_string.test
index f11c7564..d4563405 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_string/i18n_string.test
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_string/i18n_string.test
@@ -53,6 +53,28 @@ class i18nStringTestCase extends Drupali18nTestCase {
$this->assertEqual($translation, $translations[$key][$language->language], "The right $language->name ($language->language) translation has been retrieved for $name, $translation");
}
}
+
+ // Test that regular strings can be translated. Use 'Built-in interface' as
+ // filter, and translate first one.
+ $search = array(
+ 'language' => 'all',
+ 'translation' => 'all',
+ 'group' => 'default',
+ 'string' => '',
+ );
+ $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+ $this->clickLink(t('edit'));
+ // Just add a random translation.
+ $translation = $this->randomString();
+ $edit = array();
+ foreach ($this->getOtherLanguages() as $language) {
+ $langcode = $language->language;
+ $edit["translations[$langcode]"] = $translation;
+ }
+ $this->drupalPost(NULL, $edit, t('Save translations'));
+ $this->assertText(t('The string has been saved.'), t('The string has been saved.'));
+ $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
+
}
/**
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_sync/i18n_sync.info b/sites/all/modules/contrib/localisation/i18n/i18n_sync/i18n_sync.info
index 2f1cd55e..c6b644b7 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_sync/i18n_sync.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_sync/i18n_sync.info
@@ -10,9 +10,9 @@ files[] = i18n_sync.install
files[] = i18n_sync.module.inc
files[] = i18n_sync.node.inc
files[] = i18n_sync.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_taxonomy/i18n_taxonomy.info b/sites/all/modules/contrib/localisation/i18n/i18n_taxonomy/i18n_taxonomy.info
index 2412c40e..300b8407 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_taxonomy/i18n_taxonomy.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_taxonomy/i18n_taxonomy.info
@@ -11,9 +11,9 @@ files[] = i18n_taxonomy.pages.inc
files[] = i18n_taxonomy.admin.inc
files[] = i18n_taxonomy.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_taxonomy/i18n_taxonomy.module b/sites/all/modules/contrib/localisation/i18n/i18n_taxonomy/i18n_taxonomy.module
index 40533489..920e0105 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_taxonomy/i18n_taxonomy.module
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_taxonomy/i18n_taxonomy.module
@@ -213,7 +213,12 @@ function i18n_taxonomy_field_formatter_view($entity_type, $entity, $field, $inst
);
}
else {
- $term = $item['taxonomy_term'];
+ if (isset($item['taxonomy_term'])) {
+ $term = $item['taxonomy_term'];
+ }
+ else {
+ $term = taxonomy_term_load($item['tid']);
+ }
$uri = entity_uri('taxonomy_term', $term);
$element[$delta] = array(
'#type' => 'link',
@@ -1020,6 +1025,10 @@ function i18n_taxonomy_localize_terms($terms) {
if (!i18n_string_translate_langcode()) {
return $terms;
}
+ // $terms is not a valid array or term.
+ if (empty($terms)) {
+ return $terms;
+ }
$object_info = i18n_object_info('taxonomy_term');
$list = is_array($terms) ? $terms : array($terms);
foreach ($list as $index => $term) {
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_translation/i18n_translation.info b/sites/all/modules/contrib/localisation/i18n/i18n_translation/i18n_translation.info
index 190173c5..d09c7add 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_translation/i18n_translation.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_translation/i18n_translation.info
@@ -6,9 +6,9 @@ core = 7.x
files[] = i18n_translation.inc
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_user/i18n_user.info b/sites/all/modules/contrib/localisation/i18n/i18n_user/i18n_user.info
index 7c6ee3ba..e784248e 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_user/i18n_user.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_user/i18n_user.info
@@ -4,9 +4,9 @@ core = 7.x
package = Multilingual - Internationalization
dependencies[] = i18n_variable
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_user/i18n_user.module b/sites/all/modules/contrib/localisation/i18n/i18n_user/i18n_user.module
index 4d13b3ba..9c61b814 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_user/i18n_user.module
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_user/i18n_user.module
@@ -54,7 +54,7 @@ function i18n_user_user_mail_tokens(&$replacements, $data, $options) {
*/
function i18n_user_user_pass_reset_url($account) {
$timestamp = REQUEST_TIME;
- return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE, 'language' => i18n_language($account->language)));
+ return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid), array('absolute' => TRUE, 'language' => i18n_language($account->language)));
}
/**
@@ -65,5 +65,5 @@ function i18n_user_user_pass_reset_url($account) {
*/
function i18n_user_user_cancel_url($account) {
$timestamp = REQUEST_TIME;
- return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE, 'language' => i18n_language($account->language)));
+ return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid), array('absolute' => TRUE, 'language' => i18n_language($account->language)));
}
diff --git a/sites/all/modules/contrib/localisation/i18n/i18n_variable/i18n_variable.info b/sites/all/modules/contrib/localisation/i18n/i18n_variable/i18n_variable.info
index 6956a25d..3dbcd3c8 100644
--- a/sites/all/modules/contrib/localisation/i18n/i18n_variable/i18n_variable.info
+++ b/sites/all/modules/contrib/localisation/i18n/i18n_variable/i18n_variable.info
@@ -10,9 +10,9 @@ configure = admin/config/regional/i18n/variable
files[] = i18n_variable.class.inc
files[] = i18n_variable.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/localisation/i18n/tests/i18n_test.info b/sites/all/modules/contrib/localisation/i18n/tests/i18n_test.info
index 9ccf441d..2f7a00c4 100644
--- a/sites/all/modules/contrib/localisation/i18n/tests/i18n_test.info
+++ b/sites/all/modules/contrib/localisation/i18n/tests/i18n_test.info
@@ -7,9 +7,9 @@ package = Testing
core = 6.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2016-10-22
+version = "7.x-1.14"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1477154943"
diff --git a/sites/all/modules/contrib/menu/menu_admin_per_menu/LICENSE.txt b/sites/all/modules/contrib/menu/menu_admin_per_menu/LICENSE.txt
index 2c095c8d..d159169d 100644
--- a/sites/all/modules/contrib/menu/menu_admin_per_menu/LICENSE.txt
+++ b/sites/all/modules/contrib/menu/menu_admin_per_menu/LICENSE.txt
@@ -1,274 +1,339 @@
-GNU GENERAL PUBLIC LICENSE
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
- Version 2, June 1991
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
-Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave,
-Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute
-verbatim copies of this license document, but changing it is not allowed.
+ Preamble
- Preamble
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
-The licenses for most software are designed to take away your freedom to
-share and change it. By contrast, the GNU General Public License is
-intended to guarantee your freedom to share and change free software--to
-make sure the software is free for all its users. This General Public License
-applies to most of the Free Software Foundation's software and to any other
-program whose authors commit to using it. (Some other Free Software
-Foundation software is covered by the GNU Library General Public License
-instead.) You can apply it to your programs, too.
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
-When we speak of free software, we are referring to freedom, not price. Our
-General Public Licenses are designed to make sure that you have the
-freedom to distribute copies of free software (and charge for this service if
-you wish), that you receive source code or can get it if you want it, that you
-can change the software or use pieces of it in new free programs; and that
-you know you can do these things.
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
-To protect your rights, we need to make restrictions that forbid anyone to
-deny you these rights or to ask you to surrender the rights. These restrictions
-translate to certain responsibilities for you if you distribute copies of the
-software, or if you modify it.
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
-For example, if you distribute copies of such a program, whether gratis or for
-a fee, you must give the recipients all the rights that you have. You must make
-sure that they, too, receive or can get the source code. And you must show
-them these terms so they know their rights.
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
-We protect your rights with two steps: (1) copyright the software, and (2)
-offer you this license which gives you legal permission to copy, distribute
-and/or modify the software.
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
-Also, for each author's protection and ours, we want to make certain that
-everyone understands that there is no warranty for this free software. If the
-software is modified by someone else and passed on, we want its recipients
-to know that what they have is not the original, so that any problems
-introduced by others will not reflect on the original authors' reputations.
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
-Finally, any free program is threatened constantly by software patents. We
-wish to avoid the danger that redistributors of a free program will individually
-obtain patent licenses, in effect making the program proprietary. To prevent
-this, we have made it clear that any patent must be licensed for everyone's
-free use or not licensed at all.
+ The precise terms and conditions for copying, distribution and
+modification follow.
-The precise terms and conditions for copying, distribution and modification
-follow.
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
- MODIFICATION
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
-0. This License applies to any program or other work which contains a notice
-placed by the copyright holder saying it may be distributed under the terms
-of this General Public License. The "Program", below, refers to any such
-program or work, and a "work based on the Program" means either the
-Program or any derivative work under copyright law: that is to say, a work
-containing the Program or a portion of it, either verbatim or with
-modifications and/or translated into another language. (Hereinafter, translation
-is included without limitation in the term "modification".) Each licensee is
-addressed as "you".
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
-Activities other than copying, distribution and modification are not covered
-by this License; they are outside its scope. The act of running the Program is
-not restricted, and the output from the Program is covered only if its contents
-constitute a work based on the Program (independent of having been made
-by running the Program). Whether that is true depends on what the Program
-does.
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
-1. You may copy and distribute verbatim copies of the Program's source
-code as you receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice and
-disclaimer of warranty; keep intact all the notices that refer to this License
-and to the absence of any warranty; and give any other recipients of the
-Program a copy of this License along with the Program.
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
-You may charge a fee for the physical act of transferring a copy, and you
-may at your option offer warranty protection in exchange for a fee.
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
-2. You may modify your copy or copies of the Program or any portion of it,
-thus forming a work based on the Program, and copy and distribute such
-modifications or work under the terms of Section 1 above, provided that you
-also meet all of these conditions:
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
-a) You must cause the modified files to carry prominent notices stating that
-you changed the files and the date of any change.
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
-b) You must cause any work that you distribute or publish, that in whole or in
-part contains or is derived from the Program or any part thereof, to be
-licensed as a whole at no charge to all third parties under the terms of this
-License.
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
-c) If the modified program normally reads commands interactively when run,
-you must cause it, when started running for such interactive use in the most
-ordinary way, to print or display an announcement including an appropriate
-copyright notice and a notice that there is no warranty (or else, saying that
-you provide a warranty) and that users may redistribute the program under
-these conditions, and telling the user how to view a copy of this License.
-(Exception: if the Program itself is interactive but does not normally print such
-an announcement, your work based on the Program is not required to print
-an announcement.)
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
-These requirements apply to the modified work as a whole. If identifiable
-sections of that work are not derived from the Program, and can be
-reasonably considered independent and separate works in themselves, then
-this License, and its terms, do not apply to those sections when you distribute
-them as separate works. But when you distribute the same sections as part
-of a whole which is a work based on the Program, the distribution of the
-whole must be on the terms of this License, whose permissions for other
-licensees extend to the entire whole, and thus to each and every part
-regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest your rights to
-work written entirely by you; rather, the intent is to exercise the right to
-control the distribution of derivative or collective works based on the
-Program.
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of a
-storage or distribution medium does not bring the other work under the scope
-of this License.
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
-3. You may copy and distribute the Program (or a work based on it, under
-Section 2) in object code or executable form under the terms of Sections 1
-and 2 above provided that you also do one of the following:
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
-a) Accompany it with the complete corresponding machine-readable source
-code, which must be distributed under the terms of Sections 1 and 2 above
-on a medium customarily used for software interchange; or,
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
-b) Accompany it with a written offer, valid for at least three years, to give
-any third party, for a charge no more than your cost of physically performing
-source distribution, a complete machine-readable copy of the corresponding
-source code, to be distributed under the terms of Sections 1 and 2 above on
-a medium customarily used for software interchange; or,
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
-c) Accompany it with the information you received as to the offer to distribute
-corresponding source code. (This alternative is allowed only for
-noncommercial distribution and only if you received the program in object
-code or executable form with such an offer, in accord with Subsection b
-above.)
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source code
-means all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation and
-installation of the executable. However, as a special exception, the source
-code distributed need not include anything that is normally distributed (in
-either source or binary form) with the major components (compiler, kernel,
-and so on) of the operating system on which the executable runs, unless that
-component itself accompanies the executable.
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
-If distribution of executable or object code is made by offering access to
-copy from a designated place, then offering equivalent access to copy the
-source code from the same place counts as distribution of the source code,
-even though third parties are not compelled to copy the source along with the
-object code.
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
-4. You may not copy, modify, sublicense, or distribute the Program except as
-expressly provided under this License. Any attempt otherwise to copy,
-modify, sublicense or distribute the Program is void, and will automatically
-terminate your rights under this License. However, parties who have received
-copies, or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
-5. You are not required to accept this License, since you have not signed it.
-However, nothing else grants you permission to modify or distribute the
-Program or its derivative works. These actions are prohibited by law if you
-do not accept this License. Therefore, by modifying or distributing the
-Program (or any work based on the Program), you indicate your acceptance
-of this License to do so, and all its terms and conditions for copying,
-distributing or modifying the Program or works based on it.
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
-6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the original
-licensor to copy, distribute or modify the Program subject to these terms and
-conditions. You may not impose any further restrictions on the recipients'
-exercise of the rights granted herein. You are not responsible for enforcing
-compliance by third parties to this License.
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
-7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues), conditions
-are imposed on you (whether by court order, agreement or otherwise) that
-contradict the conditions of this License, they do not excuse you from the
-conditions of this License. If you cannot distribute so as to satisfy
-simultaneously your obligations under this License and any other pertinent
-obligations, then as a consequence you may not distribute the Program at all.
-For example, if a patent license would not permit royalty-free redistribution
-of the Program by all those who receive copies directly or indirectly through
-you, then the only way you could satisfy both it and this License would be to
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply and
-the section as a whole is intended to apply in other circumstances.
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
-It is not the purpose of this section to induce you to infringe any patents or
-other property right claims or to contest validity of any such claims; this
-section has the sole purpose of protecting the integrity of the free software
-distribution system, which is implemented by public license practices. Many
-people have made generous contributions to the wide range of software
-distributed through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing to
-distribute software through any other system and a licensee cannot impose
-that choice.
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
-This section is intended to make thoroughly clear what is believed to be a
-consequence of the rest of this License.
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
-8. If the distribution and/or use of the Program is restricted in certain
-countries either by patents or by copyrighted interfaces, the original copyright
-holder who places the Program under this License may add an explicit
-geographical distribution limitation excluding those countries, so that
-distribution is permitted only in or among countries not thus excluded. In such
-case, this License incorporates the limitation as if written in the body of this
-License.
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
-9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will be
-similar in spirit to the present version, but may differ in detail to address new
-problems or concerns.
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
-Each version is given a distinguishing version number. If the Program specifies
-a version number of this License which applies to it and "any later version",
-you have the option of following the terms and conditions either of that
-version or of any later version published by the Free Software Foundation. If
-the Program does not specify a version number of this License, you may
-choose any version ever published by the Free Software Foundation.
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
-10. If you wish to incorporate parts of the Program into other free programs
-whose distribution conditions are different, write to the author to ask for
-permission. For software which is copyrighted by the Free Software
-Foundation, write to the Free Software Foundation; we sometimes make
-exceptions for this. Our decision will be guided by the two goals of
-preserving the free status of all derivatives of our free software and of
-promoting the sharing and reuse of software generally.
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
- NO WARRANTY
+ NO WARRANTY
-11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,
-THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT
-PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
-STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
-WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
-PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
-NECESSARY SERVICING, REPAIR OR CORRECTION.
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
-12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
-AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR
-ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
-LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
-SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
-ARISING OUT OF THE USE OR INABILITY TO USE THE
-PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
-OR DATA BEING RENDERED INACCURATE OR LOSSES
-SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
-PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN
-IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
-THE POSSIBILITY OF SUCH DAMAGES.
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
- END OF TERMS AND CONDITIONS
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/sites/all/modules/contrib/menu/menu_admin_per_menu/README.txt b/sites/all/modules/contrib/menu/menu_admin_per_menu/README.txt
index 11bc5007..d0fadd67 100644
--- a/sites/all/modules/contrib/menu/menu_admin_per_menu/README.txt
+++ b/sites/all/modules/contrib/menu/menu_admin_per_menu/README.txt
@@ -1,14 +1,12 @@
-// $Id: README.txt,v 1.3 2010/10/29 10:31:08 anrikun Exp $
-
MENU ADMIN PER MENU
-http://drupal.org/project/menu_admin_per_menu
+https://www.drupal.org/project/menu_admin_per_menu
DESCRIPTION
-By default, Drupal 7 allows only users with "Administer menus and menu items" to add, modify or delete menu items.
+By default, Drupal allows only users with the "Administer menus and menu items" permission to add, modify or delete menu items.
In case you want for instance to let certain users manage Main menu or Navigation menu but not Management menu, this module provides this functionality.
INSTALLATION
-Please read instructions at: http://drupal.org/project/menu_admin_per_menu
+Please read instructions at: https://www.drupal.org/project/menu_admin_per_menu
CONTACT
Henri MEDOT
diff --git a/sites/all/modules/contrib/menu/menu_admin_per_menu/menu_admin_per_menu.api.php b/sites/all/modules/contrib/menu/menu_admin_per_menu/menu_admin_per_menu.api.php
new file mode 100644
index 00000000..38ed67b2
--- /dev/null
+++ b/sites/all/modules/contrib/menu/menu_admin_per_menu/menu_admin_per_menu.api.php
@@ -0,0 +1,21 @@
+
+ * @file
+ * Written by Henri MEDOT
* http://www.absyx.fr
*/
/**
- * Implementation of hook_permission().
+ * Implements hook_permission().
*/
function menu_admin_per_menu_permission() {
$perms = array();
+
$menus = menu_get_menus();
foreach ($menus as $name => $title) {
- $perms['administer '. $name .' menu items'] = array('title' => t('Administer %menu menu items', array('%menu' => $title)));
+ $perms['administer ' . $name . ' menu items'] = array('title' => t('Administer %menu menu items', array('%menu' => $title)));
}
+
return $perms;
}
/**
- * Implementation of hook_menu_alter()
+ * Implements hook_menu_alter().
*/
function menu_admin_per_menu_menu_alter(&$items) {
$items['admin/structure/menu']['page callback'] = '_menu_admin_per_menu_menu_overview_page';
@@ -43,16 +39,20 @@ function menu_admin_per_menu_menu_alter(&$items) {
$items['admin/structure/menu/item/%menu_link/delete']['access arguments'] = array(4);
}
+/**
+ * Overrides menu_overview_page().
+ */
function _menu_admin_per_menu_menu_overview_page() {
if (user_access('administer menu')) {
return menu_overview_page();
}
+ $perm_menus = _menu_admin_per_menu_get_perm_menus();
$result = db_query("SELECT * FROM {menu_custom} ORDER BY title", array(), array('fetch' => PDO::FETCH_ASSOC));
$header = array(t('Title'), array('data' => t('Operations'), 'colspan' => '2'));
$rows = array();
foreach ($result as $menu) {
- if (user_access('administer '. $menu['menu_name'] .' menu items')) {
+ if (isset($perm_menus[$menu['menu_name']])) {
$row = array(theme('menu_admin_overview', array('title' => $menu['title'], 'name' => $menu['menu_name'], 'description' => $menu['description'])));
$row[] = array('data' => l(t('list links'), 'admin/structure/menu/manage/' . $menu['menu_name']));
$row[] = array('data' => l(t('add link'), 'admin/structure/menu/manage/' . $menu['menu_name'] . '/add'));
@@ -63,39 +63,42 @@ function _menu_admin_per_menu_menu_overview_page() {
return theme('table', array('header' => $header, 'rows' => $rows));
}
+/**
+ * Access callback for the overview page of all the menus.
+ */
function _menu_admin_per_menu_access() {
- if (user_access('administer menu')) {
- return TRUE;
- }
- $perms = array_keys(menu_admin_per_menu_permission());
- foreach ($perms as $perm) {
- if (user_access($perm)) {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-function _menu_admin_per_menu_menu_access($menu = NULL) {
- if (user_access('administer menu')
- || user_access('administer '. $menu['menu_name'] .' menu items')) {
- return TRUE;
- }
- return FALSE;
-}
-
-function _menu_admin_per_menu_menu_link_access($menu_link = NULL) {
- if (user_access('administer menu')
- || user_access('administer '. $menu_link['menu_name'] .' menu items')) {
- return TRUE;
- }
- return FALSE;
+ return user_access('administer menu') || _menu_admin_per_menu_get_perm_menus();
}
/**
- * Implementation of hook_form_alter()
+ * Access callback for the overview and add menu link pages of a menu.
+ */
+function _menu_admin_per_menu_menu_access($menu) {
+ if (user_access('administer menu')) {
+ return TRUE;
+ }
+
+ $perm_menus = _menu_admin_per_menu_get_perm_menus();
+ return isset($perm_menus[$menu['menu_name']]);
+}
+
+/**
+ * Access callback for the menu link administration pages.
+ */
+function _menu_admin_per_menu_menu_link_access($menu_link) {
+ if (user_access('administer menu')) {
+ return TRUE;
+ }
+
+ $perm_menus = _menu_admin_per_menu_get_perm_menus();
+ return isset($perm_menus[$menu_link['menu_name']]);
+}
+
+/**
+ * Implements hook_form_alter().
*/
function menu_admin_per_menu_form_alter(&$form, $form_state, $form_id) {
+ // Alter the menu element of the node form.
if (isset($form['menu']['link']['parent']) && !user_access('administer menu')) {
$form['menu']['#access'] = FALSE;
if (_menu_admin_per_menu_filter_parent_options($form['menu']['link'])) {
@@ -108,39 +111,61 @@ function menu_admin_per_menu_form_alter(&$form, $form_state, $form_id) {
}
}
+/**
+ * Filters parent options based on allowed menus.
+ */
function _menu_admin_per_menu_filter_parent_options(&$element) {
$perm_menus = _menu_admin_per_menu_get_perm_menus();
- if ((count($perm_menus) > 0) && is_array($element['parent']['#options'])) {
+
+ if ($perm_menus && is_array($element['parent']['#options'])) {
$has_mlid = !empty($element['mlid']['#value']);
$default_value = $element['parent']['#default_value'];
$option_keys = array_keys($element['parent']['#options']);
+
foreach ($option_keys as $option_key) {
list($menu, $item) = explode(':', $option_key);
- if (!in_array($menu, $perm_menus)) {
+ if (!isset($perm_menus[$menu])) {
unset($element['parent']['#options'][$option_key]);
- if ($has_mlid && ($option_key == $default_value)) {
+ if ($has_mlid && $option_key == $default_value) {
return FALSE;
}
}
}
+
return count($element['parent']['#options']) > 0;
}
+
return FALSE;
}
-function _menu_admin_per_menu_get_perm_menus() {
- $perm_menus = array();
- $menus = menu_get_menus();
- foreach ($menus as $name => $title) {
- if (user_access('administer '. $name .' menu items')) {
- $perm_menus[] = $name;
- }
+/**
+ * Returns the menus for which a user has per menu admin permissions.
+ */
+function _menu_admin_per_menu_get_perm_menus($account = NULL) {
+ $perm_menus = &drupal_static(__FUNCTION__, array());
+
+ if (!isset($account)) {
+ $account = $GLOBALS['user'];
}
- return $perm_menus;
+
+ if (!isset($perm_menus[$account->uid])) {
+ $perm_menus[$account->uid] = array();
+
+ $menus = menu_get_menus();
+ foreach ($menus as $name => $title) {
+ if (user_access('administer ' . $name . ' menu items', $account)) {
+ $perm_menus[$account->uid][$name] = $name;
+ }
+ }
+
+ drupal_alter('menu_admin_per_menu_perm_menus', $perm_menus[$account->uid], $account);
+ }
+
+ return $perm_menus[$account->uid];
}
/**
- * Implementation of hook_form_FORM_ID_alter()
+ * Implements hook_form_FORM_ID_alter() for menu_edit_item().
*/
function menu_admin_per_menu_form_menu_edit_item_alter(&$form, &$form_state, $form_id) {
if (isset($form['parent']) && !user_access('administer menu') && _menu_admin_per_menu_filter_parent_options($form)) {
diff --git a/sites/all/modules/contrib/menu/menu_editor/me_node_creation/lib/CrumbsMonoPlugin.php b/sites/all/modules/contrib/menu/menu_editor/me_node_creation/lib/CrumbsMonoPlugin.php
index af7739ae..91e2b19d 100644
--- a/sites/all/modules/contrib/menu/menu_editor/me_node_creation/lib/CrumbsMonoPlugin.php
+++ b/sites/all/modules/contrib/menu/menu_editor/me_node_creation/lib/CrumbsMonoPlugin.php
@@ -1,12 +1,29 @@
setTitle('Set breadcrumbs for placeholder pages.');
}
+ /**
+ * Find candidates for the parent path.
+ *
+ * @param string $path
+ * The path that we want to find a parent for.
+ * @param array $item
+ * Item as returned from crumbs_get_router_item()
+ *
+ * @return string
+ * Parent path candidate.
+ */
function findParent($path, $item) {
switch ($item['route']) {
case 'node/add/%/mlid/%':
@@ -16,5 +33,7 @@ class me_node_creation_CrumbsMonoPlugin implements crumbs_MonoPlugin {
// Let the menu.hierarchy.* plugin do its thing
break;
}
+
+ return NULL;
}
}
diff --git a/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.create.inc b/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.create.inc
index 3da1e966..ac5ce392 100644
--- a/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.create.inc
+++ b/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.create.inc
@@ -1,10 +1,14 @@
$type->name)), PASS_THROUGH);
@@ -24,8 +28,11 @@ function me_node_creation_create_node($type, $menu_item) {
return $form;
}
-
-function _me_node_creation_form_alter(&$form, $node) {
+/**
+ * @param array $form
+ * @param object $node
+ */
+function _me_node_creation_form_alter(array &$form, $node) {
$menu_item = $node->me_node_creation_menu_item;
unset($form['menu']);
@@ -39,7 +46,7 @@ function _me_node_creation_form_alter(&$form, $node) {
}
$txt = t('The created node will be associated with the chosen menu item (!mlid), with link title "@title"', array(
- '!mlid' => $mlid_text,
+ '!mlid' => $mlid_text,
'@title' => $menu_item['link_title'],
));
$txt = "
$txt
";
diff --git a/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.info b/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.info
index 05e0477c..6eb7d937 100644
--- a/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.info
+++ b/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.info
@@ -6,9 +6,9 @@ dependencies[] = menu_editor
; xautoload for the crumbs plugin
dependencies[] = xautoload
-; Information added by drupal.org packaging script on 2013-10-01
-version = "7.x-1.0-beta3+0-dev"
+; Information added by Drupal.org packaging script on 2016-11-06
+version = "7.x-1.0-beta4"
core = "7.x"
project = "menu_editor"
-datestamp = "1380586819"
+datestamp = "1478399941"
diff --git a/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.module b/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.module
index e4cfb469..ef3adf3a 100644
--- a/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.module
+++ b/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.module
@@ -1,6 +1,5 @@
array(2, 4),
'title' => 'Create a node',
+ /* @see me_node_creation_create_node() */
'page callback' => 'me_node_creation_create_node',
'page arguments' => array(2, 4),
'file' => 'me_node_creation.create.inc',
+ /* @see me_node_creation_create_node_access() */
'access callback' => 'me_node_creation_create_node_access',
'access arguments' => array(2),
);
+ /* @see menu_editor_menu_link_load() */
$items['mlid/%menu_editor_menu_link/under-construction'] = array(
'title' => 'Under Construction',
+ /* @see menu_editor_placeholder_title() */
'title callback' => 'menu_editor_placeholder_title',
'title arguments' => array(1),
+ /* @see menu_editor_placeholder_page() */
'page callback' => 'menu_editor_placeholder_page',
'page arguments' => array(1),
'file' => 'me_node_creation.placeholder.inc',
@@ -40,11 +45,14 @@ function me_node_creation_menu() {
return $items;
}
-
/**
* Implements hook_form_alter()
+ *
+ * @param array $form
+ * @param array $form_state
+ * @param string $form_id
*/
-function me_node_creation_form_alter(&$form, &$form_state, $form_id) {
+function me_node_creation_form_alter(array &$form, array &$form_state, $form_id) {
if (empty($form['#node_edit_form']) || empty($form['#node'])) {
return;
}
@@ -53,12 +61,14 @@ function me_node_creation_form_alter(&$form, &$form_state, $form_id) {
return;
}
module_load_include('create.inc', 'me_node_creation');
- return _me_node_creation_form_alter($form, $node);
+ form_load_include($form_state, 'inc', 'node', 'node.pages');
+ _me_node_creation_form_alter($form, $node);
}
-
/**
* Implements hook_node_insert()
+ *
+ * @param object $node
*/
function me_node_creation_node_insert($node) {
$menu_item = @$node->me_node_creation_menu_item;
@@ -77,9 +87,10 @@ function me_node_creation_node_insert($node) {
}
}
-
/**
* Implements hook_crumbs_plugins()
+ *
+ * @param crumbs_InjectedAPI_hookCrumbsPlugins $api
*/
function me_node_creation_crumbs_plugins($api) {
$api->monoPlugin();
@@ -89,12 +100,15 @@ function me_node_creation_crumbs_plugins($api) {
// Wildcard loaders
// -----------------------------------------------------------------------------
-
/**
* Wildcard loader for %menu_editor_menu_link
* This is similar to menu_link_load(), but we do some loop prevention.
*
* TODO: Test if the by-reference does not explode in some edge cases.
+ *
+ * @param int $mlid
+ *
+ * @return bool
*/
function menu_editor_menu_link_load($mlid) {
static $_cache = array();
@@ -124,10 +138,9 @@ function menu_editor_menu_link_load($mlid) {
// Title callbacks
// -----------------------------------------------------------------------------
-
/**
* Title callback for mlid/%menu_link/under-construction
- *
+ *
* @param array $item
* The menu link, as returned by menu_link_load()
* @return string
@@ -138,30 +151,38 @@ function menu_editor_placeholder_title($item) {
return $item['link_title'];
}
-
/**
* Title for menu links or tabs.
* The page title can be different!
- *
- * @param $type_arg
- * @param $item
+ *
+ * @param string $type_arg
+ * @param array|mixed $item
+ *
+ * @return string
+ *
+ * @todo This is currently not in use anywhere, and not useful as-is.
*/
function me_node_creation_title($type_arg, $item) {
+ // @todo This is a stupid way to get a node type label.
foreach (node_type_get_types() as $type_name => $type_object) {
- if ($type_name == $type_arg) {
+ if ($type_name === $type_arg) {
+ // @todo This should use t() with @placeholder.
return "New $type_object->name";
}
}
- return $type->name;
+ return t('Create node of unknown type');
}
// Access callbacks
// -----------------------------------------------------------------------------
-
/**
* Access callback for node/add/%node_type/mlid/%menu_editor_mlid
+ *
+ * @param object|mixed $type
+ *
+ * @return bool
*/
function me_node_creation_create_node_access($type) {
if (!is_object($type)) {
@@ -175,9 +196,8 @@ function me_node_creation_create_node_access($type) {
// Utility
// -----------------------------------------------------------------------------
-
/**
- * @return array
+ * @return string[]
* Array of placeholders
*/
function me_node_creation_menu_editor_placeholders() {
diff --git a/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.placeholder.inc b/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.placeholder.inc
index 5bcdc9e8..8793ab33 100644
--- a/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.placeholder.inc
+++ b/sites/all/modules/contrib/menu/menu_editor/me_node_creation/me_node_creation.placeholder.inc
@@ -1,11 +1,11 @@
'Menu path autocomplete',
'description' => 'Autocomplete callback for menu path autocomplete',
+ /* @see me_path_autocomplete() */
'page callback' => 'me_path_autocomplete',
'access callback' => 'user_access',
'access arguments' => array('access content'),
@@ -30,76 +32,142 @@ function me_path_autocomplete_menu() {
}
/**
- * Find nodes and URL aliases based on title.
- * @param $string
+ * Page callback for 'mepac/autocomplete'.
+ *
+ * Finds nodes and URL aliases based on title.
+ * Sets a http header, and prints json output.
+ *
+ * @param string $string
* Title of element to find.
- * @return
- * List of elements with path as key.
+ *
+ * @see mpac_autocomplete()
*/
function me_path_autocomplete($string = NULL) {
$args = func_get_args();
$string = implode('/', $args);
- $string = strtolower($string);
- $title = filter_xss_admin($string);
- $matches = array();
- // $matches[$string] = $string;
+ $matches = _me_path_autocomplete_get_matches($string);
+
+ drupal_json_output($matches);
+}
+
+/**
+ * @param string $string
+ *
+ * @return string[]
+ */
+function _me_path_autocomplete_get_matches($string) {
+ $string = strtolower($string);
+
+ // @todo Do we need to filter this?
+ // See https://www.drupal.org/node/2785261 in mpac issue queue.
+ # $title = filter_xss_admin($string);
+
+ $matches = _me_path_autocomplete_get_matches_for_placeholders($string);
+
+ if ($string === '') {
+ return $matches;
+ }
+
+ $like_placeholder = (strlen($string) > 3) ? "%" . db_like($string) . "%" : db_like($string) . "%";
+
+ $matches += _me_path_autocomplete_get_matches_for_nodes($like_placeholder);
+ $matches += _me_path_autocomplete_get_matches_for_aliases($like_placeholder);
+
+ return $matches;
+}
+
+/**
+ * @param string $string
+ *
+ * @return string[]
+ *
+ * @see _mpac_get_matches_for_nodes()
+ */
+function _me_path_autocomplete_get_matches_for_placeholders($string) {
+
+ $matches = array();
+ /* @see hook_menu_editor_placeholders() */
foreach (module_invoke_all('menu_editor_placeholders') as $placeholder_code => $placeholder_path) {
- if (!strlen($string) || count(explode($string, $placeholder_code)) > 1) {
+ if ($string === '' || false !== strpos($placeholder_code, $string)) {
$matches[$placeholder_code] = htmlentities($placeholder_code);
}
}
-
- // Get a list of all nodes where the title matches the given string.
- if (strlen($string) > 1) {
- $like_placeholder = (strlen($string) > 3) ? "%" . db_like($string) . "%" : db_like($string) . "%";
- $nodes = db_select('node', 'n')
- ->fields('n')
- ->condition('title', $like_placeholder, 'LIKE')
- ->range(0, 8)
- ->execute();
+ return $matches;
+}
- foreach ($nodes as $node) {
- // Add node path and title to list.
- if (node_access('view', $node) && $node->status) {
- $node_title = check_plain($node->title);
- $nid = $node->nid;
- $lang = $node->language != LANGUAGE_NONE ? ($node->language . ': ') : '';
- $matches['node/'. $node->nid] = $lang . "$node_title [nid:$nid]";
- }
- }
- if (module_exists('path')) {
- // Get a list of all URL aliases where the destination matches the given
- // string.
- $aliases = db_select('url_alias')
- ->fields('url_alias')
- ->condition('alias', $like_placeholder, 'LIKE')
- ->range(0, 8)
- ->execute();
+/**
+ * @param string $like_placeholder
+ *
+ * @return string[]
+ *
+ * @see _mpac_get_matches_for_nodes()
+ */
+function _me_path_autocomplete_get_matches_for_nodes($like_placeholder) {
- foreach ($aliases as $alias) {
- // Add alias source and destination to list (and add a special marker to
- // the item).
- $lang = $alias->language != LANGUAGE_NONE ? ($alias->language . ': ') : '';
- $src = check_plain($alias->source);
- $dst = check_plain($alias->alias);
- $matches[$alias->source] = $lang . "$dst | $src";
- }
+ $q = db_select('node', 'n');
+ $q->fields('n');
+ $q->condition('title', $like_placeholder, 'LIKE');
+ $q->range(0, 8);
+
+ $matches = array();
+ foreach ($q->execute() as $node) {
+ // Add node path and title to list.
+ if (node_access('view', $node) && $node->status) {
+ $node_title = check_plain($node->title);
+ $nid = $node->nid;
+ $lang = $node->language !== LANGUAGE_NONE ? ($node->language . ': ') : '';
+ $matches['node/'. $node->nid] = $lang . "$node_title [nid:$nid]";
}
}
-
- drupal_json_output($matches);
+
+ return $matches;
+}
+
+/**
+ * @param string $like_placeholder
+ *
+ * @return string[]
+ *
+ * @see _mpac_get_matches_for_aliases()
+ */
+function _me_path_autocomplete_get_matches_for_aliases($like_placeholder) {
+
+ if (!module_exists('path')) {
+ return array();
+ }
+
+ // Get a list of all URL aliases where the destination matches the given
+ // string.
+ $q = db_select('url_alias');
+ $q->fields('url_alias');
+ $q->condition('alias', $like_placeholder, 'LIKE');
+ $q->range(0, 8);
+
+ $matches = array();
+ foreach ($q->execute() as $alias) {
+ // Add alias source and destination to list (and add a special marker to
+ // the item).
+ $lang = $alias->language !== LANGUAGE_NONE ? ($alias->language . ': ') : '';
+ $src = check_plain($alias->source);
+ $dst = check_plain($alias->alias);
+ $matches[$alias->source] = $lang . "$dst | $src";
+ }
+
+ return $matches;
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Change path field to autocomplete field.
+ *
+ * @param array $form
+ * @param array $form_state
*/
-function me_path_autocomplete_form_menu_editor_overview_form_alter(&$form, &$form_state) {
+function me_path_autocomplete_form_menu_editor_overview_form_alter(array &$form, array &$form_state) {
foreach (element_children($form) as $element_key) {
$form[$element_key]['link_path']['#autocomplete_path'] = 'mepac/autocomplete';
}
}
-
diff --git a/sites/all/modules/contrib/menu/menu_editor/menu_editor.admin.inc b/sites/all/modules/contrib/menu/menu_editor/menu_editor.admin.inc
index c81ff8ae..5f5c8fc4 100644
--- a/sites/all/modules/contrib/menu/menu_editor/menu_editor.admin.inc
+++ b/sites/all/modules/contrib/menu/menu_editor/menu_editor.admin.inc
@@ -1,14 +1,23 @@
TRUE);
$form['#multilingual_menu'] = FALSE;
@@ -34,12 +43,12 @@ function menu_editor_overview_form($form, &$form_state, $menu) {
$max_root_weight = _menu_editor_overview_tree_form($form, $form_state, $tree);
- // default values for all new menu items..
+ // default form values for all new menu items..
$default_values = array(
'link_title' => '',
'link_path' => '',
'description' => '',
- 'hidden' => true,
+ 'enabled' => true,
'expanded' => false,
'weight' => 0,
// 'mlid' => NULL, // this is different for every single one
@@ -53,19 +62,22 @@ function menu_editor_overview_form($form, &$form_state, $menu) {
break;
}
-
- for ($i=0; $i<8; ++$i) {
+ for ($i = 0; $i < 8; ++$i) {
// new menu item
$default_values['mlid'] = 'new' . $i;
- $item_key = 'mlid-new'.$i;
- $form[$item_key] = _menu_editor_overview_tree_form_item('new'.$i, $default_values, $form['#multilingual_menu']);
+ $item_key = 'mlid-new' . $i;
+ $form[$item_key] = _menu_editor_overview_tree_form_item('new' . $i, $default_values, $form['#multilingual_menu']);
$form[$item_key]['weight']['#default_value'] = $max_root_weight + $i + 1;
- $form[$item_key]['#item'] = array();
+ $form[$item_key]['#item'] = array(
+ 'module' => 'menu',
+ 'hidden' => 0,
+ 'menu_name' => $menu['menu_name'],
+ );
$form[$item_key]['#attributes'] = array('class' => 'menu-new');
$form[$item_key]['drag']['#markup'] = t('New menu item');
}
- $form['#menu'] = $menu;
+ $form['#menu'] = $menu;
if (element_children($form)) {
$form['submit'] = array(
'#type' => 'submit',
@@ -79,18 +91,25 @@ function menu_editor_overview_form($form, &$form_state, $menu) {
return $form;
}
-
/**
* Recursive helper function for menu_overview_form().
+ *
+ * @param array $form
+ * @param array $form_state
+ * @param array $tree
+ *
+ * @return int
+ * The max root weight (whatever this means)
*/
-function _menu_editor_overview_tree_form(&$form, &$form_state, $tree) {
+function _menu_editor_overview_tree_form(array &$form, array &$form_state, array $tree) {
$max_root_weight = 0;
foreach ($tree as $data) {
$title = '';
$item = $data['link'];
// Don't show callbacks; these have $item['hidden'] < 0.
if ($item && $item['hidden'] >= 0) {
- $item_key = 'mlid-'. $item['mlid'];
+ $item_key = 'mlid-' . $item['mlid'];
+ // @todo This is bogus. The value might be in $form_state['input'][$item_key], but never in $form_state[$item_key].
$weight = isset($form_state[$item_key]['weight']) ? $form_state[$item_key]['weight'] : $item['weight'];
$plid = isset($form_state[$item_key]['plid']) ? $form_state[$item_key]['plid'] : $item['plid'];
@@ -101,24 +120,30 @@ function _menu_editor_overview_tree_form(&$form, &$form_state, $tree) {
$path = $item['link_path'];
if (!empty($item['options']['query'])) {
if (is_array($item['options']['query'])) {
- $path .= '?'. drupal_http_build_query($item['options']['query']);
+ $path .= '?' . drupal_http_build_query($item['options']['query']);
}
else {
// Query could be a string, due to a malfunction in previous versions of this module.
- $path .= '?'. $item['options']['query'];
+ $path .= '?' . $item['options']['query'];
}
}
if (isset($item['options']['fragment'])) {
- $path .= '#'. $item['options']['fragment'];
+ $path .= '#' . $item['options']['fragment'];
}
+
+ /* @see menu_firstchild_form_alter() */
+ if (isset($item['href']) && '' === $item['href']) {
+ $item['hidden'] = !empty($item['options']['unaltered_hidden']);
+ }
+
$default_values = array(
'link_title' => $item['link_title'],
'link_path' => $path,
'description' => isset($item['options']['attributes']['title']) ? $item['options']['attributes']['title'] : '',
- 'hidden' => !$item['hidden'],
+ 'enabled' => !$item['hidden'],
'expanded' => $item['expanded'],
- 'weight' => $weight,
- 'plid' => $plid,
+ 'weight' => $weight,
+ 'plid' => $plid,
'depth' => 1,
);
@@ -180,7 +205,7 @@ function _menu_editor_overview_tree_form(&$form, &$form_state, $tree) {
}
// Only items created by the menu module can be deleted.
- if ($item['module'] == 'menu' || $item['updated'] == 1) {
+ if ($item['module'] === 'menu' || (string)$item['updated'] === '1') {
$form[$item_key]['delete'] = array(
'#type' => 'checkbox',
'#title' => t('delete'),
@@ -191,17 +216,23 @@ function _menu_editor_overview_tree_form(&$form, &$form_state, $tree) {
// process child elements
if ($data['below']) {
- _menu_editor_overview_tree_form($form, $form_data, $data['below']);
+ _menu_editor_overview_tree_form($form, $form_state, $data['below']);
}
}
return $max_root_weight;
}
-
+/**
+ * @param int|string $item_mlid
+ * @param array $default_values
+ * @param bool $multilingual_menu
+ *
+ * @return array
+ */
function _menu_editor_overview_tree_form_item($item_mlid, $default_values, $multilingual_menu = FALSE) {
foreach (menu_editor_get_placeholders() as $code => $path) {
- if (str_replace('@mlid', $item_mlid, $path) == $default_values['link_path']) {
+ if (str_replace('@mlid', $item_mlid, $path) === $default_values['link_path']) {
$default_values['link_path'] = $code;
}
}
@@ -210,10 +241,12 @@ function _menu_editor_overview_tree_form_item($item_mlid, $default_values, $mult
$element['link_title'] = array(
'#type' => 'textfield',
'#size' => 25,
+ '#maxlength' => 128,
);
$element['link_path'] = array(
'#type' => 'textfield',
'#size' => 25,
+ '#maxlength' => 255,
);
$element['description'] = array(
'#type' => 'textarea',
@@ -221,7 +254,7 @@ function _menu_editor_overview_tree_form_item($item_mlid, $default_values, $mult
'#rows' => 1,
'#resizable' => FALSE,
);
- $element['hidden'] = array(
+ $element['enabled'] = array(
'#type' => 'checkbox',
);
$element['expanded'] = array(
@@ -255,22 +288,31 @@ function _menu_editor_overview_tree_form_item($item_mlid, $default_values, $mult
return $element;
}
-
/**
* Weight textfield validation function
* Stolen from http://drupal.org/project/tiny_menu_editor
* Big thanks to Dmitriy.trt
+ *
+ * @param array $element
+ * @param array $form_state
*/
-function _menu_editor_valid_weight($element, &$form_state) {
+function _menu_editor_valid_weight(array $element, array &$form_state) {
if ((isset($element['#value']) && $element['#value'] !== '') || !empty($element['#required'])) {
if (!preg_match('/^\-?\d+$/', $element['#value'])) {
- form_error($element, t('Weight has to be an integer value.'));
+ form_error($element, t('Weight has to be an integer value.'));
}
}
}
-
-function menu_editor_overview_form_validate($form, &$form_state) {
+/**
+ * Form validation callback for menu_editor_overview_form.
+ *
+ * @param array $form
+ * @param array $form_state
+ *
+ * @see menu_editor_overview_form()
+ */
+function menu_editor_overview_form_validate(array $form, array &$form_state) {
$form_values = &$form_state['values'];
// Check existing items.
@@ -295,11 +337,14 @@ function menu_editor_overview_form_validate($form, &$form_state) {
}
}
-
/**
* Validate form values for a menu link being added or edited.
+ *
+ * @param array $element
+ * @param string $link_path
+ * @param string $error_key_prefix
*/
-function menu_editor_validate_item(&$element, $link_path, $error_key_prefix) {
+function menu_editor_validate_item(array &$element, $link_path, $error_key_prefix) {
$placeholders = menu_editor_get_placeholders();
if (isset($placeholders[$link_path])) {
// it would be hard to check access,
@@ -308,7 +353,7 @@ function menu_editor_validate_item(&$element, $link_path, $error_key_prefix) {
return;
}
- if ($element['link_path']['#default_value'] == $link_path) {
+ if ($element['link_path']['#default_value'] === $link_path) {
// link_path is the only field that we check,
// and we don't complain about existing link paths.
return;
@@ -334,27 +379,32 @@ function menu_editor_validate_item(&$element, $link_path, $error_key_prefix) {
}
}
-
/**
- * validate a menu item that was dynamically added through javascript
- *
- * @param unknown_type $item
+ * Validates a menu item that was dynamically added through javascript.
+ *
+ * @param array|mixed $item
+ *
+ * @return bool
*/
function menu_editor_overview_form_validate_new_item($item) {
// TODO: add some sanity checks
return true;
}
-
/**
* Submit handler for the menu overview form.
*
* This function takes great care in saving parent items first, then items
* underneath them. Saving items in the incorrect order can break the menu tree.
*
- * @see menu_overview_form()
+ * @param array $form
+ * @param array $form_state
+ *
+ * @see menu_editor_overview_form()
+ * @see menu_overview_form_submit()
+ * @see menu_edit_item_submit()
*/
-function menu_editor_overview_form_submit($form, &$form_state) {
+function menu_editor_overview_form_submit(array $form, array &$form_state) {
// When dealing with saving menu items, the order in which these items are
// saved is critical. If a changed child item is saved before its parent,
@@ -373,7 +423,9 @@ function menu_editor_overview_form_submit($form, &$form_state) {
foreach ($form_values as $item_key => $v) {
if (isset($form[$item_key]['#item'])) {
$element = $form[$item_key];
- if (!is_numeric($v['mlid'])) {
+ $original_item = $item = $element['#item'];
+
+ if (!isset($item['mlid'])) {
// add new item
unset($v['mlid']);
if (!is_string($v['link_title']) || empty($v['link_title'])) {
@@ -382,42 +434,51 @@ function menu_editor_overview_form_submit($form, &$form_state) {
if (!is_string($v['link_path']) || empty($v['link_path'])) {
continue;
}
- $element['#item']['menu_name'] = $menu_name;
+ $item['menu_name'] = $menu_name;
// Set all fields in this menu item.
foreach ($fields as $field) {
- // Check if field is set since some fields could not be NULL when
+ // Check if field is set since some fields could not be NULL when
// doing menu_link_save().
if (isset($v[$field])) {
- $element['#item'][$field] = $v[$field];
+ $item[$field] = $v[$field];
}
}
- $updated_items[$item_key] = $element['#item'];
- } else if (!empty($v['delete'])) {
+ $updated_items[$item_key] = $item;
+ }
+ elseif (!empty($v['delete'])) {
// delete existing item
- if (is_numeric($v['mlid'])) {
- menu_link_delete($v['mlid']);
+ if (is_numeric($item['mlid'])) {
+ menu_link_delete($item['mlid']);
}
continue;
- } else {
+ }
+ else {
// update existing item
// Update any fields that have changed in this menu item.
foreach ($fields as $field) {
+ // Using != instead of !== to support '5' == 5.
+ /** @noinspection TypeUnsafeComparisonInspection */
if ($v[$field] != $element[$field]['#default_value']) {
- $element['#item'][$field] = $v[$field];
- $updated_items[$item_key] = $element['#item'];
+ $item[$field] = $v[$field];
+ $updated_items[$item_key] = $item;
}
}
}
+
// Hidden is a special case, the value needs to be inverted.
// Besides, while we operate with boolean, the database wants numeric 0/1.
- if ($v['hidden'] xor $element['hidden']['#default_value']) {
- $element['#item']['hidden'] = empty($v['hidden']) ? 1 : 0;
+ if ($v['enabled'] xor $element['enabled']['#default_value']) {
+ // Checkbox for 'enabled' was changed.
+ $element['#item']['hidden'] = empty($v['enabled']) ? 1 : 0;
$updated_items[$item_key] = $element['#item'];
}
+ else {
+ // Checkbox for 'enabled' was not changed.
+ }
// langcode is a special case as well
if (!empty($form['#multilingual_menu'])) {
$langcode = isset($element['language']['#default_value']) ? $element['language']['#default_value'] : $element['language']['#value'];
- if ($v['language'] != $langcode) {
+ if ($v['language'] !== $langcode) {
$element['#item']['language'] = $v['language'];
$updated_items[$item_key] = $element['#item'];
}
@@ -477,7 +538,7 @@ function menu_editor_overview_form_submit($form, &$form_state) {
unset($item['options']['fragment']);
}
- if ($link_path != $parsed_link['path']) {
+ if ($link_path !== $parsed_link['path']) {
$link_path = $parsed_link['path'];
}
}
@@ -497,6 +558,12 @@ function menu_editor_overview_form_submit($form, &$form_state) {
}
}
+ // @see menu_firstchild_menu_link_alter() expects $link['module'] to be set.
+ $item += array(
+ 'module' => 'menu',
+ 'hidden' => 0,
+ );
+
$mlid = menu_link_save($item);
if (is_numeric($mlid)) {
@@ -519,18 +586,18 @@ function menu_editor_overview_form_submit($form, &$form_state) {
}
}
-
-
-
-
/**
* Theme the menu overview form into a table.
*
+ * @param array $variables
+ *
+ * @return string
+ *
* @ingroup themeable
*/
-function theme_menu_editor_overview_form($variables) {
+function theme_menu_editor_overview_form(array $variables) {
$form = $variables['form'];
- drupal_add_css(drupal_get_path('module', 'menu_editor') .'/menu_editor.css');
+ drupal_add_css(drupal_get_path('module', 'menu_editor') . '/menu_editor.css');
drupal_add_js(drupal_get_path('module', 'menu_editor') . '/menu_editor.js');
global $language;
$i18n_menu = $form['#multilingual_menu'] || $form['#translatable_nodes'];
@@ -548,13 +615,13 @@ function theme_menu_editor_overview_form($variables) {
if ($i18n_menu) {
$header[] = t('Language');
}
- $header[] = array('data' => t('Delete'), 'class' => 'delete-checkbox');
+ $header[] = array('data' => t('Delete'), 'class' => 'delete-checkbox');
$rows = array();
$items = array();
foreach (element_children($form) as $item_key) {
- if (isset($form[$item_key]['hidden'])) {
+ if (isset($form[$item_key]['enabled'])) {
$element = &$form[$item_key];
// Add special classes to be used for tabledrag.js.
@@ -566,7 +633,7 @@ function theme_menu_editor_overview_form($variables) {
$element['plid']['#type'] = 'hidden';
// Adjust tab index to allow vertical tabbing
- foreach (array('link_title', 'link_path', 'description', 'hidden', 'expanded') as $i => $key) {
+ foreach (array('link_title', 'link_path', 'description', 'enabled', 'expanded') as $i => $key) {
$element[$key]['#attributes']['tabindex'] = $i+2;
}
$element['link_path']['#attributes']['tabindex'] = 2;
@@ -581,7 +648,7 @@ function theme_menu_editor_overview_form($variables) {
$cells['link_title'] = array('data' => drupal_render($element['link_title']), 'class' => 'title-edit');
$cells['link_path'] = array('data' => drupal_render($element['link_path']), 'class' => 'path-edit');
$cells['description'] = array('data' => drupal_render($element['description']), 'class' => 'description');
- $cells['hidden'] = array('data' => drupal_render($element['hidden']), 'class' => 'checkbox');
+ $cells['enabled'] = array('data' => drupal_render($element['enabled']), 'class' => 'checkbox');
$cells['expanded'] = array('data' => drupal_render($element['expanded']), 'class' => 'checkbox');
$cells['mlid'] = drupal_render($element['weight']) . drupal_render($element['plid']) . drupal_render($element['mlid']);
if ($i18n_menu) {
@@ -598,8 +665,8 @@ function theme_menu_editor_overview_form($variables) {
$row['class'] = array('draggable');
if ($i18n_menu) {
$langcode = isset($element['language']['#default_value']) ? $element['language']['#default_value'] : $element['language']['#value'];
- $row['class'][] = ($langcode != LANGUAGE_NONE) ? 'langcode-'.$langcode : 'all-languages';
- $row['class'][]= ($langcode == $language->language) ? 'active-language' : '';
+ $row['class'][] = ($langcode !== LANGUAGE_NONE) ? 'langcode-'.$langcode : 'all-languages';
+ $row['class'][]= ($langcode === $language->language) ? 'active-language' : '';
}
$rows[$item_key] = $row;
}
@@ -611,4 +678,3 @@ function theme_menu_editor_overview_form($variables) {
$output .= drupal_render_children($form);
return $output;
}
-
diff --git a/sites/all/modules/contrib/menu/menu_editor/menu_editor.api.php b/sites/all/modules/contrib/menu/menu_editor/menu_editor.api.php
new file mode 100644
index 00000000..e14cd519
--- /dev/null
+++ b/sites/all/modules/contrib/menu/menu_editor/menu_editor.api.php
@@ -0,0 +1,10 @@
+' => 'mlid/@mlid/under-construction',
+ );
+}
diff --git a/sites/all/modules/contrib/menu/menu_editor/menu_editor.css b/sites/all/modules/contrib/menu/menu_editor/menu_editor.css
index 74692ebc..99935ba5 100644
--- a/sites/all/modules/contrib/menu/menu_editor/menu_editor.css
+++ b/sites/all/modules/contrib/menu/menu_editor/menu_editor.css
@@ -53,4 +53,3 @@ form#menu-editor-overview-form .focus-description-column tr.focus td.description
form#menu-editor-overview-form .focus-description-column tr.focus td.description textarea {
height:60px !important;
}
-
diff --git a/sites/all/modules/contrib/menu/menu_editor/menu_editor.info b/sites/all/modules/contrib/menu/menu_editor/menu_editor.info
index 18ba122a..2754b40c 100644
--- a/sites/all/modules/contrib/menu/menu_editor/menu_editor.info
+++ b/sites/all/modules/contrib/menu/menu_editor/menu_editor.info
@@ -4,10 +4,9 @@ package = Menu
core = 7.x
dependencies[] = menu
-
-; Information added by drupal.org packaging script on 2013-10-01
-version = "7.x-1.0-beta3+0-dev"
+; Information added by Drupal.org packaging script on 2016-11-06
+version = "7.x-1.0-beta4"
core = "7.x"
project = "menu_editor"
-datestamp = "1380586819"
+datestamp = "1478399941"
diff --git a/sites/all/modules/contrib/menu/menu_editor/menu_editor.js b/sites/all/modules/contrib/menu/menu_editor/menu_editor.js
index 33e7b0c4..02543428 100644
--- a/sites/all/modules/contrib/menu/menu_editor/menu_editor.js
+++ b/sites/all/modules/contrib/menu/menu_editor/menu_editor.js
@@ -2,31 +2,31 @@
Drupal.behaviors.menuEditor = {
attach: function (context, settings) {
$('#menu-editor-overview-form #menu-overview', context).each(function(){
-
+
// table elements
var table = $(this);
var tbody = $('tbody', this);
-
+
// delete all checkbox
(function(){
var th_delete = $('thead th.delete-checkbox', table);
var master_delete_checkbox = $('');
th_delete.html(' '+th_delete.html()+'');
th_delete.prepend(master_delete_checkbox);
-
+
var onchange = function(){
var checked_now = master_delete_checkbox.attr('checked');
$('tbody td.delete-checkbox :checkbox', table).attr('checked', checked_now);
};
-
+
master_delete_checkbox.change(onchange);
-
+
// IE does not trigger the change event..
if ($.browser.msie) {
master_delete_checkbox.click(onchange);
}
})();
-
+
// freeze width of first column (currently disabled)
if (false) {
var w = $('td.drag', this).width();
@@ -34,7 +34,7 @@
$(this).css('width', w+'px');
});
}
-
+
// get reference css for textareas
var ref_input = $('td.path-edit input', this);
var h = ref_input.height();
@@ -44,12 +44,12 @@
'padding-bottom': ref_input.css('padding-bottom')
};
var div_ref_height = ref_input.parent().height();
-
+
// adjust height of existing description textareas
$('td.description textarea', this).css(ref_css);
// this is necessary because of the vertical-align:middle
$('td.description div.form-item', this).css('height', div_ref_height+'px');
-
+
// description column resizing
$('td.description textarea', this).focus(function(){
table.addClass('focus-description-column');
diff --git a/sites/all/modules/contrib/menu/menu_editor/menu_editor.module b/sites/all/modules/contrib/menu/menu_editor/menu_editor.module
index 1aaee238..61682490 100644
--- a/sites/all/modules/contrib/menu/menu_editor/menu_editor.module
+++ b/sites/all/modules/contrib/menu/menu_editor/menu_editor.module
@@ -33,6 +33,11 @@ function menu_editor_permission() {
return $perm;
}
+/**
+ * @param array $menu
+ *
+ * @return bool
+ */
function menu_editor_form_access($menu) {
return
user_access('administer menu') ||
@@ -55,7 +60,9 @@ function menu_editor_form_access($menu) {
// }
/**
- * Implemenation of hook_theme().
+ * Implements hook_theme().
+ *
+ * @return array[]
*/
function menu_editor_theme() {
return array(
@@ -68,21 +75,33 @@ function menu_editor_theme() {
/**
* Title callback for the menu overview page and links.
+ *
+ * @param array $menu
+ *
+ * @return string
*/
-function menu_editor_overview_title($menu) {
+function menu_editor_overview_title(array $menu) {
return $menu['title'];
}
-
-
+/**
+ * @return string[]
+ */
function menu_editor_get_placeholders() {
static $placeholders;
if (!isset($placeholders)) {
+ /* @see hook_menu_editor_placeholders() */
$placeholders = module_invoke_all('menu_editor_placeholders');
}
return $placeholders;
}
+/**
+ * @param string $placeholder
+ * @param string|int $mlid
+ *
+ * @return string
+ */
function menu_editor_get_path_for_placeholder($placeholder, $mlid) {
$placeholders = menu_editor_get_placeholders();
if (isset($placeholders[$placeholder])) {
diff --git a/sites/all/modules/contrib/users/login_destination/LICENSE.txt b/sites/all/modules/contrib/users/login_destination/LICENSE.txt
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/users/login_destination/MAINTAINERS.txt b/sites/all/modules/contrib/users/login_destination/MAINTAINERS.txt
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/users/login_destination/README.txt b/sites/all/modules/contrib/users/login_destination/README.txt
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/users/login_destination/login_destination.admin.inc b/sites/all/modules/contrib/users/login_destination/login_destination.admin.inc
index a2743ace..684bda51 100755
--- a/sites/all/modules/contrib/users/login_destination/login_destination.admin.inc
+++ b/sites/all/modules/contrib/users/login_destination/login_destination.admin.inc
@@ -6,61 +6,256 @@
*/
/**
- * List destination rules.
+ * Form for editing an entire login destination at once.
+ *
+ * Shows list of all login destination.
*/
-function login_destination_overview() {
+function login_destination_overview_form($form, &$form_state) {
+ // Get all login destination rules from the database.
+ $result = db_select('login_destination', 'l')
+ ->fields('l', array(
+ 'id',
+ 'triggers',
+ 'roles',
+ 'pages_type',
+ 'pages',
+ 'destination',
+ 'weight',
+ 'enabled',
+ ))
+ ->orderBy('weight')
+ ->execute()
+ ->fetchAll();
+
+ $form['#tree'] = TRUE;
+
+ // Loop through the categories and add them to the table.
+ foreach ($result as $data) {
+ $triggers = array_map('check_plain', unserialize($data->triggers));
+ if (empty($triggers)) {
+ $triggers = array();
+ }
+
+ $roles = array_map('check_plain', unserialize($data->roles));
+ if (empty($roles)) {
+ $roles = array();
+ }
+
+ $form[$data->id]['destination']['#markup'] = theme('login_destination_destination', array('destination' => $data->destination));
+ $form[$data->id]['triggers']['#markup'] = theme('login_destination_triggers', array('items' => $triggers));
+ $form[$data->id]['pages']['#markup'] = theme('login_destination_pages', array(
+ 'pages' => $data->pages,
+ 'pages_type' => $data->pages_type,
+ ));
+ $form[$data->id]['roles']['#markup'] = theme('login_destination_roles', array('items' => $roles));
+
+ $form[$data->id]['weight'] = array(
+ '#type' => 'weight',
+ '#title' => t('Weight'),
+ '#delta' => 50,
+ '#default_value' => $data->weight,
+ '#title_display' => 'invisible',
+ );
+
+ $form[$data->id]['enabled'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Enabled'),
+ '#default_value' => $data->enabled,
+ '#title_display' => 'invisible',
+ );
+
+ // Build a list of operations.
+ $operations = array();
+ $operations['edit'] = array(
+ '#type' => 'link',
+ '#title' => t('edit'),
+ '#href' => 'admin/config/people/login-destination/edit/' . $data->id,
+ );
+
+ $operations['delete'] = array(
+ '#type' => 'link',
+ '#title' => t('delete'),
+ '#href' => 'admin/config/people/login-destination/delete/' . $data->id,
+ );
+ $form[$data->id]['operations'] = $operations;
+ }
+
+ if (element_children($form)) {
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save configuration'),
+ );
+ }
+ else {
+ $form['#empty_text'] = t('There is no Login Destination Rule.');
+ }
+
+ return $form;
+}
+
+/**
+ * Returns HTML for a login destination list.
+ *
+ * @param array $variables
+ * An associative array containing:
+ * - form: A render element representing the form.
+ *
+ * @ingroup themeable
+ *
+ * @return string
+ */
+function theme_login_destination_overview_form($variables) {
+ $form = $variables['form'];
+
+ drupal_add_tabledrag('login-destination-overview', 'order', 'sibling', 'login-destination-weight');
+
$header = array(
t('Destination'),
t('Triggers'),
t('Pages'),
t('Roles'),
- array('data' => t('Operations'), 'colspan' => 2),
+ array('data' => t('Enabled'), 'class' => array('checkbox')),
+ t('Weight'),
+ array('data' => t('Operations'), 'colspan' => '2'),
);
+
$rows = array();
+ foreach (element_children($form) as $ldid) {
+ if (!isset($form[$ldid]['enabled'])) {
+ continue;
+ }
+ $element = &$form[$ldid];
+ $operations = array();
- // Get all login destination rules from the database.
- $result = db_select('login_destination', 'l')
- ->fields('l', array('id', 'triggers', 'roles', 'pages_type', 'pages', 'destination'))
- ->orderBy('weight')
- ->execute()
- ->fetchAll();
+ foreach (element_children($element['operations']) as $op) {
+ $operations[] = array(
+ 'data' => drupal_render($element['operations'][$op]),
+ 'class' => array('login-destination-operations'),
+ );
+ }
+ while (count($operations) < 2) {
+ $operations[] = '';
+ }
- // Loop through the categories and add them to the table.
- foreach ($result as $data) {
+ $row = array();
+ $row[] = drupal_render($element['destination']);
+ $row[] = drupal_render($element['triggers']);
+ $row[] = drupal_render($element['pages']);
+ $row[] = drupal_render($element['roles']);
+ $row[] = array(
+ 'data' => drupal_render($element['enabled']),
+ 'class' => array(
+ 'checkbox',
+ 'login-destination-enabled',
+ ),
+ );
- $triggers = array_map('check_plain', unserialize($data->triggers));
- if (empty($triggers))
- $triggers = array();
+ $form[$ldid]['weight']['#attributes']['class'] = array('login-destination-weight');
- $roles = array_map('check_plain', unserialize($data->roles));
- if (empty($roles))
- $roles = array();
+ $row[] = drupal_render($element['weight']);
+ $row = array_merge($row, $operations);
+ $row = array_merge(array('data' => $row), array());
+ $row['class'][] = 'draggable';
+ $rows[] = $row;
+ }
+ $output = '';
+ if (empty($rows)) {
$rows[] = array(
- theme('login_destination_destination', array('destination' => $data->destination)),
- theme('login_destination_triggers', array('items' => $triggers)),
- theme('login_destination_pages', array('pages' => $data->pages, 'pages_type' => $data->pages_type)),
- theme('login_destination_roles', array('items' => $roles)),
- l(t('Edit'), 'admin/config/people/login-destination/edit/' . $data->id),
- l(t('Delete'), 'admin/config/people/login-destination/delete/' . $data->id),
+ array(
+ 'data' => $form['#empty_text'],
+ 'colspan' => '7',
+ ),
);
}
- if (!$rows) {
- $rows[] = array(array(
- 'data' => t('No rules available.'),
- 'colspan' => 6,
- ));
- }
-
- $build['login-destination_table'] = array(
- '#theme' => 'table',
- '#header' => $header,
- '#rows' => $rows,
+ $table_arguments = array(
+ 'header' => $header,
+ 'rows' => $rows,
+ 'attributes' => array(
+ 'id' => 'login-destination-overview',
+ ),
);
- return $build;
+
+ $output .= theme('table', $table_arguments);
+ $output .= drupal_render_children($form);
+
+ return $output;
}
+/**
+ * Submit handler for the login destination overview form.
+ *
+ * This function update the login destination rule attribute
+ * like rules are enabled/disabled or its weight.
+ *
+ * @see login_destination_overview_form()
+ */
+function login_destination_overview_form_submit($form, &$form_state) {
+ $element = &$form_state['values'];
+ foreach (element_children($element) as $ldid) {
+ if (isset($form[$ldid]['enabled'])) {
+ $login_destination_rules[$ldid] = $element[$ldid];
+ $login_destination_rules[$ldid]['ldid'] = $ldid;
+ }
+ }
+
+ foreach ($login_destination_rules as $ldid => $login_destination_rule) {
+ _login_destination_update_rules($login_destination_rule);
+ }
+
+ drupal_set_message(t('Your configuration has been saved.'), 'status');
+}
+
+/**
+ * Save all our changed items to the database.
+ *
+ * @param array $login_destination_rule
+ * An associative array representing a login destination item:
+ * - enabled: (required) can contain 0 or 1, if rule is enabled then
+ * it should be 1 else 0.
+ * - weight: (required) can contain any integer value.
+ *
+ * @return bool
+ * The ldid of the saved login destination rule, or FALSE
+ * if the login destination rule could not be saved.
+ */
+function _login_destination_update_rules($login_destination_rule) {
+
+ if (!(isset($login_destination_rule['enabled']) &&
+ isset($login_destination_rule['weight']) &&
+ isset($login_destination_rule['ldid']))
+ ) {
+ return FALSE;
+ }
+
+ if ($login_destination_rule['enabled'] != 0 &&
+ $login_destination_rule['enabled'] != 1
+ ) {
+ return FALSE;
+ }
+
+ $login_destination_rule['weight'] = (int) $login_destination_rule['weight'];
+
+ if (!is_int($login_destination_rule['weight'])) {
+ return FALSE;
+ }
+
+ db_update('login_destination')
+ ->fields(array(
+ 'enabled' => $login_destination_rule['enabled'],
+ 'weight' => $login_destination_rule['weight'],
+ ))
+ ->condition('id', $login_destination_rule['ldid'])
+ ->execute();
+
+ return $login_destination_rule['ldid'];
+}
+
+/**
+ * Render a destination of login destination rule.
+ */
function theme_login_destination_destination($variables) {
$output = nl2br(check_plain($variables['destination']));
@@ -71,6 +266,9 @@ function theme_login_destination_destination($variables) {
return $output;
}
+/**
+ * Render a trigger of login destination rule.
+ */
function theme_login_destination_triggers($variables) {
$items = array_map('check_plain', $variables['items']);
@@ -82,10 +280,11 @@ function theme_login_destination_triggers($variables) {
foreach ($items as &$item) {
switch ($item) {
case 'login':
- $item = 'Login';
+ $item = t('Login');
break;
+
case 'logout':
- $item = 'Logout';
+ $item = t('Logout');
break;
}
$output .= $item . " ";
@@ -94,9 +293,12 @@ function theme_login_destination_triggers($variables) {
return $output;
}
+/**
+ * Render a page type of login destination rule.
+ */
function theme_login_destination_pages($variables) {
$type = $variables['pages_type'];
-
+
if ($type == LOGIN_DESTINATION_REDIRECT_PHP) {
return nl2br(check_plain($variables['pages']));
}
@@ -120,11 +322,14 @@ function theme_login_destination_pages($variables) {
$output .= "~ ";
}
$output .= $page . " ";
- }
+ }
return $output;
}
+/**
+ * Render a roles of login destination rule.
+ */
function theme_login_destination_roles($variables) {
$items = array_values(array_intersect_key(_login_destination_role_options(), $variables['items']));
@@ -139,7 +344,7 @@ function theme_login_destination_roles($variables) {
* Category edit page.
*/
function login_destination_edit_form($form, &$form_state, array $rule = array()) {
- // default values
+ // Default values.
$rule += array(
'triggers' => array(),
'roles' => array(),
@@ -167,18 +372,28 @@ function login_destination_edit_form($form, &$form_state, array $rule = array())
}
else {
$options = array(
- LOGIN_DESTINATION_STATIC => t('Internal page or external URL'),
- );
- $description = t("Specify page by using its path. Example path is %blog for the blog page. %front is the front page. %current is the current page. Precede with http:// for an external URL. Leave empty to redirect to a default page.", array('%blog' => 'blog', '%front' => '', '%current' => ''));
+ LOGIN_DESTINATION_STATIC => t('Internal page or external URL'),
+ );
+ $description = t("Specify page by using its path. Example path is %blog for the blog page. %front is the front page. %current is the current page. Precede with http:// for an external URL. Leave empty to redirect to a default page.", array(
+ '%blog' => 'blog',
+ '%front' => '',
+ '%current' => '',
+ ));
- if (module_exists('php') && $access) {
+ if ($access && module_exists('php')) {
$options += array(LOGIN_DESTINATION_SNIPPET => t('Page returned by this PHP code (experts only)'));
- $description .= ' ' . t('If the PHP option is chosen, enter PHP code between %php. It should return either a string value or an array of params that the %function function will understand, e.g. %example. For more information, see the online API entry for url function. Note that executing incorrect PHP code can break your Drupal site.', array('%php' => '', '%function' => 'url($path = \'\', array $options = array())', '%example' => ' \'overlay=admin/config\', ), ); ?>', '@url' => 'http://api.drupal.org/api/drupal/includes--common.inc/function/url/7'));
+ $description .= ' ' .
+ t('If the PHP option is chosen, enter PHP code between %php. It should return either a string value or an array of params that the %function function will understand, for example. %example. For more information, see the online API entry for url function. Note that executing incorrect PHP code can break your Drupal site.', array(
+ '%php' => '',
+ '%function' => 'url($path = \'\', array $options = array())',
+ '%example' => ' \'overlay=admin/config\', ), ); ?>',
+ '@url' => 'http://api.drupal.org/api/drupal/includes--common.inc/function/url/7',
+ ));
}
$form['destination_type'] = array(
'#type' => 'radios',
- '#title' => 'Redirect to page',
+ '#title' => t('Redirect to page'),
'#default_value' => $type,
'#options' => $options,
);
@@ -197,9 +412,12 @@ function login_destination_edit_form($form, &$form_state, array $rule = array())
$form['triggers'] = array(
'#type' => 'checkboxes',
'#title' => t('Redirect upon triggers'),
- '#options' => array('login' => 'Login, registration, one-time login link', 'logout' => 'Logout'),
+ '#options' => array(
+ 'login' => t('Login, registration, one-time login link'),
+ 'logout' => t('Logout'),
+ ),
'#default_value' => $triggers,
- '#description' => 'Redirect only upon selected trigger(s). If you select no triggers, all of them will be used.',
+ '#description' => t('Redirect only upon selected trigger(s). If you select no triggers, all of them will be used.'),
);
$type = $rule['pages_type'];
@@ -216,14 +434,22 @@ function login_destination_edit_form($form, &$form_state, array $rule = array())
}
else {
$options = array(
- LOGIN_DESTINATION_REDIRECT_NOTLISTED => t('All pages except those listed'),
- LOGIN_DESTINATION_REDIRECT_LISTED => t('Only the listed pages'),
- );
- $description = t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page. %login is the login form. %register is the registration form. %reset is the one-time login (e-mail validation).", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '', '%login' => 'user', '%register' => 'user/register', '%reset' => 'user/*/edit'));
+ LOGIN_DESTINATION_REDIRECT_NOTLISTED => t('All pages except those listed'),
+ LOGIN_DESTINATION_REDIRECT_LISTED => t('Only the listed pages'),
+ );
+ $description = t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page. %login is the login form. %register is the registration form. %reset is the one-time login (e-mail validation).", array(
+ '%blog' => 'blog',
+ '%blog-wildcard' => 'blog/*',
+ '%front' => '',
+ '%login' => 'user',
+ '%register' => 'user/register',
+ '%reset' => 'user/*/edit',
+ ));
- if (module_exists('php') && $access) {
+ if ($access && module_exists('php')) {
$options += array(LOGIN_DESTINATION_REDIRECT_PHP => t('Pages on which this PHP code returns TRUE (experts only)'));
- $description .= ' ' . t('If the PHP option is chosen, enter PHP code between %php. Note that executing incorrect PHP code can break your Drupal site.', array('%php' => ''));
+ $description .= ' ' .
+ t('If the PHP option is chosen, enter PHP code between %php. Note that executing incorrect PHP code can break your Drupal site.', array('%php' => ''));
}
$form['pages_type'] = array(
@@ -249,14 +475,7 @@ function login_destination_edit_form($form, &$form_state, array $rule = array())
'#title' => t('Redirect users with roles'),
'#options' => _login_destination_role_options(),
'#default_value' => $default_role_options,
- '#description' => 'Redirect only the selected role(s). If you select no roles, all users will be redirected.',
- );
-
- $form['weight'] = array(
- '#type' => 'weight',
- '#title' => t('Weight'),
- '#default_value' => $rule['weight'],
- '#description' => t('When evaluating login destination rules, those with lighter (smaller) weights get evaluated before rules with heavier (larger) weights.'),
+ '#description' => t('Redirect only the selected role(s). If you select no roles, all users will be redirected.'),
);
$form['actions'] = array('#type' => 'actions');
@@ -279,6 +498,26 @@ function login_destination_edit_form($form, &$form_state, array $rule = array())
* Validate the contact category edit page form submission.
*/
function login_destination_edit_form_validate($form, &$form_state) {
+ $destination = $form_state['values']['destination'];
+ $destination_type = $form_state['values']['destination_type'];
+
+ // Check user has enter any path.
+ $available_urls = array('', '');
+ if (empty($destination) || $destination_type != 0 || in_array($destination, $available_urls)) {
+ return;
+ }
+ $destination = preg_replace("/\?.+/", "", $destination);
+ if (url_is_external($destination)) {
+ return;
+ }
+ // Get source path if an alias entered.
+ $source_path = drupal_lookup_path('source', $destination);
+ if (!empty($source_path)) {
+ $destination = $source_path;
+ }
+ if (!drupal_valid_path($destination)) {
+ form_set_error('destination', t('Incorrect path, please enter a valid path.'));
+ }
}
/**
@@ -296,7 +535,7 @@ function login_destination_edit_form_submit($form, &$form_state) {
}
drupal_set_message(t('Login destination to %destination has been saved.', array('%destination' => $form_state['values']['destination'])));
-
+
$form_state['redirect'] = 'admin/config/people/login-destination';
}
@@ -309,14 +548,7 @@ function login_destination_delete_form($form, &$form_state, array $rule) {
'#value' => $rule,
);
- return confirm_form(
- $form,
- t('Are you sure you want to delete the login destination %destination ?', array('%destination' => $rule['destination'])),
- 'admin/config/people/login-destination',
- t('This action cannot be undone.'),
- t('Delete'),
- t('Cancel')
- );
+ return confirm_form($form, t('Are you sure you want to delete the login destination %destination ?', array('%destination' => $rule['destination'])), 'admin/config/people/login-destination', t('This action cannot be undone.'), t('Delete'), t('Cancel'));
}
/**
diff --git a/sites/all/modules/contrib/users/login_destination/login_destination.info b/sites/all/modules/contrib/users/login_destination/login_destination.info
old mode 100755
new mode 100644
index 39aff7f7..7cc6e2db
--- a/sites/all/modules/contrib/users/login_destination/login_destination.info
+++ b/sites/all/modules/contrib/users/login_destination/login_destination.info
@@ -1,13 +1,11 @@
-
name = Login Destination
description = Customize the destination that the user is redirected to after login.
core = 7.x
-files[] = login_destination.module
-files[] = login_destination.admin.inc
configure = admin/config/people/login-destination
-; Information added by drupal.org packaging script on 2012-12-18
-version = "7.x-1.1"
+
+; Information added by Drupal.org packaging script on 2016-01-22
+version = "7.x-1.4"
core = "7.x"
project = "login_destination"
-datestamp = "1355853150"
+datestamp = "1453451940"
diff --git a/sites/all/modules/contrib/users/login_destination/login_destination.install b/sites/all/modules/contrib/users/login_destination/login_destination.install
old mode 100755
new mode 100644
index 0c306e0e..e7b45aa6
--- a/sites/all/modules/contrib/users/login_destination/login_destination.install
+++ b/sites/all/modules/contrib/users/login_destination/login_destination.install
@@ -58,6 +58,13 @@ function login_destination_schema() {
'default' => 0,
'description' => "The rule's weight.",
),
+ 'enabled' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'unsigned' => TRUE,
+ 'default' => 1,
+ 'description' => "The rule enabled/disabled status.",
+ ),
),
'primary key' => array('id'),
'indexes' => array(
@@ -69,12 +76,17 @@ function login_destination_schema() {
}
/**
- * Implementation of hook_install().
+ * Implements hook_install().
*/
function login_destination_install() {
- // update the alter option of 'user/logout' to TRUE (menu_save invokes necessary hooks)
- $result = db_query("SELECT mlid, menu_name FROM {menu_links} WHERE link_path = 'user/logout' OR link_path = 'user/login' OR link_path = 'user' ORDER BY mlid ASC");
- foreach($result as $res) {
+ // Update the alter option of 'user/logout' to TRUE,
+ // (menu_save invokes necessary hooks).
+ $result = db_query("
+ SELECT mlid, menu_name
+ FROM {menu_links}
+ WHERE link_path = 'user/logout' OR link_path = 'user/login' OR link_path = 'user'
+ ORDER BY mlid ASC");
+ foreach ($result as $res) {
$item = menu_link_load($res->mlid);
$item['options']['alter'] = TRUE;
db_update('menu_links')
@@ -87,13 +99,16 @@ function login_destination_install() {
}
/**
- * Implementation of hook_uninstall().
+ * Implements hook_uninstall().
*/
function login_destination_uninstall() {
variable_del('login_destination_preserve_destination');
variable_del('login_destination_profile_redirect');
}
+/**
+ * Implements hook_update_N().
+ */
function login_destination_update_7000() {
$type = variable_get('ld_condition_type', 'always');
$snippet = variable_get('ld_condition_snippet', '');
@@ -117,7 +132,7 @@ function login_destination_update_7000() {
if ($type == 'snippet') {
$form_state['values']['destination_type'] = 1;
- // syntax for return value has changed.
+ // Syntax for return value has changed.
$form_state['values']['destination'] = '';
}
else {
@@ -138,3 +153,44 @@ function login_destination_update_7000() {
variable_del('ld_url_type');
variable_del('ld_url_destination');
}
+
+/**
+ * Implements hook_update_N().
+ */
+function login_destination_update_7001() {
+ $spec = array(
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 1,
+ );
+
+ db_add_field('login_destination', 'enabled', $spec);
+}
+
+/**
+ * Clear hooks cache.
+ */
+function login_destination_update_7002() {
+ cache_clear_all('hook_info', 'cache_bootstrap');
+}
+
+/**
+ * Automatically give all roles with permission "Administer Users" the new dedicated permission
+ * "Administer Login Destination settings".
+ */
+function login_destination_update_7003() {
+ drupal_set_message(t('The Login Destination module has just been updated.
+ A new permission called "Administer Login Destination settings" has now been
+ added. Previously the access to the Login Destination\'s settings page was
+ managed by the "Administer Users" permission. That\'s why all roles with
+ that old permission have been just automatically given the new dedicated
+ "Administer Login Destination settings" permission. If you want to
+ duoble-check things, you can go to the
+ Permissions page now.'));
+
+ $roles = user_roles(TRUE, 'administer users');
+ foreach ($roles as $rid => $role_name) {
+ user_role_grant_permissions($rid, array('administer login destination settings'));
+ }
+}
diff --git a/sites/all/modules/contrib/users/login_destination/login_destination.module b/sites/all/modules/contrib/users/login_destination/login_destination.module
old mode 100755
new mode 100644
index 2ad42624..8757ea38
--- a/sites/all/modules/contrib/users/login_destination/login_destination.module
+++ b/sites/all/modules/contrib/users/login_destination/login_destination.module
@@ -5,30 +5,46 @@
* Control where users are directed to, once they login
*/
-// Page constants
+// Page constants.
define('LOGIN_DESTINATION_REDIRECT_NOTLISTED', 0);
define('LOGIN_DESTINATION_REDIRECT_LISTED', 1);
define('LOGIN_DESTINATION_REDIRECT_PHP', 2);
-// Destination constants
+// Destination constants.
define('LOGIN_DESTINATION_STATIC', 0);
define('LOGIN_DESTINATION_SNIPPET', 1);
/**
- * Implement hook_help().
+ * Implements hook_help().
*/
function login_destination_help($path, $arg) {
switch ($path) {
case 'admin/help#login_destination':
$output = '';
$output .= '
' . t('About') . '
';
- $output .= '
' . t('The Login Destination module allows you to customize the destination that the user is redirected to after logging in, registering to the site, using a one-time login link or logging out. The destination can be an internal page or an external URL. You may specify certain conditions like pages or user roles and make the destination depend upon them. You may also use a PHP snippets to provide custom conditions and destinations. Note that PHP Filter module has to be enabled and you have to be granted the "Use PHP for settings" permissions to be able to enter PHP code.') . '
';
+ $output .= '
' .
+ t('The Login Destination module allows you to customize the destination that the user is redirected to after logging in, registering to the site, using a one-time login link or logging out. The destination can be an internal page or an external URL. You may specify certain conditions like pages or user roles and make the destination depend upon them. You may also use a PHP snippets to provide custom conditions and destinations. Note that PHP Filter module has to be enabled and you have to be granted the "Use PHP for settings" permissions to be able to enter PHP code.') .
+ '
';
return $output;
+
case 'admin/config/people/login-destination':
- return '
' . t('Login destination rules are evaluated each time a user logs in, registers to the site, uses a one-time login link or logs out. Each rule consists of the destination, path conditions and user roles conditions. First matching rule gets executed.') . '
';
+ return '
' .
+ t('Login destination rules are evaluated each time a user logs in, registers to the site, uses a one-time login link or logs out. Each rule consists of the destination, path conditions and user roles conditions. First matching rule gets executed.') .
+ '
';
}
}
+/**
+ * Implements hook_permission().
+ */
+function login_destination_permission() {
+ return array(
+ 'administer login destination settings' => array(
+ 'title' => t('Administer Login Destination settings'),
+ ),
+ );
+}
+
/**
* Implements hook_menu().
*/
@@ -36,8 +52,9 @@ function login_destination_menu() {
$items['admin/config/people/login-destination'] = array(
'title' => 'Login destinations',
'description' => 'Customize the destination that the user is redirected to after login.',
- 'page callback' => 'login_destination_overview',
- 'access arguments' => array('administer users'),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('login_destination_overview_form'),
+ 'access arguments' => array('administer login destination settings'),
'file' => 'login_destination.admin.inc',
'weight' => 10,
);
@@ -45,7 +62,7 @@ function login_destination_menu() {
'title' => 'Add login destination rule',
'page callback' => 'drupal_get_form',
'page arguments' => array('login_destination_edit_form'),
- 'access arguments' => array('administer users'),
+ 'access arguments' => array('administer login destination settings'),
'type' => MENU_LOCAL_ACTION,
'weight' => 1,
'file' => 'login_destination.admin.inc',
@@ -54,14 +71,14 @@ function login_destination_menu() {
'title' => 'Edit login destination rule',
'page callback' => 'drupal_get_form',
'page arguments' => array('login_destination_edit_form', 5),
- 'access arguments' => array('administer users'),
+ 'access arguments' => array('administer login destination settings'),
'file' => 'login_destination.admin.inc',
);
$items['admin/config/people/login-destination/delete/%login_destination'] = array(
'title' => 'Delete login destination rule',
'page callback' => 'drupal_get_form',
'page arguments' => array('login_destination_delete_form', 5),
- 'access arguments' => array('administer users'),
+ 'access arguments' => array('administer login destination settings'),
'file' => 'login_destination.admin.inc',
);
$items['admin/config/people/login-destination/list'] = array(
@@ -74,7 +91,7 @@ function login_destination_menu() {
'description' => 'Change Login Destination settings.',
'page callback' => 'drupal_get_form',
'page arguments' => array('login_destination_settings'),
- 'access arguments' => array('administer users'),
+ 'access arguments' => array('administer login destination settings'),
'type' => MENU_LOCAL_TASK,
'file' => 'login_destination.admin.inc',
'weight' => 10,
@@ -102,12 +119,12 @@ function login_destination_load($id) {
if (empty($result['roles'])) {
$result['roles'] = array();
}
-
+
return $result;
}
/**
- * Implements hook_theme
+ * Implements hook_theme().
*/
function login_destination_theme() {
return array(
@@ -127,22 +144,26 @@ function login_destination_theme() {
'variables' => array('items' => NULL),
'file' => 'login_destination.admin.inc',
),
+ 'login_destination_overview_form' => array(
+ 'file' => 'login_destination.admin.inc',
+ 'render element' => 'form',
+ ),
);
}
/**
- * Implements hook_form_alter
+ * Implements hook_form_alter().
*/
function login_destination_form_alter(&$form, &$form_state, $form_id) {
// We redirect by using the drupal_goto_alter hook. If we simply
- // call drupal_goto() it may break compability with other modules. If we set
+ // call drupal_goto() it may break compatibility with other modules. If we set
// the $_GET['destination'] variable we will loose the possibility to redirect
// to an external URL.
// Please note the the system_goto_action() calls drupal_goto()
// More on this issue http://drupal.org/node/732542.
- // If we add the $form_state['redirect'] here it will be overriden by the
+ // If we add the $form_state['redirect'] here it will be overridden by the
// user_login_submit(). So we add a submit handler instead and will set the
// redirect later. Our submit handler will be executed after the execution
// of user_login_submit(). This is because form_submit() functions are
@@ -152,14 +173,16 @@ function login_destination_form_alter(&$form, &$form_state, $form_id) {
// original submit function from user module.
switch ($form_id) {
- case 'user_register_form': // user register page
- case 'user_login': // user login page
+ // User register page and user login page.
+ case 'user_register_form':
+ case 'user_login':
$form['#validate'][] = 'login_destination_validate';
break;
}
switch ($form_id) {
- case 'user_profile_form': // one-time login, password reset
+ // One-time login, password reset.
+ case 'user_profile_form':
if (isset($_GET['pass-reset-token'])) {
// Redirect only from user_pass_reset
// You have to explicitally turn on the option to always redirect from
@@ -181,20 +204,20 @@ function login_destination_validate($form, &$form_state) {
$_GET['q'] = 'user/register';
}
break;
+
case 'user_login':
if (drupal_match_path($_GET['q'], 'user/register')) {
$_GET['q'] = 'user';
}
break;
}
-
+
// Fix the current page in case of 403 page.
if ($form['#form_id'] == 'user_login') {
- if(drupal_get_http_header('Status') == '403 Forbidden') {
+ if (drupal_get_http_header('Status') == '403 Forbidden') {
$_GET['current'] = $_GET['destination'];
}
}
-
}
/**
@@ -205,7 +228,7 @@ function login_destination_submit($form, &$form_state) {
}
/**
- * Implements hook_menu_link_alter
+ * Implements hook_menu_link_alter().
*/
function login_destination_menu_link_alter(&$item) {
// Flag a link to be altered by hook_translated_menu_link_alter().
@@ -218,24 +241,29 @@ function login_destination_menu_link_alter(&$item) {
}
/**
- * Implements hook_translated_menu_link_alter
+ * Implements hook_translated_menu_link_alter().
*/
function login_destination_translated_menu_link_alter(&$item, $map) {
- global $user;
$paths = array('user/login', 'user');
// Append the current path to URL.
- if ($item['link_path'] == 'user/logout' || (in_array($item['link_path'], $paths) && user_is_anonymous())) {
- $item['localized_options']['query'] = array('current' => $_GET['q']);
+ if ($item['link_path'] == 'user/logout' ||
+ (in_array($item['link_path'], $paths) && user_is_anonymous())
+ ) {
+ $current = $_GET['q'];
+ if ($current == '') {
+ $current = '';
+ }
+ $item['localized_options']['query'] = array('current' => $current);
}
}
/**
- * Implements hook_page_alter
+ * Implements hook_page_alter().
*/
function login_destination_page_alter(&$page) {
// Substitute toolbar's pre_render function to change links.
if (isset($page['page_top']['toolbar']['#pre_render'])) {
- $page['page_top']['toolbar']['#pre_render'][0] = 'login_destination_toolbar_pre_render';
+ $page['page_top']['toolbar']['#pre_render'][] = 'login_destination_toolbar_pre_render';
}
}
@@ -243,23 +271,27 @@ function login_destination_page_alter(&$page) {
* Helper function to change toolbar's links.
*/
function login_destination_toolbar_pre_render($toolbar) {
- $toolbar = toolbar_pre_render($toolbar);
// Add current param to be able to evaluate previous page.
$toolbar['toolbar_user']['#links']['logout']['query'] = array('current' => $_GET['q']);
+
return $toolbar;
}
/**
- * Implements hook_user_login
+ * Implements hook_user_login().
*/
function login_destination_user_login(&$edit, $account) {
- if (!isset($_POST['form_id']) || $_POST['form_id'] != 'user_pass_reset' || variable_get('login_destination_immediate_redirect', FALSE)) {
+ $form_exception = 'user_pass_reset';
+ if (module_exists('change_pwd_page')) {
+ $form_exception = 'change_pwd_page_user_pass_reset';
+ }
+ if (!isset($_POST['form_id']) || $_POST['form_id'] != $form_exception || variable_get('login_destination_immediate_redirect', FALSE)) {
login_destination_perform_redirect('login');
}
}
/**
- * Implements hook_user_insert
+ * Implements hook_user_insert().
*/
function login_destination_user_insert(&$edit, $account, $category) {
global $user;
@@ -272,33 +304,32 @@ function login_destination_user_insert(&$edit, $account, $category) {
}
/**
- * Implements hook_user_logout
+ * Implements hook_user_logout().
*/
function login_destination_user_logout($account) {
login_destination_perform_redirect('logout', _login_destination_get_current('logout'));
}
/**
- * Implements hook_drupal_goto_alter
+ * Implements hook_drupal_goto_alter().
*/
function login_destination_drupal_goto_alter(&$path, &$options, &$http_response_code) {
- // Note that this functionality cannot be backported do 6.x as Drupal 6 does
+ // Note that this functionality cannot be backported to 6.x as Drupal 6 does
// not call drupal_alter for drupal_goto.
// This actually may be used also by templates.
- if (isset($GLOBALS['destination'])) {
- $destination = $GLOBALS['destination'];
+ if (!isset($GLOBALS['destination'])) {
+ return;
+ }
+ $destination = $GLOBALS['destination'];
+ $path = $destination;
- // alter drupal_goto
- if (is_array($destination)) {
- $path = $destination[0];
- $options = array();
- if (count($destination) > 1) {
- $options = $destination[1];
- }
- }
- else {
- $path = $destination;
+ // Alter drupal_goto.
+ if (is_array($destination)) {
+ $path = $destination[0];
+ $options = array();
+ if (count($destination) > 1) {
+ $options = $destination[1];
}
}
}
@@ -307,22 +338,28 @@ function login_destination_drupal_goto_alter(&$path, &$options, &$http_response_
* Pass destination to drupal_goto.
*/
function login_destination_prepare_goto($destination) {
- // Check if $_GET['destination'] should overwrite us
- if (!isset($_GET['destination']) || !variable_get('login_destination_preserve_destination', FALSE)) {
+ // Check if $_GET['destination'] should overwrite us.
+ if (!isset($_GET['destination']) ||
+ !variable_get('login_destination_preserve_destination', FALSE)
+ ) {
$GLOBALS['destination'] = $destination;
}
}
/**
* Evaluate rules and perform redirect.
+ *
* This function is intended to be used by external modules.
- * @param $trigger
- * @param $current if null $_GET['q'] is used
+ *
+ * @param string $trigger
+ * Action of login destination rule.
+ * @param string $current
+ * Path, if null $_GET['q'] is used.
*/
function login_destination_perform_redirect($trigger = '', $current = NULL) {
$destination = login_destination_get_destination($trigger, $current);
- // Check if we redirect
+ // Check if we redirect.
if ($destination !== FALSE) {
login_destination_prepare_goto($destination);
}
@@ -330,31 +367,39 @@ function login_destination_perform_redirect($trigger = '', $current = NULL) {
/**
* Process all destination rules and return destination path.
+ *
* This function is intended to be used by external modules.
*/
function login_destination_get_destination($trigger = '', $current = NULL) {
// Get all the login destination rules from the database.
$result = db_select('login_destination', 'l')
- //->addTag('translatable')
- ->fields('l', array('triggers', 'roles', 'pages_type', 'pages', 'destination_type', 'destination'))
+ ->fields('l', array(
+ 'triggers',
+ 'roles',
+ 'pages_type',
+ 'pages',
+ 'destination_type',
+ 'destination',
+ 'enabled',
+ ))
->orderBy('weight')
->execute()
->fetchAll();
- if ($current == NULL) {
- $current = $_GET['q'];
+ if ($current === NULL) {
+ $current = _login_destination_get_current($trigger);
}
- // examine path matches
+ // Examine path matches.
foreach ($result as $data) {
- // try to match the subsequent rule
+ // Try to match the subsequent rule.
if (_login_destination_match_rule($data, $trigger, $current)) {
// Note: Matching rule with empty destination will cancel redirect.
return _login_destination_evaluate_rule($data, $trigger);
}
}
- // no rule matched
+ // No rule matched.
return FALSE;
}
@@ -370,17 +415,21 @@ function _login_destination_eval($code) {
}
/**
- * A helper function to provide role options
+ * A helper function to provide role options.
*/
function _login_destination_role_options() {
- // user role selection, without anonymous and authentificated user roles.
+ // User role selection, without anonymous user roles.
$role_options = array_map('check_plain', user_roles(TRUE));
- unset($role_options[DRUPAL_AUTHENTICATED_RID]);
return $role_options;
}
/**
* Get the current path (before trigger was invoked).
+ *
+ * @param string $trigger
+ * Trigger.
+ *
+ * @return string
*/
function _login_destination_get_current($trigger = '') {
if (isset($_GET['current'])) {
@@ -391,38 +440,46 @@ function _login_destination_get_current($trigger = '') {
return $_GET['q'];
}
- // front by default
+ // Front by default.
return '';
}
/**
* A helper function to determine whether redirection should happen.
*
- * @return bool TRUE - apply redirect, FALSE - not to apply redirect.
+ * @return bool
+ * TRUE - apply redirect, FALSE - not to apply redirect.
*/
function _login_destination_match_rule($rule, $trigger = '', $current = NULL) {
global $user;
+ // Check rule is enabled or not.
+ if ($rule->enabled == 0) {
+ return FALSE;
+ }
+
$type = $rule->pages_type;
$pages = $rule->pages;
$triggers = unserialize($rule->triggers);
- if (empty($triggers))
+ if (empty($triggers)) {
$triggers = array();
+ }
$roles = unserialize($rule->roles);
- if (empty($roles))
+ if (empty($roles)) {
$roles = array();
+ }
- // remove non-existent roles
+ // Remove non-existent roles.
$roles = array_intersect_key(_login_destination_role_options(), $roles);
- // examine trigger match
+ // Examine trigger match.
if (!(empty($triggers) || array_key_exists($trigger, $triggers))) {
return FALSE;
}
- // examine role matches
+ // Examine role matches.
$roles_intersect = array_intersect_key($roles, $user->roles);
if (!empty($roles) && empty($roles_intersect)) {
@@ -456,34 +513,34 @@ function _login_destination_match_rule($rule, $trigger = '', $current = NULL) {
*/
function _login_destination_evaluate_rule($rule, $trigger = '') {
if ($rule->destination_type == LOGIN_DESTINATION_STATIC) {
- // take only 1st line
- if (preg_match("!^(.*?)$!", $rule->destination, $matches) === 1 ) {
+ // Take only 1st line.
+ if (preg_match("!^(.*?)$!", $rule->destination, $matches) === 1) {
$path = $matches[1];
if (empty($path)) {
return FALSE;
}
- // Current path
+ // Current path.
elseif ($path == '') {
return _login_destination_get_current($trigger);
}
- // External URL
+ // External URL.
elseif (strpos($path, '://') !== FALSE) {
return $path;
}
- // Internal URL
+ // Internal URL.
else {
$destination = drupal_parse_url($path);
$options = array();
$options['query'] = $destination['query'];
$options['fragment'] = $destination['fragment'];
- // drupal_goto cares about
+ // Drupal api, drupal_goto cares about .
return array($destination['path'], $options);
}
}
else {
- // error - multiple lines
+ // Error - multiple lines.
return '';
}
}
diff --git a/sites/all/modules/contrib/users/logintoboggan/CHANGELOG.txt b/sites/all/modules/contrib/users/logintoboggan/CHANGELOG.txt
new file mode 100644
index 00000000..4c33224d
--- /dev/null
+++ b/sites/all/modules/contrib/users/logintoboggan/CHANGELOG.txt
@@ -0,0 +1,116 @@
+7.x-1.5, 2015-05-01
+-------------------
+- Added CHANGELOG.txt.
+- Various one-time-login and validation links don't work with Drupal 6.35 and Drupal 7.35.
+- Trimming email input of any stray space characters.
+- Merge branch '7.x-1.x' of git.drupal.org:project/logintoboggan into 7.x-1.x.
+- Issue #1257572 by md2: reinstates page title on unified login page.
+- Improve message consistency.
+- Prevent an existing user's email address being used as name by another user.
+- Apply patch 1363244-1 to install file.
+- Reapply patch after creating new 7.x-1.x dev version.
+- Missing parameter in moved_deltas.
+
+7.x-1.4, 2014-07-04
+-------------------
+- Unified login form not santitizing url.
+- Change hook that removes authorized role from users with temporary role so that it happens in all page loads.
+
+7.x-1.3, 2011-11-09
+-------------------
+- Add logintoboggan_variable module to contrib.
+- Update custom js for permissions to keep up with core.
+- Setting for optional unsetting of sidebars on access denied pages.
+- Removing incorrectly committed file.
+- Merge branch 'master' of git.drupal.org:project/logintoboggan.
+- Content Access compatibility contrib module README file, bump core version in .info file.
+- Deleting the accidently added patch file.
+- The LoginToboggan rule module now lists its event in User eventgroup. patch provided by mikewink.
+- Document non-authenticated role disables auto-permission from authenticated user.
+- Fix errors in t() implementation.
+- Content Access compatibility contrib module. implements a hook which specifies to Content Access that the Non-authenticated role, if defined, requires special treatment. i did not test the module at all, the contrib folder is the wild west, so hopefully it works. ;).
+- Show unified login on Access Denied. this also abstracts the creation of the unified login form into its own function, and adds a helper function to determine which login form to build based on the LT settings.
+- Use format_username() in theme_lt_login_link() function.
+- Typo in administration page. Mimimum should be minimum.
+- Use single spacing between sentences.
+
+7.x-1.2, 2011-03-04
+-------------------
+- For #753224 by scor: LoginToboggan Rules now compatible with Drupal7/Rules-7.x.
+- Other modules cannot react upon email validation.
+- Allow One Time Login To Be Used Only Once.
+- Removing translation directories.
+- Stripping CVS keywords.
+- Disable core 'Require e-mail verification when a visitor creates an account' setting.
+
+7.x-1.1, 2011-01-20
+-------------------
+- Hook_init too late to remove auth user role.
+
+7.x-1.0, 2011-01-06
+-------------------
+- Update logintoboggan_rules to 7.x.
+- Option for unified login/register page.
+- Use user_save instead of update hook in _logintoboggan_process_validation.
+- Update registration function with new workflow from core. clean up password description, max length no longer supported. update module help for 7.x.
+- Get rid of unnecessary batching function in cron.
+- Clean up upgrade file for 7.x.
+- Move admin and validation functions to .inc files. various fixes in preparation for 7.x release.
+- Move protocol function back to main module file.
+- Break out admin pages and validation functions into .inc file.
+- Update the permissions js file in line with core updates.
+- Update install and readme for 7.x.
+- Update .info file for 7.x.
+- Add ID tags to css files.
+- Bad array syntax in logintoboggan_form_user_admin_permissions_alter.
+- Updating js/css handling for 7.x.
+- Remove unnecessary check for 'account' form element.
+- Ereg deprecated in PHP 5.3, remove from password checking function.
+- Enabling of Module Generates Warning from Token Module. move token hooks into separate .inc file.
+- Remove 30 char limit for password.
+- Email validation sent out even if new account was created by administrator.
+
+7.x-1.0-alpha3, 2010-07-25
+--------------------------
+- User_register value default has changed, contants for its values. thanks to rfay for the tipoff.
+- Remove dead code for predicting if account form was wrapped in a fieldset or not.
+- Logintoboggan_main_settings has extraneous form_state arg.
+- Remove dead menu caching code.
+- Minor update to README.txt of logintoboggan_rules module.
+- Fix strict warning.
+- Disabling Display of Login Block creates PHP Notices, block settings missing.
+- Hide the auth user checkbox on the user edit screen if the user is in the pre-auth role -- reduces UI confusion.
+- Non-authenticated role is hidden in user profile form even when 'Set password' is unchecked.
+- Redirect on invalid email validation.
+- Adding LoginToboggan/Rules integration module.
+- Update link to admin'ing roles.
+- Use 'Sentence case' for settings page.
+- Leverage newly added user_delete_multiple function to purge unvalidated users.
+- Remove hard-coded numeric deltas from blocks, per core change.
+- Switch to using user_pass_rehash\(\) for validation hashs.
+- User interface changes per #546356.
+- Cleanup menu paths and arguments.
+- Rollback of #48438 due to core's change in #437930.
+- Better check for no password.
+- Use $_GLOBALS['user'] where appropriate.
+- Use #theme element for logged in block.
+- Remove unnecessary code causing fatal error.
+
+7.x-1.0-alpha2, 2009-10-25
+--------------------------
+- Arguments -> variables per change to hook_theme.
+
+7.x-1.0-alpha1, 2009-10-21
+--------------------------
+- Doxygen cleanups. user_delete -> user_cancel. use batchAPI for deleting unvalidated users.
+- Value -> markup. refactor check for a manual removal of the pre-auth role by the admin -- use a hidden form field instead. fix logic for password description. add a missing user message for registration when the pre-auth role is the auth user. fix broken query placeholders. remove unnecessary query that erroneously updated a user's login time when an admin validated their account. fix broken call to drupal_goto. fix up redirect array. use core's user mail functionality for resending validation emails. fix broken mail_alter implementation for admin validation emails.
+- Refactor mailing code to use user module's functions, tokens, and hook_mail_alter. make sure anonymous user can't access revalidation link menu callback. remove unneeded security check from registration function.
+- Use REQUEST_TIME, as per 7.x upgrade conventions.
+- Login successful message now contains username. logged in block now uses theme_username on username. update theme functions to work for 7.x. clean up and refactor the access denied/login form functionality. use a custom user admin permission js file when the pre-auth role is not the auth user -- allows pre-auth role to have lower permissions than auth role.
+- Much cleaner implementation of the site 403 variable reset logic.
+- Fix login link and collapsible login block for 7.x.
+- Update admin paths and help for 7.x.
+- More general main settings submit function. refactor site 403 handling to work.
+- New admin path for module settings. fix 'Set password' option to work with system_settings_form.
+- Ensure arrays before array operations.
+
diff --git a/sites/all/modules/contrib/users/logintoboggan/contrib/logintoboggan_content_access_integration/logintoboggan_content_access_integration.info b/sites/all/modules/contrib/users/logintoboggan/contrib/logintoboggan_content_access_integration/logintoboggan_content_access_integration.info
index c93a8b25..d73ded95 100644
--- a/sites/all/modules/contrib/users/logintoboggan/contrib/logintoboggan_content_access_integration/logintoboggan_content_access_integration.info
+++ b/sites/all/modules/contrib/users/logintoboggan/contrib/logintoboggan_content_access_integration/logintoboggan_content_access_integration.info
@@ -6,9 +6,9 @@ core = "7.x"
dependencies[] = logintoboggan
dependencies[] = content_access
-; Information added by Drupal.org packaging script on 2014-07-08
-version = "7.x-1.4"
+; Information added by Drupal.org packaging script on 2015-05-01
+version = "7.x-1.5"
core = "7.x"
project = "logintoboggan"
-datestamp = "1404818634"
+datestamp = "1430501885"
diff --git a/sites/all/modules/contrib/users/logintoboggan/contrib/logintoboggan_rules/logintoboggan_rules.info b/sites/all/modules/contrib/users/logintoboggan/contrib/logintoboggan_rules/logintoboggan_rules.info
index b2c305fd..e3c824cd 100644
--- a/sites/all/modules/contrib/users/logintoboggan/contrib/logintoboggan_rules/logintoboggan_rules.info
+++ b/sites/all/modules/contrib/users/logintoboggan/contrib/logintoboggan_rules/logintoboggan_rules.info
@@ -6,9 +6,9 @@ core = "7.x"
dependencies[] = logintoboggan
dependencies[] = rules
-; Information added by Drupal.org packaging script on 2014-07-08
-version = "7.x-1.4"
+; Information added by Drupal.org packaging script on 2015-05-01
+version = "7.x-1.5"
core = "7.x"
project = "logintoboggan"
-datestamp = "1404818634"
+datestamp = "1430501885"
diff --git a/sites/all/modules/contrib/users/logintoboggan/contrib/logintoboggan_variable/logintoboggan_variable.info b/sites/all/modules/contrib/users/logintoboggan/contrib/logintoboggan_variable/logintoboggan_variable.info
index bed3a76f..722d363c 100644
--- a/sites/all/modules/contrib/users/logintoboggan/contrib/logintoboggan_variable/logintoboggan_variable.info
+++ b/sites/all/modules/contrib/users/logintoboggan/contrib/logintoboggan_variable/logintoboggan_variable.info
@@ -5,9 +5,9 @@ core = "7.x"
dependencies[] = logintoboggan
dependencies[] = variable
-; Information added by Drupal.org packaging script on 2014-07-08
-version = "7.x-1.4"
+; Information added by Drupal.org packaging script on 2015-05-01
+version = "7.x-1.5"
core = "7.x"
project = "logintoboggan"
-datestamp = "1404818634"
+datestamp = "1430501885"
diff --git a/sites/all/modules/contrib/users/logintoboggan/logintoboggan.info b/sites/all/modules/contrib/users/logintoboggan/logintoboggan.info
index 14eef6e3..81087dc2 100644
--- a/sites/all/modules/contrib/users/logintoboggan/logintoboggan.info
+++ b/sites/all/modules/contrib/users/logintoboggan/logintoboggan.info
@@ -7,9 +7,9 @@ configure = admin/config/system/logintoboggan
stylesheets[all][] = logintoboggan.css
-; Information added by Drupal.org packaging script on 2014-07-08
-version = "7.x-1.4"
+; Information added by Drupal.org packaging script on 2015-05-01
+version = "7.x-1.5"
core = "7.x"
project = "logintoboggan"
-datestamp = "1404818634"
+datestamp = "1430501885"
diff --git a/sites/all/modules/contrib/users/logintoboggan/logintoboggan.install b/sites/all/modules/contrib/users/logintoboggan/logintoboggan.install
index f5f05190..88d3c3bb 100644
--- a/sites/all/modules/contrib/users/logintoboggan/logintoboggan.install
+++ b/sites/all/modules/contrib/users/logintoboggan/logintoboggan.install
@@ -34,7 +34,7 @@ function logintoboggan_update_7000(&$sandbox) {
),
);
- update_fix_d7_block_deltas($sandbox, $renamed_deltas);
+ update_fix_d7_block_deltas($sandbox, $renamed_deltas, array());
}
/**
diff --git a/sites/all/modules/contrib/users/logintoboggan/logintoboggan.module b/sites/all/modules/contrib/users/logintoboggan/logintoboggan.module
index cbfa73ad..55b93fe5 100755
--- a/sites/all/modules/contrib/users/logintoboggan/logintoboggan.module
+++ b/sites/all/modules/contrib/users/logintoboggan/logintoboggan.module
@@ -447,9 +447,8 @@ function logintoboggan_user_register_submit($form, &$form_state) {
$pre_auth = logintoboggan_validating_id() != DRUPAL_AUTHENTICATED_RID;
// If we are allowing user selected passwords then skip the auto-generate function
- // The new user's status should default to the site settings, unless reg_passwd_set == 1
- // (immediate login, we are going to assign a pre-auth role), and we want to allow
- // admin approval accounts access to the site.
+ // The new user's status will be 1 (visitors can create own accounts) if reg_pass_set == 1
+ // Immediate login, we are going to assign a pre-auth role, until email validation completed
if ($reg_pass_set) {
$pass = $form_state['values']['pass'];
$status = 1;
@@ -505,7 +504,7 @@ function logintoboggan_user_register_submit($form, &$form_state) {
// 3. Visitors can create their own accounts.
$message = t('Further instructions have been sent to your e-mail address.');
if($reg_pass_set && $pre_auth && variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS) {
- $message = t('A validation e-mail has been sent to your e-mail address. In order to gain full access to the site, you will need to follow the instructions in that message.');
+ $message = t('A validation e-mail has been sent to your e-mail address. You will need to follow the instructions in that message in order to gain full access to the site.');
}
if (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS) {
@@ -560,9 +559,15 @@ function logintoboggan_user_login_validate($form, &$form_state) {
* @ingroup logintoboggan_form
*/
function logintoboggan_user_register_validate($form, &$form_state) {
+ //Check to see whether our username matches any email address currently in the system.
+ if($mail = db_query("SELECT mail FROM {users} WHERE LOWER(:name) = LOWER(mail)", array(
+ ':name' => $form_state['values']['name'],
+ ))->fetchField()) {
+ form_set_error('name', t('This e-mail has already been taken by another user.'));
+ }
//Check to see whether our e-mail address matches the confirm address if enabled.
if (variable_get('logintoboggan_confirm_email_at_registration', 0) && isset($form_state['values']['conf_mail'])) {
- if ($form_state['values']['mail'] != $form_state['values']['conf_mail']) {
+ if (trim($form_state['values']['mail']) != trim($form_state['values']['conf_mail'])) {
form_set_error('conf_mail', t('Your e-mail address and confirmed e-mail address must match.'));
}
}
@@ -756,8 +761,6 @@ function logintoboggan_unified_login_page($active_form = 'login') {
return menu_execute_active_handler(NULL, FALSE);
}
else {
- // Title just clutters the interface...
- drupal_set_title('');
$output = logintoboggan_get_authentication_form($active_form);
return $output;
}
@@ -1051,11 +1054,11 @@ function logintoboggan_process_login($account, &$edit, $redirect = array()){
function logintoboggan_eml_validate_url($account, $url_options){
$timestamp = REQUEST_TIME;
- return url("user/validate/$account->uid/$timestamp/". logintoboggan_eml_rehash($account->pass, $timestamp, $account->mail), $url_options);
+ return url("user/validate/$account->uid/$timestamp/". logintoboggan_eml_rehash($account->pass, $timestamp, $account->mail, $account->uid), $url_options);
}
-function logintoboggan_eml_rehash($password, $timestamp, $mail) {
- return user_pass_rehash($password, $timestamp, $mail);
+function logintoboggan_eml_rehash($password, $timestamp, $mail, $uid) {
+ return user_pass_rehash($password, $timestamp, $mail, $uid);
}
/**
diff --git a/sites/all/modules/contrib/users/logintoboggan/logintoboggan.unifiedlogin.js b/sites/all/modules/contrib/users/logintoboggan/logintoboggan.unifiedlogin.js
index ca67a657..c788b86c 100644
--- a/sites/all/modules/contrib/users/logintoboggan/logintoboggan.unifiedlogin.js
+++ b/sites/all/modules/contrib/users/logintoboggan/logintoboggan.unifiedlogin.js
@@ -10,6 +10,14 @@ Drupal.behaviors.unifiedLogin = {
$('.toboggan-unified #login-link').removeClass('lt-active');
$('.toboggan-unified #register-form').show();
$('.toboggan-unified #login-form').hide();
+ $.ajax({
+ url: "/user/register",
+ success: function(data) {
+ var title = data.match("(.*?)")[1];
+ $('html head').find('title').text(title);
+ $('h1.title').text(title.substring(0,title.indexOf('|')));
+ },
+ });
return false;
});
$('.toboggan-unified #login-link').click(function() {
@@ -17,6 +25,14 @@ Drupal.behaviors.unifiedLogin = {
$('.toboggan-unified #register-link').removeClass('lt-active');
$('.toboggan-unified #login-form').show();
$('.toboggan-unified #register-form').hide();
+ $.ajax({
+ url: "/user/login",
+ success: function(data) {
+ var title = data.match("(.*?)")[1];
+ $('html head').find('title').text(title);
+ $('h1.title').text(title.substring(0,title.indexOf('|')));
+ },
+ });
return false;
});
@@ -32,5 +48,4 @@ Drupal.behaviors.unifiedLogin = {
}
};
-})(jQuery);
-
+})(jQuery);
\ No newline at end of file
diff --git a/sites/all/modules/contrib/users/logintoboggan/logintoboggan.validation.inc b/sites/all/modules/contrib/users/logintoboggan/logintoboggan.validation.inc
index 3ce08bb9..9d576eed 100644
--- a/sites/all/modules/contrib/users/logintoboggan/logintoboggan.validation.inc
+++ b/sites/all/modules/contrib/users/logintoboggan/logintoboggan.validation.inc
@@ -22,7 +22,7 @@ function logintoboggan_validate_email($account, $timestamp, $hashed_pass, $actio
// - the user is still in the pre-auth role or didn't set
// their own password.
// - the hashed password is correct.
- if (((variable_get('user_email_verification', TRUE) && empty($account->login)) || ($pre_auth && array_key_exists($validating_id, $account->roles))) && $hashed_pass == logintoboggan_eml_rehash($account->pass, $timestamp, $account->mail)) {
+ if (((variable_get('user_email_verification', TRUE) && empty($account->login)) || ($pre_auth && array_key_exists($validating_id, $account->roles))) && $hashed_pass == logintoboggan_eml_rehash($account->pass, $timestamp, $account->mail, $account->uid)) {
watchdog('user', 'E-mail validation URL used for %name with timestamp @timestamp.', array('%name' => $account->name, '@timestamp' => $timestamp));
_logintoboggan_process_validation($account);
diff --git a/sites/all/modules/contrib/views/views/drush/views.drush.inc b/sites/all/modules/contrib/views/views/drush/views.drush.inc
index dd8af1b6..eb2ecc2f 100644
--- a/sites/all/modules/contrib/views/views/drush/views.drush.inc
+++ b/sites/all/modules/contrib/views/views/drush/views.drush.inc
@@ -42,10 +42,14 @@ function views_drush_command() {
),
'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
'aliases' => array('vr'),
+ 'options' => array(
+ 'all' => 'If provided, all views will be reverted.',
+ ),
'examples' => array(
'drush vr archive' => 'Reverts the "archive" view.',
'drush rln archive frontpage' => 'Reverts the "archive" and "frontpage" view.',
'drush vr' => 'Will present you with a list of overridden views to choose from, and an option to revert all overridden views.',
+ 'drush vr --all' => 'Will revert all overridden views.',
),
);
$items['views-dev'] = array(
@@ -126,15 +130,21 @@ function views_revert_views() {
}
}
- // Return early if there are no overridden views in the system.
+ // If there are no overridden views in the system, report it.
if (empty($overridden)) {
- return drush_set_error(dt('There are no overridden views in the system.'));
+ drush_log(dt('There are no overridden views in the system.'), 'ok');
}
- // If the user specified in the command the views to be overridden.
- if (!empty($viewnames)) {
+ // If the user provided the "--all" option, revert all views.
+ if (drush_get_option('all')) {
+ $i = views_revert_allviews($views);
+ }
+
+ // If the user specified a list of views on the CLI, revert those.
+ elseif (!empty($viewnames)) {
foreach ($viewnames as $key => $viewname) {
$is_overridden = key_exists($viewname, $overridden);
+
// Check if the provided view name is in the system
if ($viewname && !key_exists($viewname, $views)) {
drush_set_error(dt("'@viewname' view is not present in the system.", array('@viewname' => $viewname)));
@@ -144,18 +154,22 @@ function views_revert_views() {
drush_set_error(dt("The view specified '@viewname' is not overridden.", array('@viewname' => $viewname)));
}
// If the view is overriden, revert it.
- elseif ($is_overridden){
+ elseif ($is_overridden) {
views_revert_view($views[$viewname]);
$i++;
}
// We should never get here but well...
else {
- drush_set_error(dt("The view specified '@viewname' is not provided in code, and thus cannot be reverted.", array('@viewname' => $viewname)));
+ drush_set_error(dt(
+ "The view specified '@viewname' is not provided in code, and thus cannot be reverted.",
+ array('@viewname' => $viewname)
+ ));
}
}
}
- // The user did not specify any views in the command, prompt the user
+ // The user neither selected the "--all" option, nor provided a list of views to revert.
+ // Prompt the user.
else {
// list of choices for the user
$overridden['all'] = dt('Revert all overridden views'); // add a choice at the end
diff --git a/sites/all/modules/contrib/views/views/handlers/views_handler_area_view.inc b/sites/all/modules/contrib/views/views/handlers/views_handler_area_view.inc
index 45ea4999..3b72bf6b 100644
--- a/sites/all/modules/contrib/views/views/handlers/views_handler_area_view.inc
+++ b/sites/all/modules/contrib/views/views/handlers/views_handler_area_view.inc
@@ -51,33 +51,48 @@ class views_handler_area_view extends views_handler_area {
* Render the area
*/
function render($empty = FALSE) {
- if (!empty($this->options['view_to_insert'])) {
- list($view_name, $display_id) = explode(':', $this->options['view_to_insert']);
-
- $view = views_get_view($view_name);
- if (empty($view) || !$view->access($display_id)) {
- return;
- }
- $view->set_display($display_id);
-
- // Avoid recursion
- $view->parent_views += $this->view->parent_views;
- $view->parent_views[] = "$view_name:$display_id";
-
- // Check if the view is part of the parent views of this view
- $search = "$view_name:$display_id";
- if (in_array($search, $this->view->parent_views)) {
- drupal_set_message(t("Recursion detected in view @view display @display.", array('@view' => $view_name, '@display' => $display_id)), 'error');
+ if ($view = $this->loadView()) {
+ if (!empty($this->options['inherit_arguments']) && !empty($this->view->args)) {
+ return $view->preview(NULL, $this->view->args);
}
else {
- if (!empty($this->options['inherit_arguments']) && !empty($this->view->args)) {
- return $view->preview($display_id, $this->view->args);
- }
- else {
- return $view->preview($display_id);
- }
+ return $view->preview(NULL);
}
}
return '';
}
+
+ /**
+ * Loads the used view for rendering.
+ *
+ * @return \view|NULL
+ * The loaded view or NULL, in case the view was not loadable / recursion
+ * got detected / access got denied.
+ */
+ protected function loadView() {
+ if (empty($this->options['view_to_insert'])) {
+ return NULL;
+ }
+ list($view_name, $display_id) = explode(':', $this->options['view_to_insert']);
+
+ $view = views_get_view($view_name);
+ if (empty($view) || !$view->access($display_id)) {
+ return NULL;
+ }
+ $view->set_display($display_id);
+
+ // Avoid recursion.
+ $view->parent_views += $this->view->parent_views;
+ $view->parent_views[] = "$view_name:$display_id";
+
+ // Check if the view is part of the parent views of this view.
+ $search = "$view_name:$display_id";
+ if (in_array($search, $this->view->parent_views)) {
+ drupal_set_message(t("Recursion detected in view @view display @display.", array('@view' => $view_name, '@display' => $display_id)), 'error');
+ return NULL;
+ }
+
+ return $view;
+ }
+
}
diff --git a/sites/all/modules/contrib/views/views/handlers/views_handler_argument.inc b/sites/all/modules/contrib/views/views/handlers/views_handler_argument.inc
index 5a5ec004..86c4a0df 100644
--- a/sites/all/modules/contrib/views/views/handlers/views_handler_argument.inc
+++ b/sites/all/modules/contrib/views/views/handlers/views_handler_argument.inc
@@ -419,7 +419,7 @@ class views_handler_argument extends views_handler {
// Let the plugins do validation.
$default_id = $form_state['values']['options']['default_argument_type'];
$plugin = $this->get_plugin('argument default', $default_id);
- if ($plugin) {
+ if ($plugin && isset($form['argument_default'][$default_id]) && isset($form_state['values']['options']['argument_default'][$default_id])) {
$plugin->options_validate($form['argument_default'][$default_id], $form_state, $form_state['values']['options']['argument_default'][$default_id]);
}
@@ -1075,9 +1075,6 @@ class views_handler_argument extends views_handler {
$argument = clone $this;
if (!isset($arg) && $argument->has_default_argument()) {
$arg = $argument->get_default_argument();
-
- // remember that this argument was computed, not passed on the URL.
- $this->is_default = TRUE;
}
// Set the argument, which will also validate that the argument can be set.
if ($argument->set_argument($arg)) {
diff --git a/sites/all/modules/contrib/views/views/handlers/views_handler_field_contextual_links.inc b/sites/all/modules/contrib/views/views/handlers/views_handler_field_contextual_links.inc
index faeeedc2..4386e059 100644
--- a/sites/all/modules/contrib/views/views/handlers/views_handler_field_contextual_links.inc
+++ b/sites/all/modules/contrib/views/views/handlers/views_handler_field_contextual_links.inc
@@ -10,35 +10,7 @@
*
* @ingroup views_field_handlers
*/
-class views_handler_field_contextual_links extends views_handler_field {
- function option_definition() {
- $options = parent::option_definition();
-
- $options['fields'] = array('default' => array());
- $options['destination'] = array('default' => TRUE, 'bool' => TRUE);
-
- return $options;
- }
-
- function options_form(&$form, &$form_state) {
- $all_fields = $this->view->display_handler->get_field_labels();
- // Offer to include only those fields that follow this one.
- $field_options = array_slice($all_fields, 0, array_search($this->options['id'], array_keys($all_fields)));
- $form['fields'] = array(
- '#type' => 'checkboxes',
- '#title' => t('Fields'),
- '#description' => t('Fields to be included as contextual links.'),
- '#options' => $field_options,
- '#default_value' => $this->options['fields'],
- );
- $form['destination'] = array(
- '#type' => 'checkbox',
- '#title' => t('Include destination'),
- '#description' => t('Include a "destination" parameter in the link to return the user to the original view upon completing the contextual action.'),
- '#default_value' => $this->options['destination'],
- );
- }
-
+class views_handler_field_contextual_links extends views_handler_field_links {
function pre_render(&$values) {
// Add a row plugin css class for the contextual link.
$class = 'contextual-links-region';
@@ -50,35 +22,18 @@ class views_handler_field_contextual_links extends views_handler_field {
}
}
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+
+ $form['fields']['#description'] = t('Fields to be included as contextual links.');
+ $form['destination']['#description'] = t('Include a "destination" parameter in the link to return the user to the original view upon completing the contextual action.');
+ }
+
/**
* Render the contextual fields.
*/
function render($values) {
- $links = array();
- foreach ($this->options['fields'] as $field) {
- if (empty($this->view->style_plugin->rendered_fields[$this->view->row_index][$field])) {
- continue;
- }
- $title = $this->view->field[$field]->last_render_text;
- $path = '';
- if (!empty($this->view->field[$field]->options['alter']['path'])) {
- $path = $this->view->field[$field]->options['alter']['path'];
- }
- if (!empty($title) && !empty($path)) {
- // Make sure that tokens are replaced for this paths as well.
- $tokens = $this->get_render_tokens(array());
- $path = strip_tags(decode_entities(strtr($path, $tokens)));
-
- $links[$field] = array(
- 'href' => $path,
- 'title' => $title,
- );
- if (!empty($this->options['destination'])) {
- $links[$field]['query'] = drupal_get_destination();
- }
- }
- }
-
+ $links = $this->get_links();
if (!empty($links)) {
$build = array(
'#prefix' => '
',
@@ -97,6 +52,4 @@ class views_handler_field_contextual_links extends views_handler_field {
return '';
}
}
-
- function query() { }
}
diff --git a/sites/all/modules/contrib/views/views/handlers/views_handler_field_ctools_dropdown.inc b/sites/all/modules/contrib/views/views/handlers/views_handler_field_ctools_dropdown.inc
new file mode 100644
index 00000000..8964f88d
--- /dev/null
+++ b/sites/all/modules/contrib/views/views/handlers/views_handler_field_ctools_dropdown.inc
@@ -0,0 +1,55 @@
+ TRUE, 'bool' => TRUE);
+
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+ $form['fields']['#description'] = t('Fields to be included as ctools dropdown button.');
+ $form['destination']['#description'] = t('Include a "destination" parameter in the link to return the user to the original view upon completing a link action.');
+
+ $form['views_admin_css'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Include Views admin CSS'),
+ '#description' => t("Add additional css to match the style of the Views admin screen."),
+ '#default_value' => $this->options['views_admin_css'],
+ );
+ }
+
+ /**
+ * Render the dropdown button.
+ */
+ function render($values) {
+ static $added_admin_css;
+ $links = $this->get_links();
+
+ if (!empty($links)) {
+ if (!empty($this->options['views_admin_css']) && !$added_admin_css) {
+ views_include('admin');
+ views_ui_add_admin_css();
+ $added_admin_css = TRUE;
+ }
+
+ return theme('links__ctools_dropbutton', array('links' => $links, 'attributes' => array('class' => array('links', 'inline'))));
+ }
+ else {
+ return '';
+ }
+ }
+}
diff --git a/sites/all/modules/contrib/views/views/handlers/views_handler_field_links.inc b/sites/all/modules/contrib/views/views/handlers/views_handler_field_links.inc
new file mode 100644
index 00000000..15f64607
--- /dev/null
+++ b/sites/all/modules/contrib/views/views/handlers/views_handler_field_links.inc
@@ -0,0 +1,155 @@
+ array());
+ $options['check_access'] = array('default' => FALSE);
+ $options['destination'] = array('default' => TRUE, 'bool' => TRUE);
+
+ return $options;
+ }
+
+ /**
+ * Overrides views_handler_field::options_form().
+ */
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+
+ $all_fields = $this->view->display_handler->get_field_labels();
+ // Offer to include only those fields that follow this one.
+ $field_options = array_slice($all_fields, 0, array_search($this->options['id'], array_keys($all_fields)));
+ $form['fields'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Fields'),
+ '#description' => t('Fields to be included as links.'),
+ '#options' => $field_options,
+ '#default_value' => $this->options['fields'],
+ '#required' => TRUE,
+ );
+
+ $form['check_access'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Evaluate router path for access'),
+ '#default_value' => $this->options['check_access'],
+ '#description' => t('Will check if the path exists and is accessible for the current user. Might be useful, might be slow.'),
+ );
+
+ $form['destination'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Include destination'),
+ '#description' => t('Include a "destination" parameter in the link to return the user to the original view upon completing the link action.'),
+ '#default_value' => $this->options['destination'],
+ );
+ }
+
+ /**
+ * Overrides views_handler_field::options_form().
+ */
+ function options_submit(&$form, &$form_state) {
+ // Remove unselected options.
+ $form_state['values']['options']['fields'] = array_filter($form_state['values']['options']['fields']);
+ }
+
+ /**
+ * Return the list of links of this field.
+ *
+ * @return array
+ * The links which are used by the render function.
+ */
+ function get_links() {
+ $links = array();
+ foreach ($this->options['fields'] as $field) {
+ if (empty($this->view->field[$field]->last_render_text)) {
+ continue;
+ }
+
+ $title = $this->view->field[$field]->last_render_text;
+ // Use the alter settings for the link field source not this links field.
+ $alter = $this->view->field[$field]->options['alter'];
+ $url = array('query' => array());
+
+ // Copy code from views_handler_field::render_as_link().
+ $path = $alter['path'];
+ if (!empty($path) && $path != '') {
+ // Leave path alone on as strip_tags() would remove this.
+ // Replace tokens and strip any HTML tags in the path.
+ $tokens = $this->get_render_tokens(array());
+ $path = strip_tags(decode_entities(strtr($path, $tokens)));
+
+ if (!empty($alter['path_case']) && $alter['path_case'] != 'none') {
+ $path = $this->case_transform($path, $alter['path_case']);
+ }
+
+ if (!empty($alter['replace_spaces'])) {
+ $path = str_replace(' ', '-', $path);
+ }
+
+ $url = drupal_parse_url($path);
+ if (empty($url)) {
+ // Seriously malformed URLs may return FALSE or empty arrays.
+ continue;
+ }
+ $path = $url['path'];
+
+ // Check router menu item access for the current user.
+ if ($this->options['check_access']) {
+ $menu_item = menu_get_item($path);
+ if (!$menu_item || empty($menu_item['access'])) {
+ continue;
+ }
+ }
+
+ if (!empty($this->options['destination']) && empty($alter['external'])) {
+ // Override any destination argument included in URL.
+ $url['query'] = array_merge($url['query'], drupal_get_destination());
+ }
+
+ // Omit tweaks of query, fragment, and link_class.
+
+ $alt = strtr($alter['alt'], $tokens);
+ if ($alt && $alt != $title) {
+ // Set the title attribute only if it improves accessibility.
+ $url['attributes']['title'] = decode_entities($alt);
+ }
+
+ if (!empty($alter['rel']) && $rel = strtr($alter['rel'], $tokens)) {
+ $url['attributes']['rel'] = $rel;
+ }
+
+ $target = check_plain(trim(strtr($alter['target'], $tokens)));
+ if (!empty($target)) {
+ $url['attributes']['target'] = $target;
+ }
+ }
+
+ $links[$field] = array(
+ 'href' => $path,
+ 'title' => $title,
+ ) + $url;
+ }
+
+ return $links;
+ }
+
+ /**
+ * Overrides views_handler_field::query().
+ */
+ function query() { }
+
+}
diff --git a/sites/all/modules/contrib/views/views/handlers/views_handler_field_math.inc b/sites/all/modules/contrib/views/views/handlers/views_handler_field_math.inc
index 08fba060..50a948ae 100644
--- a/sites/all/modules/contrib/views/views/handlers/views_handler_field_math.inc
+++ b/sites/all/modules/contrib/views/views/handlers/views_handler_field_math.inc
@@ -26,7 +26,7 @@ class views_handler_field_math extends views_handler_field_numeric {
$form['expression'] = array(
'#type' => 'textarea',
'#title' => t('Expression'),
- '#description' => t('Enter mathematical expressions such as 2 + 2 or sqrt(5). You may assign variables and create mathematical functions and evaluate them. Use the ; to separate these. For example: f(x) = x + 2; f(2).'),
+ '#description' => t("Enter mathematical expressions such as 2 + 2 or sqrt(5). You may assign variables and create mathematical functions and evaluate them. Use the ; to separate these. For example: f(x) = x + 2; f(2). The result of the previous row's mathematical expression can be accessed by using the [expression] token itself."),
'#default_value' => $this->options['expression'],
);
diff --git a/sites/all/modules/contrib/views/views/handlers/views_handler_field_numeric.inc b/sites/all/modules/contrib/views/views/handlers/views_handler_field_numeric.inc
index d10d3d0b..843f4c95 100644
--- a/sites/all/modules/contrib/views/views/handlers/views_handler_field_numeric.inc
+++ b/sites/all/modules/contrib/views/views/handlers/views_handler_field_numeric.inc
@@ -107,6 +107,12 @@ class views_handler_field_numeric extends views_handler_field {
function render($values) {
$value = $this->get_value($values);
+
+ // Hiding should happen before rounding or adding prefix/suffix.
+ if ($this->options['hide_empty'] && empty($value) && ($value !== 0 || $this->options['empty_zero'])) {
+ return '';
+ }
+
if (!empty($this->options['set_precision'])) {
$value = number_format($value, $this->options['precision'], $this->options['decimal'], $this->options['separator']);
}
@@ -120,11 +126,6 @@ class views_handler_field_numeric extends views_handler_field {
}
}
- // Check to see if hiding should happen before adding prefix and suffix.
- if ($this->options['hide_empty'] && empty($value) && ($value !== 0 || $this->options['empty_zero'])) {
- return '';
- }
-
// Should we format as a plural.
if (!empty($this->options['format_plural'])) {
$value = format_plural($value, $this->options['format_plural_singular'], $this->options['format_plural_plural']);
diff --git a/sites/all/modules/contrib/views/views/handlers/views_handler_filter_combine.inc b/sites/all/modules/contrib/views/views/handlers/views_handler_filter_combine.inc
index 915924b8..c1afcf5c 100644
--- a/sites/all/modules/contrib/views/views/handlers/views_handler_filter_combine.inc
+++ b/sites/all/modules/contrib/views/views/handlers/views_handler_filter_combine.inc
@@ -54,6 +54,11 @@ class views_handler_filter_combine extends views_handler_filter_string {
$fields = array();
// Only add the fields if they have a proper field and table alias.
foreach ($this->options['fields'] as $id) {
+ // Field access checks may have removed this handler.
+ if (!isset($this->view->field[$id])) {
+ continue;
+ }
+
$field = $this->view->field[$id];
// Always add the table of the selected fields to be sure a table alias
// exists.
diff --git a/sites/all/modules/contrib/views/views/handlers/views_handler_filter_date.inc b/sites/all/modules/contrib/views/views/handlers/views_handler_filter_date.inc
index 4ef61b47..38313274 100644
--- a/sites/all/modules/contrib/views/views/handlers/views_handler_filter_date.inc
+++ b/sites/all/modules/contrib/views/views/handlers/views_handler_filter_date.inc
@@ -158,13 +158,11 @@ class views_handler_filter_date extends views_handler_filter_numeric {
}
function op_between($field) {
- $a = intval(strtotime($this->value['min'], 0));
- $b = intval(strtotime($this->value['max'], 0));
+ // Use the substitutions to ensure a consistent timestamp.
+ $query_substitutions = views_views_query_substitutions($this->view);
+ $a = intval(strtotime($this->value['min'], $query_substitutions['***CURRENT_TIME***']));
+ $b = intval(strtotime($this->value['max'], $query_substitutions['***CURRENT_TIME***']));
- if ($this->value['type'] == 'offset') {
- $a = '***CURRENT_TIME***' . sprintf('%+d', $a); // keep sign
- $b = '***CURRENT_TIME***' . sprintf('%+d', $b); // keep sign
- }
// This is safe because we are manually scrubbing the values.
// It is necessary to do it this way because $a and $b are formulas when using an offset.
$operator = strtoupper($this->operator);
@@ -172,10 +170,10 @@ class views_handler_filter_date extends views_handler_filter_numeric {
}
function op_simple($field) {
- $value = intval(strtotime($this->value['value'], 0));
- if (!empty($this->value['type']) && $this->value['type'] == 'offset') {
- $value = '***CURRENT_TIME***' . sprintf('%+d', $value); // keep sign
- }
+ // Use the substitutions to ensure a consistent timestamp.
+ $query_substitutions = views_views_query_substitutions($this->view);
+ $value = intval(strtotime($this->value['value'], $query_substitutions['***CURRENT_TIME***']));
+
// This is safe because we are manually scrubbing the value.
// It is necessary to do it this way because $value is a formula when using an offset.
$this->query->add_where_expression($this->options['group'], "$field $this->operator $value");
diff --git a/sites/all/modules/contrib/views/views/includes/admin.inc b/sites/all/modules/contrib/views/views/includes/admin.inc
index 1643b34f..237a05d5 100644
--- a/sites/all/modules/contrib/views/views/includes/admin.inc
+++ b/sites/all/modules/contrib/views/views/includes/admin.inc
@@ -4961,6 +4961,13 @@ function views_ui_admin_settings_advanced() {
'#description' => t('Select a translation method to use for Views data like header, footer, and empty text.'),
);
+ $form['locale']['views_localize_all'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use same translation method for exported views'),
+ '#description' => t('Exported views will use Core translation by default. Enable this to always use the configured translation method.'),
+ '#default_value' => variable_get('views_localize_all', FALSE),
+ );
+
$regions = array();
$regions['watchdog'] = t('Watchdog');
if (module_exists('devel')) {
diff --git a/sites/all/modules/contrib/views/views/includes/ajax.inc b/sites/all/modules/contrib/views/views/includes/ajax.inc
index cd633605..bef3c05d 100644
--- a/sites/all/modules/contrib/views/views/includes/ajax.inc
+++ b/sites/all/modules/contrib/views/views/includes/ajax.inc
@@ -48,12 +48,12 @@ function views_ajax() {
// Add all $_POST data, because AJAX is always a post and many things,
// such as tablesorts, exposed filters and paging assume $_GET.
- $_GET = $_POST + $_GET;
+ $_GET = $_POST + drupal_get_query_parameters($_GET, array('page'));
// Overwrite the destination.
// @see drupal_get_destination()
$origin_destination = $path;
- $query = drupal_http_build_query($_REQUEST);
+ $query = drupal_http_build_query(drupal_get_query_parameters());
if ($query != '') {
$origin_destination .= '?' . $query;
}
diff --git a/sites/all/modules/contrib/views/views/includes/cache.inc b/sites/all/modules/contrib/views/views/includes/cache.inc
index b74752f1..b836db41 100644
--- a/sites/all/modules/contrib/views/views/includes/cache.inc
+++ b/sites/all/modules/contrib/views/views/includes/cache.inc
@@ -67,12 +67,11 @@ function _views_fetch_data($table = NULL, $move = TRUE, $reset = FALSE) {
}
else {
if (!$fully_loaded) {
- $data = views_cache_get('views_data', TRUE);
- if (!empty($data->data)) {
+ if ($data = views_cache_get('views_data', TRUE)) {
$cache = $data->data;
}
-
- if (empty($cache)) {
+ else {
+ // No cache entry, rebuild.
$cache = _views_fetch_data_build();
}
$fully_loaded = TRUE;
@@ -127,12 +126,25 @@ function _views_data_process_entity_types(&$data) {
function _views_fetch_plugin_data($type = NULL, $plugin = NULL, $reset = FALSE) {
static $cache = NULL;
if (!isset($cache) || $reset) {
- $start = microtime(TRUE);
- views_include('plugins');
- views_include_handlers();
-
- $cache = views_discover_plugins();
-
+ // Load necessary code once.
+ if (!isset($cache)) {
+ views_include('plugins');
+ views_include_handlers();
+ }
+ // Because plugin data contains translated strings, and as such can be
+ // expensive to build, the results are cached per language.
+ global $language;
+ $cache_key = 'views:plugin_data:' . $language->language;
+ if (!$reset) {
+ if ($cache = cache_get($cache_key)) {
+ $cache = $cache->data;
+ }
+ }
+ // If not available in the cache, build it and cache it.
+ if (!$cache || $reset) {
+ $cache = views_discover_plugins();
+ cache_set($cache_key, $cache);
+ }
}
if (!$type && !$plugin) {
diff --git a/sites/all/modules/contrib/views/views/includes/handlers.inc b/sites/all/modules/contrib/views/views/includes/handlers.inc
index 43461331..6c1e8879 100644
--- a/sites/all/modules/contrib/views/views/includes/handlers.inc
+++ b/sites/all/modules/contrib/views/views/includes/handlers.inc
@@ -758,7 +758,7 @@ class views_many_to_one_helper {
*/
public $placeholders = array();
- function views_many_to_one_helper(&$handler) {
+ function __construct(&$handler) {
$this->handler = &$handler;
}
@@ -1547,7 +1547,6 @@ class views_join {
if (is_array($this->extra)) {
$extras = array();
foreach ($this->extra as $info) {
- $extra = '';
// Figure out the table name. Remember, only use aliases provided
// if at all possible.
$join_table = '';
@@ -1565,36 +1564,63 @@ class views_join {
}
}
- // Convert a single-valued array of values to the single-value case,
- // and transform from IN() notation to = notation
- if (is_array($info['value']) && count($info['value']) == 1) {
- if (empty($info['operator'])) {
- $operator = '=';
+ // If left_field is set use it for a field-to-field condition.
+ if (!empty($info['left_field'])) {
+ $operator = !empty($info['operator']) ? $info['operator'] : '=';
+ $left_table = (isset($info['left_table'])) ? $info['left_table'] : $left['alias'];
+ $extras[] = "$join_table$info[field] $operator $left_table.$info[left_field]";
+ }
+ // Else if formula is set, us it for a flexible on clause.
+ elseif (!empty($info['formula'])) {
+ // If a field is given, we build a "$field $op $formula".
+ // Without it would only be "$formula".
+ $extra = '';
+ if (isset($info['field'])) {
+ // With a single value, the '=' operator is implicit.
+ $operator = !empty($info['operator']) ? $info['operator'] : '=';
+ $extra .= "$join_table$info[field] $operator ";
+ }
+ $extra .= $info['formula'];
+ // Add placeholder arguments.
+ if (isset($info['formula_arguments']) && is_array($info['formula_arguments'])) {
+ $arguments = array_merge($arguments, $info['formula_arguments']);
+ }
+ $extras[] = $extra;
+ }
+ // Otherwise - and if we have a value - use it for a field-to-value condition.
+ elseif (!empty($info['value'])) {
+ // Convert a single-valued array of values to the single-value case,
+ // and transform from IN() notation to = notation
+ if (is_array($info['value']) && count($info['value']) == 1) {
+ if (empty($info['operator'])) {
+ $operator = '=';
+ }
+ else {
+ $operator = $info['operator'] == 'NOT IN' ? '!=' : '=';
+ }
+ $info['value'] = array_shift($info['value']);
+ }
+
+ if (is_array($info['value'])) {
+ // With an array of values, we need multiple placeholders and the
+ // 'IN' operator is implicit.
+ foreach ($info['value'] as $value) {
+ $placeholder_i = ':views_join_condition_' . $select_query->nextPlaceholder();
+ $arguments[$placeholder_i] = $value;
+ }
+
+ $operator = !empty($info['operator']) ? $info['operator'] : 'IN';
+ $placeholder = '( ' . implode(', ', array_keys($arguments)) . ' )';
}
else {
- $operator = $info['operator'] == 'NOT IN' ? '!=' : '=';
- }
- $info['value'] = array_shift($info['value']);
- }
-
- if (is_array($info['value'])) {
- // With an array of values, we need multiple placeholders and the
- // 'IN' operator is implicit.
- foreach ($info['value'] as $value) {
- $placeholder_i = $view_query->placeholder('views_join_condition_');
- $arguments[$placeholder_i] = $value;
+ // With a single value, the '=' operator is implicit.
+ $operator = !empty($info['operator']) ? $info['operator'] : '=';
+ $placeholder = ':views_join_condition_' . $select_query->nextPlaceholder();
+ $arguments[$placeholder] = $info['value'];
}
- $operator = !empty($info['operator']) ? $info['operator'] : 'IN';
- $placeholder = '( ' . implode(', ', array_keys($arguments)) . ' )';
+ $extras[] = "$join_table$info[field] $operator $placeholder";
}
- else {
- // With a single value, the '=' operator is implicit.
- $operator = !empty($info['operator']) ? $info['operator'] : '=';
- $placeholder = $view_query->placeholder('views_join_condition_');
- $arguments[$placeholder] = $info['value'];
- }
- $extras[] = "$join_table$info[field] $operator $placeholder";
}
if ($extras) {
@@ -1660,7 +1686,6 @@ class views_join_subquery extends views_join {
if (is_array($this->extra)) {
$extras = array();
foreach ($this->extra as $info) {
- $extra = '';
// Figure out the table name. Remember, only use aliases provided
// if at all possible.
$join_table = '';
diff --git a/sites/all/modules/contrib/views/views/includes/plugins.inc b/sites/all/modules/contrib/views/views/includes/plugins.inc
index bf095732..4b689825 100644
--- a/sites/all/modules/contrib/views/views/includes/plugins.inc
+++ b/sites/all/modules/contrib/views/views/includes/plugins.inc
@@ -408,7 +408,7 @@ function views_views_plugins() {
*/
function views_discover_plugins() {
$cache = array('display' => array(), 'style' => array(), 'row' => array(), 'argument default' => array(), 'argument validator' => array(), 'access' => array(), 'cache' => array(), 'exposed_form' => array());
- // Get plugins from all mdoules.
+ // Get plugins from all modules.
foreach (module_implements('views_plugins') as $module) {
$function = $module . '_views_plugins';
$result = $function();
@@ -526,6 +526,9 @@ class views_plugin extends views_object {
* Provide a full list of possible theme templates used by this style.
*/
function theme_functions() {
+ if (empty($this->definition['theme'])) {
+ $this->definition['theme'] = 'views_view';
+ }
return views_theme_functions($this->definition['theme'], $this->view, $this->display);
}
diff --git a/sites/all/modules/contrib/views/views/includes/view.inc b/sites/all/modules/contrib/views/views/includes/view.inc
index d082a0b6..d9fb43fd 100644
--- a/sites/all/modules/contrib/views/views/includes/view.inc
+++ b/sites/all/modules/contrib/views/views/includes/view.inc
@@ -812,8 +812,6 @@ class view extends views_db_object {
if (isset($arg)) {
$this->args[$position] = $arg;
}
- // remember that this argument was computed, not passed on the URL.
- $argument->is_default = TRUE;
}
// Set the argument, which will also validate that the argument can be set.
@@ -1150,7 +1148,7 @@ class view extends views_db_object {
$cache = $this->display_handler->get_plugin('cache');
}
if ($cache && $cache->cache_get('results')) {
- if($this->query->pager->use_pager()) {
+ if($this->query->pager->use_pager() || !empty($this->get_total_rows)) {
$this->query->pager->total_items = $this->total_rows;
$this->query->pager->update_page_info();
}
@@ -1593,7 +1591,7 @@ class view extends views_db_object {
$position = 0;
if (!empty($this->argument)) {
foreach ($this->argument as $argument_id => $argument) {
- if (!empty($argument->is_default) && !empty($argument->options['default_argument_skip_url'])) {
+ if (!empty($argument->options['default_argument_skip_url'])) {
unset($args[$position]);
}
$position++;
@@ -1818,6 +1816,9 @@ class view extends views_db_object {
$this->vid = $vid ? $vid : NULL;
}
+ // Let modules modify the view just prior to saving it.
+ module_invoke_all('views_view_presave', $this);
+
$transaction = db_transaction();
try {
@@ -1848,6 +1849,9 @@ class view extends views_db_object {
// Clear caches.
views_invalidate_cache();
+
+ // Notify modules that this view has been saved.
+ module_invoke_all('views_view_save', $this);
}
/**
@@ -1887,6 +1891,9 @@ class view extends views_db_object {
// Clear caches.
views_invalidate_cache();
}
+
+ // Notify modules that this view has been deleted.
+ module_invoke_all('views_view_delete', $this);
}
/**
@@ -2076,25 +2083,26 @@ class view extends views_db_object {
}
/**
- * Find and initialize the localizer plugin.
+ * Find and initialize the localization plugin.
*/
function init_localization() {
- if (isset($this->localization_plugin) && is_object($this->localization_plugin)) {
- return TRUE;
+ // If the translate attribute isn't set, init the localization plugin.
+ if (!isset($this->localization_plugin->translate)) {
+ $this->localization_plugin = views_get_plugin('localization', views_get_localization_plugin());
+
+ // If the plugin is still not set, turn off all localization by using the
+ // views_plugin_localization_none plugin. This plugin has the translate
+ // property set to FALSE, signifying localization should not occur.
+ if (empty($this->localization_plugin)) {
+ $this->localization_plugin = views_get_plugin('localization', 'none');
+ }
+
+ // Init the plugin.
+ $this->localization_plugin->init($this);
}
- $this->localization_plugin = views_get_plugin('localization', views_get_localization_plugin());
-
- if (empty($this->localization_plugin)) {
- $this->localization_plugin = views_get_plugin('localization', 'none');
- return FALSE;
- }
-
- /**
- * Figure out whether there should be options.
- */
- $this->localization_plugin->init($this);
-
+ // Return the value of the translate property. This is set to FALSE if
+ // localization is off.
return $this->localization_plugin->translate;
}
@@ -2102,6 +2110,10 @@ class view extends views_db_object {
* Determine whether a view supports admin string translation.
*/
function is_translatable() {
+ // Use translation no matter what type of view.
+ if (variable_get('views_localize_all', FALSE)) {
+ return TRUE;
+ }
// If the view is normal or overridden, use admin string translation.
// A newly created view won't have a type. Accept this.
return (!isset($this->type) || in_array($this->type, array(t('Normal'), t('Overridden')))) ? TRUE : FALSE;
@@ -2566,7 +2578,7 @@ class views_display extends views_db_object {
var $display_options;
var $db_table = 'views_display';
- function views_display($init = TRUE) {
+ function __construct($init = TRUE) {
parent::init($init);
}
diff --git a/sites/all/modules/contrib/views/views/js/ajax_view.js b/sites/all/modules/contrib/views/views/js/ajax_view.js
index 7d54c676..ce6cc52d 100644
--- a/sites/all/modules/contrib/views/views/js/ajax_view.js
+++ b/sites/all/modules/contrib/views/views/js/ajax_view.js
@@ -57,7 +57,7 @@ Drupal.views.ajaxView = function(settings) {
this.settings = settings;
// Add the ajax to exposed forms.
- this.$exposed_form = this.$view.children('.view-filters').children('form');
+ this.$exposed_form = $('#views-exposed-form-'+ settings.view_name.replace(/_/g, '-') + '-' + settings.view_display_id.replace(/_/g, '-'));
this.$exposed_form.once(jQuery.proxy(this.attachExposedFormAjax, this));
// Add the ajax to pagers.
diff --git a/sites/all/modules/contrib/views/views/js/views-admin.js b/sites/all/modules/contrib/views/views/js/views-admin.js
index 2b4ccf33..3d91fae4 100644
--- a/sites/all/modules/contrib/views/views/js/views-admin.js
+++ b/sites/all/modules/contrib/views/views/js/views-admin.js
@@ -352,7 +352,7 @@ Drupal.viewsUi.OptionsSearch.prototype.handleKeyup = function (event) {
// Determine the user's search query. The search text has been converted to
// lowercase.
- search = this.$searchBox.val().toLowerCase();
+ search = (this.$searchBox.val() || '').toLowerCase();
words = search.split(' ');
wordsLength = words.length;
diff --git a/sites/all/modules/contrib/views/views/modules/comment/views_plugin_row_comment_rss.inc b/sites/all/modules/contrib/views/views/modules/comment/views_plugin_row_comment_rss.inc
index d287b8e7..e349590d 100644
--- a/sites/all/modules/contrib/views/views/modules/comment/views_plugin_row_comment_rss.inc
+++ b/sites/all/modules/contrib/views/views/modules/comment/views_plugin_row_comment_rss.inc
@@ -107,7 +107,7 @@ class views_plugin_row_comment_rss extends views_plugin_row {
),
array(
'key' => 'dc:creator',
- 'value' => $comment->name,
+ 'value' => format_username($comment),
),
array(
'key' => 'guid',
diff --git a/sites/all/modules/contrib/views/views/modules/field.views.inc b/sites/all/modules/contrib/views/views/modules/field.views.inc
index 0bf1ad2b..eae7f6d4 100644
--- a/sites/all/modules/contrib/views/views/modules/field.views.inc
+++ b/sites/all/modules/contrib/views/views/modules/field.views.inc
@@ -435,45 +435,6 @@ function field_views_field_default_views_data($field) {
'field_name' => $field['field_name'],
);
}
-
- // Expose additional language column for translatable fields.
- if (!empty($field['translatable'])) {
- $title_language = t('@label (!name:language)', array('@label' => $label, '!name' => $field['field_name']));
- $title_short_language = t('@label:language', array('@label' => $label));
-
- $data[$table]['language'] = array(
- 'group' => $group,
- 'title' => $title_language,
- 'title short' => $title_short_language,
- 'help' => t('Language - Appears in: @bundles.', array('@bundles' => implode(', ', $bundles_names))),
- );
- $data[$table]['language']['field'] = array(
- 'handler' => 'views_handler_field_locale_language',
- );
- $data[$table]['language']['argument'] = array(
- 'field' => 'language',
- 'table' => $table,
- 'handler' => 'views_handler_argument_locale_language',
- 'additional fields' => $additional_fields,
- 'empty field name' => t(''),
- 'field_name' => $field['field_name'],
- );
- $data[$table]['language']['filter'] = array(
- 'field' => 'language',
- 'table' => $table,
- 'handler' => 'views_handler_filter_locale_language',
- 'additional fields' => $additional_fields,
- 'field_name' => $field['field_name'],
- 'allow empty' => TRUE,
- );
- $data[$table]['language']['sort'] = array(
- 'field' => 'language',
- 'table' => $table,
- 'handler' => 'views_handler_sort',
- 'additional fields' => $additional_fields,
- 'field_name' => $field['field_name'],
- );
- }
}
}
diff --git a/sites/all/modules/contrib/views/views/modules/field/views_handler_field_field.inc b/sites/all/modules/contrib/views/views/modules/field/views_handler_field_field.inc
index a91e13a0..e30a1e83 100644
--- a/sites/all/modules/contrib/views/views/modules/field/views_handler_field_field.inc
+++ b/sites/all/modules/contrib/views/views/modules/field/views_handler_field_field.inc
@@ -383,6 +383,10 @@ class views_handler_field_field extends views_handler_field {
'default' => FALSE,
'bool' => TRUE,
);
+ $options['delta_random'] = array(
+ 'default' => FALSE,
+ 'bool' => TRUE,
+ );
$options['multi_type'] = array(
'default' => 'separator'
@@ -576,6 +580,14 @@ class views_handler_field_field extends views_handler_field {
'#title' => t('First and last only'),
'#type' => 'checkbox',
'#default_value' => $this->options['delta_first_last'],
+ '#suffix' => $suffix,
+ '#dependency' => array('edit-options-group-rows' => array(TRUE)),
+ '#fieldset' => 'multiple_field_settings',
+ );
+ $form['delta_random'] = array(
+ '#title' => t('Random order'),
+ '#type' => 'checkbox',
+ '#default_value' => $this->options['delta_random'],
'#suffix' => '
',
'#dependency' => array('edit-options-group-rows' => array(TRUE)),
'#fieldset' => 'multiple_field_settings',
@@ -716,6 +728,10 @@ class views_handler_field_field extends views_handler_field {
}
function get_value($values, $field = NULL) {
+ if (!isset($values->_field_data[$this->field_alias]['entity']) || !is_object($values->_field_data[$this->field_alias]['entity'])) {
+ return array();
+ }
+
// Go ahead and render and store in $this->items.
$entity = clone $values->_field_data[$this->field_alias]['entity'];
@@ -757,6 +773,11 @@ class views_handler_field_field extends views_handler_field {
return array();
}
+ // If requested, randomize the order of the deltas.
+ if ($this->options['delta_random'] && !empty($entity->{$this->definition['field_name']})) {
+ shuffle($entity->{$this->definition['field_name']}[$langcode]);
+ }
+
// We are supposed to show only certain deltas.
if ($this->limit_values && !empty($entity->{$this->definition['field_name']})) {
$all_values = !empty($entity->{$this->definition['field_name']}[$langcode]) ? $entity->{$this->definition['field_name']}[$langcode] : array();
diff --git a/sites/all/modules/contrib/views/views/modules/locale.views.inc b/sites/all/modules/contrib/views/views/modules/locale.views.inc
index 3bff7dbd..fe6d0509 100644
--- a/sites/all/modules/contrib/views/views/modules/locale.views.inc
+++ b/sites/all/modules/contrib/views/views/modules/locale.views.inc
@@ -218,4 +218,11 @@ function locale_views_data_alter(&$data) {
'handler' => 'views_handler_sort',
),
);
+ $data['node']['specific_language'] = array(
+ 'title' => t('Specific language'),
+ 'help' => t('Sort by a specific language that the content is in.'),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort_node_language',
+ ),
+ );
}
diff --git a/sites/all/modules/contrib/views/views/modules/locale/views_handler_field_locale_link_edit.inc b/sites/all/modules/contrib/views/views/modules/locale/views_handler_field_locale_link_edit.inc
index 37893551..811bcb27 100644
--- a/sites/all/modules/contrib/views/views/modules/locale/views_handler_field_locale_link_edit.inc
+++ b/sites/all/modules/contrib/views/views/modules/locale/views_handler_field_locale_link_edit.inc
@@ -52,7 +52,7 @@ class views_handler_field_locale_link_edit extends views_handler_field {
$text = !empty($this->options['text']) ? $this->options['text'] : t('edit');
$this->options['alter']['make_link'] = TRUE;
- $this->options['alter']['path'] = 'admin/build/translate/edit/' . $data;
+ $this->options['alter']['path'] = 'admin/config/regional/translate/edit/' . $data;
$this->options['alter']['query'] = drupal_get_destination();
return $text;
diff --git a/sites/all/modules/contrib/views/views/modules/locale/views_handler_sort_node_language.inc b/sites/all/modules/contrib/views/views/modules/locale/views_handler_sort_node_language.inc
new file mode 100644
index 00000000..b4298917
--- /dev/null
+++ b/sites/all/modules/contrib/views/views/modules/locale/views_handler_sort_node_language.inc
@@ -0,0 +1,107 @@
+options['language'])) {
+ $langcode = $this->get_system_langcode($this->options['language']);
+ // Validate the langcode.
+ if (preg_match('/^[a-z0-9\-]+$/i', $langcode)) {
+ $this->ensure_my_table();
+ // See https://stackoverflow.com/questions/14104055/ordering-by-specific-field-value-first
+ $formula = "{$this->table_alias}_language = '{$langcode}'";
+ $this->query->add_orderby($this->table_alias, NULL, $this->options['order'], $formula);
+ }
+ }
+ }
+
+ /**
+ * Converts a views language code into a Drupal language code.
+ */
+ function get_system_langcode($langcode) {
+ global $language_content;
+ $default_language = language_default('language');
+ $system_langcode = str_replace(array(
+ '***CURRENT_LANGUAGE***',
+ '***DEFAULT_LANGUAGE***',
+ ),
+ array(
+ $language_content->language,
+ $default_language,
+ ),
+ $langcode);
+ return $system_langcode;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ function option_definition() {
+ $options = parent::option_definition();
+ $options['language'] = array('default' => '***CURRENT_LANGUAGE***');
+ return $options;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ function admin_summary() {
+ $summary = parent::admin_summary();
+ if ($this->options['language']) {
+ $language_options = $this->get_language_options();
+ $summary = t('@order, @language', array(
+ '@order' => $summary,
+ '@language' => $language_options[$this->options['language']],
+ ));
+ }
+ return $summary;
+ }
+
+ /**
+ * Returns languages to sort by.
+ *
+ * @return array
+ * All the languages.
+ */
+ function get_language_options() {
+ $languages = array(
+ '***CURRENT_LANGUAGE***' => t("Current user's language"),
+ '***DEFAULT_LANGUAGE***' => t("Default site language"),
+ LANGUAGE_NONE => t('No language')
+ );
+ $languages = array_merge($languages, views_language_list());
+ return $languages;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ function show_sort_form(&$form, &$form_state) {
+ parent::show_sort_form($form, $form_state);
+
+ $form['language'] = array(
+ '#type' => 'radios',
+ '#title' => t("Specific language"),
+ '#description' => t("Choose which specific language to sort by. Not to be confused with the 'Language' sort handler, which sorts by language."),
+ '#options' => $this->get_language_options(),
+ '#default_value' => $this->options['language'],
+ );
+ }
+
+}
+
diff --git a/sites/all/modules/contrib/views/views/modules/node.views.inc b/sites/all/modules/contrib/views/views/modules/node.views.inc
index 71a10237..1a9c76bd 100644
--- a/sites/all/modules/contrib/views/views/modules/node.views.inc
+++ b/sites/all/modules/contrib/views/views/modules/node.views.inc
@@ -406,6 +406,23 @@ function node_views_data() {
),
);
+ $data['node']['version_count'] = array(
+ 'title' => t('Version Count'),
+ 'help' => t('The total count of versions/revisions of a certain node.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field_node_version_count',
+ 'field' => 'nid',
+ 'click sortable' => TRUE,
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_node_version_count',
+ 'allow empty' => FALSE,
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort_node_version_count',
+ ),
+ );
+
// ----------------------------------------------------------------------
// Content revision table
@@ -413,6 +430,7 @@ function node_views_data() {
// have a group defined will go into this field by default.
$data['node_revisions']['moved to'] = 'node_revision';
$data['node_revision']['table']['entity type'] = 'node';
+ $data['node_revision']['table']['revision'] = TRUE;
$data['node_revision']['table']['group'] = t('Content revision');
// Support the conversion of the field body
$data['node_revisions']['body']['moved to'] = array('field_revision_data', 'body-revision_id');
diff --git a/sites/all/modules/contrib/views/views/modules/node/views_handler_field_node_version_count.inc b/sites/all/modules/contrib/views/views/modules/node/views_handler_field_node_version_count.inc
new file mode 100644
index 00000000..73c2925d
--- /dev/null
+++ b/sites/all/modules/contrib/views/views/modules/node/views_handler_field_node_version_count.inc
@@ -0,0 +1,21 @@
+ensure_my_table();
+ // Add the field.
+ $params = $this->options['group_type'] != 'group' ? array('function' => $this->options['group_type']) : array();
+ $this->field_alias = $this->query->add_field(NULL, '(SELECT COUNT(vid) FROM {node_revision} WHERE nid = {node}.nid)', 'node_version_count', $params);
+
+ $this->add_additional_fields();
+ }
+}
diff --git a/sites/all/modules/contrib/views/views/modules/node/views_handler_filter_node_uid_revision.inc b/sites/all/modules/contrib/views/views/modules/node/views_handler_filter_node_uid_revision.inc
index 4d3d9a70..f8f4000c 100644
--- a/sites/all/modules/contrib/views/views/modules/node/views_handler_filter_node_uid_revision.inc
+++ b/sites/all/modules/contrib/views/views/modules/node/views_handler_filter_node_uid_revision.inc
@@ -18,7 +18,7 @@ class views_handler_filter_node_uid_revision extends views_handler_filter_user_n
$args = array_values($this->value);
- $this->query->add_where_expression($this->options['group'], "$this->table_alias.uid IN($placeholder) " . $condition . " OR
+ $this->query->add_where_expression($this->options['group'], "$this->table_alias.uid IN($placeholder) " . "OR
((SELECT COUNT(*) FROM {node_revision} nr WHERE nr.uid IN($placeholder) AND nr.nid = $this->table_alias.nid) > 0)", array($placeholder => $args),
$args);
}
diff --git a/sites/all/modules/contrib/views/views/modules/node/views_handler_filter_node_version_count.inc b/sites/all/modules/contrib/views/views/modules/node/views_handler_filter_node_version_count.inc
new file mode 100644
index 00000000..c39f1d9f
--- /dev/null
+++ b/sites/all/modules/contrib/views/views/modules/node/views_handler_filter_node_version_count.inc
@@ -0,0 +1,36 @@
+operator == 'between') {
+ $this->query->add_where_expression($this->options['group'], '(SELECT COUNT(vid) FROM {node_revision} WHERE nid = {' . $this->table_alias . '}.nid) BETWEEN :min AND :max', array(':min' => $this->value['min'], ':max' => $this->value['max']));
+ }
+ else {
+ $this->query->add_where_expression($this->options['group'], '((SELECT COUNT(vid) FROM {node_revision} WHERE nid = {' . $this->table_alias . '}.nid) <= :min OR (SELECT COUNT(vid) FROM {node_revision} WHERE nid = {' . $this->table_alias . '}.nid) >= :max)', array(':min' => $this->value['min'], ':max' => $this->value['max']));
+ }
+ }
+
+ function op_simple($field) {
+ $this->query->add_where_expression($this->options['group'], '(SELECT COUNT(vid) FROM {node_revision} WHERE nid = {' . $this->table_alias . '}.nid)' . $this->operator . ' :value', array(':value' => $this->value['value']));
+ }
+
+ function op_empty($field) {
+ if ($this->operator == 'empty') {
+ $operator = "IS NULL";
+ }
+ else {
+ $operator = "IS NOT NULL";
+ }
+
+ $this->query->add_where_expression($this->options['group'], '(SELECT COUNT(vid) FROM {node_revision} WHERE nid = {' . $this->table_alias . '}.nid) ' . $this->operator);
+ }
+
+ function op_regex($field) {
+ $this->query->add_where_expression($this->options['group'], '(SELECT COUNT(vid) FROM {node_revision} WHERE nid = {' . $this->table_alias . '}.nid) RLIKE :value', array(':value' => $this->value['value']));
+ }
+}
diff --git a/sites/all/modules/contrib/views/views/modules/node/views_handler_sort_node_version_count.inc b/sites/all/modules/contrib/views/views/modules/node/views_handler_sort_node_version_count.inc
new file mode 100644
index 00000000..a8e1cf6e
--- /dev/null
+++ b/sites/all/modules/contrib/views/views/modules/node/views_handler_sort_node_version_count.inc
@@ -0,0 +1,19 @@
+ensure_my_table();
+
+ $this->query->add_orderby(NULL, '(SELECT COUNT(vid) FROM {node_revision} WHERE nid = {' . $this->table_alias . '}.nid)', $this->options['order'], 'sort_node_version_count');
+ }
+}
diff --git a/sites/all/modules/contrib/views/views/modules/node/views_plugin_row_node_rss.inc b/sites/all/modules/contrib/views/views/modules/node/views_plugin_row_node_rss.inc
index 5da746b2..66718925 100644
--- a/sites/all/modules/contrib/views/views/modules/node/views_plugin_row_node_rss.inc
+++ b/sites/all/modules/contrib/views/views/modules/node/views_plugin_row_node_rss.inc
@@ -117,7 +117,7 @@ class views_plugin_row_node_rss extends views_plugin_row {
),
array(
'key' => 'dc:creator',
- 'value' => $node->name,
+ 'value' => format_username($node),
),
array(
'key' => 'guid',
diff --git a/sites/all/modules/contrib/views/views/modules/search/views_handler_argument_search.inc b/sites/all/modules/contrib/views/views/modules/search/views_handler_argument_search.inc
index f0a4a448..959a25af 100644
--- a/sites/all/modules/contrib/views/views/modules/search/views_handler_argument_search.inc
+++ b/sites/all/modules/contrib/views/views/modules/search/views_handler_argument_search.inc
@@ -56,7 +56,7 @@ class views_handler_argument_search extends views_handler_argument {
$join->construct('search_total', $search_index, 'word', 'word');
$search_total = $this->query->add_relationship('search_total', $join, $search_index);
- $this->search_score = $this->query->add_field('', "SUM($search_index.score * $search_total.count)", 'score', array('aggregate' => TRUE));
+ $this->search_score = $this->query->add_field('', "$search_index.score * $search_total.count", 'score', array('aggregate' => TRUE, 'function' => 'sum'));
if (empty($this->query->relationships[$this->relationship])) {
$base_table = $this->query->base_table;
diff --git a/sites/all/modules/contrib/views/views/modules/search/views_handler_filter_search.inc b/sites/all/modules/contrib/views/views/modules/search/views_handler_filter_search.inc
index 16515a76..0b93031c 100644
--- a/sites/all/modules/contrib/views/views/modules/search/views_handler_filter_search.inc
+++ b/sites/all/modules/contrib/views/views/modules/search/views_handler_filter_search.inc
@@ -150,7 +150,7 @@ class views_handler_filter_search extends views_handler_filter {
$join->construct('search_total', $search_index, 'word', 'word');
$search_total = $this->query->add_relationship('search_total', $join, $search_index);
- $this->search_score = $this->query->add_field('', "SUM($search_index.score * $search_total.count)", 'score', array('aggregate' => TRUE));
+ $this->search_score = $this->query->add_field('', "$search_index.score * $search_total.count", 'score', array('aggregate' => TRUE, 'function' => 'sum'));
}
if (empty($this->query->relationships[$this->relationship])) {
diff --git a/sites/all/modules/contrib/views/views/modules/statistics.views.inc b/sites/all/modules/contrib/views/views/modules/statistics.views.inc
index d6637f3e..6d99c5e6 100644
--- a/sites/all/modules/contrib/views/views/modules/statistics.views.inc
+++ b/sites/all/modules/contrib/views/views/modules/statistics.views.inc
@@ -32,7 +32,7 @@ function statistics_views_data() {
'help' => t('The total number of times the node has been viewed.'),
'field' => array(
- 'handler' => 'views_handler_field_numeric',
+ 'handler' => 'views_handler_field_statistics_numeric',
'click sortable' => TRUE,
),
'filter' => array(
@@ -49,7 +49,7 @@ function statistics_views_data() {
'help' => t('The total number of times the node has been viewed today.'),
'field' => array(
- 'handler' => 'views_handler_field_numeric',
+ 'handler' => 'views_handler_field_statistics_numeric',
'click sortable' => TRUE,
),
'filter' => array(
@@ -66,7 +66,7 @@ function statistics_views_data() {
'help' => t('The most recent time the node has been viewed.'),
'field' => array(
- 'handler' => 'views_handler_field_date',
+ 'handler' => 'views_handler_field_node_counter_timestamp',
'click sortable' => TRUE,
),
'filter' => array(
diff --git a/sites/all/modules/contrib/views/views/modules/statistics/views_handler_field_node_counter_timestamp.inc b/sites/all/modules/contrib/views/views/modules/statistics/views_handler_field_node_counter_timestamp.inc
new file mode 100644
index 00000000..d665519b
--- /dev/null
+++ b/sites/all/modules/contrib/views/views/modules/statistics/views_handler_field_node_counter_timestamp.inc
@@ -0,0 +1,21 @@
+ t('Display content if it has the selected taxonomy terms, or children of the selected terms. Due to additional complexity, this has fewer options than the versions without depth.'),
+ 'real field' => 'nid',
+ 'argument' => array(
+ 'title' => t('Has taxonomy term ID with depth (using joins)'),
+ 'handler' => 'views_handler_argument_term_node_tid_depth_join',
+ 'accept depth modifier' => TRUE,
+ ),
+ 'filter' => array(
+ 'title' => t('Has taxonomy terms with depth (using joins)'),
+ 'handler' => 'views_handler_filter_term_node_tid_depth_join',
+ ),
+ );
+
$data['node']['term_node_tid_depth_modifier'] = array(
'title' => t('Has taxonomy term ID depth modifier'),
'help' => t('Allows the "depth" for Taxonomy: Term ID (with depth) to be modified via an additional contextual filter value.'),
diff --git a/sites/all/modules/contrib/views/views/modules/taxonomy/views_handler_argument_term_node_tid_depth_join.inc b/sites/all/modules/contrib/views/views/modules/taxonomy/views_handler_argument_term_node_tid_depth_join.inc
new file mode 100644
index 00000000..23ac62d1
--- /dev/null
+++ b/sites/all/modules/contrib/views/views/modules/taxonomy/views_handler_argument_term_node_tid_depth_join.inc
@@ -0,0 +1,191 @@
+ 0);
+ $options['break_phrase'] = array('default' => FALSE, 'bool' => TRUE);
+ $options['set_breadcrumb'] = array('default' => FALSE, 'bool' => TRUE);
+ $options['use_taxonomy_term_path'] = array('default' => FALSE, 'bool' => TRUE);
+
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ $form['depth'] = array(
+ '#type' => 'weight',
+ '#title' => t('Depth'),
+ '#default_value' => $this->options['depth'],
+ '#description' => t('The depth will match nodes tagged with terms in the hierarchy. For example, if you have the term "fruit" and a child term "apple", with a depth of 1 (or higher) then filtering for the term "fruit" will get nodes that are tagged with "apple" as well as "fruit". If negative, the reverse is true; searching for "apple" will also pick up nodes tagged with "fruit" if depth is -1 (or lower).'),
+ );
+
+ $form['break_phrase'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Allow multiple values'),
+ '#description' => t('If selected, users can enter multiple values in the form of 1+2+3. Due to the number of JOINs it would require, AND will be treated as OR with this filter.'),
+ '#default_value' => !empty($this->options['break_phrase']),
+ );
+
+ $form['set_breadcrumb'] = array(
+ '#type' => 'checkbox',
+ '#title' => t("Set the breadcrumb for the term parents"),
+ '#description' => t('If selected, the breadcrumb trail will include all parent terms, each one linking to this view. Note that this only works if just one term was received.'),
+ '#default_value' => !empty($this->options['set_breadcrumb']),
+ );
+
+ $form['use_taxonomy_term_path'] = array(
+ '#type' => 'checkbox',
+ '#title' => t("Use Drupal's taxonomy term path to create breadcrumb links"),
+ '#description' => t('If selected, the links in the breadcrumb trail will be created using the standard drupal method instead of the custom views method. This is useful if you are using modules like taxonomy redirect to modify your taxonomy term links.'),
+ '#default_value' => !empty($this->options['use_taxonomy_term_path']),
+ '#dependency' => array('edit-options-set-breadcrumb' => array(TRUE)),
+ );
+ parent::options_form($form, $form_state);
+ }
+
+ function set_breadcrumb(&$breadcrumb) {
+ if (empty($this->options['set_breadcrumb']) || !is_numeric($this->argument)) {
+ return;
+ }
+
+ return views_taxonomy_set_breadcrumb($breadcrumb, $this);
+ }
+
+ /**
+ * Override default_actions() to remove summary actions.
+ */
+ function default_actions($which = NULL) {
+ if ($which) {
+ if (in_array($which, array('ignore', 'not found', 'empty', 'default'))) {
+ return parent::default_actions($which);
+ }
+ return;
+ }
+ $actions = parent::default_actions();
+ unset($actions['summary asc']);
+ unset($actions['summary desc']);
+ unset($actions['summary asc by count']);
+ unset($actions['summary desc by count']);
+ return $actions;
+ }
+
+ function query($group_by = FALSE) {
+ $this->ensure_my_table();
+
+ if (!empty($this->options['break_phrase'])) {
+ $tids = new stdClass();
+ $tids->value = $this->argument;
+ $tids = views_break_phrase($this->argument, $tids);
+ if ($tids->value == array(-1)) {
+ return FALSE;
+ }
+
+ if (count($tids->value) > 1) {
+ $operator = 'IN';
+ }
+ else {
+ $operator = '=';
+ }
+
+ $tids = $tids->value;
+ }
+ else {
+ $operator = "=";
+ $tids = $this->argument;
+ }
+
+ // The tids variable can be an integer or an array of integers.
+ $tids = is_array($tids) ? $tids : array($tids);
+
+ if ($this->options['depth'] > 0) {
+ // When the depth is positive search the children.
+ foreach ($tids as $tid) {
+ // The term must be loaded to get vid for use in taxonomy_get_tree().
+ if ($term = taxonomy_term_load($tid)) {
+ // For every tid argument find all the children down to the depth set
+ // in the options and save the tids for the condition.
+ $tree = taxonomy_get_tree($term->vid, $term->tid, (int) $this->options['depth']);
+ $tids = array_merge($tids, array_map('_taxonomy_get_tid_from_term', $tree));
+ }
+ }
+ }
+ elseif ($this->options['depth'] < 0) {
+ // When the depth is negative search the parents.
+ foreach ($tids as $tid) {
+ // For every tid argument find all the parents up to the depth set
+ // in the options and add the tids into the array. Since there is
+ // no taxonomy function to get all parents with a depth limit it
+ // is done here building a multidimensional array.
+ if ($term = taxonomy_term_load($tid)) {
+ // A variable is needed to track the current depth level.
+ $n = 0;
+ // Initialise our depth based parents array with the leaf term.
+ $parents[$n--][] = $term;
+ while ($n >= $this->options['depth']) {
+ // At each depth find the parents of the current terms.
+ // It is important to note that it is possible for a term to have
+ // multiple parents so get the parents of every parent and so on.
+ $parents[$n] = array();
+ foreach ($parents[$n + 1] as $term) {
+ $parents[$n] += taxonomy_get_parents($term->tid);
+ }
+ // Save all the tids for the condition.
+ $tids = array_merge($tids, array_map('_taxonomy_get_tid_from_term', $parents[$n]));
+ $n--;
+ }
+ }
+ }
+ }
+
+ // Check the size of the array and set the operator accordingly.
+ if (count($tids) > 1) {
+ $operator = 'IN';
+ }
+ else {
+ $tids = current($tids);
+ $operator = '=';
+ }
+
+ // Join on taxonomy index table.
+ $join = new views_join();
+ $join->table = 'taxonomy_index';
+ $join->field = 'nid';
+ $join->left_table = $this->table_alias;
+ $join->left_field = $this->real_field;
+ $join->type = 'INNER';
+ $join->extra = array(
+ array(
+ 'field' => 'tid',
+ 'value' => $tids,
+ 'operator' => $operator,
+ )
+ );
+ $taxonomy_index_alias = $this->query->add_relationship('taxonomy_index', $join, 'node');
+
+ // Distinct is required to prevent duplicate rows.
+ $this->query->distinct = TRUE;
+ }
+
+ function title() {
+ $term = taxonomy_term_load($this->argument);
+ if (!empty($term)) {
+ return check_plain($term->name);
+ }
+
+ return t('No name');
+ }
+}
diff --git a/sites/all/modules/contrib/views/views/modules/taxonomy/views_handler_filter_term_node_tid.inc b/sites/all/modules/contrib/views/views/modules/taxonomy/views_handler_filter_term_node_tid.inc
index 8938ca9f..ca2b3449 100644
--- a/sites/all/modules/contrib/views/views/modules/taxonomy/views_handler_filter_term_node_tid.inc
+++ b/sites/all/modules/contrib/views/views/modules/taxonomy/views_handler_filter_term_node_tid.inc
@@ -206,6 +206,9 @@ class views_handler_filter_term_node_tid extends views_handler_filter_many_to_on
if (empty($form_state['exposed'])) {
// Retain the helper option
$this->helper->options_form($form, $form_state);
+
+ // Show help text if not exposed to end users.
+ $form['value']['#description'] = t('Leave blank for all. Otherwise, the first selected term will be the default instead of "Any".');
}
}
@@ -228,12 +231,25 @@ class views_handler_filter_term_node_tid extends views_handler_filter_many_to_on
return TRUE;
}
+ // We need to know the operator, which is normally set in
+ // views_handler_filter::accept_exposed_input(), before we actually call
+ // the parent version of ourselves.
+ if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator_id']) && isset($input[$this->options['expose']['operator_id']])) {
+ $this->operator = $input[$this->options['expose']['operator_id']];
+ }
+
// If view is an attachment and is inheriting exposed filters, then assume
// exposed input has already been validated
if (!empty($this->view->is_attachment) && $this->view->display_handler->uses_exposed()) {
$this->validated_exposed_input = (array) $this->view->exposed_raw_input[$this->options['expose']['identifier']];
}
+ // If we're checking for EMPTY or NOT, we don't need any input, and we can
+ // say that our input conditions are met by just having the right operator.
+ if ($this->operator == 'empty' || $this->operator == 'not empty') {
+ return TRUE;
+ }
+
// If it's non-required and there's no value don't bother filtering.
if (!$this->options['expose']['required'] && empty($this->validated_exposed_input)) {
return FALSE;
diff --git a/sites/all/modules/contrib/views/views/modules/taxonomy/views_handler_filter_term_node_tid_depth_join.inc b/sites/all/modules/contrib/views/views/modules/taxonomy/views_handler_filter_term_node_tid_depth_join.inc
new file mode 100644
index 00000000..8139b8d0
--- /dev/null
+++ b/sites/all/modules/contrib/views/views/modules/taxonomy/views_handler_filter_term_node_tid_depth_join.inc
@@ -0,0 +1,142 @@
+ t('Is one of'),
+ );
+ }
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['depth'] = array('default' => 0);
+
+ return $options;
+ }
+
+ function extra_options_form(&$form, &$form_state) {
+ parent::extra_options_form($form, $form_state);
+
+ $form['depth'] = array(
+ '#type' => 'weight',
+ '#title' => t('Depth'),
+ '#default_value' => $this->options['depth'],
+ '#description' => t('The depth will match nodes tagged with terms in the hierarchy. For example, if you have the term "fruit" and a child term "apple", with a depth of 1 (or higher) then filtering for the term "fruit" will get nodes that are tagged with "apple" as well as "fruit". If negative, the reverse is true; searching for "apple" will also pick up nodes tagged with "fruit" if depth is -1 (or lower).'),
+ );
+ }
+
+ function query() {
+ // If no filter values are present, then do nothing.
+ if (count($this->value) == 0) {
+ return;
+ }
+ elseif (count($this->value) == 1) {
+ // Somethis $this->value is an array with a single element so convert it.
+ if (is_array($this->value)) {
+ $this->value = current($this->value);
+ }
+ $operator = '=';
+ }
+ else {
+ $operator = 'IN';# " IN (" . implode(', ', array_fill(0, sizeof($this->value), '%d')) . ")";
+ }
+
+ // The normal use of ensure_my_table() here breaks Views.
+ // So instead we trick the filter into using the alias of the base table.
+ // See http://drupal.org/node/271833
+ // If a relationship is set, we must use the alias it provides.
+ if (!empty($this->relationship)) {
+ $this->table_alias = $this->relationship;
+ }
+ // If no relationship, then use the alias of the base table.
+ elseif (isset($this->query->table_queue[$this->query->base_table]['alias'])) {
+ $this->table_alias = $this->query->table_queue[$this->query->base_table]['alias'];
+ }
+ // This should never happen, but if it does, we fail quietly.
+ else {
+ return;
+ }
+
+ // The tids variable can be an integer or an array of integers.
+ $tids = is_array($this->value) ? $this->value : array($this->value);
+
+ if ($this->options['depth'] > 0) {
+ // When the depth is positive search the children.
+ foreach ($tids as $tid) {
+ // The term must be loaded to get vid for use in taxonomy_get_tree().
+ if ($term = taxonomy_term_load($tid)) {
+ // For every tid argument find all the children down to the depth set
+ // in the options and save the tids for the condition.
+ $tree = taxonomy_get_tree($term->vid, $term->tid, (int) $this->options['depth']);
+ $tids = array_merge($tids, array_map('_taxonomy_get_tid_from_term', $tree));
+ }
+ }
+ }
+ elseif ($this->options['depth'] < 0) {
+ // When the depth is negative search the parents.
+ foreach ($tids as $tid) {
+ // For every tid argument find all the parents up to the depth set
+ // in the options and add the tids into the array. Since there is
+ // no taxonomy function to get all parents with a depth limit it
+ // is done here building a multidimensional array.
+ if ($term = taxonomy_term_load($tid)) {
+ // A variable is needed to track the current depth level.
+ $n = 0;
+ // Initialise our depth based parents array with the leaf term.
+ $parents[$n--][] = $term;
+ while ($n >= $this->options['depth']) {
+ // At each depth find the parents of the current terms.
+ // It is important to note that it is possible for a term to have
+ // multiple parents so get the parents of every parent and so on.
+ $parents[$n] = array();
+ foreach ($parents[$n + 1] as $term) {
+ $parents[$n] += taxonomy_get_parents($term->tid);
+ }
+ // Save all the tids for the condition.
+ $tids = array_merge($tids, array_map('_taxonomy_get_tid_from_term', $parents[$n]));
+ $n--;
+ }
+ }
+ }
+ }
+
+ // Check the size of the array and set the operator accordingly.
+ if (count($tids) > 1) {
+ $operator = 'IN';
+ }
+ else {
+ $tids = current($tids);
+ $operator = '=';
+ }
+
+ // Join on taxonomy index table.
+ $join = new views_join();
+ $join->table = 'taxonomy_index';
+ $join->field = 'nid';
+ $join->left_table = $this->table_alias;
+ $join->left_field = $this->real_field;
+ $join->type = 'INNER';
+ $join->extra = array(
+ array(
+ 'field' => 'tid',
+ 'value' => $tids,
+ 'operator' => $operator,
+ )
+ );
+ $taxonomy_index_alias = $this->query->add_relationship('taxonomy_index', $join, 'node');
+ }
+}
diff --git a/sites/all/modules/contrib/views/views/modules/translation.views.inc b/sites/all/modules/contrib/views/views/modules/translation.views.inc
index b36c7a78..584c63f9 100644
--- a/sites/all/modules/contrib/views/views/modules/translation.views.inc
+++ b/sites/all/modules/contrib/views/views/modules/translation.views.inc
@@ -51,7 +51,7 @@ function translation_views_data_alter(&$data) {
),
);
- // The source translation.
+ // All translations.
$data['node']['translation'] = array(
'group' => t('Content translation'),
'title' => t('Translations'),
@@ -62,7 +62,7 @@ function translation_views_data_alter(&$data) {
'base' => 'node',
'base field' => 'tnid',
'relationship table' => 'node',
- 'relationship field' => 'nid',
+ 'relationship field' => 'tnid',
'handler' => 'views_handler_relationship_translation',
'label' => t('Translations'),
),
@@ -78,7 +78,7 @@ function translation_views_data_alter(&$data) {
),
);
- // The source translation.
+ // Child translation.
$data['node']['child_translation'] = array(
'group' => t('Node translation'),
'title' => t('Child translation'),
diff --git a/sites/all/modules/contrib/views/views/modules/views.views.inc b/sites/all/modules/contrib/views/views/modules/views.views.inc
index 7c3f4db9..ce3aad38 100644
--- a/sites/all/modules/contrib/views/views/modules/views.views.inc
+++ b/sites/all/modules/contrib/views/views/modules/views.views.inc
@@ -99,6 +99,14 @@ function views_views_data() {
);
}
+ $data['views']['ctools_dropdown'] = array(
+ 'title' => t('Dropdown links'),
+ 'help' => t('Displays fields in a dropdown list, like on the views listing page.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field_ctools_dropdown',
+ ),
+ );
+
$data['views']['combine'] = array(
'title' => t('Combine fields filter'),
'help' => t('Combine two fields together and search by them.'),
diff --git a/sites/all/modules/contrib/views/views/plugins/export_ui/views_ui.class.php b/sites/all/modules/contrib/views/views/plugins/export_ui/views_ui.class.php
index 9d801382..6f87e401 100644
--- a/sites/all/modules/contrib/views/views/plugins/export_ui/views_ui.class.php
+++ b/sites/all/modules/contrib/views/views/plugins/export_ui/views_ui.class.php
@@ -385,8 +385,8 @@ class views_ui extends ctools_export_ui {
$output = parent::list_page($js, $input);
if (is_string($output)) {
$output = '
' . $output . '
';
- return $output;
}
+ return $output;
}
}
diff --git a/sites/all/modules/contrib/views/views/plugins/views_plugin_argument_validate.inc b/sites/all/modules/contrib/views/views/plugins/views_plugin_argument_validate.inc
index 07b49eeb..350cb439 100644
--- a/sites/all/modules/contrib/views/views/plugins/views_plugin_argument_validate.inc
+++ b/sites/all/modules/contrib/views/views/plugins/views_plugin_argument_validate.inc
@@ -86,7 +86,7 @@ class views_plugin_argument_validate extends views_plugin {
/**
* Process the summary arguments for displaying.
*
- * Some plugins alter the argument so it uses something else interal.
+ * Some plugins alter the argument so it uses something else internally.
* For example the user validation set's the argument to the uid,
* for a faster query. But there are use cases where you want to use
* the old value again, for example the summary.
diff --git a/sites/all/modules/contrib/views/views/plugins/views_plugin_cache.inc b/sites/all/modules/contrib/views/views/plugins/views_plugin_cache.inc
index 81f71bfb..0dfc9114 100644
--- a/sites/all/modules/contrib/views/views/plugins/views_plugin_cache.inc
+++ b/sites/all/modules/contrib/views/views/plugins/views_plugin_cache.inc
@@ -206,14 +206,14 @@ class views_plugin_cache extends views_plugin {
// Slightly less simple for CSS:
$css = drupal_add_css();
$css_start = isset($this->storage['css']) ? $this->storage['css'] : array();
- $this->storage['css'] = $array_mapping_func($css, $css_start);
+ $this->storage['css'] = $this->assetDiff($css, $css_start, $array_mapping_func);
// Get javascript after/before views renders.
$js = drupal_add_js();
$js_start = isset($this->storage['js']) ? $this->storage['js'] : array();
// If there are any differences between the old and the new javascript then
// store them to be added later.
- $this->storage['js'] = $array_mapping_func($js, $js_start);
+ $this->storage['js'] = $this->assetDiff($js, $js_start, $array_mapping_func);
// Special case the settings key and get the difference of the data.
$settings = isset($js['settings']['data']) ? $js['settings']['data'] : array();
@@ -224,6 +224,38 @@ class views_plugin_cache extends views_plugin {
$this->storage['headers'] = $array_mapping_func(drupal_get_http_header(), $this->storage['headers']);
}
+ /**
+ * Computes the differences between two JS/CSS asset arrays.
+ *
+ * @param array $assets
+ * The current asset array.
+ * @param array $start_assets
+ * The original asset array.
+ * @param string $diff_function
+ * The function that should be used for computing the diff.
+ *
+ * @return array
+ * A CSS or JS asset array that contains all entries that are new/different
+ * in $assets.
+ */
+ protected function assetDiff(array $assets, array $start_assets, $diff_function) {
+ $diff = $diff_function($assets, $start_assets);
+
+ // Cleanup the resulting array since drupal_array_diff_assoc_recursive() can
+ // leave half populated arrays behind.
+ foreach ($diff as $key => $entry) {
+ // If only the weight was different we can remove this entry.
+ if (count($entry) == 1 && isset($entry['weight'])) {
+ unset($diff[$key]);
+ }
+ // If there are other differences we override with the latest entry.
+ elseif ($entry != $assets[$key]) {
+ $diff[$key] = $assets[$key];
+ }
+ }
+ return $diff;
+ }
+
/**
* Restore out of band data saved to cache. Copied from Panels.
*/
diff --git a/sites/all/modules/contrib/views/views/plugins/views_plugin_cache_time.inc b/sites/all/modules/contrib/views/views/plugins/views_plugin_cache_time.inc
index 25245ea4..d3ab7f92 100644
--- a/sites/all/modules/contrib/views/views/plugins/views_plugin_cache_time.inc
+++ b/sites/all/modules/contrib/views/views/plugins/views_plugin_cache_time.inc
@@ -107,4 +107,21 @@ class views_plugin_cache_time extends views_plugin_cache {
return CACHE_PERMANENT;
}
}
+
+ function cache_set($type) {
+ $lifespan = $this->get_lifespan($type);
+ if ($lifespan >= 0) {
+ parent::cache_set($type);
+ }
+ }
+
+ function cache_get($type) {
+ $lifespan = $this->get_lifespan($type);
+ if ($lifespan >= 0) {
+ return parent::cache_get($type);
+ }
+ else {
+ return FALSE;
+ }
+ }
}
diff --git a/sites/all/modules/contrib/views/views/plugins/views_plugin_display.inc b/sites/all/modules/contrib/views/views/plugins/views_plugin_display.inc
index db124de0..a4b732e8 100644
--- a/sites/all/modules/contrib/views/views/plugins/views_plugin_display.inc
+++ b/sites/all/modules/contrib/views/views/plugins/views_plugin_display.inc
@@ -53,7 +53,7 @@ class views_plugin_display extends views_plugin {
$this->extender[$extender] = $plugin;
}
else {
- vpr('Invalid display extender @extender', array('@handler' => $extender));
+ vpr('Invalid display extender @extender', array('@extender' => $extender));
}
}
}
@@ -739,7 +739,7 @@ class views_plugin_display extends views_plugin {
function uses_link_display() { return !$this->has_path(); }
/**
- * Check to see if the display can put the exposed formin a block.
+ * Check to see if the display can put the exposed form in a block.
*
* By default, displays that do not have a path cannot disconnect
* the exposed form and put it in a block, because the form has no
@@ -1150,7 +1150,7 @@ class views_plugin_display extends views_plugin {
);
}
- $display_comment = check_plain(drupal_substr($this->get_option('display_comment'), 0, 10));
+ $display_comment = check_plain(views_ui_truncate($this->get_option('display_comment'), 80));
$options['display_comment'] = array(
'category' => 'other',
'title' => t('Comment'),
@@ -1419,7 +1419,7 @@ class views_plugin_display extends views_plugin {
}
$form['#title'] = check_plain($this->display->display_title) . ': ';
- // Set the 'section' to hilite on the form.
+ // Set the 'section' to highlight on the form.
// If it's the item we're looking at is pulling from the default display,
// reflect that. Don't use is_defaulted since we want it to show up even
// on the default display.
@@ -1573,8 +1573,12 @@ class views_plugin_display extends views_plugin {
$plugin = $this->get_plugin('access');
$form['#title'] .= t('Access options');
if ($plugin) {
- $form['#help_topic'] = $plugin->definition['help topic'];
- $form['#help_module'] = $plugin->definition['module'];
+ if (!empty($plugin->definition['help topic'])) {
+ $form['#help_topic'] = $plugin->definition['help topic'];
+ }
+ if (!empty($plugin->definition['module'])) {
+ $form['#help_module'] = $plugin->definition['module'];
+ }
$form['access_options'] = array(
'#tree' => TRUE,
@@ -1615,8 +1619,12 @@ class views_plugin_display extends views_plugin {
$plugin = $this->get_plugin('cache');
$form['#title'] .= t('Caching options');
if ($plugin) {
- $form['#help_topic'] = $plugin->definition['help topic'];
- $form['#help_module'] = $plugin->definition['module'];
+ if (!empty($plugin->definition['help topic'])) {
+ $form['#help_topic'] = $plugin->definition['help topic'];
+ }
+ if (!empty($plugin->definition['module'])) {
+ $form['#help_module'] = $plugin->definition['module'];
+ }
$form['cache_options'] = array(
'#tree' => TRUE,
@@ -1635,11 +1643,10 @@ class views_plugin_display extends views_plugin {
$form['#title'] .= t('Query options');
$this->view->init_query();
if ($this->view->query) {
- if (isset($this->view->query->definition['help topic'])) {
+ if (!empty($this->view->query->definition['help topic'])) {
$form['#help_topic'] = $this->view->query->definition['help topic'];
}
-
- if (isset($this->view->query->definition['module'])) {
+ if (!empty($this->view->query->definition['module'])) {
$form['#help_module'] = $this->view->query->definition['module'];
}
@@ -1734,8 +1741,10 @@ class views_plugin_display extends views_plugin {
}
$plugin = $this->get_plugin(empty($style) ? 'row' : 'style');
if ($plugin) {
- if (isset($plugin->definition['help topic'])) {
+ if (!empty($plugin->definition['help topic'])) {
$form['#help_topic'] = $plugin->definition['help topic'];
+ }
+ if (!empty($plugin->definition['module'])) {
$form['#help_module'] = $plugin->definition['module'];
}
$form[$form_state['section']] = array(
@@ -2117,7 +2126,12 @@ class views_plugin_display extends views_plugin {
$plugin = $this->get_plugin('exposed_form');
$form['#title'] .= t('Exposed form options');
if ($plugin) {
- $form['#help_topic'] = $plugin->definition['help topic'];
+ if (!empty($plugin->definition['help topic'])) {
+ $form['#help_topic'] = $plugin->definition['help topic'];
+ }
+ if (!empty($plugin->definition['module'])) {
+ $form['#help_module'] = $plugin->definition['module'];
+ }
$form['exposed_form_options'] = array(
'#tree' => TRUE,
@@ -2140,7 +2154,7 @@ class views_plugin_display extends views_plugin {
'#default_value' => $pager['type'],
);
- $pager_plugin = views_fetch_plugin_data('pager', $pager['type'], array($this->view->base_table));
+ $pager_plugin = views_fetch_plugin_data('pager', $pager['type']);
if (!empty($pager_plugin['uses options'])) {
$form['markup'] = array(
'#prefix' => '
',
@@ -2154,7 +2168,12 @@ class views_plugin_display extends views_plugin {
$plugin = $this->get_plugin('pager');
$form['#title'] .= t('Pager options');
if ($plugin) {
- $form['#help_topic'] = $plugin->definition['help topic'];
+ if (!empty($plugin->definition['help topic'])) {
+ $form['#help_topic'] = $plugin->definition['help topic'];
+ }
+ if (!empty($plugin->definition['module'])) {
+ $form['#help_module'] = $plugin->definition['module'];
+ }
$form['pager_options'] = array(
'#tree' => TRUE,
@@ -2556,6 +2575,23 @@ class views_plugin_display extends views_plugin {
$url_options['query'] = $this->view->exposed_raw_input;
}
$theme = views_theme_functions('views_more', $this->view, $this->display);
+
+ $parsed_url = drupal_parse_url($path);
+ // Preserve the query string from url.
+ if (!empty($parsed_url['query'])) {
+ if (!empty($url_options['query'])) {
+ $url_options['query'] = array_merge($parsed_url['query'], $url_options['query']);
+ }
+ else {
+ $url_options['query'] = $parsed_url['query'];
+ }
+ $path = $parsed_url['path'];
+ }
+ // Add fragment if applicable.
+ if (!empty($parsed_url['fragment'])) {
+ $url_options['fragment'] = $parsed_url['fragment'];
+ }
+
$path = check_url(url($path, $url_options));
return theme($theme, array('more_url' => $path, 'link_text' => check_plain($this->use_more_text()), 'view' => $this->view));
diff --git a/sites/all/modules/contrib/views/views/plugins/views_plugin_display_attachment.inc b/sites/all/modules/contrib/views/views/plugins/views_plugin_display_attachment.inc
index 91c8d1f9..8608cfc8 100644
--- a/sites/all/modules/contrib/views/views/plugins/views_plugin_display_attachment.inc
+++ b/sites/all/modules/contrib/views/views/plugins/views_plugin_display_attachment.inc
@@ -227,6 +227,8 @@ class views_plugin_display_attachment extends views_plugin_display {
$args = $this->get_option('inherit_arguments') ? $this->view->args : array();
$view->set_arguments($args);
+ $exposed_input = $this->get_option('inherit_exposed_filters') ? $this->view->exposed_input : array();
+ $view->set_exposed_input($exposed_input);
$view->set_display($this->display->id);
if ($this->get_option('inherit_pager')) {
$view->display_handler->use_pager = $this->view->display[$display_id]->handler->use_pager();
diff --git a/sites/all/modules/contrib/views/views/plugins/views_plugin_display_block.inc b/sites/all/modules/contrib/views/views/plugins/views_plugin_display_block.inc
index c903a9b6..d581a16a 100644
--- a/sites/all/modules/contrib/views/views/plugins/views_plugin_display_block.inc
+++ b/sites/all/modules/contrib/views/views/plugins/views_plugin_display_block.inc
@@ -222,8 +222,8 @@ class views_plugin_display_block extends views_plugin_display {
}
/**
- * Save the block cache setting in the blocks table if this block allready
- * exists in the blocks table. Dirty fix untill http://drupal.org/node/235673 gets in.
+ * Save the block cache setting in the blocks table if this block already
+ * exists in the blocks table. Dirty fix until http://drupal.org/node/235673 gets in.
*/
function save_block_cache($delta, $cache_setting) {
if (strlen($delta) >= 32) {
diff --git a/sites/all/modules/contrib/views/views/plugins/views_plugin_query_default.inc b/sites/all/modules/contrib/views/views/plugins/views_plugin_query_default.inc
index 8a15e8dc..7468dd95 100644
--- a/sites/all/modules/contrib/views/views/plugins/views_plugin_query_default.inc
+++ b/sites/all/modules/contrib/views/views/plugins/views_plugin_query_default.inc
@@ -143,7 +143,7 @@ class views_plugin_query_default extends views_plugin_query {
);
/**
- * -- we no longer want the base field to appear automatigically.
+ * -- we no longer want the base field to appear automatically.
if ($base_field) {
$this->fields[$base_field] = array(
'table' => $base_table,
@@ -888,7 +888,7 @@ class views_plugin_query_default extends views_plugin_query {
/**
* Add a complex WHERE clause to the query.
*
- * The caller is reponsible for ensuring that all fields are fully qualified
+ * The caller is responsible for ensuring that all fields are fully qualified
* (TABLE.FIELD) and that the table already exists in the query.
* Internally the dbtng method "where" is used.
*
@@ -1322,6 +1322,10 @@ class views_plugin_query_default extends views_plugin_query {
if (count($this->having)) {
$this->has_aggregate = TRUE;
}
+ elseif (!$this->has_aggregate) {
+ // Allow 'GROUP BY' even no aggregation function has been set.
+ $this->has_aggregate = $this->view->display_handler->get_option('group_by');
+ }
if ($this->has_aggregate && (!empty($this->groupby) || !empty($non_aggregates))) {
$groupby = array_unique(array_merge($this->groupby, $non_aggregates));
foreach ($groupby as $field) {
@@ -1588,7 +1592,7 @@ class views_plugin_query_default extends views_plugin_query {
'sort' => 'views_handler_sort_group_by_numeric',
),
)
- );
+ ) + views_fetch_plugin_data('query_aggregate');
}
/**
@@ -1616,7 +1620,8 @@ class views_plugin_query_default extends views_plugin_query {
}
$entity_type = $table_data['table']['entity type'];
$info = entity_get_info($entity_type);
- $id_alias = $this->get_field_alias($base_table_alias, $info['entity keys']['id']);
+ $is_revision = !empty($table_data['table']['revision']);
+ $id_alias = $this->get_field_alias($base_table_alias, $info['entity keys'][$is_revision ? 'revision' : 'id']);
// Assemble the ids of the entities to load.
$ids = array();
@@ -1626,12 +1631,34 @@ class views_plugin_query_default extends views_plugin_query {
}
}
- $entities = entity_load($entity_type, $ids);
- // Re-key the array by row-index.
- $result = array();
- foreach ($ids as $key => $id) {
- $result[$key] = isset($entities[$id]) ? $entities[$id] : FALSE;
+ if (!$is_revision) {
+ $entities = entity_load($entity_type, $ids);
+
+ // Re-key the array by row-index.
+ $result = array();
+ foreach ($ids as $key => $id) {
+ $result[$key] = isset($entities[$id]) ? $entities[$id] : FALSE;
+ }
}
+ else {
+ // There's no way in core to load revisions in bulk.
+ $result = array();
+ foreach ($ids as $key => $id) {
+ // Nodes can be dealt with in core.
+ if ($entity_type == 'node') {
+ $result[$key] = node_load(NULL, $id);
+ }
+ // Otherwise see if entity is enabled.
+ elseif (module_exists('entity')) {
+ $result[$key] = entity_revision_load($entity_type, $id);
+ }
+ else {
+ // Otherwise this isn't supported.
+ watchdog('views', 'Attempt to load a revision on an unsupported entity type @entity_type.', array('@entity_type' => $entity_type), WATCHDOG_WARNING);
+ }
+ }
+ }
+
return array($entity_type, $result);
}
}
diff --git a/sites/all/modules/contrib/views/views/plugins/views_plugin_style.inc b/sites/all/modules/contrib/views/views/plugins/views_plugin_style.inc
index d355e1bc..fe126071 100644
--- a/sites/all/modules/contrib/views/views/plugins/views_plugin_style.inc
+++ b/sites/all/modules/contrib/views/views/plugins/views_plugin_style.inc
@@ -123,13 +123,23 @@ class views_plugin_style extends views_plugin {
function get_row_class($row_index) {
if ($this->uses_row_class()) {
$class = $this->options['row_class'];
+
if ($this->uses_fields() && $this->view->field) {
- $class = strip_tags($this->tokenize_value($class, $row_index));
+ $classes = array();
+
+ // Explode the value by whitespace, this allows the function to handle
+ // a single class name and multiple class names that are then tokenized.
+ foreach(explode(' ', $class) as $token_class) {
+ $classes[] = strip_tags($this->tokenize_value($token_class, $row_index));
+ }
+ }
+ else {
+ $classes = explode(' ', $class);
}
- $classes = explode(' ', $class);
+ // Convert whatever the result is to a nice clean class name
foreach ($classes as &$class) {
- $class = drupal_clean_css_identifier($class);
+ $class = drupal_html_class($class);
}
return implode(' ', $classes);
}
@@ -182,7 +192,7 @@ class views_plugin_style extends views_plugin {
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
// Only fields-based views can handle grouping. Style plugins can also exclude
- // themselves from being groupable by setting their "use grouping" definiton
+ // themselves from being groupable by setting their "use grouping" definition
// key to FALSE.
// @TODO: Document "uses grouping" in docs.php when docs.php is written.
if ($this->uses_fields() && $this->definition['uses grouping']) {
@@ -191,7 +201,7 @@ class views_plugin_style extends views_plugin {
$options += $field_labels;
// If there are no fields, we can't group on them.
if (count($options) > 1) {
- // This is for backward compability, when there was just a single select form.
+ // This is for backward compatibility, when there was just a single select form.
if (is_string($this->options['grouping'])) {
$grouping = $this->options['grouping'];
$this->options['grouping'] = array();
@@ -419,7 +429,7 @@ class views_plugin_style extends views_plugin {
* @endcode
*/
function render_grouping($records, $groupings = array(), $group_rendered = NULL) {
- // This is for backward compability, when $groupings was a string containing
+ // This is for backward compatibility, when $groupings was a string containing
// the ID of a single field.
if (is_string($groupings)) {
$rendered = $group_rendered === NULL ? TRUE : $group_rendered;
@@ -486,7 +496,7 @@ class views_plugin_style extends views_plugin {
);
}
- // If this parameter isn't explicitely set modify the output to be fully
+ // If this parameter isn't explicitly set modify the output to be fully
// backward compatible to code before Views 7.x-3.0-rc2.
// @TODO Remove this as soon as possible e.g. October 2020
if ($group_rendered === NULL) {
diff --git a/sites/all/modules/contrib/views/views/plugins/views_plugin_style_rss.inc b/sites/all/modules/contrib/views/views/plugins/views_plugin_style_rss.inc
index 27106a89..79fef3d0 100644
--- a/sites/all/modules/contrib/views/views/plugins/views_plugin_style_rss.inc
+++ b/sites/all/modules/contrib/views/views/plugins/views_plugin_style_rss.inc
@@ -71,6 +71,36 @@ class views_plugin_style_rss extends views_plugin_style {
return array();
}
+ /**
+ * Return an atom:link XHTML element to add to the channel to comply with
+ * the RSS 2.0 specification.
+ *
+ * @see http://validator.w3.org/feed/docs/warning/MissingAtomSelfLink.html
+ *
+ * @return
+ * An array that can be passed to format_xml_elements().
+ */
+ function get_channel_elements_atom_link() {
+ $url_options = array('absolute' => TRUE);
+ $input = $this->view->get_exposed_input();
+ if ($input) {
+ $url_options['query'] = $input;
+ }
+ $url = url($this->view->get_url(), $url_options);
+
+ return array(
+ array(
+ 'namespace' => array('xmlns:atom' => 'http://www.w3.org/2005/Atom'),
+ 'key' => 'atom:link',
+ 'attributes' => array(
+ 'href' => $url,
+ 'rel' => 'self',
+ 'type' => 'application/rss+xml',
+ ),
+ ),
+ );
+ }
+
/**
* Get RSS feed description.
*
@@ -99,7 +129,10 @@ class views_plugin_style_rss extends views_plugin_style {
// Fetch any additional elements for the channel and merge in their
// namespaces.
- $this->channel_elements = $this->get_channel_elements();
+ $this->channel_elements = array_merge(
+ $this->get_channel_elements(),
+ $this->get_channel_elements_atom_link()
+ );
foreach ($this->channel_elements as $element) {
if (isset($element['namespace'])) {
$this->namespaces = array_merge($this->namespaces, $element['namespace']);
diff --git a/sites/all/modules/contrib/views/views/test_templates/README.txt b/sites/all/modules/contrib/views/views/test_templates/README.txt
new file mode 100644
index 00000000..551f738f
--- /dev/null
+++ b/sites/all/modules/contrib/views/views/test_templates/README.txt
@@ -0,0 +1,11 @@
+Workaround for:
+
+- https://www.drupal.org/node/2450447
+- https://www.drupal.org/node/2415991
+
+
+Files of this folder cannot be included inside the views/tests directory because
+they are included as tests cases and make testbot crash.
+
+This files could be moved to tests/templates once
+https://www.drupal.org/node/2415991 be properly fixed.
diff --git a/sites/all/modules/contrib/views/views/tests/templates/views-view--frontpage.tpl.php b/sites/all/modules/contrib/views/views/test_templates/views-view--frontpage.tpl.php
similarity index 100%
rename from sites/all/modules/contrib/views/views/tests/templates/views-view--frontpage.tpl.php
rename to sites/all/modules/contrib/views/views/test_templates/views-view--frontpage.tpl.php
diff --git a/sites/all/modules/contrib/views/views/tests/handlers/views_handler_filter_date.test b/sites/all/modules/contrib/views/views/tests/handlers/views_handler_filter_date.test
index 34ccba66..8b92ccb5 100644
--- a/sites/all/modules/contrib/views/views/tests/handlers/views_handler_filter_date.test
+++ b/sites/all/modules/contrib/views/views/tests/handlers/views_handler_filter_date.test
@@ -50,6 +50,21 @@ class ViewsHandlerFilterDateTest extends ViewsSqlTest {
$this->assertIdenticalResultset($view, $expected_result, $this->map);
$view->destroy();
+ // Test "first day of" type of relative dates for simple operator.
+ $view->set_display('default');
+ $view->init_handlers();
+ $view->filter['created']->operator = '<';
+ $view->filter['created']->value['type'] = 'offset';
+ $view->filter['created']->value['value'] = 'last day of January 1970';
+ $view->execute_display('default');
+ $expected_result = array(
+ array('nid' => $this->nodes[0]->nid),
+ array('nid' => $this->nodes[1]->nid),
+ array('nid' => $this->nodes[2]->nid),
+ );
+ $this->assertIdenticalResultset($view, $expected_result, $this->map);
+ $view->destroy();
+
// Test offset for between operator.
$view->set_display('default');
$view->init_handlers();
@@ -63,6 +78,22 @@ class ViewsHandlerFilterDateTest extends ViewsSqlTest {
);
$this->assertIdenticalResultset($view, $expected_result, $this->map);
$view->destroy();
+
+ // Test "first day of" type of relative dates for between operator.
+ $view->set_display('default');
+ $view->init_handlers();
+ $view->filter['created']->operator = 'between';
+ $view->filter['created']->value['type'] = 'offset';
+ $view->filter['created']->value['max'] = 'last day of January 1970';
+ $view->filter['created']->value['min'] = 'first day of January 1970';
+ $view->execute_display('default');
+ $expected_result = array(
+ array('nid' => $this->nodes[0]->nid),
+ array('nid' => $this->nodes[1]->nid),
+ array('nid' => $this->nodes[2]->nid),
+ );
+ $this->assertIdenticalResultset($view, $expected_result, $this->map);
+ $view->destroy();
}
diff --git a/sites/all/modules/contrib/views/views/tests/styles/views_plugin_style.test b/sites/all/modules/contrib/views/views/tests/styles/views_plugin_style.test
index dfc5413a..2bb28574 100644
--- a/sites/all/modules/contrib/views/views/tests/styles/views_plugin_style.test
+++ b/sites/all/modules/contrib/views/views/tests/styles/views_plugin_style.test
@@ -241,7 +241,7 @@ class ViewsPluginStyleTestCase extends ViewsPluginStyleTestBase {
// Setup some random css class.
$view->init_display();
$view->init_style();
- $random_name = $this->randomName();
+ $random_name = drupal_html_class($this->randomName());
$view->style_plugin->options['row_class'] = $random_name . " test-token-[name]";
$rendered_output = $view->preview();
@@ -255,7 +255,7 @@ class ViewsPluginStyleTestCase extends ViewsPluginStyleTestBase {
$this->assertTrue(strpos($class, $random_name) !== FALSE, 'Take sure that a custom css class is added to the output.');
// Check token replacement.
- $name = $view->field['name']->get_value($view->result[$count]);
+ $name = drupal_html_class($view->field['name']->get_value($view->result[$count]));
$this->assertTrue(strpos($class, "test-token-$name") !== FALSE, 'Take sure that a token in custom css class is replaced.');
$count++;
diff --git a/sites/all/modules/contrib/views/views/tests/views_groupby.test b/sites/all/modules/contrib/views/views/tests/views_groupby.test
index 718d8dc0..4e092565 100644
--- a/sites/all/modules/contrib/views/views/tests/views_groupby.test
+++ b/sites/all/modules/contrib/views/views/tests/views_groupby.test
@@ -108,11 +108,14 @@ class ViewsQueryGroupByTest extends ViewsSqlTest {
}
/**
- * @param $group_by
- * Which group_by function should be used, for example sum or count.
+ * @param string|null $group_by
+ * (optional) Which group_by function should be used, for example sum or
+ * count. If omitted, the aggregation is tested with no group function.
+ * @param array|null $values
+ * (optional) Expected values.
*/
- function GroupByTestHelper($group_by, $values) {
- // Create 2 nodes of type1 and 3 nodes of type2
+ function GroupByTestHelper($group_by = NULL, $values = NULL) {
+ // Create 4 nodes of type1 and 3 nodes of type2
$type1 = $this->drupalCreateContentType();
$type2 = $this->drupalCreateContentType();
@@ -136,6 +139,19 @@ class ViewsQueryGroupByTest extends ViewsSqlTest {
$output = $view->execute_display();
$this->assertEqual(count($view->result), 2, 'Make sure the count of items is right.');
+
+ $results = array();
+ // There's no need for a function in order to have aggregation.
+ if (empty($group_by)) {
+ $types = array($type1->type, $type2->type);
+ $results = array_map(function ($item) { return $item->node_type; }, $view->result);
+ sort($types);
+ sort($results);
+ $this->assertIdentical($results, $types);
+ // Exit here with no aggregation function.
+ return;
+ }
+
// Group by nodetype to identify the right count.
foreach ($view->result as $item) {
$results[$item->node_type] = $item->nid;
@@ -144,7 +160,7 @@ class ViewsQueryGroupByTest extends ViewsSqlTest {
$this->assertEqual($results[$type2->type], $values[1]);
}
- function viewsGroupByViewHelper($group_by) {
+ function viewsGroupByViewHelper($group_by = NULL) {
$view = new view;
$view->name = 'group_by_count';
$view->description = '';
@@ -164,21 +180,27 @@ class ViewsQueryGroupByTest extends ViewsSqlTest {
$handler->display->display_options['pager']['type'] = 'some';
$handler->display->display_options['style_plugin'] = 'default';
$handler->display->display_options['row_plugin'] = 'fields';
- /* Field: Content: Nid */
- $handler->display->display_options['fields']['nid']['id'] = 'nid';
- $handler->display->display_options['fields']['nid']['table'] = 'node';
- $handler->display->display_options['fields']['nid']['field'] = 'nid';
- $handler->display->display_options['fields']['nid']['group_type'] = $group_by;
- $handler->display->display_options['fields']['nid']['alter']['alter_text'] = 0;
- $handler->display->display_options['fields']['nid']['alter']['make_link'] = 0;
- $handler->display->display_options['fields']['nid']['alter']['trim'] = 0;
- $handler->display->display_options['fields']['nid']['alter']['word_boundary'] = 1;
- $handler->display->display_options['fields']['nid']['alter']['ellipsis'] = 1;
- $handler->display->display_options['fields']['nid']['alter']['strip_tags'] = 0;
- $handler->display->display_options['fields']['nid']['alter']['html'] = 0;
- $handler->display->display_options['fields']['nid']['hide_empty'] = 0;
- $handler->display->display_options['fields']['nid']['empty_zero'] = 0;
- $handler->display->display_options['fields']['nid']['link_to_node'] = 0;
+
+ // The test view has 2 fields ('nid' and 'type'). Don't add 'nid' when
+ // having no aggregation function. We just want to aggregate on node type.
+ if (!empty($group_by)) {
+ /* Field: Content: Nid */
+ $handler->display->display_options['fields']['nid']['id'] = 'nid';
+ $handler->display->display_options['fields']['nid']['table'] = 'node';
+ $handler->display->display_options['fields']['nid']['field'] = 'nid';
+ $handler->display->display_options['fields']['nid']['group_type'] = $group_by;
+ $handler->display->display_options['fields']['nid']['alter']['alter_text'] = 0;
+ $handler->display->display_options['fields']['nid']['alter']['make_link'] = 0;
+ $handler->display->display_options['fields']['nid']['alter']['trim'] = 0;
+ $handler->display->display_options['fields']['nid']['alter']['word_boundary'] = 1;
+ $handler->display->display_options['fields']['nid']['alter']['ellipsis'] = 1;
+ $handler->display->display_options['fields']['nid']['alter']['strip_tags'] = 0;
+ $handler->display->display_options['fields']['nid']['alter']['html'] = 0;
+ $handler->display->display_options['fields']['nid']['hide_empty'] = 0;
+ $handler->display->display_options['fields']['nid']['empty_zero'] = 0;
+ $handler->display->display_options['fields']['nid']['link_to_node'] = 0;
+ }
+
/* Field: Content: Type */
$handler->display->display_options['fields']['type']['id'] = 'type';
$handler->display->display_options['fields']['type']['table'] = 'node';
@@ -218,6 +240,10 @@ class ViewsQueryGroupByTest extends ViewsSqlTest {
$this->GroupByTestHelper('max', array(4, 7));
}
+ function testGroupByNone() {
+ $this->GroupByTestHelper();
+ }
+
public function testGroupByCountOnlyFilters() {
// Check if GROUP BY and HAVING are included when a view
// Doesn't display SUM, COUNT, MAX... functions in SELECT statment
diff --git a/sites/all/modules/contrib/views/views/tests/views_module.test b/sites/all/modules/contrib/views/views/tests/views_module.test
index 6a27443a..e160964a 100644
--- a/sites/all/modules/contrib/views/views/tests/views_module.test
+++ b/sites/all/modules/contrib/views/views/tests/views_module.test
@@ -194,6 +194,30 @@ class ViewsModuleTest extends ViewsSqlTest {
$this->assertEqual(variable_get('views_test_views_data_count', 0), 1, 'Views data rebuilt once');
$this->assertFalse(drupal_static('_views_fetch_data_fully_loaded'), 'Views data is not fully loaded');
+
+ // Test if the cache consistency is ensured. There was an issue where
+ // calling _views_fetch_data() first with a table would prevent the function
+ // from properly rebuilt a missing the general cache entry.
+ // See https://www.drupal.org/node/2475669 for details.
+ // Make sure we start with a empty cache.
+ $this->resetStaticViewsDataCache();
+ cache_clear_all('*', 'cache_views', TRUE);
+
+ // Prime the static cache of _views_fetch_data() by calling it with a table
+ // first.
+ views_fetch_data('views_test');
+ // Now remove the general cache.
+ cache_clear_all('views_data:en', 'cache_views');
+ // Reset the static cache to see if fetches from the persistent cache
+ // properly rebuild the static cache.
+ $this->resetStaticViewsDataCache();
+ // Prime the static cache of _views_fetch_data() by calling it with a table
+ // first.
+ views_fetch_data('views_test');
+ // Fetch the general cache, which was deleted, an see if it is rebuild
+ // properly.
+ views_fetch_data();
+ $this->assertTrue(cache_get('views_data:en', 'cache_views'), 'Cache for all tables was properly rebuild.');
}
/**
diff --git a/sites/all/modules/contrib/views/views/tests/views_query.test b/sites/all/modules/contrib/views/views/tests/views_query.test
index 735df0ea..db7d6569 100644
--- a/sites/all/modules/contrib/views/views/tests/views_query.test
+++ b/sites/all/modules/contrib/views/views/tests/views_query.test
@@ -132,7 +132,6 @@ abstract class ViewsSqlTest extends ViewsTestCase {
variable_set('views_test_schema', $this->schemaDefinition());
variable_set('views_test_views_data', $this->viewsData());
variable_set('views_test_views_plugins', $this->viewsPlugins());
-
module_enable(array('views_test'));
$this->resetAll();
diff --git a/sites/all/modules/contrib/views/views/tests/views_test.info b/sites/all/modules/contrib/views/views/tests/views_test.info
index b090daa1..6e9008ed 100644
--- a/sites/all/modules/contrib/views/views/tests/views_test.info
+++ b/sites/all/modules/contrib/views/views/tests/views_test.info
@@ -5,9 +5,9 @@ core = 7.x
dependencies[] = views
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-02-11
-version = "7.x-3.10"
+; Information added by Drupal.org packaging script on 2016-06-15
+version = "7.x-3.14"
core = "7.x"
project = "views"
-datestamp = "1423648085"
+datestamp = "1466019588"
diff --git a/sites/all/modules/contrib/views/views/tests/views_test.module b/sites/all/modules/contrib/views/views/tests/views_test.module
index a7460690..be533e0c 100644
--- a/sites/all/modules/contrib/views/views/tests/views_test.module
+++ b/sites/all/modules/contrib/views/views/tests/views_test.module
@@ -23,7 +23,7 @@ function views_test_permission() {
function views_test_views_api() {
return array(
'api' => 3.0,
- 'template path' => drupal_get_path('module', 'views_test') . '/templates',
+ 'template path' => drupal_get_path('module', 'views') . '/test_templates',
);
}
diff --git a/sites/all/modules/contrib/views/views/theme/views-view-table.tpl.php b/sites/all/modules/contrib/views/views/theme/views-view-table.tpl.php
index 4fec9fa9..b3443fcc 100644
--- a/sites/all/modules/contrib/views/views/theme/views-view-table.tpl.php
+++ b/sites/all/modules/contrib/views/views/theme/views-view-table.tpl.php
@@ -27,7 +27,7 @@
$label): ?>
-
>
+
scope="col">
diff --git a/sites/all/modules/contrib/views/views/views.api.php b/sites/all/modules/contrib/views/views/views.api.php
index 70c5dc83..1c7b32b2 100644
--- a/sites/all/modules/contrib/views/views/views.api.php
+++ b/sites/all/modules/contrib/views/views/views.api.php
@@ -143,7 +143,7 @@
* responsible for building the query. Instead, they are objects that are used
* to display the view or make other modifications.
*
- * There are 10 types of plugins in Views:
+ * There are several types of plugins in Views:
* - Display: Display plugins are responsible for controlling *where* a view
* lives; that is, how they are being exposed to other parts of Drupal. Page
* and block are the most common displays, as well as the ubiquitous 'master'
@@ -431,7 +431,7 @@ function hook_views_data() {
'label' => t('Published'),
// This setting is used by the boolean filter handler, as possible option.
'type' => 'yes-no',
- // use boolean_field = 1 instead of boolean_field <> 0 in WHERE statment.
+ // use boolean_field = 1 instead of boolean_field <> 0 in WHERE statement.
'use equal' => TRUE,
),
'sort' => array(
@@ -602,7 +602,7 @@ function hook_field_views_data_views_data_alter(&$data, $field) {
* must be one of row, display, display_extender, style, argument default,
* argument validator, access, query, cache, pager, exposed_form or
* localization. The plugin name should be prefixed with your module name.
- * The value for each entry is an associateive array that may contain the
+ * The value for each entry is an associative array that may contain the
* following entries:
* - Used by all plugin types:
* - title (required): The name of the plugin, as shown in Views. Wrap in
@@ -723,7 +723,7 @@ function hook_views_plugins_alter(&$plugins) {
* - path: (optional) If includes are stored somewhere other than within the
* root module directory, specify its path here.
* - template path: (optional) A path where the module has stored it's views
- * template files. When you have specificed this key views automatically
+ * template files. When you have specified this key views automatically
* uses the template files for the views. You can use the same naming
* conventions like for normal views template files.
*/
@@ -859,7 +859,7 @@ function hook_views_default_views_alter(&$views) {
* The View being executed.
* @return
* An array with keys being the strings to replace, and the values the strings
- * to replace them with. The strings to replace are ofted surrounded with
+ * to replace them with. The strings to replace are often surrounded with
* '***', as illustrated in the example implementation.
*/
function hook_views_query_substitutions($view) {
@@ -924,7 +924,7 @@ function hook_views_pre_view(&$view, &$display_id, &$args) {
* The view object about to be processed.
*/
function hook_views_pre_build(&$view) {
- // Because of some unexplicable business logic, we should remove all
+ // Because of some inexplicable business logic, we should remove all
// attachments from all views on Mondays.
// (This alter could be done later in the execution process as well.)
if (date('D') == 'Mon') {
@@ -1075,7 +1075,7 @@ function hook_views_query_alter(&$view, &$query) {
// Traverse through the 'where' part of the query.
foreach ($query->where as &$condition_group) {
foreach ($condition_group['conditions'] as &$condition) {
- // If this is the part of the query filtering on title, chang the
+ // If this is the part of the query filtering on title, change the
// condition to filter on node ID.
if ($condition['field'] == 'node.title') {
$condition = array(
@@ -1153,8 +1153,8 @@ function hook_views_ajax_data_alter(&$commands, $view) {
// Replace Views' method for scrolling to the top of the element with your
// custom scrolling method.
foreach ($commands as &$command) {
- if ($command['method'] == 'viewsScrollTop') {
- $command['method'] .= 'myScrollTop';
+ if ($command['command'] == 'viewsScrollTop') {
+ $command['command'] .= 'myScrollTop';
}
}
}
@@ -1171,6 +1171,32 @@ function hook_views_invalidate_cache() {
cache_clear_all('views:*', 'cache_mymodule', TRUE);
}
+/**
+ * Allow modules to alter a view prior to being saved.
+ */
+function hook_views_view_presave($view) {
+ // Do some adjustments to the view. Handle with care.
+ if (mymodule_check_view($view)) {
+ mymodule_do_some_voodoo($view);
+ }
+}
+
+/**
+ * Allow modules to respond to a view being saved.
+ */
+function hook_views_view_save($view) {
+ // Make a watchdog entry.
+ watchdog('views', 'The view @name was deleted by @user at @time', array('@name' => $view->name, '@user' => $GLOBALS['user']->name, '@time' => format_date(time())));
+}
+
+/**
+ * Allow modules to respond to a view being deleted or reverted.
+ */
+function hook_views_view_delete($view) {
+ // Make a watchdog entry.
+ watchdog('views', 'The view @name was deleted by @user at @time', array('@name' => $view->name, '@user' => $GLOBALS['user']->name, '@time' => format_date(time())));
+}
+
/**
* @}
*/
diff --git a/sites/all/modules/contrib/views/views/views.info b/sites/all/modules/contrib/views/views/views.info
index 87b01b98..0b425f17 100644
--- a/sites/all/modules/contrib/views/views/views.info
+++ b/sites/all/modules/contrib/views/views/views.info
@@ -27,9 +27,11 @@ files[] = handlers/views_handler_field.inc
files[] = handlers/views_handler_field_counter.inc
files[] = handlers/views_handler_field_boolean.inc
files[] = handlers/views_handler_field_contextual_links.inc
+files[] = handlers/views_handler_field_ctools_dropdown.inc
files[] = handlers/views_handler_field_custom.inc
files[] = handlers/views_handler_field_date.inc
files[] = handlers/views_handler_field_entity.inc
+files[] = handlers/views_handler_field_links.inc
files[] = handlers/views_handler_field_markup.inc
files[] = handlers/views_handler_field_math.inc
files[] = handlers/views_handler_field_numeric.inc
@@ -116,6 +118,7 @@ files[] = modules/locale/views_handler_field_locale_link_edit.inc
files[] = modules/locale/views_handler_filter_locale_group.inc
files[] = modules/locale/views_handler_filter_locale_language.inc
files[] = modules/locale/views_handler_filter_locale_version.inc
+files[] = modules/locale/views_handler_sort_node_language.inc
files[] = modules/node/views_handler_argument_dates_various.inc
files[] = modules/node/views_handler_argument_node_language.inc
files[] = modules/node/views_handler_argument_node_nid.inc
@@ -133,11 +136,14 @@ files[] = modules/node/views_handler_field_node_revision_link_delete.inc
files[] = modules/node/views_handler_field_node_revision_link_revert.inc
files[] = modules/node/views_handler_field_node_path.inc
files[] = modules/node/views_handler_field_node_type.inc
+files[] = modules/node/views_handler_field_node_version_count.inc
files[] = modules/node/views_handler_filter_history_user_timestamp.inc
files[] = modules/node/views_handler_filter_node_access.inc
files[] = modules/node/views_handler_filter_node_status.inc
files[] = modules/node/views_handler_filter_node_type.inc
files[] = modules/node/views_handler_filter_node_uid_revision.inc
+files[] = modules/node/views_handler_filter_node_version_count.inc
+files[] = modules/node/views_handler_sort_node_version_count.inc
files[] = modules/node/views_plugin_argument_default_node.inc
files[] = modules/node/views_plugin_argument_validate_node.inc
files[] = modules/node/views_plugin_row_node_rss.inc
@@ -151,6 +157,8 @@ files[] = modules/search/views_handler_filter_search.inc
files[] = modules/search/views_handler_sort_search_score.inc
files[] = modules/search/views_plugin_row_search_view.inc
files[] = modules/statistics/views_handler_field_accesslog_path.inc
+files[] = modules/statistics/views_handler_field_node_counter_timestamp.inc
+files[] = modules/statistics/views_handler_field_statistics_numeric.inc
files[] = modules/system/views_handler_argument_file_fid.inc
files[] = modules/system/views_handler_field_file.inc
files[] = modules/system/views_handler_field_file_extension.inc
@@ -161,6 +169,7 @@ files[] = modules/system/views_handler_filter_file_status.inc
files[] = modules/taxonomy/views_handler_argument_taxonomy.inc
files[] = modules/taxonomy/views_handler_argument_term_node_tid.inc
files[] = modules/taxonomy/views_handler_argument_term_node_tid_depth.inc
+files[] = modules/taxonomy/views_handler_argument_term_node_tid_depth_join.inc
files[] = modules/taxonomy/views_handler_argument_term_node_tid_depth_modifier.inc
files[] = modules/taxonomy/views_handler_argument_vocabulary_vid.inc
files[] = modules/taxonomy/views_handler_argument_vocabulary_machine_name.inc
@@ -169,6 +178,7 @@ files[] = modules/taxonomy/views_handler_field_term_node_tid.inc
files[] = modules/taxonomy/views_handler_field_term_link_edit.inc
files[] = modules/taxonomy/views_handler_filter_term_node_tid.inc
files[] = modules/taxonomy/views_handler_filter_term_node_tid_depth.inc
+files[] = modules/taxonomy/views_handler_filter_term_node_tid_depth_join.inc
files[] = modules/taxonomy/views_handler_filter_vocabulary_vid.inc
files[] = modules/taxonomy/views_handler_filter_vocabulary_machine_name.inc
files[] = modules/taxonomy/views_handler_relationship_node_term_data.inc
@@ -318,9 +328,9 @@ files[] = tests/views_cache.test
files[] = tests/views_view.test
files[] = tests/views_ui.test
-; Information added by Drupal.org packaging script on 2015-02-11
-version = "7.x-3.10"
+; Information added by Drupal.org packaging script on 2016-06-15
+version = "7.x-3.14"
core = "7.x"
project = "views"
-datestamp = "1423648085"
+datestamp = "1466019588"
diff --git a/sites/all/modules/contrib/views/views/views.install b/sites/all/modules/contrib/views/views/views.install
index b69f4105..ca10d69a 100644
--- a/sites/all/modules/contrib/views/views/views.install
+++ b/sites/all/modules/contrib/views/views/views.install
@@ -402,7 +402,7 @@ function views_update_6008() {
}
/**
- * Enlarge the views_display.display_options field to accomodate a larger set
+ * Enlarge the views_display.display_options field to accommodate a larger set
* of configurations (e. g. fields, filters, etc.) on a display.
*/
function views_schema_6009() {
@@ -631,3 +631,17 @@ function views_update_7301() {
);
db_change_field('views_view', 'name', 'name', $new_field);
}
+
+/**
+ * Remove headers field from cache tables
+ *
+ * @see system_update_7054().
+ */
+function views_update_7302() {
+ if (db_field_exists('cache_views', 'headers')) {
+ db_drop_field('cache_views', 'headers');
+ }
+ if (db_field_exists('cache_views_data', 'headers')) {
+ db_drop_field('cache_views_data', 'headers');
+ }
+}
diff --git a/sites/all/modules/contrib/views/views/views.module b/sites/all/modules/contrib/views/views/views.module
index 9cdcfb58..aab3812d 100644
--- a/sites/all/modules/contrib/views/views/views.module
+++ b/sites/all/modules/contrib/views/views/views.module
@@ -1020,8 +1020,21 @@ function views_access() {
* permissions. If the $account argument is omitted, the current user
* is used.
*/
-function views_check_perm($perm, $account = NULL) {
- return user_access($perm, $account) || user_access('access all views', $account);
+function views_check_perm($perms, $account = NULL) {
+ // Backward compatibility to ensure also a single permission string is
+ // properly processed.
+ $perms = is_array($perms) ? $perms : array($perms);
+ if (user_access('access all views', $account)) {
+ return TRUE;
+ }
+ // Perms are handled as OR, as soon one permission allows access TRUE is
+ // returned.
+ foreach ($perms as $perm) {
+ if (user_access($perm, $account)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
}
/**
@@ -1298,7 +1311,7 @@ function views_fetch_plugin_data($type = NULL, $plugin = NULL, $reset = FALSE) {
* Either 'display', 'style' or 'row'
* @param $key
* For style plugins, this is an optional type to restrict to. May be 'normal',
- * 'summary', 'feed' or others based on the neds of the display.
+ * 'summary', 'feed' or others based on the needs of the display.
* @param $base
* An array of possible base tables.
*
@@ -2413,7 +2426,7 @@ function views_process_check_options($element, &$form_state) {
* Trim the field down to the specified length.
*
* @param $alter
- * - max_length: Maximum lenght of the string, the rest gets truncated.
+ * - max_length: Maximum length of the string, the rest gets truncated.
* - word_boundary: Trim only on a word boundary.
* - ellipsis: Show an ellipsis (...) at the end of the trimmed string.
* - html: Take sure that the html is correct.
diff --git a/sites/all/modules/contrib/views/views/views_ui.info b/sites/all/modules/contrib/views/views/views_ui.info
index d8be6e4d..cbe65b06 100644
--- a/sites/all/modules/contrib/views/views/views_ui.info
+++ b/sites/all/modules/contrib/views/views/views_ui.info
@@ -7,9 +7,9 @@ dependencies[] = views
files[] = views_ui.module
files[] = plugins/views_wizard/views_ui_base_views_wizard.class.php
-; Information added by Drupal.org packaging script on 2015-02-11
-version = "7.x-3.10"
+; Information added by Drupal.org packaging script on 2016-06-15
+version = "7.x-3.14"
core = "7.x"
project = "views"
-datestamp = "1423648085"
+datestamp = "1466019588"
diff --git a/sites/all/modules/contrib/views/views/views_ui.module b/sites/all/modules/contrib/views/views/views_ui.module
index 5366f778..f35d099f 100644
--- a/sites/all/modules/contrib/views/views/views_ui.module
+++ b/sites/all/modules/contrib/views/views/views_ui.module
@@ -248,7 +248,7 @@ function views_ui_theme() {
}
/**
- * Impements hook_custom_theme()
+ * Implements hook_custom_theme().
*/
function views_ui_custom_theme() {
$theme = variable_get('views_ui_custom_theme', '_default');
diff --git a/sites/all/modules/contrib/views/views_bulk_operations/LICENSE.txt b/sites/all/modules/contrib/views/views_bulk_operations/LICENSE.txt
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/views/views_bulk_operations/actions/archive.action.inc b/sites/all/modules/contrib/views/views_bulk_operations/actions/archive.action.inc
index 7667e493..f0055274 100644
--- a/sites/all/modules/contrib/views/views_bulk_operations/actions/archive.action.inc
+++ b/sites/all/modules/contrib/views/views_bulk_operations/actions/archive.action.inc
@@ -18,6 +18,7 @@ function views_bulk_operations_archive_action_info() {
// "Create an advanced action" dropdown on admin/config/system/actions.
'configurable' => FALSE,
'vbo_configurable' => TRUE,
+ 'behavior' => array('views_property'),
'triggers' => array('any'),
);
}
diff --git a/sites/all/modules/contrib/views/views_bulk_operations/actions/book.action.inc b/sites/all/modules/contrib/views/views_bulk_operations/actions/book.action.inc
index add893ef..ad8fa9c4 100644
--- a/sites/all/modules/contrib/views/views_bulk_operations/actions/book.action.inc
+++ b/sites/all/modules/contrib/views/views_bulk_operations/actions/book.action.inc
@@ -13,11 +13,13 @@ function views_bulk_operations_book_action_info() {
'label' => t('Move to book'),
'configurable' => TRUE,
'behavior' => array('changes_property'),
+ 'triggers' => array('any'),
);
$actions['views_bulk_operations_remove_from_book_action'] = array(
'type' => 'node',
'label' => t('Remove from book'),
'configurable' => FALSE,
+ 'triggers' => array('any'),
);
}
diff --git a/sites/all/modules/contrib/views/views_bulk_operations/actions/delete.action.inc b/sites/all/modules/contrib/views/views_bulk_operations/actions/delete.action.inc
index 1106ab04..52c72d2f 100644
--- a/sites/all/modules/contrib/views/views_bulk_operations/actions/delete.action.inc
+++ b/sites/all/modules/contrib/views/views_bulk_operations/actions/delete.action.inc
@@ -19,6 +19,7 @@ function views_bulk_operations_delete_action_info() {
'label' => t('Delete revision'),
'configurable' => FALSE,
'behavior' => array('deletes_property'),
+ 'triggers' => array('any'),
),
);
}
diff --git a/sites/all/modules/contrib/views/views_bulk_operations/actions/modify.action.inc b/sites/all/modules/contrib/views/views_bulk_operations/actions/modify.action.inc
index 71b6181c..301b17b2 100644
--- a/sites/all/modules/contrib/views/views_bulk_operations/actions/modify.action.inc
+++ b/sites/all/modules/contrib/views/views_bulk_operations/actions/modify.action.inc
@@ -82,6 +82,11 @@ function views_bulk_operations_modify_action($entity, $context) {
// The wrapper will automatically modify $entity itself.
$wrapper = entity_metadata_wrapper($context['entity_type'], $entity);
foreach ($context['selected']['properties'] as $key) {
+ if (!$wrapper->$key->access('update')) {
+ // No access.
+ continue;
+ }
+
if (in_array($key, $context['append']['properties'])) {
$old_values = $wrapper->$key->value();
$wrapper->$key->set($context['properties'][$key]);
@@ -134,7 +139,7 @@ function views_bulk_operations_modify_action_form($context, &$form_state) {
if (!empty($properties)) {
$form['properties'] = array(
'#type' => 'fieldset',
- '#title' => 'Properties',
+ '#title' => t('Properties'),
);
$form['properties']['show_value'] = array(
'#suffix' => '',
@@ -298,7 +303,7 @@ function views_bulk_operations_modify_action_form($context, &$form_state) {
$token_type = str_replace('_', '-', $entity_type);
$form['tokens'] = array(
'#type' => 'fieldset',
- '#title' => 'Available tokens',
+ '#title' => t('Available tokens'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => 998,
diff --git a/sites/all/modules/contrib/views/views_bulk_operations/actions/user_cancel.action.inc b/sites/all/modules/contrib/views/views_bulk_operations/actions/user_cancel.action.inc
index ea8e8ee1..147d2920 100644
--- a/sites/all/modules/contrib/views/views_bulk_operations/actions/user_cancel.action.inc
+++ b/sites/all/modules/contrib/views/views_bulk_operations/actions/user_cancel.action.inc
@@ -10,6 +10,7 @@ function views_bulk_operations_user_cancel_action_info() {
'label' => t('Cancel user account'),
'configurable' => TRUE,
'behavior' => array('deletes_property'),
+ 'triggers' => array('any'),
));
}
diff --git a/sites/all/modules/contrib/views/views_bulk_operations/actions/user_roles.action.inc b/sites/all/modules/contrib/views/views_bulk_operations/actions/user_roles.action.inc
index 394597c3..616f13ce 100644
--- a/sites/all/modules/contrib/views/views_bulk_operations/actions/user_roles.action.inc
+++ b/sites/all/modules/contrib/views/views_bulk_operations/actions/user_roles.action.inc
@@ -45,24 +45,19 @@ function views_bulk_operations_user_roles_action_submit($form, $form_state) {
);
}
-function views_bulk_operations_user_roles_action(&$user, $context) {
- $roles = $user->roles;
- $selected = (is_array($context['add_roles']) ? $context['add_roles'] : array()) +
- (is_array($context['remove_roles']) ? $context['remove_roles'] : array());
- $result = db_query("SELECT rid, name FROM {role} WHERE rid IN (:selected)", array(':selected' => array_keys($selected)));
- foreach ($result as $role) {
- if (isset($context['add_roles'][$role->rid])) {
- $add_roles[$role->rid] = $role->name;
- }
- if (isset($context['remove_roles'][$role->rid])) {
- $remove_roles[$role->rid] = $role->name;
- }
+function views_bulk_operations_user_roles_action($user, $context) {
+ $wrapper = entity_metadata_wrapper('user', $user);
+ if (!$wrapper->roles->access("update")) {
+ // No access.
+ return;
}
- if (!empty($add_roles)) {
- $roles += $add_roles;
+ $roles = $wrapper->roles->value();
+ if (is_array($context['add_roles'])) {
+ $roles = array_merge($roles, $context['add_roles']);
}
- if (!empty($remove_roles)) {
- $roles = array_diff($roles, $remove_roles);
+ if (is_array($context['remove_roles'])) {
+ $roles = array_diff($roles, $context['remove_roles']);
}
- user_save($user, array('roles' => $roles));
+ $wrapper->roles->set($roles);
+ $wrapper->save();
}
diff --git a/sites/all/modules/contrib/views/views_bulk_operations/actions_permissions.info b/sites/all/modules/contrib/views/views_bulk_operations/actions_permissions.info
index e57077b0..658d1adc 100644
--- a/sites/all/modules/contrib/views/views_bulk_operations/actions_permissions.info
+++ b/sites/all/modules/contrib/views/views_bulk_operations/actions_permissions.info
@@ -3,9 +3,9 @@ description = Provides permission-based access control for actions. Used by View
package = Administration
core = 7.x
-; Information added by Drupal.org packaging script on 2013-12-23
-version = "7.x-3.2"
+; Information added by Drupal.org packaging script on 2015-07-01
+version = "7.x-3.3"
core = "7.x"
project = "views_bulk_operations"
-datestamp = "1387798183"
+datestamp = "1435764542"
diff --git a/sites/all/modules/contrib/views/views_bulk_operations/js/views_bulk_operations.js b/sites/all/modules/contrib/views/views_bulk_operations/js/views_bulk_operations.js
index aeeecc6f..ca76df86 100644
--- a/sites/all/modules/contrib/views/views_bulk_operations/js/views_bulk_operations.js
+++ b/sites/all/modules/contrib/views/views_bulk_operations/js/views_bulk_operations.js
@@ -46,21 +46,23 @@
});
// Set up the ability to click anywhere on the row to select it.
- $('.views-table tbody tr', form).click(function(event) {
- if (event.target.tagName.toLowerCase() != 'input' && event.target.tagName.toLowerCase() != 'a') {
- $('input[id^="edit-views-bulk-operations"]:not(:disabled)', this).each(function() {
- var checked = this.checked;
- // trigger() toggles the checkmark *after* the event is set,
- // whereas manually clicking the checkbox toggles it *beforehand*.
- // that's why we manually set the checkmark first, then trigger the
- // event (so that listeners get notified), then re-set the checkmark
- // which the trigger will have toggled. yuck!
- this.checked = !checked;
- $(this).trigger('click');
- this.checked = !checked;
- });
- }
- });
+ if (Drupal.settings.vbo.row_clickable) {
+ $('.views-table tbody tr', form).click(function(event) {
+ if (event.target.tagName.toLowerCase() != 'input' && event.target.tagName.toLowerCase() != 'a') {
+ $('input[id^="edit-views-bulk-operations"]:not(:disabled)', this).each(function() {
+ var checked = this.checked;
+ // trigger() toggles the checkmark *after* the event is set,
+ // whereas manually clicking the checkbox toggles it *beforehand*.
+ // that's why we manually set the checkmark first, then trigger the
+ // event (so that listeners get notified), then re-set the checkmark
+ // which the trigger will have toggled. yuck!
+ this.checked = !checked;
+ $(this).trigger('click');
+ this.checked = !checked;
+ });
+ }
+ });
+ }
}
Drupal.vbo.tableSelectAllPages = function(form) {
diff --git a/sites/all/modules/contrib/views/views_bulk_operations/plugins/operation_types/action.class.php b/sites/all/modules/contrib/views/views_bulk_operations/plugins/operation_types/action.class.php
index c74d90c3..f3e60a30 100644
--- a/sites/all/modules/contrib/views/views_bulk_operations/plugins/operation_types/action.class.php
+++ b/sites/all/modules/contrib/views/views_bulk_operations/plugins/operation_types/action.class.php
@@ -20,7 +20,7 @@ class ViewsBulkOperationsAction extends ViewsBulkOperationsBaseOperation {
*/
public function getAccessMask() {
// Assume edit by default.
- if (!isset($this->operationInfo['behavior'])) {
+ if (empty($this->operationInfo['behavior'])) {
$this->operationInfo['behavior'] = array('changes_property');
}
diff --git a/sites/all/modules/contrib/views/views_bulk_operations/plugins/operation_types/rules_component.class.php b/sites/all/modules/contrib/views/views_bulk_operations/plugins/operation_types/rules_component.class.php
index 624c850b..c40da8b2 100644
--- a/sites/all/modules/contrib/views/views_bulk_operations/plugins/operation_types/rules_component.class.php
+++ b/sites/all/modules/contrib/views/views_bulk_operations/plugins/operation_types/rules_component.class.php
@@ -124,6 +124,8 @@ class ViewsBulkOperationsRulesComponent extends ViewsBulkOperationsBaseOperation
else {
$element = rules_action('component_' . $this->operationInfo['parameters']['component_key']);
}
- $element->execute($data);
+ $wrapper_type = is_array($data) ? "list<{$this->entityType}>" : $this->entityType;
+ $wrapper = entity_metadata_wrapper($wrapper_type, $data);
+ $element->execute($wrapper);
}
}
diff --git a/sites/all/modules/contrib/views/views_bulk_operations/views/views_bulk_operations_handler_field_operations.inc b/sites/all/modules/contrib/views/views_bulk_operations/views/views_bulk_operations_handler_field_operations.inc
index 9bb983f7..61886d48 100644
--- a/sites/all/modules/contrib/views/views_bulk_operations/views/views_bulk_operations_handler_field_operations.inc
+++ b/sites/all/modules/contrib/views/views_bulk_operations/views/views_bulk_operations_handler_field_operations.inc
@@ -55,6 +55,7 @@ class views_bulk_operations_handler_field_operations extends views_handler_field
'contains' => array(
'display_type' => array('default' => 0),
'enable_select_all_pages' => array('default' => TRUE),
+ 'row_clickable' => array('default' => TRUE),
'force_single' => array('default' => FALSE),
'entity_load_capacity' => array('default' => 10),
'skip_batching' => array('default' => 0),
@@ -63,11 +64,26 @@ class views_bulk_operations_handler_field_operations extends views_handler_field
$options['vbo_operations'] = array(
'default' => array(),
'unpack_translatable' => 'unpack_operations',
+ 'export' => 'export_vbo_operations',
);
return $options;
}
+ function export_vbo_operations($indent, $prefix, $storage, $option, $definition, $parents) {
+ // Anti-recursion, since we use the parent export helper.
+ unset($definition['export']);
+
+ // Find and remove all unselected/disabled operations.
+ foreach ($storage['vbo_operations'] as $operation_id => $operation) {
+ if (empty($operation['selected'])) {
+ unset($storage['vbo_operations'][$operation_id]);
+ }
+ }
+
+ return parent::export_option($indent, $prefix, $storage, $option, $definition, $parents);
+ }
+
function unpack_operations(&$translatable, $storage, $option, $definition, $parents, $keys) {
$translatable[] = array(
'value' => t('- Choose an operation -'),
@@ -107,6 +123,12 @@ class views_bulk_operations_handler_field_operations extends views_handler_field
'#default_value' => $this->options['vbo_settings']['enable_select_all_pages'],
'#description' => t('Check this box to enable the ability to select all items on all pages.'),
);
+ $form['vbo_settings']['row_clickable'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Make the whole row clickable'),
+ '#default_value' => $this->options['vbo_settings']['row_clickable'],
+ '#description' => t('Check this box to select an item when its row has been clicked. Requires JavaScript.'),
+ );
$form['vbo_settings']['force_single'] = array(
'#type' => 'checkbox',
'#title' => t('Force single'),
diff --git a/sites/all/modules/contrib/views/views_bulk_operations/views_bulk_operations.info b/sites/all/modules/contrib/views/views_bulk_operations/views_bulk_operations.info
index 2f03a14a..8fbdffaa 100644
--- a/sites/all/modules/contrib/views/views_bulk_operations/views_bulk_operations.info
+++ b/sites/all/modules/contrib/views/views_bulk_operations/views_bulk_operations.info
@@ -9,9 +9,9 @@ php = 5.2.9
files[] = plugins/operation_types/base.class.php
files[] = views/views_bulk_operations_handler_field_operations.inc
-; Information added by Drupal.org packaging script on 2013-12-23
-version = "7.x-3.2"
+; Information added by Drupal.org packaging script on 2015-07-01
+version = "7.x-3.3"
core = "7.x"
project = "views_bulk_operations"
-datestamp = "1387798183"
+datestamp = "1435764542"
diff --git a/sites/all/modules/contrib/views/views_bulk_operations/views_bulk_operations.module b/sites/all/modules/contrib/views/views_bulk_operations/views_bulk_operations.module
index b25b661c..e74eeb1d 100644
--- a/sites/all/modules/contrib/views/views_bulk_operations/views_bulk_operations.module
+++ b/sites/all/modules/contrib/views/views_bulk_operations/views_bulk_operations.module
@@ -41,21 +41,20 @@ function views_bulk_operations_load_action_includes() {
// The list of VBO actions is fairly static, so it's hardcoded for better
// performance (hitting the filesystem with file_scan_directory(), and then
// caching the result has its cost).
- $path = drupal_get_path('module', 'views_bulk_operations') . '/actions/';
$files = array(
- 'archive.action.inc',
- 'argument_selector.action.inc',
- 'book.action.inc',
- 'delete.action.inc',
- 'modify.action.inc',
- 'script.action.inc',
- 'user_roles.action.inc',
- 'user_cancel.action.inc',
+ 'archive.action',
+ 'argument_selector.action',
+ 'book.action',
+ 'delete.action',
+ 'modify.action',
+ 'script.action',
+ 'user_roles.action',
+ 'user_cancel.action',
);
if (!$loaded) {
foreach ($files as $file) {
- include_once $path . $file;
+ module_load_include('inc', 'views_bulk_operations', 'actions/' . $file);
}
$loaded = TRUE;
}
@@ -77,7 +76,7 @@ function views_bulk_operations_load_action_includes() {
function views_bulk_operations_cron() {
db_delete('queue')
->condition('name', db_like('views_bulk_operations_active_queue_'), 'LIKE')
- ->condition('created', REQUEST_TIME - 864000, '<')
+ ->condition('created', REQUEST_TIME - 86400, '<')
->execute();
}
@@ -358,7 +357,7 @@ function views_bulk_operations_form_alter(&$form, &$form_state, $form_id) {
*/
function views_bulk_operations_views_post_build(&$view) {
$vbo = _views_bulk_operations_get_field($view);
- if ($vbo && $vbo->get_selected_operations() < 1) {
+ if ($vbo && count($vbo->get_selected_operations()) < 1) {
$vbo->options['exclude'] = TRUE;
}
}
@@ -420,7 +419,7 @@ function theme_views_bulk_operations_select_all($variables) {
if ($enable_select_all_pages) {
$form['select_all']['or'] = array(
'#type' => 'markup',
- '#markup' => 'OR',
+ '#markup' => '' . t('OR') . '',
);
$form['select_all']['all_pages'] = array(
'#type' => 'checkbox',
@@ -443,6 +442,13 @@ function theme_views_bulk_operations_select_all($variables) {
*/
function views_bulk_operations_form($form, &$form_state, $vbo) {
$form['#attached']['js'][] = drupal_get_path('module', 'views_bulk_operations') . '/js/views_bulk_operations.js';
+ $form['#attached']['js'][] = array(
+ 'data' => array('vbo' => array(
+ 'row_clickable' => $vbo->get_vbo_option('row_clickable'),
+ )),
+ 'type' => 'setting',
+ );
+
$form['#attached']['css'][] = drupal_get_path('module', 'views_bulk_operations') . '/css/views_bulk_operations.css';
// Wrap the form in a div with specific classes for JS targeting and theming.
$class = 'vbo-views-form';
@@ -595,14 +601,23 @@ function views_bulk_operations_confirm_form($form, &$form_state, $view, $output)
$operation = $form_state['operation'];
$rows = $form_state['selection'];
$query = drupal_get_query_parameters($_GET, array('q'));
+ $title = t('Are you sure you want to perform %operation on the selected items?', array('%operation' => $operation->label()));
$form = confirm_form($form,
- t('Are you sure you want to perform %operation on the selected items?', array('%operation' => $operation->label())),
+ $title,
array('path' => $view->get_url(), 'query' => $query),
theme('views_bulk_operations_confirmation', array('rows' => $rows, 'vbo' => $vbo, 'operation' => $operation, 'select_all_pages' => $form_state['select_all_pages']))
);
// Add VBO's submit handler to the Confirm button added by config_form().
$form['actions']['submit']['#submit'] = array('views_bulk_operations_form_submit');
+ // We can't set the View title here as $view is just a copy of the original,
+ // and our settings changes won't "stick" for the first page load of the
+ // confirmation form. We also can't just call drupal_set_title() directly
+ // because our title will be clobbered by the actual View title later. So
+ // let's tuck the title away in the form for use later.
+ // @see views_bulk_operations_preprocess_views_view()
+ $form['#vbo_confirm_form_title'] = $title;
+
return $form;
}
@@ -618,7 +633,7 @@ function theme_views_bulk_operations_confirmation($variables) {
// Load the entities from the current page, and show their titles.
$entities = _views_bulk_operations_entity_load($entity_type, array_values($rows), $vbo->revision);
foreach ($entities as $entity) {
- $items[] = check_plain(_views_bulk_operations_entity_label($entity_type, $entity));
+ $items[] = check_plain(entity_label($entity_type, $entity));
}
// All rows on all pages have been selected, so show a count of additional items.
if ($select_all_pages) {
@@ -631,6 +646,29 @@ function theme_views_bulk_operations_confirmation($variables) {
return $output;
}
+/**
+ * Implements hook_preprocess_page().
+ *
+ * Hide action links on the configure and confirm pages.
+ */
+function views_bulk_operations_preprocess_page(&$variables) {
+ if (isset($_POST['select_all'], $_POST['operation'])) {
+ $variables['action_links'] = array();
+ }
+}
+
+/**
+ * Implements hook_preprocess_views_view().
+ */
+function views_bulk_operations_preprocess_views_view($variables) {
+ // If we've stored a title for the confirmation form, retrieve it here and
+ // retitle the View.
+ // @see views_bulk_operations_confirm_form()
+ if (array_key_exists('rows', $variables) && is_array($variables['rows']) && array_key_exists('#vbo_confirm_form_title', $variables['rows'])) {
+ $variables['view']->set_title($variables['rows']['#vbo_confirm_form_title']);
+ }
+}
+
/**
* Goes through the submitted values, and returns
* an array of selected rows, in the form of
@@ -871,7 +909,7 @@ function views_bulk_operations_adjust_selection($queue_name, $operation, $option
'views_row' => array(),
'position' => array(
'current' => ++$context['sandbox']['progress'],
- 'total' => $view->total_rows,
+ 'total' => $context['sandbox']['max'],
),
);
// Some operations require full selected rows.
@@ -1042,7 +1080,7 @@ function views_bulk_operations_queue_item_process($queue_item_data, &$log = NULL
$arguments = array(
'%operation' => $operation->label(),
'@type' => $entity_type,
- '%title' => _views_bulk_operations_entity_label($entity_type, $entity),
+ '%title' => entity_label($entity_type, $entity),
);
if ($log) {
@@ -1128,7 +1166,7 @@ function views_bulk_operations_direct_process($operation, $rows, $options) {
$context['results']['log'][] = t('Skipped %operation on @type %title due to insufficient permissions.', array(
'%operation' => $operation->label(),
'@type' => $entity_type,
- '%title' => _views_bulk_operations_entity_label($entity_type, $entity),
+ '%title' => entity_label($entity_type, $entity),
));
unset($entities[$id]);
}
@@ -1236,29 +1274,6 @@ function _views_bulk_operations_entity_load($entity_type, $ids, $revision = FALS
return $entities;
}
-/**
- * Label function for entities.
- * Core entities don't declare the "label" key, so entity_label() fails,
- * and a fallback is needed. This function provides that fallback.
- */
-function _views_bulk_operations_entity_label($entity_type, $entity) {
- $label = entity_label($entity_type, $entity);
- if (!$label) {
- $entity_info = entity_get_info($entity_type);
- $id_key = $entity_info['entity keys']['id'];
- // Many entity types (e.g. "user") have a name which fits the label perfectly.
- if (isset($entity->name)) {
- $label = $entity->name;
- }
- elseif (isset($entity->{$id_key})) {
- // Fallback to the id key.
- $label = $entity->{$id_key};
- }
- }
-
- return $label;
-}
-
/**
* Helper function to report an error.
*/
diff --git a/sites/all/modules/contrib/views/views_php/LICENSE.txt b/sites/all/modules/contrib/views/views_php/LICENSE.txt
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/views/views_php/plugins/views/views_php_handler_field.inc b/sites/all/modules/contrib/views/views_php/plugins/views/views_php_handler_field.inc
index 9164d9a7..1da366b6 100644
--- a/sites/all/modules/contrib/views/views_php/plugins/views/views_php_handler_field.inc
+++ b/sites/all/modules/contrib/views/views_php/plugins/views/views_php_handler_field.inc
@@ -220,8 +220,13 @@ class views_php_handler_field extends views_handler_field {
$value = ob_get_clean();
}
else {
- $value = check_plain($values->{$this->field_alias});
+ if (isset($values->{$this->field_alias})) {
+ $value = check_plain($values->{$this->field_alias});
+ }
+ }
+
+ if (isset($value)) {
+ return $value;
}
- return $value;
}
}
diff --git a/sites/all/modules/contrib/views/views_php/views_php.info b/sites/all/modules/contrib/views/views_php/views_php.info
index d999ce1c..63fb2385 100644
--- a/sites/all/modules/contrib/views/views_php/views_php.info
+++ b/sites/all/modules/contrib/views/views_php/views_php.info
@@ -15,9 +15,9 @@ files[] = plugins/views/views_php_plugin_pager.inc
files[] = plugins/views/views_php_plugin_query.inc
files[] = plugins/views/views_php_plugin_wrapper.inc
-; Information added by Drupal.org packaging script on 2014-01-24
-version = "7.x-1.0-alpha1"
+; Information added by Drupal.org packaging script on 2015-11-13
+version = "7.x-1.0-alpha3"
core = "7.x"
project = "views_php"
-datestamp = "1390577427"
+datestamp = "1447386022"
diff --git a/sites/all/modules/contrib/views/views_php/views_php.module b/sites/all/modules/contrib/views/views_php/views_php.module
index aee59716..d2fa27d1 100644
--- a/sites/all/modules/contrib/views/views_php/views_php.module
+++ b/sites/all/modules/contrib/views/views_php/views_php.module
@@ -148,3 +148,13 @@ function views_php_views_post_execute($view) {
$view->query->php_unwrap();
}
}
+
+/**
+ * Implements hook_views_post_build().
+ */
+function views_php_views_post_build($view) {
+ // Clear the limit and offset
+ if (!empty($view->views_php) && !empty($view->build_info['query']) && is_object($view->build_info['query'])) {
+ $view->build_info['query']->range();
+ }
+}
diff --git a/sites/all/modules/features/admin/admin.features.filter.inc b/sites/all/modules/features/admin/admin.features.filter.inc
index 2971863b..c72dc9cd 100644
--- a/sites/all/modules/features/admin/admin.features.filter.inc
+++ b/sites/all/modules/features/admin/admin.features.filter.inc
@@ -36,6 +36,47 @@ function admin_filter_default_formats() {
'video_filter_autoplay' => 0,
'video_filter_related' => 1,
'video_filter_html5' => 1,
+ 'video_filter_codecs' => array(
+ 'archive' => 'Archive.org',
+ 'bliptv' => 'Blip.tv',
+ 'candidcareer' => 'Candid Career',
+ 'capped' => 'Capped',
+ 'collegehumor' => 'College Humor',
+ 'coub' => 'Coub',
+ 'dailymotion' => 'DailyMotion',
+ 'democracynow_fullshow' => 'DemocracyNow Fullshow',
+ 'democracynow_story' => 'DemocracyNow Story',
+ 'flickr_slideshows' => 'Flickr Slideshows',
+ 'flickr_video' => 'Flickr Video',
+ 'foxnews' => 'Fox News',
+ 'gametrailers' => 'Game Trailers',
+ 'gamevideos' => 'Game Videos',
+ 'giphy' => 'Giphy',
+ 'godtube' => 'GodTube',
+ 'google' => 'Google Video',
+ 'instagram' => 'Instagram',
+ 'metacafe' => 'Meta Cafe',
+ 'mailru' => 'Mail.Ru',
+ 'myspace' => 'MySpace',
+ 'myvideo' => 'MyVideo',
+ 'picasa_slideshows' => 'Picasa Slideshows',
+ 'rutube' => 'Rutube',
+ 'slideshare' => 'Slideshare',
+ 'streamhoster' => 'Streamhoster',
+ 'teachertube' => 'Teachertube',
+ 'ted' => 'TED',
+ 'twitch' => 'Twitch',
+ 'ustream' => 'Ustream',
+ 'vbox' => 'Vbox7',
+ 'vimeo' => 'Vimeo',
+ 'vine' => 'Vine',
+ 'whatchado' => 'whatchado',
+ 'wistia' => 'Wistia',
+ 'youku' => 'YouKu',
+ 'youtube' => 'YouTube',
+ 'youtube_playlist' => 'YouTube (Playlist)',
+ ),
+ 'video_filter_multiple_sources' => TRUE,
),
),
'filter_url' => array(
diff --git a/sites/all/modules/features/admin/admin.features.user_permission.inc b/sites/all/modules/features/admin/admin.features.user_permission.inc
index 12c9400a..657524e7 100644
--- a/sites/all/modules/features/admin/admin.features.user_permission.inc
+++ b/sites/all/modules/features/admin/admin.features.user_permission.inc
@@ -48,24 +48,6 @@ function admin_user_default_permissions() {
'module' => 'views',
);
- // Exported permission: 'access backup and migrate'.
- $permissions['access backup and migrate'] = array(
- 'name' => 'access backup and migrate',
- 'roles' => array(
- 'root' => 'root',
- ),
- 'module' => 'backup_migrate',
- );
-
- // Exported permission: 'access backup files'.
- $permissions['access backup files'] = array(
- 'name' => 'access backup files',
- 'roles' => array(
- 'root' => 'root',
- ),
- 'module' => 'backup_migrate',
- );
-
// Exported permission: 'access content'.
$permissions['access content'] = array(
'name' => 'access content',
@@ -168,15 +150,6 @@ function admin_user_default_permissions() {
'module' => 'system',
);
- // Exported permission: 'administer backup and migrate'.
- $permissions['administer backup and migrate'] = array(
- 'name' => 'administer backup and migrate',
- 'roles' => array(
- 'root' => 'root',
- ),
- 'module' => 'backup_migrate',
- );
-
// Exported permission: 'administer blocks'.
$permissions['administer blocks'] = array(
'name' => 'administer blocks',
@@ -582,15 +555,6 @@ function admin_user_default_permissions() {
'module' => 'shortcut',
);
- // Exported permission: 'delete backup files'.
- $permissions['delete backup files'] = array(
- 'name' => 'delete backup files',
- 'roles' => array(
- 'root' => 'root',
- ),
- 'module' => 'backup_migrate',
- );
-
// Exported permission: 'delete revisions'.
$permissions['delete revisions'] = array(
'name' => 'delete revisions',
@@ -728,15 +692,6 @@ function admin_user_default_permissions() {
'module' => 'workflow_admin_ui',
);
- // Exported permission: 'perform backup'.
- $permissions['perform backup'] = array(
- 'name' => 'perform backup',
- 'roles' => array(
- 'root' => 'root',
- ),
- 'module' => 'backup_migrate',
- );
-
// Exported permission: 'rename features'.
$permissions['rename features'] = array(
'name' => 'rename features',
@@ -744,15 +699,6 @@ function admin_user_default_permissions() {
'module' => 'features',
);
- // Exported permission: 'restore from backup'.
- $permissions['restore from backup'] = array(
- 'name' => 'restore from backup',
- 'roles' => array(
- 'root' => 'root',
- ),
- 'module' => 'backup_migrate',
- );
-
// Exported permission: 'revert revisions'.
$permissions['revert revisions'] = array(
'name' => 'revert revisions',
diff --git a/sites/all/modules/features/admin/admin.features.wysiwyg.inc b/sites/all/modules/features/admin/admin.features.wysiwyg.inc
index fa91c5d4..4af32c12 100644
--- a/sites/all/modules/features/admin/admin.features.wysiwyg.inc
+++ b/sites/all/modules/features/admin/admin.features.wysiwyg.inc
@@ -15,9 +15,6 @@ function admin_wysiwyg_default_profiles() {
'format' => 'filtred_html',
'editor' => 'tinymce',
'settings' => array(
- 'default' => 1,
- 'user_choose' => 0,
- 'show_toggle' => 1,
'theme' => 'advanced',
'language' => 'en',
'buttons' => array(
@@ -35,6 +32,7 @@ function admin_wysiwyg_default_profiles() {
'cut' => 1,
'copy' => 1,
'paste' => 1,
+ 'formatselect' => 1,
),
'advimage' => array(
'advimage' => 1,
@@ -42,9 +40,7 @@ function admin_wysiwyg_default_profiles() {
'advlink' => array(
'advlink' => 1,
),
- 'font' => array(
- 'formatselect' => 1,
- ),
+ 'font' => array(),
'fullscreen' => array(
'fullscreen' => 1,
),
@@ -68,22 +64,30 @@ function admin_wysiwyg_default_profiles() {
'break' => 1,
),
),
- 'toolbar_loc' => 'top',
- 'toolbar_align' => 'left',
- 'path_loc' => 'bottom',
- 'resizing' => 1,
'verify_html' => 1,
'preformatted' => 0,
'convert_fonts_to_spans' => 1,
'remove_linebreaks' => 1,
'apply_source_formatting' => 0,
'paste_auto_cleanup_on_paste' => 1,
- 'block_formats' => 'h2,h3,h4,h5,h6',
'css_setting' => 'theme',
'css_path' => '',
- 'css_classes' => '',
'buttonorder' => 'fullscreen,separator,bold,italic,underline,separator,formatselect,separator,bullist,numlist,advlist,separator,link,advlink,unlink,separator,image,advimage,video_filter,separator,cut,copy,paste,pastetext,search,replace,wordcount,separator,undo,redo,separator,break',
+ 'theme_advanced_statusbar_location' => 'bottom',
+ 'theme_advanced_toolbar_location' => 'top',
+ 'theme_advanced_toolbar_align' => 'left',
+ 'theme_advanced_blockformats' => 'h2,h3,h4,h5,h6',
+ 'theme_advanced_styles' => '',
+ 'theme_advanced_resizing' => 1,
),
+ 'preferences' => array(
+ 'add_to_summaries' => NULL,
+ 'default' => 1,
+ 'show_toggle' => 1,
+ 'user_choose' => 0,
+ 'version' => '3.5.7',
+ ),
+ 'name' => 'formatfiltred_html',
);
return $profiles;
diff --git a/sites/all/modules/features/admin/admin.info b/sites/all/modules/features/admin/admin.info
index a7ab3487..256aa59e 100644
--- a/sites/all/modules/features/admin/admin.info
+++ b/sites/all/modules/features/admin/admin.info
@@ -1,12 +1,11 @@
name = Admin
core = 7.x
-package = GUI
+package = FigLi
dependencies[] = admin_menu
dependencies[] = admin_menu_source
dependencies[] = admin_theme
dependencies[] = adminimal_admin_menu
dependencies[] = auto_nodetitle
-dependencies[] = backup_migrate
dependencies[] = block
dependencies[] = content_type_extras
dependencies[] = context_ui
@@ -72,8 +71,6 @@ features[user_permission][] = access admin theme
features[user_permission][] = access administration menu
features[user_permission][] = access administration pages
features[user_permission][] = access all views
-features[user_permission][] = access backup and migrate
-features[user_permission][] = access backup files
features[user_permission][] = access content
features[user_permission][] = access content overview
features[user_permission][] = access devel information
@@ -85,7 +82,6 @@ features[user_permission][] = access user profiles
features[user_permission][] = access workflow summary views
features[user_permission][] = admin queue_ui
features[user_permission][] = administer actions
-features[user_permission][] = administer backup and migrate
features[user_permission][] = administer blocks
features[user_permission][] = administer content type defaults
features[user_permission][] = administer content types
@@ -131,7 +127,6 @@ features[user_permission][] = cancel account
features[user_permission][] = change own username
features[user_permission][] = create url aliases
features[user_permission][] = customize shortcut links
-features[user_permission][] = delete backup files
features[user_permission][] = delete revisions
features[user_permission][] = display drupal links
features[user_permission][] = execute php code
@@ -147,9 +142,7 @@ features[user_permission][] = menu edit user-menu
features[user_permission][] = notify of path changes
features[user_permission][] = override content type title display
features[user_permission][] = participate in workflow
-features[user_permission][] = perform backup
features[user_permission][] = rename features
-features[user_permission][] = restore from backup
features[user_permission][] = revert revisions
features[user_permission][] = schedule workflow transitions
features[user_permission][] = select account cancellation method
@@ -324,4 +317,5 @@ features[views_view][] = admin_contents
features[workflow][] = Publication
features[workflow_access][] = Publication
features[wysiwyg][] = filtred_html
+features_exclude[dependencies][backup_migrate] = backup_migrate
project path = sites/all/modules/features
diff --git a/sites/all/modules/features/admin/admin.strongarm.inc b/sites/all/modules/features/admin/admin.strongarm.inc
index 66edaa3f..44ba5706 100644
--- a/sites/all/modules/features/admin/admin.strongarm.inc
+++ b/sites/all/modules/features/admin/admin.strongarm.inc
@@ -530,7 +530,7 @@ function admin_strongarm() {
$strongarm->api_version = 1;
$strongarm->name = 'footer_message_msg';
$strongarm->value = array(
- 'value' => '
g.u.i. | 2 rue de la réunion, 75020 Paris | contact@g-u-i.net | 09 51 93 83 43
diff --git a/sites/all/themes/contrid/adminimal_theme/theme-settings.php b/sites/all/themes/contrid/adminimal_theme/theme-settings.php
index 904c00be..62ed81b5 100644
--- a/sites/all/themes/contrid/adminimal_theme/theme-settings.php
+++ b/sites/all/themes/contrid/adminimal_theme/theme-settings.php
@@ -1,6 +1,5 @@
-10,
);
+ $form['skin'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Adminimal skin'),
+ '#weight' => -11,
+ );
+
+ // Create the select list.
+ $form['skin']['adminimal_theme_skin'] = array(
+ '#type' => 'select',
+ '#title' => t('Skin selection'),
+ '#default_value' => theme_get_setting('adminimal_theme_skin'),
+ '#options' => array(
+ 'default' => t('Adminimal Default'),
+ //'dark' => t('Dark'),
+ //'flat' => t('Flat'),
+ 'material' => t('Material (BETA version)'),
+ 'alternative' => t('Alternative'),
+ ),
+ '#description' => t('Select desired skin style. Note that this feature is in beta stage and there might be some issues.'),
+ '#required' => FALSE,
+ );
+
+ $form['adminimal_custom']['style_checkboxes'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Style checkboxes and radio buttons in Webkit browsers.'),
+ '#description' => t('Enabling this option will style checkbox and radio buttons for Webkit browsers like Google Chrome, Safari, Opera and their mobile versions.
+ Enabling this option will not have any negative impact on older browsers that dont support pure CSS styling of checkboxes like Internet Explorer or Firefox.'),
+ '#default_value' => theme_get_setting('style_checkboxes'),
+ );
+
$form['adminimal_custom']['display_icons_config'] = array(
'#type' => 'checkbox',
'#title' => t('Display icons in Configuration page'),
'#default_value' => theme_get_setting('display_icons_config'),
);
+ $form['adminimal_custom']['rounded_buttons'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use rounded buttons'),
+ '#description' => t('Uncheck this setting if you dont like the rounded button styling for some action links'),
+ '#default_value' => theme_get_setting('rounded_buttons'),
+ );
+
+ $form['adminimal_custom']['sticky_actions'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Sticky form actions'),
+ '#description' => t('This will make the form actions div fixed bottom positioning. So for example when you visit the node edit page you wont need to scroll down to save/preview/delete the node. The form action buttons will be sticky to the bottom of the screen.'),
+ '#default_value' => theme_get_setting('sticky_actions'),
+ );
+
+ $form['adminimal_custom']['avoid_custom_font'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Avoid using "Open Sans" font'),
+ '#description' => t('(useful for languages that are not well supported by the "Open sans" font. Like Japanese for example)'),
+ '#default_value' => theme_get_setting('avoid_custom_font'),
+ );
+
+ $form['adminimal_custom']['adminimal_ckeditor'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('CKEditor support'),
+ '#description' => t('Loads custom adminimal css skin for CKEditor. Disable this to avoid css conflicts when using other CKEditor skins.'),
+ '#default_value' => theme_get_setting('adminimal_ckeditor'),
+ );
+
$form['adminimal_custom']['use_custom_media_queries'] = array(
'#type' => 'checkbox',
'#title' => t('Use Custom Media Queries'),