diff --git a/core/modules/responsive_preview/lib/Drupal/responsive_preview/Plugin/Core/Entity/Device.php b/core/modules/responsive_preview/lib/Drupal/responsive_preview/Plugin/Core/Entity/Device.php new file mode 100644 index 0000000..c641da3 --- /dev/null +++ b/core/modules/responsive_preview/lib/Drupal/responsive_preview/Plugin/Core/Entity/Device.php @@ -0,0 +1,96 @@ + 'admin/config/content/responsive_preview/manage/' . $this->id(), + 'options' => array( + 'entity_type' => $this->entityType, + 'entity' => $this, + ), + ); + } + +} diff --git a/core/modules/responsive_preview/lib/Drupal/responsive_preview/DeviceFormController.php b/core/modules/responsive_preview/lib/Drupal/responsive_preview/DeviceFormController.php new file mode 100644 index 0000000..b2badea --- /dev/null +++ b/core/modules/responsive_preview/lib/Drupal/responsive_preview/DeviceFormController.php @@ -0,0 +1,118 @@ +entity; + $form['label'] = array( + '#type' => 'textfield', + '#title' => t('Device name'), + '#default_value' => $entity->label(), + '#size' => 30, + '#required' => TRUE, + '#maxlength' => 64, + '#description' => t('The name for this device. Example: "Small", "Medium", "HTC One", "Google Glass", "Smart TV".'), + ); + $form['id'] = array( + '#type' => 'machine_name', + '#default_value' => $entity->id(), + '#required' => TRUE, + '#disabled' => !$entity->isNew(), + '#size' => 30, + '#maxlength' => 64, + '#machine_name' => array( + 'exists' => 'responsive_preview_device_load', + ), + ); + $dimensions = $entity->get('dimensions'); + $form['dimensions'] = array( + '#type' => 'details', + '#title' => t('Dimensions'), + '#tree' => TRUE, + ); + $form['dimensions']['width'] = array( + '#type' => 'textfield', + '#title' => t('Width'), + '#default_value' => $dimensions['width'], + '#field_suffix' => 'px', + '#size' => 6, + '#required' => TRUE, + ); + $form['dimensions']['height'] = array( + '#type' => 'textfield', + '#title' => t('Height'), + '#default_value' => $dimensions['height'], + '#field_suffix' => 'px', + '#size' => 6, + '#required' => TRUE, + ); + $form['dimensions']['dppx'] = array( + '#type' => 'textfield', + '#title' => t('Dots per pixel (dppx)'), + '#default_value' => $dimensions['dppx'], + '#size' => 4, + '#required' => TRUE, + ); + $form['orientation'] = array( + '#type' => 'select', + '#title' => t('Default orientation'), + '#default_value' => $entity->get('orientation'), + '#options' => array('portrait' => t('Portrait'), 'landscape' => t('Landscape')), + ); + $form['status'] = array( + '#type' => 'checkbox', + '#title' => t('Show in preview list'), + '#default_value' => $entity->get('status'), + ); + $form['weight'] = array( + '#type' => 'value', + '#value' => $entity->get('weight'), + ); + + return parent::form($form, $form_state, $entity); + } + + /** + * {@inheritdoc} + */ + public function save(array $form, array &$form_state) { + $entity = $this->entity; + + // Prevent leading and trailing spaces in device names. + $entity->set('label', trim($entity->label())); + $uri = $entity->uri(); + if ($entity->save() == SAVED_UPDATED) { + drupal_set_message(t('Device %label has been updated.', array('%label' => $entity->label()))); + watchdog('responsive_preview', 'Device %label has been updated.', array('%label' => $entity->label()), WATCHDOG_NOTICE, l(t('Edit'), $uri['path'])); + } + else { + drupal_set_message(t('Device %label has been added.', array('%label' => $entity->label()))); + watchdog('responsive_preview', 'Device %label has been added.', array('%label' => $entity->label()), WATCHDOG_NOTICE, l(t('Edit'), $uri['path'])); + } + $form_state['redirect'] = 'admin/config/content/responsive_preview'; + } + + /** + * {@inheritdoc} + */ + public function delete(array $form, array &$form_state) { + $form_state['redirect'] = 'admin/config/content/responsive_preview/manage/' . $this->entity->id() . '/delete'; + } + +} diff --git a/core/modules/responsive_preview/lib/Drupal/responsive_preview/DeviceInterface.php b/core/modules/responsive_preview/lib/Drupal/responsive_preview/DeviceInterface.php new file mode 100644 index 0000000..7b01572 --- /dev/null +++ b/core/modules/responsive_preview/lib/Drupal/responsive_preview/DeviceInterface.php @@ -0,0 +1,17 @@ + check_plain($row['label']), + ); + $dimensions = $entity->get('dimensions'); + $row['dimensions'] = array( + '#markup' => check_plain($dimensions['width'] . 'x' . $dimensions['height'] . ' (' . $dimensions['dppx'] . ' dppx)'), + ); + $row['orientation'] = array( + '#markup' => $entity->get('orientation') == 'landscape' ? t('Landscape') : t('Portrait'), + ); + $row['status'] = array( + '#markup' => $entity->get('status') ? t('yes') : t('no'), + ); + $row['#weight'] = $entity->get('weight'); + // Add weight column. + $row['weight'] = array( + '#type' => 'weight', + '#title' => t('Weight for @title', array('@title' => $entity->label())), + '#title_display' => 'invisible', + '#default_value' => $entity->get('weight'), + '#attributes' => array('class' => array('weight')), + ); + $row['operations'] = $operations; + return $row; + } + + /** + * {@inheritdoc} + */ + public function render() { + return drupal_get_form($this); + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state) { + $form['entities'] = array( + '#type' => 'table', + '#header' => $this->buildHeader(), + '#empty' => t('There is no @label yet.', array('@label' => $this->entityInfo['label'])), + '#tabledrag' => array( + array('order', 'sibling', 'weight'), + ), + ); + + foreach ($this->load() as $entity) { + $form['entities'][$entity->id()] = $this->buildRow($entity); + } + + $form['actions']['#type'] = 'actions'; + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Save order'), + '#button_type' => 'primary', + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) { + // No validation. + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + $values = $form_state['values']['entities']; + + $entities = entity_load_multiple($this->entityType, array_keys($values)); + foreach ($values as $id => $value) { + if (isset($entities[$id]) && $value['weight'] != $entities[$id]->get('weight')) { + // Update changed weight. + $entities[$id]->set('weight', $value['weight']); + $entities[$id]->save(); + } + } + + drupal_set_message(t('The device settings have been updated.')); + } +} diff --git a/core/modules/responsive_preview/lib/Drupal/responsive_preview/Form/DeviceDelete.php b/core/modules/responsive_preview/lib/Drupal/responsive_preview/Form/DeviceDelete.php new file mode 100644 index 0000000..0413b09 --- /dev/null +++ b/core/modules/responsive_preview/lib/Drupal/responsive_preview/Form/DeviceDelete.php @@ -0,0 +1,73 @@ + $this->device->label())); + } + + /** + * {@inheritdoc} + */ + protected function getCancelPath() { + return 'admin/config/content/responsive_preview'; + } + + /** + * {@inheritdoc} + */ + protected function getConfirmText() { + return t('Delete'); + } + + /** + * {@inheritdoc} + * @param \Drupal\responsive_preview\DeviceInterface $device + * The device being deleted. + */ + public function buildForm(array $form, array &$form_state, DeviceInterface $device = NULL) { + $this->device = $device; + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + $this->device->delete(); + watchdog('responsive_preview', 'Device %name has been deleted.', array('%name' => $this->device->label())); + drupal_set_message(t('Device %name has been deleted.', array('%name' => $this->device->label()))); + $form_state['redirect'] = 'admin/config/content/responsive_preview'; + } + +} diff --git a/core/modules/responsive_preview/config/responsive_preview.device.desktop.yml b/core/modules/responsive_preview/config/responsive_preview.device.desktop.yml new file mode 100644 index 0000000..14e5ba9 --- /dev/null +++ b/core/modules/responsive_preview/config/responsive_preview.device.desktop.yml @@ -0,0 +1,10 @@ +id: desktop +label: Typical desktop +dimensions: + width: 1366 + height: 768 + dppx: 1 +orientation: landscape +weight: 5 +status: 1 +langcode: en diff --git a/core/modules/responsive_preview/config/responsive_preview.device.ipad.yml b/core/modules/responsive_preview/config/responsive_preview.device.ipad.yml new file mode 100644 index 0000000..c14ecac --- /dev/null +++ b/core/modules/responsive_preview/config/responsive_preview.device.ipad.yml @@ -0,0 +1,10 @@ +id: ipad +label: iPad +dimensions: + width: 1536 + height: 2048 + dppx: 2 +orientation: portrait +weight: 2 +status: 1 +langcode: en diff --git a/core/modules/responsive_preview/config/responsive_preview.device.iphone4.yml b/core/modules/responsive_preview/config/responsive_preview.device.iphone4.yml new file mode 100644 index 0000000..c57d380 --- /dev/null +++ b/core/modules/responsive_preview/config/responsive_preview.device.iphone4.yml @@ -0,0 +1,10 @@ +id: iphone4 +label: iPhone 4 +dimensions: + width: 640 + height: 960 + dppx: 2 +orientation: portrait +weight: 1 +status: 1 +langcode: en diff --git a/core/modules/responsive_preview/config/responsive_preview.device.iphone5.yml b/core/modules/responsive_preview/config/responsive_preview.device.iphone5.yml new file mode 100644 index 0000000..d076c8d --- /dev/null +++ b/core/modules/responsive_preview/config/responsive_preview.device.iphone5.yml @@ -0,0 +1,10 @@ +id: iphone5 +label: iPhone 5 +dimensions: + width: 640 + height: 1136 + dppx: 2 +orientation: portrait +weight: 0 +status: 1 +langcode: en diff --git a/core/modules/responsive_preview/config/responsive_preview.device.nexus4.yml b/core/modules/responsive_preview/config/responsive_preview.device.nexus4.yml new file mode 100644 index 0000000..d43ffea --- /dev/null +++ b/core/modules/responsive_preview/config/responsive_preview.device.nexus4.yml @@ -0,0 +1,10 @@ +id: nexus4 +label: Nexus 4 +dimensions: + width: 768 + height: 1280 + dppx: 2 +orientation: portrait +weight: 3 +status: 1 +langcode: en diff --git a/core/modules/responsive_preview/config/responsive_preview.device.nexus7.yml b/core/modules/responsive_preview/config/responsive_preview.device.nexus7.yml new file mode 100644 index 0000000..bf17615 --- /dev/null +++ b/core/modules/responsive_preview/config/responsive_preview.device.nexus7.yml @@ -0,0 +1,10 @@ +id: nexus7 +label: Nexus 7 +dimensions: + width: 800 + height: 1280 + dppx: 1.325 +orientation: portrait +weight: 4 +status: 1 +langcode: en diff --git a/core/modules/responsive_preview/config/responsive_preview.devices.yml b/core/modules/responsive_preview/config/responsive_preview.devices.yml deleted file mode 100644 index 8f4e088..0000000 --- a/core/modules/responsive_preview/config/responsive_preview.devices.yml +++ /dev/null @@ -1,50 +0,0 @@ -# References: -# - http://en.wikipedia.org/wiki/List_of_displays_by_pixel_density -# - http://www.w3.org/blog/CSS/2012/06/14/unprefix-webkit-device-pixel-ratio/ -# - http://pieroxy.net/blog/2012/10/18/media_features_of_the_most_common_devices.html -# -# The device listing and specifications will be updated periodically through -# minor releases of Drupal. - -iphone: - label: iPhone 5 - dimensions: - width: 640 - height: 1136 - dppx: 2 - orientation: portrait -iphone4: - label: iPhone 4 - dimensions: - width: 640 - height: 960 - dppx: 2 - orientation: portrait -ipad: - label: iPad - dimensions: - width: 1536 - height: 2048 - dppx: 2 - orientation: portrait -nexus4: - label: Nexus 4 - dimensions: - width: 768 - height: 1280 - dppx: 2 - orientation: portrait -nexus7: - label: Nexus 7 - dimensions: - width: 800 - height: 1280 - dppx: 1.325 - orientation: portrait -desktop: - label: Typical desktop - dimensions: - width: 1366 - height: 768 - dppx: 1 - orientation: landscape diff --git a/core/modules/responsive_preview/lib/Drupal/responsive_preview/Form/DeviceSettingsAddForm.php b/core/modules/responsive_preview/lib/Drupal/responsive_preview/Form/DeviceSettingsAddForm.php deleted file mode 100644 index 8238873..0000000 --- a/core/modules/responsive_preview/lib/Drupal/responsive_preview/Form/DeviceSettingsAddForm.php +++ /dev/null @@ -1,116 +0,0 @@ -get('config.factory'), - $container->get('config.context.free') - ); - } - - /** - * {@inheritdoc} - */ - public function getFormID() { - return 'responsive_preview_device_settings_add'; - } - - /** - * {@inheritdoc} - */ - public function buildForm(array $form, array &$form_state) { - - $form = array( - 'label' => array( - '#type' => 'textfield', - '#title' => t('Device name'), - '#required' => TRUE, - ), - 'width' => array( - '#type' => 'textfield', - '#title' => t('Device width'), - '#size' => 6, - '#required' => TRUE, - ), - 'height' => array( - '#type' => 'textfield', - '#title' => t('Device height'), - '#size' => 6, - '#required' => TRUE, - ), - 'dppx' => array( - '#type' => 'textfield', - '#title' => t('Device dppx'), - '#default_value' => 1, - '#size' => 4, - '#required' => TRUE, - ), - 'orientation' => array( - '#type' => 'select', - '#title' => t('Default device orientation'), - '#default_value' => 'portrait', - '#options' => drupal_map_assoc(array('portrait', 'landscape')), - ), - ); - - return parent::buildForm($form, $form_state); - } - - /** - * {@inheritdoc} - */ - public function validateForm(array &$form, array &$form_state) { - parent::validateForm($form, $form_state); - } - - /** - * {@inheritdoc} - */ - public function submitForm(array &$form, array &$form_state) { - $this->configFactory->get('responsive_preview.devices')->set($form_state['values']['label'], array( - 'label' => $form_state['values']['label'], - 'dimensions' => array( - 'width' => $form_state['values']['width'], - 'height' => $form_state['values']['height'], - 'dppx' => $form_state['values']['dppx'], - ), - 'orientation' => $form_state['values']['orientation'], - ))->save(); - - parent::submitForm($form, $form_state); - } - -} diff --git a/core/modules/responsive_preview/lib/Drupal/responsive_preview/Form/DeviceSettingsForm.php b/core/modules/responsive_preview/lib/Drupal/responsive_preview/Form/DeviceSettingsForm.php deleted file mode 100644 index cbd773e..0000000 --- a/core/modules/responsive_preview/lib/Drupal/responsive_preview/Form/DeviceSettingsForm.php +++ /dev/null @@ -1,151 +0,0 @@ -get('config.factory'), - $container->get('config.context.free') - ); - } - - /** - * {@inheritdoc} - */ - public function getFormID() { - return 'responsive_preview_device_settings'; - } - - /** - * {@inheritdoc} - */ - public function buildForm(array $form, array &$form_state) { - $devices = $this->configFactory->get('responsive_preview.devices')->get(); - - $form['devices_listing'] = array( - '#type' => 'table', - '#title' => t('Device descriptions available for preview.'), - '#header' => array( - 'label' => array( - 'data' => t('Label'), - ), - 'width' => array( - 'data' => t('Width'), - ), - 'height' => array( - 'data' => t('Height'), - ), - 'dppx' => array( - 'data' => t('DPPX'), - 'class' => array(RESPONSIVE_PRIORITY_MEDIUM), - ), - 'orientation' => array( - 'data' => t('Orientation'), - 'class' => array(RESPONSIVE_PRIORITY_MEDIUM), - ), - ), - ); - - foreach ($devices as $device => $config) { - $form['devices_listing'][$device] = array( - 'label' => array( - '#type' => 'textfield', - '#title' => t('Device name'), - '#size' => null, - '#default_value' => $config['label'], - '#required' => TRUE, - ), - 'width' => array( - '#type' => 'textfield', - '#title' => t('Device width'), - '#default_value' => $config['dimensions']['width'], - '#size' => 6, - '#required' => TRUE, - ), - 'height' => array( - '#type' => 'textfield', - '#title' => t('Device height'), - '#default_value' => $config['dimensions']['height'], - '#size' => 6, - '#required' => TRUE, - ), - 'dppx' => array( - '#type' => 'textfield', - '#title' => t('Device dppx'), - '#default_value' => $config['dimensions']['dppx'], - '#size' => 4, - '#required' => TRUE, - ), - 'orientation' => array( - '#type' => 'select', - '#title' => t('Default device orientation'), - '#default_value' => $config['orientation'], - '#options' => drupal_map_assoc(array('portrait', 'landscape')), - ), - ); - } - - return parent::buildForm($form, $form_state); - } - - /** - * {@inheritdoc} - */ - public function validateForm(array &$form, array &$form_state) { - parent::validateForm($form, $form_state); - } - - /** - * {@inheritdoc} - */ - public function submitForm(array &$form, array &$form_state) { - $config = $this->configFactory->get('responsive_preview.devices'); - - foreach ($form_state['values']['devices_listing'] as $device => $settings) { - $config->set($device, array( - 'label' => $settings['label'], - 'dimensions' => array( - 'width' => $settings['width'], - 'height' => $settings['height'], - 'dppx' => $settings['dppx'], - ), - 'orientation' => $settings['orientation'], - )); - } - - $config->save(); - - parent::submitForm($form, $form_state); - } - -} diff --git a/core/modules/responsive_preview/responsive_preview.module b/core/modules/responsive_preview/responsive_preview.module index 05aaf51..4ac5daa 100644 --- a/core/modules/responsive_preview/responsive_preview.module +++ b/core/modules/responsive_preview/responsive_preview.module @@ -18,6 +18,9 @@ function responsive_preview_help($path, $arg) { $output .= '

' . t('To launch a preview, first click the toolbar tab with the small device icon. The tab has the title "@title". A list of devices will appear. Selecting a device name will launch a preview of the current page within the dimensions of that device.', array('@title' => t('Preview page layout'))) . '

'; $output .= '

' . t('To close the preview, click the close button signified visually by an x.') . '

'; return $output; + case 'admin/config/content/responsive_preview': + $output = '

' . t('Configure the set and order of available devices on this page for responsive site preview. The list of devices is shown in a dropdown accessible from the toolbar tab with a small device icon.') . '

'; + return $output; } } @@ -26,15 +29,29 @@ function responsive_preview_help($path, $arg) { */ function responsive_preview_menu() { $items['admin/config/content/responsive_preview'] = array( - 'title' => 'Responsive Preview', + 'title' => 'Responsive preview', 'description' => 'Configure device listings for content preview.', - 'route_name' => 'responsive_preview_device_settings', + 'route_name' => 'responsive_preview_device_list', ); $items['admin/config/content/responsive_preview/add'] = array( 'title' => 'Add preview device', - 'description' => 'Add a device by defining its specifications.', + 'route_name' => 'responsive_preview_device_add', 'type' => MENU_LOCAL_ACTION, - 'route_name' => 'responsive_preview_device_settings_add', + 'weight' => 1, + ); + $items['admin/config/content/responsive_preview/manage/%responsive_preview_device'] = array( + 'title' => 'Edit device', + 'route_name' => 'responsive_preview_device_edit', + ); + $items['admin/config/content/responsive_preview/manage/%responsive_preview_device/edit'] = array( + 'title' => 'Edit', + 'type' => MENU_DEFAULT_LOCAL_TASK, + ); + $items['admin/config/content/responsive_preview/manage/%responsive_preview_device/delete'] = array( + 'title' => 'Delete', + 'route_name' => 'responsive_preview_device_delete', + 'type' => MENU_LOCAL_TASK, + 'weight' => 10, ); return $items; } @@ -42,20 +59,22 @@ function responsive_preview_menu() { * Returns a list of devices and their properties from configuration. */ function responsive_preview_get_devices_list() { - $devices = config('responsive_preview.devices')->get(); + $devices = entity_load_multiple('responsive_preview_device'); + uasort($devices, array('Drupal\responsive_preview\Plugin\Core\Entity\Device', 'sort')); $links = array(); - foreach($devices as $name => $info) { - $links[$name] = array( + foreach ($devices as $device) { + $dimensions = $device->get('dimensions'); + $links[$device->id()] = array( '#type' => 'html_tag', '#tag' => 'button', - '#value' => $info['label'], + '#value' => $device->label(), '#attributes' => array( 'class' => array('device', 'icon', 'icon-active'), - 'data-responsive-preview-name' => $name, - 'data-responsive-preview-width' => (!empty($info['dimensions']['width'])) ? $info['dimensions']['width'] : '', - 'data-responsive-preview-height' => (!empty($info['dimensions']['height'])) ? $info['dimensions']['height'] : '', - 'data-responsive-preview-dppx' => (!empty($info['dimensions']['dppx'])) ? $info['dimensions']['dppx'] : '1', + 'data-responsive-preview-name' => $device->id(), + 'data-responsive-preview-width' => (!empty($dimensions['width'])) ? $dimensions['width'] : '', + 'data-responsive-preview-height' => (!empty($dimensions['height'])) ? $dimensions['height'] : '', + 'data-responsive-preview-dppx' => (!empty($dimensions['dppx'])) ? $dimensions['dppx'] : '1', ), ); } @@ -64,6 +83,20 @@ function responsive_preview_get_devices_list() { } /** + * Fetches a responsive preview device by ID. + * + * @param string $id + * A string representing the device ID (machine name). + * + * @return + * A fully-loaded device object if a device with the given ID exists, + * or FALSE otherwise. + */ +function responsive_preview_device_load($id) { + return entity_load('responsive_preview_device', $id); +} + +/** * Prevents the preview tab from rendering on administration pages. */ function responsive_preview_access() { diff --git a/core/modules/responsive_preview/responsive_preview.routing.yml b/core/modules/responsive_preview/responsive_preview.routing.yml index 07badd2..698c8c6 100644 --- a/core/modules/responsive_preview/responsive_preview.routing.yml +++ b/core/modules/responsive_preview/responsive_preview.routing.yml @@ -1,12 +1,28 @@ -responsive_preview_device_settings: +responsive_preview_device_list: pattern: '/admin/config/content/responsive_preview' defaults: - _form: 'Drupal\responsive_preview\Form\DeviceSettingsForm' + _content: '\Drupal\Core\Entity\Controller\EntityListController::listing' + entity_type: 'responsive_preview_device' requirements: _permission: 'administer site configuration' -responsive_preview_device_settings_add: + +responsive_preview_device_add: pattern: '/admin/config/content/responsive_preview/add' defaults: - _form: '\Drupal\responsive_preview\Form\DeviceSettingsAddForm' + _entity_form: responsive_preview_device.default + requirements: + _permission: 'administer site configuration' + +responsive_preview_device_edit: + pattern: '/admin/config/content/responsive_preview/manage/{responsive_preview_device}' + defaults: + _entity_form: responsive_preview_device.default + requirements: + _permission: 'administer site configuration' + +responsive_preview_device_delete: + pattern: '/admin/config/content/responsive_preview/manage/{responsive_preview_device}/delete' + defaults: + _form: '\Drupal\responsive_preview\Form\DeviceDelete' requirements: _permission: 'administer site configuration'