--- /dev/null
+/**
+ * @file
+ * A Backbone View that provides the visual view of a contextual link.
+ */
+
+(function (Drupal, Backbone, Modernizr) {
+ Drupal.contextual.VisualView = Backbone.View.extend(/** @lends Drupal.contextual.VisualView# */{
+
+ /**
+ * Events for the Backbone view.
+ *
+ * @return {object}
+ * A mapping of events to be used in the view.
+ */
+ events() {
+ // Prevents delay and simulated mouse events.
+ const touchEndToClick = function (event) {
+ event.preventDefault();
+ event.target.click();
+ };
+ const mapping = {
+ 'click .trigger': function () {
+ this.model.toggleOpen();
+ },
+ 'touchend .trigger': touchEndToClick,
+ 'click .contextual-links a': function () {
+ this.model.close().blur();
+ },
+ 'touchend .contextual-links a': touchEndToClick,
+ };
+ // We only want mouse hover events on non-touch.
+ if (!Modernizr.touchevents) {
+ mapping.mouseenter = function () {
+ this.model.focus();
+ };
+ }
+ return mapping;
+ },
+
+ /**
+ * Renders the visual view of a contextual link. Listens to mouse & touch.
+ *
+ * @constructs
+ *
+ * @augments Backbone.View
+ */
+ initialize() {
+ this.listenTo(this.model, 'change', this.render);
+ },
+
+ /**
+ * @inheritdoc
+ *
+ * @return {Drupal.contextual.VisualView}
+ * The current contextual visual view.
+ */
+ render() {
+ const isOpen = this.model.get('isOpen');
+ // The trigger should be visible when:
+ // - the mouse hovered over the region,
+ // - the trigger is locked,
+ // - and for as long as the contextual menu is open.
+ const isVisible = this.model.get('isLocked') || this.model.get('regionIsHovered') || isOpen;
+
+ this.$el
+ // The open state determines if the links are visible.
+ .toggleClass('open', isOpen)
+ // Update the visibility of the trigger.
+ .find('.trigger').toggleClass('visually-hidden', !isVisible);
+
+ // Nested contextual region handling: hide any nested contextual triggers.
+ if ('isOpen' in this.model.changed) {
+ this.$el.closest('.contextual-region')
+ .find('.contextual .trigger:not(:first)')
+ .toggle(!isOpen);
+ }
+
+ return this;
+ },
+
+ });
+}(Drupal, Backbone, Modernizr));