diff --git a/core/misc/edit.png b/core/misc/edit.png
new file mode 100644
index 0000000..299cfd1
--- /dev/null
+++ b/core/misc/edit.png
@@ -0,0 +1,3 @@
+‰PNG
+
+
diff --git a/core/modules/contextual/contextual.base-rtl.css b/core/modules/contextual/contextual.base-rtl.css
deleted file mode 100644
index 147a567..0000000
--- a/core/modules/contextual/contextual.base-rtl.css
+++ /dev/null
@@ -1,9 +0,0 @@
-
-/**
- * @file
- * RTL base styles for the Contextual module.
- */
-
-.contextual .trigger {
- text-align: left;
-}
diff --git a/core/modules/contextual/contextual.base.css b/core/modules/contextual/contextual.base.css
index cbec804..8452f52 100644
--- a/core/modules/contextual/contextual.base.css
+++ b/core/modules/contextual/contextual.base.css
@@ -4,35 +4,36 @@
* Generic base styles for contextual module.
*/
-/**
- * Contextual links behavior.
- */
-.contextual,
-.contextual .contextual-links,
-.contextual .trigger {
+.contextual-region {
+ position: relative;
+}
+.touch .contextual .trigger {
+ display: block;
+}
+.contextual .contextual-links {
display: none;
}
-.touch .contextual,
-.touch .contextual .trigger,
-.no-touch .contextual-region:hover .contextual,
-.no-touch .contextual-region:hover .contextual-links-trigger-active,
-.contextual-active .contextual-links {
+.contextual-links-active .contextual-links {
display: block;
}
/**
- * Contextual links structure.
+ * The .element-focusable class extends the .element-invisible class to allow
+ * the element to be focusable when navigated to via the keyboard.
+ *
+ * Add support for hover.
*/
-.contextual-region {
- position: relative;
+.touch .contextual-region .element-invisible.element-focusable,
+.contextual-region:hover .element-invisible.element-focusable {
+ clip: auto;
+ overflow: visible;
+ height: auto;
}
-.contextual {
- position: absolute;
- z-index: 999;
-}
-.contextual .trigger {
- overflow: hidden;
- position: relative;
- text-align: right; /* LTR */
- z-index: 1;
+/* Override the position for contextual links. */
+.contextual-region .element-invisible.element-focusable:active,
+.contextual-region .element-invisible.element-focusable:focus,
+.contextual-region:hover .element-invisible.element-focusable,
+.contextual-region-active .element-invisible.element-focusable,
+.touch .contextual-region .element-invisible.element-focusable {
+ position: relative !important;
}
diff --git a/core/modules/contextual/contextual.js b/core/modules/contextual/contextual.js
index d8a4742..0759515 100644
--- a/core/modules/contextual/contextual.js
+++ b/core/modules/contextual/contextual.js
@@ -3,55 +3,177 @@
* Attaches behaviors for the Contextual module.
*/
-(function ($) {
+(function ($, Drupal) {
"use strict";
-Drupal.contextualLinks = Drupal.contextualLinks || {};
+var contextuals = [];
/**
* Attaches outline behavior for regions associated with contextual links.
*/
-Drupal.behaviors.contextualLinks = {
+Drupal.behaviors.contextual = {
attach: function (context) {
- $(context).find('div.contextual').once('contextual-links', function () {
- var $wrapper = $(this);
- var $region = $wrapper.closest('.contextual-region');
- var $links = $wrapper.find('ul');
- var $trigger = $('').text(Drupal.t('Configure')).click(
- function (e) {
- e.preventDefault();
- e.stopPropagation();
- $links.stop(true, true).slideToggle(100);
- $wrapper.toggleClass('contextual-active');
- }
- );
- // Attach hover behavior to trigger and ul.contextual-links, for non touch devices only.
- if(!Modernizr.touch) {
- $trigger.add($links).hover(
- function () { $region.addClass('contextual-region-active'); },
- function () { $region.removeClass('contextual-region-active'); }
- );
- }
- // Hide the contextual links when user clicks a link or rolls out of the .contextual-region.
- $region.bind('mouseleave click', Drupal.contextualLinks.mouseleave);
- $region.hover(
- function() { $trigger.addClass('contextual-links-trigger-active'); },
- function() { $trigger.removeClass('contextual-links-trigger-active'); }
- );
- // Prepend the trigger.
- $wrapper.prepend($trigger);
+ $('ul.contextual-links', context).once('contextual', function () {
+ var $this = $(this);
+ var contextual = new Drupal.contextual(this, $this.closest('.contextual-region'));
+ contextuals.push(contextual);
+ $this.data('drupal-contextual', contextual);
});
+ // Bind to global edit mode changes
+ $('body').once('contextual', function (index, element) {
+ $(document)
+ .on('drupalEditMode.contextual', toggleEditMode);
+ });
+ }
+};
+
+/**
+ * Contextual links object.
+ */
+Drupal.contextual = function($links, $region) {
+ this.$links = $links;
+ this.$region = $region;
+ this.timer = null;
+
+ this.init();
+};
+
+/**
+ * Initiates a contextual links object.
+ */
+Drupal.contextual.prototype.init = function() {
+ // Wrap the links to provide positioning and behavior attachment context.
+ this.$wrapper = $(Drupal.theme.contextualWrapper())
+ .insertBefore(this.$links)
+ .append(this.$links);
+
+ // Create and append the contextual links trigger.
+ var action = Drupal.t('Open');
+ this.$trigger = $(Drupal.theme.contextualTrigger())
+ .text(Drupal.t('@action configuration options', {'@action': action}))
+ .prependTo(this.$wrapper);
+
+ // The trigger behaviors are never detached or mutated.
+ this.$region
+ .on('click.contextual', '.contextual .trigger', $.proxy(this.triggerClickHandler, this))
+ .on('mouseleave.contextual', '.contextual', {show: false}, $.proxy(this.triggerLeaveHandler, this))
+ // Attach highlight behaviors.
+ this.attachHighlightBehaviors();
+};
+
+/**
+ *
+ */
+Drupal.contextual.prototype.attachHighlightBehaviors = function () {
+ // Bind behaviors through delegation.
+ var highlightRegion = $.proxy(this.highlightRegion, this);
+ this.$region
+ .on('mouseenter.contextual.highlight', {highlight: true}, highlightRegion)
+ .on('mouseleave.contextual.highlight', {highlight: false}, highlightRegion)
+ .on('focus.contextual.highlight', '.contextual-links a, .contextual .trigger', {highlight: true}, highlightRegion)
+ .on('blur.contextual.highlight', '.contextual-links a, .contextual .trigger', {highlight: false}, highlightRegion);
+};
+
+/**
+ *
+ */
+Drupal.contextual.prototype.detachHighlightBehaviors = function () {
+ this.$region.off('.contextual.highlight');
+};
+
+/**
+ * Toggles the highlighting of a contextual region.
+ *
+ * If the state of a contextual region is toggled to inactive, the links
+ *
+ * @param Object event
+ * jQuery Event object.
+ */
+Drupal.contextual.prototype.highlightRegion = function(event) {
+ // Set up a timeout to delay the dismissal of the region highlight state.
+ if (!event.data.highlight && !this.timer) {
+ return this.timer = window.setTimeout($.proxy($.fn.trigger, $(event.target), 'mouseleave.contextual'), 100);
+ }
+ // Clear the timeout if the region should be highlighted and a timer exists.
+ if (event.data.highlight && this.timer) {
+ window.clearTimeout(this.timer);
}
+ this.$region.toggleClass('contextual-region-active', event.data.highlight);
+ // Hide the links if the contextual region is inactive.
+ var state = this.$region.hasClass('contextual-region-active');
+ if (!state) {
+ this.showLinks(state);
+ }
+ // Clear the timeout.
+ this.timer = null;
+};
+
+/**
+ * Handles click on the contextual links trigger.
+ *
+ * @param Object event
+ * jQuery Event object.
+ */
+Drupal.contextual.prototype.triggerClickHandler = function (event) {
+ event.preventDefault();
+ this.showLinks();
+};
+
+/**
+ * Handles mouseleave on the contextual links trigger.
+ *
+ * @param Object event
+ * jQuery Event object.
+ */
+Drupal.contextual.prototype.triggerLeaveHandler = function (event) {
+ var show = event && event.data && event.data.show;
+ this.showLinks(show);
+};
+
+/**
+ * Toggles the active state of the contextual links.
+ *
+ * @param Boolean show
+ * (optional) True if the links should be shown. False is the links should be
+ * hidden.
+ */
+Drupal.contextual.prototype.showLinks = function(show) {
+ this.$wrapper.toggleClass('contextual-links-active', show);
+ var isOpen = this.$wrapper.hasClass('contextual-links-active');
+ var action = (isOpen) ? Drupal.t('Close') : Drupal.t('Open');
+ this.$trigger
+ .text(Drupal.t('@action configuration options', {'@action': action}));
+};
+
+/**
+ *
+ */
+function toggleEditMode (event, data) {
+ for (var i = contextuals.length - 1; i >= 0; i--) {
+ contextuals[i][(data.editable) ? 'detachHighlightBehaviors' : 'attachHighlightBehaviors']();
+ contextuals[i].$region.toggleClass('contextual-region-active', data.editable);
+ };
+}
+
+/**
+ * Wraps contextual links.
+ *
+ * @return {String}
+ * A string representing a DOM fragment.
+ */
+Drupal.theme.contextualWrapper = function () {
+ return '
';
};
/**
- * Disables outline for the region contextual links are associated with.
+ * A trigger is an interactive element often bound to a click handler.
+ *
+ * @return {String}
+ * A string representing a DOM fragment.
*/
-Drupal.contextualLinks.mouseleave = function () {
- $(this)
- .find('.contextual-active').removeClass('contextual-active')
- .find('.contextual-links').hide();
+Drupal.theme.contextualTrigger = function () {
+ return '';
};
-})(jQuery);
+})(jQuery, Drupal);
diff --git a/core/modules/contextual/contextual.module b/core/modules/contextual/contextual.module
index bbb00e8..30dcacb 100644
--- a/core/modules/contextual/contextual.module
+++ b/core/modules/contextual/contextual.module
@@ -69,8 +69,6 @@ function contextual_element_info() {
'#pre_render' => array('contextual_pre_render_links'),
'#theme' => 'links__contextual',
'#links' => array(),
- '#prefix' => '',
- '#suffix' => '
',
'#attributes' => array('class' => array('contextual-links')),
'#attached' => array(
'library' => array(
diff --git a/core/modules/contextual/contextual.theme-rtl.css b/core/modules/contextual/contextual.theme-rtl.css
index f558ffa..ed48367 100644
--- a/core/modules/contextual/contextual.theme-rtl.css
+++ b/core/modules/contextual/contextual.theme-rtl.css
@@ -3,17 +3,26 @@
* RTL styling for contextual module.
*/
+/**
+ * Contextual links wrappers.
+ */
.contextual {
- left: 5px;
- right: auto;
-}
-.contextual .contextual-links {
- border-radius: 0 4px 4px 4px;
left: 0;
right: auto;
}
-.contextual-region .contextual .contextual-links a {
- text-align: right;
- padding: 0.4em 0.6em 0.4em 0.8em;
+/**
+ * Contextual trigger.
+ */
+.contextual .trigger {
+ float: left;
+}
+
+/**
+ * Contextual links.
+ */
+.contextual .contextual-links {
+ border-radius: 0 4px 4px 4px;
+ float: left;
+ text-align: right;
}
diff --git a/core/modules/contextual/contextual.theme.css b/core/modules/contextual/contextual.theme.css
index 8b5956a..122234c 100644
--- a/core/modules/contextual/contextual.theme.css
+++ b/core/modules/contextual/contextual.theme.css
@@ -6,40 +6,42 @@
/**
* Contextual links wrappers.
*/
-.contextual-region-active {
- outline: 1px dashed #d6d6d6;
- outline-offset: 1px;
-}
.contextual {
- right: 2px; /* LTR */
+ position: absolute;
+ right: 0; /* LTR */
top: 2px;
+ z-index: 999;
+}
+.contextual-region-active {
+ outline: 1px solid #007fff;
+ outline-offset: 1px;
}
/**
* Contextual trigger.
*/
.contextual .trigger {
- background: transparent url(images/gear-select.png) no-repeat 2px 0;
- border: 1px solid transparent;
- height: 18px;
+ background: #ffffff url("../../misc/edit.png") no-repeat center center;
+ background-size: 16px 16px;
+ border: 1px solid #ddd;
+ border-radius: 13px;
+ box-shadow:1px 1px 2px rgba(0,0,0,0.3);
+ /* Override the .element-focusable height: auto */
+ height: 28px !important;
+ float: right; /* LTR */
margin: 0;
- outline: none;
overflow: hidden;
padding: 0 2px;
- text-indent: 34px;
+ position: relative;
+ right: 2px;
width: 28px;
+ text-indent: -9999px;
+ z-index: 2;
}
-.no-touch .contextual .trigger:hover,
-.contextual-active .trigger {
- background-position: 2px -18px;
-}
-.contextual-active .trigger {
- background-color: #ffffff;
- border-bottom: none;
- border-color: #d6d6d6;
- border-radius: 4px 4px 0 0;
- position: relative;
- z-index: 1;
+.contextual-links-active .trigger {
+ border-radius: 14px 14px 0 0;
+ border-bottom: 1px solid transparent;
+ box-shadow: 2px 0 0 rgba(0,0,0,0.15);
}
/**
@@ -47,17 +49,21 @@
*/
.contextual .contextual-links {
background-color: #fff;
- border: 1px solid #d6d6d6;
- border-radius: 4px 0 4px 4px; /* LTR */
+ border: 1px solid #ddd;
+ border-radius: 10px 0 10px 10px; /* LTR */
+ box-shadow: 1px 1px 2px rgba(0,0,0,0.3);
+ clear: both;
+ float: right; /* LTR */
margin: 0;
padding: 0.25em 0;
- position: absolute;
- right: 0; /* LTR */
- text-align: left;
- top: 18px;
+ position: relative;
+ right: 2px;
+ text-align: left; /* LTR */
+ top: -1px;
white-space: nowrap;
+ z-index: 1;
}
-/* Reset the li to prevent accidential overrides by a theme. */
+/* Reset the li to prevent accidental overrides by a theme. */
.contextual-region .contextual .contextual-links li {
background-color: #fff;
border: none;
@@ -65,14 +71,16 @@
list-style-image: none;
margin: 0;
padding: 0;
+ line-height: 100%;
}
.contextual-region .contextual .contextual-links a {
+ color: black !important;
display: block;
font-family: sans-serif;
font-size: small;
- line-height: 0.8em;
+ line-height: 1.8em;
margin: 0.25em 0;
- padding: 0.4em 0.8em 0.4em 0.6em; /* LTR */
+ padding: 0.4em 0.6em;
}
.contextual-region .contextual .contextual-links a,
.no-touch .contextual-region .contextual .contextual-links a:hover,
@@ -83,5 +91,7 @@
text-decoration: none;
}
.no-touch .contextual-region .contextual .contextual-links li a:hover {
- background-color: #bfdcee;
+ color: white;
+ background-image: -webkit-linear-gradient(rgb(78,159,234) 0%,rgb(65,126,210) 100%);
+ background-image: linear-gradient(rgb(78,159,234) 0%,rgb(65,126,210) 100%);
}
diff --git a/core/modules/edit/css/edit.css b/core/modules/edit/css/edit.css
index 37e10eb..ce3d19e 100644
--- a/core/modules/edit/css/edit.css
+++ b/core/modules/edit/css/edit.css
@@ -1,4 +1,32 @@
/**
+ * Pencil icon.
+ */
+.edit-toolbar-container .pencil {
+ background: #fff url(../../../misc/edit.png) no-repeat center center;
+ background-size: 16px 16px;
+ border: 1px solid #ddd;
+ border-radius: 13px;
+ -moz-box-shadow: 1px 1px 2px rgba(0,0,0,0.3);
+ -webkit-box-shadow: 1px 1px 2px rgba(0,0,0,0.3);
+ box-shadow: 1px 1px 2px rgba(0,0,0,0.3);
+ height: 26px;
+ width: 26px;
+ margin: 0;
+ outline: none;
+ overflow: hidden;
+ padding:0;
+ text-indent: 34px;
+ position: absolute;
+ right: 2px; /* LTR */
+ top: 2px;
+}
+
+.edit-toolbar-container.edit-editing .pencil {
+ display: none;
+}
+
+
+/**
* Animations.
*/
.edit-animate-invisible {
@@ -75,10 +103,10 @@
* Toolbar.
*/
.icon-edit:before {
- background-image: url("../images/icon-edit.png");
+ background-image: url("../../../misc/edit.png");
}
.icon-edit:active:before,
-.active .icon-edit:before {
+.active.icon-edit:before {
background-image: url("../images/icon-edit-active.png");
}
.toolbar .tray.edit.active {
@@ -106,8 +134,6 @@
z-index: 250;
width: 100%;
height: 100%;
- background-color: #fff;
- background-color: rgba(255,255,255,.5);
top: 0;
left: 0;
}
@@ -122,11 +148,18 @@
}
.edit-field.edit-editable,
.edit-field .edit-editable {
- box-shadow: 0 0 1px 1px #4d9de9;
+ /**
+ * In the latest design, there's no need to indicate candidates, since they
+ * now use pencil icons.
+ * This will probably be necessary again before release.
+ */
}
/* Highlighted (hovered) editable. */
.edit-editable.edit-highlighted {
+ z-index: 305;
+}
+.edit-editable.edit-highlighted {
min-width: 200px;
}
.edit-field.edit-editable.edit-highlighted,
@@ -279,6 +312,10 @@
bottom: 1px;
box-shadow: 0 0 1px 1px #0199ff, 0 0 3px 3px rgba(153, 153, 153, .5);
background: #fff;
+ display: none;
+}
+.edit-highlighted .edit-toolbar-heightfaker {
+ display: block;
}
/* The toolbar; these are not necessarily visible. */
diff --git a/core/modules/edit/js/createjs/editingWidgets/drupalcontenteditablewidget.js b/core/modules/edit/js/createjs/editingWidgets/drupalcontenteditablewidget.js
index 5671f39..caac604 100644
--- a/core/modules/edit/js/createjs/editingWidgets/drupalcontenteditablewidget.js
+++ b/core/modules/edit/js/createjs/editingWidgets/drupalcontenteditablewidget.js
@@ -29,13 +29,6 @@
_initialize: function() {
var that = this;
- // Sets the state to 'activated' upon clicking the element.
- this.element.on("click.edit", function(event) {
- event.stopPropagation();
- event.preventDefault();
- that.options.activated();
- });
-
// Sets the state to 'changed' whenever the content has changed.
var before = jQuery.trim(this.element.text());
this.element.on('keyup paste', function (event) {
@@ -68,6 +61,7 @@
case 'highlighted':
break;
case 'activating':
+ this.options.activated();
break;
case 'active':
// Sets the "contenteditable" attribute to "true".
diff --git a/core/modules/edit/js/createjs/editingWidgets/formwidget.js b/core/modules/edit/js/createjs/editingWidgets/formwidget.js
index 3238566..ac89857 100644
--- a/core/modules/edit/js/createjs/editingWidgets/formwidget.js
+++ b/core/modules/edit/js/createjs/editingWidgets/formwidget.js
@@ -29,15 +29,7 @@
/**
* Implements Create's _initialize() method.
*/
- _initialize: function() {
- // Sets the state to 'activating' upon clicking the element.
- var that = this;
- this.element.on("click.edit", function(event) {
- event.stopPropagation();
- event.preventDefault();
- that.options.activating();
- });
- },
+ _initialize: function() {},
/**
* Makes this PropertyEditor widget react to state changes.
diff --git a/core/modules/edit/js/views/menu-view.js b/core/modules/edit/js/views/menu-view.js
index ac7c4e4..0f9ecc8 100644
--- a/core/modules/edit/js/views/menu-view.js
+++ b/core/modules/edit/js/views/menu-view.js
@@ -64,6 +64,8 @@ Drupal.edit.views.MenuView = Backbone.View.extend({
Drupal.toolbar.setHeight();
}
}
+ // Let other modules respond to the edit mode change.
+ $(document).trigger('drupalEditMode', {'editable': !isViewing});
},
/**
* Handles clicks on the edit tab of the toolbar.
diff --git a/core/modules/edit/js/views/propertyeditordecoration-view.js b/core/modules/edit/js/views/propertyeditordecoration-view.js
index 0eb4e45..aabd72c 100644
--- a/core/modules/edit/js/views/propertyeditordecoration-view.js
+++ b/core/modules/edit/js/views/propertyeditordecoration-view.js
@@ -17,8 +17,6 @@ Drupal.edit.views.PropertyEditorDecorationView = Backbone.View.extend({
_widthAttributeIsEmpty: null,
events: {
- 'mouseenter.edit' : 'onMouseEnter',
- 'mouseleave.edit' : 'onMouseLeave',
'tabIn.edit': 'onMouseEnter',
'tabOut.edit': 'onMouseLeave'
},
diff --git a/core/modules/edit/js/views/toolbar-view.js b/core/modules/edit/js/views/toolbar-view.js
index 90f5db7..41e15ad 100644
--- a/core/modules/edit/js/views/toolbar-view.js
+++ b/core/modules/edit/js/views/toolbar-view.js
@@ -29,7 +29,10 @@ Drupal.edit.views.ToolbarView = Backbone.View.extend({
'click.edit button.label': 'onClickInfoLabel',
'mouseleave.edit': 'onMouseLeave',
'click.edit button.field-save': 'onClickSave',
- 'click.edit button.field-close': 'onClickClose'
+ 'click.edit button.field-close': 'onClickClose',
+ 'mouseenter .pencil': 'onPencilMouseEnter',
+ 'mouseleave .pencil': 'onPencilMouseLeave',
+ 'click .pencil': 'onPencilClick'
},
/**
@@ -66,19 +69,26 @@ Drupal.edit.views.ToolbarView = Backbone.View.extend({
stateChange: function(from, to) {
switch (to) {
case 'inactive':
- // Nothing happens in this stage.
+ if (from) {
+ this.remove();
+ }
break;
case 'candidate':
- if (from !== 'inactive') {
+ if (from === 'inactive') {
+ this.render();
+ }
+ else {
+ // Remove all toolgroups; they're no longer necessary.
+ this.$el
+ .removeClass('edit-highlighted edit-editing')
+ .find('.edit-toolbar .edit-toolgroup').remove();
if (from !== 'highlighted' && this.getEditUISetting('padding')) {
this._unpad();
}
- this.remove();
}
break;
case 'highlighted':
// As soon as we highlight, make sure we have a toolbar in the DOM (with at least a title).
- this.render();
this.startHighlight();
break;
case 'activating':
@@ -275,6 +285,7 @@ Drupal.edit.views.ToolbarView = Backbone.View.extend({
}
this.$el
+ .addClass('edit-highlighted')
.find('.edit-toolbar')
// Append the "info" toolgroup into the toolbar.
.append(Drupal.theme('editToolgroup', {
@@ -395,6 +406,10 @@ Drupal.edit.views.ToolbarView = Backbone.View.extend({
this.$el.insertBefore(this.editor.element);
}
+ // @todo: replace "Edit" with a proper (ARIA-like) string.
+ // @todo: ->