diff --git a/core/modules/layout/layout.admin.css b/core/modules/layout/layout.admin.css
new file mode 100644
index 0000000000000000000000000000000000000000..6e38bf48d8af47ab2798e4cb8d8f9ac423de6e26
--- /dev/null
+++ b/core/modules/layout/layout.admin.css
@@ -0,0 +1,17 @@
+.layout-display {
+ background: rgb(224, 224, 224);
+}
+
+.layout-region-demonstration {
+ background-image: -moz-linear-gradient(bottom, rgb(70,70,71) 40%, rgb(91,91,94) 70%, rgb(125,124,125) 88%);
+ background-image: -o-linear-gradient(bottom, rgb(70,70,71) 40%, rgb(91,91,94) 70%, rgb(125,124,125) 88%);
+ background-image: -ms-linear-gradient(bottom, rgb(70,70,71) 40%, rgb(91,91,94) 70%, rgb(125,124,125) 88%);
+ background-image: -webkit-linear-gradient(bottom, rgb(70,70,71) 40%, rgb(91,91,94) 70%, rgb(125,124,125) 88%);
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.4, rgb(70,70,71)), color-stop(0.7, rgb(91,91,94)), color-stop(0.88, rgb(125,124,125)));
+ background-image: linear-gradient(bottom, rgb(70,70,71) 40%, rgb(91,91,94) 70%, rgb(125,124,125) 88%);
+ color: white;
+ font-size: 0.8em;
+ margin: 3px;
+ padding: 10px;
+ text-transform: uppercase;
+}
diff --git a/core/modules/layout/layout.admin.inc b/core/modules/layout/layout.admin.inc
new file mode 100644
index 0000000000000000000000000000000000000000..9a1a9213d72068bfce85f081ac04faf0c80bcee3
--- /dev/null
+++ b/core/modules/layout/layout.admin.inc
@@ -0,0 +1,75 @@
+getDefinitions();
+
+ $rows = array();
+ $header = array(t('Name'), t('Source'));
+ foreach ($layouts as $name => $layout) {
+ $provider_info = system_get_info($layout['provider']['type'], $layout['provider']['provider']);
+
+ // Build table columns for this row.
+ $row = array();
+ $row['name'] = l($layout['title'], 'admin/structure/templates/manage/' . $name);
+ // Type can either be 'module' or 'theme'.
+ $row['provider'] = t('@name @type', array('@name' => $provider_info['name'], '@type' => t($layout['provider']['type'])));
+
+ $rows[] = $row;
+ }
+
+ $build = array();
+ $build['table'] = array(
+ '#theme' => 'table',
+ '#header' => $header,
+ '#rows' => $rows,
+ );
+ return $build;
+
+ // Ensure the provider types are translatable. These do not need to run,
+ // just inform the static code parser of these source strings.
+ t('module');
+ t('theme');
+}
+
+/**
+ * Page callback: Demonstrates a layout template.
+ *
+ * @param string $key
+ * The key of the page layout being requested.
+ *
+ * @return array
+ * An array as expected by drupal_render().
+ *
+ * @see layout_menu()
+ */
+function layout_page_view($key) {
+ $layout = layout_manager()->getDefinition($key);
+ drupal_set_title(t('View template %name', array('%name' => $layout['title'])), PASS_THROUGH);
+
+ // Render the layout in an admin context with region demonstrations.
+ $instance = layout_manager()->createInstance($key, array());
+ $regions = $instance->getRegions();
+ foreach ($regions as $region => $info) {
+ $regions[$region] = '
' . check_plain($info['label']) . '
';
+ }
+ $build['demonstration'] = array(
+ '#type' => 'markup',
+ '#markup' => $instance->renderLayout(TRUE, $regions),
+ );
+ $build['#attached']['css'][] = drupal_get_path('module', 'layout') . '/layout.admin.css';
+ return $build;
+}
diff --git a/core/modules/layout/layout.module b/core/modules/layout/layout.module
index 7d8279826c956bb64be345832fa1f0281bba6f75..c6ed7ae5612d76c987eebb4aadd5c95c7790e344 100644
--- a/core/modules/layout/layout.module
+++ b/core/modules/layout/layout.module
@@ -5,6 +5,55 @@
* Manages page layouts for content presentation.
*/
+/**
+ * Implements hook_menu().
+ */
+function layout_menu() {
+ $items['admin/structure/templates'] = array(
+ 'title' => 'Templates',
+ 'description' => 'Overview of the list of layout templates available.',
+ 'page callback' => 'layout_page_list',
+ 'access callback' => 'user_access',
+ 'access arguments' => array('administer layouts'),
+ 'file' => 'layout.admin.inc',
+ );
+ $items['admin/structure/templates/manage/%'] = array(
+ 'title' => 'View template',
+ 'page callback' => 'layout_page_view',
+ 'page arguments' => array(4),
+ 'access callback' => 'layout_user_access',
+ 'access arguments' => array(4),
+ 'file' => 'layout.admin.inc',
+ );
+ return $items;
+}
+
+/**
+ * Access callback: Checks the existence of a layout.
+ *
+ * @param string $key
+ * The key of the page layout being requested.
+ *
+ * @return bool
+ * TRUE if the current user can access page layout menu items; FALSE
+ * otherwise.
+ */
+function layout_user_access($key) {
+ return (user_access('administer layouts') && layout_manager()->getDefinition($key));
+}
+
+/**
+ * Implements hook_permission().
+ */
+function layout_permission() {
+ return array(
+ 'administer layouts' => array(
+ 'title' => t('Administer templates'),
+ 'description' => t('Access administration functions for templates.'),
+ ),
+ );
+}
+
/**
* Get the layout plugin manager instance.
*
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/Derivative/Layout.php b/core/modules/layout/lib/Drupal/layout/Plugin/Derivative/Layout.php
index ce82c655a3113124b22ebe57751870e7d09da5a1..a6c4ea947dfe5b077aaa055b034e76c3defc54fc 100644
--- a/core/modules/layout/lib/Drupal/layout/Plugin/Derivative/Layout.php
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/Derivative/Layout.php
@@ -106,6 +106,7 @@ protected function iterateDirectories($dir, $provider) {
$this->derivatives[$key] = $directory->read($fileinfo->getBasename('.yml'));
$this->derivatives[$key]['theme'] = $key;
$this->derivatives[$key]['path'] = $fileinfo->getPath();
+ $this->derivatives[$key]['provider'] = $provider;
// If the layout author didn't specify a template name, assume the same
// name as the yml file.
if (!isset($this->derivatives[$key]['template'])) {
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/LayoutInterface.php b/core/modules/layout/lib/Drupal/layout/Plugin/LayoutInterface.php
index 7521c57f9c3f6821b25862cfc4b96cf26ea6162d..829f3c204105c507ddb94d421acf3849f1b4bcb6 100644
--- a/core/modules/layout/lib/Drupal/layout/Plugin/LayoutInterface.php
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/LayoutInterface.php
@@ -18,15 +18,25 @@ interface LayoutInterface extends PluginInspectionInterface {
* Returns a list of regions.
*
* @return array
- * An array of region machine names.
+ * An associative array of region information keyed by region machine
+ * names. Each region information element is a two item associative array
+ * with a 'label' and a 'type' key designating the human readable label
+ * and the type of the region.
*/
public function getRegions();
/**
* Renders layout and returns the rendered markup.
*
+ * @param bool $admin
+ * (optional) TRUE if the rendered layout is displayed in an administrative
+ * context, FALSE otherwise. Defaults to FALSE.
+ * @param array $regions
+ * (optional) An array of region render arrays keyed by region machine
+ * names. Defaults to array.
+ *
* @return string
* Rendered HTML output from the layout.
*/
- public function renderLayout();
+ public function renderLayout($admin = FALSE, $regions = array());
}
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php b/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php
index 3ded37918d1ba9a9acbb0c1a8b58e6caadfb5636..f3f6762ed315adf762adc8933b596f45c2862a4d 100644
--- a/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php
@@ -78,7 +78,7 @@ public function getAdminScriptFiles() {
/**
* Implements Drupal\layout\Plugin\LayoutInterface::renderLayout().
*/
- public function renderLayout($admin = FALSE) {
+ public function renderLayout($admin = FALSE, $regions = array()) {
$definition = $this->getDefinition();
// Assemble a render array with the regions and attached CSS/JS.
@@ -89,10 +89,8 @@ public function renderLayout($admin = FALSE) {
// Render all regions needed for this layout.
foreach ($this->getRegions() as $region => $info) {
- // @todo This is just stub code to fill in regions with stuff for now.
- // When blocks are related to layouts and not themes, we can make this
- // really be filled in with blocks.
- $build['#content'][$region] = '' . $info['label'] . '
';
+ // Initialize regions which were not provided as empty.
+ $build['#content'][$region] = empty($regions[$region]) ? '' : $regions[$region];
}
// Fill in attached CSS and JS files based on metadata.
diff --git a/core/modules/layout/lib/Drupal/layout/Tests/LayoutDerivativesTest.php b/core/modules/layout/lib/Drupal/layout/Tests/LayoutDerivativesTest.php
index 0766838d3e7fda4ca6af826e37ce239772cb5caf..f41460cb2ffd0452cf279d463aea844faecbed27 100644
--- a/core/modules/layout/lib/Drupal/layout/Tests/LayoutDerivativesTest.php
+++ b/core/modules/layout/lib/Drupal/layout/Tests/LayoutDerivativesTest.php
@@ -52,7 +52,7 @@ function testDerivatives() {
// Render the layout and look at whether expected region names and classes
// were in the output.
- $render = $layout->renderLayout();
+ $render = $this->renderLayoutDemonstration($layout);
$this->drupalSetContent($render);
$this->assertText('Middle column');
$this->assertRaw('class="layout-display layout-one-col');
@@ -68,13 +68,32 @@ function testDerivatives() {
// Render the layout and look at whether expected region names and classes
// were in the output.
- $render = $layout->renderLayout();
+ $render = $this->renderLayoutDemonstration($layout);
$this->drupalSetContent($render);
$this->assertText('Left side');
$this->assertText('Right side');
$this->assertRaw('');
}
+ /**
+ * Renders the layout with sample region content.
+ *
+ * @param \Drupal\layout\Plugin\LayoutInterface $layout
+ * The layout to be rendered.
+ *
+ * @return string
+ * Rendered HTML output from the layout.
+ */
+ function renderLayoutDemonstration($layout) {
+ // Add sample content in the regions that is looked for in the tests.
+ $regions = $layout->getRegions();
+ foreach ($regions as $region => $info) {
+ $regions[$region] = '
' . $info['label'] . '
';
+ }
+
+ return $layout->renderLayout(FALSE, $regions);
+ }
+
/**
* Test layout functionality as applies to pages.
*/
diff --git a/core/modules/layout/tests/layout_test.module b/core/modules/layout/tests/layout_test.module
index b9eb63be451d381bc05b9f594d1fe9820637f7b1..74de123e905c04c703b41f660e7dad17ff3e5890 100644
--- a/core/modules/layout/tests/layout_test.module
+++ b/core/modules/layout/tests/layout_test.module
@@ -27,11 +27,19 @@ function layout_test_page() {
global $theme;
$theme = 'layout_test_theme';
theme_enable(array($theme));
+
$display = entity_load('display', 'test_twocol');
$layout = $display->getLayoutInstance();
+
// @todo This tests that the layout can render its regions, but does not test
// block rendering: http://drupal.org/node/1812720.
- return $layout->renderLayout();
+ // Add sample content in the regions that is looked for in the tests.
+ $regions = $layout->getRegions();
+ foreach ($regions as $region => $info) {
+ $regions[$region] = '' . $info['label'] . '
';
+ }
+
+ return $layout->renderLayout(FALSE, $regions);
}
/**