Move all files to 2017/
72
2017/web/core/misc/active-link.es6.js
Normal file
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* @file
|
||||
* Attaches behaviors for Drupal's active link marking.
|
||||
*/
|
||||
|
||||
(function(Drupal, drupalSettings) {
|
||||
/**
|
||||
* Append is-active class.
|
||||
*
|
||||
* The link is only active if its path corresponds to the current path, the
|
||||
* language of the linked path is equal to the current language, and if the
|
||||
* query parameters of the link equal those of the current request, since the
|
||||
* same request with different query parameters may yield a different page
|
||||
* (e.g. pagers, exposed View filters).
|
||||
*
|
||||
* Does not discriminate based on element type, so allows you to set the
|
||||
* is-active class on any element: a, li…
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.activeLinks = {
|
||||
attach(context) {
|
||||
// Start by finding all potentially active links.
|
||||
const path = drupalSettings.path;
|
||||
const queryString = JSON.stringify(path.currentQuery);
|
||||
const querySelector = path.currentQuery
|
||||
? `[data-drupal-link-query='${queryString}']`
|
||||
: ':not([data-drupal-link-query])';
|
||||
const originalSelectors = [
|
||||
`[data-drupal-link-system-path="${path.currentPath}"]`,
|
||||
];
|
||||
let selectors;
|
||||
|
||||
// If this is the front page, we have to check for the <front> path as
|
||||
// well.
|
||||
if (path.isFront) {
|
||||
originalSelectors.push('[data-drupal-link-system-path="<front>"]');
|
||||
}
|
||||
|
||||
// Add language filtering.
|
||||
selectors = [].concat(
|
||||
// Links without any hreflang attributes (most of them).
|
||||
originalSelectors.map(selector => `${selector}:not([hreflang])`),
|
||||
// Links with hreflang equals to the current language.
|
||||
originalSelectors.map(
|
||||
selector => `${selector}[hreflang="${path.currentLanguage}"]`,
|
||||
),
|
||||
);
|
||||
|
||||
// Add query string selector for pagers, exposed filters.
|
||||
selectors = selectors.map(current => current + querySelector);
|
||||
|
||||
// Query the DOM.
|
||||
const activeLinks = context.querySelectorAll(selectors.join(','));
|
||||
const il = activeLinks.length;
|
||||
for (let i = 0; i < il; i++) {
|
||||
activeLinks[i].classList.add('is-active');
|
||||
}
|
||||
},
|
||||
detach(context, settings, trigger) {
|
||||
if (trigger === 'unload') {
|
||||
const activeLinks = context.querySelectorAll(
|
||||
'[data-drupal-link-system-path].is-active',
|
||||
);
|
||||
const il = activeLinks.length;
|
||||
for (let i = 0; i < il; i++) {
|
||||
activeLinks[i].classList.remove('is-active');
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
})(Drupal, drupalSettings);
|
47
2017/web/core/misc/active-link.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function (Drupal, drupalSettings) {
|
||||
Drupal.behaviors.activeLinks = {
|
||||
attach: function attach(context) {
|
||||
var path = drupalSettings.path;
|
||||
var queryString = JSON.stringify(path.currentQuery);
|
||||
var querySelector = path.currentQuery ? '[data-drupal-link-query=\'' + queryString + '\']' : ':not([data-drupal-link-query])';
|
||||
var originalSelectors = ['[data-drupal-link-system-path="' + path.currentPath + '"]'];
|
||||
var selectors = void 0;
|
||||
|
||||
if (path.isFront) {
|
||||
originalSelectors.push('[data-drupal-link-system-path="<front>"]');
|
||||
}
|
||||
|
||||
selectors = [].concat(originalSelectors.map(function (selector) {
|
||||
return selector + ':not([hreflang])';
|
||||
}), originalSelectors.map(function (selector) {
|
||||
return selector + '[hreflang="' + path.currentLanguage + '"]';
|
||||
}));
|
||||
|
||||
selectors = selectors.map(function (current) {
|
||||
return current + querySelector;
|
||||
});
|
||||
|
||||
var activeLinks = context.querySelectorAll(selectors.join(','));
|
||||
var il = activeLinks.length;
|
||||
for (var i = 0; i < il; i++) {
|
||||
activeLinks[i].classList.add('is-active');
|
||||
}
|
||||
},
|
||||
detach: function detach(context, settings, trigger) {
|
||||
if (trigger === 'unload') {
|
||||
var activeLinks = context.querySelectorAll('[data-drupal-link-system-path].is-active');
|
||||
var il = activeLinks.length;
|
||||
for (var i = 0; i < il; i++) {
|
||||
activeLinks[i].classList.remove('is-active');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
})(Drupal, drupalSettings);
|
1538
2017/web/core/misc/ajax.es6.js
Normal file
633
2017/web/core/misc/ajax.js
Normal file
|
@ -0,0 +1,633 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
|
||||
|
||||
(function ($, window, Drupal, drupalSettings) {
|
||||
Drupal.behaviors.AJAX = {
|
||||
attach: function attach(context, settings) {
|
||||
function loadAjaxBehavior(base) {
|
||||
var elementSettings = settings.ajax[base];
|
||||
if (typeof elementSettings.selector === 'undefined') {
|
||||
elementSettings.selector = '#' + base;
|
||||
}
|
||||
$(elementSettings.selector).once('drupal-ajax').each(function () {
|
||||
elementSettings.element = this;
|
||||
elementSettings.base = base;
|
||||
Drupal.ajax(elementSettings);
|
||||
});
|
||||
}
|
||||
|
||||
Object.keys(settings.ajax || {}).forEach(function (base) {
|
||||
return loadAjaxBehavior(base);
|
||||
});
|
||||
|
||||
Drupal.ajax.bindAjaxLinks(document.body);
|
||||
|
||||
$('.use-ajax-submit').once('ajax').each(function () {
|
||||
var elementSettings = {};
|
||||
|
||||
elementSettings.url = $(this.form).attr('action');
|
||||
|
||||
elementSettings.setClick = true;
|
||||
|
||||
elementSettings.event = 'click';
|
||||
|
||||
elementSettings.progress = { type: 'throbber' };
|
||||
elementSettings.base = $(this).attr('id');
|
||||
elementSettings.element = this;
|
||||
|
||||
Drupal.ajax(elementSettings);
|
||||
});
|
||||
},
|
||||
detach: function detach(context, settings, trigger) {
|
||||
if (trigger === 'unload') {
|
||||
Drupal.ajax.expired().forEach(function (instance) {
|
||||
Drupal.ajax.instances[instance.instanceIndex] = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.AjaxError = function (xmlhttp, uri, customMessage) {
|
||||
var statusCode = void 0;
|
||||
var statusText = void 0;
|
||||
var responseText = void 0;
|
||||
if (xmlhttp.status) {
|
||||
statusCode = '\n' + Drupal.t('An AJAX HTTP error occurred.') + '\n' + Drupal.t('HTTP Result Code: !status', { '!status': xmlhttp.status });
|
||||
} else {
|
||||
statusCode = '\n' + Drupal.t('An AJAX HTTP request terminated abnormally.');
|
||||
}
|
||||
statusCode += '\n' + Drupal.t('Debugging information follows.');
|
||||
var pathText = '\n' + Drupal.t('Path: !uri', { '!uri': uri });
|
||||
statusText = '';
|
||||
|
||||
try {
|
||||
statusText = '\n' + Drupal.t('StatusText: !statusText', {
|
||||
'!statusText': $.trim(xmlhttp.statusText)
|
||||
});
|
||||
} catch (e) {}
|
||||
|
||||
responseText = '';
|
||||
|
||||
try {
|
||||
responseText = '\n' + Drupal.t('ResponseText: !responseText', {
|
||||
'!responseText': $.trim(xmlhttp.responseText)
|
||||
});
|
||||
} catch (e) {}
|
||||
|
||||
responseText = responseText.replace(/<("[^"]*"|'[^']*'|[^'">])*>/gi, '');
|
||||
responseText = responseText.replace(/[\n]+\s+/g, '\n');
|
||||
|
||||
var readyStateText = xmlhttp.status === 0 ? '\n' + Drupal.t('ReadyState: !readyState', {
|
||||
'!readyState': xmlhttp.readyState
|
||||
}) : '';
|
||||
|
||||
customMessage = customMessage ? '\n' + Drupal.t('CustomMessage: !customMessage', {
|
||||
'!customMessage': customMessage
|
||||
}) : '';
|
||||
|
||||
this.message = statusCode + pathText + statusText + customMessage + responseText + readyStateText;
|
||||
|
||||
this.name = 'AjaxError';
|
||||
};
|
||||
|
||||
Drupal.AjaxError.prototype = new Error();
|
||||
Drupal.AjaxError.prototype.constructor = Drupal.AjaxError;
|
||||
|
||||
Drupal.ajax = function (settings) {
|
||||
if (arguments.length !== 1) {
|
||||
throw new Error('Drupal.ajax() function must be called with one configuration object only');
|
||||
}
|
||||
|
||||
var base = settings.base || false;
|
||||
var element = settings.element || false;
|
||||
delete settings.base;
|
||||
delete settings.element;
|
||||
|
||||
if (!settings.progress && !element) {
|
||||
settings.progress = false;
|
||||
}
|
||||
|
||||
var ajax = new Drupal.Ajax(base, element, settings);
|
||||
ajax.instanceIndex = Drupal.ajax.instances.length;
|
||||
Drupal.ajax.instances.push(ajax);
|
||||
|
||||
return ajax;
|
||||
};
|
||||
|
||||
Drupal.ajax.instances = [];
|
||||
|
||||
Drupal.ajax.expired = function () {
|
||||
return Drupal.ajax.instances.filter(function (instance) {
|
||||
return instance && instance.element !== false && !document.body.contains(instance.element);
|
||||
});
|
||||
};
|
||||
|
||||
Drupal.ajax.bindAjaxLinks = function (element) {
|
||||
$(element).find('.use-ajax').once('ajax').each(function (i, ajaxLink) {
|
||||
var $linkElement = $(ajaxLink);
|
||||
|
||||
var elementSettings = {
|
||||
progress: { type: 'throbber' },
|
||||
dialogType: $linkElement.data('dialog-type'),
|
||||
dialog: $linkElement.data('dialog-options'),
|
||||
dialogRenderer: $linkElement.data('dialog-renderer'),
|
||||
base: $linkElement.attr('id'),
|
||||
element: ajaxLink
|
||||
};
|
||||
var href = $linkElement.attr('href');
|
||||
|
||||
if (href) {
|
||||
elementSettings.url = href;
|
||||
elementSettings.event = 'click';
|
||||
}
|
||||
Drupal.ajax(elementSettings);
|
||||
});
|
||||
};
|
||||
|
||||
Drupal.Ajax = function (base, element, elementSettings) {
|
||||
var defaults = {
|
||||
event: element ? 'mousedown' : null,
|
||||
keypress: true,
|
||||
selector: base ? '#' + base : null,
|
||||
effect: 'none',
|
||||
speed: 'none',
|
||||
method: 'replaceWith',
|
||||
progress: {
|
||||
type: 'throbber',
|
||||
message: Drupal.t('Please wait...')
|
||||
},
|
||||
submit: {
|
||||
js: true
|
||||
}
|
||||
};
|
||||
|
||||
$.extend(this, defaults, elementSettings);
|
||||
|
||||
this.commands = new Drupal.AjaxCommands();
|
||||
|
||||
this.instanceIndex = false;
|
||||
|
||||
if (this.wrapper) {
|
||||
this.wrapper = '#' + this.wrapper;
|
||||
}
|
||||
|
||||
this.element = element;
|
||||
|
||||
this.element_settings = elementSettings;
|
||||
|
||||
this.elementSettings = elementSettings;
|
||||
|
||||
if (this.element && this.element.form) {
|
||||
this.$form = $(this.element.form);
|
||||
}
|
||||
|
||||
if (!this.url) {
|
||||
var $element = $(this.element);
|
||||
if ($element.is('a')) {
|
||||
this.url = $element.attr('href');
|
||||
} else if (this.element && element.form) {
|
||||
this.url = this.$form.attr('action');
|
||||
}
|
||||
}
|
||||
|
||||
var originalUrl = this.url;
|
||||
|
||||
this.url = this.url.replace(/\/nojs(\/|$|\?|#)/, '/ajax$1');
|
||||
|
||||
if (drupalSettings.ajaxTrustedUrl[originalUrl]) {
|
||||
drupalSettings.ajaxTrustedUrl[this.url] = true;
|
||||
}
|
||||
|
||||
var ajax = this;
|
||||
|
||||
ajax.options = {
|
||||
url: ajax.url,
|
||||
data: ajax.submit,
|
||||
beforeSerialize: function beforeSerialize(elementSettings, options) {
|
||||
return ajax.beforeSerialize(elementSettings, options);
|
||||
},
|
||||
beforeSubmit: function beforeSubmit(formValues, elementSettings, options) {
|
||||
ajax.ajaxing = true;
|
||||
return ajax.beforeSubmit(formValues, elementSettings, options);
|
||||
},
|
||||
beforeSend: function beforeSend(xmlhttprequest, options) {
|
||||
ajax.ajaxing = true;
|
||||
return ajax.beforeSend(xmlhttprequest, options);
|
||||
},
|
||||
success: function success(response, status, xmlhttprequest) {
|
||||
if (typeof response === 'string') {
|
||||
response = $.parseJSON(response);
|
||||
}
|
||||
|
||||
if (response !== null && !drupalSettings.ajaxTrustedUrl[ajax.url]) {
|
||||
if (xmlhttprequest.getResponseHeader('X-Drupal-Ajax-Token') !== '1') {
|
||||
var customMessage = Drupal.t('The response failed verification so will not be processed.');
|
||||
return ajax.error(xmlhttprequest, ajax.url, customMessage);
|
||||
}
|
||||
}
|
||||
|
||||
return ajax.success(response, status);
|
||||
},
|
||||
complete: function complete(xmlhttprequest, status) {
|
||||
ajax.ajaxing = false;
|
||||
if (status === 'error' || status === 'parsererror') {
|
||||
return ajax.error(xmlhttprequest, ajax.url);
|
||||
}
|
||||
},
|
||||
|
||||
dataType: 'json',
|
||||
type: 'POST'
|
||||
};
|
||||
|
||||
if (elementSettings.dialog) {
|
||||
ajax.options.data.dialogOptions = elementSettings.dialog;
|
||||
}
|
||||
|
||||
if (ajax.options.url.indexOf('?') === -1) {
|
||||
ajax.options.url += '?';
|
||||
} else {
|
||||
ajax.options.url += '&';
|
||||
}
|
||||
|
||||
var wrapper = 'drupal_' + (elementSettings.dialogType || 'ajax');
|
||||
if (elementSettings.dialogRenderer) {
|
||||
wrapper += '.' + elementSettings.dialogRenderer;
|
||||
}
|
||||
ajax.options.url += Drupal.ajax.WRAPPER_FORMAT + '=' + wrapper;
|
||||
|
||||
$(ajax.element).on(elementSettings.event, function (event) {
|
||||
if (!drupalSettings.ajaxTrustedUrl[ajax.url] && !Drupal.url.isLocal(ajax.url)) {
|
||||
throw new Error(Drupal.t('The callback URL is not local and not trusted: !url', {
|
||||
'!url': ajax.url
|
||||
}));
|
||||
}
|
||||
return ajax.eventResponse(this, event);
|
||||
});
|
||||
|
||||
if (elementSettings.keypress) {
|
||||
$(ajax.element).on('keypress', function (event) {
|
||||
return ajax.keypressResponse(this, event);
|
||||
});
|
||||
}
|
||||
|
||||
if (elementSettings.prevent) {
|
||||
$(ajax.element).on(elementSettings.prevent, false);
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.ajax.WRAPPER_FORMAT = '_wrapper_format';
|
||||
|
||||
Drupal.Ajax.AJAX_REQUEST_PARAMETER = '_drupal_ajax';
|
||||
|
||||
Drupal.Ajax.prototype.execute = function () {
|
||||
if (this.ajaxing) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.beforeSerialize(this.element, this.options);
|
||||
|
||||
return $.ajax(this.options);
|
||||
} catch (e) {
|
||||
this.ajaxing = false;
|
||||
window.alert('An error occurred while attempting to process ' + this.options.url + ': ' + e.message);
|
||||
|
||||
return $.Deferred().reject();
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.Ajax.prototype.keypressResponse = function (element, event) {
|
||||
var ajax = this;
|
||||
|
||||
if (event.which === 13 || event.which === 32 && element.type !== 'text' && element.type !== 'textarea' && element.type !== 'tel' && element.type !== 'number') {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
$(element).trigger(ajax.elementSettings.event);
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.Ajax.prototype.eventResponse = function (element, event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
var ajax = this;
|
||||
|
||||
if (ajax.ajaxing) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (ajax.$form) {
|
||||
if (ajax.setClick) {
|
||||
element.form.clk = element;
|
||||
}
|
||||
|
||||
ajax.$form.ajaxSubmit(ajax.options);
|
||||
} else {
|
||||
ajax.beforeSerialize(ajax.element, ajax.options);
|
||||
$.ajax(ajax.options);
|
||||
}
|
||||
} catch (e) {
|
||||
ajax.ajaxing = false;
|
||||
window.alert('An error occurred while attempting to process ' + ajax.options.url + ': ' + e.message);
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.Ajax.prototype.beforeSerialize = function (element, options) {
|
||||
if (this.$form) {
|
||||
var settings = this.settings || drupalSettings;
|
||||
Drupal.detachBehaviors(this.$form.get(0), settings, 'serialize');
|
||||
}
|
||||
|
||||
options.data[Drupal.Ajax.AJAX_REQUEST_PARAMETER] = 1;
|
||||
|
||||
var pageState = drupalSettings.ajaxPageState;
|
||||
options.data['ajax_page_state[theme]'] = pageState.theme;
|
||||
options.data['ajax_page_state[theme_token]'] = pageState.theme_token;
|
||||
options.data['ajax_page_state[libraries]'] = pageState.libraries;
|
||||
};
|
||||
|
||||
Drupal.Ajax.prototype.beforeSubmit = function (formValues, element, options) {};
|
||||
|
||||
Drupal.Ajax.prototype.beforeSend = function (xmlhttprequest, options) {
|
||||
if (this.$form) {
|
||||
options.extraData = options.extraData || {};
|
||||
|
||||
options.extraData.ajax_iframe_upload = '1';
|
||||
|
||||
var v = $.fieldValue(this.element);
|
||||
if (v !== null) {
|
||||
options.extraData[this.element.name] = v;
|
||||
}
|
||||
}
|
||||
|
||||
$(this.element).prop('disabled', true);
|
||||
|
||||
if (!this.progress || !this.progress.type) {
|
||||
return;
|
||||
}
|
||||
|
||||
var progressIndicatorMethod = 'setProgressIndicator' + this.progress.type.slice(0, 1).toUpperCase() + this.progress.type.slice(1).toLowerCase();
|
||||
if (progressIndicatorMethod in this && typeof this[progressIndicatorMethod] === 'function') {
|
||||
this[progressIndicatorMethod].call(this);
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.theme.ajaxProgressThrobber = function (message) {
|
||||
var messageMarkup = typeof message === 'string' ? Drupal.theme('ajaxProgressMessage', message) : '';
|
||||
var throbber = '<div class="throbber"> </div>';
|
||||
|
||||
return '<div class="ajax-progress ajax-progress-throbber">' + throbber + messageMarkup + '</div>';
|
||||
};
|
||||
|
||||
Drupal.theme.ajaxProgressIndicatorFullscreen = function () {
|
||||
return '<div class="ajax-progress ajax-progress-fullscreen"> </div>';
|
||||
};
|
||||
|
||||
Drupal.theme.ajaxProgressMessage = function (message) {
|
||||
return '<div class="message">' + message + '</div>';
|
||||
};
|
||||
|
||||
Drupal.Ajax.prototype.setProgressIndicatorBar = function () {
|
||||
var progressBar = new Drupal.ProgressBar('ajax-progress-' + this.element.id, $.noop, this.progress.method, $.noop);
|
||||
if (this.progress.message) {
|
||||
progressBar.setProgress(-1, this.progress.message);
|
||||
}
|
||||
if (this.progress.url) {
|
||||
progressBar.startMonitoring(this.progress.url, this.progress.interval || 1500);
|
||||
}
|
||||
this.progress.element = $(progressBar.element).addClass('ajax-progress ajax-progress-bar');
|
||||
this.progress.object = progressBar;
|
||||
$(this.element).after(this.progress.element);
|
||||
};
|
||||
|
||||
Drupal.Ajax.prototype.setProgressIndicatorThrobber = function () {
|
||||
this.progress.element = $(Drupal.theme('ajaxProgressThrobber', this.progress.message));
|
||||
$(this.element).after(this.progress.element);
|
||||
};
|
||||
|
||||
Drupal.Ajax.prototype.setProgressIndicatorFullscreen = function () {
|
||||
this.progress.element = $(Drupal.theme('ajaxProgressIndicatorFullscreen'));
|
||||
$('body').after(this.progress.element);
|
||||
};
|
||||
|
||||
Drupal.Ajax.prototype.success = function (response, status) {
|
||||
var _this = this;
|
||||
|
||||
if (this.progress.element) {
|
||||
$(this.progress.element).remove();
|
||||
}
|
||||
if (this.progress.object) {
|
||||
this.progress.object.stopMonitoring();
|
||||
}
|
||||
$(this.element).prop('disabled', false);
|
||||
|
||||
var elementParents = $(this.element).parents('[data-drupal-selector]').addBack().toArray();
|
||||
|
||||
var focusChanged = false;
|
||||
Object.keys(response || {}).forEach(function (i) {
|
||||
if (response[i].command && _this.commands[response[i].command]) {
|
||||
_this.commands[response[i].command](_this, response[i], status);
|
||||
if (response[i].command === 'invoke' && response[i].method === 'focus') {
|
||||
focusChanged = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!focusChanged && this.element && !$(this.element).data('disable-refocus')) {
|
||||
var target = false;
|
||||
|
||||
for (var n = elementParents.length - 1; !target && n >= 0; n--) {
|
||||
target = document.querySelector('[data-drupal-selector="' + elementParents[n].getAttribute('data-drupal-selector') + '"]');
|
||||
}
|
||||
|
||||
if (target) {
|
||||
$(target).trigger('focus');
|
||||
}
|
||||
}
|
||||
|
||||
if (this.$form) {
|
||||
var settings = this.settings || drupalSettings;
|
||||
Drupal.attachBehaviors(this.$form.get(0), settings);
|
||||
}
|
||||
|
||||
this.settings = null;
|
||||
};
|
||||
|
||||
Drupal.Ajax.prototype.getEffect = function (response) {
|
||||
var type = response.effect || this.effect;
|
||||
var speed = response.speed || this.speed;
|
||||
|
||||
var effect = {};
|
||||
if (type === 'none') {
|
||||
effect.showEffect = 'show';
|
||||
effect.hideEffect = 'hide';
|
||||
effect.showSpeed = '';
|
||||
} else if (type === 'fade') {
|
||||
effect.showEffect = 'fadeIn';
|
||||
effect.hideEffect = 'fadeOut';
|
||||
effect.showSpeed = speed;
|
||||
} else {
|
||||
effect.showEffect = type + 'Toggle';
|
||||
effect.hideEffect = type + 'Toggle';
|
||||
effect.showSpeed = speed;
|
||||
}
|
||||
|
||||
return effect;
|
||||
};
|
||||
|
||||
Drupal.Ajax.prototype.error = function (xmlhttprequest, uri, customMessage) {
|
||||
if (this.progress.element) {
|
||||
$(this.progress.element).remove();
|
||||
}
|
||||
if (this.progress.object) {
|
||||
this.progress.object.stopMonitoring();
|
||||
}
|
||||
|
||||
$(this.wrapper).show();
|
||||
|
||||
$(this.element).prop('disabled', false);
|
||||
|
||||
if (this.$form) {
|
||||
var settings = this.settings || drupalSettings;
|
||||
Drupal.attachBehaviors(this.$form.get(0), settings);
|
||||
}
|
||||
throw new Drupal.AjaxError(xmlhttprequest, uri, customMessage);
|
||||
};
|
||||
|
||||
Drupal.theme.ajaxWrapperNewContent = function ($newContent, ajax, response) {
|
||||
return (response.effect || ajax.effect) !== 'none' && $newContent.filter(function (i) {
|
||||
return !($newContent[i].nodeName === '#comment' || $newContent[i].nodeName === '#text' && /^(\s|\n|\r)*$/.test($newContent[i].textContent));
|
||||
}).length > 1 ? Drupal.theme('ajaxWrapperMultipleRootElements', $newContent) : $newContent;
|
||||
};
|
||||
|
||||
Drupal.theme.ajaxWrapperMultipleRootElements = function ($elements) {
|
||||
return $('<div></div>').append($elements);
|
||||
};
|
||||
|
||||
Drupal.AjaxCommands = function () {};
|
||||
Drupal.AjaxCommands.prototype = {
|
||||
insert: function insert(ajax, response) {
|
||||
var $wrapper = response.selector ? $(response.selector) : $(ajax.wrapper);
|
||||
var method = response.method || ajax.method;
|
||||
var effect = ajax.getEffect(response);
|
||||
|
||||
var settings = response.settings || ajax.settings || drupalSettings;
|
||||
|
||||
var $newContent = $($.parseHTML(response.data, document, true));
|
||||
|
||||
$newContent = Drupal.theme('ajaxWrapperNewContent', $newContent, ajax, response);
|
||||
|
||||
switch (method) {
|
||||
case 'html':
|
||||
case 'replaceWith':
|
||||
case 'replaceAll':
|
||||
case 'empty':
|
||||
case 'remove':
|
||||
Drupal.detachBehaviors($wrapper.get(0), settings);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$wrapper[method]($newContent);
|
||||
|
||||
if (effect.showEffect !== 'show') {
|
||||
$newContent.hide();
|
||||
}
|
||||
|
||||
var $ajaxNewContent = $newContent.find('.ajax-new-content');
|
||||
if ($ajaxNewContent.length) {
|
||||
$ajaxNewContent.hide();
|
||||
$newContent.show();
|
||||
$ajaxNewContent[effect.showEffect](effect.showSpeed);
|
||||
} else if (effect.showEffect !== 'show') {
|
||||
$newContent[effect.showEffect](effect.showSpeed);
|
||||
}
|
||||
|
||||
if ($newContent.parents('html').length) {
|
||||
$newContent.each(function (index, element) {
|
||||
if (element.nodeType === Node.ELEMENT_NODE) {
|
||||
Drupal.attachBehaviors(element, settings);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
remove: function remove(ajax, response, status) {
|
||||
var settings = response.settings || ajax.settings || drupalSettings;
|
||||
$(response.selector).each(function () {
|
||||
Drupal.detachBehaviors(this, settings);
|
||||
}).remove();
|
||||
},
|
||||
changed: function changed(ajax, response, status) {
|
||||
var $element = $(response.selector);
|
||||
if (!$element.hasClass('ajax-changed')) {
|
||||
$element.addClass('ajax-changed');
|
||||
if (response.asterisk) {
|
||||
$element.find(response.asterisk).append(' <abbr class="ajax-changed" title="' + Drupal.t('Changed') + '">*</abbr> ');
|
||||
}
|
||||
}
|
||||
},
|
||||
alert: function alert(ajax, response, status) {
|
||||
window.alert(response.text, response.title);
|
||||
},
|
||||
redirect: function redirect(ajax, response, status) {
|
||||
window.location = response.url;
|
||||
},
|
||||
css: function css(ajax, response, status) {
|
||||
$(response.selector).css(response.argument);
|
||||
},
|
||||
settings: function settings(ajax, response, status) {
|
||||
var ajaxSettings = drupalSettings.ajax;
|
||||
|
||||
if (ajaxSettings) {
|
||||
Drupal.ajax.expired().forEach(function (instance) {
|
||||
|
||||
if (instance.selector) {
|
||||
var selector = instance.selector.replace('#', '');
|
||||
if (selector in ajaxSettings) {
|
||||
delete ajaxSettings[selector];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (response.merge) {
|
||||
$.extend(true, drupalSettings, response.settings);
|
||||
} else {
|
||||
ajax.settings = response.settings;
|
||||
}
|
||||
},
|
||||
data: function data(ajax, response, status) {
|
||||
$(response.selector).data(response.name, response.value);
|
||||
},
|
||||
invoke: function invoke(ajax, response, status) {
|
||||
var $element = $(response.selector);
|
||||
$element[response.method].apply($element, _toConsumableArray(response.args));
|
||||
},
|
||||
restripe: function restripe(ajax, response, status) {
|
||||
$(response.selector).find('> tbody > tr:visible, > tr:visible').removeClass('odd even').filter(':even').addClass('odd').end().filter(':odd').addClass('even');
|
||||
},
|
||||
update_build_id: function update_build_id(ajax, response, status) {
|
||||
$('input[name="form_build_id"][value="' + response.old + '"]').val(response.new);
|
||||
},
|
||||
add_css: function add_css(ajax, response, status) {
|
||||
$('head').prepend(response.data);
|
||||
|
||||
var match = void 0;
|
||||
var importMatch = /^@import url\("(.*)"\);$/gim;
|
||||
if (document.styleSheets[0].addImport && importMatch.test(response.data)) {
|
||||
importMatch.lastIndex = 0;
|
||||
do {
|
||||
match = importMatch.exec(response.data);
|
||||
document.styleSheets[0].addImport(match[1]);
|
||||
} while (match);
|
||||
}
|
||||
}
|
||||
};
|
||||
})(jQuery, window, Drupal, drupalSettings);
|
117
2017/web/core/misc/announce.es6.js
Normal file
|
@ -0,0 +1,117 @@
|
|||
/**
|
||||
* @file
|
||||
* Adds an HTML element and method to trigger audio UAs to read system messages.
|
||||
*
|
||||
* Use {@link Drupal.announce} to indicate to screen reader users that an
|
||||
* element on the page has changed state. For instance, if clicking a link
|
||||
* loads 10 more items into a list, one might announce the change like this.
|
||||
*
|
||||
* @example
|
||||
* $('#search-list')
|
||||
* .on('itemInsert', function (event, data) {
|
||||
* // Insert the new items.
|
||||
* $(data.container.el).append(data.items.el);
|
||||
* // Announce the change to the page contents.
|
||||
* Drupal.announce(Drupal.t('@count items added to @container',
|
||||
* {'@count': data.items.length, '@container': data.container.title}
|
||||
* ));
|
||||
* });
|
||||
*/
|
||||
|
||||
(function(Drupal, debounce) {
|
||||
let liveElement;
|
||||
const announcements = [];
|
||||
|
||||
/**
|
||||
* Builds a div element with the aria-live attribute and add it to the DOM.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for drupalAnnounce.
|
||||
*/
|
||||
Drupal.behaviors.drupalAnnounce = {
|
||||
attach(context) {
|
||||
// Create only one aria-live element.
|
||||
if (!liveElement) {
|
||||
liveElement = document.createElement('div');
|
||||
liveElement.id = 'drupal-live-announce';
|
||||
liveElement.className = 'visually-hidden';
|
||||
liveElement.setAttribute('aria-live', 'polite');
|
||||
liveElement.setAttribute('aria-busy', 'false');
|
||||
document.body.appendChild(liveElement);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Concatenates announcements to a single string; appends to the live region.
|
||||
*/
|
||||
function announce() {
|
||||
const text = [];
|
||||
let priority = 'polite';
|
||||
let announcement;
|
||||
|
||||
// Create an array of announcement strings to be joined and appended to the
|
||||
// aria live region.
|
||||
const il = announcements.length;
|
||||
for (let i = 0; i < il; i++) {
|
||||
announcement = announcements.pop();
|
||||
text.unshift(announcement.text);
|
||||
// If any of the announcements has a priority of assertive then the group
|
||||
// of joined announcements will have this priority.
|
||||
if (announcement.priority === 'assertive') {
|
||||
priority = 'assertive';
|
||||
}
|
||||
}
|
||||
|
||||
if (text.length) {
|
||||
// Clear the liveElement so that repeated strings will be read.
|
||||
liveElement.innerHTML = '';
|
||||
// Set the busy state to true until the node changes are complete.
|
||||
liveElement.setAttribute('aria-busy', 'true');
|
||||
// Set the priority to assertive, or default to polite.
|
||||
liveElement.setAttribute('aria-live', priority);
|
||||
// Print the text to the live region. Text should be run through
|
||||
// Drupal.t() before being passed to Drupal.announce().
|
||||
liveElement.innerHTML = text.join('\n');
|
||||
// The live text area is updated. Allow the AT to announce the text.
|
||||
liveElement.setAttribute('aria-busy', 'false');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers audio UAs to read the supplied text.
|
||||
*
|
||||
* The aria-live region will only read the text that currently populates its
|
||||
* text node. Replacing text quickly in rapid calls to announce results in
|
||||
* only the text from the most recent call to {@link Drupal.announce} being
|
||||
* read. By wrapping the call to announce in a debounce function, we allow for
|
||||
* time for multiple calls to {@link Drupal.announce} to queue up their
|
||||
* messages. These messages are then joined and append to the aria-live region
|
||||
* as one text node.
|
||||
*
|
||||
* @param {string} text
|
||||
* A string to be read by the UA.
|
||||
* @param {string} [priority='polite']
|
||||
* A string to indicate the priority of the message. Can be either
|
||||
* 'polite' or 'assertive'.
|
||||
*
|
||||
* @return {function}
|
||||
* The return of the call to debounce.
|
||||
*
|
||||
* @see http://www.w3.org/WAI/PF/aria-practices/#liveprops
|
||||
*/
|
||||
Drupal.announce = function(text, priority) {
|
||||
// Save the text and priority into a closure variable. Multiple simultaneous
|
||||
// announcements will be concatenated and read in sequence.
|
||||
announcements.push({
|
||||
text,
|
||||
priority,
|
||||
});
|
||||
// Immediately invoke the function that debounce returns. 200 ms is right at
|
||||
// the cusp where humans notice a pause, so we will wait
|
||||
// at most this much time before the set of queued announcements is read.
|
||||
return debounce(announce, 200)();
|
||||
};
|
||||
})(Drupal, Drupal.debounce);
|
61
2017/web/core/misc/announce.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function (Drupal, debounce) {
|
||||
var liveElement = void 0;
|
||||
var announcements = [];
|
||||
|
||||
Drupal.behaviors.drupalAnnounce = {
|
||||
attach: function attach(context) {
|
||||
if (!liveElement) {
|
||||
liveElement = document.createElement('div');
|
||||
liveElement.id = 'drupal-live-announce';
|
||||
liveElement.className = 'visually-hidden';
|
||||
liveElement.setAttribute('aria-live', 'polite');
|
||||
liveElement.setAttribute('aria-busy', 'false');
|
||||
document.body.appendChild(liveElement);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function announce() {
|
||||
var text = [];
|
||||
var priority = 'polite';
|
||||
var announcement = void 0;
|
||||
|
||||
var il = announcements.length;
|
||||
for (var i = 0; i < il; i++) {
|
||||
announcement = announcements.pop();
|
||||
text.unshift(announcement.text);
|
||||
|
||||
if (announcement.priority === 'assertive') {
|
||||
priority = 'assertive';
|
||||
}
|
||||
}
|
||||
|
||||
if (text.length) {
|
||||
liveElement.innerHTML = '';
|
||||
|
||||
liveElement.setAttribute('aria-busy', 'true');
|
||||
|
||||
liveElement.setAttribute('aria-live', priority);
|
||||
|
||||
liveElement.innerHTML = text.join('\n');
|
||||
|
||||
liveElement.setAttribute('aria-busy', 'false');
|
||||
}
|
||||
}
|
||||
|
||||
Drupal.announce = function (text, priority) {
|
||||
announcements.push({
|
||||
text: text,
|
||||
priority: priority
|
||||
});
|
||||
|
||||
return debounce(announce, 200)();
|
||||
};
|
||||
})(Drupal, Drupal.debounce);
|
288
2017/web/core/misc/autocomplete.es6.js
Normal file
|
@ -0,0 +1,288 @@
|
|||
/**
|
||||
* @file
|
||||
* Autocomplete based on jQuery UI.
|
||||
*/
|
||||
|
||||
(function($, Drupal) {
|
||||
let autocomplete;
|
||||
|
||||
/**
|
||||
* Helper splitting terms from the autocomplete value.
|
||||
*
|
||||
* @function Drupal.autocomplete.splitValues
|
||||
*
|
||||
* @param {string} value
|
||||
* The value being entered by the user.
|
||||
*
|
||||
* @return {Array}
|
||||
* Array of values, split by comma.
|
||||
*/
|
||||
function autocompleteSplitValues(value) {
|
||||
// We will match the value against comma-separated terms.
|
||||
const result = [];
|
||||
let quote = false;
|
||||
let current = '';
|
||||
const valueLength = value.length;
|
||||
let character;
|
||||
|
||||
for (let i = 0; i < valueLength; i++) {
|
||||
character = value.charAt(i);
|
||||
if (character === '"') {
|
||||
current += character;
|
||||
quote = !quote;
|
||||
} else if (character === ',' && !quote) {
|
||||
result.push(current.trim());
|
||||
current = '';
|
||||
} else {
|
||||
current += character;
|
||||
}
|
||||
}
|
||||
if (value.length > 0) {
|
||||
result.push($.trim(current));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last value of an multi-value textfield.
|
||||
*
|
||||
* @function Drupal.autocomplete.extractLastTerm
|
||||
*
|
||||
* @param {string} terms
|
||||
* The value of the field.
|
||||
*
|
||||
* @return {string}
|
||||
* The last value of the input field.
|
||||
*/
|
||||
function extractLastTerm(terms) {
|
||||
return autocomplete.splitValues(terms).pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* The search handler is called before a search is performed.
|
||||
*
|
||||
* @function Drupal.autocomplete.options.search
|
||||
*
|
||||
* @param {object} event
|
||||
* The event triggered.
|
||||
*
|
||||
* @return {bool}
|
||||
* Whether to perform a search or not.
|
||||
*/
|
||||
function searchHandler(event) {
|
||||
const options = autocomplete.options;
|
||||
|
||||
if (options.isComposing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const term = autocomplete.extractLastTerm(event.target.value);
|
||||
// Abort search if the first character is in firstCharacterBlacklist.
|
||||
if (
|
||||
term.length > 0 &&
|
||||
options.firstCharacterBlacklist.indexOf(term[0]) !== -1
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
// Only search when the term is at least the minimum length.
|
||||
return term.length >= options.minLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* JQuery UI autocomplete source callback.
|
||||
*
|
||||
* @param {object} request
|
||||
* The request object.
|
||||
* @param {function} response
|
||||
* The function to call with the response.
|
||||
*/
|
||||
function sourceData(request, response) {
|
||||
const elementId = this.element.attr('id');
|
||||
|
||||
if (!(elementId in autocomplete.cache)) {
|
||||
autocomplete.cache[elementId] = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter through the suggestions removing all terms already tagged and
|
||||
* display the available terms to the user.
|
||||
*
|
||||
* @param {object} suggestions
|
||||
* Suggestions returned by the server.
|
||||
*/
|
||||
function showSuggestions(suggestions) {
|
||||
const tagged = autocomplete.splitValues(request.term);
|
||||
const il = tagged.length;
|
||||
for (let i = 0; i < il; i++) {
|
||||
const index = suggestions.indexOf(tagged[i]);
|
||||
if (index >= 0) {
|
||||
suggestions.splice(index, 1);
|
||||
}
|
||||
}
|
||||
response(suggestions);
|
||||
}
|
||||
|
||||
// Get the desired term and construct the autocomplete URL for it.
|
||||
const term = autocomplete.extractLastTerm(request.term);
|
||||
|
||||
/**
|
||||
* Transforms the data object into an array and update autocomplete results.
|
||||
*
|
||||
* @param {object} data
|
||||
* The data sent back from the server.
|
||||
*/
|
||||
function sourceCallbackHandler(data) {
|
||||
autocomplete.cache[elementId][term] = data;
|
||||
|
||||
// Send the new string array of terms to the jQuery UI list.
|
||||
showSuggestions(data);
|
||||
}
|
||||
|
||||
// Check if the term is already cached.
|
||||
if (autocomplete.cache[elementId].hasOwnProperty(term)) {
|
||||
showSuggestions(autocomplete.cache[elementId][term]);
|
||||
} else {
|
||||
const options = $.extend(
|
||||
{ success: sourceCallbackHandler, data: { q: term } },
|
||||
autocomplete.ajax,
|
||||
);
|
||||
$.ajax(this.element.attr('data-autocomplete-path'), options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an autocompletefocus event.
|
||||
*
|
||||
* @return {bool}
|
||||
* Always returns false.
|
||||
*/
|
||||
function focusHandler() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an autocompleteselect event.
|
||||
*
|
||||
* @param {jQuery.Event} event
|
||||
* The event triggered.
|
||||
* @param {object} ui
|
||||
* The jQuery UI settings object.
|
||||
*
|
||||
* @return {bool}
|
||||
* Returns false to indicate the event status.
|
||||
*/
|
||||
function selectHandler(event, ui) {
|
||||
const terms = autocomplete.splitValues(event.target.value);
|
||||
// Remove the current input.
|
||||
terms.pop();
|
||||
// Add the selected item.
|
||||
terms.push(ui.item.value);
|
||||
|
||||
event.target.value = terms.join(', ');
|
||||
// Return false to tell jQuery UI that we've filled in the value already.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override jQuery UI _renderItem function to output HTML by default.
|
||||
*
|
||||
* @param {jQuery} ul
|
||||
* jQuery collection of the ul element.
|
||||
* @param {object} item
|
||||
* The list item to append.
|
||||
*
|
||||
* @return {jQuery}
|
||||
* jQuery collection of the ul element.
|
||||
*/
|
||||
function renderItem(ul, item) {
|
||||
return $('<li>')
|
||||
.append($('<a>').html(item.label))
|
||||
.appendTo(ul);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the autocomplete behavior to all required fields.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the autocomplete behaviors.
|
||||
* @prop {Drupal~behaviorDetach} detach
|
||||
* Detaches the autocomplete behaviors.
|
||||
*/
|
||||
Drupal.behaviors.autocomplete = {
|
||||
attach(context) {
|
||||
// Act on textfields with the "form-autocomplete" class.
|
||||
const $autocomplete = $(context)
|
||||
.find('input.form-autocomplete')
|
||||
.once('autocomplete');
|
||||
if ($autocomplete.length) {
|
||||
// Allow options to be overridden per instance.
|
||||
const blacklist = $autocomplete.attr(
|
||||
'data-autocomplete-first-character-blacklist',
|
||||
);
|
||||
$.extend(autocomplete.options, {
|
||||
firstCharacterBlacklist: blacklist || '',
|
||||
});
|
||||
// Use jQuery UI Autocomplete on the textfield.
|
||||
$autocomplete.autocomplete(autocomplete.options).each(function() {
|
||||
$(this).data('ui-autocomplete')._renderItem =
|
||||
autocomplete.options.renderItem;
|
||||
});
|
||||
|
||||
// Use CompositionEvent to handle IME inputs. It requests remote server on "compositionend" event only.
|
||||
$autocomplete.on('compositionstart.autocomplete', () => {
|
||||
autocomplete.options.isComposing = true;
|
||||
});
|
||||
$autocomplete.on('compositionend.autocomplete', () => {
|
||||
autocomplete.options.isComposing = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
detach(context, settings, trigger) {
|
||||
if (trigger === 'unload') {
|
||||
$(context)
|
||||
.find('input.form-autocomplete')
|
||||
.removeOnce('autocomplete')
|
||||
.autocomplete('destroy');
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Autocomplete object implementation.
|
||||
*
|
||||
* @namespace Drupal.autocomplete
|
||||
*/
|
||||
autocomplete = {
|
||||
cache: {},
|
||||
// Exposes options to allow overriding by contrib.
|
||||
splitValues: autocompleteSplitValues,
|
||||
extractLastTerm,
|
||||
// jQuery UI autocomplete options.
|
||||
|
||||
/**
|
||||
* JQuery UI option object.
|
||||
*
|
||||
* @name Drupal.autocomplete.options
|
||||
*/
|
||||
options: {
|
||||
source: sourceData,
|
||||
focus: focusHandler,
|
||||
search: searchHandler,
|
||||
select: selectHandler,
|
||||
renderItem,
|
||||
minLength: 1,
|
||||
// Custom options, used by Drupal.autocomplete.
|
||||
firstCharacterBlacklist: '',
|
||||
// Custom options, indicate IME usage status.
|
||||
isComposing: false,
|
||||
},
|
||||
ajax: {
|
||||
dataType: 'json',
|
||||
},
|
||||
};
|
||||
|
||||
Drupal.autocomplete = autocomplete;
|
||||
})(jQuery, Drupal);
|
164
2017/web/core/misc/autocomplete.js
Normal file
|
@ -0,0 +1,164 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal) {
|
||||
var autocomplete = void 0;
|
||||
|
||||
function autocompleteSplitValues(value) {
|
||||
var result = [];
|
||||
var quote = false;
|
||||
var current = '';
|
||||
var valueLength = value.length;
|
||||
var character = void 0;
|
||||
|
||||
for (var i = 0; i < valueLength; i++) {
|
||||
character = value.charAt(i);
|
||||
if (character === '"') {
|
||||
current += character;
|
||||
quote = !quote;
|
||||
} else if (character === ',' && !quote) {
|
||||
result.push(current.trim());
|
||||
current = '';
|
||||
} else {
|
||||
current += character;
|
||||
}
|
||||
}
|
||||
if (value.length > 0) {
|
||||
result.push($.trim(current));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function extractLastTerm(terms) {
|
||||
return autocomplete.splitValues(terms).pop();
|
||||
}
|
||||
|
||||
function searchHandler(event) {
|
||||
var options = autocomplete.options;
|
||||
|
||||
if (options.isComposing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var term = autocomplete.extractLastTerm(event.target.value);
|
||||
|
||||
if (term.length > 0 && options.firstCharacterBlacklist.indexOf(term[0]) !== -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return term.length >= options.minLength;
|
||||
}
|
||||
|
||||
function sourceData(request, response) {
|
||||
var elementId = this.element.attr('id');
|
||||
|
||||
if (!(elementId in autocomplete.cache)) {
|
||||
autocomplete.cache[elementId] = {};
|
||||
}
|
||||
|
||||
function showSuggestions(suggestions) {
|
||||
var tagged = autocomplete.splitValues(request.term);
|
||||
var il = tagged.length;
|
||||
for (var i = 0; i < il; i++) {
|
||||
var index = suggestions.indexOf(tagged[i]);
|
||||
if (index >= 0) {
|
||||
suggestions.splice(index, 1);
|
||||
}
|
||||
}
|
||||
response(suggestions);
|
||||
}
|
||||
|
||||
var term = autocomplete.extractLastTerm(request.term);
|
||||
|
||||
function sourceCallbackHandler(data) {
|
||||
autocomplete.cache[elementId][term] = data;
|
||||
|
||||
showSuggestions(data);
|
||||
}
|
||||
|
||||
if (autocomplete.cache[elementId].hasOwnProperty(term)) {
|
||||
showSuggestions(autocomplete.cache[elementId][term]);
|
||||
} else {
|
||||
var options = $.extend({ success: sourceCallbackHandler, data: { q: term } }, autocomplete.ajax);
|
||||
$.ajax(this.element.attr('data-autocomplete-path'), options);
|
||||
}
|
||||
}
|
||||
|
||||
function focusHandler() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function selectHandler(event, ui) {
|
||||
var terms = autocomplete.splitValues(event.target.value);
|
||||
|
||||
terms.pop();
|
||||
|
||||
terms.push(ui.item.value);
|
||||
|
||||
event.target.value = terms.join(', ');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function renderItem(ul, item) {
|
||||
return $('<li>').append($('<a>').html(item.label)).appendTo(ul);
|
||||
}
|
||||
|
||||
Drupal.behaviors.autocomplete = {
|
||||
attach: function attach(context) {
|
||||
var $autocomplete = $(context).find('input.form-autocomplete').once('autocomplete');
|
||||
if ($autocomplete.length) {
|
||||
var blacklist = $autocomplete.attr('data-autocomplete-first-character-blacklist');
|
||||
$.extend(autocomplete.options, {
|
||||
firstCharacterBlacklist: blacklist || ''
|
||||
});
|
||||
|
||||
$autocomplete.autocomplete(autocomplete.options).each(function () {
|
||||
$(this).data('ui-autocomplete')._renderItem = autocomplete.options.renderItem;
|
||||
});
|
||||
|
||||
$autocomplete.on('compositionstart.autocomplete', function () {
|
||||
autocomplete.options.isComposing = true;
|
||||
});
|
||||
$autocomplete.on('compositionend.autocomplete', function () {
|
||||
autocomplete.options.isComposing = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
detach: function detach(context, settings, trigger) {
|
||||
if (trigger === 'unload') {
|
||||
$(context).find('input.form-autocomplete').removeOnce('autocomplete').autocomplete('destroy');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
autocomplete = {
|
||||
cache: {},
|
||||
|
||||
splitValues: autocompleteSplitValues,
|
||||
extractLastTerm: extractLastTerm,
|
||||
|
||||
options: {
|
||||
source: sourceData,
|
||||
focus: focusHandler,
|
||||
search: searchHandler,
|
||||
select: selectHandler,
|
||||
renderItem: renderItem,
|
||||
minLength: 1,
|
||||
|
||||
firstCharacterBlacklist: '',
|
||||
|
||||
isComposing: false
|
||||
},
|
||||
ajax: {
|
||||
dataType: 'json'
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.autocomplete = autocomplete;
|
||||
})(jQuery, Drupal);
|
47
2017/web/core/misc/batch.es6.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* @file
|
||||
* Drupal's batch API.
|
||||
*/
|
||||
|
||||
(function($, Drupal) {
|
||||
/**
|
||||
* Attaches the batch behavior to progress bars.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.batch = {
|
||||
attach(context, settings) {
|
||||
const batch = settings.batch;
|
||||
const $progress = $('[data-drupal-progress]').once('batch');
|
||||
let progressBar;
|
||||
|
||||
// Success: redirect to the summary.
|
||||
function updateCallback(progress, status, pb) {
|
||||
if (progress === '100') {
|
||||
pb.stopMonitoring();
|
||||
window.location = `${batch.uri}&op=finished`;
|
||||
}
|
||||
}
|
||||
|
||||
function errorCallback(pb) {
|
||||
$progress.prepend($('<p class="error"></p>').html(batch.errorMessage));
|
||||
$('#wait').hide();
|
||||
}
|
||||
|
||||
if ($progress.length) {
|
||||
progressBar = new Drupal.ProgressBar(
|
||||
'updateprogress',
|
||||
updateCallback,
|
||||
'POST',
|
||||
errorCallback,
|
||||
);
|
||||
progressBar.setProgress(-1, batch.initMessage);
|
||||
progressBar.startMonitoring(`${batch.uri}&op=do`, 10);
|
||||
// Remove HTML from no-js progress bar.
|
||||
$progress.empty();
|
||||
// Append the JS progressbar element.
|
||||
$progress.append(progressBar.element);
|
||||
}
|
||||
},
|
||||
};
|
||||
})(jQuery, Drupal);
|
38
2017/web/core/misc/batch.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal) {
|
||||
Drupal.behaviors.batch = {
|
||||
attach: function attach(context, settings) {
|
||||
var batch = settings.batch;
|
||||
var $progress = $('[data-drupal-progress]').once('batch');
|
||||
var progressBar = void 0;
|
||||
|
||||
function updateCallback(progress, status, pb) {
|
||||
if (progress === '100') {
|
||||
pb.stopMonitoring();
|
||||
window.location = batch.uri + '&op=finished';
|
||||
}
|
||||
}
|
||||
|
||||
function errorCallback(pb) {
|
||||
$progress.prepend($('<p class="error"></p>').html(batch.errorMessage));
|
||||
$('#wait').hide();
|
||||
}
|
||||
|
||||
if ($progress.length) {
|
||||
progressBar = new Drupal.ProgressBar('updateprogress', updateCallback, 'POST', errorCallback);
|
||||
progressBar.setProgress(-1, batch.initMessage);
|
||||
progressBar.startMonitoring(batch.uri + '&op=do', 10);
|
||||
|
||||
$progress.empty();
|
||||
|
||||
$progress.append(progressBar.element);
|
||||
}
|
||||
}
|
||||
};
|
||||
})(jQuery, Drupal);
|
184
2017/web/core/misc/collapse.es6.js
Normal file
|
@ -0,0 +1,184 @@
|
|||
/**
|
||||
* @file
|
||||
* Polyfill for HTML5 details elements.
|
||||
*/
|
||||
|
||||
(function($, Modernizr, Drupal) {
|
||||
/**
|
||||
* The collapsible details object represents a single details element.
|
||||
*
|
||||
* @constructor Drupal.CollapsibleDetails
|
||||
*
|
||||
* @param {HTMLElement} node
|
||||
* The details element.
|
||||
*/
|
||||
function CollapsibleDetails(node) {
|
||||
this.$node = $(node);
|
||||
this.$node.data('details', this);
|
||||
// Expand details if there are errors inside, or if it contains an
|
||||
// element that is targeted by the URI fragment identifier.
|
||||
const anchor =
|
||||
window.location.hash && window.location.hash !== '#'
|
||||
? `, ${window.location.hash}`
|
||||
: '';
|
||||
if (this.$node.find(`.error${anchor}`).length) {
|
||||
this.$node.attr('open', true);
|
||||
}
|
||||
// Initialize and setup the summary,
|
||||
this.setupSummary();
|
||||
// Initialize and setup the legend.
|
||||
this.setupLegend();
|
||||
}
|
||||
|
||||
$.extend(
|
||||
CollapsibleDetails,
|
||||
/** @lends Drupal.CollapsibleDetails */ {
|
||||
/**
|
||||
* Holds references to instantiated CollapsibleDetails objects.
|
||||
*
|
||||
* @type {Array.<Drupal.CollapsibleDetails>}
|
||||
*/
|
||||
instances: [],
|
||||
},
|
||||
);
|
||||
|
||||
$.extend(
|
||||
CollapsibleDetails.prototype,
|
||||
/** @lends Drupal.CollapsibleDetails# */ {
|
||||
/**
|
||||
* Initialize and setup summary events and markup.
|
||||
*
|
||||
* @fires event:summaryUpdated
|
||||
*
|
||||
* @listens event:summaryUpdated
|
||||
*/
|
||||
setupSummary() {
|
||||
this.$summary = $('<span class="summary"></span>');
|
||||
this.$node
|
||||
.on('summaryUpdated', $.proxy(this.onSummaryUpdated, this))
|
||||
.trigger('summaryUpdated');
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize and setup legend markup.
|
||||
*/
|
||||
setupLegend() {
|
||||
// Turn the summary into a clickable link.
|
||||
const $legend = this.$node.find('> summary');
|
||||
|
||||
$('<span class="details-summary-prefix visually-hidden"></span>')
|
||||
.append(this.$node.attr('open') ? Drupal.t('Hide') : Drupal.t('Show'))
|
||||
.prependTo($legend)
|
||||
.after(document.createTextNode(' '));
|
||||
|
||||
// .wrapInner() does not retain bound events.
|
||||
$('<a class="details-title"></a>')
|
||||
.attr('href', `#${this.$node.attr('id')}`)
|
||||
.prepend($legend.contents())
|
||||
.appendTo($legend);
|
||||
|
||||
$legend
|
||||
.append(this.$summary)
|
||||
.on('click', $.proxy(this.onLegendClick, this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle legend clicks.
|
||||
*
|
||||
* @param {jQuery.Event} e
|
||||
* The event triggered.
|
||||
*/
|
||||
onLegendClick(e) {
|
||||
this.toggle();
|
||||
e.preventDefault();
|
||||
},
|
||||
|
||||
/**
|
||||
* Update summary.
|
||||
*/
|
||||
onSummaryUpdated() {
|
||||
const text = $.trim(this.$node.drupalGetSummary());
|
||||
this.$summary.html(text ? ` (${text})` : '');
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle the visibility of a details element using smooth animations.
|
||||
*/
|
||||
toggle() {
|
||||
const isOpen = !!this.$node.attr('open');
|
||||
const $summaryPrefix = this.$node.find(
|
||||
'> summary span.details-summary-prefix',
|
||||
);
|
||||
if (isOpen) {
|
||||
$summaryPrefix.html(Drupal.t('Show'));
|
||||
} else {
|
||||
$summaryPrefix.html(Drupal.t('Hide'));
|
||||
}
|
||||
// Delay setting the attribute to emulate chrome behavior and make
|
||||
// details-aria.js work as expected with this polyfill.
|
||||
setTimeout(() => {
|
||||
this.$node.attr('open', !isOpen);
|
||||
}, 0);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Polyfill HTML5 details element.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches behavior for the details element.
|
||||
*/
|
||||
Drupal.behaviors.collapse = {
|
||||
attach(context) {
|
||||
if (Modernizr.details) {
|
||||
return;
|
||||
}
|
||||
const $collapsibleDetails = $(context)
|
||||
.find('details')
|
||||
.once('collapse')
|
||||
.addClass('collapse-processed');
|
||||
if ($collapsibleDetails.length) {
|
||||
for (let i = 0; i < $collapsibleDetails.length; i++) {
|
||||
CollapsibleDetails.instances.push(
|
||||
new CollapsibleDetails($collapsibleDetails[i]),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Open parent details elements of a targeted page fragment.
|
||||
*
|
||||
* Opens all (nested) details element on a hash change or fragment link click
|
||||
* when the target is a child element, in order to make sure the targeted
|
||||
* element is visible. Aria attributes on the summary
|
||||
* are set by triggering the click event listener in details-aria.js.
|
||||
*
|
||||
* @param {jQuery.Event} e
|
||||
* The event triggered.
|
||||
* @param {jQuery} $target
|
||||
* The targeted node as a jQuery object.
|
||||
*/
|
||||
const handleFragmentLinkClickOrHashChange = (e, $target) => {
|
||||
$target
|
||||
.parents('details')
|
||||
.not('[open]')
|
||||
.find('> summary')
|
||||
.trigger('click');
|
||||
};
|
||||
|
||||
/**
|
||||
* Binds a listener to handle fragment link clicks and URL hash changes.
|
||||
*/
|
||||
$('body').on(
|
||||
'formFragmentLinkClickOrHashChange.details',
|
||||
handleFragmentLinkClickOrHashChange,
|
||||
);
|
||||
|
||||
// Expose constructor in the public space.
|
||||
Drupal.CollapsibleDetails = CollapsibleDetails;
|
||||
})(jQuery, Modernizr, Drupal);
|
87
2017/web/core/misc/collapse.js
Normal file
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Modernizr, Drupal) {
|
||||
function CollapsibleDetails(node) {
|
||||
this.$node = $(node);
|
||||
this.$node.data('details', this);
|
||||
|
||||
var anchor = window.location.hash && window.location.hash !== '#' ? ', ' + window.location.hash : '';
|
||||
if (this.$node.find('.error' + anchor).length) {
|
||||
this.$node.attr('open', true);
|
||||
}
|
||||
|
||||
this.setupSummary();
|
||||
|
||||
this.setupLegend();
|
||||
}
|
||||
|
||||
$.extend(CollapsibleDetails, {
|
||||
instances: []
|
||||
});
|
||||
|
||||
$.extend(CollapsibleDetails.prototype, {
|
||||
setupSummary: function setupSummary() {
|
||||
this.$summary = $('<span class="summary"></span>');
|
||||
this.$node.on('summaryUpdated', $.proxy(this.onSummaryUpdated, this)).trigger('summaryUpdated');
|
||||
},
|
||||
setupLegend: function setupLegend() {
|
||||
var $legend = this.$node.find('> summary');
|
||||
|
||||
$('<span class="details-summary-prefix visually-hidden"></span>').append(this.$node.attr('open') ? Drupal.t('Hide') : Drupal.t('Show')).prependTo($legend).after(document.createTextNode(' '));
|
||||
|
||||
$('<a class="details-title"></a>').attr('href', '#' + this.$node.attr('id')).prepend($legend.contents()).appendTo($legend);
|
||||
|
||||
$legend.append(this.$summary).on('click', $.proxy(this.onLegendClick, this));
|
||||
},
|
||||
onLegendClick: function onLegendClick(e) {
|
||||
this.toggle();
|
||||
e.preventDefault();
|
||||
},
|
||||
onSummaryUpdated: function onSummaryUpdated() {
|
||||
var text = $.trim(this.$node.drupalGetSummary());
|
||||
this.$summary.html(text ? ' (' + text + ')' : '');
|
||||
},
|
||||
toggle: function toggle() {
|
||||
var _this = this;
|
||||
|
||||
var isOpen = !!this.$node.attr('open');
|
||||
var $summaryPrefix = this.$node.find('> summary span.details-summary-prefix');
|
||||
if (isOpen) {
|
||||
$summaryPrefix.html(Drupal.t('Show'));
|
||||
} else {
|
||||
$summaryPrefix.html(Drupal.t('Hide'));
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
_this.$node.attr('open', !isOpen);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
Drupal.behaviors.collapse = {
|
||||
attach: function attach(context) {
|
||||
if (Modernizr.details) {
|
||||
return;
|
||||
}
|
||||
var $collapsibleDetails = $(context).find('details').once('collapse').addClass('collapse-processed');
|
||||
if ($collapsibleDetails.length) {
|
||||
for (var i = 0; i < $collapsibleDetails.length; i++) {
|
||||
CollapsibleDetails.instances.push(new CollapsibleDetails($collapsibleDetails[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var handleFragmentLinkClickOrHashChange = function handleFragmentLinkClickOrHashChange(e, $target) {
|
||||
$target.parents('details').not('[open]').find('> summary').trigger('click');
|
||||
};
|
||||
|
||||
$('body').on('formFragmentLinkClickOrHashChange.details', handleFragmentLinkClickOrHashChange);
|
||||
|
||||
Drupal.CollapsibleDetails = CollapsibleDetails;
|
||||
})(jQuery, Modernizr, Drupal);
|
58
2017/web/core/misc/date.es6.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* @file
|
||||
* Polyfill for HTML5 date input.
|
||||
*/
|
||||
|
||||
(function($, Modernizr, Drupal) {
|
||||
/**
|
||||
* Attach datepicker fallback on date elements.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior. Accepts in `settings.date` an object listing
|
||||
* elements to process, keyed by the HTML ID of the form element containing
|
||||
* the human-readable value. Each element is an datepicker settings object.
|
||||
* @prop {Drupal~behaviorDetach} detach
|
||||
* Detach the behavior destroying datepickers on effected elements.
|
||||
*/
|
||||
Drupal.behaviors.date = {
|
||||
attach(context, settings) {
|
||||
const $context = $(context);
|
||||
// Skip if date are supported by the browser.
|
||||
if (Modernizr.inputtypes.date === true) {
|
||||
return;
|
||||
}
|
||||
$context
|
||||
.find('input[data-drupal-date-format]')
|
||||
.once('datePicker')
|
||||
.each(function() {
|
||||
const $input = $(this);
|
||||
const datepickerSettings = {};
|
||||
const dateFormat = $input.data('drupalDateFormat');
|
||||
// The date format is saved in PHP style, we need to convert to jQuery
|
||||
// datepicker.
|
||||
datepickerSettings.dateFormat = dateFormat
|
||||
.replace('Y', 'yy')
|
||||
.replace('m', 'mm')
|
||||
.replace('d', 'dd');
|
||||
// Add min and max date if set on the input.
|
||||
if ($input.attr('min')) {
|
||||
datepickerSettings.minDate = $input.attr('min');
|
||||
}
|
||||
if ($input.attr('max')) {
|
||||
datepickerSettings.maxDate = $input.attr('max');
|
||||
}
|
||||
$input.datepicker(datepickerSettings);
|
||||
});
|
||||
},
|
||||
detach(context, settings, trigger) {
|
||||
if (trigger === 'unload') {
|
||||
$(context)
|
||||
.find('input[data-drupal-date-format]')
|
||||
.findOnce('datePicker')
|
||||
.datepicker('destroy');
|
||||
}
|
||||
},
|
||||
};
|
||||
})(jQuery, Modernizr, Drupal);
|
38
2017/web/core/misc/date.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Modernizr, Drupal) {
|
||||
Drupal.behaviors.date = {
|
||||
attach: function attach(context, settings) {
|
||||
var $context = $(context);
|
||||
|
||||
if (Modernizr.inputtypes.date === true) {
|
||||
return;
|
||||
}
|
||||
$context.find('input[data-drupal-date-format]').once('datePicker').each(function () {
|
||||
var $input = $(this);
|
||||
var datepickerSettings = {};
|
||||
var dateFormat = $input.data('drupalDateFormat');
|
||||
|
||||
datepickerSettings.dateFormat = dateFormat.replace('Y', 'yy').replace('m', 'mm').replace('d', 'dd');
|
||||
|
||||
if ($input.attr('min')) {
|
||||
datepickerSettings.minDate = $input.attr('min');
|
||||
}
|
||||
if ($input.attr('max')) {
|
||||
datepickerSettings.maxDate = $input.attr('max');
|
||||
}
|
||||
$input.datepicker(datepickerSettings);
|
||||
});
|
||||
},
|
||||
detach: function detach(context, settings, trigger) {
|
||||
if (trigger === 'unload') {
|
||||
$(context).find('input[data-drupal-date-format]').findOnce('datePicker').datepicker('destroy');
|
||||
}
|
||||
}
|
||||
};
|
||||
})(jQuery, Modernizr, Drupal);
|
48
2017/web/core/misc/debounce.es6.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* @file
|
||||
* Adapted from underscore.js with the addition Drupal namespace.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Limits the invocations of a function in a given time frame.
|
||||
*
|
||||
* The debounce function wrapper should be used sparingly. One clear use case
|
||||
* is limiting the invocation of a callback attached to the window resize event.
|
||||
*
|
||||
* Before using the debounce function wrapper, consider first whether the
|
||||
* callback could be attached to an event that fires less frequently or if the
|
||||
* function can be written in such a way that it is only invoked under specific
|
||||
* conditions.
|
||||
*
|
||||
* @param {function} func
|
||||
* The function to be invoked.
|
||||
* @param {number} wait
|
||||
* The time period within which the callback function should only be
|
||||
* invoked once. For example if the wait period is 250ms, then the callback
|
||||
* will only be called at most 4 times per second.
|
||||
* @param {bool} immediate
|
||||
* Whether we wait at the beginning or end to execute the function.
|
||||
*
|
||||
* @return {function}
|
||||
* The debounced function.
|
||||
*/
|
||||
Drupal.debounce = function(func, wait, immediate) {
|
||||
let timeout;
|
||||
let result;
|
||||
return function(...args) {
|
||||
const context = this;
|
||||
const later = function() {
|
||||
timeout = null;
|
||||
if (!immediate) {
|
||||
result = func.apply(context, args);
|
||||
}
|
||||
};
|
||||
const callNow = immediate && !timeout;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) {
|
||||
result = func.apply(context, args);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
};
|
31
2017/web/core/misc/debounce.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
Drupal.debounce = function (func, wait, immediate) {
|
||||
var timeout = void 0;
|
||||
var result = void 0;
|
||||
return function () {
|
||||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
||||
args[_key] = arguments[_key];
|
||||
}
|
||||
|
||||
var context = this;
|
||||
var later = function later() {
|
||||
timeout = null;
|
||||
if (!immediate) {
|
||||
result = func.apply(context, args);
|
||||
}
|
||||
};
|
||||
var callNow = immediate && !timeout;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) {
|
||||
result = func.apply(context, args);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
};
|
30
2017/web/core/misc/details-aria.es6.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* @file
|
||||
* Add aria attribute handling for details and summary elements.
|
||||
*/
|
||||
|
||||
(function($, Drupal) {
|
||||
/**
|
||||
* Handles `aria-expanded` and `aria-pressed` attributes on details elements.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.detailsAria = {
|
||||
attach() {
|
||||
$('body')
|
||||
.once('detailsAria')
|
||||
.on('click.detailsAria', 'summary', event => {
|
||||
const $summary = $(event.currentTarget);
|
||||
const open =
|
||||
$(event.currentTarget.parentNode).attr('open') === 'open'
|
||||
? 'false'
|
||||
: 'true';
|
||||
|
||||
$summary.attr({
|
||||
'aria-expanded': open,
|
||||
'aria-pressed': open,
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
})(jQuery, Drupal);
|
22
2017/web/core/misc/details-aria.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal) {
|
||||
Drupal.behaviors.detailsAria = {
|
||||
attach: function attach() {
|
||||
$('body').once('detailsAria').on('click.detailsAria', 'summary', function (event) {
|
||||
var $summary = $(event.currentTarget);
|
||||
var open = $(event.currentTarget.parentNode).attr('open') === 'open' ? 'false' : 'true';
|
||||
|
||||
$summary.attr({
|
||||
'aria-expanded': open,
|
||||
'aria-pressed': open
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
})(jQuery, Drupal);
|
258
2017/web/core/misc/dialog/dialog.ajax.es6.js
Normal file
|
@ -0,0 +1,258 @@
|
|||
/**
|
||||
* @file
|
||||
* Extends the Drupal AJAX functionality to integrate the dialog API.
|
||||
*/
|
||||
|
||||
(function($, Drupal) {
|
||||
/**
|
||||
* Initialize dialogs for Ajax purposes.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behaviors for dialog ajax functionality.
|
||||
*/
|
||||
Drupal.behaviors.dialog = {
|
||||
attach(context, settings) {
|
||||
const $context = $(context);
|
||||
|
||||
// Provide a known 'drupal-modal' DOM element for Drupal-based modal
|
||||
// dialogs. Non-modal dialogs are responsible for creating their own
|
||||
// elements, since there can be multiple non-modal dialogs at a time.
|
||||
if (!$('#drupal-modal').length) {
|
||||
// Add 'ui-front' jQuery UI class so jQuery UI widgets like autocomplete
|
||||
// sit on top of dialogs. For more information see
|
||||
// http://api.jqueryui.com/theming/stacking-elements/.
|
||||
$('<div id="drupal-modal" class="ui-front"/>')
|
||||
.hide()
|
||||
.appendTo('body');
|
||||
}
|
||||
|
||||
// Special behaviors specific when attaching content within a dialog.
|
||||
// These behaviors usually fire after a validation error inside a dialog.
|
||||
const $dialog = $context.closest('.ui-dialog-content');
|
||||
if ($dialog.length) {
|
||||
// Remove and replace the dialog buttons with those from the new form.
|
||||
if ($dialog.dialog('option', 'drupalAutoButtons')) {
|
||||
// Trigger an event to detect/sync changes to buttons.
|
||||
$dialog.trigger('dialogButtonsChange');
|
||||
}
|
||||
|
||||
// Force focus on the modal when the behavior is run.
|
||||
$dialog.dialog('widget').trigger('focus');
|
||||
}
|
||||
|
||||
const originalClose = settings.dialog.close;
|
||||
// Overwrite the close method to remove the dialog on closing.
|
||||
settings.dialog.close = function(event, ...args) {
|
||||
originalClose.apply(settings.dialog, [event, ...args]);
|
||||
$(event.target).remove();
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Scan a dialog for any primary buttons and move them to the button area.
|
||||
*
|
||||
* @param {jQuery} $dialog
|
||||
* An jQuery object containing the element that is the dialog target.
|
||||
*
|
||||
* @return {Array}
|
||||
* An array of buttons that need to be added to the button area.
|
||||
*/
|
||||
prepareDialogButtons($dialog) {
|
||||
const buttons = [];
|
||||
const $buttons = $dialog.find(
|
||||
'.form-actions input[type=submit], .form-actions a.button',
|
||||
);
|
||||
$buttons.each(function() {
|
||||
// Hidden form buttons need special attention. For browser consistency,
|
||||
// the button needs to be "visible" in order to have the enter key fire
|
||||
// the form submit event. So instead of a simple "hide" or
|
||||
// "display: none", we set its dimensions to zero.
|
||||
// See http://mattsnider.com/how-forms-submit-when-pressing-enter/
|
||||
const $originalButton = $(this).css({
|
||||
display: 'block',
|
||||
width: 0,
|
||||
height: 0,
|
||||
padding: 0,
|
||||
border: 0,
|
||||
overflow: 'hidden',
|
||||
});
|
||||
buttons.push({
|
||||
text: $originalButton.html() || $originalButton.attr('value'),
|
||||
class: $originalButton.attr('class'),
|
||||
click(e) {
|
||||
// If the original button is an anchor tag, triggering the "click"
|
||||
// event will not simulate a click. Use the click method instead.
|
||||
if ($originalButton.is('a')) {
|
||||
$originalButton[0].click();
|
||||
} else {
|
||||
$originalButton
|
||||
.trigger('mousedown')
|
||||
.trigger('mouseup')
|
||||
.trigger('click');
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
return buttons;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Command to open a dialog.
|
||||
*
|
||||
* @param {Drupal.Ajax} ajax
|
||||
* The Drupal Ajax object.
|
||||
* @param {object} response
|
||||
* Object holding the server response.
|
||||
* @param {number} [status]
|
||||
* The HTTP status code.
|
||||
*
|
||||
* @return {bool|undefined}
|
||||
* Returns false if there was no selector property in the response object.
|
||||
*/
|
||||
Drupal.AjaxCommands.prototype.openDialog = function(ajax, response, status) {
|
||||
if (!response.selector) {
|
||||
return false;
|
||||
}
|
||||
let $dialog = $(response.selector);
|
||||
if (!$dialog.length) {
|
||||
// Create the element if needed.
|
||||
$dialog = $(
|
||||
`<div id="${response.selector.replace(/^#/, '')}" class="ui-front"/>`,
|
||||
).appendTo('body');
|
||||
}
|
||||
// Set up the wrapper, if there isn't one.
|
||||
if (!ajax.wrapper) {
|
||||
ajax.wrapper = $dialog.attr('id');
|
||||
}
|
||||
|
||||
// Use the ajax.js insert command to populate the dialog contents.
|
||||
response.command = 'insert';
|
||||
response.method = 'html';
|
||||
ajax.commands.insert(ajax, response, status);
|
||||
|
||||
// Move the buttons to the jQuery UI dialog buttons area.
|
||||
if (!response.dialogOptions.buttons) {
|
||||
response.dialogOptions.drupalAutoButtons = true;
|
||||
response.dialogOptions.buttons = Drupal.behaviors.dialog.prepareDialogButtons(
|
||||
$dialog,
|
||||
);
|
||||
}
|
||||
|
||||
// Bind dialogButtonsChange.
|
||||
$dialog.on('dialogButtonsChange', () => {
|
||||
const buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
|
||||
$dialog.dialog('option', 'buttons', buttons);
|
||||
});
|
||||
|
||||
// Open the dialog itself.
|
||||
response.dialogOptions = response.dialogOptions || {};
|
||||
const dialog = Drupal.dialog($dialog.get(0), response.dialogOptions);
|
||||
if (response.dialogOptions.modal) {
|
||||
dialog.showModal();
|
||||
} else {
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
// Add the standard Drupal class for buttons for style consistency.
|
||||
$dialog
|
||||
.parent()
|
||||
.find('.ui-dialog-buttonset')
|
||||
.addClass('form-actions');
|
||||
};
|
||||
|
||||
/**
|
||||
* Command to close a dialog.
|
||||
*
|
||||
* If no selector is given, it defaults to trying to close the modal.
|
||||
*
|
||||
* @param {Drupal.Ajax} [ajax]
|
||||
* The ajax object.
|
||||
* @param {object} response
|
||||
* Object holding the server response.
|
||||
* @param {string} response.selector
|
||||
* The selector of the dialog.
|
||||
* @param {bool} response.persist
|
||||
* Whether to persist the dialog element or not.
|
||||
* @param {number} [status]
|
||||
* The HTTP status code.
|
||||
*/
|
||||
Drupal.AjaxCommands.prototype.closeDialog = function(ajax, response, status) {
|
||||
const $dialog = $(response.selector);
|
||||
if ($dialog.length) {
|
||||
Drupal.dialog($dialog.get(0)).close();
|
||||
if (!response.persist) {
|
||||
$dialog.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Unbind dialogButtonsChange.
|
||||
$dialog.off('dialogButtonsChange');
|
||||
};
|
||||
|
||||
/**
|
||||
* Command to set a dialog property.
|
||||
*
|
||||
* JQuery UI specific way of setting dialog options.
|
||||
*
|
||||
* @param {Drupal.Ajax} [ajax]
|
||||
* The Drupal Ajax object.
|
||||
* @param {object} response
|
||||
* Object holding the server response.
|
||||
* @param {string} response.selector
|
||||
* Selector for the dialog element.
|
||||
* @param {string} response.optionsName
|
||||
* Name of a key to set.
|
||||
* @param {string} response.optionValue
|
||||
* Value to set.
|
||||
* @param {number} [status]
|
||||
* The HTTP status code.
|
||||
*/
|
||||
Drupal.AjaxCommands.prototype.setDialogOption = function(
|
||||
ajax,
|
||||
response,
|
||||
status,
|
||||
) {
|
||||
const $dialog = $(response.selector);
|
||||
if ($dialog.length) {
|
||||
$dialog.dialog('option', response.optionName, response.optionValue);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Binds a listener on dialog creation to handle the cancel link.
|
||||
*
|
||||
* @param {jQuery.Event} e
|
||||
* The event triggered.
|
||||
* @param {Drupal.dialog~dialogDefinition} dialog
|
||||
* The dialog instance.
|
||||
* @param {jQuery} $element
|
||||
* The jQuery collection of the dialog element.
|
||||
* @param {object} [settings]
|
||||
* Dialog settings.
|
||||
*/
|
||||
$(window).on('dialog:aftercreate', (e, dialog, $element, settings) => {
|
||||
$element.on('click.dialog', '.dialog-cancel', e => {
|
||||
dialog.close('cancel');
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Removes all 'dialog' listeners.
|
||||
*
|
||||
* @param {jQuery.Event} e
|
||||
* The event triggered.
|
||||
* @param {Drupal.dialog~dialogDefinition} dialog
|
||||
* The dialog instance.
|
||||
* @param {jQuery} $element
|
||||
* jQuery collection of the dialog element.
|
||||
*/
|
||||
$(window).on('dialog:beforeclose', (e, dialog, $element) => {
|
||||
$element.off('.dialog');
|
||||
});
|
||||
})(jQuery, Drupal);
|
134
2017/web/core/misc/dialog/dialog.ajax.js
Normal file
|
@ -0,0 +1,134 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal) {
|
||||
Drupal.behaviors.dialog = {
|
||||
attach: function attach(context, settings) {
|
||||
var $context = $(context);
|
||||
|
||||
if (!$('#drupal-modal').length) {
|
||||
$('<div id="drupal-modal" class="ui-front"/>').hide().appendTo('body');
|
||||
}
|
||||
|
||||
var $dialog = $context.closest('.ui-dialog-content');
|
||||
if ($dialog.length) {
|
||||
if ($dialog.dialog('option', 'drupalAutoButtons')) {
|
||||
$dialog.trigger('dialogButtonsChange');
|
||||
}
|
||||
|
||||
$dialog.dialog('widget').trigger('focus');
|
||||
}
|
||||
|
||||
var originalClose = settings.dialog.close;
|
||||
|
||||
settings.dialog.close = function (event) {
|
||||
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
args[_key - 1] = arguments[_key];
|
||||
}
|
||||
|
||||
originalClose.apply(settings.dialog, [event].concat(args));
|
||||
$(event.target).remove();
|
||||
};
|
||||
},
|
||||
prepareDialogButtons: function prepareDialogButtons($dialog) {
|
||||
var buttons = [];
|
||||
var $buttons = $dialog.find('.form-actions input[type=submit], .form-actions a.button');
|
||||
$buttons.each(function () {
|
||||
var $originalButton = $(this).css({
|
||||
display: 'block',
|
||||
width: 0,
|
||||
height: 0,
|
||||
padding: 0,
|
||||
border: 0,
|
||||
overflow: 'hidden'
|
||||
});
|
||||
buttons.push({
|
||||
text: $originalButton.html() || $originalButton.attr('value'),
|
||||
class: $originalButton.attr('class'),
|
||||
click: function click(e) {
|
||||
if ($originalButton.is('a')) {
|
||||
$originalButton[0].click();
|
||||
} else {
|
||||
$originalButton.trigger('mousedown').trigger('mouseup').trigger('click');
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return buttons;
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.AjaxCommands.prototype.openDialog = function (ajax, response, status) {
|
||||
if (!response.selector) {
|
||||
return false;
|
||||
}
|
||||
var $dialog = $(response.selector);
|
||||
if (!$dialog.length) {
|
||||
$dialog = $('<div id="' + response.selector.replace(/^#/, '') + '" class="ui-front"/>').appendTo('body');
|
||||
}
|
||||
|
||||
if (!ajax.wrapper) {
|
||||
ajax.wrapper = $dialog.attr('id');
|
||||
}
|
||||
|
||||
response.command = 'insert';
|
||||
response.method = 'html';
|
||||
ajax.commands.insert(ajax, response, status);
|
||||
|
||||
if (!response.dialogOptions.buttons) {
|
||||
response.dialogOptions.drupalAutoButtons = true;
|
||||
response.dialogOptions.buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
|
||||
}
|
||||
|
||||
$dialog.on('dialogButtonsChange', function () {
|
||||
var buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
|
||||
$dialog.dialog('option', 'buttons', buttons);
|
||||
});
|
||||
|
||||
response.dialogOptions = response.dialogOptions || {};
|
||||
var dialog = Drupal.dialog($dialog.get(0), response.dialogOptions);
|
||||
if (response.dialogOptions.modal) {
|
||||
dialog.showModal();
|
||||
} else {
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
$dialog.parent().find('.ui-dialog-buttonset').addClass('form-actions');
|
||||
};
|
||||
|
||||
Drupal.AjaxCommands.prototype.closeDialog = function (ajax, response, status) {
|
||||
var $dialog = $(response.selector);
|
||||
if ($dialog.length) {
|
||||
Drupal.dialog($dialog.get(0)).close();
|
||||
if (!response.persist) {
|
||||
$dialog.remove();
|
||||
}
|
||||
}
|
||||
|
||||
$dialog.off('dialogButtonsChange');
|
||||
};
|
||||
|
||||
Drupal.AjaxCommands.prototype.setDialogOption = function (ajax, response, status) {
|
||||
var $dialog = $(response.selector);
|
||||
if ($dialog.length) {
|
||||
$dialog.dialog('option', response.optionName, response.optionValue);
|
||||
}
|
||||
};
|
||||
|
||||
$(window).on('dialog:aftercreate', function (e, dialog, $element, settings) {
|
||||
$element.on('click.dialog', '.dialog-cancel', function (e) {
|
||||
dialog.close('cancel');
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
});
|
||||
|
||||
$(window).on('dialog:beforeclose', function (e, dialog, $element) {
|
||||
$element.off('.dialog');
|
||||
});
|
||||
})(jQuery, Drupal);
|
97
2017/web/core/misc/dialog/dialog.es6.js
Normal file
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* @file
|
||||
* Dialog API inspired by HTML5 dialog element.
|
||||
*
|
||||
* @see http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#the-dialog-element
|
||||
*/
|
||||
|
||||
(function($, Drupal, drupalSettings) {
|
||||
/**
|
||||
* Default dialog options.
|
||||
*
|
||||
* @type {object}
|
||||
*
|
||||
* @prop {bool} [autoOpen=true]
|
||||
* @prop {string} [dialogClass='']
|
||||
* @prop {string} [buttonClass='button']
|
||||
* @prop {string} [buttonPrimaryClass='button--primary']
|
||||
* @prop {function} close
|
||||
*/
|
||||
drupalSettings.dialog = {
|
||||
autoOpen: true,
|
||||
dialogClass: '',
|
||||
// Drupal-specific extensions: see dialog.jquery-ui.js.
|
||||
buttonClass: 'button',
|
||||
buttonPrimaryClass: 'button--primary',
|
||||
// When using this API directly (when generating dialogs on the client
|
||||
// side), you may want to override this method and do
|
||||
// `jQuery(event.target).remove()` as well, to remove the dialog on
|
||||
// closing.
|
||||
close(event) {
|
||||
Drupal.dialog(event.target).close();
|
||||
Drupal.detachBehaviors(event.target, null, 'unload');
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {object} Drupal.dialog~dialogDefinition
|
||||
*
|
||||
* @prop {boolean} open
|
||||
* Is the dialog open or not.
|
||||
* @prop {*} returnValue
|
||||
* Return value of the dialog.
|
||||
* @prop {function} show
|
||||
* Method to display the dialog on the page.
|
||||
* @prop {function} showModal
|
||||
* Method to display the dialog as a modal on the page.
|
||||
* @prop {function} close
|
||||
* Method to hide the dialog from the page.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Polyfill HTML5 dialog element with jQueryUI.
|
||||
*
|
||||
* @param {HTMLElement} element
|
||||
* The element that holds the dialog.
|
||||
* @param {object} options
|
||||
* jQuery UI options to be passed to the dialog.
|
||||
*
|
||||
* @return {Drupal.dialog~dialogDefinition}
|
||||
* The dialog instance.
|
||||
*/
|
||||
Drupal.dialog = function(element, options) {
|
||||
let undef;
|
||||
const $element = $(element);
|
||||
const dialog = {
|
||||
open: false,
|
||||
returnValue: undef,
|
||||
};
|
||||
|
||||
function openDialog(settings) {
|
||||
settings = $.extend({}, drupalSettings.dialog, options, settings);
|
||||
// Trigger a global event to allow scripts to bind events to the dialog.
|
||||
$(window).trigger('dialog:beforecreate', [dialog, $element, settings]);
|
||||
$element.dialog(settings);
|
||||
dialog.open = true;
|
||||
$(window).trigger('dialog:aftercreate', [dialog, $element, settings]);
|
||||
}
|
||||
|
||||
function closeDialog(value) {
|
||||
$(window).trigger('dialog:beforeclose', [dialog, $element]);
|
||||
$element.dialog('close');
|
||||
dialog.returnValue = value;
|
||||
dialog.open = false;
|
||||
$(window).trigger('dialog:afterclose', [dialog, $element]);
|
||||
}
|
||||
|
||||
dialog.show = () => {
|
||||
openDialog({ modal: false });
|
||||
};
|
||||
dialog.showModal = () => {
|
||||
openDialog({ modal: true });
|
||||
};
|
||||
dialog.close = closeDialog;
|
||||
|
||||
return dialog;
|
||||
};
|
||||
})(jQuery, Drupal, drupalSettings);
|
34
2017/web/core/misc/dialog/dialog.jquery-ui.es6.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* @file
|
||||
* Adds default classes to buttons for styling purposes.
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
$.widget('ui.dialog', $.ui.dialog, {
|
||||
options: {
|
||||
buttonClass: 'button',
|
||||
buttonPrimaryClass: 'button--primary',
|
||||
},
|
||||
_createButtons() {
|
||||
const opts = this.options;
|
||||
let primaryIndex;
|
||||
let index;
|
||||
const il = opts.buttons.length;
|
||||
for (index = 0; index < il; index++) {
|
||||
if (
|
||||
opts.buttons[index].primary &&
|
||||
opts.buttons[index].primary === true
|
||||
) {
|
||||
primaryIndex = index;
|
||||
delete opts.buttons[index].primary;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this._super();
|
||||
const $buttons = this.uiButtonSet.children().addClass(opts.buttonClass);
|
||||
if (typeof primaryIndex !== 'undefined') {
|
||||
$buttons.eq(index).addClass(opts.buttonPrimaryClass);
|
||||
}
|
||||
},
|
||||
});
|
||||
})(jQuery);
|
33
2017/web/core/misc/dialog/dialog.jquery-ui.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($) {
|
||||
$.widget('ui.dialog', $.ui.dialog, {
|
||||
options: {
|
||||
buttonClass: 'button',
|
||||
buttonPrimaryClass: 'button--primary'
|
||||
},
|
||||
_createButtons: function _createButtons() {
|
||||
var opts = this.options;
|
||||
var primaryIndex = void 0;
|
||||
var index = void 0;
|
||||
var il = opts.buttons.length;
|
||||
for (index = 0; index < il; index++) {
|
||||
if (opts.buttons[index].primary && opts.buttons[index].primary === true) {
|
||||
primaryIndex = index;
|
||||
delete opts.buttons[index].primary;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this._super();
|
||||
var $buttons = this.uiButtonSet.children().addClass(opts.buttonClass);
|
||||
if (typeof primaryIndex !== 'undefined') {
|
||||
$buttons.eq(index).addClass(opts.buttonPrimaryClass);
|
||||
}
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
56
2017/web/core/misc/dialog/dialog.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
drupalSettings.dialog = {
|
||||
autoOpen: true,
|
||||
dialogClass: '',
|
||||
|
||||
buttonClass: 'button',
|
||||
buttonPrimaryClass: 'button--primary',
|
||||
close: function close(event) {
|
||||
Drupal.dialog(event.target).close();
|
||||
Drupal.detachBehaviors(event.target, null, 'unload');
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.dialog = function (element, options) {
|
||||
var undef = void 0;
|
||||
var $element = $(element);
|
||||
var dialog = {
|
||||
open: false,
|
||||
returnValue: undef
|
||||
};
|
||||
|
||||
function openDialog(settings) {
|
||||
settings = $.extend({}, drupalSettings.dialog, options, settings);
|
||||
|
||||
$(window).trigger('dialog:beforecreate', [dialog, $element, settings]);
|
||||
$element.dialog(settings);
|
||||
dialog.open = true;
|
||||
$(window).trigger('dialog:aftercreate', [dialog, $element, settings]);
|
||||
}
|
||||
|
||||
function closeDialog(value) {
|
||||
$(window).trigger('dialog:beforeclose', [dialog, $element]);
|
||||
$element.dialog('close');
|
||||
dialog.returnValue = value;
|
||||
dialog.open = false;
|
||||
$(window).trigger('dialog:afterclose', [dialog, $element]);
|
||||
}
|
||||
|
||||
dialog.show = function () {
|
||||
openDialog({ modal: false });
|
||||
};
|
||||
dialog.showModal = function () {
|
||||
openDialog({ modal: true });
|
||||
};
|
||||
dialog.close = closeDialog;
|
||||
|
||||
return dialog;
|
||||
};
|
||||
})(jQuery, Drupal, drupalSettings);
|
138
2017/web/core/misc/dialog/dialog.position.es6.js
Normal file
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* @file
|
||||
* Positioning extensions for dialogs.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Triggers when content inside a dialog changes.
|
||||
*
|
||||
* @event dialogContentResize
|
||||
*/
|
||||
|
||||
(function($, Drupal, drupalSettings, debounce, displace) {
|
||||
// autoResize option will turn off resizable and draggable.
|
||||
drupalSettings.dialog = $.extend(
|
||||
{ autoResize: true, maxHeight: '95%' },
|
||||
drupalSettings.dialog,
|
||||
);
|
||||
|
||||
/**
|
||||
* Position the dialog's center at the center of displace.offsets boundaries.
|
||||
*
|
||||
* @function Drupal.dialog~resetPosition
|
||||
*
|
||||
* @param {object} options
|
||||
* Options object.
|
||||
*
|
||||
* @return {object}
|
||||
* Altered options object.
|
||||
*/
|
||||
function resetPosition(options) {
|
||||
const offsets = displace.offsets;
|
||||
const left = offsets.left - offsets.right;
|
||||
const top = offsets.top - offsets.bottom;
|
||||
|
||||
const leftString = `${(left > 0 ? '+' : '-') +
|
||||
Math.abs(Math.round(left / 2))}px`;
|
||||
const topString = `${(top > 0 ? '+' : '-') +
|
||||
Math.abs(Math.round(top / 2))}px`;
|
||||
options.position = {
|
||||
my: `center${left !== 0 ? leftString : ''} center${
|
||||
top !== 0 ? topString : ''
|
||||
}`,
|
||||
of: window,
|
||||
};
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the current options for positioning.
|
||||
*
|
||||
* This is used as a window resize and scroll callback to reposition the
|
||||
* jQuery UI dialog. Although not a built-in jQuery UI option, this can
|
||||
* be disabled by setting autoResize: false in the options array when creating
|
||||
* a new {@link Drupal.dialog}.
|
||||
*
|
||||
* @function Drupal.dialog~resetSize
|
||||
*
|
||||
* @param {jQuery.Event} event
|
||||
* The event triggered.
|
||||
*
|
||||
* @fires event:dialogContentResize
|
||||
*/
|
||||
function resetSize(event) {
|
||||
const positionOptions = [
|
||||
'width',
|
||||
'height',
|
||||
'minWidth',
|
||||
'minHeight',
|
||||
'maxHeight',
|
||||
'maxWidth',
|
||||
'position',
|
||||
];
|
||||
let adjustedOptions = {};
|
||||
let windowHeight = $(window).height();
|
||||
let option;
|
||||
let optionValue;
|
||||
let adjustedValue;
|
||||
for (let n = 0; n < positionOptions.length; n++) {
|
||||
option = positionOptions[n];
|
||||
optionValue = event.data.settings[option];
|
||||
if (optionValue) {
|
||||
// jQuery UI does not support percentages on heights, convert to pixels.
|
||||
if (
|
||||
typeof optionValue === 'string' &&
|
||||
/%$/.test(optionValue) &&
|
||||
/height/i.test(option)
|
||||
) {
|
||||
// Take offsets in account.
|
||||
windowHeight -= displace.offsets.top + displace.offsets.bottom;
|
||||
adjustedValue = parseInt(
|
||||
0.01 * parseInt(optionValue, 10) * windowHeight,
|
||||
10,
|
||||
);
|
||||
// Don't force the dialog to be bigger vertically than needed.
|
||||
if (
|
||||
option === 'height' &&
|
||||
event.data.$element.parent().outerHeight() < adjustedValue
|
||||
) {
|
||||
adjustedValue = 'auto';
|
||||
}
|
||||
adjustedOptions[option] = adjustedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Offset the dialog center to be at the center of Drupal.displace.offsets.
|
||||
if (!event.data.settings.modal) {
|
||||
adjustedOptions = resetPosition(adjustedOptions);
|
||||
}
|
||||
event.data.$element
|
||||
.dialog('option', adjustedOptions)
|
||||
.trigger('dialogContentResize');
|
||||
}
|
||||
|
||||
$(window).on({
|
||||
'dialog:aftercreate': function(event, dialog, $element, settings) {
|
||||
const autoResize = debounce(resetSize, 20);
|
||||
const eventData = { settings, $element };
|
||||
if (settings.autoResize === true || settings.autoResize === 'true') {
|
||||
$element
|
||||
.dialog('option', { resizable: false, draggable: false })
|
||||
.dialog('widget')
|
||||
.css('position', 'fixed');
|
||||
$(window)
|
||||
.on('resize.dialogResize scroll.dialogResize', eventData, autoResize)
|
||||
.trigger('resize.dialogResize');
|
||||
$(document).on(
|
||||
'drupalViewportOffsetChange.dialogResize',
|
||||
eventData,
|
||||
autoResize,
|
||||
);
|
||||
}
|
||||
},
|
||||
'dialog:beforeclose': function(event, dialog, $element) {
|
||||
$(window).off('.dialogResize');
|
||||
$(document).off('.dialogResize');
|
||||
},
|
||||
});
|
||||
})(jQuery, Drupal, drupalSettings, Drupal.debounce, Drupal.displace);
|
69
2017/web/core/misc/dialog/dialog.position.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal, drupalSettings, debounce, displace) {
|
||||
drupalSettings.dialog = $.extend({ autoResize: true, maxHeight: '95%' }, drupalSettings.dialog);
|
||||
|
||||
function resetPosition(options) {
|
||||
var offsets = displace.offsets;
|
||||
var left = offsets.left - offsets.right;
|
||||
var top = offsets.top - offsets.bottom;
|
||||
|
||||
var leftString = (left > 0 ? '+' : '-') + Math.abs(Math.round(left / 2)) + 'px';
|
||||
var topString = (top > 0 ? '+' : '-') + Math.abs(Math.round(top / 2)) + 'px';
|
||||
options.position = {
|
||||
my: 'center' + (left !== 0 ? leftString : '') + ' center' + (top !== 0 ? topString : ''),
|
||||
of: window
|
||||
};
|
||||
return options;
|
||||
}
|
||||
|
||||
function resetSize(event) {
|
||||
var positionOptions = ['width', 'height', 'minWidth', 'minHeight', 'maxHeight', 'maxWidth', 'position'];
|
||||
var adjustedOptions = {};
|
||||
var windowHeight = $(window).height();
|
||||
var option = void 0;
|
||||
var optionValue = void 0;
|
||||
var adjustedValue = void 0;
|
||||
for (var n = 0; n < positionOptions.length; n++) {
|
||||
option = positionOptions[n];
|
||||
optionValue = event.data.settings[option];
|
||||
if (optionValue) {
|
||||
if (typeof optionValue === 'string' && /%$/.test(optionValue) && /height/i.test(option)) {
|
||||
windowHeight -= displace.offsets.top + displace.offsets.bottom;
|
||||
adjustedValue = parseInt(0.01 * parseInt(optionValue, 10) * windowHeight, 10);
|
||||
|
||||
if (option === 'height' && event.data.$element.parent().outerHeight() < adjustedValue) {
|
||||
adjustedValue = 'auto';
|
||||
}
|
||||
adjustedOptions[option] = adjustedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!event.data.settings.modal) {
|
||||
adjustedOptions = resetPosition(adjustedOptions);
|
||||
}
|
||||
event.data.$element.dialog('option', adjustedOptions).trigger('dialogContentResize');
|
||||
}
|
||||
|
||||
$(window).on({
|
||||
'dialog:aftercreate': function dialogAftercreate(event, dialog, $element, settings) {
|
||||
var autoResize = debounce(resetSize, 20);
|
||||
var eventData = { settings: settings, $element: $element };
|
||||
if (settings.autoResize === true || settings.autoResize === 'true') {
|
||||
$element.dialog('option', { resizable: false, draggable: false }).dialog('widget').css('position', 'fixed');
|
||||
$(window).on('resize.dialogResize scroll.dialogResize', eventData, autoResize).trigger('resize.dialogResize');
|
||||
$(document).on('drupalViewportOffsetChange.dialogResize', eventData, autoResize);
|
||||
}
|
||||
},
|
||||
'dialog:beforeclose': function dialogBeforeclose(event, dialog, $element) {
|
||||
$(window).off('.dialogResize');
|
||||
$(document).off('.dialogResize');
|
||||
}
|
||||
});
|
||||
})(jQuery, Drupal, drupalSettings, Drupal.debounce, Drupal.displace);
|
234
2017/web/core/misc/dialog/off-canvas.base.css
Normal file
|
@ -0,0 +1,234 @@
|
|||
/**
|
||||
* @file
|
||||
* Set base styles for the off-canvas dialog.
|
||||
*/
|
||||
|
||||
/* Set some global attributes. */
|
||||
#drupal-off-canvas *,
|
||||
#drupal-off-canvas *:not(div) {
|
||||
background: #444;
|
||||
font-family: "Lucida Grande", 'Lucida Sans Unicode', 'liberation sans', sans-serif;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
/* Generic elements. */
|
||||
#drupal-off-canvas a,
|
||||
#drupal-off-canvas .link {
|
||||
border-bottom: none;
|
||||
font-family: "Lucida Grande", 'Lucida Sans Unicode', 'liberation sans', sans-serif;
|
||||
font-size: inherit;
|
||||
font-weight: normal;
|
||||
color: #85bef4;
|
||||
text-decoration: none;
|
||||
transition: color 0.5s ease;
|
||||
}
|
||||
|
||||
#drupal-off-canvas a:focus,
|
||||
#drupal-off-canvas .link:focus,
|
||||
#drupal-off-canvas a:hover,
|
||||
#drupal-off-canvas .link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
#drupal-off-canvas hr {
|
||||
height: 1px;
|
||||
background: #ccc;
|
||||
}
|
||||
#drupal-off-canvas summary,
|
||||
#drupal-off-canvas .fieldgroup:not(.form-composite) > legend {
|
||||
font-weight: bold;
|
||||
}
|
||||
#drupal-off-canvas h1,
|
||||
#drupal-off-canvas .heading-a {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
font-size: 1.625em;
|
||||
line-height: 1.875em;
|
||||
}
|
||||
#drupal-off-canvas h2,
|
||||
#drupal-off-canvas .heading-b {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
font-size: 1.385em;
|
||||
}
|
||||
#drupal-off-canvas h3,
|
||||
#drupal-off-canvas .heading-c {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
font-size: 1.231em;
|
||||
}
|
||||
#drupal-off-canvas h4,
|
||||
#drupal-off-canvas .heading-d {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
font-size: 1.154em;
|
||||
}
|
||||
#drupal-off-canvas h5,
|
||||
#drupal-off-canvas .heading-e {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
font-size: 1.077em;
|
||||
}
|
||||
#drupal-off-canvas h6,
|
||||
#drupal-off-canvas .heading-f {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
font-size: 1.077em;
|
||||
}
|
||||
#drupal-off-canvas p {
|
||||
margin: 1em 0;
|
||||
}
|
||||
#drupal-off-canvas dl {
|
||||
margin: 0 0 20px;
|
||||
}
|
||||
#drupal-off-canvas dl dd,
|
||||
#drupal-off-canvas dl dl {
|
||||
margin-left: 20px; /* LTR */
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
[dir="rtl"] #drupal-off-canvas dl dd,
|
||||
[dir="rtl"] #drupal-off-canvas dl dl {
|
||||
margin-right: 20px;
|
||||
}
|
||||
#drupal-off-canvas blockquote {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
#drupal-off-canvas address {
|
||||
font-style: italic;
|
||||
}
|
||||
#drupal-off-canvas u,
|
||||
#drupal-off-canvas ins {
|
||||
text-decoration: underline;
|
||||
}
|
||||
#drupal-off-canvas s,
|
||||
#drupal-off-canvas strike,
|
||||
#drupal-off-canvas del {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
#drupal-off-canvas big {
|
||||
font-size: larger;
|
||||
}
|
||||
#drupal-off-canvas small {
|
||||
font-size: smaller;
|
||||
}
|
||||
#drupal-off-canvas sub {
|
||||
vertical-align: sub;
|
||||
font-size: smaller;
|
||||
line-height: normal;
|
||||
}
|
||||
#drupal-off-canvas sup {
|
||||
vertical-align: super;
|
||||
font-size: smaller;
|
||||
line-height: normal;
|
||||
}
|
||||
#drupal-off-canvas abbr,
|
||||
#drupal-off-canvas acronym {
|
||||
border-bottom: dotted 1px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#drupal-off-canvas ul {
|
||||
list-style-type: disc;
|
||||
list-style-image: none;
|
||||
}
|
||||
[dir="rtl"] #drupal-off-canvas .messages__list {
|
||||
margin-right: 0;
|
||||
}
|
||||
#drupal-off-canvas ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
#drupal-off-canvas ul li,
|
||||
#drupal-off-canvas ol li {
|
||||
display: block;
|
||||
}
|
||||
#drupal-off-canvas blockquote,
|
||||
#drupal-off-canvas code {
|
||||
margin: 20px 0;
|
||||
}
|
||||
#drupal-off-canvas pre {
|
||||
margin: 20px 0;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/* Classes for hidden and visually hidden elements. See hidden.module.css. */
|
||||
#drupal-off-canvas .hidden {
|
||||
display: none;
|
||||
}
|
||||
#drupal-off-canvas .visually-hidden {
|
||||
position: absolute !important;
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
overflow: hidden;
|
||||
height: 1px;
|
||||
width: 1px;
|
||||
word-wrap: normal;
|
||||
}
|
||||
#drupal-off-canvas .visually-hidden.focusable:active,
|
||||
#drupal-off-canvas .visually-hidden.focusable:focus {
|
||||
position: static !important;
|
||||
clip: auto;
|
||||
overflow: visible;
|
||||
height: auto;
|
||||
width: auto;
|
||||
}
|
||||
#drupal-off-canvas .invisible {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/* Some system classes. See system.admin.css. */
|
||||
#drupal-off-canvas .panel {
|
||||
padding: 5px 5px 15px;
|
||||
}
|
||||
#drupal-off-canvas .panel__description {
|
||||
margin: 0 0 3px;
|
||||
padding: 2px 0 3px 0;
|
||||
}
|
||||
#drupal-off-canvas .compact-link {
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
#drupal-off-canvas small .admin-link:before {
|
||||
content: ' [';
|
||||
}
|
||||
#drupal-off-canvas small .admin-link:after {
|
||||
content: ']';
|
||||
}
|
||||
|
||||
/* Override jQuery UI */
|
||||
#drupal-off-canvas .ui-widget-content a {
|
||||
color: #85bef4 !important;
|
||||
}
|
||||
|
||||
/* Message styles */
|
||||
#drupal-off-canvas .messages {
|
||||
background: no-repeat 10px 17px;
|
||||
}
|
||||
[dir="rtl"] #drupal-off-canvas .messages {
|
||||
background-position: right 10px top 17px;
|
||||
}
|
||||
#drupal-off-canvas .messages abbr {
|
||||
color: #444;
|
||||
}
|
||||
#drupal-off-canvas .messages--status {
|
||||
background-color: #f3faef;
|
||||
background-image: url(../icons/73b355/check.svg);
|
||||
color: #325e1c;
|
||||
}
|
||||
#drupal-off-canvas .messages--warning {
|
||||
background-color: #fdf8ed;
|
||||
background-image: url(../icons/e29700/warning.svg);
|
||||
color: #734c00;
|
||||
}
|
||||
|
||||
#drupal-off-canvas .messages--error {
|
||||
background-color: #fcf4f2;
|
||||
background-image: url(../icons/e32700/error.svg);
|
||||
color: #a51b00;
|
||||
}
|
||||
|
||||
#drupal-off-canvas .messages--error div[role="alert"] {
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
}
|
118
2017/web/core/misc/dialog/off-canvas.button.css
Normal file
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* @file
|
||||
* Visual styling for buttons in the off-canvas dialog.
|
||||
*
|
||||
* @see seven/css/components/buttons.css
|
||||
*/
|
||||
|
||||
#drupal-off-canvas button,
|
||||
#drupal-off-canvas .button {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
margin: 0 0 10px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
font-family: "Lucida Grande", 'Lucida Sans Unicode', 'liberation sans', sans-serif;
|
||||
line-height: normal;
|
||||
text-transform: none;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
#drupal-off-canvas button.link {
|
||||
display: inline;
|
||||
background: transparent;
|
||||
font-size: 14px;
|
||||
color: #85bef4;
|
||||
transition: color 0.5s ease;
|
||||
}
|
||||
#drupal-off-canvas button.link:hover,
|
||||
#drupal-off-canvas button.link:focus {
|
||||
color: #46a0f5;
|
||||
text-decoration: none;
|
||||
}
|
||||
#drupal-off-canvas input[type="submit"].button {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
padding: 4px 20px;
|
||||
border: 0;
|
||||
border-radius: 20em;
|
||||
background: #777;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
color: #f5f5f5;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: background 0.5s ease;
|
||||
}
|
||||
#drupal-off-canvas input[type="submit"].button:hover,
|
||||
#drupal-off-canvas input[type="submit"].button:focus,
|
||||
#drupal-off-canvas input[type="submit"].button:active {
|
||||
border: 0;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
z-index: 10;
|
||||
}
|
||||
#drupal-off-canvas input[type="submit"].button:focus,
|
||||
#drupal-off-canvas input[type="submit"].button:active {
|
||||
box-shadow: 0 3px 3px 2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
#drupal-off-canvas input[type="submit"].button--primary {
|
||||
border: 0;
|
||||
background: #277abd;
|
||||
color: #fff;
|
||||
margin-top: 15px;
|
||||
}
|
||||
#drupal-off-canvas input[type="submit"].button--primary:hover,
|
||||
#drupal-off-canvas input[type="submit"].button--primary:focus,
|
||||
#drupal-off-canvas input[type="submit"].button--primary:active {
|
||||
background: #236aaf;
|
||||
outline: none;
|
||||
}
|
||||
#drupal-off-canvas .button-action:before {
|
||||
margin-left: -0.2em; /* LTR */
|
||||
padding-right: 0.2em; /* LTR */
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
}
|
||||
[dir="rtl"] #drupal-off-canvas .button-action:before {
|
||||
margin-right: -0.2em;
|
||||
margin-left: 0;
|
||||
padding-right: 0;
|
||||
padding-left: 0.2em;
|
||||
}
|
||||
#drupal-off-canvas .no-touchevents .button--small {
|
||||
font-size: 13px;
|
||||
padding: 2px 1em;
|
||||
}
|
||||
#drupal-off-canvas .button:disabled,
|
||||
#drupal-off-canvas .button:disabled:active,
|
||||
#drupal-off-canvas .button.is-disabled,
|
||||
#drupal-off-canvas .button.is-disabled:active {
|
||||
border: 0;
|
||||
background: #555;
|
||||
color: #5c5c5c;
|
||||
font-weight: normal;
|
||||
cursor: default;
|
||||
}
|
||||
#drupal-off-canvas .button--danger {
|
||||
border-radius: 0;
|
||||
color: #c72100;
|
||||
font-weight: 400;
|
||||
text-decoration: none;
|
||||
}
|
||||
#drupal-off-canvas .button--danger:hover,
|
||||
#drupal-off-canvas .button--danger:focus,
|
||||
#drupal-off-canvas .button--danger:active {
|
||||
color: #ff2a00;
|
||||
text-decoration: none;
|
||||
text-shadow: none;
|
||||
}
|
||||
#drupal-off-canvas .button--danger:disabled,
|
||||
#drupal-off-canvas .button--danger.is-disabled {
|
||||
color: #737373;
|
||||
cursor: default;
|
||||
}
|
55
2017/web/core/misc/dialog/off-canvas.css
Normal file
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* @file
|
||||
* CSS for off-canvas dialog.
|
||||
*/
|
||||
|
||||
/* Position the off-canvas dialog container outside the right of the viewport. */
|
||||
.ui-dialog-off-canvas {
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* Wrap the form that's inside the off-canvas dialog. */
|
||||
.ui-dialog-off-canvas .ui-dialog-content {
|
||||
padding: 0 20px;
|
||||
/* Prevent horizontal scrollbar. */
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
[dir="rtl"] .ui-dialog-off-canvas .ui-dialog-content {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Position the off-canvas dialog container outside the right of the viewport. */
|
||||
.ui-dialog-off-canvas {
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* Wrap the form that's inside the off-canvas dialog. */
|
||||
.ui-dialog-off-canvas #drupal-off-canvas {
|
||||
padding: 0 20px 20px;
|
||||
/* Prevent horizontal scrollbar. */
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
[dir="rtl"] .ui-dialog-off-canvas #drupal-off-canvas {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/*
|
||||
* Force the off-canvas dialog to be 100% width at the same breakpoint the
|
||||
* dialog system uses to expand dialog widths.
|
||||
*/
|
||||
@media all and (max-width: 48em) { /* 768px */
|
||||
.ui-dialog.ui-dialog-off-canvas {
|
||||
width: 100% !important;
|
||||
}
|
||||
/* When off-canvas dialog is at 100% width stop the body from scrolling */
|
||||
.js-off-canvas-dialog-open {
|
||||
height: 100%;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
}
|
60
2017/web/core/misc/dialog/off-canvas.details.css
Normal file
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* @file
|
||||
* Visual styling for summary and details in the off-canvas dialog.
|
||||
*/
|
||||
|
||||
#drupal-off-canvas details,
|
||||
#drupal-off-canvas summary {
|
||||
display: block;
|
||||
font-family: "Lucida Grande", 'Lucida Sans Unicode', 'liberation sans', sans-serif;
|
||||
}
|
||||
#drupal-off-canvas details,
|
||||
#drupal-off-canvas summary,
|
||||
#drupal-off-canvas .ui-dialog-content {
|
||||
background: #474747;
|
||||
color: #ddd;
|
||||
}
|
||||
#drupal-off-canvas summary a {
|
||||
color: #ddd;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
#drupal-off-canvas summary a:hover,
|
||||
#drupal-off-canvas summary a:focus {
|
||||
color: #fff;
|
||||
}
|
||||
#drupal-off-canvas details,
|
||||
#drupal-off-canvas summary,
|
||||
#drupal-off-canvas .details-wrapper {
|
||||
border-width: 0;
|
||||
/* Cancel out the padding of the parent. */
|
||||
margin: 0 -20px;
|
||||
padding: 0 20px;
|
||||
}
|
||||
#drupal-off-canvas summary {
|
||||
text-shadow: none;
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
#drupal-off-canvas summary:hover,
|
||||
#drupal-off-canvas summary:focus {
|
||||
background-color: #222;
|
||||
}
|
||||
#drupal-off-canvas details[open] {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
#drupal-off-canvas details[open] > summary {
|
||||
background-color: #333;
|
||||
color: #eee;
|
||||
}
|
||||
#drupal-off-canvas details[open] > summary:hover {
|
||||
background-color: #222;
|
||||
color: #fff;
|
||||
}
|
||||
#drupal-off-canvas details .placeholder {
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
font-style: italic;
|
||||
background: transparent;
|
||||
}
|
291
2017/web/core/misc/dialog/off-canvas.dropbutton.css
Normal file
|
@ -0,0 +1,291 @@
|
|||
/**
|
||||
* @file
|
||||
* Styles for dropbuttons in the off-canvas dialog.
|
||||
*/
|
||||
|
||||
#drupal-off-canvas .dropbutton-wrapper,
|
||||
#drupal-off-canvas .dropbutton-widget {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
display: block;
|
||||
position: static;
|
||||
transition: none;
|
||||
}
|
||||
#drupal-off-canvas .dropbutton-widget {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: #277abd;
|
||||
border-radius: 1em;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
text-transform: none;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
line-height: normal;
|
||||
cursor: pointer;
|
||||
transition: background 0.5s ease;
|
||||
}
|
||||
#drupal-off-canvas .dropbutton-widget:hover {
|
||||
background: #2b8bd8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Style dropbutton single.
|
||||
*/
|
||||
|
||||
#drupal-off-canvas .dropbutton-single .dropbutton-action a {
|
||||
padding: 0;
|
||||
/* Overlap icon for trigger. */
|
||||
margin-top: -2em;
|
||||
height: 2.2em;
|
||||
cursor: pointer;
|
||||
}
|
||||
#drupal-off-canvas .dropbutton-single .dropbutton-action:hover,
|
||||
#drupal-off-canvas .dropbutton-single .dropbutton-action:focus,
|
||||
#drupal-off-canvas .dropbutton-single .dropbutton-action a:hover,
|
||||
#drupal-off-canvas .dropbutton-single .dropbutton-action a:focus {
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
}
|
||||
#drupal-off-canvas .dropbutton-widget .dropbutton {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
#drupal-off-canvas .dropbutton li,
|
||||
#drupal-off-canvas .dropbutton a {
|
||||
display: block;
|
||||
width: auto;
|
||||
padding: 4px 0;
|
||||
text-align: left;
|
||||
color: #555;
|
||||
outline: none;
|
||||
}
|
||||
#drupal-off-canvas .dropbutton li:hover,
|
||||
#drupal-off-canvas .dropbutton li:focus,
|
||||
#drupal-off-canvas .dropbutton a:hover,
|
||||
#drupal-off-canvas .dropbutton a:focus {
|
||||
background: transparent;
|
||||
color: #333;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* Style dropbutton multiple.
|
||||
*/
|
||||
|
||||
#drupal-off-canvas .dropbutton-multiple .dropbutton-widget {
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
}
|
||||
#drupal-off-canvas .dropbutton-multiple .dropbutton-widget:hover {
|
||||
background-color: #2b8bd8;
|
||||
}
|
||||
|
||||
/* Hide the other actions until the dropbutton is triggered. */
|
||||
#drupal-off-canvas .dropbutton-multiple .dropbutton .secondary-action {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* The toggle to expand the button. */
|
||||
#drupal-off-canvas .dropbutton-toggle {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0; /* LTR */
|
||||
bottom: 0;
|
||||
display: block;
|
||||
width: 2em;
|
||||
color: #fff;
|
||||
text-indent: 110%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#drupal-off-canvas .dropbutton-toggle button {
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0 solid transparent;
|
||||
border-bottom-right-radius: 1em; /* LTR */
|
||||
border-top-right-radius: 1em; /* LTR */
|
||||
cursor: pointer;
|
||||
}
|
||||
#drupal-off-canvas .dropbutton-toggle button:hover,
|
||||
#drupal-off-canvas .dropbutton-toggle button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* The toggle arrow. */
|
||||
#drupal-off-canvas .dropbutton-arrow {
|
||||
position: absolute;
|
||||
display: block;
|
||||
height: 0;
|
||||
width: 0;
|
||||
margin-top: 0;
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: transparent;
|
||||
border-right-color: transparent;
|
||||
border-style: solid;
|
||||
border-width: 0.3333em 0.3333em 0;
|
||||
color: #fff;
|
||||
line-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
#drupal-off-canvas span.dropbutton-arrow {
|
||||
top: 7px;
|
||||
right: 7px; /* LTR */
|
||||
background: transparent;
|
||||
}
|
||||
#drupal-off-canvas span.dropbutton-arrow:hover {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#drupal-off-canvas .dropbutton-action > .js-form-submit.form-submit,
|
||||
#drupal-off-canvas .dropbutton-toggle button {
|
||||
position: relative;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dropbuttons when in a table cell.
|
||||
*/
|
||||
|
||||
/* Make sure table cell doesn't collapse around absolute positioned dropbutton. */
|
||||
#drupal-off-canvas td .dropbutton-single {
|
||||
min-width: 2em;
|
||||
}
|
||||
#drupal-off-canvas td .dropbutton-multiple {
|
||||
min-width: 2em;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
border: 0;
|
||||
}
|
||||
#drupal-off-canvas td .dropbutton-multiple .dropbutton-action a,
|
||||
#drupal-off-canvas td .dropbutton-multiple .dropbutton-action input,
|
||||
#drupal-off-canvas td .dropbutton-multiple .dropbutton-action button {
|
||||
width: auto;
|
||||
padding: 0;
|
||||
font-size: inherit;
|
||||
}
|
||||
#drupal-off-canvas td .dropbutton-wrapper {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Push the widget to the right so text expands left. */
|
||||
#drupal-off-canvas td .dropbutton-widget {
|
||||
position: absolute;
|
||||
right: 12px; /* LTR */
|
||||
padding: 0;
|
||||
background: #277abd none;
|
||||
}
|
||||
|
||||
/* Push the wrapper to the right edge of the td. */
|
||||
#drupal-off-canvas td .dropbutton-single,
|
||||
#drupal-off-canvas td .dropbutton-multiple {
|
||||
float: right; /* LTR */
|
||||
padding-right: 0;
|
||||
margin-right: 0;
|
||||
max-width: initial;
|
||||
min-width: initial;
|
||||
position: relative;
|
||||
}
|
||||
#drupal-off-canvas td .dropbutton-widget .dropbutton {
|
||||
margin: 0;
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Push text out of the way. */
|
||||
#drupal-off-canvas td .dropbutton-multiple li,
|
||||
#drupal-off-canvas td .dropbutton-multiple a {
|
||||
margin-left: -9999px;
|
||||
background: transparent;
|
||||
}
|
||||
#drupal-off-canvas td .dropbutton-multiple.open .dropbutton li,
|
||||
#drupal-off-canvas td .dropbutton-multiple.open .dropbutton a {
|
||||
margin-left: 0;
|
||||
width: auto;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Collapse the button to a circle. */
|
||||
#drupal-off-canvas td .dropbutton-toggle {
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
border-radius: 1em;
|
||||
}
|
||||
#drupal-off-canvas td .dropbutton-wrapper .dropbutton-widget .dropbutton-toggle button {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Prevent list item from expanding its container. */
|
||||
#drupal-off-canvas td ul.dropbutton li.edit {
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
}
|
||||
|
||||
/* Make li text transparent above icon so it's clickable. */
|
||||
#drupal-off-canvas td .dropbutton-single li.edit.dropbutton-action > a {
|
||||
color: transparent;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Put pencil icon in place of hidden 'edit' text on single buttons. */
|
||||
#drupal-off-canvas td .dropbutton-single .edit:before {
|
||||
content: '.';
|
||||
display: block;
|
||||
color: transparent;
|
||||
background: transparent url(../icons/ffffff/pencil.svg) no-repeat center;
|
||||
background-size: 14px;
|
||||
}
|
||||
|
||||
/* Dropbutton when triggered expands to show secondary items. */
|
||||
#drupal-off-canvas .dropbutton-multiple.open {
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
/* Create visual separation if there is an adjacent button. */
|
||||
#drupal-off-canvas .dropbutton-multiple.open .dropbutton-widget {
|
||||
box-shadow: 0 3px 3px 2px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
/* Triggered dropbutton expands to show secondary items. */
|
||||
#drupal-off-canvas .dropbutton-multiple.open,
|
||||
#drupal-off-canvas .dropbutton-multiple.open .dropbutton-widget {
|
||||
display: block;
|
||||
width: auto;
|
||||
height: auto;
|
||||
max-width: none;
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* Triggered dropbutton in td expands to show secondary items. */
|
||||
#drupal-off-canvas td .dropbutton-multiple.open .dropbutton,
|
||||
#drupal-off-canvas .dropbutton-multiple.open .dropbutton .secondary-action {
|
||||
display: block;
|
||||
width: auto;
|
||||
height: auto;
|
||||
padding-right: 1em; /* LTR */
|
||||
}
|
||||
[dir="rtl"] #drupal-off-canvas td .dropbutton-multiple.open .dropbutton {
|
||||
padding-left: 1em;
|
||||
padding-right: inherit;
|
||||
}
|
||||
#drupal-off-canvas .dropbutton-multiple.open .dropbutton li a {
|
||||
padding: 2px 1em;
|
||||
}
|
||||
|
||||
/* When open, the toggle arrow points upward. */
|
||||
#drupal-off-canvas .dropbutton-multiple.open span.dropbutton-arrow {
|
||||
border-bottom: 0.3333em solid;
|
||||
border-top-color: transparent;
|
||||
top: 2px;
|
||||
}
|
359
2017/web/core/misc/dialog/off-canvas.es6.js
Normal file
|
@ -0,0 +1,359 @@
|
|||
/**
|
||||
* @file
|
||||
* Drupal's off-canvas library.
|
||||
*/
|
||||
|
||||
(($, Drupal, debounce, displace) => {
|
||||
/**
|
||||
* Off-canvas dialog implementation using jQuery Dialog.
|
||||
*
|
||||
* Transforms the regular dialogs created using Drupal.dialog when the dialog
|
||||
* element equals '#drupal-off-canvas' into an side-loading dialog.
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
Drupal.offCanvas = {
|
||||
/**
|
||||
* Storage for position information about the tray.
|
||||
*
|
||||
* @type {?String}
|
||||
*/
|
||||
position: null,
|
||||
|
||||
/**
|
||||
* The minimum height of the tray when opened at the top of the page.
|
||||
*
|
||||
* @type {Number}
|
||||
*/
|
||||
minimumHeight: 30,
|
||||
|
||||
/**
|
||||
* The minimum width to use body displace needs to match the width at which
|
||||
* the tray will be 100% width. @see core/misc/dialog/off-canvas.css
|
||||
*
|
||||
* @type {Number}
|
||||
*/
|
||||
minDisplaceWidth: 768,
|
||||
|
||||
/**
|
||||
* Wrapper used to position off-canvas dialog.
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
$mainCanvasWrapper: $('[data-off-canvas-main-canvas]'),
|
||||
|
||||
/**
|
||||
* Determines if an element is an off-canvas dialog.
|
||||
*
|
||||
* @param {jQuery} $element
|
||||
* The dialog element.
|
||||
*
|
||||
* @return {bool}
|
||||
* True this is currently an off-canvas dialog.
|
||||
*/
|
||||
isOffCanvas($element) {
|
||||
return $element.is('#drupal-off-canvas');
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove off-canvas dialog events.
|
||||
*
|
||||
* @param {jQuery} $element
|
||||
* The target element.
|
||||
*/
|
||||
removeOffCanvasEvents($element) {
|
||||
$element.off('.off-canvas');
|
||||
$(document).off('.off-canvas');
|
||||
$(window).off('.off-canvas');
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler fired before an off-canvas dialog has been opened.
|
||||
*
|
||||
* @param {Object} settings
|
||||
* Settings related to the composition of the dialog.
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
beforeCreate({ settings, $element }) {
|
||||
// Clean up previous dialog event handlers.
|
||||
Drupal.offCanvas.removeOffCanvasEvents($element);
|
||||
|
||||
$('body').addClass('js-off-canvas-dialog-open');
|
||||
// @see http://api.jqueryui.com/position/
|
||||
settings.position = {
|
||||
my: 'left top',
|
||||
at: `${Drupal.offCanvas.getEdge()} top`,
|
||||
of: window,
|
||||
};
|
||||
|
||||
/**
|
||||
* Applies initial height and with to dialog based depending on position.
|
||||
* @see http://api.jqueryui.com/dialog for all dialog options.
|
||||
*/
|
||||
const position = settings.drupalOffCanvasPosition;
|
||||
const height = position === 'side' ? $(window).height() : settings.height;
|
||||
const width = position === 'side' ? settings.width : '100%';
|
||||
settings.height = height;
|
||||
settings.width = width;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler fired after an off-canvas dialog has been closed.
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
beforeClose({ $element }) {
|
||||
$('body').removeClass('js-off-canvas-dialog-open');
|
||||
// Remove all *.off-canvas events
|
||||
Drupal.offCanvas.removeOffCanvasEvents($element);
|
||||
Drupal.offCanvas.resetPadding();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler fired when an off-canvas dialog has been opened.
|
||||
*
|
||||
* @param {jQuery} $element
|
||||
* The off-canvas dialog element.
|
||||
* @param {Object} settings
|
||||
* Settings related to the composition of the dialog.
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
afterCreate({ $element, settings }) {
|
||||
const eventData = { settings, $element, offCanvasDialog: this };
|
||||
|
||||
$element
|
||||
.on(
|
||||
'dialogContentResize.off-canvas',
|
||||
eventData,
|
||||
Drupal.offCanvas.handleDialogResize,
|
||||
)
|
||||
.on(
|
||||
'dialogContentResize.off-canvas',
|
||||
eventData,
|
||||
Drupal.offCanvas.bodyPadding,
|
||||
);
|
||||
|
||||
Drupal.offCanvas
|
||||
.getContainer($element)
|
||||
.attr(`data-offset-${Drupal.offCanvas.getEdge()}`, '');
|
||||
|
||||
$(window)
|
||||
.on(
|
||||
'resize.off-canvas',
|
||||
eventData,
|
||||
debounce(Drupal.offCanvas.resetSize, 100),
|
||||
)
|
||||
.trigger('resize.off-canvas');
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle classes based on title existence.
|
||||
* Called with Drupal.offCanvas.afterCreate.
|
||||
*
|
||||
* @param {Object} settings
|
||||
* Settings related to the composition of the dialog.
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
render({ settings }) {
|
||||
$(
|
||||
'.ui-dialog-off-canvas, .ui-dialog-off-canvas .ui-dialog-titlebar',
|
||||
).toggleClass('ui-dialog-empty-title', !settings.title);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adjusts the dialog on resize.
|
||||
*
|
||||
* @param {jQuery.Event} event
|
||||
* The event triggered.
|
||||
* @param {object} event.data
|
||||
* Data attached to the event.
|
||||
*/
|
||||
handleDialogResize(event) {
|
||||
const $element = event.data.$element;
|
||||
const $container = Drupal.offCanvas.getContainer($element);
|
||||
|
||||
const $offsets = $container.find(
|
||||
'> :not(#drupal-off-canvas, .ui-resizable-handle)',
|
||||
);
|
||||
let offset = 0;
|
||||
|
||||
// Let scroll element take all the height available.
|
||||
$element.css({ height: 'auto' });
|
||||
const modalHeight = $container.height();
|
||||
|
||||
$offsets.each((i, e) => {
|
||||
offset += $(e).outerHeight();
|
||||
});
|
||||
|
||||
// Take internal padding into account.
|
||||
const scrollOffset = $element.outerHeight() - $element.height();
|
||||
$element.height(modalHeight - offset - scrollOffset);
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets the size of the dialog.
|
||||
*
|
||||
* @param {jQuery.Event} event
|
||||
* The event triggered.
|
||||
* @param {object} event.data
|
||||
* Data attached to the event.
|
||||
*/
|
||||
resetSize(event) {
|
||||
const $element = event.data.$element;
|
||||
const container = Drupal.offCanvas.getContainer($element);
|
||||
const position = event.data.settings.drupalOffCanvasPosition;
|
||||
|
||||
// Only remove the `data-offset-*` attribute if the value previously
|
||||
// exists and the orientation is changing.
|
||||
if (Drupal.offCanvas.position && Drupal.offCanvas.position !== position) {
|
||||
container.removeAttr(`data-offset-${Drupal.offCanvas.position}`);
|
||||
}
|
||||
// Set a minimum height on $element
|
||||
if (position === 'top') {
|
||||
$element.css('min-height', `${Drupal.offCanvas.minimumHeight}px`);
|
||||
}
|
||||
|
||||
displace();
|
||||
|
||||
const offsets = displace.offsets;
|
||||
|
||||
const topPosition =
|
||||
position === 'side' && offsets.top !== 0 ? `+${offsets.top}` : '';
|
||||
const adjustedOptions = {
|
||||
// @see http://api.jqueryui.com/position/
|
||||
position: {
|
||||
my: `${Drupal.offCanvas.getEdge()} top`,
|
||||
at: `${Drupal.offCanvas.getEdge()} top${topPosition}`,
|
||||
of: window,
|
||||
},
|
||||
};
|
||||
|
||||
const height =
|
||||
position === 'side'
|
||||
? `${$(window).height() - (offsets.top + offsets.bottom)}px`
|
||||
: event.data.settings.height;
|
||||
container.css({
|
||||
position: 'fixed',
|
||||
height,
|
||||
});
|
||||
|
||||
$element
|
||||
.dialog('option', adjustedOptions)
|
||||
.trigger('dialogContentResize.off-canvas');
|
||||
|
||||
Drupal.offCanvas.position = position;
|
||||
},
|
||||
|
||||
/**
|
||||
* Adjusts the body padding when the dialog is resized.
|
||||
*
|
||||
* @param {jQuery.Event} event
|
||||
* The event triggered.
|
||||
* @param {object} event.data
|
||||
* Data attached to the event.
|
||||
*/
|
||||
bodyPadding(event) {
|
||||
const position = event.data.settings.drupalOffCanvasPosition;
|
||||
if (
|
||||
position === 'side' &&
|
||||
$('body').outerWidth() < Drupal.offCanvas.minDisplaceWidth
|
||||
) {
|
||||
return;
|
||||
}
|
||||
Drupal.offCanvas.resetPadding();
|
||||
const $element = event.data.$element;
|
||||
const $container = Drupal.offCanvas.getContainer($element);
|
||||
const $mainCanvasWrapper = Drupal.offCanvas.$mainCanvasWrapper;
|
||||
|
||||
const width = $container.outerWidth();
|
||||
const mainCanvasPadding = $mainCanvasWrapper.css(
|
||||
`padding-${Drupal.offCanvas.getEdge()}`,
|
||||
);
|
||||
if (position === 'side' && width !== mainCanvasPadding) {
|
||||
$mainCanvasWrapper.css(
|
||||
`padding-${Drupal.offCanvas.getEdge()}`,
|
||||
`${width}px`,
|
||||
);
|
||||
$container.attr(`data-offset-${Drupal.offCanvas.getEdge()}`, width);
|
||||
displace();
|
||||
}
|
||||
|
||||
const height = $container.outerHeight();
|
||||
if (position === 'top') {
|
||||
$mainCanvasWrapper.css('padding-top', `${height}px`);
|
||||
$container.attr('data-offset-top', height);
|
||||
displace();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The HTML element that surrounds the dialog.
|
||||
* @param {HTMLElement} $element
|
||||
* The dialog element.
|
||||
*
|
||||
* @return {HTMLElement}
|
||||
* The containing element.
|
||||
*/
|
||||
getContainer($element) {
|
||||
return $element.dialog('widget');
|
||||
},
|
||||
|
||||
/**
|
||||
* The edge of the screen that the dialog should appear on.
|
||||
*
|
||||
* @return {string}
|
||||
* The edge the tray will be shown on, left or right.
|
||||
*/
|
||||
getEdge() {
|
||||
return document.documentElement.dir === 'rtl' ? 'left' : 'right';
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets main canvas wrapper and toolbar padding / margin.
|
||||
*/
|
||||
resetPadding() {
|
||||
Drupal.offCanvas.$mainCanvasWrapper.css(
|
||||
`padding-${Drupal.offCanvas.getEdge()}`,
|
||||
0,
|
||||
);
|
||||
Drupal.offCanvas.$mainCanvasWrapper.css('padding-top', 0);
|
||||
displace();
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Attaches off-canvas dialog behaviors.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches event listeners for off-canvas dialogs.
|
||||
*/
|
||||
Drupal.behaviors.offCanvasEvents = {
|
||||
attach: () => {
|
||||
$(window)
|
||||
.once('off-canvas')
|
||||
.on({
|
||||
'dialog:beforecreate': (event, dialog, $element, settings) => {
|
||||
if (Drupal.offCanvas.isOffCanvas($element)) {
|
||||
Drupal.offCanvas.beforeCreate({ dialog, $element, settings });
|
||||
}
|
||||
},
|
||||
'dialog:aftercreate': (event, dialog, $element, settings) => {
|
||||
if (Drupal.offCanvas.isOffCanvas($element)) {
|
||||
Drupal.offCanvas.render({ dialog, $element, settings });
|
||||
Drupal.offCanvas.afterCreate({ $element, settings });
|
||||
}
|
||||
},
|
||||
'dialog:beforeclose': (event, dialog, $element) => {
|
||||
if (Drupal.offCanvas.isOffCanvas($element)) {
|
||||
Drupal.offCanvas.beforeClose({ dialog, $element });
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
})(jQuery, Drupal, Drupal.debounce, Drupal.displace);
|
133
2017/web/core/misc/dialog/off-canvas.form.css
Normal file
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* @file
|
||||
* Visual styling for forms in the off-canvas dialog.
|
||||
*/
|
||||
|
||||
#drupal-off-canvas form {
|
||||
font-family: "Lucida Grande", 'Lucida Sans Unicode', 'liberation sans', sans-serif;
|
||||
color: #ddd;
|
||||
}
|
||||
#drupal-off-canvas input[type="checkbox"] {
|
||||
-webkit-appearance: checkbox;
|
||||
}
|
||||
#drupal-off-canvas input[type="radio"] {
|
||||
-webkit-appearance: radio;
|
||||
}
|
||||
#drupal-off-canvas select {
|
||||
-webkit-appearance: menulist;
|
||||
-moz-appearance: menulist;
|
||||
}
|
||||
#drupal-off-canvas option {
|
||||
display: block;
|
||||
font-family: "Lucida Grande", 'Lucida Sans Unicode', 'liberation sans', sans-serif;
|
||||
}
|
||||
#drupal-off-canvas label {
|
||||
line-height: normal;
|
||||
font-family: inherit;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: #ddd;
|
||||
}
|
||||
#drupal-off-canvas .visually-hidden {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
width: 0;
|
||||
letter-spacing: -2em;
|
||||
}
|
||||
#drupal-off-canvas .description,
|
||||
#drupal-off-canvas .form-item .description,
|
||||
#drupal-off-canvas .details-description {
|
||||
color: #ddd;
|
||||
margin-top: 5px;
|
||||
font-family: inherit;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
}
|
||||
#drupal-off-canvas .form-item {
|
||||
margin-bottom: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
/* Set size and position for all inputs. */
|
||||
#drupal-off-canvas .form-select,
|
||||
#drupal-off-canvas .form-text,
|
||||
#drupal-off-canvas .form-tel,
|
||||
#drupal-off-canvas .form-email,
|
||||
#drupal-off-canvas .form-url,
|
||||
#drupal-off-canvas .form-search,
|
||||
#drupal-off-canvas .form-number,
|
||||
#drupal-off-canvas .form-color,
|
||||
#drupal-off-canvas .form-file,
|
||||
#drupal-off-canvas .form-textarea,
|
||||
#drupal-off-canvas .form-date,
|
||||
#drupal-off-canvas .form-time {
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
padding: 6px;
|
||||
margin: 5px 0 0 0;
|
||||
border-width: 1px;
|
||||
border-radius: 2px;
|
||||
display: block;
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
line-height: 16px;
|
||||
}
|
||||
/* Reduce contrast for fields against dark background. */
|
||||
#drupal-off-canvas .form-text,
|
||||
#drupal-off-canvas .form-tel,
|
||||
#drupal-off-canvas .form-email,
|
||||
#drupal-off-canvas .form-url,
|
||||
#drupal-off-canvas .form-search,
|
||||
#drupal-off-canvas .form-number,
|
||||
#drupal-off-canvas .form-color,
|
||||
#drupal-off-canvas .form-file,
|
||||
#drupal-off-canvas .form-textarea,
|
||||
#drupal-off-canvas .form-date,
|
||||
#drupal-off-canvas .form-time {
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.125);
|
||||
background-color: #eee;
|
||||
border-color: #333;
|
||||
color: #595959;
|
||||
}
|
||||
#drupal-off-canvas .form-text:focus,
|
||||
#drupal-off-canvas .form-tel:focus,
|
||||
#drupal-off-canvas .form-email:focus,
|
||||
#drupal-off-canvas .form-url:focus,
|
||||
#drupal-off-canvas .form-search:focus,
|
||||
#drupal-off-canvas .form-number:focus,
|
||||
#drupal-off-canvas .form-color:focus,
|
||||
#drupal-off-canvas .form-file:focus,
|
||||
#drupal-off-canvas .form-textarea:focus,
|
||||
#drupal-off-canvas .form-date:focus,
|
||||
#drupal-off-canvas .form-time:focus {
|
||||
border-color: #40b6ff;
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.125), 0 0 8px #40b6ff;
|
||||
background-color: #fff;
|
||||
}
|
||||
#drupal-off-canvas td .form-item,
|
||||
#drupal-off-canvas td .form-select {
|
||||
margin: 0;
|
||||
}
|
||||
#drupal-off-canvas .form-file {
|
||||
margin-bottom: 5px;
|
||||
width: 100%;
|
||||
}
|
||||
#drupal-off-canvas .form-actions {
|
||||
text-align: center;
|
||||
margin: 10px 0;
|
||||
}
|
||||
#drupal-off-canvas .ui-autocomplete {
|
||||
background-color: white;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
cursor: default;
|
||||
}
|
||||
#drupal-off-canvas .ui-autocomplete li {
|
||||
display: block;
|
||||
}
|
||||
#drupal-off-canvas .ui-autocomplete li a {
|
||||
color: #595959 !important;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
}
|
184
2017/web/core/misc/dialog/off-canvas.js
Normal file
|
@ -0,0 +1,184 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal, debounce, displace) {
|
||||
Drupal.offCanvas = {
|
||||
position: null,
|
||||
|
||||
minimumHeight: 30,
|
||||
|
||||
minDisplaceWidth: 768,
|
||||
|
||||
$mainCanvasWrapper: $('[data-off-canvas-main-canvas]'),
|
||||
|
||||
isOffCanvas: function isOffCanvas($element) {
|
||||
return $element.is('#drupal-off-canvas');
|
||||
},
|
||||
removeOffCanvasEvents: function removeOffCanvasEvents($element) {
|
||||
$element.off('.off-canvas');
|
||||
$(document).off('.off-canvas');
|
||||
$(window).off('.off-canvas');
|
||||
},
|
||||
beforeCreate: function beforeCreate(_ref) {
|
||||
var settings = _ref.settings,
|
||||
$element = _ref.$element;
|
||||
|
||||
Drupal.offCanvas.removeOffCanvasEvents($element);
|
||||
|
||||
$('body').addClass('js-off-canvas-dialog-open');
|
||||
|
||||
settings.position = {
|
||||
my: 'left top',
|
||||
at: Drupal.offCanvas.getEdge() + ' top',
|
||||
of: window
|
||||
};
|
||||
|
||||
var position = settings.drupalOffCanvasPosition;
|
||||
var height = position === 'side' ? $(window).height() : settings.height;
|
||||
var width = position === 'side' ? settings.width : '100%';
|
||||
settings.height = height;
|
||||
settings.width = width;
|
||||
},
|
||||
beforeClose: function beforeClose(_ref2) {
|
||||
var $element = _ref2.$element;
|
||||
|
||||
$('body').removeClass('js-off-canvas-dialog-open');
|
||||
|
||||
Drupal.offCanvas.removeOffCanvasEvents($element);
|
||||
Drupal.offCanvas.resetPadding();
|
||||
},
|
||||
afterCreate: function afterCreate(_ref3) {
|
||||
var $element = _ref3.$element,
|
||||
settings = _ref3.settings;
|
||||
|
||||
var eventData = { settings: settings, $element: $element, offCanvasDialog: this };
|
||||
|
||||
$element.on('dialogContentResize.off-canvas', eventData, Drupal.offCanvas.handleDialogResize).on('dialogContentResize.off-canvas', eventData, Drupal.offCanvas.bodyPadding);
|
||||
|
||||
Drupal.offCanvas.getContainer($element).attr('data-offset-' + Drupal.offCanvas.getEdge(), '');
|
||||
|
||||
$(window).on('resize.off-canvas', eventData, debounce(Drupal.offCanvas.resetSize, 100)).trigger('resize.off-canvas');
|
||||
},
|
||||
render: function render(_ref4) {
|
||||
var settings = _ref4.settings;
|
||||
|
||||
$('.ui-dialog-off-canvas, .ui-dialog-off-canvas .ui-dialog-titlebar').toggleClass('ui-dialog-empty-title', !settings.title);
|
||||
},
|
||||
handleDialogResize: function handleDialogResize(event) {
|
||||
var $element = event.data.$element;
|
||||
var $container = Drupal.offCanvas.getContainer($element);
|
||||
|
||||
var $offsets = $container.find('> :not(#drupal-off-canvas, .ui-resizable-handle)');
|
||||
var offset = 0;
|
||||
|
||||
$element.css({ height: 'auto' });
|
||||
var modalHeight = $container.height();
|
||||
|
||||
$offsets.each(function (i, e) {
|
||||
offset += $(e).outerHeight();
|
||||
});
|
||||
|
||||
var scrollOffset = $element.outerHeight() - $element.height();
|
||||
$element.height(modalHeight - offset - scrollOffset);
|
||||
},
|
||||
resetSize: function resetSize(event) {
|
||||
var $element = event.data.$element;
|
||||
var container = Drupal.offCanvas.getContainer($element);
|
||||
var position = event.data.settings.drupalOffCanvasPosition;
|
||||
|
||||
if (Drupal.offCanvas.position && Drupal.offCanvas.position !== position) {
|
||||
container.removeAttr('data-offset-' + Drupal.offCanvas.position);
|
||||
}
|
||||
|
||||
if (position === 'top') {
|
||||
$element.css('min-height', Drupal.offCanvas.minimumHeight + 'px');
|
||||
}
|
||||
|
||||
displace();
|
||||
|
||||
var offsets = displace.offsets;
|
||||
|
||||
var topPosition = position === 'side' && offsets.top !== 0 ? '+' + offsets.top : '';
|
||||
var adjustedOptions = {
|
||||
position: {
|
||||
my: Drupal.offCanvas.getEdge() + ' top',
|
||||
at: Drupal.offCanvas.getEdge() + ' top' + topPosition,
|
||||
of: window
|
||||
}
|
||||
};
|
||||
|
||||
var height = position === 'side' ? $(window).height() - (offsets.top + offsets.bottom) + 'px' : event.data.settings.height;
|
||||
container.css({
|
||||
position: 'fixed',
|
||||
height: height
|
||||
});
|
||||
|
||||
$element.dialog('option', adjustedOptions).trigger('dialogContentResize.off-canvas');
|
||||
|
||||
Drupal.offCanvas.position = position;
|
||||
},
|
||||
bodyPadding: function bodyPadding(event) {
|
||||
var position = event.data.settings.drupalOffCanvasPosition;
|
||||
if (position === 'side' && $('body').outerWidth() < Drupal.offCanvas.minDisplaceWidth) {
|
||||
return;
|
||||
}
|
||||
Drupal.offCanvas.resetPadding();
|
||||
var $element = event.data.$element;
|
||||
var $container = Drupal.offCanvas.getContainer($element);
|
||||
var $mainCanvasWrapper = Drupal.offCanvas.$mainCanvasWrapper;
|
||||
|
||||
var width = $container.outerWidth();
|
||||
var mainCanvasPadding = $mainCanvasWrapper.css('padding-' + Drupal.offCanvas.getEdge());
|
||||
if (position === 'side' && width !== mainCanvasPadding) {
|
||||
$mainCanvasWrapper.css('padding-' + Drupal.offCanvas.getEdge(), width + 'px');
|
||||
$container.attr('data-offset-' + Drupal.offCanvas.getEdge(), width);
|
||||
displace();
|
||||
}
|
||||
|
||||
var height = $container.outerHeight();
|
||||
if (position === 'top') {
|
||||
$mainCanvasWrapper.css('padding-top', height + 'px');
|
||||
$container.attr('data-offset-top', height);
|
||||
displace();
|
||||
}
|
||||
},
|
||||
getContainer: function getContainer($element) {
|
||||
return $element.dialog('widget');
|
||||
},
|
||||
getEdge: function getEdge() {
|
||||
return document.documentElement.dir === 'rtl' ? 'left' : 'right';
|
||||
},
|
||||
resetPadding: function resetPadding() {
|
||||
Drupal.offCanvas.$mainCanvasWrapper.css('padding-' + Drupal.offCanvas.getEdge(), 0);
|
||||
Drupal.offCanvas.$mainCanvasWrapper.css('padding-top', 0);
|
||||
displace();
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.behaviors.offCanvasEvents = {
|
||||
attach: function attach() {
|
||||
$(window).once('off-canvas').on({
|
||||
'dialog:beforecreate': function dialogBeforecreate(event, dialog, $element, settings) {
|
||||
if (Drupal.offCanvas.isOffCanvas($element)) {
|
||||
Drupal.offCanvas.beforeCreate({ dialog: dialog, $element: $element, settings: settings });
|
||||
}
|
||||
},
|
||||
'dialog:aftercreate': function dialogAftercreate(event, dialog, $element, settings) {
|
||||
if (Drupal.offCanvas.isOffCanvas($element)) {
|
||||
Drupal.offCanvas.render({ dialog: dialog, $element: $element, settings: settings });
|
||||
Drupal.offCanvas.afterCreate({ $element: $element, settings: settings });
|
||||
}
|
||||
},
|
||||
'dialog:beforeclose': function dialogBeforeclose(event, dialog, $element) {
|
||||
if (Drupal.offCanvas.isOffCanvas($element)) {
|
||||
Drupal.offCanvas.beforeClose({ dialog: dialog, $element: $element });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
})(jQuery, Drupal, Drupal.debounce, Drupal.displace);
|
11
2017/web/core/misc/dialog/off-canvas.layout.css
Normal file
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* @file
|
||||
* Visual styling for layouts in the off-canvas dialog.
|
||||
*
|
||||
* See seven/css/layout/layout.css
|
||||
*/
|
||||
|
||||
.layout-icon__region {
|
||||
fill: #f5f5f2;
|
||||
stroke: #666;
|
||||
}
|
11
2017/web/core/misc/dialog/off-canvas.motion.css
Normal file
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* @file
|
||||
* Motion effects for off-canvas dialog.
|
||||
*
|
||||
* Motion effects are in a separate file so that they can be easily turned off
|
||||
* to improve performance if desired.
|
||||
*/
|
||||
|
||||
.dialog-off-canvas-main-canvas {
|
||||
transition: padding-right 0.7s ease, padding-left 0.7s ease, padding-top 0.3s ease;
|
||||
}
|
388
2017/web/core/misc/dialog/off-canvas.reset.css
Normal file
|
@ -0,0 +1,388 @@
|
|||
/**
|
||||
* @file
|
||||
* Reset most HTML elements styles for the off-canvas dialog.
|
||||
*
|
||||
* This is a generic reset. Drupal-specific classes are reset in components.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Do not include div in then initial overrides because including div will
|
||||
* cause the need for many more overrides in this file.
|
||||
*/
|
||||
#drupal-off-canvas *:not(div),
|
||||
#drupal-off-canvas *:not(svg *),
|
||||
#drupal-off-canvas *:after,
|
||||
#drupal-off-canvas *:before {
|
||||
all: initial;
|
||||
box-sizing: border-box;
|
||||
text-shadow: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-tap-highlight-color: initial;
|
||||
}
|
||||
|
||||
/* Reset size and position on elements. */
|
||||
#drupal-off-canvas a,
|
||||
#drupal-off-canvas abbr,
|
||||
#drupal-off-canvas acronym,
|
||||
#drupal-off-canvas address,
|
||||
#drupal-off-canvas applet,
|
||||
#drupal-off-canvas article,
|
||||
#drupal-off-canvas aside,
|
||||
#drupal-off-canvas audio,
|
||||
#drupal-off-canvas b,
|
||||
#drupal-off-canvas big,
|
||||
#drupal-off-canvas blockquote,
|
||||
#drupal-off-canvas body,
|
||||
#drupal-off-canvas canvas,
|
||||
#drupal-off-canvas caption,
|
||||
#drupal-off-canvas cite,
|
||||
#drupal-off-canvas code,
|
||||
#drupal-off-canvas dd,
|
||||
#drupal-off-canvas del,
|
||||
#drupal-off-canvas dfn,
|
||||
#drupal-off-canvas dialog,
|
||||
#drupal-off-canvas dl,
|
||||
#drupal-off-canvas dt,
|
||||
#drupal-off-canvas em,
|
||||
#drupal-off-canvas embed,
|
||||
#drupal-off-canvas fieldset,
|
||||
#drupal-off-canvas figcaption,
|
||||
#drupal-off-canvas figure,
|
||||
#drupal-off-canvas footer,
|
||||
#drupal-off-canvas form,
|
||||
#drupal-off-canvas h1,
|
||||
#drupal-off-canvas h2,
|
||||
#drupal-off-canvas h3,
|
||||
#drupal-off-canvas h4,
|
||||
#drupal-off-canvas h5,
|
||||
#drupal-off-canvas h6,
|
||||
#drupal-off-canvas header,
|
||||
#drupal-off-canvas hgroup,
|
||||
#drupal-off-canvas hr,
|
||||
#drupal-off-canvas html,
|
||||
#drupal-off-canvas i,
|
||||
#drupal-off-canvas iframe,
|
||||
#drupal-off-canvas img,
|
||||
#drupal-off-canvas ins,
|
||||
#drupal-off-canvas kbd,
|
||||
#drupal-off-canvas label,
|
||||
#drupal-off-canvas legend,
|
||||
#drupal-off-canvas li,
|
||||
#drupal-off-canvas main,
|
||||
#drupal-off-canvas mark,
|
||||
#drupal-off-canvas menu,
|
||||
#drupal-off-canvas meter,
|
||||
#drupal-off-canvas nav,
|
||||
#drupal-off-canvas object,
|
||||
#drupal-off-canvas ol,
|
||||
#drupal-off-canvas output,
|
||||
#drupal-off-canvas p,
|
||||
#drupal-off-canvas pre,
|
||||
#drupal-off-canvas progress,
|
||||
#drupal-off-canvas q,
|
||||
#drupal-off-canvas rp,
|
||||
#drupal-off-canvas rt,
|
||||
#drupal-off-canvas s,
|
||||
#drupal-off-canvas samp,
|
||||
#drupal-off-canvas section,
|
||||
#drupal-off-canvas small,
|
||||
#drupal-off-canvas span,
|
||||
#drupal-off-canvas strike,
|
||||
#drupal-off-canvas strong,
|
||||
#drupal-off-canvas sub,
|
||||
#drupal-off-canvas sup,
|
||||
#drupal-off-canvas table,
|
||||
#drupal-off-canvas tbody,
|
||||
#drupal-off-canvas td,
|
||||
#drupal-off-canvas tfoot,
|
||||
#drupal-off-canvas th,
|
||||
#drupal-off-canvas thead,
|
||||
#drupal-off-canvas time,
|
||||
#drupal-off-canvas tr,
|
||||
#drupal-off-canvas tt,
|
||||
#drupal-off-canvas u,
|
||||
#drupal-off-canvas ul,
|
||||
#drupal-off-canvas var,
|
||||
#drupal-off-canvas video,
|
||||
#drupal-off-canvas xmp {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
/*
|
||||
* Override the default (display: inline) for browsers that do not recognize HTML5 tags.
|
||||
* IE8 (and lower) requires a shiv: http://ejohn.org/blog/html5-shiv
|
||||
*/
|
||||
#drupal-off-canvas article,
|
||||
#drupal-off-canvas aside,
|
||||
#drupal-off-canvas figcaption,
|
||||
#drupal-off-canvas figure,
|
||||
#drupal-off-canvas footer,
|
||||
#drupal-off-canvas header,
|
||||
#drupal-off-canvas hgroup,
|
||||
#drupal-off-canvas main,
|
||||
#drupal-off-canvas menu,
|
||||
#drupal-off-canvas nav,
|
||||
#drupal-off-canvas section {
|
||||
display: block;
|
||||
line-height: normal;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Makes browsers agree.
|
||||
* IE + Opera = font-weight: bold.
|
||||
* Gecko + WebKit = font-weight: bolder.
|
||||
*/
|
||||
#drupal-off-canvas b,
|
||||
#drupal-off-canvas strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#drupal-off-canvas em,
|
||||
#drupal-off-canvas i {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
#drupal-off-canvas img {
|
||||
color: transparent;
|
||||
font-size: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#drupal-off-canvas ul,
|
||||
#drupal-off-canvas ol {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
/* reset table styling. */
|
||||
#drupal-off-canvas table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
#drupal-off-canvas table thead,
|
||||
#drupal-off-canvas table tbody,
|
||||
#drupal-off-canvas table tbody tr:nth-child(even),
|
||||
#drupal-off-canvas table tbody tr:nth-child(odd),
|
||||
#drupal-off-canvas table tfoot {
|
||||
border: 0;
|
||||
background: transparent none;
|
||||
}
|
||||
#drupal-off-canvas th,
|
||||
#drupal-off-canvas td,
|
||||
#drupal-off-canvas caption {
|
||||
font-weight: normal;
|
||||
}
|
||||
#drupal-off-canvas q {
|
||||
quotes: none;
|
||||
}
|
||||
#drupal-off-canvas q:before,
|
||||
#drupal-off-canvas q:after {
|
||||
content: none;
|
||||
}
|
||||
#drupal-off-canvas sub,
|
||||
#drupal-off-canvas sup,
|
||||
#drupal-off-canvas small {
|
||||
font-size: 75%;
|
||||
}
|
||||
#drupal-off-canvas sub,
|
||||
#drupal-off-canvas sup {
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
#drupal-off-canvas sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
#drupal-off-canvas sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
/*
|
||||
* For IE9. Without, occasionally draws shapes
|
||||
* outside the boundaries of <svg> rectangle.
|
||||
*/
|
||||
#drupal-off-canvas svg {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Specific resets for inputs. */
|
||||
#drupal-off-canvas input[type="search"]::-webkit-search-decoration {
|
||||
display: none;
|
||||
}
|
||||
#drupal-off-canvas input {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#drupal-off-canvas input[type="checkbox"],
|
||||
#drupal-off-canvas input[type="radio"] {
|
||||
position: static;
|
||||
margin: 0;
|
||||
}
|
||||
#drupal-off-canvas input:invalid,
|
||||
#drupal-off-canvas button:invalid,
|
||||
#drupal-off-canvas select:invalid,
|
||||
#drupal-off-canvas textarea:invalid,
|
||||
#drupal-off-canvas input:focus,
|
||||
#drupal-off-canvas button:focus,
|
||||
#drupal-off-canvas select:focus,
|
||||
#drupal-off-canvas textarea:focus,
|
||||
#drupal-off-canvas input[type="file"]:focus,
|
||||
#drupal-off-canvas input[type="file"]:active,
|
||||
#drupal-off-canvas input[type="radio"]:focus,
|
||||
#drupal-off-canvas input[type="radio"]:active,
|
||||
#drupal-off-canvas input[type="checkbox"]:focus,
|
||||
#drupal-off-canvas input[type="checkbox"]:active {
|
||||
box-shadow: none;
|
||||
z-index: 1;
|
||||
}
|
||||
#drupal-off-canvas input[role="button"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
#drupal-off-canvas button,
|
||||
#drupal-off-canvas input[type="reset"],
|
||||
#drupal-off-canvas input[type="submit"],
|
||||
#drupal-off-canvas input[type="button"] {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
display: inline-block;
|
||||
background-image: none;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
overflow: visible;
|
||||
text-shadow: none;
|
||||
text-decoration: none;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
}
|
||||
#drupal-off-canvas button:hover,
|
||||
#drupal-off-canvas input[type="reset"]:hover,
|
||||
#drupal-off-canvas input[type="submit"]:hover,
|
||||
#drupal-off-canvas input[type="button"]:hover {
|
||||
background-image: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
#drupal-off-canvas button:active,
|
||||
#drupal-off-canvas input[type="reset"]:active,
|
||||
#drupal-off-canvas input[type="submit"]:active,
|
||||
#drupal-off-canvas input[type="button"]:active {
|
||||
background-image: none;
|
||||
box-shadow: none;
|
||||
border-color: grey;
|
||||
}
|
||||
#drupal-off-canvas button::-moz-focus-inner,
|
||||
#drupal-off-canvas input[type="reset"]::-moz-focus-inner,
|
||||
#drupal-off-canvas input[type="submit"]::-moz-focus-inner,
|
||||
#drupal-off-canvas input[type="button"]::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#drupal-off-canvas textarea,
|
||||
#drupal-off-canvas select,
|
||||
#drupal-off-canvas input[type="date"],
|
||||
#drupal-off-canvas input[type="datetime"],
|
||||
#drupal-off-canvas input[type="datetime-local"],
|
||||
#drupal-off-canvas input[type="email"],
|
||||
#drupal-off-canvas input[type="month"],
|
||||
#drupal-off-canvas input[type="number"],
|
||||
#drupal-off-canvas input[type="password"],
|
||||
#drupal-off-canvas input[type="search"],
|
||||
#drupal-off-canvas input[type="tel"],
|
||||
#drupal-off-canvas input[type="text"],
|
||||
#drupal-off-canvas input[type="time"],
|
||||
#drupal-off-canvas input[type="url"],
|
||||
#drupal-off-canvas input[type="week"] {
|
||||
height: auto;
|
||||
vertical-align: middle;
|
||||
border-radius: 0;
|
||||
}
|
||||
#drupal-off-canvas textarea[disabled],
|
||||
#drupal-off-canvas select[disabled],
|
||||
#drupal-off-canvas input[type="date"][disabled],
|
||||
#drupal-off-canvas input[type="datetime"][disabled],
|
||||
#drupal-off-canvas input[type="datetime-local"][disabled],
|
||||
#drupal-off-canvas input[type="email"][disabled],
|
||||
#drupal-off-canvas input[type="month"][disabled],
|
||||
#drupal-off-canvas input[type="number"][disabled],
|
||||
#drupal-off-canvas input[type="password"][disabled],
|
||||
#drupal-off-canvas input[type="search"][disabled],
|
||||
#drupal-off-canvas input[type="tel"][disabled],
|
||||
#drupal-off-canvas input[type="text"][disabled],
|
||||
#drupal-off-canvas input[type="time"][disabled],
|
||||
#drupal-off-canvas input[type="url"][disabled],
|
||||
#drupal-off-canvas input[type="week"][disabled] {
|
||||
background-color: grey;
|
||||
}
|
||||
#drupal-off-canvas input[type="hidden"] {
|
||||
visibility: hidden;
|
||||
}
|
||||
#drupal-off-canvas button[disabled],
|
||||
#drupal-off-canvas input[disabled],
|
||||
#drupal-off-canvas select[disabled],
|
||||
#drupal-off-canvas select[disabled] option,
|
||||
#drupal-off-canvas select[disabled] optgroup,
|
||||
#drupal-off-canvas textarea[disabled] {
|
||||
box-shadow: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
cursor: default;
|
||||
}
|
||||
#drupal-off-canvas input:placeholder,
|
||||
#drupal-off-canvas textarea:placeholder {
|
||||
color: grey;
|
||||
}
|
||||
#drupal-off-canvas textarea,
|
||||
#drupal-off-canvas select[size],
|
||||
#drupal-off-canvas select[multiple] {
|
||||
height: auto;
|
||||
}
|
||||
#drupal-off-canvas select[size="0"],
|
||||
#drupal-off-canvas select[size="1"] {
|
||||
height: auto;
|
||||
}
|
||||
#drupal-off-canvas textarea {
|
||||
min-height: 40px;
|
||||
overflow: auto;
|
||||
resize: vertical;
|
||||
width: 100%;
|
||||
}
|
||||
#drupal-off-canvas optgroup {
|
||||
color: black;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
}
|
||||
#drupal-off-canvas optgroup::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#drupal-off-canvas * button {
|
||||
background: none;
|
||||
border: 1px solid grey;
|
||||
color: black;
|
||||
padding: 0;
|
||||
text-decoration: none;
|
||||
overflow: visible;
|
||||
vertical-align: middle;
|
||||
width: auto;
|
||||
}
|
||||
#drupal-off-canvas * textarea,
|
||||
#drupal-off-canvas * select,
|
||||
#drupal-off-canvas *:not(div) textarea,
|
||||
#drupal-off-canvas *:not(div) select {
|
||||
background: white;
|
||||
border: 1px solid grey;
|
||||
color: black;
|
||||
padding: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* To standardize off-canvas selection color. */
|
||||
#drupal-off-canvas ::-moz-selection,
|
||||
#drupal-off-canvas ::selection {
|
||||
background-color: rgba(175, 175, 175, 0.5);
|
||||
color: inherit;
|
||||
}
|
89
2017/web/core/misc/dialog/off-canvas.table.css
Normal file
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
* @file
|
||||
* Visual styling for tables in the off-canvas dialog.
|
||||
*/
|
||||
|
||||
#drupal-off-canvas table * {
|
||||
font-family: "Lucida Grande", 'Lucida Sans Unicode', 'liberation sans', sans-serif;
|
||||
}
|
||||
#drupal-off-canvas table {
|
||||
display: table;
|
||||
width: 100%;
|
||||
min-width: calc(100% + 40px);
|
||||
/* Cancel out the padding of the parent to make the table full width. */
|
||||
margin: 0 -20px -10px -20px;
|
||||
border: 0;
|
||||
border-collapse: collapse;
|
||||
font-size: 12px;
|
||||
color: #ddd;
|
||||
}
|
||||
#drupal-off-canvas table thead {
|
||||
display: table-header-group;
|
||||
}
|
||||
#drupal-off-canvas table tbody {
|
||||
display: table-row-group;
|
||||
}
|
||||
#drupal-off-canvas tr {
|
||||
display: table-row;
|
||||
}
|
||||
#drupal-off-canvas tr:hover td {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#drupal-off-canvas td,
|
||||
#drupal-off-canvas th {
|
||||
display: table-cell;
|
||||
height: auto;
|
||||
width: auto;
|
||||
padding: 2px 8px;
|
||||
vertical-align: middle;
|
||||
border-bottom: 1px solid #777;
|
||||
background-color: transparent;
|
||||
}
|
||||
[dir="rtl"] #drupal-off-canvas th,
|
||||
[dir="rtl"] #drupal-off-canvas td {
|
||||
text-align: right;
|
||||
}
|
||||
#drupal-off-canvas th {
|
||||
font-weight: bold;
|
||||
}
|
||||
#drupal-off-canvas th.checkbox,
|
||||
#drupal-off-canvas td.checkbox {
|
||||
width: 20px;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
#drupal-off-canvas div.checkbox.menu-enabled {
|
||||
position: static;
|
||||
display: inline;
|
||||
width: auto;
|
||||
}
|
||||
#drupal-off-canvas th:first-child,
|
||||
#drupal-off-canvas td:first-child {
|
||||
width: 150px;
|
||||
}
|
||||
/* For lack of a better class, using this to grab the operations th. */
|
||||
#drupal-off-canvas .tabledrag-has-colspan {
|
||||
text-align: right;
|
||||
padding-right: 20px;
|
||||
}
|
||||
#drupal-off-canvas td {
|
||||
padding: 6px 8px;
|
||||
color: #ddd;
|
||||
}
|
||||
/* Hide overflow with ellipsis for links. */
|
||||
#drupal-off-canvas td a {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
background: transparent;
|
||||
}
|
||||
#drupal-off-canvas tr td:first-child,
|
||||
#drupal-off-canvas tr th:first-child {
|
||||
padding-left: 20px; /* LTR */
|
||||
}
|
||||
[dir="rtl"] #drupal-off-canvas tr td:first-child,
|
||||
[dir="rtl"] #drupal-off-canvas tr th:first-child {
|
||||
padding-right: 20px;
|
||||
}
|
122
2017/web/core/misc/dialog/off-canvas.tabledrag.css
Normal file
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* @file
|
||||
* Table drag behavior for off-canvas dialog.
|
||||
*
|
||||
* @see tabledrag.js
|
||||
*/
|
||||
|
||||
#drupal-off-canvas .drag {
|
||||
cursor: move;
|
||||
}
|
||||
#drupal-off-canvas tr.region-title {
|
||||
font-weight: normal;
|
||||
}
|
||||
#drupal-off-canvas table .region-message {
|
||||
color: #fff;
|
||||
}
|
||||
#drupal-off-canvas table .region-populated {
|
||||
display: none;
|
||||
}
|
||||
#drupal-off-canvas .add-new .tabledrag-changed {
|
||||
display: none;
|
||||
}
|
||||
#drupal-off-canvas .draggable a.tabledrag-handle {
|
||||
background-image: none;
|
||||
margin: 0 5px 0 0;
|
||||
height: auto;
|
||||
min-width: 20px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
float: left; /* LTR */
|
||||
text-decoration: none;
|
||||
cursor: move;
|
||||
}
|
||||
[dir="rtl"] #drupal-off-canvas .draggable a.tabledrag-handle {
|
||||
float: right;
|
||||
margin-right: 0;
|
||||
margin-left: 5px;
|
||||
}
|
||||
#drupal-off-canvas a.tabledrag-handle .handle {
|
||||
/* Use lighter drag icon against dark background. */
|
||||
background-color: transparent;
|
||||
background-image: url(../icons/bebebe/move.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: auto;
|
||||
}
|
||||
#drupal-off-canvas .draggable a.tabledrag-handle:hover .handle,
|
||||
#drupal-off-canvas .draggable a.tabledrag-handle:focus .handle {
|
||||
background-image: url(../icons/787878/move.svg);
|
||||
text-decoration: none;
|
||||
}
|
||||
#drupal-off-canvas tr td {
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
#drupal-off-canvas tr td abbr {
|
||||
margin-left: 5px; /* LTR */
|
||||
}
|
||||
|
||||
[dir="rtl"] #drupal-off-canvas tr td abbr {
|
||||
margin-left: 0;
|
||||
margin-right: 5px;
|
||||
}
|
||||
#drupal-off-canvas tr:hover td {
|
||||
background: #222;
|
||||
}
|
||||
#drupal-off-canvas tr.drag td {
|
||||
background: #111;
|
||||
}
|
||||
#drupal-off-canvas tr.drag-previous td {
|
||||
background: #000;
|
||||
}
|
||||
#drupal-off-canvas tr.drag-previous:hover td {
|
||||
background: #222;
|
||||
}
|
||||
body div.tabledrag-changed-warning {
|
||||
margin-bottom: 0.5em;
|
||||
font-size: 14px;
|
||||
}
|
||||
#drupal-off-canvas .touchevents .draggable td {
|
||||
padding: 0 10px;
|
||||
}
|
||||
#drupal-off-canvas .touchevents .draggable .menu-item__link {
|
||||
display: inline-block;
|
||||
padding: 10px 0;
|
||||
}
|
||||
#drupal-off-canvas .touchevents a.tabledrag-handle {
|
||||
height: 44px;
|
||||
width: 40px;
|
||||
}
|
||||
#drupal-off-canvas .touchevents a.tabledrag-handle .handle {
|
||||
background-position: 40% 19px; /* LTR */
|
||||
height: 21px;
|
||||
}
|
||||
[dir="rtl"] #drupal-off-canvas .touch a.tabledrag-handle .handle {
|
||||
background-position: right 40% top 19px;
|
||||
}
|
||||
#drupal-off-canvas .touchevents .draggable.drag a.tabledrag-handle .handle {
|
||||
background-position: 50% -32px;
|
||||
}
|
||||
#drupal-off-canvas .tabledrag-toggle-weight-wrapper {
|
||||
padding-top: 10px;
|
||||
text-align: right; /* LTR */
|
||||
}
|
||||
[dir="rtl"] #drupal-off-canvas .tabledrag-toggle-weight-wrapper {
|
||||
text-align: left;
|
||||
}
|
||||
#drupal-off-canvas .indentation {
|
||||
float: left; /* LTR */
|
||||
height: auto;
|
||||
margin: 0 3px 0 -10px; /* LTR */
|
||||
padding: 0 0 0 10px; /* LTR */
|
||||
width: auto;
|
||||
}
|
||||
[dir="rtl"] #drupal-off-canvas .indentation {
|
||||
float: right;
|
||||
margin: 0 -10px 0 3px;
|
||||
padding: 0 10px 0 0;
|
||||
}
|
100
2017/web/core/misc/dialog/off-canvas.theme.css
Normal file
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* @file
|
||||
* Styling for the off-canvas ui dialog. Including overrides for jQuery UI.
|
||||
*/
|
||||
|
||||
/* Style the dialog-off-canvas container. */
|
||||
.ui-dialog.ui-dialog-off-canvas {
|
||||
background: #444;
|
||||
border-radius: 0;
|
||||
box-shadow: 0 0 4px 2px rgba(0, 0, 0, 0.3333);
|
||||
padding: 0;
|
||||
color: #ddd;
|
||||
/* Layer the dialog just under the toolbar. */
|
||||
z-index: 501;
|
||||
}
|
||||
.ui-widget.ui-dialog.ui-dialog-off-canvas {
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
/* Style the off-canvas dialog header. */
|
||||
.ui-dialog.ui-dialog-off-canvas .ui-dialog-titlebar {
|
||||
padding: 1em;
|
||||
background: #2d2d2d;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #000;
|
||||
border-radius: 0;
|
||||
font-weight: normal;
|
||||
color: #fff;
|
||||
}
|
||||
/* Hide the default jQuery UI dialog close button. */
|
||||
.ui-dialog.ui-dialog-off-canvas .ui-dialog-titlebar-close .ui-icon {
|
||||
visibility: hidden;
|
||||
}
|
||||
.ui-dialog.ui-dialog-off-canvas .ui-dialog-titlebar-close {
|
||||
background-image: url(../icons/bebebe/ex.svg);
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-color: transparent;
|
||||
border: 3px solid transparent;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
position: absolute;
|
||||
top: calc(50% - 6px);
|
||||
right: 1em;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
.ui-dialog.ui-dialog-off-canvas .ui-dialog-titlebar-close:hover,
|
||||
.ui-dialog.ui-dialog-off-canvas .ui-dialog-titlebar-close:focus {
|
||||
background-image: url(../icons/ffffff/ex.svg);
|
||||
border: 3px solid #fff;
|
||||
}
|
||||
[dir="rtl"] .ui-dialog.ui-dialog-off-canvas .ui-dialog-titlebar-close {
|
||||
left: 1em;
|
||||
right: auto;
|
||||
}
|
||||
.ui-dialog.ui-dialog-off-canvas .ui-dialog-title {
|
||||
margin: 0;
|
||||
/* Push the text away from the icon. */
|
||||
padding-left: 30px; /* LTR */
|
||||
padding-right: 0; /* LTR */
|
||||
/* Ensure that long titles do not overlap the close button. */
|
||||
max-width: 210px;
|
||||
font-size: 16px;
|
||||
font-family: "Lucida Grande", 'Lucida Sans Unicode', 'liberation sans', sans-serif;
|
||||
text-align: left; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .ui-dialog.ui-dialog-off-canvas .ui-dialog-title {
|
||||
float: right;
|
||||
text-align: right;
|
||||
padding-left: 0;
|
||||
padding-right: 30px;
|
||||
}
|
||||
.ui-dialog.ui-dialog-off-canvas .ui-dialog-title:before {
|
||||
background: transparent url(../icons/ffffff/pencil.svg) no-repeat scroll center center;
|
||||
background-size: 100% auto;
|
||||
content: '';
|
||||
display: block;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: 1em; /* LTR */
|
||||
top: 0;
|
||||
width: 20px;
|
||||
}
|
||||
[dir="rtl"] .ui-dialog.ui-dialog-off-canvas .ui-dialog-title:before {
|
||||
left: auto;
|
||||
right: 1em;
|
||||
}
|
||||
|
||||
/* Override default styling from jQuery UI. */
|
||||
#drupal-off-canvas .ui-state-default,
|
||||
#drupal-off-canvas .ui-widget-content .ui-state-default,
|
||||
#drupal-off-canvas .ui-widget-header .ui-state-default {
|
||||
border: 0;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
#drupal-off-canvas .ui-widget-content a {
|
||||
color: #85bef4;
|
||||
}
|
224
2017/web/core/misc/displace.es6.js
Normal file
|
@ -0,0 +1,224 @@
|
|||
/**
|
||||
* @file
|
||||
* Manages elements that can offset the size of the viewport.
|
||||
*
|
||||
* Measures and reports viewport offset dimensions from elements like the
|
||||
* toolbar that can potentially displace the positioning of other elements.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {object} Drupal~displaceOffset
|
||||
*
|
||||
* @prop {number} top
|
||||
* @prop {number} left
|
||||
* @prop {number} right
|
||||
* @prop {number} bottom
|
||||
*/
|
||||
|
||||
/**
|
||||
* Triggers when layout of the page changes.
|
||||
*
|
||||
* This is used to position fixed element on the page during page resize and
|
||||
* Toolbar toggling.
|
||||
*
|
||||
* @event drupalViewportOffsetChange
|
||||
*/
|
||||
|
||||
(function($, Drupal, debounce) {
|
||||
/**
|
||||
* @name Drupal.displace.offsets
|
||||
*
|
||||
* @type {Drupal~displaceOffset}
|
||||
*/
|
||||
let offsets = {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates displacement for element based on its dimensions and placement.
|
||||
*
|
||||
* @param {HTMLElement} el
|
||||
* The jQuery element whose dimensions and placement will be measured.
|
||||
*
|
||||
* @param {string} edge
|
||||
* The name of the edge of the viewport that the element is associated
|
||||
* with.
|
||||
*
|
||||
* @return {number}
|
||||
* The viewport displacement distance for the requested edge.
|
||||
*/
|
||||
function getRawOffset(el, edge) {
|
||||
const $el = $(el);
|
||||
const documentElement = document.documentElement;
|
||||
let displacement = 0;
|
||||
const horizontal = edge === 'left' || edge === 'right';
|
||||
// Get the offset of the element itself.
|
||||
let placement = $el.offset()[horizontal ? 'left' : 'top'];
|
||||
// Subtract scroll distance from placement to get the distance
|
||||
// to the edge of the viewport.
|
||||
placement -=
|
||||
window[`scroll${horizontal ? 'X' : 'Y'}`] ||
|
||||
document.documentElement[`scroll${horizontal ? 'Left' : 'Top'}`] ||
|
||||
0;
|
||||
// Find the displacement value according to the edge.
|
||||
switch (edge) {
|
||||
// Left and top elements displace as a sum of their own offset value
|
||||
// plus their size.
|
||||
case 'top':
|
||||
// Total displacement is the sum of the elements placement and size.
|
||||
displacement = placement + $el.outerHeight();
|
||||
break;
|
||||
|
||||
case 'left':
|
||||
// Total displacement is the sum of the elements placement and size.
|
||||
displacement = placement + $el.outerWidth();
|
||||
break;
|
||||
|
||||
// Right and bottom elements displace according to their left and
|
||||
// top offset. Their size isn't important.
|
||||
case 'bottom':
|
||||
displacement = documentElement.clientHeight - placement;
|
||||
break;
|
||||
|
||||
case 'right':
|
||||
displacement = documentElement.clientWidth - placement;
|
||||
break;
|
||||
|
||||
default:
|
||||
displacement = 0;
|
||||
}
|
||||
return displacement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a specific edge's offset.
|
||||
*
|
||||
* Any element with the attribute data-offset-{edge} e.g. data-offset-top will
|
||||
* be considered in the viewport offset calculations. If the attribute has a
|
||||
* numeric value, that value will be used. If no value is provided, one will
|
||||
* be calculated using the element's dimensions and placement.
|
||||
*
|
||||
* @function Drupal.displace.calculateOffset
|
||||
*
|
||||
* @param {string} edge
|
||||
* The name of the edge to calculate. Can be 'top', 'right',
|
||||
* 'bottom' or 'left'.
|
||||
*
|
||||
* @return {number}
|
||||
* The viewport displacement distance for the requested edge.
|
||||
*/
|
||||
function calculateOffset(edge) {
|
||||
let edgeOffset = 0;
|
||||
const displacingElements = document.querySelectorAll(
|
||||
`[data-offset-${edge}]`,
|
||||
);
|
||||
const n = displacingElements.length;
|
||||
for (let i = 0; i < n; i++) {
|
||||
const el = displacingElements[i];
|
||||
// If the element is not visible, do consider its dimensions.
|
||||
if (el.style.display === 'none') {
|
||||
continue;
|
||||
}
|
||||
// If the offset data attribute contains a displacing value, use it.
|
||||
let displacement = parseInt(el.getAttribute(`data-offset-${edge}`), 10);
|
||||
// If the element's offset data attribute exits
|
||||
// but is not a valid number then get the displacement
|
||||
// dimensions directly from the element.
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
if (isNaN(displacement)) {
|
||||
displacement = getRawOffset(el, edge);
|
||||
}
|
||||
// If the displacement value is larger than the current value for this
|
||||
// edge, use the displacement value.
|
||||
edgeOffset = Math.max(edgeOffset, displacement);
|
||||
}
|
||||
|
||||
return edgeOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the viewport offsets.
|
||||
*
|
||||
* @return {Drupal~displaceOffset}
|
||||
* An object whose keys are the for sides an element -- top, right, bottom
|
||||
* and left. The value of each key is the viewport displacement distance for
|
||||
* that edge.
|
||||
*/
|
||||
function calculateOffsets() {
|
||||
return {
|
||||
top: calculateOffset('top'),
|
||||
right: calculateOffset('right'),
|
||||
bottom: calculateOffset('bottom'),
|
||||
left: calculateOffset('left'),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs listeners of the current offset dimensions.
|
||||
*
|
||||
* @function Drupal.displace
|
||||
*
|
||||
* @prop {Drupal~displaceOffset} offsets
|
||||
*
|
||||
* @param {bool} [broadcast]
|
||||
* When true or undefined, causes the recalculated offsets values to be
|
||||
* broadcast to listeners.
|
||||
*
|
||||
* @return {Drupal~displaceOffset}
|
||||
* An object whose keys are the for sides an element -- top, right, bottom
|
||||
* and left. The value of each key is the viewport displacement distance for
|
||||
* that edge.
|
||||
*
|
||||
* @fires event:drupalViewportOffsetChange
|
||||
*/
|
||||
function displace(broadcast) {
|
||||
offsets = calculateOffsets();
|
||||
Drupal.displace.offsets = offsets;
|
||||
if (typeof broadcast === 'undefined' || broadcast) {
|
||||
$(document).trigger('drupalViewportOffsetChange', offsets);
|
||||
}
|
||||
return offsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a resize handler on the window.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.drupalDisplace = {
|
||||
attach() {
|
||||
// Mark this behavior as processed on the first pass.
|
||||
if (this.displaceProcessed) {
|
||||
return;
|
||||
}
|
||||
this.displaceProcessed = true;
|
||||
|
||||
$(window).on('resize.drupalDisplace', debounce(displace, 200));
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign the displace function to a property of the Drupal global object.
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
Drupal.displace = displace;
|
||||
$.extend(Drupal.displace, {
|
||||
/**
|
||||
* Expose offsets to other scripts to avoid having to recalculate offsets.
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
offsets,
|
||||
|
||||
/**
|
||||
* Expose method to compute a single edge offsets.
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
calculateOffset,
|
||||
});
|
||||
})(jQuery, Drupal, Drupal.debounce);
|
107
2017/web/core/misc/displace.js
Normal file
|
@ -0,0 +1,107 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal, debounce) {
|
||||
var offsets = {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0
|
||||
};
|
||||
|
||||
function getRawOffset(el, edge) {
|
||||
var $el = $(el);
|
||||
var documentElement = document.documentElement;
|
||||
var displacement = 0;
|
||||
var horizontal = edge === 'left' || edge === 'right';
|
||||
|
||||
var placement = $el.offset()[horizontal ? 'left' : 'top'];
|
||||
|
||||
placement -= window['scroll' + (horizontal ? 'X' : 'Y')] || document.documentElement['scroll' + (horizontal ? 'Left' : 'Top')] || 0;
|
||||
|
||||
switch (edge) {
|
||||
case 'top':
|
||||
displacement = placement + $el.outerHeight();
|
||||
break;
|
||||
|
||||
case 'left':
|
||||
displacement = placement + $el.outerWidth();
|
||||
break;
|
||||
|
||||
case 'bottom':
|
||||
displacement = documentElement.clientHeight - placement;
|
||||
break;
|
||||
|
||||
case 'right':
|
||||
displacement = documentElement.clientWidth - placement;
|
||||
break;
|
||||
|
||||
default:
|
||||
displacement = 0;
|
||||
}
|
||||
return displacement;
|
||||
}
|
||||
|
||||
function calculateOffset(edge) {
|
||||
var edgeOffset = 0;
|
||||
var displacingElements = document.querySelectorAll('[data-offset-' + edge + ']');
|
||||
var n = displacingElements.length;
|
||||
for (var i = 0; i < n; i++) {
|
||||
var el = displacingElements[i];
|
||||
|
||||
if (el.style.display === 'none') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var displacement = parseInt(el.getAttribute('data-offset-' + edge), 10);
|
||||
|
||||
if (isNaN(displacement)) {
|
||||
displacement = getRawOffset(el, edge);
|
||||
}
|
||||
|
||||
edgeOffset = Math.max(edgeOffset, displacement);
|
||||
}
|
||||
|
||||
return edgeOffset;
|
||||
}
|
||||
|
||||
function calculateOffsets() {
|
||||
return {
|
||||
top: calculateOffset('top'),
|
||||
right: calculateOffset('right'),
|
||||
bottom: calculateOffset('bottom'),
|
||||
left: calculateOffset('left')
|
||||
};
|
||||
}
|
||||
|
||||
function displace(broadcast) {
|
||||
offsets = calculateOffsets();
|
||||
Drupal.displace.offsets = offsets;
|
||||
if (typeof broadcast === 'undefined' || broadcast) {
|
||||
$(document).trigger('drupalViewportOffsetChange', offsets);
|
||||
}
|
||||
return offsets;
|
||||
}
|
||||
|
||||
Drupal.behaviors.drupalDisplace = {
|
||||
attach: function attach() {
|
||||
if (this.displaceProcessed) {
|
||||
return;
|
||||
}
|
||||
this.displaceProcessed = true;
|
||||
|
||||
$(window).on('resize.drupalDisplace', debounce(displace, 200));
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.displace = displace;
|
||||
$.extend(Drupal.displace, {
|
||||
offsets: offsets,
|
||||
|
||||
calculateOffset: calculateOffset
|
||||
});
|
||||
})(jQuery, Drupal, Drupal.debounce);
|
164
2017/web/core/misc/dropbutton/dropbutton.css
Normal file
|
@ -0,0 +1,164 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Base styles for dropbuttons.
|
||||
*/
|
||||
|
||||
/**
|
||||
* When a dropbutton has only one option, it is simply a button.
|
||||
*/
|
||||
.dropbutton-wrapper,
|
||||
.dropbutton-wrapper div {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.js .dropbutton-wrapper,
|
||||
.js .dropbutton-widget {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.js .dropbutton-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Splitbuttons */
|
||||
@media screen and (min-width: 600px) {
|
||||
.form-actions .dropbutton-wrapper {
|
||||
float: left; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .form-actions .dropbutton-wrapper {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.js .form-actions .dropbutton-widget {
|
||||
position: static;
|
||||
}
|
||||
.js td .dropbutton-widget {
|
||||
position: absolute;
|
||||
}
|
||||
.js td .dropbutton-wrapper {
|
||||
min-height: 2em;
|
||||
}
|
||||
.js td .dropbutton-multiple {
|
||||
padding-right: 10em; /* LTR */
|
||||
margin-right: 2em; /* LTR */
|
||||
max-width: 100%;
|
||||
}
|
||||
[dir="rtl"].js td .dropbutton-multiple {
|
||||
padding-right: 0;
|
||||
margin-right: 0;
|
||||
padding-left: 10em;
|
||||
margin-left: 2em;
|
||||
}
|
||||
.js td .dropbutton-multiple .dropbutton-action a,
|
||||
.js td .dropbutton-multiple .dropbutton-action input,
|
||||
.js td .dropbutton-multiple .dropbutton-action button {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* UL styles are over-scoped in core, so this selector needs weight parity. */
|
||||
.js .dropbutton-widget .dropbutton {
|
||||
list-style-image: none;
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
.js .dropbutton li,
|
||||
.js .dropbutton a {
|
||||
display: block;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.js .dropbutton li:hover,
|
||||
.js .dropbutton li:focus,
|
||||
.js .dropbutton a:hover,
|
||||
.js .dropbutton a:focus {
|
||||
outline: initial;
|
||||
}
|
||||
|
||||
/**
|
||||
* The dropbutton styling.
|
||||
*
|
||||
* A dropbutton is a widget that displays a list of action links as a button
|
||||
* with a primary action. Secondary actions are hidden behind a click on a
|
||||
* twisty arrow.
|
||||
*
|
||||
* The arrow is created using border on a zero-width, zero-height span.
|
||||
* The arrow inherits the link color, but can be overridden with border colors.
|
||||
*/
|
||||
.js .dropbutton-multiple .dropbutton-widget {
|
||||
padding-right: 2em; /* LTR */
|
||||
}
|
||||
.js[dir="rtl"] .dropbutton-multiple .dropbutton-widget {
|
||||
padding-left: 2em;
|
||||
padding-right: 0;
|
||||
}
|
||||
.dropbutton-multiple.open,
|
||||
.dropbutton-multiple.open .dropbutton-widget {
|
||||
max-width: none;
|
||||
}
|
||||
.dropbutton-multiple.open {
|
||||
z-index: 100;
|
||||
}
|
||||
.dropbutton-multiple .dropbutton .secondary-action {
|
||||
display: none;
|
||||
}
|
||||
.dropbutton-multiple.open .dropbutton .secondary-action {
|
||||
display: block;
|
||||
}
|
||||
.dropbutton-toggle {
|
||||
bottom: 0;
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 0; /* LTR */
|
||||
text-indent: 110%;
|
||||
top: 0;
|
||||
white-space: nowrap;
|
||||
width: 2em;
|
||||
}
|
||||
[dir="rtl"] .dropbutton-toggle {
|
||||
left: 0;
|
||||
right: auto;
|
||||
}
|
||||
.dropbutton-toggle button {
|
||||
background: none;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.dropbutton-toggle button:hover,
|
||||
.dropbutton-toggle button:focus {
|
||||
outline: initial;
|
||||
}
|
||||
.dropbutton-arrow {
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: transparent;
|
||||
border-right-color: transparent;
|
||||
border-style: solid;
|
||||
border-width: 0.3333em 0.3333em 0;
|
||||
display: block;
|
||||
height: 0;
|
||||
line-height: 0;
|
||||
position: absolute;
|
||||
right: 40%; /* 0.6667em; */ /* LTR */
|
||||
top: 50%;
|
||||
margin-top: -0.1666em;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
[dir="rtl"] .dropbutton-arrow {
|
||||
left: 0.6667em;
|
||||
right: auto;
|
||||
}
|
||||
.dropbutton-multiple.open .dropbutton-arrow {
|
||||
border-bottom: 0.3333em solid;
|
||||
border-top-color: transparent;
|
||||
top: 0.6667em;
|
||||
}
|
243
2017/web/core/misc/dropbutton/dropbutton.es6.js
Normal file
|
@ -0,0 +1,243 @@
|
|||
/**
|
||||
* @file
|
||||
* Dropbutton feature.
|
||||
*/
|
||||
|
||||
(function($, Drupal) {
|
||||
/**
|
||||
* A DropButton presents an HTML list as a button with a primary action.
|
||||
*
|
||||
* All secondary actions beyond the first in the list are presented in a
|
||||
* dropdown list accessible through a toggle arrow associated with the button.
|
||||
*
|
||||
* @constructor Drupal.DropButton
|
||||
*
|
||||
* @param {HTMLElement} dropbutton
|
||||
* A DOM element.
|
||||
* @param {object} settings
|
||||
* A list of options including:
|
||||
* @param {string} settings.title
|
||||
* The text inside the toggle link element. This text is hidden
|
||||
* from visual UAs.
|
||||
*/
|
||||
function DropButton(dropbutton, settings) {
|
||||
// Merge defaults with settings.
|
||||
const options = $.extend(
|
||||
{ title: Drupal.t('List additional actions') },
|
||||
settings,
|
||||
);
|
||||
const $dropbutton = $(dropbutton);
|
||||
|
||||
/**
|
||||
* @type {jQuery}
|
||||
*/
|
||||
this.$dropbutton = $dropbutton;
|
||||
|
||||
/**
|
||||
* @type {jQuery}
|
||||
*/
|
||||
this.$list = $dropbutton.find('.dropbutton');
|
||||
|
||||
/**
|
||||
* Find actions and mark them.
|
||||
*
|
||||
* @type {jQuery}
|
||||
*/
|
||||
this.$actions = this.$list.find('li').addClass('dropbutton-action');
|
||||
|
||||
// Add the special dropdown only if there are hidden actions.
|
||||
if (this.$actions.length > 1) {
|
||||
// Identify the first element of the collection.
|
||||
const $primary = this.$actions.slice(0, 1);
|
||||
// Identify the secondary actions.
|
||||
const $secondary = this.$actions.slice(1);
|
||||
$secondary.addClass('secondary-action');
|
||||
// Add toggle link.
|
||||
$primary.after(Drupal.theme('dropbuttonToggle', options));
|
||||
// Bind mouse events.
|
||||
this.$dropbutton.addClass('dropbutton-multiple').on({
|
||||
/**
|
||||
* Adds a timeout to close the dropdown on mouseleave.
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
'mouseleave.dropbutton': $.proxy(this.hoverOut, this),
|
||||
|
||||
/**
|
||||
* Clears timeout when mouseout of the dropdown.
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
'mouseenter.dropbutton': $.proxy(this.hoverIn, this),
|
||||
|
||||
/**
|
||||
* Similar to mouseleave/mouseenter, but for keyboard navigation.
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
'focusout.dropbutton': $.proxy(this.focusOut, this),
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
'focusin.dropbutton': $.proxy(this.focusIn, this),
|
||||
});
|
||||
} else {
|
||||
this.$dropbutton.addClass('dropbutton-single');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegated callback for opening and closing dropbutton secondary actions.
|
||||
*
|
||||
* @function Drupal.DropButton~dropbuttonClickHandler
|
||||
*
|
||||
* @param {jQuery.Event} e
|
||||
* The event triggered.
|
||||
*/
|
||||
function dropbuttonClickHandler(e) {
|
||||
e.preventDefault();
|
||||
$(e.target)
|
||||
.closest('.dropbutton-wrapper')
|
||||
.toggleClass('open');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process elements with the .dropbutton class on page load.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches dropButton behaviors.
|
||||
*/
|
||||
Drupal.behaviors.dropButton = {
|
||||
attach(context, settings) {
|
||||
const $dropbuttons = $(context)
|
||||
.find('.dropbutton-wrapper')
|
||||
.once('dropbutton');
|
||||
if ($dropbuttons.length) {
|
||||
// Adds the delegated handler that will toggle dropdowns on click.
|
||||
const $body = $('body').once('dropbutton-click');
|
||||
if ($body.length) {
|
||||
$body.on('click', '.dropbutton-toggle', dropbuttonClickHandler);
|
||||
}
|
||||
// Initialize all buttons.
|
||||
const il = $dropbuttons.length;
|
||||
for (let i = 0; i < il; i++) {
|
||||
DropButton.dropbuttons.push(
|
||||
new DropButton($dropbuttons[i], settings.dropbutton),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Extend the DropButton constructor.
|
||||
*/
|
||||
$.extend(
|
||||
DropButton,
|
||||
/** @lends Drupal.DropButton */ {
|
||||
/**
|
||||
* Store all processed DropButtons.
|
||||
*
|
||||
* @type {Array.<Drupal.DropButton>}
|
||||
*/
|
||||
dropbuttons: [],
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Extend the DropButton prototype.
|
||||
*/
|
||||
$.extend(
|
||||
DropButton.prototype,
|
||||
/** @lends Drupal.DropButton# */ {
|
||||
/**
|
||||
* Toggle the dropbutton open and closed.
|
||||
*
|
||||
* @param {bool} [show]
|
||||
* Force the dropbutton to open by passing true or to close by
|
||||
* passing false.
|
||||
*/
|
||||
toggle(show) {
|
||||
const isBool = typeof show === 'boolean';
|
||||
show = isBool ? show : !this.$dropbutton.hasClass('open');
|
||||
this.$dropbutton.toggleClass('open', show);
|
||||
},
|
||||
|
||||
/**
|
||||
* @method
|
||||
*/
|
||||
hoverIn() {
|
||||
// Clear any previous timer we were using.
|
||||
if (this.timerID) {
|
||||
window.clearTimeout(this.timerID);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @method
|
||||
*/
|
||||
hoverOut() {
|
||||
// Wait half a second before closing.
|
||||
this.timerID = window.setTimeout($.proxy(this, 'close'), 500);
|
||||
},
|
||||
|
||||
/**
|
||||
* @method
|
||||
*/
|
||||
open() {
|
||||
this.toggle(true);
|
||||
},
|
||||
|
||||
/**
|
||||
* @method
|
||||
*/
|
||||
close() {
|
||||
this.toggle(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {jQuery.Event} e
|
||||
* The event triggered.
|
||||
*/
|
||||
focusOut(e) {
|
||||
this.hoverOut.call(this, e);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {jQuery.Event} e
|
||||
* The event triggered.
|
||||
*/
|
||||
focusIn(e) {
|
||||
this.hoverIn.call(this, e);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
$.extend(
|
||||
Drupal.theme,
|
||||
/** @lends Drupal.theme */ {
|
||||
/**
|
||||
* A toggle is an interactive element often bound to a click handler.
|
||||
*
|
||||
* @param {object} options
|
||||
* Options object.
|
||||
* @param {string} [options.title]
|
||||
* The button text.
|
||||
*
|
||||
* @return {string}
|
||||
* A string representing a DOM fragment.
|
||||
*/
|
||||
dropbuttonToggle(options) {
|
||||
return `<li class="dropbutton-toggle"><button type="button"><span class="dropbutton-arrow"><span class="visually-hidden">${
|
||||
options.title
|
||||
}</span></span></button></li>`;
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// Expose constructor in the public space.
|
||||
Drupal.DropButton = DropButton;
|
||||
})(jQuery, Drupal);
|
102
2017/web/core/misc/dropbutton/dropbutton.js
Normal file
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal) {
|
||||
function DropButton(dropbutton, settings) {
|
||||
var options = $.extend({ title: Drupal.t('List additional actions') }, settings);
|
||||
var $dropbutton = $(dropbutton);
|
||||
|
||||
this.$dropbutton = $dropbutton;
|
||||
|
||||
this.$list = $dropbutton.find('.dropbutton');
|
||||
|
||||
this.$actions = this.$list.find('li').addClass('dropbutton-action');
|
||||
|
||||
if (this.$actions.length > 1) {
|
||||
var $primary = this.$actions.slice(0, 1);
|
||||
|
||||
var $secondary = this.$actions.slice(1);
|
||||
$secondary.addClass('secondary-action');
|
||||
|
||||
$primary.after(Drupal.theme('dropbuttonToggle', options));
|
||||
|
||||
this.$dropbutton.addClass('dropbutton-multiple').on({
|
||||
'mouseleave.dropbutton': $.proxy(this.hoverOut, this),
|
||||
|
||||
'mouseenter.dropbutton': $.proxy(this.hoverIn, this),
|
||||
|
||||
'focusout.dropbutton': $.proxy(this.focusOut, this),
|
||||
|
||||
'focusin.dropbutton': $.proxy(this.focusIn, this)
|
||||
});
|
||||
} else {
|
||||
this.$dropbutton.addClass('dropbutton-single');
|
||||
}
|
||||
}
|
||||
|
||||
function dropbuttonClickHandler(e) {
|
||||
e.preventDefault();
|
||||
$(e.target).closest('.dropbutton-wrapper').toggleClass('open');
|
||||
}
|
||||
|
||||
Drupal.behaviors.dropButton = {
|
||||
attach: function attach(context, settings) {
|
||||
var $dropbuttons = $(context).find('.dropbutton-wrapper').once('dropbutton');
|
||||
if ($dropbuttons.length) {
|
||||
var $body = $('body').once('dropbutton-click');
|
||||
if ($body.length) {
|
||||
$body.on('click', '.dropbutton-toggle', dropbuttonClickHandler);
|
||||
}
|
||||
|
||||
var il = $dropbuttons.length;
|
||||
for (var i = 0; i < il; i++) {
|
||||
DropButton.dropbuttons.push(new DropButton($dropbuttons[i], settings.dropbutton));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.extend(DropButton, {
|
||||
dropbuttons: []
|
||||
});
|
||||
|
||||
$.extend(DropButton.prototype, {
|
||||
toggle: function toggle(show) {
|
||||
var isBool = typeof show === 'boolean';
|
||||
show = isBool ? show : !this.$dropbutton.hasClass('open');
|
||||
this.$dropbutton.toggleClass('open', show);
|
||||
},
|
||||
hoverIn: function hoverIn() {
|
||||
if (this.timerID) {
|
||||
window.clearTimeout(this.timerID);
|
||||
}
|
||||
},
|
||||
hoverOut: function hoverOut() {
|
||||
this.timerID = window.setTimeout($.proxy(this, 'close'), 500);
|
||||
},
|
||||
open: function open() {
|
||||
this.toggle(true);
|
||||
},
|
||||
close: function close() {
|
||||
this.toggle(false);
|
||||
},
|
||||
focusOut: function focusOut(e) {
|
||||
this.hoverOut.call(this, e);
|
||||
},
|
||||
focusIn: function focusIn(e) {
|
||||
this.hoverIn.call(this, e);
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(Drupal.theme, {
|
||||
dropbuttonToggle: function dropbuttonToggle(options) {
|
||||
return '<li class="dropbutton-toggle"><button type="button"><span class="dropbutton-arrow"><span class="visually-hidden">' + options.title + '</span></span></button></li>';
|
||||
}
|
||||
});
|
||||
|
||||
Drupal.DropButton = DropButton;
|
||||
})(jQuery, Drupal);
|
586
2017/web/core/misc/drupal.es6.js
Normal file
|
@ -0,0 +1,586 @@
|
|||
/**
|
||||
* @file
|
||||
* Defines the Drupal JavaScript API.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A jQuery object, typically the return value from a `$(selector)` call.
|
||||
*
|
||||
* Holds an HTMLElement or a collection of HTMLElements.
|
||||
*
|
||||
* @typedef {object} jQuery
|
||||
*
|
||||
* @prop {number} length=0
|
||||
* Number of elements contained in the jQuery object.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Variable generated by Drupal that holds all translated strings from PHP.
|
||||
*
|
||||
* Content of this variable is automatically created by Drupal when using the
|
||||
* Interface Translation module. It holds the translation of strings used on
|
||||
* the page.
|
||||
*
|
||||
* This variable is used to pass data from the backend to the frontend. Data
|
||||
* contained in `drupalSettings` is used during behavior initialization.
|
||||
*
|
||||
* @global
|
||||
*
|
||||
* @var {object} drupalTranslations
|
||||
*/
|
||||
|
||||
/**
|
||||
* Global Drupal object.
|
||||
*
|
||||
* All Drupal JavaScript APIs are contained in this namespace.
|
||||
*
|
||||
* @global
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
window.Drupal = { behaviors: {}, locale: {} };
|
||||
|
||||
// JavaScript should be made compatible with libraries other than jQuery by
|
||||
// wrapping it in an anonymous closure.
|
||||
(function(Drupal, drupalSettings, drupalTranslations) {
|
||||
/**
|
||||
* Helper to rethrow errors asynchronously.
|
||||
*
|
||||
* This way Errors bubbles up outside of the original callstack, making it
|
||||
* easier to debug errors in the browser.
|
||||
*
|
||||
* @param {Error|string} error
|
||||
* The error to be thrown.
|
||||
*/
|
||||
Drupal.throwError = function(error) {
|
||||
setTimeout(() => {
|
||||
throw error;
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom error thrown after attach/detach if one or more behaviors failed.
|
||||
* Initializes the JavaScript behaviors for page loads and Ajax requests.
|
||||
*
|
||||
* @callback Drupal~behaviorAttach
|
||||
*
|
||||
* @param {HTMLDocument|HTMLElement} context
|
||||
* An element to detach behaviors from.
|
||||
* @param {?object} settings
|
||||
* An object containing settings for the current context. It is rarely used.
|
||||
*
|
||||
* @see Drupal.attachBehaviors
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reverts and cleans up JavaScript behavior initialization.
|
||||
*
|
||||
* @callback Drupal~behaviorDetach
|
||||
*
|
||||
* @param {HTMLDocument|HTMLElement} context
|
||||
* An element to attach behaviors to.
|
||||
* @param {object} settings
|
||||
* An object containing settings for the current context.
|
||||
* @param {string} trigger
|
||||
* One of `'unload'`, `'move'`, or `'serialize'`.
|
||||
*
|
||||
* @see Drupal.detachBehaviors
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {object} Drupal~behavior
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Function run on page load and after an Ajax call.
|
||||
* @prop {Drupal~behaviorDetach} detach
|
||||
* Function run when content is serialized or removed from the page.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Holds all initialization methods.
|
||||
*
|
||||
* @namespace Drupal.behaviors
|
||||
*
|
||||
* @type {Object.<string, Drupal~behavior>}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines a behavior to be run during attach and detach phases.
|
||||
*
|
||||
* Attaches all registered behaviors to a page element.
|
||||
*
|
||||
* Behaviors are event-triggered actions that attach to page elements,
|
||||
* enhancing default non-JavaScript UIs. Behaviors are registered in the
|
||||
* {@link Drupal.behaviors} object using the method 'attach' and optionally
|
||||
* also 'detach'.
|
||||
*
|
||||
* {@link Drupal.attachBehaviors} is added below to the `jQuery.ready` event
|
||||
* and therefore runs on initial page load. Developers implementing Ajax in
|
||||
* their solutions should also call this function after new page content has
|
||||
* been loaded, feeding in an element to be processed, in order to attach all
|
||||
* behaviors to the new content.
|
||||
*
|
||||
* Behaviors should use `var elements =
|
||||
* $(context).find(selector).once('behavior-name');` to ensure the behavior is
|
||||
* attached only once to a given element. (Doing so enables the reprocessing
|
||||
* of given elements, which may be needed on occasion despite the ability to
|
||||
* limit behavior attachment to a particular element.)
|
||||
*
|
||||
* @example
|
||||
* Drupal.behaviors.behaviorName = {
|
||||
* attach: function (context, settings) {
|
||||
* // ...
|
||||
* },
|
||||
* detach: function (context, settings, trigger) {
|
||||
* // ...
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* @param {HTMLDocument|HTMLElement} [context=document]
|
||||
* An element to attach behaviors to.
|
||||
* @param {object} [settings=drupalSettings]
|
||||
* An object containing settings for the current context. If none is given,
|
||||
* the global {@link drupalSettings} object is used.
|
||||
*
|
||||
* @see Drupal~behaviorAttach
|
||||
* @see Drupal.detachBehaviors
|
||||
*
|
||||
* @throws {Drupal~DrupalBehaviorError}
|
||||
*/
|
||||
Drupal.attachBehaviors = function(context, settings) {
|
||||
context = context || document;
|
||||
settings = settings || drupalSettings;
|
||||
const behaviors = Drupal.behaviors;
|
||||
// Execute all of them.
|
||||
Object.keys(behaviors || {}).forEach(i => {
|
||||
if (typeof behaviors[i].attach === 'function') {
|
||||
// Don't stop the execution of behaviors in case of an error.
|
||||
try {
|
||||
behaviors[i].attach(context, settings);
|
||||
} catch (e) {
|
||||
Drupal.throwError(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Detaches registered behaviors from a page element.
|
||||
*
|
||||
* Developers implementing Ajax in their solutions should call this function
|
||||
* before page content is about to be removed, feeding in an element to be
|
||||
* processed, in order to allow special behaviors to detach from the content.
|
||||
*
|
||||
* Such implementations should use `.findOnce()` and `.removeOnce()` to find
|
||||
* elements with their corresponding `Drupal.behaviors.behaviorName.attach`
|
||||
* implementation, i.e. `.removeOnce('behaviorName')`, to ensure the behavior
|
||||
* is detached only from previously processed elements.
|
||||
*
|
||||
* @param {HTMLDocument|HTMLElement} [context=document]
|
||||
* An element to detach behaviors from.
|
||||
* @param {object} [settings=drupalSettings]
|
||||
* An object containing settings for the current context. If none given,
|
||||
* the global {@link drupalSettings} object is used.
|
||||
* @param {string} [trigger='unload']
|
||||
* A string containing what's causing the behaviors to be detached. The
|
||||
* possible triggers are:
|
||||
* - `'unload'`: The context element is being removed from the DOM.
|
||||
* - `'move'`: The element is about to be moved within the DOM (for example,
|
||||
* during a tabledrag row swap). After the move is completed,
|
||||
* {@link Drupal.attachBehaviors} is called, so that the behavior can undo
|
||||
* whatever it did in response to the move. Many behaviors won't need to
|
||||
* do anything simply in response to the element being moved, but because
|
||||
* IFRAME elements reload their "src" when being moved within the DOM,
|
||||
* behaviors bound to IFRAME elements (like WYSIWYG editors) may need to
|
||||
* take some action.
|
||||
* - `'serialize'`: When an Ajax form is submitted, this is called with the
|
||||
* form as the context. This provides every behavior within the form an
|
||||
* opportunity to ensure that the field elements have correct content
|
||||
* in them before the form is serialized. The canonical use-case is so
|
||||
* that WYSIWYG editors can update the hidden textarea to which they are
|
||||
* bound.
|
||||
*
|
||||
* @throws {Drupal~DrupalBehaviorError}
|
||||
*
|
||||
* @see Drupal~behaviorDetach
|
||||
* @see Drupal.attachBehaviors
|
||||
*/
|
||||
Drupal.detachBehaviors = function(context, settings, trigger) {
|
||||
context = context || document;
|
||||
settings = settings || drupalSettings;
|
||||
trigger = trigger || 'unload';
|
||||
const behaviors = Drupal.behaviors;
|
||||
// Execute all of them.
|
||||
Object.keys(behaviors || {}).forEach(i => {
|
||||
if (typeof behaviors[i].detach === 'function') {
|
||||
// Don't stop the execution of behaviors in case of an error.
|
||||
try {
|
||||
behaviors[i].detach(context, settings, trigger);
|
||||
} catch (e) {
|
||||
Drupal.throwError(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Encodes special characters in a plain-text string for display as HTML.
|
||||
*
|
||||
* @param {string} str
|
||||
* The string to be encoded.
|
||||
*
|
||||
* @return {string}
|
||||
* The encoded string.
|
||||
*
|
||||
* @ingroup sanitization
|
||||
*/
|
||||
Drupal.checkPlain = function(str) {
|
||||
str = str
|
||||
.toString()
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
return str;
|
||||
};
|
||||
|
||||
/**
|
||||
* Replaces placeholders with sanitized values in a string.
|
||||
*
|
||||
* @param {string} str
|
||||
* A string with placeholders.
|
||||
* @param {object} args
|
||||
* An object of replacements pairs to make. Incidences of any key in this
|
||||
* array are replaced with the corresponding value. Based on the first
|
||||
* character of the key, the value is escaped and/or themed:
|
||||
* - `'!variable'`: inserted as is.
|
||||
* - `'@variable'`: escape plain text to HTML ({@link Drupal.checkPlain}).
|
||||
* - `'%variable'`: escape text and theme as a placeholder for user-
|
||||
* submitted content ({@link Drupal.checkPlain} +
|
||||
* `{@link Drupal.theme}('placeholder')`).
|
||||
*
|
||||
* @return {string}
|
||||
* The formatted string.
|
||||
*
|
||||
* @see Drupal.t
|
||||
*/
|
||||
Drupal.formatString = function(str, args) {
|
||||
// Keep args intact.
|
||||
const processedArgs = {};
|
||||
// Transform arguments before inserting them.
|
||||
Object.keys(args || {}).forEach(key => {
|
||||
switch (key.charAt(0)) {
|
||||
// Escaped only.
|
||||
case '@':
|
||||
processedArgs[key] = Drupal.checkPlain(args[key]);
|
||||
break;
|
||||
|
||||
// Pass-through.
|
||||
case '!':
|
||||
processedArgs[key] = args[key];
|
||||
break;
|
||||
|
||||
// Escaped and placeholder.
|
||||
default:
|
||||
processedArgs[key] = Drupal.theme('placeholder', args[key]);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return Drupal.stringReplace(str, processedArgs, null);
|
||||
};
|
||||
|
||||
/**
|
||||
* Replaces substring.
|
||||
*
|
||||
* The longest keys will be tried first. Once a substring has been replaced,
|
||||
* its new value will not be searched again.
|
||||
*
|
||||
* @param {string} str
|
||||
* A string with placeholders.
|
||||
* @param {object} args
|
||||
* Key-value pairs.
|
||||
* @param {Array|null} keys
|
||||
* Array of keys from `args`. Internal use only.
|
||||
*
|
||||
* @return {string}
|
||||
* The replaced string.
|
||||
*/
|
||||
Drupal.stringReplace = function(str, args, keys) {
|
||||
if (str.length === 0) {
|
||||
return str;
|
||||
}
|
||||
|
||||
// If the array of keys is not passed then collect the keys from the args.
|
||||
if (!Array.isArray(keys)) {
|
||||
keys = Object.keys(args || {});
|
||||
|
||||
// Order the keys by the character length. The shortest one is the first.
|
||||
keys.sort((a, b) => a.length - b.length);
|
||||
}
|
||||
|
||||
if (keys.length === 0) {
|
||||
return str;
|
||||
}
|
||||
|
||||
// Take next longest one from the end.
|
||||
const key = keys.pop();
|
||||
const fragments = str.split(key);
|
||||
|
||||
if (keys.length) {
|
||||
for (let i = 0; i < fragments.length; i++) {
|
||||
// Process each fragment with a copy of remaining keys.
|
||||
fragments[i] = Drupal.stringReplace(fragments[i], args, keys.slice(0));
|
||||
}
|
||||
}
|
||||
|
||||
return fragments.join(args[key]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Translates strings to the page language, or a given language.
|
||||
*
|
||||
* See the documentation of the server-side t() function for further details.
|
||||
*
|
||||
* @param {string} str
|
||||
* A string containing the English text to translate.
|
||||
* @param {Object.<string, string>} [args]
|
||||
* An object of replacements pairs to make after translation. Incidences
|
||||
* of any key in this array are replaced with the corresponding value.
|
||||
* See {@link Drupal.formatString}.
|
||||
* @param {object} [options]
|
||||
* Additional options for translation.
|
||||
* @param {string} [options.context='']
|
||||
* The context the source string belongs to.
|
||||
*
|
||||
* @return {string}
|
||||
* The formatted string.
|
||||
* The translated string.
|
||||
*/
|
||||
Drupal.t = function(str, args, options) {
|
||||
options = options || {};
|
||||
options.context = options.context || '';
|
||||
|
||||
// Fetch the localized version of the string.
|
||||
if (
|
||||
typeof drupalTranslations !== 'undefined' &&
|
||||
drupalTranslations.strings &&
|
||||
drupalTranslations.strings[options.context] &&
|
||||
drupalTranslations.strings[options.context][str]
|
||||
) {
|
||||
str = drupalTranslations.strings[options.context][str];
|
||||
}
|
||||
|
||||
if (args) {
|
||||
str = Drupal.formatString(str, args);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the URL to a Drupal page.
|
||||
*
|
||||
* @param {string} path
|
||||
* Drupal path to transform to URL.
|
||||
*
|
||||
* @return {string}
|
||||
* The full URL.
|
||||
*/
|
||||
Drupal.url = function(path) {
|
||||
return drupalSettings.path.baseUrl + drupalSettings.path.pathPrefix + path;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the passed in URL as an absolute URL.
|
||||
*
|
||||
* @param {string} url
|
||||
* The URL string to be normalized to an absolute URL.
|
||||
*
|
||||
* @return {string}
|
||||
* The normalized, absolute URL.
|
||||
*
|
||||
* @see https://github.com/angular/angular.js/blob/v1.4.4/src/ng/urlUtils.js
|
||||
* @see https://grack.com/blog/2009/11/17/absolutizing-url-in-javascript
|
||||
* @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L53
|
||||
*/
|
||||
Drupal.url.toAbsolute = function(url) {
|
||||
const urlParsingNode = document.createElement('a');
|
||||
|
||||
// Decode the URL first; this is required by IE <= 6. Decoding non-UTF-8
|
||||
// strings may throw an exception.
|
||||
try {
|
||||
url = decodeURIComponent(url);
|
||||
} catch (e) {
|
||||
// Empty.
|
||||
}
|
||||
|
||||
urlParsingNode.setAttribute('href', url);
|
||||
|
||||
// IE <= 7 normalizes the URL when assigned to the anchor node similar to
|
||||
// the other browsers.
|
||||
return urlParsingNode.cloneNode(false).href;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the URL is within Drupal's base path.
|
||||
*
|
||||
* @param {string} url
|
||||
* The URL string to be tested.
|
||||
*
|
||||
* @return {bool}
|
||||
* `true` if local.
|
||||
*
|
||||
* @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L58
|
||||
*/
|
||||
Drupal.url.isLocal = function(url) {
|
||||
// Always use browser-derived absolute URLs in the comparison, to avoid
|
||||
// attempts to break out of the base path using directory traversal.
|
||||
let absoluteUrl = Drupal.url.toAbsolute(url);
|
||||
let { protocol } = window.location;
|
||||
|
||||
// Consider URLs that match this site's base URL but use HTTPS instead of HTTP
|
||||
// as local as well.
|
||||
if (protocol === 'http:' && absoluteUrl.indexOf('https:') === 0) {
|
||||
protocol = 'https:';
|
||||
}
|
||||
let baseUrl = `${protocol}//${
|
||||
window.location.host
|
||||
}${drupalSettings.path.baseUrl.slice(0, -1)}`;
|
||||
|
||||
// Decoding non-UTF-8 strings may throw an exception.
|
||||
try {
|
||||
absoluteUrl = decodeURIComponent(absoluteUrl);
|
||||
} catch (e) {
|
||||
// Empty.
|
||||
}
|
||||
try {
|
||||
baseUrl = decodeURIComponent(baseUrl);
|
||||
} catch (e) {
|
||||
// Empty.
|
||||
}
|
||||
|
||||
// The given URL matches the site's base URL, or has a path under the site's
|
||||
// base URL.
|
||||
return absoluteUrl === baseUrl || absoluteUrl.indexOf(`${baseUrl}/`) === 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats a string containing a count of items.
|
||||
*
|
||||
* This function ensures that the string is pluralized correctly. Since
|
||||
* {@link Drupal.t} is called by this function, make sure not to pass
|
||||
* already-localized strings to it.
|
||||
*
|
||||
* See the documentation of the server-side
|
||||
* \Drupal\Core\StringTranslation\TranslationInterface::formatPlural()
|
||||
* function for more details.
|
||||
*
|
||||
* @param {number} count
|
||||
* The item count to display.
|
||||
* @param {string} singular
|
||||
* The string for the singular case. Please make sure it is clear this is
|
||||
* singular, to ease translation (e.g. use "1 new comment" instead of "1
|
||||
* new"). Do not use @count in the singular string.
|
||||
* @param {string} plural
|
||||
* The string for the plural case. Please make sure it is clear this is
|
||||
* plural, to ease translation. Use @count in place of the item count, as in
|
||||
* "@count new comments".
|
||||
* @param {object} [args]
|
||||
* An object of replacements pairs to make after translation. Incidences
|
||||
* of any key in this array are replaced with the corresponding value.
|
||||
* See {@link Drupal.formatString}.
|
||||
* Note that you do not need to include @count in this array.
|
||||
* This replacement is done automatically for the plural case.
|
||||
* @param {object} [options]
|
||||
* The options to pass to the {@link Drupal.t} function.
|
||||
*
|
||||
* @return {string}
|
||||
* A translated string.
|
||||
*/
|
||||
Drupal.formatPlural = function(count, singular, plural, args, options) {
|
||||
args = args || {};
|
||||
args['@count'] = count;
|
||||
|
||||
const pluralDelimiter = drupalSettings.pluralDelimiter;
|
||||
const translations = Drupal.t(
|
||||
singular + pluralDelimiter + plural,
|
||||
args,
|
||||
options,
|
||||
).split(pluralDelimiter);
|
||||
let index = 0;
|
||||
|
||||
// Determine the index of the plural form.
|
||||
if (
|
||||
typeof drupalTranslations !== 'undefined' &&
|
||||
drupalTranslations.pluralFormula
|
||||
) {
|
||||
index =
|
||||
count in drupalTranslations.pluralFormula
|
||||
? drupalTranslations.pluralFormula[count]
|
||||
: drupalTranslations.pluralFormula.default;
|
||||
} else if (args['@count'] !== 1) {
|
||||
index = 1;
|
||||
}
|
||||
|
||||
return translations[index];
|
||||
};
|
||||
|
||||
/**
|
||||
* Encodes a Drupal path for use in a URL.
|
||||
*
|
||||
* For aesthetic reasons slashes are not escaped.
|
||||
*
|
||||
* @param {string} item
|
||||
* Unencoded path.
|
||||
*
|
||||
* @return {string}
|
||||
* The encoded path.
|
||||
*/
|
||||
Drupal.encodePath = function(item) {
|
||||
return window.encodeURIComponent(item).replace(/%2F/g, '/');
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates the themed representation of a Drupal object.
|
||||
*
|
||||
* All requests for themed output must go through this function. It examines
|
||||
* the request and routes it to the appropriate theme function. If the current
|
||||
* theme does not provide an override function, the generic theme function is
|
||||
* called.
|
||||
*
|
||||
* @example
|
||||
* <caption>To retrieve the HTML for text that should be emphasized and
|
||||
* displayed as a placeholder inside a sentence.</caption>
|
||||
* Drupal.theme('placeholder', text);
|
||||
*
|
||||
* @namespace
|
||||
*
|
||||
* @param {function} func
|
||||
* The name of the theme function to call.
|
||||
* @param {...args}
|
||||
* Additional arguments to pass along to the theme function.
|
||||
*
|
||||
* @return {string|object|HTMLElement|jQuery}
|
||||
* Any data the theme function returns. This could be a plain HTML string,
|
||||
* but also a complex object.
|
||||
*/
|
||||
Drupal.theme = function(func, ...args) {
|
||||
if (func in Drupal.theme) {
|
||||
return Drupal.theme[func](...args);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats text for emphasized display in a placeholder inside a sentence.
|
||||
*
|
||||
* @param {string} str
|
||||
* The text to format (plain-text).
|
||||
*
|
||||
* @return {string}
|
||||
* The formatted text (html).
|
||||
*/
|
||||
Drupal.theme.placeholder = function(str) {
|
||||
return `<em class="placeholder">${Drupal.checkPlain(str)}</em>`;
|
||||
};
|
||||
})(Drupal, window.drupalSettings, window.drupalTranslations);
|
17
2017/web/core/misc/drupal.init.es6.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Allow other JavaScript libraries to use $.
|
||||
if (window.jQuery) {
|
||||
jQuery.noConflict();
|
||||
}
|
||||
|
||||
// Class indicating that JS is enabled; used for styling purpose.
|
||||
document.documentElement.className += ' js';
|
||||
|
||||
// JavaScript should be made compatible with libraries other than jQuery by
|
||||
// wrapping it in an anonymous closure.
|
||||
|
||||
(function(domready, Drupal, drupalSettings) {
|
||||
// Attach all behaviors.
|
||||
domready(() => {
|
||||
Drupal.attachBehaviors(document, drupalSettings);
|
||||
});
|
||||
})(domready, Drupal, window.drupalSettings);
|
18
2017/web/core/misc/drupal.init.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
if (window.jQuery) {
|
||||
jQuery.noConflict();
|
||||
}
|
||||
|
||||
document.documentElement.className += ' js';
|
||||
|
||||
(function (domready, Drupal, drupalSettings) {
|
||||
domready(function () {
|
||||
Drupal.attachBehaviors(document, drupalSettings);
|
||||
});
|
||||
})(domready, Drupal, window.drupalSettings);
|
191
2017/web/core/misc/drupal.js
Normal file
|
@ -0,0 +1,191 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
window.Drupal = { behaviors: {}, locale: {} };
|
||||
|
||||
(function (Drupal, drupalSettings, drupalTranslations) {
|
||||
Drupal.throwError = function (error) {
|
||||
setTimeout(function () {
|
||||
throw error;
|
||||
}, 0);
|
||||
};
|
||||
|
||||
Drupal.attachBehaviors = function (context, settings) {
|
||||
context = context || document;
|
||||
settings = settings || drupalSettings;
|
||||
var behaviors = Drupal.behaviors;
|
||||
|
||||
Object.keys(behaviors || {}).forEach(function (i) {
|
||||
if (typeof behaviors[i].attach === 'function') {
|
||||
try {
|
||||
behaviors[i].attach(context, settings);
|
||||
} catch (e) {
|
||||
Drupal.throwError(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Drupal.detachBehaviors = function (context, settings, trigger) {
|
||||
context = context || document;
|
||||
settings = settings || drupalSettings;
|
||||
trigger = trigger || 'unload';
|
||||
var behaviors = Drupal.behaviors;
|
||||
|
||||
Object.keys(behaviors || {}).forEach(function (i) {
|
||||
if (typeof behaviors[i].detach === 'function') {
|
||||
try {
|
||||
behaviors[i].detach(context, settings, trigger);
|
||||
} catch (e) {
|
||||
Drupal.throwError(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Drupal.checkPlain = function (str) {
|
||||
str = str.toString().replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
||||
return str;
|
||||
};
|
||||
|
||||
Drupal.formatString = function (str, args) {
|
||||
var processedArgs = {};
|
||||
|
||||
Object.keys(args || {}).forEach(function (key) {
|
||||
switch (key.charAt(0)) {
|
||||
case '@':
|
||||
processedArgs[key] = Drupal.checkPlain(args[key]);
|
||||
break;
|
||||
|
||||
case '!':
|
||||
processedArgs[key] = args[key];
|
||||
break;
|
||||
|
||||
default:
|
||||
processedArgs[key] = Drupal.theme('placeholder', args[key]);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return Drupal.stringReplace(str, processedArgs, null);
|
||||
};
|
||||
|
||||
Drupal.stringReplace = function (str, args, keys) {
|
||||
if (str.length === 0) {
|
||||
return str;
|
||||
}
|
||||
|
||||
if (!Array.isArray(keys)) {
|
||||
keys = Object.keys(args || {});
|
||||
|
||||
keys.sort(function (a, b) {
|
||||
return a.length - b.length;
|
||||
});
|
||||
}
|
||||
|
||||
if (keys.length === 0) {
|
||||
return str;
|
||||
}
|
||||
|
||||
var key = keys.pop();
|
||||
var fragments = str.split(key);
|
||||
|
||||
if (keys.length) {
|
||||
for (var i = 0; i < fragments.length; i++) {
|
||||
fragments[i] = Drupal.stringReplace(fragments[i], args, keys.slice(0));
|
||||
}
|
||||
}
|
||||
|
||||
return fragments.join(args[key]);
|
||||
};
|
||||
|
||||
Drupal.t = function (str, args, options) {
|
||||
options = options || {};
|
||||
options.context = options.context || '';
|
||||
|
||||
if (typeof drupalTranslations !== 'undefined' && drupalTranslations.strings && drupalTranslations.strings[options.context] && drupalTranslations.strings[options.context][str]) {
|
||||
str = drupalTranslations.strings[options.context][str];
|
||||
}
|
||||
|
||||
if (args) {
|
||||
str = Drupal.formatString(str, args);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
Drupal.url = function (path) {
|
||||
return drupalSettings.path.baseUrl + drupalSettings.path.pathPrefix + path;
|
||||
};
|
||||
|
||||
Drupal.url.toAbsolute = function (url) {
|
||||
var urlParsingNode = document.createElement('a');
|
||||
|
||||
try {
|
||||
url = decodeURIComponent(url);
|
||||
} catch (e) {}
|
||||
|
||||
urlParsingNode.setAttribute('href', url);
|
||||
|
||||
return urlParsingNode.cloneNode(false).href;
|
||||
};
|
||||
|
||||
Drupal.url.isLocal = function (url) {
|
||||
var absoluteUrl = Drupal.url.toAbsolute(url);
|
||||
var protocol = window.location.protocol;
|
||||
|
||||
if (protocol === 'http:' && absoluteUrl.indexOf('https:') === 0) {
|
||||
protocol = 'https:';
|
||||
}
|
||||
var baseUrl = protocol + '//' + window.location.host + drupalSettings.path.baseUrl.slice(0, -1);
|
||||
|
||||
try {
|
||||
absoluteUrl = decodeURIComponent(absoluteUrl);
|
||||
} catch (e) {}
|
||||
try {
|
||||
baseUrl = decodeURIComponent(baseUrl);
|
||||
} catch (e) {}
|
||||
|
||||
return absoluteUrl === baseUrl || absoluteUrl.indexOf(baseUrl + '/') === 0;
|
||||
};
|
||||
|
||||
Drupal.formatPlural = function (count, singular, plural, args, options) {
|
||||
args = args || {};
|
||||
args['@count'] = count;
|
||||
|
||||
var pluralDelimiter = drupalSettings.pluralDelimiter;
|
||||
var translations = Drupal.t(singular + pluralDelimiter + plural, args, options).split(pluralDelimiter);
|
||||
var index = 0;
|
||||
|
||||
if (typeof drupalTranslations !== 'undefined' && drupalTranslations.pluralFormula) {
|
||||
index = count in drupalTranslations.pluralFormula ? drupalTranslations.pluralFormula[count] : drupalTranslations.pluralFormula.default;
|
||||
} else if (args['@count'] !== 1) {
|
||||
index = 1;
|
||||
}
|
||||
|
||||
return translations[index];
|
||||
};
|
||||
|
||||
Drupal.encodePath = function (item) {
|
||||
return window.encodeURIComponent(item).replace(/%2F/g, '/');
|
||||
};
|
||||
|
||||
Drupal.theme = function (func) {
|
||||
if (func in Drupal.theme) {
|
||||
var _Drupal$theme;
|
||||
|
||||
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
args[_key - 1] = arguments[_key];
|
||||
}
|
||||
|
||||
return (_Drupal$theme = Drupal.theme)[func].apply(_Drupal$theme, args);
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.theme.placeholder = function (str) {
|
||||
return '<em class="placeholder">' + Drupal.checkPlain(str) + '</em>';
|
||||
};
|
||||
})(Drupal, window.drupalSettings, window.drupalTranslations);
|
24
2017/web/core/misc/drupalSettingsLoader.es6.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* @file
|
||||
* Parse inline JSON and initialize the drupalSettings global object.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
// Use direct child elements to harden against XSS exploits when CSP is on.
|
||||
const settingsElement = document.querySelector(
|
||||
'head > script[type="application/json"][data-drupal-selector="drupal-settings-json"], body > script[type="application/json"][data-drupal-selector="drupal-settings-json"]',
|
||||
);
|
||||
|
||||
/**
|
||||
* Variable generated by Drupal with all the configuration created from PHP.
|
||||
*
|
||||
* @global
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
window.drupalSettings = {};
|
||||
|
||||
if (settingsElement !== null) {
|
||||
window.drupalSettings = JSON.parse(settingsElement.textContent);
|
||||
}
|
||||
})();
|
16
2017/web/core/misc/drupalSettingsLoader.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function () {
|
||||
var settingsElement = document.querySelector('head > script[type="application/json"][data-drupal-selector="drupal-settings-json"], body > script[type="application/json"][data-drupal-selector="drupal-settings-json"]');
|
||||
|
||||
window.drupalSettings = {};
|
||||
|
||||
if (settingsElement !== null) {
|
||||
window.drupalSettings = JSON.parse(settingsElement.textContent);
|
||||
}
|
||||
})();
|
BIN
2017/web/core/misc/druplicon.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
71
2017/web/core/misc/entity-form.es6.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* @file
|
||||
* Defines Javascript behaviors for the block_content module.
|
||||
*/
|
||||
|
||||
(function($, Drupal) {
|
||||
/**
|
||||
* Sets summaries about revision and translation of entities.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches summary behaviour entity form tabs.
|
||||
*
|
||||
* Specifically, it updates summaries to the revision information and the
|
||||
* translation options.
|
||||
*/
|
||||
Drupal.behaviors.entityContentDetailsSummaries = {
|
||||
attach(context) {
|
||||
const $context = $(context);
|
||||
$context
|
||||
.find('.entity-content-form-revision-information')
|
||||
.drupalSetSummary(context => {
|
||||
const $revisionContext = $(context);
|
||||
const revisionCheckbox = $revisionContext.find(
|
||||
'.js-form-item-revision input',
|
||||
);
|
||||
|
||||
// Return 'New revision' if the 'Create new revision' checkbox is checked,
|
||||
// or if the checkbox doesn't exist, but the revision log does. For users
|
||||
// without the "Administer content" permission the checkbox won't appear,
|
||||
// but the revision log will if the content type is set to auto-revision.
|
||||
if (
|
||||
revisionCheckbox.is(':checked') ||
|
||||
(!revisionCheckbox.length &&
|
||||
$revisionContext.find('.js-form-item-revision-log textarea')
|
||||
.length)
|
||||
) {
|
||||
return Drupal.t('New revision');
|
||||
}
|
||||
|
||||
return Drupal.t('No revision');
|
||||
});
|
||||
|
||||
$context
|
||||
.find('details.entity-translation-options')
|
||||
.drupalSetSummary(context => {
|
||||
const $translationContext = $(context);
|
||||
let translate;
|
||||
let $checkbox = $translationContext.find(
|
||||
'.js-form-item-translation-translate input',
|
||||
);
|
||||
|
||||
if ($checkbox.length) {
|
||||
translate = $checkbox.is(':checked')
|
||||
? Drupal.t('Needs to be updated')
|
||||
: Drupal.t('Does not need to be updated');
|
||||
} else {
|
||||
$checkbox = $translationContext.find(
|
||||
'.js-form-item-translation-retranslate input',
|
||||
);
|
||||
translate = $checkbox.is(':checked')
|
||||
? Drupal.t('Flag other translations as outdated')
|
||||
: Drupal.t('Do not flag other translations as outdated');
|
||||
}
|
||||
|
||||
return translate;
|
||||
});
|
||||
},
|
||||
};
|
||||
})(jQuery, Drupal);
|
39
2017/web/core/misc/entity-form.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal) {
|
||||
Drupal.behaviors.entityContentDetailsSummaries = {
|
||||
attach: function attach(context) {
|
||||
var $context = $(context);
|
||||
$context.find('.entity-content-form-revision-information').drupalSetSummary(function (context) {
|
||||
var $revisionContext = $(context);
|
||||
var revisionCheckbox = $revisionContext.find('.js-form-item-revision input');
|
||||
|
||||
if (revisionCheckbox.is(':checked') || !revisionCheckbox.length && $revisionContext.find('.js-form-item-revision-log textarea').length) {
|
||||
return Drupal.t('New revision');
|
||||
}
|
||||
|
||||
return Drupal.t('No revision');
|
||||
});
|
||||
|
||||
$context.find('details.entity-translation-options').drupalSetSummary(function (context) {
|
||||
var $translationContext = $(context);
|
||||
var translate = void 0;
|
||||
var $checkbox = $translationContext.find('.js-form-item-translation-translate input');
|
||||
|
||||
if ($checkbox.length) {
|
||||
translate = $checkbox.is(':checked') ? Drupal.t('Needs to be updated') : Drupal.t('Does not need to be updated');
|
||||
} else {
|
||||
$checkbox = $translationContext.find('.js-form-item-translation-retranslate input');
|
||||
translate = $checkbox.is(':checked') ? Drupal.t('Flag other translations as outdated') : Drupal.t('Do not flag other translations as outdated');
|
||||
}
|
||||
|
||||
return translate;
|
||||
});
|
||||
}
|
||||
};
|
||||
})(jQuery, Drupal);
|
BIN
2017/web/core/misc/favicon.ico
Normal file
After Width: | Height: | Size: 5.3 KiB |
8
2017/web/core/misc/feed.svg
Normal file
|
@ -0,0 +1,8 @@
|
|||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<rect fill="#ff9900" width="16" height="16" x="0" y="0" rx="3" ry="3"/>
|
||||
<g fill="#ffffff">
|
||||
<circle cx="4.25" cy="11.812" r="1.5"/>
|
||||
<path d="M10,13.312H7.875c0-2.83-2.295-5.125-5.125-5.125l0,0V6.062C6.754,6.062,10,9.308,10,13.312z"/>
|
||||
<path d="M11.5,13.312c0-4.833-3.917-8.75-8.75-8.75V2.375c6.041,0,10.937,4.896,10.937,10.937H11.5z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 462 B |
325
2017/web/core/misc/form.es6.js
Normal file
|
@ -0,0 +1,325 @@
|
|||
/**
|
||||
* @file
|
||||
* Form features.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Triggers when a value in the form changed.
|
||||
*
|
||||
* The event triggers when content is typed or pasted in a text field, before
|
||||
* the change event triggers.
|
||||
*
|
||||
* @event formUpdated
|
||||
*/
|
||||
|
||||
/**
|
||||
* Triggers when a click on a page fragment link or hash change is detected.
|
||||
*
|
||||
* The event triggers when the fragment in the URL changes (a hash change) and
|
||||
* when a link containing a fragment identifier is clicked. In case the hash
|
||||
* changes due to a click this event will only be triggered once.
|
||||
*
|
||||
* @event formFragmentLinkClickOrHashChange
|
||||
*/
|
||||
|
||||
(function($, Drupal, debounce) {
|
||||
/**
|
||||
* Retrieves the summary for the first element.
|
||||
*
|
||||
* @return {string}
|
||||
* The text of the summary.
|
||||
*/
|
||||
$.fn.drupalGetSummary = function() {
|
||||
const callback = this.data('summaryCallback');
|
||||
return this[0] && callback ? $.trim(callback(this[0])) : '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the summary for all matched elements.
|
||||
*
|
||||
* @param {function} callback
|
||||
* Either a function that will be called each time the summary is
|
||||
* retrieved or a string (which is returned each time).
|
||||
*
|
||||
* @return {jQuery}
|
||||
* jQuery collection of the current element.
|
||||
*
|
||||
* @fires event:summaryUpdated
|
||||
*
|
||||
* @listens event:formUpdated
|
||||
*/
|
||||
$.fn.drupalSetSummary = function(callback) {
|
||||
const self = this;
|
||||
|
||||
// To facilitate things, the callback should always be a function. If it's
|
||||
// not, we wrap it into an anonymous function which just returns the value.
|
||||
if (typeof callback !== 'function') {
|
||||
const val = callback;
|
||||
callback = function() {
|
||||
return val;
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
this.data('summaryCallback', callback)
|
||||
// To prevent duplicate events, the handlers are first removed and then
|
||||
// (re-)added.
|
||||
.off('formUpdated.summary')
|
||||
.on('formUpdated.summary', () => {
|
||||
self.trigger('summaryUpdated');
|
||||
})
|
||||
// The actual summaryUpdated handler doesn't fire when the callback is
|
||||
// changed, so we have to do this manually.
|
||||
.trigger('summaryUpdated')
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Prevents consecutive form submissions of identical form values.
|
||||
*
|
||||
* Repetitive form submissions that would submit the identical form values
|
||||
* are prevented, unless the form values are different to the previously
|
||||
* submitted values.
|
||||
*
|
||||
* This is a simplified re-implementation of a user-agent behavior that
|
||||
* should be natively supported by major web browsers, but at this time, only
|
||||
* Firefox has a built-in protection.
|
||||
*
|
||||
* A form value-based approach ensures that the constraint is triggered for
|
||||
* consecutive, identical form submissions only. Compared to that, a form
|
||||
* button-based approach would (1) rely on [visible] buttons to exist where
|
||||
* technically not required and (2) require more complex state management if
|
||||
* there are multiple buttons in a form.
|
||||
*
|
||||
* This implementation is based on form-level submit events only and relies
|
||||
* on jQuery's serialize() method to determine submitted form values. As such,
|
||||
* the following limitations exist:
|
||||
*
|
||||
* - Event handlers on form buttons that preventDefault() do not receive a
|
||||
* double-submit protection. That is deemed to be fine, since such button
|
||||
* events typically trigger reversible client-side or server-side
|
||||
* operations that are local to the context of a form only.
|
||||
* - Changed values in advanced form controls, such as file inputs, are not
|
||||
* part of the form values being compared between consecutive form submits
|
||||
* (due to limitations of jQuery.serialize()). That is deemed to be
|
||||
* acceptable, because if the user forgot to attach a file, then the size of
|
||||
* HTTP payload will most likely be small enough to be fully passed to the
|
||||
* server endpoint within (milli)seconds. If a user mistakenly attached a
|
||||
* wrong file and is technically versed enough to cancel the form submission
|
||||
* (and HTTP payload) in order to attach a different file, then that
|
||||
* edge-case is not supported here.
|
||||
*
|
||||
* Lastly, all forms submitted via HTTP GET are idempotent by definition of
|
||||
* HTTP standards, so excluded in this implementation.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.formSingleSubmit = {
|
||||
attach() {
|
||||
function onFormSubmit(e) {
|
||||
const $form = $(e.currentTarget);
|
||||
const formValues = $form.serialize();
|
||||
const previousValues = $form.attr('data-drupal-form-submit-last');
|
||||
if (previousValues === formValues) {
|
||||
e.preventDefault();
|
||||
} else {
|
||||
$form.attr('data-drupal-form-submit-last', formValues);
|
||||
}
|
||||
}
|
||||
|
||||
$('body')
|
||||
.once('form-single-submit')
|
||||
.on('submit.singleSubmit', 'form:not([method~="GET"])', onFormSubmit);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a 'formUpdated' event each time a form element is modified.
|
||||
*
|
||||
* @param {HTMLElement} element
|
||||
* The element to trigger a form updated event on.
|
||||
*
|
||||
* @fires event:formUpdated
|
||||
*/
|
||||
function triggerFormUpdated(element) {
|
||||
$(element).trigger('formUpdated');
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the IDs of all form fields in the given form.
|
||||
*
|
||||
* @param {HTMLFormElement} form
|
||||
* The form element to search.
|
||||
*
|
||||
* @return {Array}
|
||||
* Array of IDs for form fields.
|
||||
*/
|
||||
function fieldsList(form) {
|
||||
const $fieldList = $(form)
|
||||
.find('[name]')
|
||||
.map(
|
||||
// We use id to avoid name duplicates on radio fields and filter out
|
||||
// elements with a name but no id.
|
||||
(index, element) => element.getAttribute('id'),
|
||||
);
|
||||
// Return a true array.
|
||||
return $.makeArray($fieldList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the 'formUpdated' event on form elements when they are modified.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches formUpdated behaviors.
|
||||
* @prop {Drupal~behaviorDetach} detach
|
||||
* Detaches formUpdated behaviors.
|
||||
*
|
||||
* @fires event:formUpdated
|
||||
*/
|
||||
Drupal.behaviors.formUpdated = {
|
||||
attach(context) {
|
||||
const $context = $(context);
|
||||
const contextIsForm = $context.is('form');
|
||||
const $forms = (contextIsForm ? $context : $context.find('form')).once(
|
||||
'form-updated',
|
||||
);
|
||||
let formFields;
|
||||
|
||||
if ($forms.length) {
|
||||
// Initialize form behaviors, use $.makeArray to be able to use native
|
||||
// forEach array method and have the callback parameters in the right
|
||||
// order.
|
||||
$.makeArray($forms).forEach(form => {
|
||||
const events = 'change.formUpdated input.formUpdated ';
|
||||
const eventHandler = debounce(event => {
|
||||
triggerFormUpdated(event.target);
|
||||
}, 300);
|
||||
formFields = fieldsList(form).join(',');
|
||||
|
||||
form.setAttribute('data-drupal-form-fields', formFields);
|
||||
$(form).on(events, eventHandler);
|
||||
});
|
||||
}
|
||||
// On ajax requests context is the form element.
|
||||
if (contextIsForm) {
|
||||
formFields = fieldsList(context).join(',');
|
||||
// @todo replace with form.getAttribute() when #1979468 is in.
|
||||
const currentFields = $(context).attr('data-drupal-form-fields');
|
||||
// If there has been a change in the fields or their order, trigger
|
||||
// formUpdated.
|
||||
if (formFields !== currentFields) {
|
||||
triggerFormUpdated(context);
|
||||
}
|
||||
}
|
||||
},
|
||||
detach(context, settings, trigger) {
|
||||
const $context = $(context);
|
||||
const contextIsForm = $context.is('form');
|
||||
if (trigger === 'unload') {
|
||||
const $forms = (contextIsForm
|
||||
? $context
|
||||
: $context.find('form')
|
||||
).removeOnce('form-updated');
|
||||
if ($forms.length) {
|
||||
$.makeArray($forms).forEach(form => {
|
||||
form.removeAttribute('data-drupal-form-fields');
|
||||
$(form).off('.formUpdated');
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Prepopulate form fields with information from the visitor browser.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for filling user info from browser.
|
||||
*/
|
||||
Drupal.behaviors.fillUserInfoFromBrowser = {
|
||||
attach(context, settings) {
|
||||
const userInfo = ['name', 'mail', 'homepage'];
|
||||
const $forms = $('[data-user-info-from-browser]').once(
|
||||
'user-info-from-browser',
|
||||
);
|
||||
if ($forms.length) {
|
||||
userInfo.forEach(info => {
|
||||
const $element = $forms.find(`[name=${info}]`);
|
||||
const browserData = localStorage.getItem(`Drupal.visitor.${info}`);
|
||||
const emptyOrDefault =
|
||||
$element.val() === '' ||
|
||||
$element.attr('data-drupal-default-value') === $element.val();
|
||||
if ($element.length && emptyOrDefault && browserData) {
|
||||
$element.val(browserData);
|
||||
}
|
||||
});
|
||||
}
|
||||
$forms.on('submit', () => {
|
||||
userInfo.forEach(info => {
|
||||
const $element = $forms.find(`[name=${info}]`);
|
||||
if ($element.length) {
|
||||
localStorage.setItem(`Drupal.visitor.${info}`, $element.val());
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a fragment interaction event on a hash change or fragment link click.
|
||||
*
|
||||
* @param {jQuery.Event} e
|
||||
* The event triggered.
|
||||
*
|
||||
* @fires event:formFragmentLinkClickOrHashChange
|
||||
*/
|
||||
const handleFragmentLinkClickOrHashChange = e => {
|
||||
let url;
|
||||
if (e.type === 'click') {
|
||||
url = e.currentTarget.location
|
||||
? e.currentTarget.location
|
||||
: e.currentTarget;
|
||||
} else {
|
||||
url = window.location;
|
||||
}
|
||||
const hash = url.hash.substr(1);
|
||||
if (hash) {
|
||||
const $target = $(`#${hash}`);
|
||||
$('body').trigger('formFragmentLinkClickOrHashChange', [$target]);
|
||||
|
||||
/**
|
||||
* Clicking a fragment link or a hash change should focus the target
|
||||
* element, but event timing issues in multiple browsers require a timeout.
|
||||
*/
|
||||
setTimeout(() => $target.trigger('focus'), 300);
|
||||
}
|
||||
};
|
||||
|
||||
const debouncedHandleFragmentLinkClickOrHashChange = debounce(
|
||||
handleFragmentLinkClickOrHashChange,
|
||||
300,
|
||||
true,
|
||||
);
|
||||
|
||||
// Binds a listener to handle URL fragment changes.
|
||||
$(window).on(
|
||||
'hashchange.form-fragment',
|
||||
debouncedHandleFragmentLinkClickOrHashChange,
|
||||
);
|
||||
|
||||
/**
|
||||
* Binds a listener to handle clicks on fragment links and absolute URL links
|
||||
* containing a fragment, this is needed next to the hash change listener
|
||||
* because clicking such links doesn't trigger a hash change when the fragment
|
||||
* is already in the URL.
|
||||
*/
|
||||
$(document).on(
|
||||
'click.form-fragment',
|
||||
'a[href*="#"]',
|
||||
debouncedHandleFragmentLinkClickOrHashChange,
|
||||
);
|
||||
})(jQuery, Drupal, Drupal.debounce);
|
151
2017/web/core/misc/form.js
Normal file
|
@ -0,0 +1,151 @@
|
|||
/**
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal, debounce) {
|
||||
$.fn.drupalGetSummary = function () {
|
||||
var callback = this.data('summaryCallback');
|
||||
return this[0] && callback ? $.trim(callback(this[0])) : '';
|
||||
};
|
||||
|
||||
$.fn.drupalSetSummary = function (callback) {
|
||||
var self = this;
|
||||
|
||||
if (typeof callback !== 'function') {
|
||||
var val = callback;
|
||||
callback = function callback() {
|
||||
return val;
|
||||
};
|
||||
}
|
||||
|
||||
return this.data('summaryCallback', callback).off('formUpdated.summary').on('formUpdated.summary', function () {
|
||||
self.trigger('summaryUpdated');
|
||||
}).trigger('summaryUpdated');
|
||||
};
|
||||
|
||||
Drupal.behaviors.formSingleSubmit = {
|
||||
attach: function attach() {
|
||||
function onFormSubmit(e) {
|
||||
var $form = $(e.currentTarget);
|
||||
var formValues = $form.serialize();
|
||||
var previousValues = $form.attr('data-drupal-form-submit-last');
|
||||
if (previousValues === formValues) {
|
||||
e.preventDefault();
|
||||
} else {
|
||||
$form.attr('data-drupal-form-submit-last', formValues);
|
||||
}
|
||||
}
|
||||
|
||||
$('body').once('form-single-submit').on('submit.singleSubmit', 'form:not([method~="GET"])', onFormSubmit);
|
||||
}
|
||||
};
|
||||
|
||||
function triggerFormUpdated(element) {
|
||||
$(element).trigger('formUpdated');
|
||||
}
|
||||
|
||||
function fieldsList(form) {
|
||||
var $fieldList = $(form).find('[name]').map(function (index, element) {
|
||||
return element.getAttribute('id');
|
||||
});
|
||||
|
||||
return $.makeArray($fieldList);
|
||||
}
|
||||
|
||||
Drupal.behaviors.formUpdated = {
|
||||
attach: function attach(context) {
|
||||
var $context = $(context);
|
||||
var contextIsForm = $context.is('form');
|
||||
var $forms = (contextIsForm ? $context : $context.find('form')).once('form-updated');
|
||||
var formFields = void 0;
|
||||
|
||||
if ($forms.length) {
|
||||
$.makeArray($forms).forEach(function (form) {
|
||||
var events = 'change.formUpdated input.formUpdated ';
|
||||
var eventHandler = debounce(function (event) {
|
||||
triggerFormUpdated(event.target);
|
||||
}, 300);
|
||||
formFields = fieldsList(form).join(',');
|
||||
|
||||
form.setAttribute('data-drupal-form-fields', formFields);
|
||||
$(form).on(events, eventHandler);
|
||||
});
|
||||
}
|
||||
|
||||
if (contextIsForm) {
|
||||
formFields = fieldsList(context).join(',');
|
||||
|
||||
var currentFields = $(context).attr('data-drupal-form-fields');
|
||||
|
||||
if (formFields !== currentFields) {
|
||||
triggerFormUpdated(context);
|
||||
}
|
||||
}
|
||||
},
|
||||
detach: function detach(context, settings, trigger) {
|
||||
var $context = $(context);
|
||||
var contextIsForm = $context.is('form');
|
||||
if (trigger === 'unload') {
|
||||
var $forms = (contextIsForm ? $context : $context.find('form')).removeOnce('form-updated');
|
||||
if ($forms.length) {
|
||||
$.makeArray($forms).forEach(function (form) {
|
||||
form.removeAttribute('data-drupal-form-fields');
|
||||
$(form).off('.formUpdated');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.behaviors.fillUserInfoFromBrowser = {
|
||||
attach: function attach(context, settings) {
|
||||
var userInfo = ['name', 'mail', 'homepage'];
|
||||
var $forms = $('[data-user-info-from-browser]').once('user-info-from-browser');
|
||||
if ($forms.length) {
|
||||
userInfo.forEach(function (info) {
|
||||
var $element = $forms.find('[name=' + info + ']');
|
||||
var browserData = localStorage.getItem('Drupal.visitor.' + info);
|
||||
var emptyOrDefault = $element.val() === '' || $element.attr('data-drupal-default-value') === $element.val();
|
||||
if ($element.length && emptyOrDefault && browserData) {
|
||||
$element.val(browserData);
|
||||
}
|
||||
});
|
||||
}
|
||||
$forms.on('submit', function () {
|
||||
userInfo.forEach(function (info) {
|
||||
var $element = $forms.find('[name=' + info + ']');
|
||||
if ($element.length) {
|
||||
localStorage.setItem('Drupal.visitor.' + info, $element.val());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var handleFragmentLinkClickOrHashChange = function handleFragmentLinkClickOrHashChange(e) {
|
||||
var url = void 0;
|
||||
if (e.type === 'click') {
|
||||
url = e.currentTarget.location ? e.currentTarget.location : e.currentTarget;
|
||||
} else {
|
||||
url = window.location;
|
||||
}
|
||||
var hash = url.hash.substr(1);
|
||||
if (hash) {
|
||||
var $target = $('#' + hash);
|
||||
$('body').trigger('formFragmentLinkClickOrHashChange', [$target]);
|
||||
|
||||
setTimeout(function () {
|
||||
return $target.trigger('focus');
|
||||
}, 300);
|
||||
}
|
||||
};
|
||||
|
||||
var debouncedHandleFragmentLinkClickOrHashChange = debounce(handleFragmentLinkClickOrHashChange, 300, true);
|
||||
|
||||
$(window).on('hashchange.form-fragment', debouncedHandleFragmentLinkClickOrHashChange);
|
||||
|
||||
$(document).on('click.form-fragment', 'a[href*="#"]', debouncedHandleFragmentLinkClickOrHashChange);
|
||||
})(jQuery, Drupal, Drupal.debounce);
|
BIN
2017/web/core/misc/help.png
Normal file
After Width: | Height: | Size: 294 B |
1
2017/web/core/misc/icons/000000/barchart.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g><path fill="#000000" d="M4 13.529c0 .275-.225.5-.5.5h-3c-.275 0-.5-.225-.5-.5v-4.25c0-.274.225-.5.5-.5h3c.275 0 .5.226.5.5v4.25zM10.002 13.529c0 .275-.225.5-.5.5h-3.002c-.275 0-.5-.225-.5-.5v-13c0-.275.225-.5.5-.5h3.002c.275 0 .5.225.5.5v13zM16.002 13.529c0 .275-.225.5-.5.5h-3c-.275 0-.5-.225-.5-.5v-9.5c0-.275.225-.5.5-.5h3c.275 0 .5.225.5.5v9.5z"/></g></svg>
|
After Width: | Height: | Size: 428 B |
1
2017/web/core/misc/icons/000000/chevron-left.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#000000" d="M7.951 7.645c-.193.196-.193.516 0 .71l3.258 3.29c.193.193.191.519-.002.709l-1.371 1.371c-.193.192-.512.191-.707 0l-5.335-5.371c-.194-.194-.194-.514 0-.708l5.335-5.369c.195-.195.514-.195.707-.001l1.371 1.371c.193.194.195.513.002.709l-3.258 3.289z"/></svg>
|
After Width: | Height: | Size: 342 B |
2
2017/web/core/misc/icons/000000/chevron-right.svg
Normal file
|
@ -0,0 +1,2 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#000000" d="M8.053 8.355c.193-.195.193-.517 0-.711l-3.26-3.289c-.193-.195-.192-.514.002-.709l1.371-1.371c.194-.194.512-.193.706.001l5.335 5.369c.195.195.195.515 0 .708l-5.335 5.37c-.194.192-.512.193-.706.002l-1.371-1.371c-.194-.195-.195-.514-.002-.709l3.26-3.29z"/></svg>
|
||||
|
After Width: | Height: | Size: 348 B |
1
2017/web/core/misc/icons/000000/ex.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#000000" d="M3.51 13.925c.194.194.512.195.706.001l3.432-3.431c.194-.194.514-.194.708 0l3.432 3.431c.192.194.514.193.707-.001l1.405-1.417c.191-.195.189-.514-.002-.709l-3.397-3.4c-.192-.193-.192-.514-.002-.708l3.401-3.43c.189-.195.189-.515 0-.709l-1.407-1.418c-.195-.195-.513-.195-.707-.001l-3.43 3.431c-.195.194-.516.194-.708 0l-3.432-3.431c-.195-.195-.512-.194-.706.001l-1.407 1.417c-.194.195-.194.515 0 .71l3.403 3.429c.193.195.193.514-.001.708l-3.4 3.399c-.194.195-.195.516-.001.709l1.406 1.419z"/></svg>
|
After Width: | Height: | Size: 582 B |
1
2017/web/core/misc/icons/000000/file.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g><path fill="#000000" d="M12.502 7h-5c-.276 0-.502-.225-.502-.5v-5c0-.275-.225-.5-.5-.5h-3c-.275 0-.5.225-.5.5v12.029c0 .275.225.5.5.5h9.002c.275 0 .5-.225.5-.5v-6.029c0-.275-.225-.5-.5-.5zM8.502 6h4c.275 0 .34-.159.146-.354l-4.293-4.292c-.195-.195-.353-.129-.353.146v4c0 .275.225.5.5.5z"/></g></svg>
|
After Width: | Height: | Size: 366 B |
1
2017/web/core/misc/icons/000000/move.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#000000" d="M14.904 7.753l-2.373-2.372c-.291-.292-.529-.193-.529.22v1.399h-3v-3h1.398c.414 0 .512-.239.221-.53l-2.371-2.372c-.137-.136-.36-.136-.497 0l-2.372 2.372c-.292.292-.193.53.22.53h1.399v3h-3v-1.369c0-.413-.239-.511-.53-.22l-2.372 2.372c-.136.136-.136.359 0 .494l2.372 2.372c.291.292.53.192.53-.219v-1.43h3v3h-1.4c-.413 0-.511.238-.22.529l2.374 2.373c.137.137.36.137.495 0l2.373-2.373c.29-.291.19-.529-.222-.529h-1.398v-3h3v1.4c0 .412.238.511.529.219l2.373-2.371c.137-.137.137-.359 0-.495z"/></svg>
|
After Width: | Height: | Size: 581 B |
1
2017/web/core/misc/icons/000000/orgchart.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px"><path d="M15.002,11.277c0-0.721,0-1.471,0-2.014c0-1.456-0.824-2.25-2.25-2.25c-1.428,0-3.5,0-3.5,0c-0.139,0-0.25-0.112-0.25-0.25v-2.04c0.596-0.346,1-0.984,1-1.723c0-1.104-0.895-2-2-2C6.896,1,6,1.896,6,3c0,0.738,0.405,1.376,1,1.722v2.042c0,0.138-0.112,0.25-0.25,0.25c0,0-2.138,0-3.5,0S1,7.932,1,9.266c0,0.521,0,1.277,0,2.012c-0.595,0.353-1,0.984-1,1.729c0,1.104,0.896,2,2,2s2-0.896,2-2c0-0.732-0.405-1.377-1-1.729V9.266c0-0.139,0.112-0.25,0.25-0.25h3.536C6.904,9.034,7,9.126,7,9.25v2.027C6.405,11.624,6,12.26,6,13c0,1.104,0.896,2,2.002,2c1.105,0,2-0.896,2-2c0-0.738-0.404-1.376-1-1.723V9.25c0-0.124,0.098-0.216,0.215-0.234h3.535c0.137,0,0.25,0.111,0.25,0.25v2.012c-0.596,0.353-1,0.984-1,1.729c0,1.104,0.896,2,2,2s2-0.896,2-2C16.002,12.262,15.598,11.623,15.002,11.277z"/></svg>
|
After Width: | Height: | Size: 842 B |
1
2017/web/core/misc/icons/000000/paintbrush.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#000000" d="M8.184 7.928l-1.905 1.983-3.538-2.436 4.714-4.713 2.623 3.183-1.894 1.983zm-1.746-7.523c-.236-.416-.803-.649-1.346.083-.259.349-4.727 4.764-4.91 4.983-.182.218-.294.721.044.976.34.258 5.611 3.933 5.611 3.933l-.225.229c.7.729.816.854 1.046.863.75.016 2.035-1.457 2.578-.854.541.604 3.537 3.979 3.537 3.979.51.531 1.305.559 1.815.041.521-.521.541-1.311.025-1.848 0 0-2.742-2.635-3.904-3.619-.578-.479.869-2.051.854-2.839-.008-.238-.125-.361-.823-1.095l-.22.243c0 .003-3.846-4.659-4.082-5.075z"/></svg>
|
After Width: | Height: | Size: 587 B |
1
2017/web/core/misc/icons/000000/people.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g><path fill="#000000" d="M6.722 11.291l.451-.17-.165-.32c-.536-1.039-.685-1.934-.761-2.672-.082-.808-.144-2.831 1.053-4.189.244-.278.493-.493.743-.675.012-.826-.135-1.766-.646-2.345-.618-.7-1.4-.787-1.4-.787l-.497-.055-.498.055s-.783.087-1.398.787c-.617.702-.717 1.948-.625 2.855.06.583.17 1.263.574 2.05.274.533.341.617.355 1.01.022.595.027 1.153-.671 1.538-.697.383-1.564.508-2.403 1.088-.596.41-.709 1.033-.78 1.459l-.051.41c-.029.273.173.498.448.498h5.012c.457-.24.89-.402 1.259-.537zM5.064 15.096c.07-.427.184-1.05.78-1.46.838-.581 1.708-.706 2.404-1.089.699-.385.693-.943.672-1.537-.014-.393-.08-.477-.354-1.01-.406-.787-.515-1.467-.576-2.049-.093-.909.008-2.155.625-2.856.615-.7 1.398-.787 1.398-.787l.492-.055h.002l.496.055s.781.087 1.396.787c.615.701.72 1.947.623 2.855-.062.583-.172 1.262-.571 2.049-.271.533-.341.617-.354 1.01-.021.595-.062 1.22.637 1.604.697.385 1.604.527 2.438 1.104.923.641.822 1.783.822 1.783-.022.275-.269.5-.542.5h-9.991c-.275 0-.477-.223-.448-.496l.051-.408z"/></g></svg>
|
After Width: | Height: | Size: 1 KiB |
1
2017/web/core/misc/icons/000000/puzzlepiece.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#000000" d="M11.002 11v2.529c0 .275-.225.471-.5.471h-3c-.827 0-1.112-.754-.604-1.316l.81-.725c.509-.562.513-1.461-.097-2.01-.383-.344-1.027-.728-2.111-.728s-1.727.386-2.109.731c-.609.549-.606 1.45-.097 2.015l.808.717c.509.562.223 1.316-.602 1.316h-3c-.276 0-.5-.193-.5-.471v-9.029c0-.276.224-.5.5-.5h3c.825 0 1.111-.768.602-1.332l-.808-.73c-.51-.563-.513-1.465.097-2.014.382-.344 1.025-.731 2.109-.731s1.728.387 2.111.731c.608.548.606 1.45.097 2.014l-.81.73c-.509.564-.223 1.332.603 1.332h3c.274 0 .5.224.5.5v2.5c0 .825.642 1.111 1.233.602l.771-.808c.599-.51 1.547-.513 2.127.097.364.383.772 1.025.772 2.109s-.408 1.727-.771 2.109c-.58.604-1.529.604-2.127.097l-.77-.808c-.593-.509-1.234-.223-1.234.602z"/></svg>
|
After Width: | Height: | Size: 787 B |
1
2017/web/core/misc/icons/000000/questionmark-disc.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#000000" d="M8.002 1c-3.868 0-7.002 3.134-7.002 7s3.134 7 7.002 7c3.865 0 7-3.134 7-7s-3.135-7-7-7zm3 5c0 .551-.16 1.085-.477 1.586l-.158.22c-.07.093-.189.241-.361.393-.168.148-.35.299-.545.447l-.203.189-.141.129-.096.17-.021.235v.63h-2.001v-.704c.026-.396.078-.73.204-.999.125-.269.271-.498.439-.688l.225-.21-.01-.015.176-.14.137-.128c.186-.139.357-.277.516-.417l.148-.18c.098-.152.168-.323.168-.518 0-.552-.447-1-1-1s-1.002.448-1.002 1h-2c0-1.657 1.343-3 3.002-3 1.656 0 3 1.343 3 3zm-1.75 6.619c0 .344-.281.625-.625.625h-1.25c-.345 0-.626-.281-.626-.625v-1.238c0-.344.281-.625.626-.625h1.25c.344 0 .625.281.625.625v1.238z"/></svg>
|
After Width: | Height: | Size: 709 B |
1
2017/web/core/misc/icons/000000/wrench.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#000000" d="M14.416 11.586l-.01-.008v-.001l-5.656-5.656c.15-.449.252-.921.252-1.421 0-2.485-2.016-4.5-4.502-4.5-.505 0-.981.102-1.434.255l2.431 2.431-.588 2.196-2.196.588-2.445-2.445c-.162.464-.268.956-.268 1.475 0 2.486 2.014 4.5 4.5 4.5.5 0 .972-.102 1.421-.251l5.667 5.665c.781.781 2.047.781 2.828 0s.781-2.047 0-2.828z"/></svg>
|
After Width: | Height: | Size: 407 B |
1
2017/web/core/misc/icons/004875/twistie-down.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#004875" d="M2.611 5.393c-.17-.216-.084-.393.191-.393h10.397c.275 0 .361.177.191.393l-5.08 6.464c-.17.216-.452.216-.622 0l-5.077-6.464z"/></svg>
|
After Width: | Height: | Size: 220 B |
1
2017/web/core/misc/icons/004875/twistie-up.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#004875" d="M13.391 10.607c.17.216.084.393-.191.393h-10.398c-.275 0-.361-.177-.191-.393l5.08-6.464c.17-.216.45-.216.62 0l5.08 6.464z"/></svg>
|
After Width: | Height: | Size: 217 B |
1
2017/web/core/misc/icons/0074bd/chevron-left.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#0074bd" d="M7.951 7.645c-.193.196-.193.516 0 .71l3.258 3.29c.193.193.191.519-.002.709l-1.371 1.371c-.193.192-.512.191-.707 0l-5.335-5.371c-.194-.194-.194-.514 0-.708l5.335-5.369c.195-.195.514-.195.707-.001l1.371 1.371c.193.194.195.513.002.709l-3.258 3.289z"/></svg>
|
After Width: | Height: | Size: 342 B |
1
2017/web/core/misc/icons/0074bd/chevron-right.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#0074bd" d="M8.053 8.355c.193-.195.193-.517 0-.711l-3.26-3.289c-.193-.195-.192-.514.002-.709l1.371-1.371c.194-.194.512-.193.706.001l5.335 5.369c.195.195.195.515 0 .708l-5.335 5.37c-.194.192-.512.193-.706.002l-1.371-1.371c-.194-.195-.195-.514-.002-.709l3.26-3.29z"/></svg>
|
After Width: | Height: | Size: 347 B |
1
2017/web/core/misc/icons/008ee6/twistie-down.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#008ee6" d="M2.611 5.393c-.17-.216-.084-.393.191-.393h10.397c.275 0 .361.177.191.393l-5.08 6.464c-.17.216-.452.216-.622 0l-5.077-6.464z"/></svg>
|
After Width: | Height: | Size: 220 B |
1
2017/web/core/misc/icons/008ee6/twistie-up.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#008ee6" d="M13.391 10.607c.17.216.084.393-.191.393h-10.398c-.275 0-.361-.177-.191-.393l5.08-6.464c.17-.216.45-.216.62 0l5.08 6.464z"/></svg>
|
After Width: | Height: | Size: 217 B |
1
2017/web/core/misc/icons/333333/caret-down.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#333333" d="M3.8 5.4c-.165-.22-.075-.4.2-.4h8.002c.275 0 .365.18.199.4l-3.898 5.2c-.166.221-.436.221-.6 0l-3.903-5.2z"/></svg>
|
After Width: | Height: | Size: 202 B |
1
2017/web/core/misc/icons/424242/loupe.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#424242" d="M14.648 12.788l-4.23-4.228c.525-.855.834-1.858.834-2.938 0-3.105-2.52-5.624-5.627-5.624-3.106.002-5.625 2.521-5.625 5.627 0 3.105 2.519 5.625 5.625 5.625 1.076 0 2.08-.309 2.936-.832l4.229 4.229c.194.195.515.195.707 0l1.151-1.146c.194-.2.194-.519 0-.713zm-13.35-7.163c0-2.39 1.938-4.327 4.327-4.327 2.391 0 4.328 1.937 4.328 4.327 0 2.391-1.936 4.327-4.328 4.327-2.39 0-4.327-1.936-4.327-4.327z"/></svg>
|
After Width: | Height: | Size: 491 B |
1
2017/web/core/misc/icons/505050/loupe.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#505050" d="M14.648 12.788l-4.23-4.228c.525-.855.834-1.858.834-2.938 0-3.105-2.52-5.624-5.627-5.624-3.106.002-5.625 2.521-5.625 5.627 0 3.105 2.519 5.625 5.625 5.625 1.076 0 2.08-.309 2.936-.832l4.229 4.229c.194.195.515.195.707 0l1.151-1.146c.194-.2.194-.519 0-.713zm-13.35-7.163c0-2.39 1.938-4.327 4.327-4.327 2.391 0 4.328 1.937 4.328 4.327 0 2.391-1.936 4.327-4.328 4.327-2.39 0-4.327-1.936-4.327-4.327z"/></svg>
|
After Width: | Height: | Size: 491 B |
1
2017/web/core/misc/icons/5181c6/chevron-disc-down.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#5181C6" d="M8.002 1c-3.869 0-7.002 3.134-7.002 7s3.133 7 7.002 7c3.865 0 7-3.134 7-7s-3.135-7-7-7zm4.459 6.336l-4.105 4.105c-.196.189-.515.189-.708 0l-4.107-4.105c-.194-.194-.194-.513 0-.707l.977-.978c.194-.194.513-.194.707 0l2.422 2.421c.192.195.513.195.708 0l2.422-2.42c.188-.194.512-.194.707 0l.977.977c.193.194.193.513 0 .707z"/></svg>
|
After Width: | Height: | Size: 416 B |
1
2017/web/core/misc/icons/5181c6/chevron-disc-up.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#5181C6" d="M8.002 1c-3.867 0-7.002 3.134-7.002 7s3.135 7 7.002 7 7-3.134 7-7-3.133-7-7-7zm4.462 8.37l-.979.979c-.19.19-.516.19-.707 0l-2.422-2.419c-.196-.194-.515-.194-.708 0l-2.423 2.417c-.194.193-.513.193-.707 0l-.977-.976c-.194-.194-.194-.514 0-.707l4.106-4.106c.193-.194.515-.194.708 0l4.109 4.105c.19.192.19.513 0 .707z"/></svg>
|
After Width: | Height: | Size: 410 B |
1
2017/web/core/misc/icons/5181c6/pencil.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g><path fill="#5181C6" d="M14.545 3.042l-1.586-1.585c-.389-.389-1.025-.389-1.414 0l-1.293 1.293 3 3 1.293-1.293c.389-.389.389-1.026 0-1.415z"/><rect fill="#5181C6" x="5.129" y="3.8" transform="matrix(-.707 -.707 .707 -.707 6.189 20.064)" width="4.243" height="9.899"/><path fill="#5181C6" d="M.908 14.775c-.087.262.055.397.316.312l2.001-.667-1.65-1.646-.667 2.001z"/></g></svg>
|
After Width: | Height: | Size: 442 B |
1
2017/web/core/misc/icons/5181c6/twistie-down.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#5181C6" d="M2.611 5.393c-.17-.216-.084-.393.191-.393h10.397c.275 0 .361.177.191.393l-5.08 6.464c-.17.216-.452.216-.622 0l-5.077-6.464z"/></svg>
|
After Width: | Height: | Size: 220 B |
1
2017/web/core/misc/icons/5181c6/twistie-up.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#5181C6" d="M13.391 10.607c.17.216.084.393-.191.393h-10.398c-.275 0-.361-.177-.191-.393l5.08-6.464c.17-.216.45-.216.62 0l5.08 6.464z"/></svg>
|
After Width: | Height: | Size: 217 B |
1
2017/web/core/misc/icons/73b355/check.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#73b355"><path d="M6.464 13.676c-.194.194-.513.194-.707 0l-4.96-4.955c-.194-.193-.194-.513 0-.707l1.405-1.407c.194-.195.512-.195.707 0l2.849 2.848c.194.193.513.193.707 0l6.629-6.626c.195-.194.514-.194.707 0l1.404 1.404c.193.194.193.513 0 .707l-8.741 8.736z"/></svg>
|
After Width: | Height: | Size: 334 B |
1
2017/web/core/misc/icons/787878/barchart.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g><path fill="#787878" d="M4 13.529c0 .275-.225.5-.5.5h-3c-.275 0-.5-.225-.5-.5v-4.25c0-.274.225-.5.5-.5h3c.275 0 .5.226.5.5v4.25zM10.002 13.529c0 .275-.225.5-.5.5h-3.002c-.275 0-.5-.225-.5-.5v-13c0-.275.225-.5.5-.5h3.002c.275 0 .5.225.5.5v13zM16.002 13.529c0 .275-.225.5-.5.5h-3c-.275 0-.5-.225-.5-.5v-9.5c0-.275.225-.5.5-.5h3c.275 0 .5.225.5.5v9.5z"/></g></svg>
|
After Width: | Height: | Size: 428 B |
1
2017/web/core/misc/icons/787878/chevron-disc-down.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#787878" d="M8.002 1c-3.869 0-7.002 3.134-7.002 7s3.133 7 7.002 7c3.865 0 7-3.134 7-7s-3.135-7-7-7zm4.459 6.336l-4.105 4.105c-.196.189-.515.189-.708 0l-4.107-4.105c-.194-.194-.194-.513 0-.707l.977-.978c.194-.194.513-.194.707 0l2.422 2.421c.192.195.513.195.708 0l2.422-2.42c.188-.194.512-.194.707 0l.977.977c.193.194.193.513 0 .707z"/></svg>
|
After Width: | Height: | Size: 416 B |
1
2017/web/core/misc/icons/787878/chevron-disc-up.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#787878" d="M8.002 1c-3.867 0-7.002 3.134-7.002 7s3.135 7 7.002 7 7-3.134 7-7-3.133-7-7-7zm4.462 8.37l-.979.979c-.19.19-.516.19-.707 0l-2.422-2.419c-.196-.194-.515-.194-.708 0l-2.423 2.417c-.194.193-.513.193-.707 0l-.977-.976c-.194-.194-.194-.514 0-.707l4.106-4.106c.193-.194.515-.194.708 0l4.109 4.105c.19.192.19.513 0 .707z"/></svg>
|
After Width: | Height: | Size: 410 B |
1
2017/web/core/misc/icons/787878/cog.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#787878" d="M15.176 9.041c.045-.327.076-.658.076-.998 0-.36-.035-.71-.086-1.056l-2.275-.293c-.115-.426-.283-.827-.498-1.201l1.396-1.808c-.416-.551-.906-1.039-1.459-1.452l-1.807 1.391c-.373-.215-.774-.383-1.2-.499l-.292-2.252c-.338-.048-.677-.081-1.029-.081s-.694.033-1.032.082l-.291 2.251c-.426.116-.826.284-1.2.499l-1.805-1.391c-.552.413-1.044.901-1.459 1.452l1.395 1.808c-.215.374-.383.774-.499 1.2l-2.276.294c-.05.346-.085.696-.085 1.056 0 .34.031.671.077.998l2.285.295c.115.426.284.826.499 1.2l-1.417 1.836c.411.55.896 1.038 1.443 1.452l1.842-1.42c.374.215.774.383 1.2.498l.298 2.311c.337.047.677.08 1.025.08s.688-.033 1.021-.08l.299-2.311c.426-.115.826-.283 1.201-.498l1.842 1.42c.547-.414 1.031-.902 1.443-1.452l-1.416-1.837c.215-.373.383-.773.498-1.199l2.286-.295zm-7.174 1.514c-1.406 0-2.543-1.137-2.543-2.541 0-1.402 1.137-2.541 2.543-2.541 1.402 0 2.541 1.138 2.541 2.541 0 1.404-1.139 2.541-2.541 2.541z"/></svg>
|
After Width: | Height: | Size: 999 B |
1
2017/web/core/misc/icons/787878/ex.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#787878" d="M3.51 13.925c.194.194.512.195.706.001l3.432-3.431c.194-.194.514-.194.708 0l3.432 3.431c.192.194.514.193.707-.001l1.405-1.417c.191-.195.189-.514-.002-.709l-3.397-3.4c-.192-.193-.192-.514-.002-.708l3.401-3.43c.189-.195.189-.515 0-.709l-1.407-1.418c-.195-.195-.513-.195-.707-.001l-3.43 3.431c-.195.194-.516.194-.708 0l-3.432-3.431c-.195-.195-.512-.194-.706.001l-1.407 1.417c-.194.195-.194.515 0 .71l3.403 3.429c.193.195.193.514-.001.708l-3.4 3.399c-.194.195-.195.516-.001.709l1.406 1.419z"/></svg>
|
After Width: | Height: | Size: 582 B |
1
2017/web/core/misc/icons/787878/file.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g><path fill="#787878" d="M12.502 7h-5c-.276 0-.502-.225-.502-.5v-5c0-.275-.225-.5-.5-.5h-3c-.275 0-.5.225-.5.5v12.029c0 .275.225.5.5.5h9.002c.275 0 .5-.225.5-.5v-6.029c0-.275-.225-.5-.5-.5zM8.502 6h4c.275 0 .34-.159.146-.354l-4.293-4.292c-.195-.195-.353-.129-.353.146v4c0 .275.225.5.5.5z"/></g></svg>
|
After Width: | Height: | Size: 366 B |
1
2017/web/core/misc/icons/787878/key.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px"><path fill="#787878" d="M13.727,7.714C12.418,6.406,10.479,6.145,8.9,6.896L3.001,1H0v2h1l0,0v1.618L1.378,5H3v1h1v1.622h1.622l0.864,0.862L5.5,9.5l0.992,0.99c-0.062,1.162,0.335,2.346,1.223,3.234c1.66,1.653,4.352,1.653,6.012,0C15.385,12.064,15.385,9.373,13.727,7.714z M12.898,12.896c-0.646,0.646-1.693,0.646-2.338,0c-0.646-0.646-0.646-1.692,0-2.338c0.645-0.646,1.688-0.646,2.338,0C13.543,11.204,13.543,12.252,12.898,12.896z"/></svg>
|
After Width: | Height: | Size: 496 B |
1
2017/web/core/misc/icons/787878/move.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#787878" d="M14.904 7.753l-2.373-2.372c-.291-.292-.529-.193-.529.22v1.399h-3v-3h1.398c.414 0 .512-.239.221-.53l-2.371-2.372c-.137-.136-.36-.136-.497 0l-2.372 2.372c-.292.292-.193.53.22.53h1.399v3h-3v-1.369c0-.413-.239-.511-.53-.22l-2.372 2.372c-.136.136-.136.359 0 .494l2.372 2.372c.291.292.53.192.53-.219v-1.43h3v3h-1.4c-.413 0-.511.238-.22.529l2.374 2.373c.137.137.36.137.495 0l2.373-2.373c.29-.291.19-.529-.222-.529h-1.398v-3h3v1.4c0 .412.238.511.529.219l2.373-2.371c.137-.137.137-.359 0-.495z"/></svg>
|
After Width: | Height: | Size: 581 B |
1
2017/web/core/misc/icons/787878/orgchart.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px"><path fill="#787878" d="M15.002,11.277c0-0.721,0-1.471,0-2.014c0-1.456-0.824-2.25-2.25-2.25c-1.428,0-3.5,0-3.5,0c-0.139,0-0.25-0.112-0.25-0.25v-2.04c0.596-0.346,1-0.984,1-1.723c0-1.104-0.895-2-2-2C6.896,1,6,1.896,6,3c0,0.738,0.405,1.376,1,1.722v2.042c0,0.138-0.112,0.25-0.25,0.25c0,0-2.138,0-3.5,0S1,7.932,1,9.266c0,0.521,0,1.277,0,2.012c-0.595,0.353-1,0.984-1,1.729c0,1.104,0.896,2,2,2s2-0.896,2-2c0-0.732-0.405-1.377-1-1.729V9.266c0-0.139,0.112-0.25,0.25-0.25h3.536C6.904,9.034,7,9.126,7,9.25v2.027C6.405,11.624,6,12.26,6,13c0,1.104,0.896,2,2.002,2c1.105,0,2-0.896,2-2c0-0.738-0.404-1.376-1-1.723V9.25c0-0.124,0.098-0.216,0.215-0.234h3.535c0.137,0,0.25,0.111,0.25,0.25v2.012c-0.596,0.353-1,0.984-1,1.729c0,1.104,0.896,2,2,2s2-0.896,2-2C16.002,12.262,15.598,11.623,15.002,11.277z"/></svg>
|
After Width: | Height: | Size: 857 B |
1
2017/web/core/misc/icons/787878/paintbrush.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#787878" d="M8.184 7.928l-1.905 1.983-3.538-2.436 4.714-4.713 2.623 3.183-1.894 1.983zm-1.746-7.523c-.236-.416-.803-.649-1.346.083-.259.349-4.727 4.764-4.91 4.983-.182.218-.294.721.044.976.34.258 5.611 3.933 5.611 3.933l-.225.229c.7.729.816.854 1.046.863.75.016 2.035-1.457 2.578-.854.541.604 3.537 3.979 3.537 3.979.51.531 1.305.559 1.815.041.521-.521.541-1.311.025-1.848 0 0-2.742-2.635-3.904-3.619-.578-.479.869-2.051.854-2.839-.008-.238-.125-.361-.823-1.095l-.22.243c0 .003-3.846-4.659-4.082-5.075z"/></svg>
|
After Width: | Height: | Size: 587 B |
1
2017/web/core/misc/icons/787878/pencil.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g><path fill="#787878" d="M14.545 3.042l-1.586-1.585c-.389-.389-1.025-.389-1.414 0l-1.293 1.293 3 3 1.293-1.293c.389-.389.389-1.026 0-1.415z"/><rect fill="#787878" x="5.129" y="3.8" transform="matrix(-.707 -.707 .707 -.707 6.189 20.064)" width="4.243" height="9.899"/><path fill="#787878" d="M.908 14.775c-.087.262.055.397.316.312l2.001-.667-1.65-1.646-.667 2.001z"/></g></svg>
|
After Width: | Height: | Size: 442 B |
1
2017/web/core/misc/icons/787878/people.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g><path fill="#787878" d="M6.722 11.291l.451-.17-.165-.32c-.536-1.039-.685-1.934-.761-2.672-.082-.808-.144-2.831 1.053-4.189.244-.278.493-.493.743-.675.012-.826-.135-1.766-.646-2.345-.618-.7-1.4-.787-1.4-.787l-.497-.055-.498.055s-.783.087-1.398.787c-.617.702-.717 1.948-.625 2.855.06.583.17 1.263.574 2.05.274.533.341.617.355 1.01.022.595.027 1.153-.671 1.538-.697.383-1.564.508-2.403 1.088-.596.41-.709 1.033-.78 1.459l-.051.41c-.029.273.173.498.448.498h5.012c.457-.24.89-.402 1.259-.537zM5.064 15.096c.07-.427.184-1.05.78-1.46.838-.581 1.708-.706 2.404-1.089.699-.385.693-.943.672-1.537-.014-.393-.08-.477-.354-1.01-.406-.787-.515-1.467-.576-2.049-.093-.909.008-2.155.625-2.856.615-.7 1.398-.787 1.398-.787l.492-.055h.002l.496.055s.781.087 1.396.787c.615.701.72 1.947.623 2.855-.062.583-.172 1.262-.571 2.049-.271.533-.341.617-.354 1.01-.021.595-.062 1.22.637 1.604.697.385 1.604.527 2.438 1.104.923.641.822 1.783.822 1.783-.022.275-.269.5-.542.5h-9.991c-.275 0-.477-.223-.448-.496l.051-.408z"/></g></svg>
|
After Width: | Height: | Size: 1 KiB |
1
2017/web/core/misc/icons/787878/plus.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px"><path fill="#787878" d="M0.656,9.023c0,0.274,0.224,0.5,0.499,0.5l4.853,0.001c0.274-0.001,0.501,0.226,0.5,0.5l0.001,4.853 c-0.001,0.273,0.227,0.5,0.501,0.5l1.995-0.009c0.273-0.003,0.497-0.229,0.5-0.503l0.002-4.806c0-0.272,0.228-0.5,0.499-0.502 l4.831-0.021c0.271-0.005,0.497-0.23,0.501-0.502l0.008-1.998c0-0.276-0.225-0.5-0.499-0.5l-4.852,0c-0.275,0-0.502-0.228-0.501-0.5 L9.493,1.184c0-0.275-0.225-0.499-0.5-0.499L6.997,0.693C6.722,0.694,6.496,0.92,6.495,1.195L6.476,6.026 c-0.001,0.274-0.227,0.5-0.501,0.5L1.167,6.525C0.892,6.526,0.665,6.752,0.665,7.026L0.656,9.023z"/></svg>
|
After Width: | Height: | Size: 644 B |
1
2017/web/core/misc/icons/787878/push-left.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g><path fill="#787878" d="M2.5 2h-2.491v12.029h2.491c.276 0 .5-.225.5-.5v-11.029c0-.276-.224-.5-.5-.5zM14.502 6.029h-4c-.275 0-.5-.225-.5-.5v-1c0-.275-.16-.341-.354-.146l-3.294 3.292c-.194.194-.194.513 0 .708l3.294 3.293c.188.193.354.129.354-.146v-1c0-.271.227-.5.5-.5h4c.275 0 .5-.225.5-.5v-3c0-.276-.225-.501-.5-.501z"/></g></svg>
|
After Width: | Height: | Size: 397 B |