diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index da3a277..481adea 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -1752,7 +1752,8 @@ function drupal_anonymous_user() {
*
* In order to bootstrap Drupal from another PHP script, you can use this code:
* @code
- * require_once '/path/to/drupal/core/includes/bootstrap.inc';
+ * define('DRUPAL_ROOT', '/path/to/drupal');
+ * require_once DRUPAL_ROOT . '/core/includes/bootstrap.inc';
* drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
* @endcode
*
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 1980f2f..358a59a 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2,7 +2,6 @@
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\Json;
-use Drupal\Component\Utility\SortArray;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Tags;
use Drupal\Component\Utility\Url;
@@ -2835,9 +2834,7 @@ function drupal_get_library($module, $name = NULL) {
if (is_scalar($options)) {
// The JavaScript or CSS file has been specified in shorthand
// format, without an array of options. In this case $options is the
- // filename. Convert the shorthand version and remove the old array
- // key.
- unset($module_libraries[$key]['js'][$file]);
+ // filename.
$file = $options;
$options = array();
}
@@ -3731,31 +3728,7 @@ function drupal_render_page($page) {
* - If this element has an array of #theme_wrappers defined and
* #render_children is not set, #children is then re-rendered by passing the
* element in its current state to theme() successively for each item in
- * #theme_wrappers. Since #theme and #theme_wrappers hooks often define
- * variables with the same names it is possible to explicitly override each
- * attribute passed to each #theme_wrappers hook by setting the hook name as
- * the key and an array of overrides as the value in #theme_wrappers array.
- * For example, if we have a render element as follows:
- * @code
- * array(
- * '#theme' => 'image',
- * '#attributes' => array('class' => 'foo'),
- * '#theme_wrappers' => array('container'),
- * );
- * @endcode
- * and we need to pass the class 'bar' as an attribute for 'container', we
- * can rewrite our element thus:
- * @code
- * array(
- * '#theme' => 'image',
- * '#attributes' => array('class' => 'foo'),
- * '#theme_wrappers' => array(
- * 'container' => array(
- * '#attributes' => array('class' => 'bar'),
- * ),
- * ),
- * );
- * @endcode
+ * #theme_wrappers.
* - If this element has an array of #post_render functions defined, they are
* called sequentially to modify the rendered #children. Unlike #pre_render
* functions, #post_render functions are passed both the rendered #children
@@ -3884,24 +3857,8 @@ function drupal_render(&$elements) {
// If the internal #render_children property is set, do not call the
// #theme_wrappers function(s) to prevent infinite recursion.
if (isset($elements['#theme_wrappers']) && !isset($elements['#render_children'])) {
- foreach ($elements['#theme_wrappers'] as $key => $value) {
- // If the value of a #theme_wrappers item is an array then the theme hook
- // is found in the key of the item and the value contains attribute
- // overrides. Attribute overrides replace key/value pairs in $elements for
- // only this theme() call. This allows #theme hooks and #theme_wrappers
- // hooks to share variable names without conflict or ambiguity.
- $wrapper_elements = $elements;
- if (is_array($value)) {
- $wrapper_hook = $key;
- foreach ($value as $attribute => $override) {
- $wrapper_elements[$attribute] = $override;
- }
- }
- else {
- $wrapper_hook = $value;
- }
-
- $elements['#children'] = theme($wrapper_hook, $wrapper_elements);
+ foreach ($elements['#theme_wrappers'] as $theme_wrapper) {
+ $elements['#children'] = theme($theme_wrapper, $elements);
}
}
@@ -4274,16 +4231,14 @@ function drupal_render_cid_create($elements) {
* that optionally include a '#weight' key.
* @param $b
* Second item for comparison.
- *
- * @return int
- * The comparison result for uasort().
- *
- * @see \Drupal\Component\Utility\SortArray::sortByWeightProperty()
- *
- * @deprecated as of Drupal 8.0. Use SortArray::sortByWeightProperty() instead.
*/
function element_sort($a, $b) {
- return SortArray::sortByWeightProperty($a, $b);
+ $a_weight = (is_array($a) && isset($a['#weight'])) ? $a['#weight'] : 0;
+ $b_weight = (is_array($b) && isset($b['#weight'])) ? $b['#weight'] : 0;
+ if ($a_weight == $b_weight) {
+ return 0;
+ }
+ return ($a_weight < $b_weight) ? -1 : 1;
}
/**
@@ -4298,16 +4253,11 @@ function element_sort($a, $b) {
* that optionally include a '#title' key.
* @param $b
* Second item for comparison.
- *
- * @return int
- * The comparison result for uasort().
- *
- * @see \Drupal\Component\Utility\SortArray::sortByTitleProperty()
- *
- * @deprecated as of Drupal 8.0. Use SortArray::sortByTitleProperty() instead.
*/
function element_sort_by_title($a, $b) {
- return SortArray::sortByTitleProperty($a, $b);
+ $a_title = (is_array($a) && isset($a['#title'])) ? $a['#title'] : '';
+ $b_title = (is_array($b) && isset($b['#title'])) ? $b['#title'] : '';
+ return strnatcasecmp($a_title, $b_title);
}
/**
@@ -4365,16 +4315,14 @@ function element_info_property($type, $property_name, $default = NULL) {
* element, a default value of 0 will be used.
* @param $b
* Second item for comparison.
- *
- * @return int
- * The comparison result for uasort().
- *
- * @see \Drupal\Component\Utility\SortArray::sortByWeightElement()
- *
- * @deprecated as of Drupal 8.0. Use SortArray::sortByWeightElement() instead.
*/
function drupal_sort_weight($a, $b) {
- return SortArray::sortByWeightElement((array) $a, (array) $b);
+ $a_weight = (is_array($a) && isset($a['weight'])) ? $a['weight'] : 0;
+ $b_weight = (is_array($b) && isset($b['weight'])) ? $b['weight'] : 0;
+ if ($a_weight == $b_weight) {
+ return 0;
+ }
+ return ($a_weight < $b_weight) ? -1 : 1;
}
/**
@@ -4387,16 +4335,15 @@ function drupal_sort_weight($a, $b) {
* that optionally include a 'title' key.
* @param $b
* Second item for comparison.
- *
- * @return int
- * The comparison result for uasort().
- *
- * @see \Drupal\Component\Utility\SortArray::sortByTitleElement()
- *
- * @deprecated as of Drupal 8.0. Use SortArray::sortByTitleElement() instead.
*/
function drupal_sort_title($a, $b) {
- return SortArray::sortByTitleElement($a, $b);
+ if (!isset($b['title'])) {
+ return -1;
+ }
+ if (!isset($a['title'])) {
+ return 1;
+ }
+ return strcasecmp($a['title'], $b['title']);
}
/**
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 7e0e5e2..ae39080 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1745,6 +1745,20 @@ function theme_links($variables) {
}
/**
+ * Returns HTML for wrapping a dropbutton menu.
+ *
+ * @param array $variables
+ * An associative array containing:
+ * - element: An associative array containing the properties and children of
+ * the dropbutton menu. Properties used: #children.
+ */
+function theme_dropbutton_wrapper($variables) {
+ if (!empty($variables['element']['#children'])) {
+ return '
' . $variables['element']['#children'] . '
';
+ }
+}
+
+/**
* Returns HTML for an image.
*
* @param $variables
@@ -2322,6 +2336,27 @@ function theme_more_link($variables) {
}
/**
+ * Returns HTML for a progress bar.
+ *
+ * Note that the core Batch API uses this only for non-JavaScript batch jobs.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - percent: The percentage of the progress.
+ * - message: A string containing information to be displayed.
+ */
+function theme_progress_bar($variables) {
+ $output = '
';
+ $output .= '
' . $variables['label'] . '
';
+ $output .= '
';
+ $output .= '
' . $variables['percent'] . '%
';
+ $output .= '
' . $variables['message'] . '
';
+ $output .= '
';
+
+ return $output;
+}
+
+/**
* Returns HTML for an indentation div; used for drag and drop tables.
*
* @param $variables
@@ -2682,6 +2717,10 @@ function template_preprocess_page(&$variables) {
$variables['main_menu'] = array(
'#theme' =>'links__system_main_menu',
'#links' => $variables['main_menu'],
+ '#attributes' => array(
+ 'id' => 'main-menu',
+ 'class' => array('links', 'inline', 'clearfix'),
+ ),
'#heading' => array(
'text' => t('Main menu'),
'class' => array('visually-hidden'),
@@ -2692,6 +2731,10 @@ function template_preprocess_page(&$variables) {
$variables['secondary_menu'] = array(
'#theme' =>'links__system_secondary_menu',
'#links' => $variables['secondary_menu'],
+ '#attributes' => array(
+ 'id' => 'secondary-menu',
+ 'class' => array('links', 'inline', 'clearfix'),
+ ),
'#heading' => array(
'text' => t('Secondary menu'),
'class' => array('visually-hidden'),
@@ -2998,8 +3041,7 @@ function drupal_common_theme() {
'variables' => array('links' => array(), 'attributes' => array('class' => array('links')), 'heading' => array()),
),
'dropbutton_wrapper' => array(
- 'variables' => array('children' => NULL),
- 'template' => 'dropbutton-wrapper',
+ 'render element' => 'element',
),
'image' => array(
// HTML 4 and XHTML 1.0 always require an alt attribute. The HTML 5 draft
@@ -3040,8 +3082,7 @@ function drupal_common_theme() {
'variables' => array('url' => NULL, 'title' => NULL)
),
'progress_bar' => array(
- 'variables' => array('label' => NULL, 'percent' => NULL, 'message' => NULL),
- 'template' => 'progress-bar',
+ 'variables' => array('percent' => NULL, 'message' => NULL),
),
'indentation' => array(
'variables' => array('size' => 1),
@@ -3057,12 +3098,15 @@ function drupal_common_theme() {
),
'task_list' => array(
'variables' => array('items' => NULL, 'active' => NULL, 'variant' => NULL),
+ 'template' => 'task-list',
),
'authorize_message' => array(
'variables' => array('message' => NULL, 'success' => TRUE),
+ 'template' => 'authorize-message',
),
'authorize_report' => array(
- 'variables' => array('messages' => array()),
+ 'variables' => array('messages' => array(), 'attributes' => array()),
+ 'template' => 'authorize-report',
),
// From pager.inc.
'pager' => array(
diff --git a/core/includes/theme.maintenance.inc b/core/includes/theme.maintenance.inc
index 5c35ac3..be606c3 100644
--- a/core/includes/theme.maintenance.inc
+++ b/core/includes/theme.maintenance.inc
@@ -6,6 +6,7 @@
*/
use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Template\Attribute;
/**
* Sets up the theming system for maintenance page.
@@ -106,17 +107,16 @@ function _theme_load_offline_registry($theme, $base_theme = NULL, $theme_engine
}
/**
- * Returns HTML for a list of maintenance tasks to perform.
+ * Prepares variables for maintenance task list templates.
*
- * @param $variables
+ * Default template: task-list.html.twig.
+ *
+ * @param array $variables
* An associative array containing:
* - items: An associative array of maintenance tasks.
* - active: The key for the currently active maintenance task.
- * - variant: A variant name to be used for a CSS class.
- *
- * @ingroup themeable
*/
-function theme_task_list($variables) {
+function template_preprocess_task_list(&$variables) {
$items = $variables['items'];
$active = $variables['active'];
if (isset($variables['variant'])) {
@@ -127,76 +127,59 @@ function theme_task_list($variables) {
}
$done = isset($items[$active]) || $active == NULL;
- $output = '
';
- }
- return $output;
-}
-
-/**
- * Returns HTML for a single log message from the authorize.php batch operation.
- *
- * @param $variables
- * An associative array containing:
- * - message: The log message.
- * - success: A boolean indicating failure or success.
- *
- * @ingroup themeable
- */
-function theme_authorize_message($variables) {
- $message = $variables['message'];
- $success = $variables['success'];
- if ($success) {
- $item = array('data' => $message, 'class' => array('success'));
- }
- else {
- $item = array('data' => '' . $message . '', 'class' => array('failure'));
}
- return $item;
}
diff --git a/core/includes/update.inc b/core/includes/update.inc
index d3baaef..4a17a7f 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -13,6 +13,7 @@
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Config\ConfigException;
use Drupal\Core\DrupalKernel;
+use Drupal\Component\Gettext\PoHeader;
use Drupal\Component\Uuid\Uuid;
use Drupal\Component\Utility\NestedArray;
use Symfony\Component\HttpFoundation\Request;
@@ -480,9 +481,14 @@ function update_prepare_d8_language() {
$prefixes = array();
$domains = array();
foreach ($languages as $language) {
+ $header = new PoHeader($language->language);
+ $language->formula = str_replace('$n', 'n', $language->formula);
+ $plural_forms = 'nplurals=' . $language->plurals . '; plural=' . $language->formula . ';';
+ $parsed = $header->parsePluralForms($plural_forms);
+ list($nplurals, $formula) = $parsed;
$plurals[$language->language] = array(
- 'plurals' => $language->plurals,
- 'formula' => $language->formula,
+ 'plurals' => $nplurals,
+ 'formula' => $formula,
);
$javascript[$language->language] = $language->javascript;
$prefixes[$language->language] = $language->prefix;
diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php
index 672a0d1..db2552b 100644
--- a/core/lib/Drupal.php
+++ b/core/lib/Drupal.php
@@ -251,7 +251,7 @@ public static function queue($name, $reliable = FALSE) {
/**
* Returns a key/value storage collection.
*
- * @param string $collection
+ * @param $collection
* Name of the key/value collection to return.
*
* @return \Drupal\Core\KeyValueStore\KeyValueStoreInterface
@@ -305,10 +305,10 @@ public static function entityQuery($entity_type, $conjunction = 'AND') {
/**
* Returns the entity query aggregate object for this entity type.
*
- * @param string $entity_type
+ * @param $entity_type
* The entity type, e.g. node, for which the query object should be
* returned.
- * @param string $conjunction
+ * @param $conjunction
* AND if all conditions in the query need to apply, OR if any of them is
* enough. Optional, defaults to AND.
*
@@ -331,7 +331,7 @@ public static function flood() {
/**
* Returns the module handler.
*
- * @return \Drupal\Core\Extension\ModuleHandlerInterface
+ * @return \Drupal\Core\Extension\ModuleHandler
*/
public static function moduleHandler() {
return static::$container->get('module_handler');
@@ -364,7 +364,7 @@ public static function token() {
/**
* Returns the url generator service.
*
- * @return \Drupal\Core\Routing\PathBasedGeneratorInterface
+ * @return \Drupal\Core\Routing\UrlGenerator
* The url generator service.
*/
public static function urlGenerator() {
diff --git a/core/lib/Drupal/Component/Gettext/PoHeader.php b/core/lib/Drupal/Component/Gettext/PoHeader.php
index 44959eb..421ddd7 100644
--- a/core/lib/Drupal/Component/Gettext/PoHeader.php
+++ b/core/lib/Drupal/Component/Gettext/PoHeader.php
@@ -189,10 +189,14 @@ public function __toString() {
* The Plural-Forms entry value.
*
* @return
- * An array containing the number of plural forms and the converted version
- * of the formula that can be evaluated with PHP later.
+ * An indexed array of parsed plural formula data. Containing:
+ * - 'nplurals': The number of plural forms defined by the plural formula.
+ * - 'plurals': Array of plural positions keyed by plural value.
+ *
+ * @throws Exception
*/
function parsePluralForms($pluralforms) {
+ $plurals = array();
// First, delete all whitespace.
$pluralforms = strtr($pluralforms, array(" " => "", "\t" => ""));
@@ -214,14 +218,31 @@ function parsePluralForms($pluralforms) {
return FALSE;
}
- // Get PHP version of the plural formula.
- $plural = $this->parseArithmetic($plural);
+ // If the number of plurals is zero, we return a default result.
+ if ($nplurals == 0) {
+ return array($nplurals, array('default' => 0));
+ }
+
+ // Calculate possible plural positions of different plural values. All known
+ // plural formula's are repetitive above 100.
+ // For data compression we store the last position the array value
+ // changes and store it as default.
+ $element_stack = $this->parseArithmetic($plural);
+ $default = 0;
+ if ($element_stack !== FALSE) {
+ for ($i = 0; $i <= 199; $i++) {
+ $plurals[$i] = $this->evaluatePlural($element_stack, $i);
+ }
+ $default = $plurals[$i - 1];
+ $plurals = array_filter($plurals, function ($value) use ($default) {
+ return ($value != $default);
+ });
+ $plurals['default'] = $default;
- if ($plural !== FALSE) {
- return array($nplurals, $plural);
+ return array($nplurals, $plurals);
}
else {
- throw new Exception('The plural formula could not be parsed.');
+ throw new \Exception('The plural formula could not be parsed.');
}
}
@@ -247,7 +268,7 @@ private function parseHeader($header) {
}
/**
- * Parses and sanitizes an arithmetic formula into a PHP expression.
+ * Parses and sanitizes an arithmetic formula into a plural element stack.
*
* While parsing, we ensure, that the operators have the right
* precedence and associativity.
@@ -256,7 +277,7 @@ private function parseHeader($header) {
* A string containing the arithmetic formula.
*
* @return
- * A version of the formula to evaluate with PHP later.
+ * A stack of values and operations to be evaluated.
*/
private function parseArithmetic($string) {
// Operator precedence table.
@@ -319,8 +340,9 @@ private function parseArithmetic($string) {
$element_stack[] = $topop;
$topop = array_pop($operator_stack);
}
+ $return = $element_stack;
- // Now extract formula from stack.
+ // Now validate stack.
$previous_size = count($element_stack) + 1;
while (count($element_stack) < $previous_size) {
$previous_size = count($element_stack);
@@ -344,12 +366,7 @@ private function parseArithmetic($string) {
}
// If only one element is left, the number of operators is appropriate.
- if (count($element_stack) == 1) {
- return $element_stack[0];
- }
- else {
- return FALSE;
- }
+ return count($element_stack) == 1 ? $return : FALSE;
}
/**
@@ -417,4 +434,136 @@ private function tokenizeFormula($formula) {
return $tokens;
}
+ /**
+ * Evaluate the plural element stack using a plural value.
+ *
+ * Using an element stack, which represents a plural formula, we calculate
+ * which plural string should be used for a given plural value.
+ *
+ * An example of plural formula parting and evaluation:
+ * Plural formula: 'n!=1'
+ * This formula is parsed by parseArithmetic() to a stack (array) of elements:
+ * array(
+ * 0 => '$n',
+ * 1 => '1',
+ * 2 => '!=',
+ * );
+ * The evaluatePlural() method evaluates the $element_stack using the plural
+ * value $n. Before the actual evaluation, the '$n' in the array is replaced
+ * by the value of $n.
+ * For example: $n = 2 results in:
+ * array(
+ * 0 => '2',
+ * 1 => '1',
+ * 2 => '!=',
+ * );
+ * The stack is processed until only one element is (the result) is left. In
+ * every iteration the top elements of the stack, up until the first operator,
+ * are evaluated. After evaluation the arguments and the operator itself are
+ * removed and replaced by the evaluation result. This is typically 2
+ * arguments and 1 element for the operator.
+ * Because the operator is '!=' the example stack is evaluated as:
+ * $f = (int) 2 != 1;
+ * The resulting stack is:
+ * array(
+ * 0 => 1,
+ * );
+ * With only one element left in the stack (the final result) the loop is
+ * terminated and the result is returned.
+ *
+ * @param array $element_stack
+ * Array of plural formula values and operators create by parseArithmetic().
+ * @param integer $n
+ * The @count number for which we are determining the right plural position.
+ *
+ * @return integer
+ * Number of the plural string to be used for the given plural value.
+ *
+ * @see parseArithmetic()
+ * @throws Exception
+ */
+ protected function evaluatePlural($element_stack, $n) {
+ $count = count($element_stack);
+ $limit = $count;
+ // Replace the '$n' value in the formula by the plural value.
+ for ($i = 0; $i < $count; $i++) {
+ if ($element_stack[$i] === '$n') {
+ $element_stack[$i] = $n;
+ }
+ }
+
+ // We process the stack until only one element is (the result) is left.
+ // We limit the number of evaluation cycles to prevent an endless loop in
+ // case the stack contains an error.
+ while (isset($element_stack[1])) {
+ for ($i = 2; $i < $count; $i++) {
+ // There's no point in checking non-symbols. Also, switch(TRUE) would
+ // match any case and so it would break.
+ if (is_bool($element_stack[$i]) || is_numeric($element_stack[$i])) {
+ continue;
+ }
+ $f = NULL;
+ $length = 3;
+ $delta = 2;
+ switch ($element_stack[$i]) {
+ case '==':
+ $f = $element_stack[$i - 2] == $element_stack[$i - 1];
+ break;
+ case '!=':
+ $f = $element_stack[$i - 2] != $element_stack[$i - 1];
+ break;
+ case '<=':
+ $f = $element_stack[$i - 2] <= $element_stack[$i - 1];
+ break;
+ case '>=':
+ $f = $element_stack[$i - 2] >= $element_stack[$i - 1];
+ break;
+ case '<':
+ $f = $element_stack[$i - 2] < $element_stack[$i - 1];
+ break;
+ case '>':
+ $f = $element_stack[$i - 2] > $element_stack[$i - 1];
+ break;
+ case '+':
+ $f = $element_stack[$i - 2] + $element_stack[$i - 1];
+ break;
+ case '-':
+ $f = $element_stack[$i - 2] - $element_stack[$i - 1];
+ break;
+ case '*':
+ $f = $element_stack[$i - 2] * $element_stack[$i - 1];
+ break;
+ case '/':
+ $f = $element_stack[$i - 2] / $element_stack[$i - 1];
+ break;
+ case '%':
+ $f = $element_stack[$i - 2] % $element_stack[$i - 1];
+ break;
+ case '&&':
+ $f = $element_stack[$i - 2] && $element_stack[$i - 1];
+ break;
+ case '||':
+ $f = $element_stack[$i - 2] || $element_stack[$i - 1];
+ break;
+ case ':':
+ $f = $element_stack[$i - 3] ? $element_stack[$i - 2] : $element_stack[$i - 1];
+ // This operator has 3 preceding elements, instead of the default 2.
+ $length = 5;
+ $delta = 3;
+ break;
+ }
+
+ // If the element is an operator we remove the processed elements and
+ // store the result.
+ if (isset($f)) {
+ array_splice($element_stack, $i - $delta, $length, $f);
+ break;
+ }
+ }
+ }
+ if (!$limit) {
+ throw new \Exception('The plural formula could not be evaluated.');
+ }
+ return (int) $element_stack[0];
+ }
}
diff --git a/core/lib/Drupal/Component/Utility/SortArray.php b/core/lib/Drupal/Component/Utility/SortArray.php
deleted file mode 100644
index 92763f5..0000000
--- a/core/lib/Drupal/Component/Utility/SortArray.php
+++ /dev/null
@@ -1,137 +0,0 @@
-container->get('plugin.manager.entity');
- }
-
- /**
- * Returns the requested cache bin.
- *
- * @param string $bin
- * (optional) The cache bin for which the cache object should be returned,
- * defaults to 'cache'.
- *
- * @return \Drupal\Core\Cache\CacheBackendInterface
- * The cache object associated with the specified bin.
- */
- protected function cache($bin = 'cache') {
- return $this->container->get('cache.' . $bin);
- }
-
- /**
- * Retrieves a configuration object.
- *
- * This is the main entry point to the configuration API. Calling
- * @code $this->config('book.admin') @endcode will return a configuration
- * object in which the book module can store its administrative settings.
- *
- * @param string $name
- * The name of the configuration object to retrieve. The name corresponds to
- * a configuration file. For @code config('book.admin') @endcode, the config
- * object returned will contain the contents of book.admin configuration file.
- *
- * @return \Drupal\Core\Config\Config
- * A configuration object.
- */
- protected function config($name) {
- return $this->container->get('config.factory')->get($name);
- }
-
- /**
- * Returns a key/value storage collection.
- *
- * @param string $collection
- * Name of the key/value collection to return.
- *
- * @return \Drupal\Core\KeyValueStore\KeyValueStoreInterface
- */
- protected function keyValue($collection) {
- return $this->container->get('keyvalue')->get($collection);
- }
-
- /**
- * Returns the state storage service.
- *
- * Use this to store machine-generated data, local to a specific environment
- * that does not need deploying and does not need human editing; for example,
- * the last time cron was run. Data which needs to be edited by humans and
- * needs to be the same across development, production, etc. environments
- * (for example, the system maintenance message) should use config() instead.
- *
- * @return \Drupal\Core\KeyValueStore\KeyValueStoreInterface
- */
- protected function state() {
- return $this->container->get('state');
- }
-
- /**
- * Returns the module handler.
- *
- * @return \Drupal\Core\Extension\ModuleHandlerInterface
- */
- protected function moduleHandler() {
- return $this->container->get('module_handler');
- }
-
- /**
- * Returns the url generator service.
- *
- * @return \Drupal\Core\Routing\PathBasedGeneratorInterface
- * The url generator service.
- */
- protected function urlGenerator() {
- return $this->container->get('url_generator');
- }
-
- /**
- * Translates a string to the current language or to a given language using
- * the string translation service.
- *
- * @param string $string
- * A string containing the English string to translate.
- * @param array $args
- * An associative array of replacements to make after translation. Based
- * on the first character of the key, the value is escaped and/or themed.
- * See \Drupal\Core\Utility\String::format() for details.
- * @param array $options
- * An associative array of additional options, with the following elements:
- * - 'langcode': The language code to translate to a language other than
- * what is used to display the page.
- * - 'context': The context the source string belongs to.
- *
- * @return string
- * The translated string.
- */
- protected function t($string, array $args = array(), array $options = array()) {
- return $this->container->get('string_translation')->translate($string, $args, $options);
- }
-
- /**
- * Returns the language manager service.
- *
- * @return \Drupal\Core\Language\LanguageManager
- * The language manager.
- */
- protected function languageManager() {
- return $this->container->get('language_manager');
- }
-
- /**
- * Returns a redirect response object for the specified
- *
- * @param string $route_name
- * The name of the route to which to redirect.
- * @param array $parameters
- * Parameters for the route.
- * @param int $status
- * The HTTP redirect status code for the redirect. The default is 302 Found.
- * @return \Symfony\Component\HttpFoundation\RedirectResponse
- * A redirect response object that may be returned by the controller.
- */
- public function redirect($route_name, array $parameters = array(), $status = 302) {
- $url = $this->container->get('url_generator')->generate($route_name, $parameters, TRUE);
- return new RedirectResponse($url, $status);
- }
-}
diff --git a/core/lib/Drupal/Core/Controller/ControllerInterface.php b/core/lib/Drupal/Core/Controller/ControllerInterface.php
index 5cdab2e..f87ae12 100644
--- a/core/lib/Drupal/Core/Controller/ControllerInterface.php
+++ b/core/lib/Drupal/Core/Controller/ControllerInterface.php
@@ -11,14 +11,6 @@
/**
* Defines a common interface for route controllers.
- *
- * This interface gives controller classes a factory method for instantiation
- * rather than relying on a services.yml entry. However, it may result in
- * a lot of boilerplate code in the class. As an alternative, controllers that
- * contain only limited glue code ("thin" controllers) should instead extend
- * ControllerBase as that allows direct access to the container. That renders
- * the controller very difficult to unit test so should only be used for
- * controllers that are trivial in complexity.
*/
interface ControllerInterface {
diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Insert.php b/core/lib/Drupal/Core/Database/Driver/mysql/Insert.php
index c41fdf3..233118c 100644
--- a/core/lib/Drupal/Core/Database/Driver/mysql/Insert.php
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Insert.php
@@ -49,8 +49,7 @@ public function __toString() {
// If we're selecting from a SelectQuery, finish building the query and
// pass it back, as any remaining options are irrelevant.
if (!empty($this->fromQuery)) {
- $insert_fields_string = $insert_fields ? ' (' . implode(', ', $insert_fields) . ') ' : ' ';
- return $comments . 'INSERT INTO {' . $this->table . '}' . $insert_fields_string . $this->fromQuery;
+ return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
}
$query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Insert.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Insert.php
index 998cbb7..dffa1fd 100644
--- a/core/lib/Drupal/Core/Database/Driver/pgsql/Insert.php
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Insert.php
@@ -118,8 +118,7 @@ public function __toString() {
// If we're selecting from a SelectQuery, finish building the query and
// pass it back, as any remaining options are irrelevant.
if (!empty($this->fromQuery)) {
- $insert_fields_string = $insert_fields ? ' (' . implode(', ', $insert_fields) . ') ' : ' ';
- return $comments . 'INSERT INTO {' . $this->table . '}' . $insert_fields_string . $this->fromQuery;
+ return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
}
$query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
diff --git a/core/lib/Drupal/Core/Database/Driver/sqlite/Insert.php b/core/lib/Drupal/Core/Database/Driver/sqlite/Insert.php
index 3a0bcaa..e584943 100644
--- a/core/lib/Drupal/Core/Database/Driver/sqlite/Insert.php
+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Insert.php
@@ -40,11 +40,10 @@ public function __toString() {
// If we're selecting from a SelectQuery, finish building the query and
// pass it back, as any remaining options are irrelevant.
if (!empty($this->fromQuery)) {
- $insert_fields_string = $this->insertFields ? ' (' . implode(', ', $this->insertFields) . ') ' : ' ';
- return $comments . 'INSERT INTO {' . $this->table . '}' . $insert_fields_string . $this->fromQuery;
+ return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') ' . $this->fromQuery;
}
return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') VALUES (' . implode(', ', $placeholders) . ')';
}
-}
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Database/Query/Insert.php b/core/lib/Drupal/Core/Database/Query/Insert.php
index 72cadb8..7862436 100644
--- a/core/lib/Drupal/Core/Database/Query/Insert.php
+++ b/core/lib/Drupal/Core/Database/Query/Insert.php
@@ -284,11 +284,10 @@ public function preExecute() {
// first call to fields() does have an effect.
$this->fields(array_merge(array_keys($this->fromQuery->getFields()), array_keys($this->fromQuery->getExpressions())));
}
- else {
- // Don't execute query without fields.
- if (count($this->insertFields) + count($this->defaultFields) == 0) {
- throw new NoFieldsException('There are no fields available to insert with.');
- }
+
+ // Don't execute query without fields.
+ if (count($this->insertFields) + count($this->defaultFields) == 0) {
+ throw new NoFieldsException('There are no fields available to insert with.');
}
// If no values have been added, silently ignore this query. This can happen
diff --git a/core/lib/Drupal/Core/Entity/Controller/EntityListController.php b/core/lib/Drupal/Core/Entity/Controller/EntityListController.php
index 7a07a38..5edbca1 100644
--- a/core/lib/Drupal/Core/Entity/Controller/EntityListController.php
+++ b/core/lib/Drupal/Core/Entity/Controller/EntityListController.php
@@ -7,13 +7,40 @@
namespace Drupal\Core\Entity\Controller;
-use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Controller\ControllerInterface;
+use Drupal\Core\Entity\EntityManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines a generic controller to list entities.
*/
-class EntityListController extends ControllerBase {
+class EntityListController implements ControllerInterface {
+
+ /**
+ * The entity manager
+ *
+ * @var \Drupal\Core\Entity\EntityManager
+ */
+ protected $entityManager;
+
+ /**
+ * Creates an EntityListController object.
+ *
+ * @param \Drupal\Core\Entity\EntityManager $entity_manager
+ * The entity manager.
+ */
+ public function __construct(EntityManager $entity_manager) {
+ $this->entityManager = $entity_manager;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container) {
+ return new static(
+ $container->get('plugin.manager.entity')
+ );
+ }
/**
* Provides the listing page for any entity type.
@@ -25,7 +52,7 @@ class EntityListController extends ControllerBase {
* A render array as expected by drupal_render().
*/
public function listing($entity_type) {
- return $this->entityManager()->getListController($entity_type)->render();
+ return $this->entityManager->getListController($entity_type)->render();
}
}
diff --git a/core/lib/Drupal/Core/Entity/EntityListController.php b/core/lib/Drupal/Core/Entity/EntityListController.php
index 09cc203..88b2207 100644
--- a/core/lib/Drupal/Core/Entity/EntityListController.php
+++ b/core/lib/Drupal/Core/Entity/EntityListController.php
@@ -9,7 +9,6 @@
use Drupal\Core\Extension\ModuleHandlerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Component\Utility\String;
/**
* Provides a generic implementation of an entity list controller.
@@ -145,7 +144,7 @@ public function buildHeader() {
* @see Drupal\Core\Entity\EntityListController::render()
*/
public function buildRow(EntityInterface $entity) {
- $row['label'] = String::checkPlain($entity->label());
+ $row['label'] = $entity->label();
$row['id'] = $entity->id();
$operations = $this->buildOperations($entity);
$row['operations']['data'] = $operations;
diff --git a/core/misc/autocomplete.js b/core/misc/autocomplete.js
index 0378b95..a11ddf4 100644
--- a/core/misc/autocomplete.js
+++ b/core/misc/autocomplete.js
@@ -221,15 +221,15 @@ Drupal.jsAC.prototype.found = function (matches) {
}
// Prepare matches.
+ var ul = $('
');
var ac = this;
- var ul = $('
')
- .on('mousedown', 'li', function (e) { ac.select(this); })
- .on('mouseover', 'li', function (e) { ac.highlight(this); })
- .on('mouseout', 'li', function (e) { ac.unhighlight(this); });
for (var key in matches) {
if (matches.hasOwnProperty(key)) {
$('')
.html($('').html(matches[key]))
+ .mousedown(function () { ac.select(this); })
+ .mouseover(function () { ac.highlight(this); })
+ .mouseout(function () { ac.unhighlight(this); })
.data('autocompleteValue', key)
.appendTo(ul);
}
diff --git a/core/misc/dialog.ajax.js b/core/misc/dialog.ajax.js
index c56515b..8bb6599 100644
--- a/core/misc/dialog.ajax.js
+++ b/core/misc/dialog.ajax.js
@@ -33,6 +33,9 @@
}
}
},
+ detach: function (context, settings) {
+ $(context).find('form').off('submit.dialogSubmit');
+ },
/**
* Scan a dialog for any primary buttons and move them to the button area.
@@ -66,6 +69,12 @@
}
});
});
+ if ($buttons.length) {
+ $dialog.find('form').on('submit.dialogSubmit', function (e) {
+ $buttons.first().trigger('click');
+ e.preventDefault();
+ });
+ }
return buttons;
}
};
diff --git a/core/modules/action/lib/Drupal/action/Plugin/views/field/BulkForm.php b/core/modules/action/lib/Drupal/action/Plugin/views/field/BulkForm.php
new file mode 100644
index 0000000..3d9f92e
--- /dev/null
+++ b/core/modules/action/lib/Drupal/action/Plugin/views/field/BulkForm.php
@@ -0,0 +1,116 @@
+ 'exclude',
+ );
+ $options['selected_actions'] = array(
+ 'default' => array(),
+ );
+ return $options;
+ }
+
+ /**
+ * Overrides \Drupal\views\Plugin\views\field\FieldPluginBase::buildOptionsForm().
+ */
+ public function buildOptionsForm(&$form, &$form_state) {
+ parent::buildOptionsForm($form, $form_state);
+
+ $form['include_exclude'] = array(
+ '#type' => 'radios',
+ '#title' => t('Available actions'),
+ '#options' => array(
+ 'exclude' => t('All actions, except selected'),
+ 'include' => t('Only selected actions'),
+ ),
+ '#default_value' => $this->options['include_exclude'],
+ );
+ $form['selected_actions'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Selected actions'),
+ '#options' => $this->getBulkOptions(FALSE),
+ '#default_value' => $this->options['selected_actions'],
+ );
+ }
+
+ /**
+ * Overrides \Drupal\views\Plugin\views\PluginBase::buildOptionsForm().
+ */
+ public function validateOptionsForm(&$form, &$form_state) {
+ parent::validateOptionsForm($form, $form_state);
+
+ $form_state['values']['options']['selected_actions'] = array_filter($form_state['values']['options']['selected_actions']);
+ }
+
+ /**
+ * Implements \Drupal\system\Plugin\views\field\BulkFormBase::getBulkOptions().
+ *
+ * @param bool $filtered
+ * (optional) Whether to filter actions to selected actions.
+ */
+ protected function getBulkOptions($filtered = TRUE) {
+ // Get all available actions.
+ $entity_type = $this->getEntityType();
+ $options = array();
+ // Filter the action list.
+ foreach ($this->actions as $id => $action) {
+ if ($filtered) {
+ $in_selected = in_array($id, $this->options['selected_actions']);
+ // If the field is configured to include only the selected actions,
+ // skip actions that were not selected.
+ if (($this->options['include_exclude'] == 'include') && !$in_selected) {
+ continue;
+ }
+ // Otherwise, if the field is configured to exclude the selected
+ // actions, skip actions that were selected.
+ elseif (($this->options['include_exclude'] == 'exclude') && $in_selected) {
+ continue;
+ }
+ }
+ // Only allow actions that are valid for this entity type.
+ if (($action->getType() == $entity_type)) {
+ $options[$id] = $action->label();
+ }
+ }
+
+ return $options;
+ }
+
+ /**
+ * Implements \Drupal\system\Plugin\views\field\BulkFormBase::views_form_submit().
+ */
+ public function views_form_submit(&$form, &$form_state) {
+ parent::views_form_submit($form, $form_state);
+ if ($form_state['step'] == 'views_form_views_form') {
+ $count = count(array_filter($form_state['values'][$this->options['id']]));
+ $action = $this->actions[$form_state['values']['action']];
+ if ($count) {
+ drupal_set_message(format_plural($count, '%action was applied to @count item.', '%action was applied to @count items.', array(
+ '%action' => $action->label(),
+ )));
+ }
+ }
+ }
+
+}
diff --git a/core/modules/aggregator/aggregator.pages.inc b/core/modules/aggregator/aggregator.pages.inc
index 0fa2bd8..98dc665 100644
--- a/core/modules/aggregator/aggregator.pages.inc
+++ b/core/modules/aggregator/aggregator.pages.inc
@@ -157,7 +157,7 @@ function _aggregator_page_list($items, $op, $feed_source = '') {
$build['feed_source'] = is_array($feed_source) ? $feed_source : array('#markup' => $feed_source);
if ($items) {
$build['items'] = entity_view_multiple($items, 'default');
- $build['pager'] = array('#theme' => 'pager');
+ $build['pager']['#markup'] = theme('pager');
}
}
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/views/row/Rss.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/views/row/Rss.php
index 98709ea..7239213 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/views/row/Rss.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/views/row/Rss.php
@@ -99,13 +99,11 @@ public function render($row) {
),
);
- $build = array(
- '#theme' => $this->themeFunctions(),
- '#view' => $this->view,
- '#options' => $this->options,
- '#row' => $item,
- );
- return drupal_render($build);
+ return theme($this->themeFunctions(), array(
+ 'view' => $this->view,
+ 'options' => $this->options,
+ 'row' => $item,
+ ));
}
}
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index 8eeb57f..9820348 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -61,14 +61,14 @@ function block_help($path, $arg) {
$output .= '
' . t('Blocks can be configured to be visible only on certain pages, only to users of certain roles, or only on pages displaying certain content types. Some dynamic blocks, such as those generated by modules, will be displayed only on certain pages.', array('@content-type' => url('admin/structure/types'), '@user' => url('user'))) . '
';
if (module_exists('custom_block')) {
$output .= '
' . t('Creating custom blocks') . '
';
- $output .= '
' . t('Users with the Administer blocks permission can add custom blocks, which are then listed on the Blocks administration page. Once created, custom blocks behave just like default and module-generated blocks.', array('@blocks' => url('admin/structure/block'), '@block-add' => url('admin/structure/block/list/' . config('system.theme')->get('default') . '/add/custom_blocks'))) . '
';
+ $output .= '
' . t('Users with the Administer blocks permission can add custom blocks, which are then listed on the Blocks administration page. Once created, custom blocks behave just like default and module-generated blocks.', array('@blocks' => url('admin/structure/block'), '@block-add' => url('admin/structure/block/list/block_plugin_ui:' . config('system.theme')->get('default') . '/add/custom_blocks'))) . '
';
}
$output .= '';
return $output;
}
if ($arg[0] == 'admin' && $arg[1] == 'structure' && $arg['2'] == 'block' && (empty($arg[3]) || $arg[3] == 'list') && empty($arg[5])) {
if (!empty($arg[4])) {
- $demo_theme = $arg[4];
+ list(, $demo_theme) = explode(':', $arg[4]);
}
else {
$demo_theme = config('system.theme')->get('default');
@@ -136,28 +136,28 @@ function block_menu() {
// and plugin IDs to decouple the routes from these dependencies and allow
// hook_menu_local_tasks() to check for the untranslated tab_parent path.
// @see http://drupal.org/node/1067408
- foreach (list_themes() as $key => $theme) {
- $items["admin/structure/block/list/$key"] = array(
- 'title' => check_plain($theme->info['name']),
- 'type' => $key == $default_theme ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
- 'route_name' => "block_admin_display.$key",
- );
- $items["admin/structure/block/list/$key/add"] = array(
- 'title' => 'Place blocks',
- 'type' => MENU_LOCAL_ACTION,
- 'route_name' => "block_plugin_ui.$key",
- );
- $items["admin/structure/block/demo/$key"] = array(
- 'title' => check_plain($theme->info['name']),
- 'page callback' => 'block_admin_demo',
- 'page arguments' => array($key),
- 'type' => MENU_CALLBACK,
- 'access callback' => '_block_themes_access',
- 'access arguments' => array($key),
- 'theme callback' => '_block_custom_theme',
- 'theme arguments' => array($key),
- 'file' => 'block.admin.inc',
- );
+ $themes = list_themes();
+ foreach (drupal_container()->get('plugin.manager.system.plugin_ui')->getDefinitions() as $plugin_id => $plugin) {
+ list($plugin_base, $key) = explode(':', $plugin_id);
+ if ($plugin_base == 'block_plugin_ui') {
+ $theme = $themes[$key];
+ $items['admin/structure/block/list/' . $plugin_id] = array(
+ 'title' => check_plain($theme->info['name']),
+ 'type' => $key == $default_theme ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
+ 'route_name' => 'block_admin_display.' . $plugin_id
+ );
+ $items['admin/structure/block/demo/' . $key] = array(
+ 'title' => check_plain($theme->info['name']),
+ 'page callback' => 'block_admin_demo',
+ 'page arguments' => array($key),
+ 'type' => MENU_CALLBACK,
+ 'access callback' => '_block_themes_access',
+ 'access arguments' => array($key),
+ 'theme callback' => '_block_custom_theme',
+ 'theme arguments' => array($key),
+ 'file' => 'block.admin.inc',
+ );
+ }
}
return $items;
}
diff --git a/core/modules/block/block.routing.yml b/core/modules/block/block.routing.yml
index 669e0a2..cabd4cb 100644
--- a/core/modules/block/block.routing.yml
+++ b/core/modules/block/block.routing.yml
@@ -26,10 +26,3 @@ block_admin_add:
_content: '\Drupal\block\Controller\BlockAddController::blockAddConfigureForm'
requirements:
_permission: 'administer blocks'
-
-block_autocomplete:
- pattern: '/block/autocomplete'
- defaults:
- _controller: '\Drupal\block\Controller\BlockAutocompleteController::autocomplete'
- requirements:
- _permission: 'administer blocks'
diff --git a/core/modules/block/block.services.yml b/core/modules/block/block.services.yml
index b361dba..9b6b40d 100644
--- a/core/modules/block/block.services.yml
+++ b/core/modules/block/block.services.yml
@@ -13,6 +13,7 @@ services:
class: Drupal\block\Routing\RouteSubscriber
tags:
- { name: event_subscriber}
+ arguments: ['@plugin.manager.system.plugin_ui']
block.theme_access_check:
class: Drupal\block\Access\BlockThemeAccessCheck
tags:
diff --git a/core/modules/block/lib/Drupal/block/BlockFormController.php b/core/modules/block/lib/Drupal/block/BlockFormController.php
index 6041b2c..0386277 100644
--- a/core/modules/block/lib/Drupal/block/BlockFormController.php
+++ b/core/modules/block/lib/Drupal/block/BlockFormController.php
@@ -283,7 +283,7 @@ public function submit(array $form, array &$form_state) {
drupal_set_message(t('The block configuration has been saved.'));
cache_invalidate_tags(array('content' => TRUE));
- $form_state['redirect'] = 'admin/structure/block/list/' . $entity->get('theme');
+ $form_state['redirect'] = 'admin/structure/block/list/block_plugin_ui:' . $entity->get('theme');
}
/**
diff --git a/core/modules/block/lib/Drupal/block/Controller/BlockAddController.php b/core/modules/block/lib/Drupal/block/Controller/BlockAddController.php
index 0d065eb..f7f4e38 100644
--- a/core/modules/block/lib/Drupal/block/Controller/BlockAddController.php
+++ b/core/modules/block/lib/Drupal/block/Controller/BlockAddController.php
@@ -7,13 +7,33 @@
namespace Drupal\block\Controller;
-use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Controller\ControllerInterface;
+use Drupal\Core\Entity\EntityManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Controller for building the block instance add form.
*/
-class BlockAddController extends ControllerBase {
+class BlockAddController implements ControllerInterface {
+
+ /**
+ * Constructs a Block object.
+ *
+ * @param \Drupal\Core\Entity\EntityManager $entity_manager
+ * Entity manager service.
+ */
+ public function __construct(EntityManager $entity_manager) {
+ $this->entityManager = $entity_manager;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container) {
+ return new static(
+ $container->get('plugin.manager.entity')
+ );
+ }
/**
* Build the block instance add form.
@@ -31,9 +51,8 @@ public function blockAddConfigureForm($plugin_id, $theme) {
drupal_set_title(t('Configure block'));
// Create a block entity.
- $entity = $this->entityManager()->getStorageController('block')->create(array('plugin' => $plugin_id, 'theme' => $theme));
+ $entity = $this->entityManager->getStorageController('block')->create(array('plugin' => $plugin_id, 'theme' => $theme));
- return $this->entityManager()->getForm($entity);
+ return $this->entityManager->getForm($entity);
}
-
}
diff --git a/core/modules/block/lib/Drupal/block/Controller/BlockAutocompleteController.php b/core/modules/block/lib/Drupal/block/Controller/BlockAutocompleteController.php
deleted file mode 100644
index 539a8c1..0000000
--- a/core/modules/block/lib/Drupal/block/Controller/BlockAutocompleteController.php
+++ /dev/null
@@ -1,78 +0,0 @@
-manager = $manager;
- }
-
- /**
- * {@inheritdoc}
- */
- public static function create(ContainerInterface $container) {
- return new static(
- $container->get('plugin.manager.block')
- );
- }
-
- /**
- * Autocompletes a block plugin ID.
- *
- * @param \Symfony\Component\HttpFoundation\Request $request
- * The request object.
- *
- * @return \Symfony\Component\HttpFoundation\JsonResponse
- * The matched plugins as JSON.
- */
- public function autocomplete(Request $request) {
- $string_typed = $request->query->get('q');
- // The passed string may be comma or space separated.
- $string_typed = Tags::explode($string_typed);
- // Take the last result and lowercase it.
- $string = Unicode::strtolower(array_pop($string_typed));
- $matches = array();
- if ($string) {
- $titles = array();
- // Gather all block plugins and their admin titles.
- foreach($this->manager->getDefinitions() as $plugin_id => $plugin) {
- $titles[$plugin_id] = $plugin['admin_label'];
- }
- // Find any matching block plugin IDs.
- $matches = preg_grep("/\b". $string . "/i", $titles);
- }
-
- return new JsonResponse($matches);
- }
-
-}
diff --git a/core/modules/block/lib/Drupal/block/Controller/BlockListController.php b/core/modules/block/lib/Drupal/block/Controller/BlockListController.php
index f31e652..23b145c 100644
--- a/core/modules/block/lib/Drupal/block/Controller/BlockListController.php
+++ b/core/modules/block/lib/Drupal/block/Controller/BlockListController.php
@@ -9,6 +9,8 @@
use Drupal\Core\Entity\Controller\EntityListController;
use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Core\Config\ConfigFactory;
+use Drupal\Core\Entity\EntityManager;
/**
* Defines a controller to list blocks.
@@ -16,17 +18,50 @@
class BlockListController extends EntityListController {
/**
+ * The configuration factory object.
+ *
+ * @var \Drupal\Core\Config\ConfigFactory
+ */
+ protected $configFactory;
+
+
+ /**
+ * Creates an BlockListController object.
+ *
+ * @param \Drupal\Core\Entity\EntityManager $entity_manager
+ * The entity manager.
+ * @param \Drupal\Core\Config\ConfigFactory $config_factory
+ * Configuration factory object.
+ */
+ public function __construct(EntityManager $entity_manager, ConfigFactory $config_factory) {
+ $this->entityManager = $entity_manager;
+ $this->configFactory = $config_factory;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container) {
+ return new static(
+ $container->get('plugin.manager.entity'),
+ $container->get('config.factory')
+ );
+ }
+
+ /**
* Shows the block administration page.
*
+ * @param string $entity_type
+ * Entity type of list page.
* @param string|null $theme
* Theme key of block list.
*
* @return array
* A render array as expected by drupal_render().
*/
- public function listing($theme = NULL) {
- $theme = $theme ?: $this->config('system.theme')->get('default');
- return $this->entityManager()->getListController('block')->render($theme);
+ public function listing($entity_type, $theme = NULL) {
+ $default_theme = $theme ?: $this->configFactory->get('system.theme')->get('default');
+ return $this->entityManager->getListController($entity_type)->render($default_theme);
}
}
diff --git a/core/modules/block/lib/Drupal/block/Form/PlaceBlocksForm.php b/core/modules/block/lib/Drupal/block/Form/PlaceBlocksForm.php
deleted file mode 100644
index ffc4b9e..0000000
--- a/core/modules/block/lib/Drupal/block/Form/PlaceBlocksForm.php
+++ /dev/null
@@ -1,157 +0,0 @@
-manager = $manager;
- }
-
- /**
- * {@inheritdoc}
- */
- public static function create(ContainerInterface $container) {
- return new static(
- $container->get('plugin.manager.block')
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFormID() {
- return 'block_plugin_ui';
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildForm(array $form, array &$form_state, $theme = NULL, $category = NULL) {
- $this->theme = $theme;
- $form['#theme'] = 'system_plugin_ui_form';
- $rows = array();
- $categories = array();
- foreach ($this->manager->getDefinitions() as $plugin_id => $plugin_definition) {
- if (empty($category) || $plugin_definition['category'] == $category) {
- $rows[$plugin_id] = $this->row($plugin_id, $plugin_definition);
- }
- $categories[$plugin_definition['category']] = array(
- 'title' => $plugin_definition['category'],
- 'href' => 'admin/structure/block/list/' . $this->theme . '/add/' . $plugin_definition['category'],
- );
- }
-
- $form['right']['block'] = array(
- '#type' => 'textfield',
- '#title' => t('Search'),
- '#autocomplete_path' => 'block/autocomplete',
- );
- $form['right']['submit'] = array(
- '#type' => 'submit',
- '#button_type' => 'primary',
- '#value' => t('Next'),
- );
- $form['right']['all_plugins'] = array(
- '#type' => 'link',
- '#title' => t('All blocks'),
- '#href' => 'admin/structure/block/list/' . $this->theme . '/add',
- );
- if (!empty($categories)) {
- $form['right']['categories'] = array(
- '#theme' => 'links',
- '#heading' => array(
- 'text' => t('Categories'),
- 'level' => 'h3',
- ),
- '#links' => $categories,
- );
- }
-
- // Sort rows alphabetically.
- asort($rows);
- $form['left']['plugin_library'] = array(
- '#theme' => 'table',
- '#header' => array(t('Subject'), t('Operations')),
- '#rows' => $rows,
- );
- return $form;
- }
-
- /**
- * Generates the row data for a single block plugin.
- *
- * @param string $plugin_id
- * The plugin ID.
- * @param array $plugin_definition
- * The plugin definition.
- *
- * @return array
- * The row data for a single block plugin.
- */
- protected function row($plugin_id, array $plugin_definition) {
- $row = array();
- $row[] = String::checkPlain($plugin_definition['admin_label']);
- $row[] = array('data' => array(
- '#type' => 'operations',
- '#links' => array(
- 'configure' => array(
- 'title' => t('Place block'),
- 'href' => 'admin/structure/block/add/' . $plugin_id . '/' . $this->theme,
- ),
- ),
- ));
- return $row;
- }
-
- /**
- * {@inheritdoc}
- */
- public function validateForm(array &$form, array &$form_state) {
- if (!$this->manager->getDefinition($form_state['values']['block'])) {
- form_set_error('block', t('You must select a valid block.'));
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function submitForm(array &$form, array &$form_state) {
- $form_state['redirect'] = 'admin/structure/block/add/' . $form_state['values']['block'] . '/' . $this->theme;
- }
-
-}
diff --git a/core/modules/block/lib/Drupal/block/Plugin/Derivative/BlockPluginUI.php b/core/modules/block/lib/Drupal/block/Plugin/Derivative/BlockPluginUI.php
new file mode 100644
index 0000000..aaeef6e
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/Plugin/Derivative/BlockPluginUI.php
@@ -0,0 +1,29 @@
+ $theme) {
+ $this->derivatives[$key] = $base_plugin_definition;
+ }
+ return parent::getDerivativeDefinitions($base_plugin_definition);
+ }
+}
diff --git a/core/modules/block/lib/Drupal/block/Plugin/PluginUI/BlockPluginUI.php b/core/modules/block/lib/Drupal/block/Plugin/PluginUI/BlockPluginUI.php
new file mode 100644
index 0000000..de7e079
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/Plugin/PluginUI/BlockPluginUI.php
@@ -0,0 +1,229 @@
+getPluginId());
+ $plugin_definition = $this->getPluginDefinition();
+ // @todo Find out how to let the manager be injected into the class.
+ $manager = drupal_container()->get($plugin_definition['manager']);
+ $plugins = $manager->getDefinitions();
+ $form['#theme'] = 'system_plugin_ui_form';
+ $form['theme'] = array(
+ '#type' => 'value',
+ '#value' => $theme,
+ );
+ $form['manager'] = array(
+ '#type' => 'value',
+ '#value' => $manager,
+ );
+ $form['instance'] = array(
+ '#type' => 'value',
+ '#value' => $this,
+ );
+ $form['right']['block'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Search'),
+ '#autocomplete_path' => 'system/autocomplete/' . $this->getPluginId(),
+ );
+ $form['right']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Next'),
+ );
+ $rows = array();
+ foreach ($plugins as $plugin_id => $display_plugin_definition) {
+ if (empty($facet) || $this->facetCompare($facet, $display_plugin_definition)) {
+ $rows[$plugin_id] = $this->row($plugin_id, $display_plugin_definition);
+ }
+ foreach ($plugin_definition['facets'] as $key => $title) {
+ $facets[$key][$display_plugin_definition[$key]] = $this->facetLink($key, $plugin_id, $display_plugin_definition);
+ }
+ $form['right']['all_plugins'] = array(
+ '#type' => 'link',
+ '#title' => $plugin_definition['all_plugins'],
+ '#href' => $this->allPluginsUrl($plugin_id, $display_plugin_definition),
+ );
+ foreach ($facets as $group => $values) {
+ $form['right'][$group] = array(
+ '#theme' => 'links',
+ '#heading' => array(
+ 'text' => $plugin_definition['facets'][$group],
+ 'level' => 'h3',
+ ),
+ '#links' => $values,
+ );
+ }
+ }
+ // Sort rows alphabetically.
+ asort($rows);
+ $form['left']['plugin_library'] = array(
+ '#theme' => 'table',
+ '#header' => $this->tableHeader(),
+ '#rows' => $rows,
+ );
+ return $form;
+ }
+
+ /**
+ * Overrides \Drupal\system\Plugin\PluginUIBase::formValidate().
+ */
+ public function formValidate($form, &$form_state) {
+ $definitions = $form_state['values']['manager']->getDefinitions();
+ if (!isset($definitions[$form_state['values']['block']])) {
+ form_set_error('block', t('You must select a valid block.'));
+ }
+ }
+
+ /**
+ * Overrides \Drupal\system\Plugin\PluginUIBase::formSubmit().
+ */
+ public function formSubmit($form, &$form_state) {
+ $form_state['redirect'] = 'admin/structure/block/add/' . $form_state['values']['block'] . '/' . $form_state['values']['theme'];
+ }
+
+ /**
+ * Overrides \Drupal\system\Plugin\PluginUIBase::access().
+ */
+ public function access() {
+ list($plugin, $theme) = explode(':', $this->getPluginId());
+ return _block_themes_access($theme);
+ }
+
+ /**
+ * Overrides \Drupal\system\Plugin\PluginUIBase::tableHeader().
+ */
+ public function tableHeader() {
+ return array(t('Subject'), t('Operations'));
+ }
+
+ /**
+ * Overrides \Drupal\system\Plugin\PluginUIBase::row().
+ */
+ public function row($display_plugin_id, array $display_plugin_definition) {
+ $plugin_definition = $this->getPluginDefinition();
+ list($plugin, $theme) = explode(':', $this->getPluginId());
+ $row = array();
+ $row[] = check_plain($display_plugin_definition['admin_label']);
+ $row[] = array('data' => array(
+ '#type' => 'operations',
+ '#links' => array(
+ 'configure' => array(
+ 'title' => $plugin_definition['link_title'],
+ 'href' => $plugin_definition['config_path'] . '/' . $display_plugin_id . '/' . $theme,
+ ),
+ ),
+ ));
+ return $row;
+ }
+
+ /**
+ * Creates a facet link for a given facet of a display plugin.
+ *
+ * Provides individually formatted links for the faceting that happens within
+ * the user interface. Since this is a faceting style procedure, each plugin
+ * may be parsed multiple times in order to extract all facets and their
+ * appropriate labels.
+ *
+ * The $display_plugin_id and $display_plugin_definition are provided for
+ * convenience when overriding this method.
+ *
+ * @param string $facet
+ * A simple string indicating what element of the $display_plugin_definition
+ * to utilize for faceting.
+ * @param string $display_plugin_id
+ * The plugin ID of the plugin we are currently parsing a facet link from.
+ * @param array $display_plugin_definition
+ * The plugin definition we are parsing.
+ *
+ * @return array
+ * Returns a row array comaptible with theme_links().
+ */
+ protected function facetLink($facet, $display_plugin_id, array $display_plugin_definition) {
+ $plugin_definition = $this->getPluginDefinition();
+ return array(
+ 'title' => $display_plugin_definition[$facet],
+ 'href' => $plugin_definition['path'] . '/' . $this->getPluginId() . '/' . $facet . ':' . $display_plugin_definition[$facet],
+ );
+ }
+
+ /**
+ * Determines whether a given facet should be displayed for a plugin.
+ *
+ * Compares a given plugin definition with the selected facet to determine if
+ * the plugin should be displayed in the user interface.
+ *
+ * @param string $facet
+ * A colon separated string representing the key/value paring of a selected
+ * facet.
+ * @param array $display_plugin_definition
+ * The plugin definition to be compared.
+ *
+ * @return bool
+ * Returns TRUE if the selected facet matches this plugin.
+ */
+ protected function facetCompare($facet, $display_plugin_definition) {
+ list($facet_type, $option) = explode(':', $facet);
+ return $option == $display_plugin_definition[$facet_type];
+ }
+
+ /**
+ * Provides an "all" style link to reset the facets.
+ *
+ * The $display_plugin_id and $display_plugin_definition are provided for
+ * convenience when overriding this method.
+ *
+ * @param string $display_plugin_id
+ * The plugin ID of the plugin we are currently parsing a facet link from.
+ * @param array $display_plugin_definition
+ * The plugin definition we are parsing.
+ *
+ * @return string
+ * Returns a simple URL string for use within l().
+ */
+ protected function allPluginsUrl($display_plugin_id, $display_plugin_definition) {
+ $plugin_definition = $this->getPluginDefinition();
+ return $plugin_definition['path'] . '/' . $this->getPluginId() . '/add';
+ }
+
+}
diff --git a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
index 7a50351..34daaca 100644
--- a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
+++ b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
@@ -1,7 +1,6 @@
alterInfo($module_handler, 'block');
$this->setCacheBackend($cache_backend, $language_manager, 'block_plugins');
}
-
- /**
- * {@inheritdoc}
- */
- public function processDefinition(&$definition, $plugin_id) {
- parent::processDefinition($definition, $plugin_id);
-
- // Ensure that every block has a category.
- $definition += array(
- 'category' => $definition['provider'],
- );
- }
-
}
diff --git a/core/modules/block/lib/Drupal/block/Routing/RouteSubscriber.php b/core/modules/block/lib/Drupal/block/Routing/RouteSubscriber.php
index de32cd1..deea1f4 100644
--- a/core/modules/block/lib/Drupal/block/Routing/RouteSubscriber.php
+++ b/core/modules/block/lib/Drupal/block/Routing/RouteSubscriber.php
@@ -1,5 +1,4 @@
pluginManager = $plugin_manager;
+ }
+
+ /**
* Implements EventSubscriberInterface::getSubscribedEvents().
*/
public static function getSubscribedEvents() {
@@ -37,32 +55,18 @@ public static function getSubscribedEvents() {
*/
public function routes(RouteBuildEvent $event) {
$collection = $event->getRouteCollection();
- foreach (list_themes(TRUE) as $key => $theme) {
- // The block entity listing page.
- $route = new Route(
- "admin/structure/block/list/$key",
- array(
+ foreach ($this->pluginManager->getDefinitions() as $plugin_id => $plugin) {
+ list($plugin_base, $key) = explode(':', $plugin_id);
+ if ($plugin_base == 'block_plugin_ui') {
+ $route = new Route('admin/structure/block/list/' . $plugin_id, array(
'_controller' => '\Drupal\block\Controller\BlockListController::listing',
+ 'entity_type' => 'block',
'theme' => $key,
- ),
- array(
+ ), array(
'_block_themes_access' => 'TRUE',
- )
- );
- $collection->add("block_admin_display.$key", $route);
-
- // The block plugin listing page.
- $route = new Route(
- "admin/structure/block/list/$key/add/{category}",
- array(
- '_form' => '\Drupal\block\Form\PlaceBlocksForm',
- 'category' => NULL,
- 'theme' => $key,
- ),
- array('_block_themes_access' => 'TRUE')
- );
- $collection->add("block_plugin_ui.$key", $route);
+ ));
+ $collection->add('block_admin_display.' . $plugin_id, $route);
+ }
}
}
-
}
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php
index c3a220f..8c64ac8 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php
@@ -38,14 +38,14 @@ function testAdminTheme() {
$this->drupalLogin($admin_user);
// Ensure that access to block admin page is denied when theme is disabled.
- $this->drupalGet('admin/structure/block/list/bartik');
+ $this->drupalGet('admin/structure/block/list/block_plugin_ui:bartik');
$this->assertResponse(403);
// Enable admin theme and confirm that tab is accessible.
theme_enable(array('bartik'));
$edit['admin_theme'] = 'bartik';
$this->drupalPost('admin/appearance', $edit, t('Save configuration'));
- $this->drupalGet('admin/structure/block/list/bartik');
+ $this->drupalGet('admin/structure/block/list/block_plugin_ui:bartik');
$this->assertResponse(200);
}
}
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockLibrarySearchTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockLibrarySearchTest.php
index 8dcfeaa..22f47e8 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockLibrarySearchTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockLibrarySearchTest.php
@@ -49,11 +49,11 @@ protected function setUp() {
*/
function testBlockLibrarySearch() {
// Check that the block plugin is valid.
- $this->drupalPost('admin/structure/block/list/stark/add', array('block' => 'invalid_block'), t('Next'));
+ $this->drupalPost('admin/structure/block/list/block_plugin_ui:stark/add', array('block' => 'invalid_block'), t('Next'));
$this->assertText('You must select a valid block.');
// Check that the block search form redirects to the correct block form.
- $this->drupalPost('admin/structure/block/list/stark/add', array('block' => 'system_main_block'), t('Next'));
+ $this->drupalPost('admin/structure/block/list/block_plugin_ui:stark/add', array('block' => 'system_main_block'), t('Next'));
$this->assertUrl('admin/structure/block/add/system_main_block/stark');
}
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
index c766053..e665609 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
@@ -274,7 +274,7 @@ function testBlockModuleDisable() {
}
// Ensure that the disabled module's block plugin is no longer available.
- $this->drupalGet('admin/structure/block/list/' . config('system.theme')->get('default') . '/add');
+ $this->drupalGet('admin/structure/block/list/block_plugin_ui:' . config('system.theme')->get('default') . '/add');
$this->assertNoText(t('Test block caching'));
// Confirm that the block is no longer displayed on the front page.
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockTitleXSSTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockTitleXSSTest.php
index 3036ecd..6562545 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockTitleXSSTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockTitleXSSTest.php
@@ -45,7 +45,7 @@ function testXSSInTitle() {
$this->drupalLogin($this->drupalCreateUser(array('administer blocks', 'access administration pages')));
$default_theme = config('system.theme')->get('default');
- $this->drupalGet('admin/structure/block/list/' . $default_theme . '/add');
+ $this->drupalGet('admin/structure/block/list/block_plugin_ui:' . $default_theme . '/add');
$this->assertNoRaw("", 'The block title was properly sanitized in Block Plugin UI Admin page.');
}
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockUiTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockUiTest.php
index 62d2498..7ad84e1 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockUiTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockUiTest.php
@@ -110,7 +110,7 @@ function testBlockAdminUiPage() {
*/
function testBlockSearch() {
$block = t('Administration');
- $blocks = drupal_json_decode($this->drupalGet('block/autocomplete', array('query' => array('q' => $block))));
+ $blocks = drupal_json_decode($this->drupalGet('system/autocomplete/block_plugin_ui:stark', array('query' => array('q' => $block))));
$this->assertEqual($blocks['system_menu_block:menu-admin'], $block, t('Can search for block with name !block.', array('!block' => $block)));
}
diff --git a/core/modules/block/lib/Drupal/block/Tests/NonDefaultBlockAdminTest.php b/core/modules/block/lib/Drupal/block/Tests/NonDefaultBlockAdminTest.php
index 72f3d1d..7cf114c 100644
--- a/core/modules/block/lib/Drupal/block/Tests/NonDefaultBlockAdminTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/NonDefaultBlockAdminTest.php
@@ -34,7 +34,7 @@ function testNonDefaultBlockAdmin() {
$this->drupalLogin($admin_user);
$new_theme = 'bartik';
theme_enable(array($new_theme));
- $this->drupalGet('admin/structure/block/list/' . $new_theme);
+ $this->drupalGet('admin/structure/block/list/block_plugin_ui:' . $new_theme);
$this->assertText('Bartik(' . t('active tab') . ')', 'Tab for non-default theme found.');
}
}
diff --git a/core/modules/breakpoint/breakpoint.install b/core/modules/breakpoint/breakpoint.install
index dcc0b35..a419a9b 100644
--- a/core/modules/breakpoint/breakpoint.install
+++ b/core/modules/breakpoint/breakpoint.install
@@ -9,6 +9,8 @@
* Implements hook_enable().
*
* Import breakpoints from all enabled themes.
+ *
+ * @todo: This should be removed if https://drupal.org/node/1813100 is resolved.
*/
function breakpoint_enable() {
// Import breakpoints from themes.
diff --git a/core/modules/breakpoint/breakpoint.module b/core/modules/breakpoint/breakpoint.module
index 2b819af..ce3c894 100644
--- a/core/modules/breakpoint/breakpoint.module
+++ b/core/modules/breakpoint/breakpoint.module
@@ -188,7 +188,7 @@ function _breakpoint_import_breakpoint_groups($source, $source_type) {
*/
function _breakpoint_delete_breakpoints($list, $source_type) {
$ids = config_get_storage_names_with_prefix('breakpoint.breakpoint_group.' . $source_type . '.');
- $entity_info = Drupal::service('plugin.manager.entity')->getDefinition('breakpoint_group');
+ $entity_info = entity_get_info('breakpoint_group');
// Remove the breakpoint.breakpoint part of the breakpoint identifier.
foreach ($ids as &$id) {
@@ -202,8 +202,8 @@ function _breakpoint_delete_breakpoints($list, $source_type) {
$breakpoint_group->delete();
// Get all breakpoints defined by this theme/module.
- $breakpoint_ids = Drupal::service('config.storage')->listAll('breakpoint.breakpoint.' . $source_type . '.' . $breakpoint_group->id() . '.');
- $entity_info = Drupal::service('plugin.manager.entity')->getDefinition('breakpoint');
+ $breakpoint_ids = drupal_container()->get('config.storage')->listAll('breakpoint.breakpoint.' . $source_type . '.' . $breakpoint_group->id() . '.');
+ $entity_info = entity_get_info('breakpoint');
// Remove the breakpoint.breakpoint part of the breakpoint identifier.
foreach ($breakpoint_ids as &$breakpoint_id) {
@@ -277,7 +277,7 @@ function breakpoint_get_theme_media_queries($theme_key) {
* An array of breakpoints in the form $breakpoint['name'] = 'media query'.
*/
function breakpoint_get_module_media_queries($module) {
- if (!Drupal::moduleHandler()->moduleExists($module)) {
+ if (!module_exists($module)) {
throw new \Exception('Illegal module name passed.');
}
diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginManager.php b/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginManager.php
index 555eae3..da2bcfd 100644
--- a/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginManager.php
+++ b/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginManager.php
@@ -40,7 +40,7 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
}
/**
- * Retrieves enabled plugins' files, keyed by plugin ID.
+ * Determines which plug-ins are enabled.
*
* For CKEditor plugins that implement:
* - CKEditorPluginButtonsInterface, not CKEditorPluginContextualInterface,
@@ -64,7 +64,7 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
* the Drupal root-relative plugin files as values.
* For internal plugins, the value is NULL.
*/
- public function getEnabledPluginFiles(Editor $editor, $include_internal_plugins = FALSE) {
+ public function getEnabledPlugins(Editor $editor, $include_internal_plugins = FALSE) {
$plugins = array_keys($this->getDefinitions());
$toolbar_buttons = array_unique(NestedArray::mergeDeepArray($editor->settings['toolbar']['buttons']));
$enabled_plugins = array();
@@ -108,15 +108,16 @@ public function getEnabledPluginFiles(Editor $editor, $include_internal_plugins
}
/**
- * Retrieves all available CKEditor buttons, keyed by plugin ID.
+ * Retrieves all plugins that implement CKEditorPluginButtonsInterface.
*
* @return array
- * All availble CKEditor buttons, with plugin IDs as keys and button
- * metadata (as implemented by getButtons()) as values.
+ * A list of the CKEditor plugins that implement buttons, with the plugin
+ * IDs as keys and lists of button metadata (as implemented by getButtons())
+ * as values.
*
* @see CKEditorPluginButtonsInterface::getButtons()
*/
- public function getButtons() {
+ public function getButtonsPlugins() {
$plugins = array_keys($this->getDefinitions());
$buttons_plugins = array();
diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/Editor/CKEditor.php b/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/Editor/CKEditor.php
index eca1381..5b79bf2 100644
--- a/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/Editor/CKEditor.php
+++ b/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/Editor/CKEditor.php
@@ -86,7 +86,7 @@ public function settingsForm(array $form, array &$form_state, EditorEntity $edit
$ckeditor_settings_toolbar = array(
'#theme' => 'ckeditor_settings_toolbar',
'#editor' => $editor,
- '#plugins' => $this->ckeditorPluginManager->getButtons(),
+ '#plugins' => $this->ckeditorPluginManager->getButtonsPlugins(),
);
$form['toolbar'] = array(
'#type' => 'container',
@@ -135,7 +135,7 @@ public function settingsForm(array $form, array &$form_state, EditorEntity $edit
}
}
// Get a list of all buttons that are provided by all plugins.
- $all_buttons = array_reduce($this->ckeditorPluginManager->getButtons(), function($result, $item) {
+ $all_buttons = array_reduce($this->ckeditorPluginManager->getButtonsPlugins(), function($result, $item) {
return array_merge($result, array_keys($item));
}, array());
// Build a fake Editor object, which we'll use to generate JavaScript
@@ -196,18 +196,18 @@ public function getJSSettings(EditorEntity $editor) {
$settings = array();
// Get the settings for all enabled plugins, even the internal ones.
- $enabled_plugins = array_keys($this->ckeditorPluginManager->getEnabledPluginFiles($editor, TRUE));
+ $enabled_plugins = array_keys($this->ckeditorPluginManager->getEnabledPlugins($editor, TRUE));
foreach ($enabled_plugins as $plugin_id) {
$plugin = $this->ckeditorPluginManager->createInstance($plugin_id);
$settings += $plugin->getConfig($editor);
}
// Next, set the most fundamental CKEditor settings.
- $external_plugin_files = $this->ckeditorPluginManager->getEnabledPluginFiles($editor);
+ $external_plugins = $this->ckeditorPluginManager->getEnabledPlugins($editor);
$settings += array(
'toolbar' => $this->buildToolbarJSSetting($editor),
'contentsCss' => $this->buildContentsCssJSSetting($editor),
- 'extraPlugins' => implode(',', array_keys($external_plugin_files)),
+ 'extraPlugins' => implode(',', array_keys($external_plugins)),
// @todo: Remove image and link plugins from CKEditor build.
'removePlugins' => 'image,link',
'language' => $language_interface->id,
@@ -221,7 +221,7 @@ public function getJSSettings(EditorEntity $editor) {
// Finally, set Drupal-specific CKEditor settings.
$settings += array(
- 'drupalExternalPlugins' => array_map('file_create_url', $external_plugin_files),
+ 'drupalExternalPlugins' => array_map('file_create_url', $external_plugins),
);
ksort($settings);
@@ -238,7 +238,7 @@ public function getLibraries(EditorEntity $editor) {
);
// Get the required libraries for any enabled plugins.
- $enabled_plugins = array_keys($this->ckeditorPluginManager->getEnabledPluginFiles($editor));
+ $enabled_plugins = array_keys($this->ckeditorPluginManager->getEnabledPlugins($editor));
foreach ($enabled_plugins as $plugin_id) {
$plugin = $this->ckeditorPluginManager->createInstance($plugin_id);
$additional_libraries = array_udiff($plugin->getLibraries($editor), $libraries, function($a, $b) {
diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorPluginManagerTest.php b/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorPluginManagerTest.php
index cee1e75..3d31c04 100644
--- a/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorPluginManagerTest.php
+++ b/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorPluginManagerTest.php
@@ -74,8 +74,8 @@ function testEnabledPlugins() {
'drupalimage' => 'core/modules/ckeditor/js/plugins/drupalimage/plugin.js',
'drupallink' => 'core/modules/ckeditor/js/plugins/drupallink/plugin.js',
);
- $this->assertIdentical($enabled_plugins, $this->manager->getEnabledPluginFiles($editor), 'Only built-in plugins are enabled.');
- $this->assertIdentical(array('internal' => NULL) + $enabled_plugins, $this->manager->getEnabledPluginFiles($editor, TRUE), 'Only the "internal" plugin is enabled.');
+ $this->assertIdentical($enabled_plugins, $this->manager->getEnabledPlugins($editor), 'Only built-in plugins are enabled.');
+ $this->assertIdentical(array('internal' => NULL) + $enabled_plugins, $this->manager->getEnabledPlugins($editor, TRUE), 'Only the "internal" plugin is enabled.');
// Enable the CKEditor Test module, which has the Llama plugin (plus three
// variations of it, to cover all possible ways a plugin can be enabled) and
@@ -87,8 +87,8 @@ function testEnabledPlugins() {
$plugin_ids = array_keys($this->manager->getDefinitions());
sort($plugin_ids);
$this->assertIdentical(array('drupalimage', 'drupallink', 'internal', 'llama', 'llama_button', 'llama_contextual', 'llama_contextual_and_button', 'stylescombo'), $plugin_ids, 'Additional CKEditor plugins found.');
- $this->assertIdentical($enabled_plugins, $this->manager->getEnabledPluginFiles($editor), 'Only the internal plugins are enabled.');
- $this->assertIdentical(array('internal' => NULL) + $enabled_plugins, $this->manager->getEnabledPluginFiles($editor, TRUE), 'Only the "internal" plugin is enabled.');
+ $this->assertIdentical($enabled_plugins, $this->manager->getEnabledPlugins($editor), 'Only the internal plugins are enabled.');
+ $this->assertIdentical(array('internal' => NULL) + $enabled_plugins, $this->manager->getEnabledPlugins($editor, TRUE), 'Only the "internal" plugin is enabled.');
// Case 3: enable each of the newly available plugins, if possible:
// a. Llama: cannot be enabled, since it does not implement
@@ -111,19 +111,19 @@ function testEnabledPlugins() {
$file['c'] = 'core/modules/ckeditor/tests/modules/js/llama_contextual.js';
$file['cb'] = 'core/modules/ckeditor/tests/modules/js/llama_contextual_and_button.js';
$expected = $enabled_plugins + array('llama_button' => $file['b'], 'llama_contextual_and_button' => $file['cb']);
- $this->assertIdentical($expected, $this->manager->getEnabledPluginFiles($editor), 'The LlamaButton and LlamaContextualAndButton plugins are enabled.');
- $this->assertIdentical(array('internal' => NULL) + $expected, $this->manager->getEnabledPluginFiles($editor, TRUE), 'The LlamaButton and LlamaContextualAndButton plugins are enabled.');
+ $this->assertIdentical($expected, $this->manager->getEnabledPlugins($editor), 'The LlamaButton and LlamaContextualAndButton plugins are enabled.');
+ $this->assertIdentical(array('internal' => NULL) + $expected, $this->manager->getEnabledPlugins($editor, TRUE), 'The LlamaButton and LlamaContextualAndButton plugins are enabled.');
$editor->settings['toolbar']['buttons'][0] = $original_toolbar;
$editor->settings['toolbar']['buttons'][0][] = 'Strike';
$editor->save();
$expected = $enabled_plugins + array('llama_contextual' => $file['c'], 'llama_contextual_and_button' => $file['cb']);
- $this->assertIdentical($expected, $this->manager->getEnabledPluginFiles($editor), 'The LLamaContextual and LlamaContextualAndButton plugins are enabled.');
- $this->assertIdentical(array('internal' => NULL) + $expected, $this->manager->getEnabledPluginFiles($editor, TRUE), 'The LlamaContextual and LlamaContextualAndButton plugins are enabled.');
+ $this->assertIdentical($expected, $this->manager->getEnabledPlugins($editor), 'The LLamaContextual and LlamaContextualAndButton plugins are enabled.');
+ $this->assertIdentical(array('internal' => NULL) + $expected, $this->manager->getEnabledPlugins($editor, TRUE), 'The LlamaContextual and LlamaContextualAndButton plugins are enabled.');
$editor->settings['toolbar']['buttons'][0][] = 'Llama';
$editor->save();
$expected = $enabled_plugins + array('llama_button' => $file['b'], 'llama_contextual' => $file['c'], 'llama_contextual_and_button' => $file['cb']);
- $this->assertIdentical($expected, $this->manager->getEnabledPluginFiles($editor), 'The LlamaButton, LlamaContextual and LlamaContextualAndButton plugins are enabled.');
- $this->assertIdentical(array('internal' => NULL) + $expected, $this->manager->getEnabledPluginFiles($editor, TRUE), 'The LLamaButton, LlamaContextual and LlamaContextualAndButton plugins are enabled.');
+ $this->assertIdentical($expected, $this->manager->getEnabledPlugins($editor), 'The LlamaButton, LlamaContextual and LlamaContextualAndButton plugins are enabled.');
+ $this->assertIdentical(array('internal' => NULL) + $expected, $this->manager->getEnabledPlugins($editor, TRUE), 'The LLamaButton, LlamaContextual and LlamaContextualAndButton plugins are enabled.');
}
}
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php
index f97d6cf..7917731 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php
@@ -166,11 +166,11 @@ function testListUI() {
$this->assertTitle('Test configuration | Drupal');
// Test for the table.
- $element = $this->xpath('//div[@class="l-content"]//table');
+ $element = $this->xpath('//div[@id="content"]//table');
$this->assertTrue($element, 'Configuration entity list table found.');
// Test the table header.
- $elements = $this->xpath('//div[@class="l-content"]//table/thead/tr/th');
+ $elements = $this->xpath('//div[@id="content"]//table/thead/tr/th');
$this->assertEqual(count($elements), 3, 'Correct number of table header cells found.');
// Test the contents of each th cell.
@@ -180,7 +180,7 @@ function testListUI() {
}
// Check the number of table row cells.
- $elements = $this->xpath('//div[@class="l-content"]//table/tbody/tr[@class="odd"]/td');
+ $elements = $this->xpath('//div[@id="content"]//table/tbody/tr[@class="odd"]/td');
$this->assertEqual(count($elements), 3, 'Correct number of table row cells found.');
// Check the contents of each row cell. The first cell contains the label,
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 56d9508..bce6a02 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -19,7 +19,7 @@ function content_translation_help($path, $arg) {
case 'admin/help#content_translation':
$output = '';
$output .= '
' . t('About') . '
';
- $output .= '
' . t('The Content Translation module allows you to create and manage translations for your Drupal site content. You can specify which elements need to be translated at the content-type level for content items and comments, at the vocabulary level for taxonomy terms, and at the site level for user accounts. Other modules may provide additional elements that can be translated. For more information, see the online handbook entry for Content Translation.', array('!url' => 'http://drupal.org/documentation/modules/translation_entity')) . '
';
+ $output .= '
' . t('The Content Translation module allows you to create and manage translations for your Drupal site content. You can specify which elements need to be translated at the content-type level for content items and comments, at the vocabulary level for taxonomy terms, and at the site level for user accounts. Other modules may provide additional elements that can be translated. For more information, see the online handbook entry for Content Translation.', array('!url' => 'http://drupal.org/documentation/modules/entity_translation')) . '
';
$output .= '
' . t('Uses') . '
';
$output .= '
';
$output .= '
' . t('Enabling translation') . '
';
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php
index c17bd06..919603e 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php
@@ -63,7 +63,7 @@ function testSettingsUI() {
'settings[comment][comment_node_article][translatable]' => TRUE,
);
$this->assertSettings('comment', 'comment_node_article', FALSE, $edit);
- $xpath_err = '//div[contains(@class, "error")]';
+ $xpath_err = '//div[@id="messages"]//div[contains(@class, "error")]';
$this->assertTrue($this->xpath($xpath_err), 'Enabling translation only for entity bundles generates a form error.');
// Test that the translation settings are not stored if a non-configurable
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php
index 74b779b..a83be54 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php
@@ -190,7 +190,7 @@ protected function assertAuthoringInfo() {
'content_translation[created]' => '19/11/1978',
);
$this->drupalPost($path, $edit, $this->getFormSubmitAction($entity));
- $this->assertTrue($this->xpath('//div[contains(@class, "error")]//ul'), 'Invalid values generate a list of form errors.');
+ $this->assertTrue($this->xpath('//div[@id="messages"]//div[contains(@class, "error")]//ul'), 'Invalid values generate a list of form errors.');
$this->assertEqual($entity->translation[$langcode]['uid'] == $values[$langcode]['uid'], 'Translation author correctly kept.');
$this->assertEqual($entity->translation[$langcode]['created'] == $values[$langcode]['created'], 'Translation date correctly kept.');
}
diff --git a/core/modules/datetime/datetime.install b/core/modules/datetime/datetime.install
new file mode 100644
index 0000000..e0362a8
--- /dev/null
+++ b/core/modules/datetime/datetime.install
@@ -0,0 +1,23 @@
+ 'The date value',
+ 'type' => 'varchar',
+ 'length' => 20,
+ 'not null' => FALSE,
+ );
+ $indexes = array(
+ 'value' => array('value'),
+ );
+ return array('columns' => $db_columns, 'indexes' => $indexes);
+}
diff --git a/core/modules/datetime/datetime.module b/core/modules/datetime/datetime.module
index ebbcdd8..fdee1a6 100644
--- a/core/modules/datetime/datetime.module
+++ b/core/modules/datetime/datetime.module
@@ -91,6 +91,74 @@ function datetime_theme() {
}
/**
+ * Implements hook_field_is_empty().
+ */
+function datetime_field_is_empty($item, $field_type) {
+ if (empty($item['value'])) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Implements hook_field_info().
+ */
+function datetime_field_info() {
+ return array(
+ 'datetime' => array(
+ 'label' => 'Date',
+ 'description' => t('Create and store date values.'),
+ 'settings' => array(
+ 'datetime_type' => 'datetime',
+ ),
+ 'instance_settings' => array(
+ 'default_value' => 'now',
+ ),
+ 'default_widget' => 'datetime_default',
+ 'default_formatter' => 'datetime_default',
+ 'class' => '\Drupal\datetime\Type\DateTimeItem',
+ ),
+ );
+}
+
+/**
+ * Implements hook_field_settings_form().
+ */
+function datetime_field_settings_form($field, $instance) {
+ $settings = $field['settings'];
+
+ $form['datetime_type'] = array(
+ '#type' => 'select',
+ '#title' => t('Date type'),
+ '#description' => t('Choose the type of date to create.'),
+ '#default_value' => $settings['datetime_type'],
+ '#options' => array(
+ 'datetime' => t('Date and time'),
+ 'date' => t('Date only'),
+ ),
+ );
+ return $form;
+}
+
+/**
+ * Implements hook_field_instance_settings_form().
+ */
+function datetime_field_instance_settings_form($field, $instance) {
+ $settings = $instance['settings'];
+
+ $form['default_value'] = array(
+ '#type' => 'select',
+ '#title' => t('Default date'),
+ '#description' => t('Set a default value for this date.'),
+ '#default_value' => $settings['default_value'],
+ '#options' => array('blank' => t('No default value'), 'now' => t('The current date')),
+ '#weight' => 1,
+ );
+
+ return $form;
+}
+
+/**
* Validation callback for the datetime widget element.
*
* The date has already been validated by the datetime form type validator and
@@ -167,6 +235,30 @@ function datetime_datelist_widget_validate(&$element, &$form_state) {
}
/**
+ * Implements hook_field_load().
+ *
+ * The function generates a Date object for each field early so that it is
+ * cached in the field cache. This avoids the need to generate the object later.
+ * The date will be retrieved in UTC, the local timezone adjustment must be made
+ * in real time, based on the preferences of the site and user.
+ */
+function datetime_field_load($entity_type, $entities, $field, $instances, $langcode, &$items) {
+ foreach ($entities as $id => $entity) {
+ foreach ($items[$id] as $delta => $item) {
+ $items[$id][$delta]['date'] = NULL;
+ $value = isset($item['value']) ? $item['value'] : NULL;
+ if (!empty($value)) {
+ $storage_format = $field['settings']['datetime_type'] == 'date' ? DATETIME_DATE_STORAGE_FORMAT: DATETIME_DATETIME_STORAGE_FORMAT;
+ $date = new DrupalDateTime($value, DATETIME_STORAGE_TIMEZONE, $storage_format);
+ if ($date instanceOf DrupalDateTime && !$date->hasErrors()) {
+ $items[$id][$delta]['date'] = $date;
+ }
+ }
+ }
+ }
+}
+
+/**
* Sets a default value for an empty date field.
*
* Callback for $instance['default_value_function'], as implemented by
diff --git a/core/modules/datetime/lib/Drupal/datetime/Plugin/field/field_type/DateTimeItem.php b/core/modules/datetime/lib/Drupal/datetime/Plugin/field/field_type/DateTimeItem.php
deleted file mode 100644
index 0c51dd4..0000000
--- a/core/modules/datetime/lib/Drupal/datetime/Plugin/field/field_type/DateTimeItem.php
+++ /dev/null
@@ -1,140 +0,0 @@
- 'datetime_iso8601',
- 'label' => t('Date value'),
- );
- }
-
- return static::$propertyDefinitions;
- }
-
- /**
- * {@inheritdoc}
- */
- public static function schema(FieldInterface $field) {
- return array(
- 'columns' => array(
- 'value' => array(
- 'description' => 'The date value.',
- 'type' => 'varchar',
- 'length' => 20,
- 'not null' => FALSE,
- ),
- ),
- 'indexes' => array(
- 'value' => array('value'),
- ),
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function settingsForm(array $form, array &$form_state) {
- $element = array();
-
- $element['datetime_type'] = array(
- '#type' => 'select',
- '#title' => t('Date type'),
- '#description' => t('Choose the type of date to create.'),
- '#default_value' => $this->getFieldSetting('datetime_type'),
- '#options' => array(
- 'datetime' => t('Date and time'),
- 'date' => t('Date only'),
- ),
- );
-
- return $element;
- }
-
- /**
- * {@inheritdoc}
- */
- public function instanceSettingsForm(array $form, array &$form_state) {
- $element = array();
-
- $element['default_value'] = array(
- '#type' => 'select',
- '#title' => t('Default date'),
- '#description' => t('Set a default value for this date.'),
- '#default_value' => $this->getFieldSetting('default_value'),
- '#options' => array('blank' => t('No default value'), 'now' => t('The current date')),
- '#weight' => 1,
- );
-
- return $element;
- }
-
- /**
- * {@inheritdoc}
- */
- public function prepareCache() {
- // The function generates a Date object for each field early so that it is
- // cached in the field cache. This avoids the need to generate the object
- // later. The date will be retrieved in UTC, the local timezone adjustment
- // must be made in real time, based on the preferences of the site and user.
- $value = $this->get('value')->getValue();
- if (!empty($value)) {
- $storage_format = $this->getFieldSetting('datetime_type') == 'date' ? DATETIME_DATE_STORAGE_FORMAT : DATETIME_DATETIME_STORAGE_FORMAT;
- $date = new DrupalDateTime($value, DATETIME_STORAGE_TIMEZONE, $storage_format);
- if ($date instanceOf DrupalDateTime && !$date->hasErrors()) {
- $this->set('date', $date);
- }
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function isEmpty() {
- $value = $this->get('value')->getValue();
- return $value === NULL || $value === '';
- }
-
-}
diff --git a/core/modules/datetime/lib/Drupal/datetime/Type/DateTimeItem.php b/core/modules/datetime/lib/Drupal/datetime/Type/DateTimeItem.php
new file mode 100644
index 0000000..78c1824
--- /dev/null
+++ b/core/modules/datetime/lib/Drupal/datetime/Type/DateTimeItem.php
@@ -0,0 +1,39 @@
+ 'datetime_iso8601',
+ 'label' => t('Date value'),
+ );
+ }
+ return self::$propertyDefinitions;
+ }
+}
diff --git a/core/modules/editor/js/editor.js b/core/modules/editor/js/editor.js
index 18493d6..5893e11 100644
--- a/core/modules/editor/js/editor.js
+++ b/core/modules/editor/js/editor.js
@@ -60,10 +60,7 @@ Drupal.behaviors.editor = {
if (event.isDefaultPrevented()) {
return;
}
- // Detach the current editor (if any).
- if (settings.editor.formats[activeFormatID]) {
- Drupal.editorDetach(field, settings.editor.formats[activeFormatID], 'serialize');
- }
+ Drupal.editorDetach(field, settings.editor.formats[activeFormatID], 'serialize');
});
});
},
diff --git a/core/modules/editor/lib/Drupal/editor/Form/EditorImageDialog.php b/core/modules/editor/lib/Drupal/editor/Form/EditorImageDialog.php
index dcc78a5..0fa6249 100644
--- a/core/modules/editor/lib/Drupal/editor/Form/EditorImageDialog.php
+++ b/core/modules/editor/lib/Drupal/editor/Form/EditorImageDialog.php
@@ -122,9 +122,8 @@ public function submitForm(array &$form, array &$form_state) {
if (form_get_errors()) {
unset($form['#prefix'], $form['#suffix']);
- $status_messages = array('#theme' => 'status_messages');
$output = drupal_render($form);
- $output = '
diff --git a/core/modules/system/templates/progress-bar.html.twig b/core/modules/system/templates/progress-bar.html.twig
deleted file mode 100644
index 0d11991..0000000
--- a/core/modules/system/templates/progress-bar.html.twig
+++ /dev/null
@@ -1,23 +0,0 @@
-{#
-/**
- * @file
- * Default theme implementation for a progress bar.
- *
- * Note that the core Batch API uses this only for non-JavaScript batch jobs.
- *
- * Available variables:
- * - label: The label of the working task.
- * - percent: The percentage of the progress.
- * - message: A string containing information to be displayed.
- *
- * @ingroup themeable
- */
-#}
-
- {% if label %}
-
{{ label }}
- {% endif %}
-
-
{{ percent }}%
-
{{ message }}
-
diff --git a/core/modules/system/templates/task-list.html.twig b/core/modules/system/templates/task-list.html.twig
new file mode 100644
index 0000000..4242dc2
--- /dev/null
+++ b/core/modules/system/templates/task-list.html.twig
@@ -0,0 +1,27 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a list of maintenance tasks to perform.
+ *
+ * Available variables:
+ * - tasks: A list of maintenance tasks to perform. Each item in the list has
+ * the following variables:
+ * - item: The maintenance task.
+ * - attributes: HTML attributes for the maintenance task.
+ * - status: (optional) Text describing the status of the maintenance task,
+ * 'active' or 'done'.
+ *
+ * @ingroup themeable
+ */
+#}
+
');
}
/**
diff --git a/core/modules/views/lib/Drupal/views/Tests/Wizard/BasicTest.php b/core/modules/views/lib/Drupal/views/Tests/Wizard/BasicTest.php
index 8f3f4eb..0a8f18e 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Wizard/BasicTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Wizard/BasicTest.php
@@ -122,7 +122,7 @@ function testViewsWizardAndListing() {
$this->assertLinkByHref(url($view3['page[path]']));
// Confirm that the block is available in the block administration UI.
- $this->drupalGet('admin/structure/block/list/' . config('system.theme')->get('default') . '/add');
+ $this->drupalGet('admin/structure/block/list/block_plugin_ui:' . config('system.theme')->get('default') . '/add');
$this->assertText('View: ' . $view3['label']);
// Place the block.
diff --git a/core/modules/views/lib/Drupal/views/Tests/Wizard/ItemsPerPageTest.php b/core/modules/views/lib/Drupal/views/Tests/Wizard/ItemsPerPageTest.php
index 485f048..e6808c7 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Wizard/ItemsPerPageTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Wizard/ItemsPerPageTest.php
@@ -75,7 +75,7 @@ function testItemsPerPage() {
$this->assertTrue($pos5 < $pos4 && $pos4 < $pos3 && $pos3 < $pos2, 'The nodes appear in the expected order in the page display.');
// Confirm that the block is listed in the block administration UI.
- $this->drupalGet('admin/structure/block/list/' . config('system.theme')->get('default') . '/add');
+ $this->drupalGet('admin/structure/block/list/block_plugin_ui:' . config('system.theme')->get('default') . '/add');
$this->assertText('View: ' . $view['label']);
// Place the block, visit a page that displays the block, and check that the
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_exposed_block.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_exposed_block.yml
deleted file mode 100644
index 0528a1d..0000000
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_exposed_block.yml
+++ /dev/null
@@ -1,56 +0,0 @@
-base_table: node
-core: '8'
-description: ''
-status: '1'
-display:
- default:
- display_options:
- access:
- type: none
- cache:
- type: none
- exposed_form:
- options:
- reset_button: '1'
- type: basic
- filters:
- type:
- expose:
- identifier: type
- label: 'Content: Type'
- operator_id: type_op
- reduce: '0'
- exposed: '1'
- field: type
- id: type
- table: node_field_data
- plugin_id: node_type
- provider: views
- pager:
- type: full
- query:
- options:
- query_comment: '0'
- type: views_query
- style:
- type: default
- row:
- type: 'entity:node'
- options:
- comments: '0'
- links: '1'
- display_plugin: default
- display_title: Master
- id: default
- position: '0'
- page_1:
- display_options:
- path: test_exposed_block
- exposed_block: '1'
- display_plugin: page
- display_title: Page
- id: page_1
- position: '0'
-label: ''
-id: test_exposed_block
-tag: ''
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 4b90f77..bb312ff 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -485,6 +485,8 @@ function views_preprocess_html(&$variables) {
if ($key !== FALSE) {
unset($variables['attributes']['class'][$key]);
$variables['attributes']['data-views-page-contextual-id'] = $variables['title_suffix']['contextual_links']['#id'];
+ // Add the JavaScript, with a group and weight such that it will run
+ // before modules/contextual/contextual.js.
drupal_add_library('views', 'views.contextual-links');
}
}
@@ -819,7 +821,6 @@ function views_library_info() {
'title' => 'Views Contextual links',
'version' => VERSION,
'js' => array(
- // Set to -10 to move it before the contextual links javascript file.
"$path/js/views-contextual.js" => array('group' => JS_LIBRARY, 'weight' => -10),
),
'dependencies' => array(
diff --git a/core/modules/views/views.theme.inc b/core/modules/views/views.theme.inc
index 0f44cd9..522552e 100644
--- a/core/modules/views/views.theme.inc
+++ b/core/modules/views/views.theme.inc
@@ -616,38 +616,27 @@ function template_preprocess_views_view_table(&$variables) {
// Render each field into its appropriate column.
foreach ($result as $num => $row) {
-
- // Skip building the attributes and content if the field is to be excluded
- // from the display.
- if (!empty($fields[$field]->options['exclude'])) {
- continue;
- }
-
- // Reference to the column in the loop to make the code easier to read.
- $column_reference =& $variables['rows'][$num]['columns'][$column];
-
// Add field classes.
- $column_reference['attributes'] = array();
+ $variables['rows'][$num]['columns'][$column]['attributes'] = array();
if ($fields[$field]->options['element_default_classes']) {
- $column_reference['attributes']['class'][] = 'views-field';
- $column_reference['attributes']['class'][] = 'views-field-' . $variables['fields'][$field];
+ $variables['rows'][$num]['columns'][$column]['attributes']['class'][] = 'views-field';
+ $variables['rows'][$num]['columns'][$column]['attributes']['class'][] = 'views-field-' . $variables['fields'][$field];
}
if ($classes = $fields[$field]->elementClasses($num)) {
- $column_reference['attributes']['class'][] = $classes;
+ $variables['rows'][$num]['columns'][$column]['attributes']['class'][] = $classes;
}
-
// Add responsive header classes.
if (!empty($options['info'][$field]['responsive'])) {
- $column_reference['attributes']['class'][] = $options['info'][$field]['responsive'];
+ $variables['rows'][$num]['columns'][$column]['attributes']['class'][] = $options['info'][$field]['responsive'];
}
// Improves accessibility of complex tables.
if (isset($variables['header'][$field]['attributes']['id'])) {
- $column_reference['attributes']['headers'] = array($variables['header'][$field]['attributes']['id']);
+ $variables['rows'][$num]['columns'][$column]['attributes']['headers'] = array($variables['header'][$field]['attributes']['id']);
}
- if (!empty($fields[$field])) {
+ if (!empty($fields[$field]) && empty($fields[$field]->options['exclude'])) {
$field_output = $handler->getField($num, $field);
$element_type = $fields[$field]->elementType(TRUE, TRUE);
if ($element_type) {
@@ -655,20 +644,20 @@ function template_preprocess_views_view_table(&$variables) {
}
// Only bother with separators and stuff if the field shows up.
- if (!empty($field_output) && empty($column_reference['content'])) {
+ if (!empty($field_output) && empty($variables['rows'][$num]['columns'][$column]['content'])) {
// Place the field into the column, along with an optional separator.
- if (!empty($column_reference['content'])) {
+ if (!empty($variables['rows'][$num][$column]['content'])) {
if (!empty($options['info'][$column]['separator'])) {
- $column_reference['content'] .= filter_xss_admin($options['info'][$column]['separator']);
+ $variables['rows'][$num]['columns'][$column]['content'] .= filter_xss_admin($options['info'][$column]['separator']);
}
}
else {
- $column_reference['content'] = '';
+ $variables['rows'][$num]['columns'][$column]['content'] = '';
}
- $column_reference['content'] .= $field_output;
+ $variables['rows'][$num]['columns'][$column]['content'] .= $field_output;
}
}
- $column_reference['attributes'] = new Attribute($column_reference['attributes']);
+ $variables['rows'][$num]['columns'][$column]['attributes'] = new Attribute($variables['rows'][$num]['columns'][$column]['attributes']);
}
// Remove columns if the option is hide empty column is checked and the
diff --git a/core/modules/views_ui/js/views-admin.js b/core/modules/views_ui/js/views-admin.js
index d20b0af..9dc1075 100644
--- a/core/modules/views_ui/js/views-admin.js
+++ b/core/modules/views_ui/js/views-admin.js
@@ -2,76 +2,78 @@
* @file
* Some basic behaviors and utility functions for Views UI.
*/
-(function ($, Drupal, drupalSettings, debounce) {
-
-"use strict";
-
Drupal.viewsUi = {};
+Drupal.behaviors.viewsUiEditView = {};
+
/**
* Improve the user experience of the views edit interface.
*/
-Drupal.behaviors.viewsUiEditView = {
- attach: function () {
- // Only show the SQL rewrite warning when the user has chosen the
- // corresponding checkbox.
- $('#edit-query-options-disable-sql-rewrite').on('click', function () {
- $('.sql-rewrite-warning').toggleClass('js-hide');
- });
- }
+Drupal.behaviors.viewsUiEditView.attach = function (context, settings) {
+
+ "use strict";
+
+ // Only show the SQL rewrite warning when the user has chosen the
+ // corresponding checkbox.
+ jQuery('#edit-query-options-disable-sql-rewrite').click(function () {
+ jQuery('.sql-rewrite-warning').toggleClass('js-hide');
+ });
};
+Drupal.behaviors.viewsUiAddView = {};
+
/**
* In the add view wizard, use the view name to prepopulate form fields such as
* page title and menu link.
*/
-Drupal.behaviors.viewsUiAddView = {
- attach: function (context) {
- var $context = $(context);
- // Set up regular expressions to allow only numbers, letters, and dashes.
- var exclude = new RegExp('[^a-z0-9\\-]+', 'g');
- var replace = '-';
- var suffix;
-
- // The page title, block title, and menu link fields can all be prepopulated
- // with the view name - no regular expression needed.
- var $fields = $context.find('[id^="edit-page-title"], [id^="edit-block-title"], [id^="edit-page-link-properties-title"]');
- if ($fields.length) {
- if (!this.fieldsFiller) {
- this.fieldsFiller = new Drupal.viewsUi.FormFieldFiller($fields);
- }
- else {
- // After an AJAX response, this.fieldsFiller will still have event
- // handlers bound to the old version of the form fields (which don't exist
- // anymore). The event handlers need to be unbound and then rebound to the
- // new markup. Note that jQuery.live is difficult to make work in this
- // case because the IDs of the form fields change on every AJAX response.
- this.fieldsFiller.rebind($fields);
- }
+Drupal.behaviors.viewsUiAddView.attach = function (context, settings) {
+
+ "use strict";
+
+ var $ = jQuery;
+ var exclude, replace, suffix;
+ // Set up regular expressions to allow only numbers, letters, and dashes.
+ exclude = new RegExp('[^a-z0-9\\-]+', 'g');
+ replace = '-';
+
+ // The page title, block title, and menu link fields can all be prepopulated
+ // with the view name - no regular expression needed.
+ var $fields = $(context).find('[id^="edit-page-title"], [id^="edit-block-title"], [id^="edit-page-link-properties-title"]');
+ if ($fields.length) {
+ if (!this.fieldsFiller) {
+ this.fieldsFiller = new Drupal.viewsUi.FormFieldFiller($fields);
}
+ else {
+ // After an AJAX response, this.fieldsFiller will still have event
+ // handlers bound to the old version of the form fields (which don't exist
+ // anymore). The event handlers need to be unbound and then rebound to the
+ // new markup. Note that jQuery.live is difficult to make work in this
+ // case because the IDs of the form fields change on every AJAX response.
+ this.fieldsFiller.rebind($fields);
+ }
+ }
- // Prepopulate the path field with a URLified version of the view name.
- var $pathField = $context.find('[id^="edit-page-path"]');
- if ($pathField.length) {
- if (!this.pathFiller) {
- this.pathFiller = new Drupal.viewsUi.FormFieldFiller($pathField, exclude, replace);
- }
- else {
- this.pathFiller.rebind($pathField);
- }
+ // Prepopulate the path field with a URLified version of the view name.
+ var $pathField = $(context).find('[id^="edit-page-path"]');
+ if ($pathField.length) {
+ if (!this.pathFiller) {
+ this.pathFiller = new Drupal.viewsUi.FormFieldFiller($pathField, exclude, replace);
}
+ else {
+ this.pathFiller.rebind($pathField);
+ }
+ }
- // Populate the RSS feed field with a URLified version of the view name, and
- // an .xml suffix (to make it unique).
- var $feedField = $context.find('[id^="edit-page-feed-properties-path"]');
- if ($feedField.length) {
- if (!this.feedFiller) {
- suffix = '.xml';
- this.feedFiller = new Drupal.viewsUi.FormFieldFiller($feedField, exclude, replace, suffix);
- }
- else {
- this.feedFiller.rebind($feedField);
- }
+ // Populate the RSS feed field with a URLified version of the view name, and
+ // an .xml suffix (to make it unique).
+ var $feedField = $(context).find('[id^="edit-page-feed-properties-path"]');
+ if ($feedField.length) {
+ if (!this.feedFiller) {
+ suffix = '.xml';
+ this.feedFiller = new Drupal.viewsUi.FormFieldFiller($feedField, exclude, replace, suffix);
+ }
+ else {
+ this.feedFiller.rebind($feedField);
}
}
};
@@ -93,6 +95,10 @@ Drupal.behaviors.viewsUiAddView = {
* Optional. A suffix to append at the end of the target field content.
*/
Drupal.viewsUi.FormFieldFiller = function ($target, exclude, replace, suffix) {
+
+ "use strict";
+
+ var $ = jQuery;
this.source = $('#edit-label');
this.target = $target;
this.exclude = exclude || false;
@@ -112,85 +118,108 @@ Drupal.viewsUi.FormFieldFiller = function ($target, exclude, replace, suffix) {
// Object constructor; no return value.
};
-$.extend(Drupal.viewsUi.FormFieldFiller.prototype, {
- /**
- * Bind the form-filling behavior.
- */
- bind: function () {
- this.unbind();
- // Populate the form field when the source changes.
- this.source.on('keyup.viewsUi change.viewsUi', this.populate);
- // Quit populating the field as soon as it gets focus.
- this.target.on('focus.viewsUi', this.unbind);
- },
+/**
+ * Bind the form-filling behavior.
+ */
+Drupal.viewsUi.FormFieldFiller.prototype.bind = function () {
- /**
- * Get the source form field value as altered by the passed-in parameters.
- */
- getTransliterated: function () {
- var from = this.source.val();
- if (this.exclude) {
- from = from.toLowerCase().replace(this.exclude, this.replace);
- }
- return from + this.suffix;
- },
+ "use strict";
- /**
- * Populate the target form field with the altered source field value.
- */
- _populate: function () {
- var transliterated = this.getTransliterated();
- this.target.val(transliterated);
- },
+ this.unbind();
+ // Populate the form field when the source changes.
+ this.source.bind('keyup.viewsUi change.viewsUi', this.populate);
+ // Quit populating the field as soon as it gets focus.
+ this.target.bind('focus.viewsUi', this.unbind);
+};
- /**
- * Stop prepopulating the form fields.
- */
- _unbind: function () {
- this.source.off('keyup.viewsUi change.viewsUi', this.populate);
- this.target.off('focus.viewsUi', this.unbind);
- },
+/**
+ * Get the source form field value as altered by the passed-in parameters.
+ */
+Drupal.viewsUi.FormFieldFiller.prototype.getTransliterated = function () {
- /**
- * Bind event handlers to the new form fields, after they're replaced via AJAX.
- */
- rebind: function ($fields) {
- this.target = $fields;
- this.bind();
- }});
-
-
-Drupal.behaviors.addItemForm = {
- attach: function (context) {
- // The add item form may have an id of views-ui-add-item-form--n.
- var $form = $(context).find('form[id^="views-ui-add-item-form"]').first();
- // Make sure we don't add more than one event handler to the same form.
- $form = $form.once('views-ui-add-item-form');
- if ($form.length) {
- new Drupal.viewsUi.AddItemForm($form);
- }
+ "use strict";
+
+ var from = this.source.val();
+ if (this.exclude) {
+ from = from.toLowerCase().replace(this.exclude, this.replace);
}
+ return from + this.suffix;
};
-Drupal.viewsUi.AddItemForm = function ($form) {
+/**
+ * Populate the target form field with the altered source field value.
+ */
+Drupal.viewsUi.FormFieldFiller.prototype._populate = function () {
+
+ "use strict";
+
+ var transliterated = this.getTransliterated();
+ this.target.val(transliterated);
+};
+
+/**
+ * Stop prepopulating the form fields.
+ */
+Drupal.viewsUi.FormFieldFiller.prototype._unbind = function () {
+
+ "use strict";
+
+ this.source.unbind('keyup.viewsUi change.viewsUi', this.populate);
+ this.target.unbind('focus.viewsUi', this.unbind);
+};
+
+/**
+ * Bind event handlers to the new form fields, after they're replaced via AJAX.
+ */
+Drupal.viewsUi.FormFieldFiller.prototype.rebind = function ($fields) {
+
+ "use strict";
+
+ this.target = $fields;
+ this.bind();
+};
+
+Drupal.behaviors.addItemForm = {};
+Drupal.behaviors.addItemForm.attach = function (context) {
+
+ "use strict";
+
+ var $ = jQuery;
+ // The add item form may have an id of views-ui-add-item-form--n.
+ var $form = $(context).find('form[id^="views-ui-add-item-form"]').first();
+ // Make sure we don't add more than one event handler to the same form.
+ $form = $form.once('views-ui-add-item-form');
+ if ($form.length) {
+ new Drupal.viewsUi.addItemForm($form);
+ }
+};
+
+Drupal.viewsUi.addItemForm = function($form) {
+
+ "use strict";
+
this.$form = $form;
- this.$form.find('.views-filterable-options :checkbox').on('click', $.proxy(this.handleCheck, this));
+ this.$form.find('.views-filterable-options :checkbox').click(jQuery.proxy(this.handleCheck, this));
// Find the wrapper of the displayed text.
this.$selected_div = this.$form.find('.views-selected-options').parent();
this.$selected_div.hide();
this.checkedItems = [];
};
-Drupal.viewsUi.AddItemForm.prototype.handleCheck = function (event) {
- var $target = $(event.target);
- var label = $.trim($target.next().text());
+Drupal.viewsUi.addItemForm.prototype.handleCheck = function (event) {
+
+ "use strict";
+
+ var $target = jQuery(event.target);
+ var label = jQuery.trim($target.next().text());
// Add/remove the checked item to the list.
if ($target.is(':checked')) {
this.$selected_div.show();
this.checkedItems.push(label);
}
else {
- var position = $.inArray(label, this.checkedItems);
+ var length = this.checkedItems.length;
+ var position = jQuery.inArray(label, this.checkedItems);
// Delete the item from the list and take sure that the list doesn't have undefined items left.
for (var i = 0; i < this.checkedItems.length; i++) {
if (i === position) {
@@ -210,7 +239,10 @@ Drupal.viewsUi.AddItemForm.prototype.handleCheck = function (event) {
/**
* Refresh the display of the checked items.
*/
-Drupal.viewsUi.AddItemForm.prototype.refreshCheckedItems = function () {
+Drupal.viewsUi.addItemForm.prototype.refreshCheckedItems = function() {
+
+ "use strict";
+
// Perhaps we should precache the text div, too.
this.$selected_div.find('.views-selected-options').html(this.checkedItems.join(', '));
Drupal.viewsUi.resizeModal('', true);
@@ -221,51 +253,55 @@ Drupal.viewsUi.AddItemForm.prototype.refreshCheckedItems = function () {
* The following behavior detaches the elements from the DOM, wraps them
* in an unordered list, then appends them to the list of tabs.
*/
-Drupal.behaviors.viewsUiRenderAddViewButton = {
- attach: function (context) {
- // Build the add display menu and pull the display input buttons into it.
- var $menu = $(context).find('#views-display-menu-tabs').once('views-ui-render-add-view-button-processed');
- if (!$menu.length) {
- return;
- }
+Drupal.behaviors.viewsUiRenderAddViewButton = {};
- var $addDisplayDropdown = $('
');
- var $displayButtons = $menu.nextAll('input.add-display').detach();
- $displayButtons.appendTo($addDisplayDropdown.find('.action-list')).wrap('
')
- .parent().first().addClass('first').end().last().addClass('last');
- // Remove the 'Add ' prefix from the button labels since they're being palced
- // in an 'Add' dropdown.
- // @todo This assumes English, but so does $addDisplayDropdown above. Add
- // support for translation.
- $displayButtons.each(function () {
- var label = $(this).val();
- if (label.substr(0, 4) === 'Add ') {
- $(this).val(label.substr(4));
- }
- });
- $addDisplayDropdown.appendTo($menu);
+Drupal.behaviors.viewsUiRenderAddViewButton.attach = function (context, settings) {
- // Add the click handler for the add display button
- $menu.find('li.add > a').on('click', function (event) {
- event.preventDefault();
- var $trigger = $(this);
- Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu($trigger);
- });
- // Add a mouseleave handler to close the dropdown when the user mouses
- // away from the item. We use mouseleave instead of mouseout because
- // the user is going to trigger mouseout when she moves from the trigger
- // link to the sub menu items.
- // We use the live binder because the open class on this item will be
- // toggled on and off and we want the handler to take effect in the cases
- // that the class is present, but not when it isn't.
- $('li.add', $menu).on('mouseleave', function (event) {
- var $this = $(this);
- var $trigger = $this.children('a[href="#"]');
- if ($this.children('.action-list').is(':visible')) {
- Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu($trigger);
- }
- });
+ "use strict";
+
+ var $ = jQuery;
+ // Build the add display menu and pull the display input buttons into it.
+ var $menu = $('#views-display-menu-tabs', context).once('views-ui-render-add-view-button-processed');
+
+ if (!$menu.length) {
+ return;
}
+ var $addDisplayDropdown = $('
');
+ var $displayButtons = $menu.nextAll('input.add-display').detach();
+ $displayButtons.appendTo($addDisplayDropdown.find('.action-list')).wrap('
')
+ .parent().first().addClass('first').end().last().addClass('last');
+ // Remove the 'Add ' prefix from the button labels since they're being palced
+ // in an 'Add' dropdown.
+ // @todo This assumes English, but so does $addDisplayDropdown above. Add
+ // support for translation.
+ $displayButtons.each(function () {
+ var label = $(this).val();
+ if (label.substr(0, 4) === 'Add ') {
+ $(this).val(label.substr(4));
+ }
+ });
+ $addDisplayDropdown.appendTo($menu);
+
+ // Add the click handler for the add display button
+ $('li.add > a', $menu).bind('click', function (event) {
+ event.preventDefault();
+ var $trigger = $(this);
+ Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu($trigger);
+ });
+ // Add a mouseleave handler to close the dropdown when the user mouses
+ // away from the item. We use mouseleave instead of mouseout because
+ // the user is going to trigger mouseout when she moves from the trigger
+ // link to the sub menu items.
+ // We use the live binder because the open class on this item will be
+ // toggled on and off and we want the handler to take effect in the cases
+ // that the class is present, but not when it isn't.
+ $('li.add', $menu).on('mouseleave', function (event) {
+ var $this = $(this);
+ var $trigger = $this.children('a[href="#"]');
+ if ($this.children('.action-list').is(':visible')) {
+ Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu($trigger);
+ }
+ });
};
/**
@@ -273,19 +309,26 @@ Drupal.behaviors.viewsUiRenderAddViewButton = {
* not written specifically for this UI, but I'm not sure where to put it.
*/
Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu = function ($trigger) {
+
+ "use strict";
+
$trigger.parent().toggleClass('open');
$trigger.next().slideToggle('fast');
};
-Drupal.behaviors.viewsUiSearchOptions = {
- attach: function (context) {
- // The add item form may have an id of views-ui-add-item-form--n.
- var $form = $(context).find('form[id^="views-ui-add-item-form"]').first();
- // Make sure we don't add more than one event handler to the same form.
- $form = $form.once('views-ui-filter-options');
- if ($form.length) {
- new Drupal.viewsUi.OptionsSearch($form);
- }
+Drupal.behaviors.viewsUiSearchOptions = {};
+
+Drupal.behaviors.viewsUiSearchOptions.attach = function (context) {
+
+ "use strict";
+
+ var $ = jQuery;
+ // The add item form may have an id of views-ui-add-item-form--n.
+ var $form = $(context).find('form[id^="views-ui-add-item-form"]').first();
+ // Make sure we don't add more than one event handler to the same form.
+ $form = $form.once('views-ui-filter-options');
+ if ($form.length) {
+ new Drupal.viewsUi.OptionsSearch($form);
}
};
@@ -297,152 +340,171 @@ Drupal.behaviors.viewsUiSearchOptions = {
* containing "taxonomy" in their label.
*/
Drupal.viewsUi.OptionsSearch = function ($form) {
+
+ "use strict";
+
this.$form = $form;
// Add a keyup handler to the search box.
this.$searchBox = this.$form.find('#edit-override-controls-options-search');
- this.$searchBox.keyup($.proxy(this.handleKeyup, this));
+ this.$searchBox.keyup(jQuery.proxy(this.handleKeyup, this));
// Get a list of option labels and their corresponding divs and maintain it
// in memory, so we have as little overhead as possible at keyup time.
this.options = this.getOptions(this.$form.find('.filterable-option'));
// Restripe on initial loading.
this.handleKeyup();
// Trap the ENTER key in the search box so that it doesn't submit the form.
- this.$searchBox.on('keypress', function (event) {
+ this.$searchBox.keypress(function(event) {
if (event.which === 13) {
event.preventDefault();
}
});
};
-$.extend(Drupal.viewsUi.OptionsSearch.prototype, {
- /**
- * Assemble a list of all the filterable options on the form.
- *
- * @param $allOptions
- * A $ object representing the rows of filterable options to be
- * shown and hidden depending on the user's search terms.
- */
- getOptions: function ($allOptions) {
- var i, $label, $description, $option;
- var options = [];
- var length = $allOptions.length;
- for (i = 0; i < length; i++) {
- $option = $($allOptions[i]);
- $label = $option.find('label');
- $description = $option.find('div.description');
- options[i] = {
- // Search on the lowercase version of the label text + description.
- 'searchText': $label.text().toLowerCase() + " " + $description.text().toLowerCase(),
- // Maintain a reference to the jQuery object for each row, so we don't
- // have to create a new object inside the performance-sensitive keyup
- // handler.
- '$div': $option
- };
- }
- return options;
- },
-
- /**
- * Keyup handler for the search box that hides or shows the relevant options.
- */
- handleKeyup: function (event) {
- var found, i, j, option, search, words, wordsLength, zebraClass, zebraCounter;
-
- // Determine the user's search query. The search text has been converted to
- // lowercase.
- search = this.$searchBox.val().toLowerCase();
- words = search.split(' ');
- wordsLength = words.length;
-
- // Start the counter for restriping rows.
- zebraCounter = 0;
-
- // Search through the search texts in the form for matching text.
- var length = this.options.length;
- for (i = 0; i < length; i++) {
- // Use a local variable for the option being searched, for performance.
- option = this.options[i];
- found = true;
- // Each word in the search string has to match the item in order for the
- // item to be shown.
- for (j = 0; j < wordsLength; j++) {
- if (option.searchText.indexOf(words[j]) === -1) {
- found = false;
- }
- }
- if (found) {
- // Show the checkbox row, and restripe it.
- zebraClass = (zebraCounter % 2) ? 'odd' : 'even';
- option.$div.show();
- option.$div.removeClass('even odd');
- option.$div.addClass(zebraClass);
- zebraCounter++;
- }
- else {
- // The search string wasn't found; hide this item.
- option.$div.hide();
- }
- }
+/**
+ * Assemble a list of all the filterable options on the form.
+ *
+ * @param $allOptions
+ * A jQuery object representing the rows of filterable options to be
+ * shown and hidden depending on the user's search terms.
+ */
+Drupal.viewsUi.OptionsSearch.prototype.getOptions = function ($allOptions) {
+
+ "use strict";
+
+ var $ = jQuery;
+ var i, $label, $description, $option;
+ var options = [];
+ var length = $allOptions.length;
+ for (i = 0; i < length; i++) {
+ $option = $($allOptions[i]);
+ $label = $option.find('label');
+ $description = $option.find('div.description');
+ options[i] = {
+ // Search on the lowercase version of the label text + description.
+ 'searchText': $label.text().toLowerCase() + " " + $description.text().toLowerCase(),
+ // Maintain a reference to the jQuery object for each row, so we don't
+ // have to create a new object inside the performance-sensitive keyup
+ // handler.
+ '$div': $option
+ };
}
-});
+ return options;
+};
-Drupal.behaviors.viewsUiPreview = {
- attach: function (context) {
- // Only act on the edit view form.
- var $contextualFiltersBucket = $(context).find('.views-display-column .views-ui-display-tab-bucket.contextual-filters');
- if ($contextualFiltersBucket.length === 0) {
- return;
+/**
+ * Keyup handler for the search box that hides or shows the relevant options.
+ */
+Drupal.viewsUi.OptionsSearch.prototype.handleKeyup = function (event) {
+
+ "use strict";
+
+ var found, i, j, option, search, words, wordsLength, zebraClass, zebraCounter;
+
+ // Determine the user's search query. The search text has been converted to
+ // lowercase.
+ search = this.$searchBox.val().toLowerCase();
+ words = search.split(' ');
+ wordsLength = words.length;
+
+ // Start the counter for restriping rows.
+ zebraCounter = 0;
+
+ // Search through the search texts in the form for matching text.
+ var length = this.options.length;
+ for (i = 0; i < length; i++) {
+ // Use a local variable for the option being searched, for performance.
+ option = this.options[i];
+ found = true;
+ // Each word in the search string has to match the item in order for the
+ // item to be shown.
+ for (j = 0; j < wordsLength; j++) {
+ if (option.searchText.indexOf(words[j]) === -1) {
+ found = false;
+ }
}
-
- // If the display has no contextual filters, hide the form where you enter
- // the contextual filters for the live preview. If it has contextual filters,
- // show the form.
- var $contextualFilters = $contextualFiltersBucket.find('.views-display-setting a');
- if ($contextualFilters.length) {
- $('#preview-args').parent().show();
+ if (found) {
+ // Show the checkbox row, and restripe it.
+ zebraClass = (zebraCounter % 2) ? 'odd' : 'even';
+ option.$div.show();
+ option.$div.removeClass('even odd');
+ option.$div.addClass(zebraClass);
+ zebraCounter++;
}
else {
- $('#preview-args').parent().hide();
+ // The search string wasn't found; hide this item.
+ option.$div.hide();
}
+ }
+};
- // Executes an initial preview.
- if ($('#edit-displays-live-preview').once('edit-displays-live-preview').is(':checked')) {
- $('#preview-submit').once('edit-displays-live-preview').trigger('click');
- }
+Drupal.behaviors.viewsUiPreview = {};
+Drupal.behaviors.viewsUiPreview.attach = function (context, settings) {
+
+ "use strict";
+
+ var $ = jQuery;
+
+ // Only act on the edit view form.
+ var contextualFiltersBucket = $('.views-display-column .views-ui-display-tab-bucket.contextual-filters', context);
+ if (contextualFiltersBucket.length === 0) {
+ return;
+ }
+
+ // If the display has no contextual filters, hide the form where you enter
+ // the contextual filters for the live preview. If it has contextual filters,
+ // show the form.
+ var contextualFilters = $('.views-display-setting a', contextualFiltersBucket);
+ if (contextualFilters.length) {
+ $('#preview-args').parent().show();
+ }
+ else {
+ $('#preview-args').parent().hide();
+ }
+
+ // Executes an initial preview.
+ if ($('#edit-displays-live-preview').once('edit-displays-live-preview').is(':checked')) {
+ $('#preview-submit').once('edit-displays-live-preview').click();
}
};
-Drupal.behaviors.viewsUiRearrangeFilter = {
- attach: function (context) {
- // Only act on the rearrange filter form.
- if (typeof Drupal.tableDrag === 'undefined' || typeof Drupal.tableDrag['views-rearrange-filters'] === 'undefined') {
- return;
- }
- var $context = $(context);
- var $table = $context.find('#views-rearrange-filters').once('views-rearrange-filters');
- var $operator = $context.find('.form-item-filter-groups-operator').once('views-rearrange-filters');
- if ($table.length) {
- new Drupal.viewsUi.RearrangeFilterHandler($table, $operator);
- }
+Drupal.behaviors.viewsUiRearrangeFilter = {};
+Drupal.behaviors.viewsUiRearrangeFilter.attach = function (context, settings) {
+
+ "use strict";
+
+ var $ = jQuery;
+ // Only act on the rearrange filter form.
+ if (typeof Drupal.tableDrag === 'undefined' || typeof Drupal.tableDrag['views-rearrange-filters'] === 'undefined') {
+ return;
+ }
+
+ var table = $('#views-rearrange-filters', context).once('views-rearrange-filters');
+ var operator = $('.form-item-filter-groups-operator', context).once('views-rearrange-filters');
+ if (table.length) {
+ new Drupal.viewsUi.rearrangeFilterHandler(table, operator);
}
};
/**
* Improve the UI of the rearrange filters dialog box.
*/
-Drupal.viewsUi.RearrangeFilterHandler = function ($table, $operator) {
+Drupal.viewsUi.rearrangeFilterHandler = function (table, operator) {
+
+ "use strict";
+
+ var $ = jQuery;
// Keep a reference to the
being altered and to the div containing
// the filter groups operator dropdown (if it exists).
- this.table = $table;
- this.operator = $operator;
+ this.table = table;
+ this.operator = operator;
this.hasGroupOperator = this.operator.length > 0;
// Keep a reference to all draggable rows within the table.
- this.draggableRows = $table.find('.draggable');
+ this.draggableRows = $('.draggable', table);
// Keep a reference to the buttons for adding and removing filter groups.
this.addGroupButton = $('input#views-add-group');
- this.removeGroupButtons = $table.find('input.views-remove-group');
+ this.removeGroupButtons = $('input.views-remove-group', table);
// Add links that duplicate the functionality of the (hidden) add and remove
// buttons.
@@ -465,9 +527,9 @@ Drupal.viewsUi.RearrangeFilterHandler = function ($table, $operator) {
// next to the filters in each group, and bind a handler so that they change
// based on the values of the operator dropdown within that group.
this.redrawOperatorLabels();
- $table.find('.views-group-title select')
+ $('.views-group-title select', table)
.once('views-rearrange-filter-handler')
- .on('change.views-rearrange-filter-handler', $.proxy(this, 'redrawOperatorLabels'));
+ .bind('change.views-rearrange-filter-handler', $.proxy(this, 'redrawOperatorLabels'));
// Bind handlers so that when a "Remove" link is clicked, we:
// - Update the rowspans of cells containing an operator dropdown (since they
@@ -475,92 +537,96 @@ Drupal.viewsUi.RearrangeFilterHandler = function ($table, $operator) {
// - Redraw the operator labels next to the filters in the group (since the
// filter that is currently displayed last in each group is not supposed to
// have a label display next to it).
- $table.find('a.views-groups-remove-link')
+ $('a.views-groups-remove-link', this.table)
.once('views-rearrange-filter-handler')
- .on('click.views-rearrange-filter-handler', $.proxy(this, 'updateRowspans'))
- .on('click.views-rearrange-filter-handler', $.proxy(this, 'redrawOperatorLabels'));
+ .bind('click.views-rearrange-filter-handler', $.proxy(this, 'updateRowspans'))
+ .bind('click.views-rearrange-filter-handler', $.proxy(this, 'redrawOperatorLabels'));
};
-$.extend(Drupal.viewsUi.RearrangeFilterHandler.prototype, {
- /**
- * Insert links that allow filter groups to be added and removed.
- */
- insertAddRemoveFilterGroupLinks: function () {
-
- // Insert a link for adding a new group at the top of the page, and make it
- // match the action links styling used in a typical page.tpl.php. Note that
- // Drupal does not provide a theme function for this markup, so this is the
- // best we can do.
- $('
')
- .prependTo(this.table.parent())
- // When the link is clicked, dynamically click the hidden form button for
- // adding a new filter group.
+/**
+ * Insert links that allow filter groups to be added and removed.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.insertAddRemoveFilterGroupLinks = function () {
+
+ "use strict";
+
+ var $ = jQuery;
+
+ // Insert a link for adding a new group at the top of the page, and make it
+ // match the action links styling used in a typical page.tpl.php. Note that
+ // Drupal does not provide a theme function for this markup, so this is the
+ // best we can do.
+ $('
')
+ .prependTo(this.table.parent())
+ // When the link is clicked, dynamically click the hidden form button for
+ // adding a new filter group.
+ .once('views-rearrange-filter-handler')
+ .bind('click.views-rearrange-filter-handler', $.proxy(this, 'clickAddGroupButton'));
+
+ // Find each (visually hidden) button for removing a filter group and insert
+ // a link next to it.
+ var length = this.removeGroupButtons.length;
+ var i;
+ for (i = 0; i < length; i++) {
+ var $removeGroupButton = $(this.removeGroupButtons[i]);
+ var buttonId = $removeGroupButton.attr('id');
+ $('' + Drupal.t('Remove group') + '')
+ .insertBefore($removeGroupButton)
+ // When the link is clicked, dynamically click the corresponding form
+ // button.
.once('views-rearrange-filter-handler')
- .on('click.views-rearrange-filter-handler', $.proxy(this, 'clickAddGroupButton'));
-
- // Find each (visually hidden) button for removing a filter group and insert
- // a link next to it.
- var length = this.removeGroupButtons.length;
- var i;
- for (i = 0; i < length; i++) {
- var $removeGroupButton = $(this.removeGroupButtons[i]);
- var buttonId = $removeGroupButton.attr('id');
- $('' + Drupal.t('Remove group') + '')
- .insertBefore($removeGroupButton)
- // When the link is clicked, dynamically click the corresponding form
- // button.
- .once('views-rearrange-filter-handler')
- .on('click.views-rearrange-filter-handler', { buttonId: buttonId }, $.proxy(this, 'clickRemoveGroupButton'));
- }
- },
+ .bind('click.views-rearrange-filter-handler', {buttonId: buttonId}, $.proxy(this, 'clickRemoveGroupButton'));
+ }
+};
- /**
- * Dynamically click the button that adds a new filter group.
- */
- clickAddGroupButton: function () {
- // Due to conflicts between Drupal core's AJAX system and the Views AJAX
- // system, the only way to get this to work seems to be to trigger both the
- // .mousedown() and .submit() events.
- this.addGroupButton
- .trigger('mousedown')
- .trigger('submit');
- event.preventDefault();
- },
+/**
+ * Dynamically click the button that adds a new filter group.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.clickAddGroupButton = function () {
- /**
- * Dynamically click a button for removing a filter group.
- *
- * @param event
- * Event being triggered, with event.data.buttonId set to the ID of the
- * form button that should be clicked.
- */
- clickRemoveGroupButton: function (event) {
- // For some reason, here we only need to trigger .submit(), unlike for
- // Drupal.viewsUi.RearrangeFilterHandler.prototype.clickAddGroupButton()
- // where we had to trigger .mousedown() also.
- this.table.find('#' + event.data.buttonId).trigger('submit');
- event.preventDefault();
- },
+ "use strict";
- /**
- * Move the groups operator so that it's between the first two groups, and
- * duplicate it between any subsequent groups.
- */
- duplicateGroupsOperator: function () {
- var dropdowns, newRow, titleRow;
+ // Due to conflicts between Drupal core's AJAX system and the Views AJAX
+ // system, the only way to get this to work seems to be to trigger both the
+ // .mousedown() and .submit() events.
+ this.addGroupButton.mousedown();
+ this.addGroupButton.submit();
+ event.preventDefault();
+};
+
+/**
+ * Dynamically click a button for removing a filter group.
+ *
+ * @param event
+ * Event being triggered, with event.data.buttonId set to the ID of the
+ * form button that should be clicked.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.clickRemoveGroupButton = function (event) {
+
+ "use strict";
- var titleRows = $('tr.views-group-title');
+ // For some reason, here we only need to trigger .submit(), unlike for
+ // Drupal.viewsUi.rearrangeFilterHandler.prototype.clickAddGroupButton()
+ // where we had to trigger .mousedown() also.
+ jQuery('input#' + event.data.buttonId, this.table).submit();
+ event.preventDefault();
+};
- // Get rid of the explanatory text around the operator; its placement is
- // explanatory enough.
- this.operator.find('label').add('div.description').addClass('element-invisible');
- this.operator.find('select').addClass('form-select');
+/**
+ * Move the groups operator so that it's between the first two groups, and
+ * duplicate it between any subsequent groups.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.duplicateGroupsOperator = function () {
- // Keep a list of the operator dropdowns, so we can sync their behavior later.
- dropdowns = this.operator;
+ "use strict";
- // Move the operator to a new row just above the second group.
- titleRow = $('tr#views-group-title-2');
+ var $ = jQuery;
+ var dropdowns, newRow;
+
+ var titleRows = $('tr.views-group-title'), titleRow;
+
+ // Get rid of the explanatory text around the operator; its placement is
+ // explanatory enough.
this.operator.find('label').add('div.description').addClass('visually-hidden');
this.operator.find('select').addClass('form-select');
@@ -581,231 +647,261 @@ $.extend(Drupal.viewsUi.RearrangeFilterHandler.prototype, {
var fakeOperator = this.operator.clone();
fakeOperator.attr('id', '');
newRow = $('
');
- newRow.find('td').append(fakeOperator);
- newRow.insertBefore(titleRow);
- dropdowns = dropdowns.add(fakeOperator);
- }
+ newRow.find('td').append(fakeOperator);
+ newRow.insertBefore(titleRow);
+ dropdowns = dropdowns.add(fakeOperator);
+ }
- return dropdowns;
- },
+ return dropdowns;
+};
- /**
- * Make the duplicated groups operators change in sync with each other.
- */
- syncGroupsOperators: function () {
- if (this.dropdowns.length < 2) {
- // We only have one dropdown (or none at all), so there's nothing to sync.
- return;
- }
+/**
+ * Make the duplicated groups operators change in sync with each other.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.syncGroupsOperators = function () {
- this.dropdowns.on('change', $.proxy(this, 'operatorChangeHandler'));
- },
+ "use strict";
+
+ if (this.dropdowns.length < 2) {
+ // We only have one dropdown (or none at all), so there's nothing to sync.
+ return;
+ }
+
+ this.dropdowns.change(jQuery.proxy(this, 'operatorChangeHandler'));
+};
+
+/**
+ * Click handler for the operators that appear between filter groups.
+ *
+ * Forces all operator dropdowns to have the same value.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.operatorChangeHandler = function (event) {
+
+ "use strict";
+
+ var $ = jQuery;
+ var $target = $(event.target);
+ var operators = this.dropdowns.find('select').not($target);
+
+ // Change the other operators to match this new value.
+ operators.val($target.val());
+};
+
+Drupal.viewsUi.rearrangeFilterHandler.prototype.modifyTableDrag = function () {
+
+ "use strict";
+
+ var tableDrag = Drupal.tableDrag['views-rearrange-filters'];
+ var filterHandler = this;
/**
- * Click handler for the operators that appear between filter groups.
+ * Override the row.onSwap method from tabledrag.js.
*
- * Forces all operator dropdowns to have the same value.
+ * When a row is dragged to another place in the table, several things need
+ * to occur.
+ * - The row needs to be moved so that it's within one of the filter groups.
+ * - The operator cells that span multiple rows need their rowspan attributes
+ * updated to reflect the number of rows in each group.
+ * - The operator labels that are displayed next to each filter need to be
+ * redrawn, to account for the row's new location.
*/
- operatorChangeHandler: function (event) {
- var $target = $(event.target);
- var operators = this.dropdowns.find('select').not($target);
-
- // Change the other operators to match this new value.
- operators.val($target.val());
- },
-
- modifyTableDrag: function () {
- var tableDrag = Drupal.tableDrag['views-rearrange-filters'];
- var filterHandler = this;
-
- /**
- * Override the row.onSwap method from tabledrag.js.
- *
- * When a row is dragged to another place in the table, several things need
- * to occur.
- * - The row needs to be moved so that it's within one of the filter groups.
- * - The operator cells that span multiple rows need their rowspan attributes
- * updated to reflect the number of rows in each group.
- * - The operator labels that are displayed next to each filter need to be
- * redrawn, to account for the row's new location.
- */
- tableDrag.row.prototype.onSwap = function () {
- if (filterHandler.hasGroupOperator) {
- // Make sure the row that just got moved (this.group) is inside one of
- // the filter groups (i.e. below an empty marker row or a draggable). If
- // it isn't, move it down one.
- var thisRow = $(this.group);
- var previousRow = thisRow.prev('tr');
- if (previousRow.length && !previousRow.hasClass('group-message') && !previousRow.hasClass('draggable')) {
- // Move the dragged row down one.
- var next = thisRow.next();
- if (next.is('tr')) {
- this.swap('after', next);
- }
+ tableDrag.row.prototype.onSwap = function () {
+ if (filterHandler.hasGroupOperator) {
+ // Make sure the row that just got moved (this.group) is inside one of
+ // the filter groups (i.e. below an empty marker row or a draggable). If
+ // it isn't, move it down one.
+ var thisRow = jQuery(this.group);
+ var previousRow = thisRow.prev('tr');
+ if (previousRow.length && !previousRow.hasClass('group-message') && !previousRow.hasClass('draggable')) {
+ // Move the dragged row down one.
+ var next = thisRow.next();
+ if (next.is('tr')) {
+ this.swap('after', next);
}
- filterHandler.updateRowspans();
}
- // Redraw the operator labels that are displayed next to each filter, to
- // account for the row's new location.
- filterHandler.redrawOperatorLabels();
- };
+ filterHandler.updateRowspans();
+ }
+ // Redraw the operator labels that are displayed next to each filter, to
+ // account for the row's new location.
+ filterHandler.redrawOperatorLabels();
+ };
- /**
- * Override the onDrop method from tabledrag.js.
- */
- tableDrag.onDrop = function () {
- // If the tabledrag change marker (i.e., the "*") has been inserted inside
- // a row after the operator label (i.e., "And" or "Or") rearrange the items
- // so the operator label continues to appear last.
- var changeMarker = $(this.oldRowElement).find('.tabledrag-changed');
- if (changeMarker.length) {
- // Search for occurrences of the operator label before the change marker,
- // and reverse them.
- var operatorLabel = changeMarker.prevAll('.views-operator-label');
- if (operatorLabel.length) {
- operatorLabel.insertAfter(changeMarker);
- }
+ /**
+ * Override the onDrop method from tabledrag.js.
+ */
+ tableDrag.onDrop = function () {
+ var $ = jQuery;
+
+ // If the tabledrag change marker (i.e., the "*") has been inserted inside
+ // a row after the operator label (i.e., "And" or "Or") rearrange the items
+ // so the operator label continues to appear last.
+ var changeMarker = $(this.oldRowElement).find('.tabledrag-changed');
+ if (changeMarker.length) {
+ // Search for occurrences of the operator label before the change marker,
+ // and reverse them.
+ var operatorLabel = changeMarker.prevAll('.views-operator-label');
+ if (operatorLabel.length) {
+ operatorLabel.insertAfter(changeMarker);
}
+ }
- // Make sure the "group" dropdown is properly updated when rows are dragged
- // into an empty filter group. This is borrowed heavily from the block.js
- // implementation of tableDrag.onDrop().
- var groupRow = $(this.rowObject.element).prevAll('tr.group-message').get(0);
- var groupName = groupRow.className.replace(/([^ ]+[ ]+)*group-([^ ]+)-message([ ]+[^ ]+)*/, '$2');
- var groupField = $('select.views-group-select', this.rowObject.element);
- if ($(this.rowObject.element).prev('tr').is('.group-message') && !groupField.is('.views-group-select-' + groupName)) {
- var oldGroupName = groupField.attr('class').replace(/([^ ]+[ ]+)*views-group-select-([^ ]+)([ ]+[^ ]+)*/, '$2');
- groupField.removeClass('views-group-select-' + oldGroupName).addClass('views-group-select-' + groupName);
- groupField.val(groupName);
- }
- };
- },
+ // Make sure the "group" dropdown is properly updated when rows are dragged
+ // into an empty filter group. This is borrowed heavily from the block.js
+ // implementation of tableDrag.onDrop().
+ var groupRow = $(this.rowObject.element).prevAll('tr.group-message').get(0);
+ var groupName = groupRow.className.replace(/([^ ]+[ ]+)*group-([^ ]+)-message([ ]+[^ ]+)*/, '$2');
+ var groupField = $('select.views-group-select', this.rowObject.element);
+ if ($(this.rowObject.element).prev('tr').is('.group-message') && !groupField.is('.views-group-select-' + groupName)) {
+ var oldGroupName = groupField.attr('class').replace(/([^ ]+[ ]+)*views-group-select-([^ ]+)([ ]+[^ ]+)*/, '$2');
+ groupField.removeClass('views-group-select-' + oldGroupName).addClass('views-group-select-' + groupName);
+ groupField.val(groupName);
+ }
+ };
+};
- /**
- * Redraw the operator labels that are displayed next to each filter.
- */
- redrawOperatorLabels: function () {
- for (var i = 0; i < this.draggableRows.length; i++) {
- // Within the row, the operator labels are displayed inside the first table
- // cell (next to the filter name).
- var $draggableRow = $(this.draggableRows[i]);
- var $firstCell = $draggableRow.find('td:first');
- if ($firstCell.length) {
- // The value of the operator label ("And" or "Or") is taken from the
- // first operator dropdown we encounter, going backwards from the current
- // row. This dropdown is the one associated with the current row's filter
- // group.
- var operatorValue = $draggableRow.prevAll('.views-group-title').find('option:selected').html();
- var operatorLabel = '' + operatorValue + '';
- // If the next visible row after this one is a draggable filter row,
- // display the operator label next to the current row. (Checking for
- // visibility is necessary here since the "Remove" links hide the removed
- // row but don't actually remove it from the document).
- var $nextRow = $draggableRow.nextAll(':visible').eq(0);
- var $existingOperatorLabel = $firstCell.find('.views-operator-label');
- if ($nextRow.hasClass('draggable')) {
- // If an operator label was already there, replace it with the new one.
- if ($existingOperatorLabel.length) {
- $existingOperatorLabel.replaceWith(operatorLabel);
- }
- // Otherwise, append the operator label to the end of the table cell.
- else {
- $firstCell.append(operatorLabel);
- }
+/**
+ * Redraw the operator labels that are displayed next to each filter.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.redrawOperatorLabels = function () {
+
+ "use strict";
+
+ var $ = jQuery;
+ var i;
+ for (i = 0; i < this.draggableRows.length; i++) {
+ // Within the row, the operator labels are displayed inside the first table
+ // cell (next to the filter name).
+ var $draggableRow = $(this.draggableRows[i]);
+ var $firstCell = $('td:first', $draggableRow);
+ if ($firstCell.length) {
+ // The value of the operator label ("And" or "Or") is taken from the
+ // first operator dropdown we encounter, going backwards from the current
+ // row. This dropdown is the one associated with the current row's filter
+ // group.
+ var operatorValue = $draggableRow.prevAll('.views-group-title').find('option:selected').html();
+ var operatorLabel = '' + operatorValue + '';
+ // If the next visible row after this one is a draggable filter row,
+ // display the operator label next to the current row. (Checking for
+ // visibility is necessary here since the "Remove" links hide the removed
+ // row but don't actually remove it from the document).
+ var $nextRow = $draggableRow.nextAll(':visible').eq(0);
+ var $existingOperatorLabel = $firstCell.find('.views-operator-label');
+ if ($nextRow.hasClass('draggable')) {
+ // If an operator label was already there, replace it with the new one.
+ if ($existingOperatorLabel.length) {
+ $existingOperatorLabel.replaceWith(operatorLabel);
}
- // If the next row doesn't contain a filter, then this is the last row
- // in the group. We don't want to display the operator there (since
- // operators should only display between two related filters, e.g.
- // "filter1 AND filter2 AND filter3"). So we remove any existing label
- // that this row has.
+ // Otherwise, append the operator label to the end of the table cell.
else {
- $existingOperatorLabel.remove();
+ $firstCell.append(operatorLabel);
}
}
+ // If the next row doesn't contain a filter, then this is the last row
+ // in the group. We don't want to display the operator there (since
+ // operators should only display between two related filters, e.g.
+ // "filter1 AND filter2 AND filter3"). So we remove any existing label
+ // that this row has.
+ else {
+ $existingOperatorLabel.remove();
+ }
}
- },
+ }
+};
- /**
- * Update the rowspan attribute of each cell containing an operator dropdown.
- */
- updateRowspans: function () {
- var i, $row, $currentEmptyRow, draggableCount, $operatorCell;
- var rows = $(this.table).find('tr');
- var length = rows.length;
- for (i = 0; i < length; i++) {
- $row = $(rows[i]);
- if ($row.hasClass('views-group-title')) {
- // This row is a title row.
- // Keep a reference to the cell containing the dropdown operator.
- $operatorCell = $row.find('td.group-operator');
- // Assume this filter group is empty, until we find otherwise.
- draggableCount = 0;
- $currentEmptyRow = $row.next('tr');
- $currentEmptyRow.removeClass('group-populated').addClass('group-empty');
- // The cell with the dropdown operator should span the title row and
- // the "this group is empty" row.
- $operatorCell.attr('rowspan', 2);
- }
- else if ($row.hasClass('draggable') && $row.is(':visible')) {
- // We've found a visible filter row, so we now know the group isn't empty.
- draggableCount++;
- $currentEmptyRow.removeClass('group-empty').addClass('group-populated');
- // The operator cell should span all draggable rows, plus the title.
- $operatorCell.attr('rowspan', draggableCount + 1);
- }
+/**
+ * Update the rowspan attribute of each cell containing an operator dropdown.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.updateRowspans = function () {
+
+ "use strict";
+
+ var $ = jQuery;
+ var i, $row, $currentEmptyRow, draggableCount, $operatorCell;
+ var rows = $(this.table).find('tr');
+ var length = rows.length;
+ for (i = 0; i < length; i++) {
+ $row = $(rows[i]);
+ if ($row.hasClass('views-group-title')) {
+ // This row is a title row.
+ // Keep a reference to the cell containing the dropdown operator.
+ $operatorCell = $($row.find('td.group-operator'));
+ // Assume this filter group is empty, until we find otherwise.
+ draggableCount = 0;
+ $currentEmptyRow = $row.next('tr');
+ $currentEmptyRow.removeClass('group-populated').addClass('group-empty');
+ // The cell with the dropdown operator should span the title row and
+ // the "this group is empty" row.
+ $operatorCell.attr('rowspan', 2);
}
- }});
+ else if (($row).hasClass('draggable') && $row.is(':visible')) {
+ // We've found a visible filter row, so we now know the group isn't empty.
+ draggableCount++;
+ $currentEmptyRow.removeClass('group-empty').addClass('group-populated');
+ // The operator cell should span all draggable rows, plus the title.
+ $operatorCell.attr('rowspan', draggableCount + 1);
+ }
+ }
+};
+Drupal.behaviors.viewsFilterConfigSelectAll = {};
/**
* Add a select all checkbox, which checks each checkbox at once.
*/
-Drupal.behaviors.viewsFilterConfigSelectAll = {
- attach: function (context) {
- // Show the select all checkbox.
- $(context).find('#views-ui-config-item-form div.form-item-options-value-all').once('filterConfigSelectAll')
- .show()
- .find('input[type=checkbox]')
- .on('click', function () {
- var checked = $(this).is(':checked');
- // Update all checkbox beside the select all checkbox.
- $(this).parents('.form-checkboxes').find('input[type=checkbox]').each(function () {
- $(this).attr('checked', checked);
- });
- });
- // Uncheck the select all checkbox if any of the others are unchecked.
- $('#views-ui-config-item-form').find('div.form-type-checkbox').not($('.form-item-options-value-all'))
- .find('input[type=checkbox]')
- .on('click', function () {
- if ($(this).is('checked') === false) {
- $('#edit-options-value-all').prop('checked', false);
- }
- });
- }
+Drupal.behaviors.viewsFilterConfigSelectAll.attach = function(context) {
+
+ "use strict";
+
+ var $ = jQuery;
+ // Show the select all checkbox.
+ $('#views-ui-config-item-form div.form-item-options-value-all', context).once(function() {
+ $(this).show();
+ })
+ .find('input[type=checkbox]')
+ .click(function() {
+ var checked = $(this).is(':checked');
+ // Update all checkbox beside the select all checkbox.
+ $(this).parents('.form-checkboxes').find('input[type=checkbox]').each(function() {
+ $(this).attr('checked', checked);
+ });
+ });
+ // Uncheck the select all checkbox if any of the others are unchecked.
+ $('#views-ui-config-item-form div.form-type-checkbox').not($('.form-item-options-value-all')).find('input[type=checkbox]').each(function() {
+ $(this).click(function() {
+ if ($(this).is('checked') === false) {
+ $('#edit-options-value-all').prop('checked', false);
+ }
+ });
+ });
};
/**
* Remove icon class from elements that are themed as buttons or dropbuttons.
*/
-Drupal.behaviors.viewsRemoveIconClass = {
- attach: function (context) {
- $(context).find('.dropbutton').once('dropbutton-icon', function () {
- $(this).find('.icon').removeClass('icon');
- });
- }
+Drupal.behaviors.viewsRemoveIconClass = {};
+Drupal.behaviors.viewsRemoveIconClass.attach = function (context, settings) {
+
+ "use strict";
+
+ jQuery(context).find('.dropbutton').once('dropbutton-icon', function () {
+ jQuery(this).find('.icon').removeClass('icon');
+ });
};
/**
* Change "Expose filter" buttons into checkboxes.
*/
-Drupal.behaviors.viewsUiCheckboxify = {
- attach: function (context, settings) {
- var $buttons = $('#edit-options-expose-button-button, #edit-options-group-button-button').once('views-ui-checkboxify');
- var length = $buttons.length;
- var i;
- for (i = 0; i < length; i++) {
- new Drupal.viewsUi.Checkboxifier($buttons[i]);
- }
+Drupal.behaviors.viewsUiCheckboxify = {};
+Drupal.behaviors.viewsUiCheckboxify.attach = function (context, settings) {
+
+ "use strict";
+
+ var $ = jQuery;
+ var $buttons = $('#edit-options-expose-button-button, #edit-options-group-button-button').once('views-ui-checkboxify');
+ var length = $buttons.length;
+ var i;
+ for (i = 0; i < length; i++) {
+ new Drupal.viewsUi.Checkboxifier($buttons[i]);
}
};
@@ -813,26 +909,30 @@ Drupal.behaviors.viewsUiCheckboxify = {
* Change the default widget to select the default group according to the
* selected widget for the exposed group.
*/
-Drupal.behaviors.viewsUiChangeDefaultWidget = {
- attach: function () {
- function changeDefaultWidget (event) {
- if ($(event.target).prop('checked')) {
- $('input.default-radios').hide();
- $('td.any-default-radios-row').parent().hide();
- $('input.default-checkboxes').show();
- }
- else {
- $('input.default-checkboxes').hide();
- $('td.any-default-radios-row').parent().show();
- $('input.default-radios').show();
- }
+Drupal.behaviors.viewsUiChangeDefaultWidget = {};
+Drupal.behaviors.viewsUiChangeDefaultWidget.attach = function (context, settings) {
+
+ "use strict";
+
+ var $ = jQuery;
+ function change_default_widget(multiple) {
+ if (multiple) {
+ $('input.default-radios').hide();
+ $('td.any-default-radios-row').parent().hide();
+ $('input.default-checkboxes').show();
+ }
+ else {
+ $('input.default-checkboxes').hide();
+ $('td.any-default-radios-row').parent().show();
+ $('input.default-radios').show();
}
- // Update on widget change.
- $('input[name="options[group_info][multiple]"]')
- .on('change', changeDefaultWidget)
- // Update the first time the form is rendered.
- .trigger('change');
}
+ // Update on widget change.
+ $('input[name="options[group_info][multiple]"]').change(function() {
+ change_default_widget($(this).attr("checked"));
+ });
+ // Update the first time the form is rendered.
+ $('input[name="options[group_info][multiple]"]').trigger('change');
};
/**
@@ -842,6 +942,10 @@ Drupal.behaviors.viewsUiChangeDefaultWidget = {
* The DOM object representing the button to be checkboxified.
*/
Drupal.viewsUi.Checkboxifier = function (button) {
+
+ "use strict";
+
+ var $ = jQuery;
this.$button = $(button);
this.$parent = this.$button.parent('div.views-expose, div.views-grouped');
this.$input = this.$parent.find('input:checkbox, input:radio');
@@ -857,6 +961,9 @@ Drupal.viewsUi.Checkboxifier = function (button) {
* When the checkbox is checked or unchecked, simulate a button press.
*/
Drupal.viewsUi.Checkboxifier.prototype.clickHandler = function (e) {
+
+ "use strict";
+
this.$button.mousedown();
this.$button.submit();
};
@@ -864,48 +971,52 @@ Drupal.viewsUi.Checkboxifier.prototype.clickHandler = function (e) {
/**
* Change the Apply button text based upon the override select state.
*/
-Drupal.behaviors.viewsUiOverrideSelect = {
- attach: function (context) {
- $(context).find('#edit-override-dropdown').once('views-ui-override-button-text', function () {
- // Closures! :(
- var $submit = $('#edit-submit');
- var old_value = $submit.val();
-
- $submit.once('views-ui-override-button-text')
- .on('mouseup', function () {
- $(this).val(old_value);
- return true;
- });
-
- $(this).on('change', function () {
- var $this = $(this);
- if ($this.val() === 'default') {
- $submit.val(Drupal.t('Apply (all displays)'));
- }
- else if ($this.val() === 'default_revert') {
- $submit.val(Drupal.t('Revert to default'));
- }
- else {
- $submit.val(Drupal.t('Apply (this display)'));
- }
- })
- .trigger('change');
- });
+Drupal.behaviors.viewsUiOverrideSelect = {};
+Drupal.behaviors.viewsUiOverrideSelect.attach = function (context, settings) {
+
+ "use strict";
+
+ var $ = jQuery;
+ $('#edit-override-dropdown', context).once('views-ui-override-button-text', function() {
+ // Closures! :(
+ var $submit = $('#edit-submit', context);
+ var old_value = $submit.val();
+
+ $submit.once('views-ui-override-button-text')
+ .bind('mouseup', function() {
+ $(this).val(old_value);
+ return true;
+ });
+
+ $(this).bind('change', function() {
+ if ($(this).val() === 'default') {
+ $submit.val(Drupal.t('Apply (all displays)'));
+ }
+ else if ($(this).val() === 'default_revert') {
+ $submit.val(Drupal.t('Revert to default'));
+ }
+ else {
+ $submit.val(Drupal.t('Apply (this display)'));
+ }
+ })
+ .trigger('change');
+ });
- }
};
Drupal.viewsUi.resizeModal = function (e, no_shrink) {
+
+ "use strict";
+
+ var $ = jQuery;
var $modal = $('.views-ui-dialog');
- var $window = $(window);
- var windowWidth = $window.width();
- var $scroll = $modal.find('.scroll');
+ var $scroll = $('.scroll', $modal);
if ($modal.size() === 0 || $modal.css('display') === 'none') {
return;
}
- var maxWidth = parseInt(windowWidth * 0.85, 10); // 85% of window
- var minWidth = parseInt(windowWidth * 0.6, 10); // 60% of window
+ var maxWidth = parseInt($(window).width() * .85); // 70% of window
+ var minWidth = parseInt($(window).width() * .6); // 70% of window
// Set the modal to the minwidth so that our width calculation of
// children works.
@@ -913,7 +1024,7 @@ Drupal.viewsUi.resizeModal = function (e, no_shrink) {
var width = minWidth;
// Don't let the window get more than 80% of the display high.
- var maxHeight = parseInt($window.height() * 0.8, 10);
+ var maxHeight = parseInt($(window).height() * .8);
var minHeight = 200;
if (no_shrink) {
minHeight = $modal.height();
@@ -928,10 +1039,10 @@ Drupal.viewsUi.resizeModal = function (e, no_shrink) {
// Calculate the height of the 'scroll' region.
var scrollHeight = 0;
- scrollHeight += parseInt($scroll.css('padding-top'), 10);
- scrollHeight += parseInt($scroll.css('padding-bottom'), 10);
+ scrollHeight += parseInt($scroll.css('padding-top'));
+ scrollHeight += parseInt($scroll.css('padding-bottom'));
- $scroll.children().each(function () {
+ $scroll.children().each(function() {
var w = $(this).innerWidth();
if (w > width) {
width = w;
@@ -943,8 +1054,8 @@ Drupal.viewsUi.resizeModal = function (e, no_shrink) {
// will be.
var difference = 0;
- difference += parseInt($scroll.css('padding-top'), 10);
- difference += parseInt($scroll.css('padding-bottom'), 10);
+ difference += parseInt($scroll.css('padding-top'));
+ difference += parseInt($scroll.css('padding-bottom'));
difference += $('.views-override').outerHeight(true);
difference += $('.views-messages').outerHeight(true);
difference += $('#views-ajax-title').outerHeight(true);
@@ -987,29 +1098,34 @@ Drupal.viewsUi.resizeModal = function (e, no_shrink) {
};
-Drupal.behaviors.viewsUiHandlerRemoveLink = {
- attach: function (context) {
- var $context = $(context);
- // Handle handler deletion by looking for the hidden checkbox and hiding the
- // row.
- $context.find('a.views-remove-link').once('views').on('click', function (event) {
- var id = $(this).attr('id').replace('views-remove-link-', '');
- $context.find('#views-row-' + id).hide();
- $context.find('#views-removed-' + id).prop('checked', true);
- event.preventDefault();
- });
+Drupal.behaviors.viewsUiHandlerRemoveLink = {};
+Drupal.behaviors.viewsUiHandlerRemoveLink.attach = function(context) {
+ var $ = jQuery;
+
+ // Handle handler deletion by looking for the hidden checkbox and hiding the
+ // row.
+ $('a.views-remove-link', context).once('views-processed').click(function(event) {
+ var id = $(this).attr('id').replace('views-remove-link-', '');
+ $('#views-row-' + id, context).hide();
+ $('#views-removed-' + id, context).attr('checked', true);
+ event.preventDefault();
+ });
+
+ // Handle display deletion by looking for the hidden checkbox and hiding the
+ // row.
+ $('a.display-remove-link', context).once('display').click(function(event) {
+ var id = $(this).attr('id').replace('display-remove-link-', '');
+ $('#display-row-' + id, context).hide();
+ $('#display-removed-' + id, context).attr('checked', true);
+ event.preventDefault();
+ });
- // Handle display deletion by looking for the hidden checkbox and hiding the
- // row.
- $context.find('a.display-remove-link').once('display').on('click', function (event) {
- var id = $(this).attr('id').replace('display-remove-link-', '');
- $context.find('#display-row-' + id).hide();
- $context.find('#display-removed-' + id).prop('checked', true);
- event.preventDefault();
- });
- }
};
-$(window).on('resize scroll', debounce(Drupal.viewsUi.resizeModal, 100));
+jQuery(function() {
-})(jQuery, Drupal, drupalSettings, Drupal.debounce);
+ "use strict"
+
+ jQuery(window).bind('resize', Drupal.viewsUi.resizeModal);
+ jQuery(window).bind('scroll', Drupal.viewsUi.resizeModal);
+});
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Tests/OverrideDisplaysTest.php b/core/modules/views_ui/lib/Drupal/views_ui/Tests/OverrideDisplaysTest.php
index 1dab1f6..38b3d36 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/Tests/OverrideDisplaysTest.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/Tests/OverrideDisplaysTest.php
@@ -54,7 +54,7 @@ function testOverrideDisplays() {
$this->assertText($original_title);
// Confirm that the view block is available in the block administration UI.
- $this->drupalGet('admin/structure/block/list/' . config('system.theme')->get('default') . '/add');
+ $this->drupalGet('admin/structure/block/list/block_plugin_ui:' . config('system.theme')->get('default') . '/add');
$this->assertText('View: ' . $view['label']);
// Place the block.
@@ -112,7 +112,7 @@ function testWizardMixedDefaultOverriddenDisplays() {
$this->assertNoText($view['block[title]']);
// Confirm that the block is available in the block administration UI.
- $this->drupalGet('admin/structure/block/list/' . config('system.theme')->get('default') . '/add');
+ $this->drupalGet('admin/structure/block/list/block_plugin_ui:' . config('system.theme')->get('default') . '/add');
$this->assertText('View: ' . $view['label']);
// Put the block into the first sidebar region, and make sure it will not
diff --git a/core/modules/views_ui/views_ui.module b/core/modules/views_ui/views_ui.module
index 02ee998..295c805 100644
--- a/core/modules/views_ui/views_ui.module
+++ b/core/modules/views_ui/views_ui.module
@@ -201,7 +201,6 @@ function views_ui_library_info() {
array('system', 'jquery'),
array('system', 'drupal'),
array('system', 'drupalSettings'),
- array('system', 'drupal.debounce'),
array('system', 'jquery.once'),
array('system', 'jquery.form'),
array('system', 'drupal.ajax'),
diff --git a/core/tests/Drupal/Tests/Component/Utility/SortArrayTest.php b/core/tests/Drupal/Tests/Component/Utility/SortArrayTest.php
deleted file mode 100644
index 07a493b..0000000
--- a/core/tests/Drupal/Tests/Component/Utility/SortArrayTest.php
+++ /dev/null
@@ -1,326 +0,0 @@
- 'SortArray test',
- 'description' => 'Test that the SortArray functions work properly.',
- 'group' => 'Common',
- );
- }
-
- /**
- * Tests SortArray::sortByWeightElement() input against expected output.
- *
- * @dataProvider providerSortByWeightElement
- *
- * @param array $a
- * The first input array for the SortArray::sortByWeightElement() method.
- * @param array $b
- * The second input array for the SortArray::sortByWeightElement().
- * @param integer $expected
- * The expected output from calling the method.
- *
- * @see Drupal\Component\Utility\SortArray::sortByWeightElement()
- * @see Drupal\Tests\Component\Utility\SortArrayTest::providersortByWeightElement()
- */
- public function testSortByWeightElement($a, $b, $expected) {
- $result = SortArray::sortByWeightElement($a, $b);
- $this->assertEquals($expected, $result);
- }
-
- /**
- * Data provider for SortArray::sortByWeightElement().
- *
- * @return array
- * An array of tests, matching the parameter inputs for
- * testSortByWeightElement.
- *
- * @see \Drupal\Component\Utility\SortArray::sortByWeightElement()
- * @see \Drupal\Tests\Component\Utility\SortArrayTest::testSortByWeightElement()
- */
- public function providerSortByWeightElement() {
- $tests = array();
-
- // Weights set and equal.
- $tests[] = array(
- array('weight' => 1),
- array('weight' => 1),
- 0
- );
-
- // Weights set and $a is less (lighter) than $b.
- $tests[] = array(
- array('weight' => 1),
- array('weight' => 2),
- -1
- );
-
- // Weights set and $a is greater (heavier) than $b.
- $tests[] = array(
- array('weight' => 2),
- array('weight' => 1),
- 1
- );
-
- // Weights not set.
- $tests[] = array(
- array(),
- array(),
- 0
- );
-
- // Weights for $b not set.
- $tests[] = array(
- array('weight' => 1),
- array(),
- 1
- );
-
- // Weights for $a not set.
- $tests[] = array(
- array(),
- array('weight' => 1),
- -1
- );
-
- return $tests;
- }
-
- /**
- * Tests SortArray::sortByWeightProperty() input against expected output.
- *
- * @dataProvider providerSortByWeightProperty
- *
- * @param array $a
- * The first input array for the SortArray::sortByWeightProperty() method.
- * @param array $b
- * The second input array for the SortArray::sortByWeightProperty().
- * @param integer $expected
- * The expected output from calling the method.
- *
- * @see Drupal\Component\Utility\SortArray::sortByWeightProperty()
- * @see Drupal\Tests\Component\Utility\SortArrayTest::SortByWeightProperty()
- */
- public function testSortByWeightProperty($a, $b, $expected) {
- $result = SortArray::sortByWeightProperty($a, $b);
- $this->assertEquals($expected, $result);
- }
-
- /**
- * Data provider for SortArray::sortByWeightProperty().
- *
- * @return array
- * An array of tests, matching the parameter inputs for
- * testSortByWeightProperty.
- *
- * @see \Drupal\Component\Utility\SortArray::sortByWeightProperty()
- * @see \Drupal\Tests\Component\Utility\SortArrayTest::testSortByWeightProperty()
- */
- public function providerSortByWeightProperty() {
- $tests = array();
-
- // Weights set and equal.
- $tests[] = array(
- array('#weight' => 1),
- array('#weight' => 1),
- 0
- );
-
- // Weights set and $a is less (lighter) than $b.
- $tests[] = array(
- array('#weight' => 1),
- array('#weight' => 2),
- -1
- );
-
- // Weights set and $a is greater (heavier) than $b.
- $tests[] = array(
- array('#weight' => 2),
- array('#weight' => 1),
- 1
- );
-
- // Weights not set.
- $tests[] = array(
- array(),
- array(),
- 0
- );
-
- // Weights for $b not set.
- $tests[] = array(
- array('#weight' => 1),
- array(),
- 1
- );
-
- // Weights for $a not set.
- $tests[] = array(
- array(),
- array('#weight' => 1),
- -1
- );
-
- return $tests;
- }
-
- /**
- * Tests SortArray::sortByTitleElement() input against expected output.
- *
- * @dataProvider providerSortByTitleElement
- *
- * @param array $a
- * The first input item for comparison.
- * @param array $b
- * The second item for comparison.
- * @param integer $expected
- * The expected output from calling the method.
- *
- * @see Drupal\Component\Utility\SortArray::sortByTitleElement()
- * @see Drupal\Tests\Component\Utility\SortArrayTest::providerSortByTitleElement()
- */
- public function testSortByTitleElement($a, $b, $expected) {
- $result = SortArray::sortByTitleElement($a, $b);
- $this->assertEquals($expected, $result);
- }
-
- /**
- * Data provider for SortArray::sortByTitleElement().
- *
- * @return array
- * An array of tests, matching the parameter inputs for
- * testSortByTitleElement.
- *
- * @see \Drupal\Component\Utility\SortArray::sortByTitleElement()
- * @see \Drupal\Tests\Component\Utility\SortArrayTest::testSortByTitleElement()
- */
- public function providerSortByTitleElement() {
- $tests = array();
-
- // Titles set and equal.
- $tests[] = array(
- array('title' => 'test'),
- array('title' => 'test'),
- 0
- );
-
- // Title $a not set.
- $tests[] = array(
- array(),
- array('title' => 'test'),
- -4
- );
-
- // Title $b not set.
- $tests[] = array(
- array('title' => 'test'),
- array(),
- 4
- );
-
- // Titles set but not equal.
- $tests[] = array(
- array('title' => 'test'),
- array('title' => 'testing'),
- -1
- );
-
- // Titles set but not equal.
- $tests[] = array(
- array('title' => 'testing'),
- array('title' => 'test'),
- 1
- );
-
- return $tests;
- }
-
- /**
- * Tests SortArray::sortByTitleProperty() input against expected output.
- *
- * @dataProvider providerSortByTitleProperty
- *
- * @param array $a
- * The first input item for comparison.
- * @param array $b
- * The second item for comparison.
- * @param integer $expected
- * The expected output from calling the method.
- *
- * @see Drupal\Component\Utility\SortArray::sortByTitleProperty()
- * @see Drupal\Tests\Component\Utility\SortArrayTest::SortByTitleProperty()
- */
- public function testSortByTitleProperty($a, $b, $expected) {
- $result = SortArray::sortByTitleProperty($a, $b);
- $this->assertEquals($expected, $result);
- }
-
- /**
- * Data provider for SortArray::sortByTitleProperty().
- *
- * @return array
- * An array of tests, matching the parameter inputs for
- * testSortByTitleProperty.
- *
- * @see \Drupal\Component\Utility\SortArray::sortByTitleProperty()
- * @see \Drupal\Tests\Component\Utility\SortArrayTest::testSortByTitleProperty()
- */
- public function providerSortByTitleProperty() {
- $tests = array();
-
- // Titles set and equal.
- $tests[] = array(
- array('#title' => 'test'),
- array('#title' => 'test'),
- 0
- );
-
- // Title $a not set.
- $tests[] = array(
- array(),
- array('#title' => 'test'),
- -4
- );
-
- // Title $b not set.
- $tests[] = array(
- array('#title' => 'test'),
- array(),
- 4
- );
-
- // Titles set but not equal.
- $tests[] = array(
- array('#title' => 'test'),
- array('#title' => 'testing'),
- -1
- );
-
- // Titles set but not equal.
- $tests[] = array(
- array('#title' => 'testing'),
- array('#title' => 'test'),
- 1
- );
-
- return $tests;
- }
-
-}
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityListControllerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityListControllerTest.php
deleted file mode 100644
index ead80b5..0000000
--- a/core/tests/Drupal/Tests/Core/Entity/EntityListControllerTest.php
+++ /dev/null
@@ -1,148 +0,0 @@
- 'Entity list controller test',
- 'description' => 'Unit test of entity access checking system.',
- 'group' => 'Entity'
- );
- }
-
- /**
- * Entity info used by the test.
- *
- * @var array
- *
- * @see entity_get_info()
- */
- public static $entityInfo = array(
- 'entity_keys' => array(
- 'id' => 'id',
- 'label' => 'label',
- ),
- 'config_prefix' => 'user.role',
- 'class' => 'Drupal\user\Plugin\Core\Entity\Role',
- );
-
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
-
- $this->role = $this
- ->getMockBuilder('Drupal\user\Plugin\Core\Entity\Role')
- ->setConstructorArgs(array('entityInfo' => static::$entityInfo, 'user_role'))
- ->getMock();
-
- // Creates a stub role storage controller and replace the buildOperations()
- // method with an empty version, because buildOperations() relies on hooks.
- $role_storage_controller = $this->getMockBuilder('Drupal\user\RoleStorageController')
- ->disableOriginalConstructor()
- ->getMock();
-
- $module_handler = $this->getMockBuilder('Drupal\Core\Extension\ModuleHandler')
- ->disableOriginalConstructor()
- ->getMock();
-
- $this->entityListController = $this->getMock('Drupal\Core\Entity\EntityListController', array('buildOperations'), array('user_role', static::$entityInfo, $role_storage_controller, $module_handler));
-
- $this->entityListController->expects($this->any())
- ->method('buildOperations')
- ->will($this->returnValue(array()));
-
- }
-
- /**
- * Tests that buildRow() returns a string which has been run through
- * String::checkPlain().
- *
- * @dataProvider providerTestBuildRow
- *
- * @param string $input
- * The entity label being passed into buildRow.
- * @param string $expected
- * The expected output of the label from buildRow.
- * @param string $message
- * The message to provide as output for the test.
- * @param bool $ignorewarnings
- * Whether or not to ignore PHP 5.3+ invalid multibyte sequence warnings.
- *
- * @see \Drupal\Component\Utility\Drupal\Core\Entity\EntityListController::buildRow()
- */
- public function testBuildRow($input, $expected, $message, $ignorewarnings = FALSE) {
- $this->role->expects($this->any())
- ->method('label')
- ->will($this->returnValue($input));
-
- if ($ignorewarnings) {
- $built_row = @$this->entityListController->buildRow($this->role);
- }
- else {
- $built_row = $this->entityListController->buildRow($this->role);
- }
-
- $this->assertEquals($built_row['label'], $expected, $message);
- }
-
- /**
- * Data provider for testBuildRow().
- *
- * @see self::testBuildRow()
- * @see \Drupal\Tests\Component\Utility\StringTest::providerCheckPlain()
- *
- * @return array
- * An array containing a string, the expected return from
- * String::checkPlain, a message to be output for failures, and whether the
- * test should be processed as multibyte.
- */
- public function providerTestBuildRow() {
- $tests = array();
- // Checks that invalid multi-byte sequences are rejected.
- $tests[] = array("Foo\xC0barbaz", '', 'EntityListController::buildRow() rejects invalid sequence "Foo\xC0barbaz"', TRUE);
- $tests[] = array("\xc2\"", '', 'EntityListController::buildRow() rejects invalid sequence "\xc2\""', TRUE);
- $tests[] = array("Fooÿñ", "Fooÿñ", 'EntityListController::buildRow() accepts valid sequence "Fooÿñ"');
-
- // Checks that special characters are escaped.
- $tests[] = array("