diff --git a/core/modules/page/config/page.front_page.yml b/core/modules/page/config/page.front_page.yml new file mode 100644 index 0000000..97f0dda --- /dev/null +++ b/core/modules/page/config/page.front_page.yml @@ -0,0 +1,7 @@ +id: front_page +uuid: 5da81acf-3264-4d91-9b00-b2461c86e974 +label: 'Front page' +visibility: '1' +paths: '' +layout: '1' +langcode: und diff --git a/core/modules/page/config/page.not_admin_page.yml b/core/modules/page/config/page.not_admin_page.yml new file mode 100644 index 0000000..89e9dc9 --- /dev/null +++ b/core/modules/page/config/page.not_admin_page.yml @@ -0,0 +1,7 @@ +id: not_admin_page +uuid: 45e82840-d11b-4726-8d09-9be84a69457d +label: 'Not admin page' +visibility: '0' +paths: "admin\r\nadmin/*" +layout: '2' +langcode: und diff --git a/core/modules/page/config/page.user_page.yml b/core/modules/page/config/page.user_page.yml new file mode 100644 index 0000000..643a916 --- /dev/null +++ b/core/modules/page/config/page.user_page.yml @@ -0,0 +1,7 @@ +id: user_page +uuid: ccd213ff-54d4-4f3a-9a00-f8406842dff0 +label: 'User page' +visibility: '1' +paths: "user\r\nuser/*" +layout: '0' +langcode: und diff --git a/core/modules/page/lib/Drupal/page/Page.php b/core/modules/page/lib/Drupal/page/Page.php new file mode 100644 index 0000000..21a71e3 --- /dev/null +++ b/core/modules/page/lib/Drupal/page/Page.php @@ -0,0 +1,59 @@ + 'textfield', + '#title' => t('Label'), + '#maxlength' => 255, + '#default_value' => $page->label(), + '#description' => t("Example: 'Front page' or 'Section page'."), + '#required' => TRUE, + ); + $form['id'] = array( + '#type' => 'machine_name', + '#default_value' => $page->id(), + '#machine_name' => array( + 'exists' => 'page_load', + 'source' => array('label'), + ), + '#disabled' => (bool) $page->id(), + ); + + // @todo make this actually rely on layouts from the patch at + // http://drupal.org/node/1787846 when committed. + $form['layout'] = array( + '#type' => 'select', + '#title' => t('Layout for this page'), + '#default_value' => isset($page->layout) ? $page->layout : 'foo', + '#options' => array('foo', 'bar', 'baz'), + ); + + // @todo this would ideally be pluggable and depend on general conditions + // and all, however, these are not yet abstracted. + $options = array( + 0 => t('All pages except those listed'), + 1 => t('Only the listed pages'), + ); + $description = t("Enter one path per line. The '*' character is a wildcard. Example paths are %user for the current user's page and %user-wildcard for every user page. %front is the front page.", array('%user' => 'user', '%user-wildcard' => 'user/*', '%front' => '')); + $form['visibility'] = array( + '#type' => 'radios', + '#title' => t('Apply to specific paths'), + '#options' => $options, + '#default_value' => isset($page->visibility) ? $page->visibility : 0, + ); + $form['paths'] = array( + '#type' => 'textarea', + '#title' => '' . t('Paths') . '', + '#default_value' => isset($page->paths) ? $page->paths : '', + '#description' => $description, + ); + + return parent::form($form, $form_state, $page); + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::actions(). + */ + protected function actions(array $form, array &$form_state) { + // Only includes a Save action for the entity, no direct Delete button. + return array( + 'submit' => array( + '#value' => t('Save'), + '#validate' => array( + array($this, 'validate'), + ), + '#submit' => array( + array($this, 'submit'), + array($this, 'save'), + ), + ), + ); + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::save(). + */ + public function save(array $form, array &$form_state) { + $page = $this->getEntity($form_state); + $page->save(); + + watchdog('page', 'Page @label saved.', array('@label' => $page->label()), WATCHDOG_NOTICE); + drupal_set_message(t('Page %label saved.', array('%label' => $page->label()))); + + $form_state['redirect'] = 'admin/structure/pages'; + } + +} + diff --git a/core/modules/page/lib/Drupal/page/PageListController.php b/core/modules/page/lib/Drupal/page/PageListController.php new file mode 100644 index 0000000..e9b3dde --- /dev/null +++ b/core/modules/page/lib/Drupal/page/PageListController.php @@ -0,0 +1,51 @@ +label(); + $row['paths'] = nl2br(check_plain($entity->paths)); + $operations = $this->buildOperations($entity); + $row['operations']['data'] = $operations; + return $row; + } + +} diff --git a/core/modules/page/page.admin.inc b/core/modules/page/page.admin.inc new file mode 100644 index 0000000..16c4d86 --- /dev/null +++ b/core/modules/page/page.admin.inc @@ -0,0 +1,67 @@ +render(); +} + +/** + * Page callback: Presents the page editing form. + * + * @see page_menu() + */ +function page_page_edit(Page $page) { + drupal_set_title(t('Edit page @label', array('@label' => $page->label())), PASS_THROUGH); + return entity_get_form($page); +} + +/** + * Page callback: Provides the new page addition form. + * + * @see page_menu() + */ +function page_page_add() { + $page = entity_create('page', array()); + return entity_get_form($page); +} + +/** + * Page callback: Form constructor for page deletion confirmation form. + * + * @see page_menu() + */ +function page_delete_confirm($form, &$form_state, Page $page) { + // Always provide entity id in the same form key as in the entity edit form. + $form['id'] = array('#type' => 'value', '#value' => $page->id()); + $form_state['page'] = $page; + return confirm_form($form, + t('Are you sure you want to remove the page %title?', array('%title' => $page->label())), + 'admin/structure/pages', + t('This action cannot be undone.'), + t('Delete'), + t('Cancel') + ); +} + +/** + * Form submission handler for page_delete_confirm(). + */ +function page_delete_confirm_submit($form, &$form_state) { + $page = $form_state['page']; + $page->delete(); + drupal_set_message(t('Page %label has been deleted.', array('%label' => $page->label()))); + watchdog('page', 'Page %label has been deleted.', array('%label' => $page->label()), WATCHDOG_NOTICE); + $form_state['redirect'] = 'admin/structure/pages'; +} diff --git a/core/modules/page/page.info b/core/modules/page/page.info new file mode 100644 index 0000000..ecf60f4 --- /dev/null +++ b/core/modules/page/page.info @@ -0,0 +1,7 @@ +name = Page +description = Makes it possible to swap different page layouts. +package = Core +version = VERSION +core = 8.x +dependencies[] = config +configure = admin/structure/pages diff --git a/core/modules/page/page.module b/core/modules/page/page.module new file mode 100644 index 0000000..81db1cf --- /dev/null +++ b/core/modules/page/page.module @@ -0,0 +1,159 @@ + 'Page library', + 'description' => 'Manage pages using layouts that allow content to be placed.', + 'page callback' => 'page_page_list', + 'access callback' => 'user_access', + 'access arguments' => array('administer pages'), + 'file' => 'page.admin.inc', + ); + $items['admin/structure/pages/add'] = array( + 'title' => 'Add page', + 'page callback' => 'page_page_add', + 'access callback' => 'user_access', + 'access arguments' => array('administer pages'), + 'type' => MENU_LOCAL_ACTION, + 'file' => 'page.admin.inc', + ); + $items['admin/structure/pages/page/%page/edit'] = array( + 'title' => 'Edit page', + 'page callback' => 'page_page_edit', + 'page arguments' => array(4), + 'access callback' => 'user_access', + 'access arguments' => array('administer pages'), + 'type' => MENU_CALLBACK, + 'file' => 'page.admin.inc', + ); + $items['admin/structure/pages/page/%page/delete'] = array( + 'title' => 'Delete', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('page_delete_confirm', 4), + 'access callback' => 'user_access', + 'access arguments' => array('administer pages'), + 'type' => MENU_CALLBACK, + 'file' => 'page.admin.inc', + ); + return $items; +} + +/** + * Implements hook_permission(). + */ +function page_permission() { + return array( + 'administer pages' => array( + 'title' => t('Administer pages'), + 'description' => t('Manage the set of pages with distinct layouts on the site.'), + ), + ); +} + +/** + * @todo remove this in favor of actually integrating with layout mappers. + */ +function page_init() { + if ($page = page_get_matched_page()) { + drupal_set_message(t('%page matched', array('%page' => $page->label()))); + } +} + +/** + * API function to look up if the current page is matched by a config. + * + * @return Drupal\page\Page|FALSE + */ +function page_get_matched_page() { + $pages = page_load_all(); + $page_match = FALSE; + foreach ($pages as $page) { + if (!empty($page->paths)) { + // Convert paths to lowercase. This allows comparison of the same path + // with different case. Ex: /Page, /page, /PAGE. + $paths = drupal_strtolower($page->paths); + // Compare the lowercase path alias (if any) and internal path. + $path = current_path(); + $path_alias = drupal_strtolower(drupal_get_path_alias($path)); + $page_match = drupal_match_path($path_alias, $paths) || (($path != $path_alias) && drupal_match_path($path, $paths)); + // When $page->visibility has a value of 0, the page is used on all + // paths except those listed in $page->paths. When set to 1, it is + // used only on those pages listed in $page->paths. + $page_match = !($page->visibility xor $page_match); + if ($page_match) { + break; + } + } + } + return $page_match ? $page : FALSE; +} + +/** + * Implements hook_entity_info(). + */ +function page_entity_info() { + $types['page'] = array( + 'label' => 'Page', + 'entity class' => 'Drupal\page\Page', + 'controller class' => 'Drupal\Core\Config\Entity\ConfigStorageController', + 'form controller class' => array( + 'default' => 'Drupal\page\PageFormController', + ), + 'list controller class' => 'Drupal\page\PageListController', + 'list path' => 'admin/structure/pages', + 'uri callback' => 'page_uri', + 'config prefix' => 'page', + 'entity keys' => array( + 'id' => 'id', + 'label' => 'label', + 'uuid' => 'uuid', + ), + ); + return $types; +} + +/** + * Entity URI callback. + * + * @param Drupal\page\Page $page + * Page configuration entity instance. + * + * @return array + * Entity URI information. + */ +function page_uri(Page $page) { + return array( + 'path' => 'admin/structure/pages/page/' . $page->id(), + ); +} + +/** + * Load one page object by its identifier. + * + * @return Drupal\page\Page + * Page configuration entity instance. + */ +function page_load($id) { + return entity_load('page', $id); +} + +/** + * Load all page objects. + * + * @return array + * List of Drupal\page\Page instances keyed by id. + */ +function page_load_all() { + return entity_load_multiple('page'); +}