Popover content
@@ -83,22 +134,34 @@ describe("ouiPopover", () => {
`
);
- const rootElement = element[0].querySelector(".oui-popover");
- const $rootElement = angular.element(rootElement);
- const trigger = element[0].querySelector("[oui-popover-trigger]");
- const $trigger = angular.element(trigger);
- const closeButton = element[0].querySelector(".oui-popover__close-button");
- const $closeButton = angular.element(closeButton);
-
- expect($rootElement.hasClass("oui-popover_active")).toBeFalsy();
- $trigger.triggerHandler("click");
- expect($rootElement.hasClass("oui-popover_active")).toBeTruthy();
- $trigger.triggerHandler("click");
- expect($rootElement.hasClass("oui-popover_active")).toBeFalsy();
- $trigger.triggerHandler("click");
- expect($rootElement.hasClass("oui-popover_active")).toBeTruthy();
- $closeButton.triggerHandler("click");
- expect($rootElement.hasClass("oui-popover_active")).toBeFalsy();
+ $timeout.flush();
+
+ const controller = element.controller("ouiPopover");
+ controller.openPopover();
+
+ expect(controller.popper.options.placement).toEqual("bottom-start");
+ });
+
+ it("should set aria-expanded when trigger is clicked", () => {
+ const element = testUtils.compileTemplate(`
+
+
+
+ Popover content
+
+ `
+ );
+
+ $timeout.flush();
+
+ const trigger = angular.element(element[0].querySelector("[oui-popover-trigger]"));
+ expect(trigger.attr("aria-expanded")).toBe("false");
+
+ trigger.triggerHandler("click");
+ expect(trigger.attr("aria-expanded")).toBe("true");
+
+ trigger.triggerHandler("click");
+ expect(trigger.attr("aria-expanded")).toBe("false");
});
});
});
diff --git a/packages/oui-popover/src/popover-content.html b/packages/oui-popover/src/popover-content.html
deleted file mode 100644
index 6e784b4e..00000000
--- a/packages/oui-popover/src/popover-content.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
diff --git a/packages/oui-popover/src/popover-trigger.directive.js b/packages/oui-popover/src/popover-trigger.directive.js
deleted file mode 100644
index 485713fd..00000000
--- a/packages/oui-popover/src/popover-trigger.directive.js
+++ /dev/null
@@ -1,41 +0,0 @@
-const popoverTriggerClass = "oui-popover__trigger";
-
-export default () => {
- "ngInject";
-
- return {
- restrict: "AE",
- require: "^ouiPopover",
- scope: {},
- link: (scope, element, attrs, ctrl) => {
- const triggerElement = element;
-
- triggerElement.addClass(popoverTriggerClass);
-
- triggerElement.attr("id", ctrl.id);
- triggerElement.attr({ "aria-haspopup": true, "aria-expanded": false });
-
- triggerElement.on("click", () => ctrl.onTriggerClick());
-
- scope.$on("oui:popover:afterOpen", (e, id) => {
- if (id !== ctrl.id) {
- return;
- }
-
- triggerElement.attr("aria-expanded", true);
- });
-
- scope.$on("oui:popover:afterClose", (e, id) => {
- if (id !== ctrl.id) {
- return;
- }
-
- triggerElement.attr("aria-expanded", false);
- });
-
- scope.$on("$destroy", () => {
- triggerElement.off("click");
- });
- }
- };
-};
diff --git a/packages/oui-popover/src/popover.component.js b/packages/oui-popover/src/popover.component.js
deleted file mode 100644
index 6531221c..00000000
--- a/packages/oui-popover/src/popover.component.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import controller from "./popover.controller";
-import template from "./popover.html";
-
-export default {
- template,
- controller,
- bindings: {
- placement: "@?"
- },
- transclude: true
-};
diff --git a/packages/oui-popover/src/popover.controller.js b/packages/oui-popover/src/popover.controller.js
index b22df046..c7624775 100644
--- a/packages/oui-popover/src/popover.controller.js
+++ b/packages/oui-popover/src/popover.controller.js
@@ -1,39 +1,91 @@
+import { addDefaultParameter } from "@ovh-ui/common/component-utils";
import Popper from "popper.js";
+import template from "./popover.html";
const KEY_ESCAPE = 27;
export default class PopoverController {
- constructor ($scope, $element, $attrs, $document, $timeout) {
+ constructor ($attrs, $compile, $document, $element, $scope, $timeout) {
"ngInject";
- this.$scope = $scope;
- this.$element = $element;
this.$attrs = $attrs;
+ this.$compile = $compile;
this.$document = $document;
+ this.$element = $element;
+ this.$scope = $scope;
this.$timeout = $timeout;
}
$onInit () {
- this.isPopoverOpen = false;
+ // Deprecated: Support for component `oui-popover`
+ // Check if directive is an attribute or a component
+ this.isComponent = angular.isUndefined(this.$attrs.ouiPopover);
+
+ // Deprecated: Support for `placement` attribute
+ this.placement = this.placement || this.$attrs.placement;
- // Use internal id to map trigger
this.id = `ouiPopover${this.$scope.$id}`;
+ this.isPopoverOpen = false;
- if (angular.isUndefined(this.placement)) {
- this.placement = "right";
- }
+ addDefaultParameter(this, "placement", "right");
}
$postLink () {
- this.triggerElement = this.$element[0].querySelector(".oui-popover__trigger");
- this.popperElement = this.$element[0].querySelector(".oui-popover__content");
- this.arrowElement = this.$element[0].querySelector(".oui-popover__arrow");
+ this.setPopover();
+ this.setTrigger();
}
$destroy () {
this.closePopover();
}
+ setPopover () {
+ this.$timeout(() => {
+ // Deprecated: Support for component `oui-popover-content`
+ if (this.isComponent) {
+ this.popperElement = this.$element[0].querySelector(".oui-popover");
+ this.arrowElement = this.$element[0].querySelector(".oui-popover__arrow");
+ return;
+ }
+
+ // Support for attribute `oui-popover`
+ // Create a new scope to compile the popover next to the trigger
+ const popoverScope = angular.extend(this.$scope.$new(true), { $popoverCtrl: this });
+ const popoverTemplate = this.$compile(template)(popoverScope);
+
+ // Add compiled template after $element
+ this.$element
+ .removeAttr("title") // Remove title to avoid native tooltip
+ .after(popoverTemplate);
+
+ this.popperElement = this.$element.next()[0];
+ this.arrowElement = this.popperElement.querySelector(".oui-popover__arrow");
+ });
+ }
+
+ setTrigger () {
+ this.$timeout(() => {
+ // Deprecated: Support for component `oui-popover-trigger`
+ if (this.isComponent) {
+ this.triggerElement = this.$element[0].querySelector(".oui-popover__trigger");
+ this.$triggerElement = angular.element(this.triggerElement);
+ return;
+ }
+
+ // Support for attribute `oui-popover`
+ this.triggerElement = this.$element[0];
+ this.$triggerElement = angular.element(this.triggerElement);
+
+ this.$triggerElement
+ .addClass("oui-popover__trigger")
+ .attr({
+ "aria-haspopup": true,
+ "aria-expanded": false
+ })
+ .on("click", () => this.onTriggerClick());
+ });
+ }
+
onTriggerClick () {
if (!this.isPopoverOpen) {
this.openPopover();
@@ -52,20 +104,33 @@ export default class PopoverController {
openPopover () {
this.isPopoverOpen = true;
- angular.element(this.$element.children()[0]).addClass("oui-popover_active");
this.updatePopper();
this.$document.on("keydown", evt => this.triggerKeyHandler(evt));
- this.$scope.$broadcast("oui:popover:afterOpen", this.id);
+
+ // Deprecated: Support for component `oui-popover-trigger`
+ if (this.isComponent) {
+ this.$triggerElement.attr("aria-expanded", true);
+ return;
+ }
+
+ // Support for attribute `oui-popover`
+ this.$element.attr("aria-expanded", true);
}
closePopover () {
this.isPopoverOpen = false;
- angular.element(this.$element.children()[0]).removeClass("oui-popover_active");
- this.destroyPopper();
this.$document.off("keydown", evt => this.triggerKeyHandler(evt));
- this.$scope.$broadcast("oui:popover:afterClose", this.id);
+
+ // Deprecated: Support for component `oui-popover-trigger`
+ if (this.isComponent) {
+ this.$triggerElement.attr("aria-expanded", false);
+ return;
+ }
+
+ // Support for attribute `oui-popover`
+ this.$element.attr("aria-expanded", false);
}
createPopper () {
diff --git a/packages/oui-popover/src/popover.directive.js b/packages/oui-popover/src/popover.directive.js
new file mode 100644
index 00000000..b388e7d5
--- /dev/null
+++ b/packages/oui-popover/src/popover.directive.js
@@ -0,0 +1,17 @@
+import controller from "./popover.controller";
+
+export default () => {
+ "ngInject";
+
+ return {
+ restrict: "AE",
+ bindToController: {
+ text: "@ouiPopover",
+ title: "@?",
+ placement: "@?ouiPopoverPlacement",
+ template: "@?ouiPopoverTemplate"
+ },
+ controller,
+ controllerAs: "$popoverCtrl"
+ };
+};
diff --git a/packages/oui-popover/src/popover.html b/packages/oui-popover/src/popover.html
index ecfd3b09..460f5661 100644
--- a/packages/oui-popover/src/popover.html
+++ b/packages/oui-popover/src/popover.html
@@ -1,3 +1,18 @@
-
+
diff --git a/packages/oui-popover/src/trigger/popover-trigger.controller.js b/packages/oui-popover/src/trigger/popover-trigger.controller.js
new file mode 100644
index 00000000..9f664c2d
--- /dev/null
+++ b/packages/oui-popover/src/trigger/popover-trigger.controller.js
@@ -0,0 +1,26 @@
+// Deprecated: Support only for old use
+export default class {
+ constructor ($element, $scope, $timeout) {
+ "ngInject";
+
+ this.$element = $element;
+ this.$scope = $scope;
+ this.$timeout = $timeout;
+ }
+
+ $postLink () {
+ this.$timeout(() =>
+ this.$element
+ .addClass("oui-popover__trigger")
+ .attr({
+ "aria-haspopup": true,
+ "aria-expanded": false
+ })
+ .on("click", () => this.popover.onTriggerClick())
+ );
+ }
+
+ $onDestroy () {
+ this.$element.off("click");
+ }
+}
diff --git a/packages/oui-popover/src/trigger/popover-trigger.directive.js b/packages/oui-popover/src/trigger/popover-trigger.directive.js
new file mode 100644
index 00000000..78be2ab2
--- /dev/null
+++ b/packages/oui-popover/src/trigger/popover-trigger.directive.js
@@ -0,0 +1,16 @@
+import controller from "./popover-trigger.controller";
+
+// Deprecated: Support only for old use
+export default () => {
+ "ngInject";
+
+ return {
+ restrict: "AE",
+ require: {
+ popover: "^ouiPopover"
+ },
+ controller,
+ bindToController: true,
+ scope: {}
+ };
+};
diff --git a/packages/oui-tooltip/src/tooltip.controller.js b/packages/oui-tooltip/src/tooltip.controller.js
index 8f308029..93d9b64a 100644
--- a/packages/oui-tooltip/src/tooltip.controller.js
+++ b/packages/oui-tooltip/src/tooltip.controller.js
@@ -17,8 +17,11 @@ export default class {
addDefaultParameter(this, "placement", "top");
}
- $postLink () {
+ $onDestroy () {
+ this.destroyPopper();
+ }
+ $postLink () {
this.$timeout(() => {
if (this.title) {
addDefaultParameter(this, "text", this.title);
@@ -49,4 +52,13 @@ export default class {
placement: this.placement
});
}
+
+ destroyPopper () {
+ if (!this.popper) {
+ return;
+ }
+
+ this.popper.destroy();
+ this.popper = null;
+ }
}