core/misc/edit.png | 3 + core/modules/contextual/contextual.js | 47 ++++++++-- core/modules/contextual/contextual.theme.css | 33 ++++--- core/modules/edit/css/edit.css | 14 +-- core/modules/edit/edit.module | 11 +++ core/modules/edit/images/icon-edit-active.png | 7 +- core/modules/edit/images/icon-edit.png | 5 -- core/modules/edit/js/app.js | 42 ++++++--- .../editingWidgets/drupalcontenteditablewidget.js | 8 +- .../edit/js/createjs/editingWidgets/formwidget.js | 10 +-- core/modules/edit/js/models/edit-app-model.js | 1 + core/modules/edit/js/views/contextuallink-view.js | 94 ++++++++++++++++++++ core/modules/edit/js/views/menu-view.js | 22 +++++ .../edit/js/views/propertyeditordecoration-view.js | 20 +++++ core/modules/edit/js/views/toolbar-view.js | 18 ++-- .../node/lib/Drupal/node/NodeRenderController.php | 6 +- core/modules/node/node.module | 3 +- 17 files changed, 274 insertions(+), 70 deletions(-) diff --git a/core/misc/edit.png b/core/misc/edit.png new file mode 100644 index 0000000..d176245 --- /dev/null +++ b/core/misc/edit.png @@ -0,0 +1,3 @@ +PNG + + IHDR!-#IDATxڵ́@EєKH)%XHDDĀ(Fl,ᗐۻ0BI>80LҿfPԠȾjpŰG.E4־kdpa:Ǐǣ79Bp08OTYv;C n8!C fcp(#=^Uu%_V9T{l\Vy/X, E{n>Zwf5x@EQ  t:C[L&9jȳ/$UW5IENDB` \ No newline at end of file diff --git a/core/modules/contextual/contextual.js b/core/modules/contextual/contextual.js index dee63e6..67a333e 100644 --- a/core/modules/contextual/contextual.js +++ b/core/modules/contextual/contextual.js @@ -7,6 +7,8 @@ "use strict"; +var contextuals = []; + /** * Attaches outline behavior for regions associated with contextual links. */ @@ -14,7 +16,14 @@ Drupal.behaviors.contextual = { attach: function (context) { $('ul.contextual-links', context).once('contextual', function () { var $this = $(this); - $this.data('drupal-contextual', new Drupal.contextual($this, $this.closest('.contextual-region'))); + 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); }); } }; @@ -54,15 +63,32 @@ Drupal.contextual.prototype.init = function() { .attr('aria-pressed', false) .prependTo(this.$wrapper); - // Bind behaviors through delegation. - var highlightRegion = $.proxy(this.highlightRegion, this); + // The trigger behaviors are never detached or mutated. this.$region .on('click.contextual', '.contextual .trigger', $.proxy(this.triggerClickHandler, this)) - .on('mouseenter.contextual', {highlight: true}, highlightRegion) - .on('mouseleave.contextual', {highlight: false}, highlightRegion) .on('mouseleave.contextual', '.contextual', {show: false}, $.proxy(this.triggerLeaveHandler, this)) - .on('focus.contextual', '.contextual-links a, .contextual .trigger', {highlight: true}, highlightRegion) - .on('blur.contextual', '.contextual-links a, .contextual .trigger', {highlight: false}, highlightRegion); + // 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'); }; /** @@ -138,6 +164,13 @@ Drupal.contextual.prototype.showLinks = function(show) { }; +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. * diff --git a/core/modules/contextual/contextual.theme.css b/core/modules/contextual/contextual.theme.css index aca019c..ac6a1c4 100644 --- a/core/modules/contextual/contextual.theme.css +++ b/core/modules/contextual/contextual.theme.css @@ -21,28 +21,31 @@ * Contextual trigger. */ .contextual .trigger { - background: transparent url("images/gear-select.png") no-repeat 2px 0; - border: 1px solid transparent; - border-radius: 4px 4px 0 0; + background-attachment: scroll; + background-color: #ffffff; + background-image: url("../../misc/edit.png"); + background-position: center center; + background-repeat: no-repeat; + background-size: 16px 16px; + border: 1px solid #dddddd; + border-radius: 13px; + box-shadow: 1px 1px 2px rgba(0,0,0,0.3); /* Override the .element-focusable height: auto */ - height: 18px !important; + height: 28px !important; float: right; /* LTR */ margin: 0; overflow: hidden; padding: 0 2px; position: relative; - width: 34px; + right: 2px; + width: 28px; text-indent: -9999px; z-index: 2; } -.no-touch .contextual .trigger:hover, .contextual-links-active .trigger { - background-position: 2px -18px; -} -.contextual-links-active .trigger { - background-color: #fff; - border-bottom: none; - border-color: #d6d6d6; + border-bottom-color: transparent; + border-radius: 13px 13px 0 0; + box-shadow: none; } /** @@ -52,7 +55,7 @@ */ .contextual-region .contextual .contextual-links { background-color: #fff; - border: 1px solid #d6d6d6; + border: 1px solid #dddddd; border-radius: 4px 0 4px 4px; /* LTR */ clear: both; float: right; /* LTR */ @@ -90,5 +93,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..fcf8893 100644 --- a/core/modules/edit/css/edit.css +++ b/core/modules/edit/css/edit.css @@ -75,10 +75,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 { @@ -103,11 +103,10 @@ #edit_overlay { position: fixed; - z-index: 250; + /* @todo remove edit-overlay, not needed in this model */ + z-index: -200000; width: 100%; height: 100%; - background-color: #fff; - background-color: rgba(255,255,255,.5); top: 0; left: 0; } @@ -127,6 +126,7 @@ /* Highlighted (hovered) editable. */ .edit-editable.edit-highlighted { + z-index: 305; min-width: 200px; } .edit-field.edit-editable.edit-highlighted, @@ -279,6 +279,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/edit.module b/core/modules/edit/edit.module index 584cace..cb67596 100644 --- a/core/modules/edit/edit.module +++ b/core/modules/edit/edit.module @@ -98,6 +98,7 @@ function edit_library_info() { // Views. $path . '/js/views/propertyeditordecoration-view.js' => $options, $path . '/js/views/menu-view.js' => $options, + $path . '/js/views/contextuallink-view.js' => $options, $path . '/js/views/modal-view.js' => $options, $path . '/js/views/overlay-view.js' => $options, $path . '/js/views/toolbar-view.js' => $options, @@ -171,6 +172,16 @@ function edit_preprocess_field(&$variables) { } /** + * Implements hook_preprocess_HOOK() for node.tpl.php. + * + * @todo Move towards hook_preprocess_entity() once that's available. + */ +function edit_preprocess_node(&$variables) { + $node = $variables['elements']['#node']; + $variables['attributes']['data-edit-entity'] = 'node/' . $node->nid; +} + +/** * Form constructor for the field editing form. * * @ingroup forms diff --git a/core/modules/edit/images/icon-edit-active.png b/core/modules/edit/images/icon-edit-active.png index ad84761..a9143aa 100644 --- a/core/modules/edit/images/icon-edit-active.png +++ b/core/modules/edit/images/icon-edit-active.png @@ -1,3 +1,8 @@ PNG  - IHDRj `PLTE[tRNS@ P00p`ϟDƙIDATxe DQ8Ϩ/BDU9xV+D\?x@qWcF8wicS B}?v;Vf.V$JgX=Kضp0XS"iRw\:LL\~;Z5wu 5E)LIENDB` \ No newline at end of file + IHDR!-IDATxڭmP]”@ )(%PGܕHX@ JH<(4p|O%}y Y~ +tu&0hA+\l'Sv'`^+yX +)DsqV+9%FaHrTCͦs"6 +sPa%"y{{Soր=!_\Ay}O`|l0GE+! &hdY0'/M`NR!C2Nh~CR˂sW9yiH. "D0G\Od2Q +R>Hq.APa`0.h߹#.~_az&.w&Ha*ѿ +⹆ M0Gia MHn0GCNsn+Cժ a"BO+}37IENDB` \ No newline at end of file diff --git a/core/modules/edit/images/icon-edit.png b/core/modules/edit/images/icon-edit.png deleted file mode 100644 index 4f0dcc2..0000000 --- a/core/modules/edit/images/icon-edit.png +++ /dev/null @@ -1,5 +0,0 @@ -PNG - - IHDRj PLTE̻ʪ̡̜ˠ̣̽¼ǷʨªZ(e+tRNSϟ `π@`0p0p`0PϟϟcIDATxeW0{W -H"ʵ,y {Hpyo?mf,RBRxB vL;&LPJaRb\(Tbn(1wϔJ)ԈkS -58äT^4P6c}[i <ާ'-+HP>KIENDB` \ No newline at end of file diff --git a/core/modules/edit/js/app.js b/core/modules/edit/js/app.js index 00bba20..10c936b 100644 --- a/core/modules/edit/js/app.js +++ b/core/modules/edit/js/app.js @@ -60,7 +60,7 @@ }); // When view/edit mode is toggled in the menu, update the editor widgets. - this.model.on('change:isViewing', this.appStateChange); + this.model.on('change:activeEntity', this.appStateChange); }, /** @@ -74,7 +74,7 @@ */ findEditableProperties: function($context) { var that = this; - var newState = (this.model.get('isViewing')) ? 'inactive' : 'candidate'; + var activeEntity = this.model.get('activeEntity'); this.domService.findSubjectElements($context).each(function() { var $element = $(this); @@ -103,10 +103,17 @@ .on('destroyedPropertyEditor.edit', function(event, editor) { that.undecorateEditor(editor); that.$entityElements = that.$entityElements.not($(this)); - }) - // Transition the new PropertyEditor into the current state. - .createEditable('setState', newState); + // Transition the new PropertyEditor into the default state. + .createEditable('setState', 'inactive'); + + // If the new PropertyEditor is for the entity that's currently being + // edited, then transition it to the 'candidate' state. + // (This happens when a field was modified and is re-rendered.) + var entityOfProperty = $element.createEditable('option', 'model'); + if (entityOfProperty.getSubjectUri() === activeEntity) { + $element.createEditable('setState', 'candidate'); + } // Add this new EditableEntity widget element to the list. that.$entityElements = that.$entityElements.add($element); @@ -116,18 +123,30 @@ /** * Sets the state of PropertyEditor widgets when edit mode begins or ends. * - * Should be called whenever EditAppModel's "isViewing" changes. + * Should be called whenever EditAppModel's "activeEntity" changes. */ appStateChange: function() { // @todo: BLOCKED_ON(Create.js, https://github.com/bergie/create/issues/133, https://github.com/bergie/create/issues/140) // We're currently setting the state on EditableEntity widgets instead of // PropertyEditor widgets, because of // https://github.com/bergie/create/issues/133. - var newState = (this.model.get('isViewing')) ? 'inactive' : 'candidate'; + + var activeEntity = this.model.get('activeEntity'); + var $editableFieldsForEntity = $('[data-edit-id^="' + activeEntity + '/"]'); + + // First, change the status of all PropertyEditor widgets to 'inactive'. this.$entityElements.each(function() { - $(this).createEditable('setState', newState); + $(this).createEditable('setState', 'inactive', null, {reason: 'stop'}); }); + + // Then, change the status of PropertyEditor widgets of the currently + // active entity to 'candidate'. + $editableFieldsForEntity.each(function() { + $(this).createEditable('setState', 'candidate'); + }); + // Manage the page's tab indexes. + /* if (newState === 'candidate') { this._manageDocumentFocus(); Drupal.edit.setMessage(Drupal.t('In place edit mode is active'), Drupal.t('Page navigation is limited to editable items.'), Drupal.t('Press escape to exit')); @@ -136,6 +155,7 @@ this._releaseDocumentFocusManagement(); Drupal.edit.setMessage(Drupal.t('Edit mode is inactive.'), Drupal.t('Resume normal page navigation')); } + */ }, /** @@ -159,9 +179,9 @@ // If the app is in view mode, then reject all state changes except for // those to 'inactive'. - if (this.model.get('isViewing')) { - if (to !== 'inactive') { - accept = false; + if (context && context.reason === 'stop') { + if (from === 'candidate' && to === 'inactive') { + accept = true; } } // Handling of edit mode state changes is more granular. 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/models/edit-app-model.js b/core/modules/edit/js/models/edit-app-model.js index b6ff36f..1e4dcc6 100644 --- a/core/modules/edit/js/models/edit-app-model.js +++ b/core/modules/edit/js/models/edit-app-model.js @@ -12,6 +12,7 @@ Drupal.edit.models.EditAppModel = Backbone.Model.extend({ defaults: { // We always begin in view mode. isViewing: true, + activeEntity: null, highlightedEditor: null, activeEditor: null, // Reference to a ModalView-instance if a transition requires confirmation. diff --git a/core/modules/edit/js/views/contextuallink-view.js b/core/modules/edit/js/views/contextuallink-view.js new file mode 100644 index 0000000..cb6a2f6 --- /dev/null +++ b/core/modules/edit/js/views/contextuallink-view.js @@ -0,0 +1,94 @@ +/** + * @file + * A Backbone View that a dynamic contextual link. + */ +(function ($, _, Backbone, Drupal) { + +"use strict"; + +Drupal.edit = Drupal.edit || {}; +Drupal.edit.views = Drupal.edit.views || {}; +Drupal.edit.views.ContextualLinkView = Backbone.View.extend({ + + entity: null, + + events: { + 'click': 'onClick' + }, + + /** + * Implements Backbone Views' initialize() function. + * + * @param options + * An object with the following keys: + * - entity: the entity ID (e.g. node/1) of the entity + */ + initialize: function (options) { + this.entity = options.entity; + + // Initial render. + this.render(); + + // Re-render whenever the app state's active entity changes. + this.model.on('change:activeEntity', this.render, this); + }, + + /** + * Equates clicks anywhere on the overlay to clicking the active editor's (if + * any) "close" button. + * + * @param {Object} event + */ + onClick: function (event) { + event.preventDefault(); + + var that = this; + var updateActiveEntity = function() { + // The active entity is the current entity, i.e. stop editing the current + // entity. + if (that.model.get('activeEntity') === that.entity) { + that.model.set('activeEntity', null); + } + // The active entity is different from the current entity, i.e. start + // editing this entity instead of the previous one. + else { + that.model.set('activeEntity', that.entity); + } + }; + + // If there's an active editor, attempt to set its state to 'candidate', and + // only then do what the user asked. + // (Only when all PropertyEditor widgets of an entity are in the 'candidate' + // state, it is possible to stop editing it.) + var activeEditor = this.model.get('activeEditor'); + if (activeEditor) { + var editableEntity = activeEditor.options.widget; + var predicate = activeEditor.options.property; + editableEntity.setState('candidate', predicate, { reason: 'stop or switch' }, function(accepted) { + if (accepted) { + updateActiveEntity(); + } + else { + // No change. + } + }); + } + // Otherwise, we can immediately do what the user asked. + else { + updateActiveEntity(); + } + }, + + /** + * Render the "Quick edit" contextual link. + */ + render: function () { + var activeEntity = this.model.get('activeEntity'); + var string = (activeEntity !== this.entity) ? Drupal.t('Quick edit') : Drupal.t('Stop quick edit'); + this.$el.html('' + string + ''); + return this; + } + +}); + +})(jQuery, _, Backbone, Drupal); diff --git a/core/modules/edit/js/views/menu-view.js b/core/modules/edit/js/views/menu-view.js index ac7c4e4..d5e34d4 100644 --- a/core/modules/edit/js/views/menu-view.js +++ b/core/modules/edit/js/views/menu-view.js @@ -34,13 +34,33 @@ Drupal.edit.views.MenuView = Backbone.View.extend({ $('#toolbar-administration').on('click.edit', '.bar a:not(#toolbar-tab-edit)', _.bind(function (event) { this.model.set('isViewing', true); }, this)); + // We have to call stateChange() here because URL fragments are not passed // to the server, thus the wrong anchor may be marked as active. this.stateChange(); + + // Add "Quick edit" links to all contextual menus where editing the full + // node is possible. + // @todo Generalize this to work for all entities. + var that = this; + $('ul.contextual-links li.node-edit') + .before('
  • ') + .each(function() { + // Instantiate ContextualLinkView. + var $editContextualLink = $(this).prev(); + var editContextualLinkView = new Drupal.edit.views.ContextualLinkView({ + el: $editContextualLink.get(0), + model: that.model, + entity: $editContextualLink.parents('[data-edit-entity]').attr('data-edit-entity') + }); + }); }, /** * Listens to app state changes. + * + * @todo This stuff is all for the "Edit mode" toggle, which doesn't really + * belong in Edit.module anymore. */ stateChange: function() { var isViewing = this.model.get('isViewing'); @@ -64,6 +84,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..aad9832 100644 --- a/core/modules/edit/js/views/propertyeditordecoration-view.js +++ b/core/modules/edit/js/views/propertyeditordecoration-view.js @@ -19,6 +19,7 @@ Drupal.edit.views.PropertyEditorDecorationView = Backbone.View.extend({ events: { 'mouseenter.edit' : 'onMouseEnter', 'mouseleave.edit' : 'onMouseLeave', + 'click': 'onClick', 'tabIn.edit': 'onMouseEnter', 'tabOut.edit': 'onMouseLeave' }, @@ -38,7 +39,12 @@ Drupal.edit.views.PropertyEditorDecorationView = Backbone.View.extend({ this.editor = options.editor; this.toolbarId = options.toolbarId; + this.predicate = this.editor.options.property; + this.$el.css('background-color', this._getBgColor(this.$el)); + + // Only start listening to events as soon as we're no longer in the 'inactive' state. + this.undelegateEvents(); }, /** @@ -113,13 +119,27 @@ Drupal.edit.views.PropertyEditorDecorationView = Backbone.View.extend({ }); }, + /** + * Clicks: transition to 'activating' stage. + * + * @param event + */ + onClick: function(event) { + var editableEntity = this.editor.options.widget; + editableEntity.setState('activating', this.predicate); + event.preventDefault(); + event.stopPropagation(); + }, + decorate: function () { this.$el.addClass('edit-animate-fast edit-candidate edit-editable'); + this.delegateEvents(); }, undecorate: function () { this.$el .removeClass('edit-candidate edit-editable edit-highlighted edit-editing'); + this.undelegateEvents(); }, startHighlight: function () { diff --git a/core/modules/edit/js/views/toolbar-view.js b/core/modules/edit/js/views/toolbar-view.js index 90f5db7..b052362 100644 --- a/core/modules/edit/js/views/toolbar-view.js +++ b/core/modules/edit/js/views/toolbar-view.js @@ -29,7 +29,7 @@ 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', }, /** @@ -66,19 +66,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 +282,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', { diff --git a/core/modules/node/lib/Drupal/node/NodeRenderController.php b/core/modules/node/lib/Drupal/node/NodeRenderController.php index e829e40..6a6608a 100644 --- a/core/modules/node/lib/Drupal/node/NodeRenderController.php +++ b/core/modules/node/lib/Drupal/node/NodeRenderController.php @@ -88,11 +88,7 @@ public function buildContent(array $entities, array $displays, $view_mode, $lang */ protected function alterBuild(array &$build, EntityInterface $entity, EntityDisplay $display, $view_mode, $langcode = NULL) { parent::alterBuild($build, $entity, $display, $view_mode, $langcode); - // Add contextual links for this node, except when the node is already being - // displayed on its own page. Modules may alter this behavior (for example, - // to restrict contextual links to certain view modes) by implementing - // hook_node_view_alter(). - if (!empty($entity->nid) && !($view_mode == 'full' && node_is_page($entity))) { + if (!empty($entity->nid)) { $build['#contextual_links']['node'] = array('node', array($entity->nid)); } } diff --git a/core/modules/node/node.module b/core/modules/node/node.module index f2206a0..ff073ae 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -1769,7 +1769,7 @@ function node_menu() { 'access arguments' => array('update', 1), 'weight' => 0, 'type' => MENU_LOCAL_TASK, - 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE, + 'context' => MENU_CONTEXT_INLINE, 'file' => 'node.pages.inc', ); $items['node/%node/delete'] = array( @@ -1791,6 +1791,7 @@ function node_menu() { 'access arguments' => array(1), 'weight' => 2, 'type' => MENU_LOCAL_TASK, + 'context' => MENU_CONTEXT_INLINE, 'file' => 'node.pages.inc', ); $items['node/%node/revisions/%node_revision/view'] = array(