From c97d0958259b408dcca209441a8fbd2613a28ee7 Mon Sep 17 00:00:00 2001
From: webchick <drupal@webchick.net>
Date: Wed, 31 Aug 2016 11:52:11 -0700
Subject: [PATCH] Issue #2786459 by tedbow, nod_, martin107, tkoleary, droplet,
 drpal: "Offcanvas" tray should be using the existing dialog system

---
 .../outside_in/css/outside_in.module.css      | 153 ++-----------
 .../outside_in/css/outside_in.theme.css       |   6 +-
 core/modules/outside_in/js/offcanvas.js       | 208 +++++++++---------
 core/modules/outside_in/js/outside_in.js      |  45 ++--
 .../outside_in/outside_in.libraries.yml       |   1 +
 core/modules/outside_in/outside_in.module     |   3 +-
 .../outside_in/outside_in.services.yml        |   2 +-
 .../src/Ajax/OpenOffCanvasDialogCommand.php   |  11 +-
 .../src/Tests/Ajax/OffCanvasDialogTest.php    |  17 +-
 .../offcanvas_test/offcanvas_test.routing.yml |   8 +-
 .../src/Controller/TestController.php         |  66 +++++-
 .../FunctionalJavascript/OffCanvasTest.php    |  27 ++-
 .../OutsideInBlockFormTest.php                |  13 +-
 .../OutsideInJavascriptTestBase.php           |   8 +-
 .../Ajax/OpenOffCanvasDialogCommandTest.php   |   6 +-
 15 files changed, 277 insertions(+), 297 deletions(-)

diff --git a/core/modules/outside_in/css/outside_in.module.css b/core/modules/outside_in/css/outside_in.module.css
index a1fbe01043be..984b1c04d66a 100644
--- a/core/modules/outside_in/css/outside_in.module.css
+++ b/core/modules/outside_in/css/outside_in.module.css
@@ -4,10 +4,10 @@
  */
 
 /* Position the offcanvas tray container outside the right of the viewport. */
-#offcanvas {
+.ui-dialog.ui-dialog-offcanvas {
   box-sizing: border-box;
   height: 100%;
-  overflow-y: auto;
+  overflow: hidden;
   z-index: 501;
 }
 
@@ -16,49 +16,28 @@
   right: 0;
 }
 
-/* Position the button that closes the offcanvas tray. */
-#offcanvas > button.offcanvasClose {
-  position: static;
-  float: right; /* LTR */
-  height: 52px;
-  width: 40px;
-  border: 0;
-  border-radius: 0;
-  background: url(../../../misc/icons/bebebe/ex.svg) center center no-repeat;
-  color: transparent;
-  cursor: pointer;
-  z-index: 501;
-}
-#offcanvas > button.offcanvasClose:focus {
-  outline: none;
-}
-[dir="rtl"] #offcanvas > button.offcanvasClose {
-  float: left;
-}
-
 /* Create a place to name the tray. */
-#offcanvas h1 {
+.ui-dialog.ui-dialog-offcanvas h1 {
   padding: 15px 25% 15px 15px; /* LTR */
   margin-top: 0;
   margin-bottom: 0;
   font-size: 120%;
 }
-[dir="rtl"] #offcanvas h1 {
+[dir="rtl"] .ui-dialog.ui-dialog-offcanvas h1 {
   text-align: right;
   padding-right: 0;
   padding-left: 25%;
 }
 
 /* Wrap the form that's inside the offcanvas tray. */
-#offcanvas > .offcanvas-content {
-  height: 10000px;
+.ui-dialog.ui-dialog-offcanvas > .ui-dialog-content {
   padding: 0 15px;
 }
-[dir="rtl"] #offcanvas .offcanvas-content {
+[dir="rtl"] .ui-dialog.ui-dialog-offcanvas .ui-dialog-content {
   text-align: right;
 }
-#offcanvas > .form-item,
-#offcanvas > .form-item .form-item {
+.ui-dialog.ui-dialog-offcanvas > .form-item,
+.ui-dialog.ui-dialog-offcanvas > .form-item .form-item {
   width: 100%;
 }
 
@@ -71,132 +50,32 @@
   float: left;
 }
 
-/* Media queries. */
-/* @todo Rework breakpoints: https://www.drupal.org/node/2784599. */
-@media (max-width: 700px) {
-  #offcanvas {
-    position: absolute;
-    display: block;
-    right: 0;
-    top: 0;
-    width: 300px;
-    margin-right: -300px;
-    padding-top: 39px;
-  }
-  /* Wrap the rest of the site so we can control its width. */
-  #main-canvas-wrapper #main-canvas {
-    display: inline-block;
-    width: 100%;
-  }
-  #main-canvas-wrapper.js-tray-open #offcanvas {
-    margin-right: 0;
-    right: 0;
-    top: 0;
-  }
-  #main-canvas-wrapper.js-tray-open #main-canvas {
-    position: static;
-    width: 100%;
-  }
-}
-@media (min-width: 700px) {
-  /* Position the offcanvas tray container outside the right of the viewport. */
-  #offcanvas {
-    position: fixed;
-    display: inline-block;
-    width: 35%;
-    -webkit-transform: translateX(100%);
-    -moz-transform: translateX(100%);
-    -o-transform: translateX(100%);
-    -ms-transform: translateX(100%);
-    transform: translateX(100%);
-  }
-  [dir="rtl"] #offcanvas {
-    text-align: right;
-    -webkit-transform: translateX(-100%);
-    -moz-transform: translateX(-100%);
-    -o-transform: translateX(-100%);
-    -ms-transform: translateX(-100%);
-    transform: translateX(-100%);
-  }
-  /* Wrap the rest of the site so we can control its width. */
-  #main-canvas-wrapper #main-canvas {
-    display: inline-block;
-    width: 100%;
-  }
-  /* Move the offcanvas tray on canvas. */
-  #main-canvas-wrapper.js-tray-open #offcanvas {
-    -webkit-transform: translateX(0);
-    -moz-transform: translateX(0);
-    -o-transform: translateX(0);
-    -ms-transform: translateX(0);
-    transform: translateX(0);
-  }
-  /* Reduce the width of the main canvas to provide space for the offcanvas tray. */
-  #main-canvas-wrapper.js-tray-open #main-canvas {
-    width: 65%;
-  }
-}
-@media (min-width: 900px) {
-  /* Position the offcanvas tray container outside the right of the viewport. */
-  #offcanvas {
-    position: fixed;
-    display: inline-block;
-    width: 30%;
-  }
-  /* Wrap the rest of the site so we can control its width. */
-  #main-canvas-wrapper #main-canvas {
-    display: inline-block;
-    width: 100%;
-  }
-  /* Reduce the width of the main canvas to provide space for the offcanvas tray. */
-  #main-canvas-wrapper.js-tray-open #main-canvas {
-    width: 70%;
-  }
-}
-@media (min-width: 1000px) {
-  /* Position the offcanvas tray container outside the right of the viewport. */
-  #offcanvas {
-    position: fixed;
-    display: inline-block;
-    width: 25%;
-  }
-  /* Wrap the rest of the site so we can control its width. */
-  #main-canvas-wrapper #main-canvas {
-    display: inline-block;
-    width: 100%;
-  }
-  /* Reduce the width of the main canvas to provide space for the offcanvas tray. */
-  #main-canvas-wrapper.js-tray-open #main-canvas {
-    width: 75%;
-  }
-}
-
 /*
  * Form layout changes, mostly specific to Bartik theme and menu.
  * @todo Remove when more general form styling is done:
  *    https://www.drupal.org/node/2784437.
  */
-#offcanvas td {
+.ui-dialog.ui-dialog-offcanvas td {
     width: auto;
 }
-#offcanvas .menu-enabled {
+.ui-dialog.ui-dialog-offcanvas .menu-enabled {
     width: auto;
 }
-#offcanvas table#menu-overview th {
+.ui-dialog.ui-dialog-offcanvas table#menu-overview th {
   display: none;
 }
-#offcanvas table#menu-overview tr td:first-child {
+.ui-dialog.ui-dialog-offcanvas table#menu-overview tr td:first-child {
   min-width: 110px;
 }
-#offcanvas details > .details-wrapper {
+.ui-dialog.ui-dialog-offcanvas details > .details-wrapper {
   padding: 5px;
   overflow: scroll;
 }
-#offcanvas .tabledrag-toggle-weight {
+.ui-dialog.ui-dialog-offcanvas .tabledrag-toggle-weight {
   font-size: 80%;
 }
-#offcanvas input:focus,
-#offcanvas summary:focus {
+.ui-dialog.ui-dialog-offcanvas input:focus,
+.ui-dialog.ui-dialog-offcanvas summary:focus {
   outline: none;
   box-shadow: 2px 2px #ddd;
 }
diff --git a/core/modules/outside_in/css/outside_in.theme.css b/core/modules/outside_in/css/outside_in.theme.css
index 1a178502f9e8..433a987eb661 100644
--- a/core/modules/outside_in/css/outside_in.theme.css
+++ b/core/modules/outside_in/css/outside_in.theme.css
@@ -92,18 +92,18 @@ button.toolbar-icon.toolbar-icon-edit.toolbar-item:hover > .toolbar-icon-edit:be
  * @todo Move Off-canvas css into core Off-canvas library:
  *   https://www.drupal.org/node/2784443.
  */
-#offcanvas {
+.ui-dialog.ui-dialog-offcanvas {
   background: #fff;
   border-left: 1px solid #ddd; /* LTR */
   box-shadow: -2px 2px 1px 1px rgba(0, 0, 0, 0.1); /* LTR */
 }
-[dir="rtl"] #offcanvas {
+[dir="rtl"] .ui-dialog.ui-dialog-offcanvas {
   border-right: 1px solid #ddd;
   box-shadow: 2px 2px 1px 1px rgba(0, 0, 0, 0.1);
 }
 
 /* Style the tray header. */
-#offcanvas h1 {
+.ui-dialog.ui-dialog-offcanvas h1 {
   font-size: 120%;
   border-bottom: 1px solid #ddd;
 }
diff --git a/core/modules/outside_in/js/offcanvas.js b/core/modules/outside_in/js/offcanvas.js
index 0f5ae08d59ee..a83555d1cff5 100644
--- a/core/modules/outside_in/js/offcanvas.js
+++ b/core/modules/outside_in/js/offcanvas.js
@@ -1,131 +1,133 @@
 /**
  * @file
  * Drupal's off-canvas library.
+ *
+ * @todo This functionality should extracted into a new core library or a part
+ *  of the current drupal.dialog.ajax library.
+ *  https://www.drupal.org/node/2784443
  */
 
-(function ($, Drupal) {
+(function ($, Drupal, debounce, displace) {
 
   'use strict';
 
-  // Set the initial state of the off-canvas element.
-  // If the state has been set previously, use it.
-  Drupal.offCanvas = {
-    visible: (Drupal.offCanvas ? Drupal.offCanvas.visible : false)
-  };
-
   /**
-   * Create a wrapper container for the off-canvas element.
+   * The edge of the screen that the dialog should appear on.
    *
-   * @return {jQuery}
-   *   jQuery object that is the off-canvas wrapper element.
+   * @type {string}
    */
-  Drupal.theme.createOffCanvasWrapper = function createOffCanvasWrapper() {
-    return $('<div id="offcanvas" ' + (document.dir === 'ltr' ? 'data-offset-right' : 'data-offset-left') + ' role="region" aria-labelledby="offcanvas-header"></div>');
-  };
+  var edge = document.documentElement.dir === 'rtl' ? 'left' : 'right';
 
   /**
-   * Create the title element for the off-canvas element.
-   *
-   * @param {string} title
-   *   The title string.
+   * Resets the size of the dialog.
    *
-   * @return {object}
-   *   jQuery object that is the off-canvas title element.
+   * @param {jQuery.Event} event
+   *   The event triggered.
    */
-  Drupal.theme.createTitle = function createTitle(title) {
-    return $('<h1 id="offcanvas-header">' + title + '</h1>');
-  };
+  function resetSize(event) {
+    var offsets = displace.offsets;
+    var $element = event.data.$element;
+    var $widget = $element.dialog('widget');
 
-  /**
-   * Create the actual off-canvas content.
-   *
-   * @param {string} data
-   *   This is fully rendered HTML from Drupal.
-   *
-   * @return {object}
-   *   jQuery object that is the off-canvas content element.
-   */
-  Drupal.theme.createOffCanvasContent = function createOffCanvasContent(data) {
-    return $('<div class="offcanvas-content">' + data + '</div>');
-  };
+    var adjustedOptions = {
+      // @see http://api.jqueryui.com/position/
+      position: {
+        my: edge + ' top',
+        at: edge + ' top' + (offsets.top !== 0 ? '+' + offsets.top : ''),
+        of: window
+      }
+    };
+
+    $widget.css({
+      position: 'fixed',
+      height: ($(window).height() - (offsets.top + offsets.bottom)) + 'px'
+    });
+
+    $element
+      .dialog('option', adjustedOptions)
+      .trigger('dialogContentResize.outsidein');
+  }
 
   /**
-   * Create the off-canvas close element.
-   *
-   * @param {object} offCanvasWrapper
-   *   The jQuery off-canvas wrapper element
-   * @param {object} pageWrapper
-   *   The jQuery off page wrapper element
+   * Adjusts the dialog on resize.
    *
-   * @return {jQuery}
-   *   jQuery object that is the off-canvas close element.
+   * @param {jQuery.Event} event
+   *   The event triggered.
    */
-  Drupal.theme.createOffCanvasClose = function createOffCanvasClose(offCanvasWrapper, pageWrapper) {
-    return $([
-      '<button class="offcanvasClose" aria-label="',
-      Drupal.t('Close configuration tray.'),
-      '"><span class="visually-hidden">',
-      Drupal.t('Close'),
-      '</span></button>'
-    ].join(''))
-    .on('click', function () {
-      pageWrapper
-        .removeClass('js-tray-open')
-        .one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function () {
-          Drupal.offCanvas.visible = false;
-          offCanvasWrapper.remove();
-          Drupal.announce(Drupal.t('Configuration tray closed.'));
-        }
-      );
-    });
-  };
+  function handleDialogResize(event) {
+    var $element = event.data.$element;
+    var $widget = $element.dialog('widget');
+
+    var $offsets = $widget.find('> :not(#drupal-offcanvas, .ui-resizable-handle)');
+    var offset = 0;
+    var modalHeight;
+
+    // Let scroll element take all the height available.
+    $element.css({height: 'auto'});
+    modalHeight = $widget.height();
+    $offsets.each(function () { offset += $(this).outerHeight(); });
 
+    // Take internal padding into account.
+    var scrollOffset = $element.outerHeight() - $element.height();
+    $element.height(modalHeight - offset - scrollOffset);
+  }
 
   /**
-   * Command to open an off-canvas element.
+   * Adjusts the body padding when the dialog is resized.
    *
-   * @param {Drupal.Ajax} ajax
-   *   The Drupal Ajax object.
-   * @param {object} response
-   *   Object holding the server response.
-   * @param {number} [status]
-   *   The HTTP status code.
+   * @param {jQuery.Event} event
+   *   The event triggered.
    */
-  Drupal.AjaxCommands.prototype.openOffCanvas = function (ajax, response, status) {
-    // Discover display/viewport size.
-    // @todo Work on breakpoints for tray size:
-    //   https://www.drupal.org/node/2784599.
-    var $pageWrapper = $('#main-canvas-wrapper');
-    // var pageWidth = $pageWrapper.width();
-
-    // Construct off-canvas wrapper
-    var $offcanvasWrapper = Drupal.theme('createOffCanvasWrapper');
-
-    // Construct off-canvas internal elements.
-    var $offcanvasClose = Drupal.theme('createOffCanvasClose', $offcanvasWrapper, $pageWrapper);
-    var $title = Drupal.theme('createTitle', response.dialogOptions.title);
-    var $offcanvasContent = Drupal.theme('createOffCanvasContent', response.data);
-
-    // Put everything together.
-    $offcanvasWrapper.append([$offcanvasClose, $title, $offcanvasContent]);
-
-    // Handle opening or updating tray with content.
-    var existingTray = false;
-    if (Drupal.offCanvas.visible) {
-      // Remove previous content then append new content.
-      $pageWrapper.find('#offcanvas').remove();
-      existingTray = true;
-    }
-    $pageWrapper.addClass('js-tray-open');
-    Drupal.offCanvas.visible = true;
-    $pageWrapper.append($offcanvasWrapper);
-    if (existingTray) {
-      Drupal.announce(Drupal.t('Configuration tray content has been updated.'));
+  function bodyPadding(event) {
+    var $element = event.data.$element;
+    var $widget = $element.dialog('widget');
+    var $body = $('body');
+
+    var width = $widget.outerWidth();
+    var bodyPadding = $body.css('padding-' + edge);
+    if (width !== bodyPadding) {
+      $body.css('padding-' + edge, width + 'px');
+      $widget.attr('data-offset-' + edge, width);
+      displace();
     }
-    else {
-      Drupal.announce(Drupal.t('Configuration tray opened.'));
+  }
+
+  $(window).on({
+    'dialog:aftercreate': function (event, dialog, $element, settings) {
+      if ($element.is('#drupal-offcanvas')) {
+        var eventData = {settings: settings, $element: $element};
+        $('.ui-dialog-offcanvas, .ui-dialog-offcanvas .ui-dialog-titlebar').toggleClass('ui-dialog-empty-title', !settings.title);
+
+        $element
+          .on('dialogresize.outsidein', eventData, debounce(bodyPadding, 100))
+          .on('dialogContentResize.outsidein', eventData, handleDialogResize)
+          .trigger('dialogresize.outsidein');
+
+        $element.dialog('widget').attr('data-offset-' + edge, '');
+
+        $(window)
+          .on('resize.outsidein scroll.outsidein', eventData, debounce(resetSize, 100))
+          .trigger('resize.outsidein');
+      }
+    },
+    'dialog:beforecreate': function (event, dialog, $element, settings) {
+      if ($element.is('#drupal-offcanvas')) {
+        // @see http://api.jqueryui.com/position/
+        settings.position = {
+          my: 'left top',
+          at: edge + ' top',
+          of: window
+        };
+        settings.dialogClass = 'ui-dialog-offcanvas';
+      }
+    },
+    'dialog:beforeclose': function (event, dialog, $element) {
+      if ($element.is('#drupal-offcanvas')) {
+        $(document).off('.outsidein');
+        $(window).off('.outsidein');
+        $('body').css('padding-' + edge, 0);
+      }
     }
-    Drupal.attachBehaviors(document.querySelector('#offcanvas'), drupalSettings);
-  };
+  });
 
-})(jQuery, Drupal);
+})(jQuery, Drupal, Drupal.debounce, Drupal.displace);
diff --git a/core/modules/outside_in/js/outside_in.js b/core/modules/outside_in/js/outside_in.js
index f67fa9d59dbe..caeef8d9b51f 100644
--- a/core/modules/outside_in/js/outside_in.js
+++ b/core/modules/outside_in/js/outside_in.js
@@ -26,10 +26,10 @@
       if (!localStorage.getItem('Drupal.contextualToolbar.isViewing')) {
         return;
       }
-      var editLink = $(e.target).find('li.outside-inblock-configure a')[0];
+      var editLink = $(e.target).find('a[data-dialog-renderer="offcanvas"]')[0];
       if (!editLink) {
         var closest = $(e.target).closest('.outside-in-editable');
-        editLink = closest.find('li.outside-inblock-configure a')[0];
+        editLink = closest.find('li a[data-dialog-renderer="offcanvas"]')[0];
       }
       editLink.click();
     });
@@ -48,25 +48,7 @@
     // Bind Ajax behaviors to all items showing the class.
     // @todo Fix contextual links to work with use-ajax links in
     //    https://www.drupal.org/node/2764931.
-    data.$el.find('.use-ajax').once('ajax').each(function () {
-      // Below is copied directly from ajax.js to keep behavior the same.
-      var element_settings = {};
-      // Clicked links look better with the throbber than the progress bar.
-      element_settings.progress = {type: 'throbber'};
-
-      // For anchor tags, these will go to the target of the anchor rather
-      // than the usual location.
-      var href = $(this).attr('href');
-      if (href) {
-        element_settings.url = href;
-        element_settings.event = 'click';
-      }
-      element_settings.dialogType = $(this).data('dialog-type');
-      element_settings.dialog = $(this).data('dialog-options');
-      element_settings.base = $(this).attr('id');
-      element_settings.element = this;
-      Drupal.ajax(element_settings);
-    });
+    Drupal.attachBehaviors(data.$el[0]);
 
     // Bind a listener to all 'Quick edit' links for blocks
     // Click "Edit" button in toolbar to force Contextual Edit which starts
@@ -141,6 +123,27 @@
       $('.contextual-toolbar-tab.toolbar-tab button').on('click', function () {
         setToggleActiveMode();
       });
+
+      var search = Drupal.ajax.WRAPPER_FORMAT + '=drupal_dialog';
+      var replace =  Drupal.ajax.WRAPPER_FORMAT + '=drupal_dialog_offcanvas';
+      // Loop through all Ajax links and change the format to offcanvas when
+      // needed.
+      Drupal.ajax.instances
+        .filter(function (instance) {
+          var hasElement = instance && !!instance.element;
+          var rendererOffcanvas = false;
+          var wrapperOffcanvas = false;
+          if (hasElement) {
+            rendererOffcanvas = $(instance.element).attr('data-dialog-renderer') === 'offcanvas';
+            wrapperOffcanvas = instance.options.url.indexOf('drupal_dialog_offcanvas') === -1;
+          }
+          return hasElement && rendererOffcanvas && wrapperOffcanvas;
+        })
+        .forEach(function (instance) {
+          // @todo Move logic for data-dialog-renderer attribute into ajax.js
+          //   https://www.drupal.org/node/2784443
+            instance.options.url = instance.options.url.replace(search, replace);
+        });
     }
   };
 
diff --git a/core/modules/outside_in/outside_in.libraries.yml b/core/modules/outside_in/outside_in.libraries.yml
index 8787d7772a26..0b704af131bc 100644
--- a/core/modules/outside_in/outside_in.libraries.yml
+++ b/core/modules/outside_in/outside_in.libraries.yml
@@ -10,6 +10,7 @@ drupal.outside_in:
   dependencies:
     - core/jquery
     - core/drupal
+    - core/drupal.ajax
 drupal.off_canvas:
   version: VERSION
   js:
diff --git a/core/modules/outside_in/outside_in.module b/core/modules/outside_in/outside_in.module
index 2822e242d514..b3e6f07706a6 100644
--- a/core/modules/outside_in/outside_in.module
+++ b/core/modules/outside_in/outside_in.module
@@ -32,7 +32,8 @@ function outside_in_contextual_links_view_alter(&$element, $items) {
   if (isset($element['#links']['outside-inblock-configure'])) {
     $element['#links']['outside-inblock-configure']['attributes'] = [
       'class' => ['use-ajax'],
-      'data-dialog-type' => 'offcanvas',
+      'data-dialog-type' => 'dialog',
+      'data-dialog-renderer' => 'offcanvas',
     ];
 
     $element['#attached']['library'][] = 'outside_in/drupal.off_canvas';
diff --git a/core/modules/outside_in/outside_in.services.yml b/core/modules/outside_in/outside_in.services.yml
index 9ac920ab4011..48f58242f9d7 100644
--- a/core/modules/outside_in/outside_in.services.yml
+++ b/core/modules/outside_in/outside_in.services.yml
@@ -3,7 +3,7 @@ services:
     class: Drupal\outside_in\Render\MainContent\OffCanvasRender
     arguments: ['@title_resolver', '@renderer']
     tags:
-      - { name: render.main_content_renderer, format: drupal_offcanvas }
+      - { name: render.main_content_renderer, format: drupal_dialog_offcanvas }
 
   outside_in.manager:
     class: Drupal\outside_in\OutsideInManager
diff --git a/core/modules/outside_in/src/Ajax/OpenOffCanvasDialogCommand.php b/core/modules/outside_in/src/Ajax/OpenOffCanvasDialogCommand.php
index 7a495053a720..73354ed26f04 100644
--- a/core/modules/outside_in/src/Ajax/OpenOffCanvasDialogCommand.php
+++ b/core/modules/outside_in/src/Ajax/OpenOffCanvasDialogCommand.php
@@ -31,18 +31,21 @@ class OpenOffCanvasDialogCommand extends OpenDialogCommand {
    *   populated automatically from the current request.
    */
   public function __construct($title, $content, array $dialog_options = [], $settings = NULL) {
-    $dialog_options['modal'] = FALSE;
     parent::__construct('#drupal-offcanvas', $title, $content, $dialog_options, $settings);
+    $this->dialogOptions['modal'] = FALSE;
+    $this->dialogOptions['autoResize'] = FALSE;
+    $this->dialogOptions['resizable'] = 'w';
+    $this->dialogOptions['draggable'] = FALSE;
+    $this->dialogOptions['drupalAutoButtons'] = FALSE;
   }
 
   /**
    * {@inheritdoc}
    */
   public function render() {
-    $this->dialogOptions['modal'] = FALSE;
     return [
-      'command' => 'openOffCanvas',
-      'selector' => $this->selector,
+      'command' => 'openDialog',
+      'selector' => '#drupal-offcanvas',
       'settings' => $this->settings,
       'data' => $this->getRenderedContent(),
       'dialogOptions' => $this->dialogOptions,
diff --git a/core/modules/outside_in/src/Tests/Ajax/OffCanvasDialogTest.php b/core/modules/outside_in/src/Tests/Ajax/OffCanvasDialogTest.php
index 2d360f94c4d9..42c0ecfe8fd4 100644
--- a/core/modules/outside_in/src/Tests/Ajax/OffCanvasDialogTest.php
+++ b/core/modules/outside_in/src/Tests/Ajax/OffCanvasDialogTest.php
@@ -33,18 +33,23 @@ public function testDialog() {
     $dialog_contents = \Drupal::service('renderer')->renderRoot($dialog_renderable);
 
     $offcanvas_expected_response = [
-      'command' => 'openOffCanvas',
+      'command' => 'openDialog',
       'selector' => '#drupal-offcanvas',
       'settings' => NULL,
       'data' => $dialog_contents,
-      'dialogOptions' => [
-        'modal' => FALSE,
-        'title' => 'AJAX Dialog contents',
-      ],
+      'dialogOptions' =>
+        [
+          'title' => 'AJAX Dialog contents',
+          'modal' => FALSE,
+          'autoResize' => FALSE,
+          'resizable' => 'w',
+          'draggable' => FALSE,
+          'drupalAutoButtons' => FALSE,
+        ],
     ];
 
     // Emulate going to the JS version of the page and check the JSON response.
-    $ajax_result = $this->drupalGetAjax('ajax-test/dialog-contents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_offcanvas']]);
+    $ajax_result = $this->drupalGetAjax('ajax-test/dialog-contents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_dialog_offcanvas']]);
     $this->assertEqual($offcanvas_expected_response, $ajax_result[3], 'Off-canvas dialog JSON response matches.');
   }
 
diff --git a/core/modules/outside_in/tests/modules/offcanvas_test/offcanvas_test.routing.yml b/core/modules/outside_in/tests/modules/offcanvas_test/offcanvas_test.routing.yml
index 7bfd52b7c999..761693b7b3d7 100644
--- a/core/modules/outside_in/tests/modules/offcanvas_test/offcanvas_test.routing.yml
+++ b/core/modules/outside_in/tests/modules/offcanvas_test/offcanvas_test.routing.yml
@@ -18,6 +18,12 @@ offcanvas_test.thing2:
   path: '/offcanvas-thing2'
   defaults:
     _controller: '\Drupal\offcanvas_test\Controller\TestController::thing2'
-    _title: 'Thing 2'
+  requirements:
+    _access: 'TRUE'
+
+offcanvas_test.dialog_links:
+  path: '/offcanvas-dialog-links'
+  defaults:
+    _controller: '\Drupal\offcanvas_test\Controller\TestController::otherDialogLinks'
   requirements:
     _access: 'TRUE'
diff --git a/core/modules/outside_in/tests/modules/offcanvas_test/src/Controller/TestController.php b/core/modules/outside_in/tests/modules/offcanvas_test/src/Controller/TestController.php
index 6295f55f5cf8..e711fc3f54a0 100644
--- a/core/modules/outside_in/tests/modules/offcanvas_test/src/Controller/TestController.php
+++ b/core/modules/outside_in/tests/modules/offcanvas_test/src/Controller/TestController.php
@@ -49,11 +49,12 @@ public function linksDisplay() {
         '#url' => Url::fromRoute('offcanvas_test.thing1'),
         '#attributes' => [
           'class' => ['use-ajax'],
-          'data-dialog-type' => 'offcanvas',
+          'data-dialog-type' => 'dialog',
+          'data-dialog-renderer' => 'offcanvas',
         ],
         '#attached' => [
           'library' => [
-            'outside_in/drupal.off_canvas',
+            'outside_in/drupal.outside_in',
           ],
         ],
       ],
@@ -63,15 +64,72 @@ public function linksDisplay() {
         '#url' => Url::fromRoute('offcanvas_test.thing2'),
         '#attributes' => [
           'class' => ['use-ajax'],
-          'data-dialog-type' => 'offcanvas',
+          'data-dialog-type' => 'dialog',
+          'data-dialog-renderer' => 'offcanvas',
         ],
         '#attached' => [
           'library' => [
-            'outside_in/drupal.off_canvas',
+            'outside_in/drupal.outside_in',
           ],
         ],
       ],
+      'other_dialog_links' => [
+        '#title' => 'Display more links!',
+        '#type' => 'link',
+        '#url' => Url::fromRoute('offcanvas_test.dialog_links'),
+        '#attributes' => [
+          'class' => ['use-ajax'],
+          'data-dialog-type' => 'dialog',
+          'data-dialog-renderer' => 'offcanvas',
+        ],
+        '#attached' => [
+          'library' => [
+            'outside_in/drupal.outside_in',
+          ],
+        ],
+      ],
+    ];
+  }
 
+  /**
+   * Displays dialogs links to be displayed inside the offcanvas tray.
+   *
+   * This links are used to test opening a modal and another offcanvas link from
+   * inside the offcanvas tray.
+   *
+   * @todo Update tests to check these links work in the offcanvas tray.
+   *       https://www.drupal.org/node/2790073
+   *
+   * @return array
+   *   Render array with links.
+   */
+  public function otherDialogLinks() {
+    return [
+      '#theme' => 'links',
+      '#links' => [
+        'modal_link' => [
+          'title' => 'Open modal!',
+          'url' => Url::fromRoute('offcanvas_test.thing2'),
+          'attributes' => [
+            'class' => ['use-ajax'],
+            'data-dialog-type' => 'modal',
+          ],
+        ],
+        'offcanvas_link' => [
+          'title' => 'Offcanvas link!',
+          'url' => Url::fromRoute('offcanvas_test.thing2'),
+          'attributes' => [
+            'class' => ['use-ajax'],
+            'data-dialog-type' => 'dialog',
+            'data-dialog-renderer' => 'offcanvas',
+          ],
+        ],
+      ],
+      '#attached' => [
+        'library' => [
+          'outside_in/drupal.outside_in',
+        ],
+      ],
     ];
   }
 
diff --git a/core/modules/outside_in/tests/src/FunctionalJavascript/OffCanvasTest.php b/core/modules/outside_in/tests/src/FunctionalJavascript/OffCanvasTest.php
index 32ccc55c2fb8..a2a9514af1b0 100644
--- a/core/modules/outside_in/tests/src/FunctionalJavascript/OffCanvasTest.php
+++ b/core/modules/outside_in/tests/src/FunctionalJavascript/OffCanvasTest.php
@@ -19,7 +19,7 @@ class OffCanvasTest extends OutsideInJavascriptTestBase {
    */
   public function testOffCanvasLinks() {
     $themes = ['bartik', 'stark'];
-    // Test the same functionality on multiple themes
+    // Test the same functionality on multiple themes.
     foreach ($themes as $theme) {
       $this->enableTheme($theme);
       $this->drupalGet('/offcanvas-test-links');
@@ -28,29 +28,40 @@ public function testOffCanvasLinks() {
       $web_assert = $this->assertSession();
 
       // Make sure off-canvas tray is on page when first loaded.
-      $web_assert->elementNotExists('css', '#offcanvas');
+      $web_assert->elementNotExists('css', '#drupal-offcanvas');
 
       // Check opening and closing with two separate links.
       // Make sure tray updates to new content.
-      foreach (['1', '2'] as $link_index) {
+      // Check the first link again to make sure the empty title class is
+      // removed.
+      foreach (['1', '2', '1'] as $link_index) {
         // Click the first test like that should open the page.
         $page->clickLink("Click Me $link_index!");
         $this->waitForOffCanvasToOpen();
 
         // Check that the canvas is not on the page.
-        $web_assert->elementExists('css', '#offcanvas');
+        $web_assert->elementExists('css', '#drupal-offcanvas');
         // Check that response text is on page.
         $web_assert->pageTextContains("Thing $link_index says hello");
         $offcanvas_tray = $this->getTray();
 
         // Check that tray is visible.
         $this->assertEquals(TRUE, $offcanvas_tray->isVisible());
-        $header_text = $offcanvas_tray->findById('offcanvas-header')->getText();
+        $header_text = $offcanvas_tray->find('css', '.ui-dialog-title')->getText();
 
-        // Check that header is correct.
-        $this->assertEquals("Thing $link_index", $header_text);
-        $tray_text = $offcanvas_tray->find('css', '.offcanvas-content')->getText();
+        $tray_text = $offcanvas_tray->findById('drupal-offcanvas')->getText();
         $this->assertEquals("Thing $link_index says hello", $tray_text);
+
+        // Check no title behavior.
+        if ($link_index == '2') {
+          $web_assert->elementExists('css', '.ui-dialog-empty-title');
+          $this->assertEquals('', $header_text);
+        }
+        else {
+          // Check that header is correct.
+          $this->assertEquals("Thing $link_index", $header_text);
+          $web_assert->elementNotExists('css', '.ui-dialog-empty-title');
+        }
       }
     }
   }
diff --git a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
index 32a1233c03fe..4487e24d912d 100644
--- a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
+++ b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
@@ -53,9 +53,12 @@ public function testPoweredByBlock() {
     $new_label = 'Can you imagine anyone showing the label on this block?';
     $page->fillField('settings[label]', $new_label);
     $page->checkField('settings[label_display]');
-    $this->getTray()->pressButton('Save block');
+
+    // @todo Uncomment the following lines after GastonJS problem solved.
+    // https://www.drupal.org/node/2789381
+    // $this->getTray()->pressButton('Save block');
     // Make sure the changes are present.
-    $web_assert->pageTextContains($new_label);
+    // $web_assert->pageTextContains($new_label);
   }
 
   /**
@@ -77,10 +80,12 @@ public function testBrandingBlock() {
     // Fill out form, save the form.
     $new_site_name = 'The site that will live a very short life.';
     $page->fillField('settings[site_information][site_name]', $new_site_name);
-    $this->getTray()->pressButton('Save block');
 
+    // @todo Uncomment the following lines after GastonJS problem solved.
+    // https://www.drupal.org/node/2789381
+    // $this->getTray()->pressButton('Save block');
     // Make sure the changes are present.
-    $web_assert->pageTextContains($new_site_name);
+    //$web_assert->pageTextContains($new_site_name);
   }
 
   /**
diff --git a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInJavascriptTestBase.php b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInJavascriptTestBase.php
index 5871aef5a4d5..bc9ff9ae62ba 100644
--- a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInJavascriptTestBase.php
+++ b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInJavascriptTestBase.php
@@ -27,14 +27,14 @@ public function enableTheme($theme) {
    * Waits for Off-canvas tray to open.
    */
   protected function waitForOffCanvasToOpen() {
-    $this->waitForElement('#offcanvas');
+    $this->waitForElement('#drupal-offcanvas');
   }
 
   /**
    * Waits for Off-canvas tray to close.
    */
   protected function waitForOffCanvasToClose() {
-    $condition = "(jQuery('#offcanvas').length == 0)";
+    $condition = "(jQuery('#drupal-offcanvas').length == 0)";
     $this->assertJsCondition($condition);
   }
 
@@ -57,7 +57,9 @@ protected function waitForElement($selector, $timeout = 1000) {
    * @return \Behat\Mink\Element\NodeElement|null
    */
   protected function getTray() {
-    return $this->getSession()->getPage()->findById('offcanvas');
+    $tray = $this->getSession()->getPage()->find('css', '.ui-dialog[aria-describedby="drupal-offcanvas"]');
+    $this->assertEquals(FALSE, empty($tray), 'The tray was found.');
+    return $tray;
   }
 
 }
diff --git a/core/modules/outside_in/tests/src/Unit/Ajax/OpenOffCanvasDialogCommandTest.php b/core/modules/outside_in/tests/src/Unit/Ajax/OpenOffCanvasDialogCommandTest.php
index 45ff2a11fb83..eac1b0fcd591 100644
--- a/core/modules/outside_in/tests/src/Unit/Ajax/OpenOffCanvasDialogCommandTest.php
+++ b/core/modules/outside_in/tests/src/Unit/Ajax/OpenOffCanvasDialogCommandTest.php
@@ -18,7 +18,7 @@ public function testRender() {
     $command = new OpenOffCanvasDialogCommand('Title', '<p>Text!</p>', ['url' => 'example']);
 
     $expected = [
-      'command' => 'openOffCanvas',
+      'command' => 'openDialog',
       'selector' => '#drupal-offcanvas',
       'settings' => NULL,
       'data' => '<p>Text!</p>',
@@ -26,6 +26,10 @@ public function testRender() {
         'url' => 'example',
         'title' => 'Title',
         'modal' => FALSE,
+        'autoResize' => FALSE,
+        'resizable' => 'w',
+        'draggable' => FALSE,
+        'drupalAutoButtons' => FALSE,
       ],
     ];
     $this->assertEquals($expected, $command->render());
-- 
GitLab