From 5139f590c88b78600c8e6891ce471f41d05ec81e Mon Sep 17 00:00:00 2001 From: FORESTIER Fabien <fabien.forestier@soprasteria.com> Date: Tue, 5 Nov 2019 15:04:26 +0100 Subject: [PATCH] Add copy link button on articles, add custom event tracking --- package-lock.json | 77 ++++++++++++++----- .../main/header/header.component.ts | 5 +- .../cms-post-detail.component.ts | 1 + .../components/home/home.component.html | 2 +- .../components/home/home.component.ts | 5 ++ .../page-header/page-header.component.html | 9 +++ .../page-header/page-header.component.scss | 9 +++ .../page-header/page-header.component.ts | 33 ++++++++ src/app/shared/models/cms-page.model.ts | 1 + src/i18n/traductions.fr.ts | 5 ++ src/i18n/traductions.ts | 5 ++ 11 files changed, 131 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index bde2edac..275a3c52 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "webapp", - "version": "2.3.1", + "version": "2.3.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1418,6 +1418,7 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "dev": true, + "optional": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -2673,7 +2674,8 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true + "dev": true, + "optional": true }, "constants-browserify": { "version": "1.0.0", @@ -3068,7 +3070,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true + "dev": true, + "optional": true }, "depd": { "version": "1.1.2", @@ -4127,7 +4130,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -4148,12 +4152,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4168,17 +4174,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -4295,7 +4304,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -4307,6 +4317,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4321,6 +4332,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4328,12 +4340,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -4352,6 +4366,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -4432,7 +4447,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -4444,6 +4460,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -4529,7 +4546,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -4565,6 +4583,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4584,6 +4603,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4627,12 +4647,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -4641,6 +4663,7 @@ "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", "dev": true, + "optional": true, "requires": { "graceful-fs": "^4.1.2", "inherits": "~2.0.0", @@ -4653,6 +4676,7 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, + "optional": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -4669,6 +4693,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4678,6 +4703,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4717,7 +4743,8 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true + "dev": true, + "optional": true }, "get-stream": { "version": "3.0.0", @@ -4965,7 +4992,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true + "dev": true, + "optional": true }, "has-value": { "version": "1.0.0", @@ -6400,6 +6428,7 @@ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, + "optional": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", @@ -6412,7 +6441,8 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "dev": true, + "optional": true } } }, @@ -6683,7 +6713,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true + "dev": true, + "optional": true }, "map-visit": { "version": "1.0.0", @@ -7385,6 +7416,7 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, + "optional": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -8556,6 +8588,7 @@ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, + "optional": true, "requires": { "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", @@ -8567,6 +8600,7 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, + "optional": true, "requires": { "graceful-fs": "^4.1.2", "pify": "^2.0.0", @@ -8577,7 +8611,8 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "dev": true, + "optional": true } } }, @@ -8586,6 +8621,7 @@ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, + "optional": true, "requires": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" @@ -8596,6 +8632,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, + "optional": true, "requires": { "path-exists": "^2.0.0", "pinkie-promise": "^2.0.0" @@ -8606,6 +8643,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, + "optional": true, "requires": { "pinkie-promise": "^2.0.0" } @@ -11678,6 +11716,7 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, + "optional": true, "requires": { "string-width": "^1.0.2 || 2" } diff --git a/src/app/core/components/main/header/header.component.ts b/src/app/core/components/main/header/header.component.ts index f7b496c2..aadc9987 100644 --- a/src/app/core/components/main/header/header.component.ts +++ b/src/app/core/components/main/header/header.component.ts @@ -1,9 +1,10 @@ -import { Component, OnInit, Output, EventEmitter } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { AppRoutes } from '../../../../routes'; import { DatasetResearchService } from '../../../../geosource/services'; import { Router, NavigationEnd } from '@angular/router'; import { UserService } from '../../../../user/services'; import { AppStateService } from '../../../services'; +import { Angulartics2Piwik } from 'angulartics2/piwik'; @Component({ selector: 'app-header', @@ -23,6 +24,7 @@ export class HeaderComponent implements OnInit { private _router: Router, private _userService: UserService, private _appStateService: AppStateService, + private _angulartics2Piwik: Angulartics2Piwik, ) { } ngOnInit() { @@ -48,6 +50,7 @@ export class HeaderComponent implements OnInit { toggleBurger() { this.isBurgerActive = !this.isBurgerActive; this._appStateService.changeMenuState(this.isBurgerActive); + this._angulartics2Piwik.eventTrack('BurgerMenu', { category: 'Navigation', label: 'BurgerManu', value: 1 }); } toggleUserDropdown() { diff --git a/src/app/editorialisation/components/cms-post-detail/cms-post-detail.component.ts b/src/app/editorialisation/components/cms-post-detail/cms-post-detail.component.ts index d916926c..c04ec94d 100644 --- a/src/app/editorialisation/components/cms-post-detail/cms-post-detail.component.ts +++ b/src/app/editorialisation/components/cms-post-detail/cms-post-detail.component.ts @@ -22,6 +22,7 @@ export class CMSPostDetailComponent implements OnInit { safePostContent: SafeHtml; pageHeaderInfo: IPageHeaderInfo = { title: '', + hasCopyLinkBtn: true, }; relations: { datasetsMetadata: Metadata[]; diff --git a/src/app/editorialisation/components/home/home.component.html b/src/app/editorialisation/components/home/home.component.html index 3de2090b..bdb35223 100644 --- a/src/app/editorialisation/components/home/home.component.html +++ b/src/app/editorialisation/components/home/home.component.html @@ -15,7 +15,7 @@ </div> <div class="search column is-7-desktop is-8-tablet "> <app-search-bar class="app-search-bar"></app-search-bar> - <a class="explore-link" [routerLink]="['/', AppRoutes.research.uri]"> + <a class="explore-link" [routerLink]="['/', AppRoutes.research.uri]" (click)="trackExploreButtonEvent()"> <button class="button explore-button" i18n="@@home.explore">Explore</button> </a> </div> diff --git a/src/app/editorialisation/components/home/home.component.ts b/src/app/editorialisation/components/home/home.component.ts index 15575e27..8991a565 100644 --- a/src/app/editorialisation/components/home/home.component.ts +++ b/src/app/editorialisation/components/home/home.component.ts @@ -9,6 +9,7 @@ import { forkJoin } from 'rxjs/internal/observable/forkJoin'; import { NotificationService } from '../../../core/services'; import { Notification } from '../../../core/models'; import { notificationMessages } from '../../../../i18n/traductions'; +import { Angulartics2Piwik } from 'angulartics2/piwik'; @Component({ selector: 'app-home', @@ -34,6 +35,7 @@ export class HomeComponent implements OnInit { private _datasetResearchService: DatasetResearchService, private _notificationService: NotificationService, private _router: Router, + private _angulartics2Piwik: Angulartics2Piwik, ) { } ngOnInit() { @@ -100,4 +102,7 @@ export class HomeComponent implements OnInit { this._router.navigate(['/', AppRoutes.research.uri]); } + trackExploreButtonEvent() { + this._angulartics2Piwik.eventTrack('ExploreButton', { category: 'HomePage', label: 'Explore', value: 1 }); + } } diff --git a/src/app/shared/components/page-header/page-header.component.html b/src/app/shared/components/page-header/page-header.component.html index 70e7aa65..d88d1bc2 100644 --- a/src/app/shared/components/page-header/page-header.component.html +++ b/src/app/shared/components/page-header/page-header.component.html @@ -17,4 +17,13 @@ <span>{{ pageInfo.subtitle }}</span> </div> </div> + + <button *ngIf="pageInfo.hasCopyLinkBtn" class="button copy-link-button has-tooltip-left tooltip" type="button" + (click)="copyToClipboard()" [attr.data-tooltip]="messageClipboard"> + <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" viewBox="0 0 20 20"> + <path fill="#818080" fill-rule="evenodd" + d="M1.852 7.777a2.619 2.619 0 0 1 0-3.703l2.222-2.222a2.619 2.619 0 0 1 3.704 0l2.963 2.963a2.619 2.619 0 0 1 0 3.703l-.37.37.74.741.37-.37a2.619 2.619 0 0 1 3.704 0l2.963 2.963a2.619 2.619 0 0 1 0 3.704l-2.222 2.222a2.619 2.619 0 0 1-3.704 0L9.26 15.185a2.619 2.619 0 0 1 0-3.704l.37-.37-.74-.741-.37.37a2.619 2.619 0 0 1-3.704 0L1.852 7.777zm7.037-.37l-.74-.74a1.048 1.048 0 0 0-1.482 1.48l.74.742-.37.37a.524.524 0 0 1-.74 0L3.332 6.296a.524.524 0 0 1 0-.74l2.223-2.223a.524.524 0 0 1 .74 0L9.26 6.296a.524.524 0 0 1 0 .74l-.37.371zm2.222 5.185l-.37.37a.524.524 0 0 0 0 .742l2.963 2.962a.524.524 0 0 0 .74 0l2.223-2.222a.524.524 0 0 0 0-.74l-2.963-2.963a.524.524 0 0 0-.741 0l-.37.37.74.74a1.047 1.047 0 1 1-1.481 1.482l-.74-.74z" + clip-rule="evenodd" /> + </svg> + </button> </div> \ No newline at end of file diff --git a/src/app/shared/components/page-header/page-header.component.scss b/src/app/shared/components/page-header/page-header.component.scss index 73b4cc65..208fe83c 100644 --- a/src/app/shared/components/page-header/page-header.component.scss +++ b/src/app/shared/components/page-header/page-header.component.scss @@ -96,3 +96,12 @@ line-height: 1.15; color: $brand-color; } + +.copy-link-button { + position: absolute; + top: 10px; + right: 10px; + padding: 0; + height: 2.25rem; + width: 2.25rem; +} \ No newline at end of file diff --git a/src/app/shared/components/page-header/page-header.component.ts b/src/app/shared/components/page-header/page-header.component.ts index 7f189915..5e83e1ba 100644 --- a/src/app/shared/components/page-header/page-header.component.ts +++ b/src/app/shared/components/page-header/page-header.component.ts @@ -3,6 +3,9 @@ import { Router } from '@angular/router'; import { AppRoutes } from '../../../routes'; import { NavigationHistoryService } from '../../../core/services'; import { IPageHeaderInfo } from '../../models'; +import { buttonCopyLinkToCliboardMessages } from '../../../../i18n/traductions'; +import { Angulartics2Piwik } from 'angulartics2/piwik'; + @Component({ selector: 'app-page-header', @@ -14,10 +17,12 @@ export class PageHeaderComponent implements OnInit { constructor( private _navigationHistoryService: NavigationHistoryService, private _router: Router, + private _angulartics2Piwik: Angulartics2Piwik, ) { } @Input() pageInfo: IPageHeaderInfo; @Input() customGoToPreviousPage: any; + messageClipboard: string = buttonCopyLinkToCliboardMessages.hover; ngOnInit() { } @@ -36,4 +41,32 @@ export class PageHeaderComponent implements OnInit { } } + copyToClipboard() { + const el = document.createElement('input'); // Create a <input> element + el.value = window.location.href; // Set its value to the string that you want copied + el.setAttribute('readonly', ''); // Make it readonly to be tamper-proof + el.style.position = 'absolute'; + el.style.left = '-9999px'; // Move outside the screen to make it invisible + document.body.appendChild(el); // Append the <input> element to the HTML document + const selected = + document.getSelection().rangeCount > 0 // Check if there is any content selected previously + ? document.getSelection().getRangeAt(0) // Store selection if found + : false; // Mark as false to know no selection existed before + el.select(); // Select the <input> content + document.execCommand('copy'); // Copy - only works as a result of a user action (e.g. click events) + document.body.removeChild(el); // Remove the <input> element + if (selected) { // If a selection existed before copying + document.getSelection().removeAllRanges(); // Unselect everything on the HTML document + document.getSelection().addRange(selected); // Restore the original selection + } + this.messageClipboard = buttonCopyLinkToCliboardMessages.copied; + + this._angulartics2Piwik.eventTrack('ShareArticle', { category: 'Edito', label: window.location.href, value: 1}); + + setTimeout(() => { + this.messageClipboard = buttonCopyLinkToCliboardMessages.hover; + // tslint:disable-next-line:align + }, 2000); + } + } diff --git a/src/app/shared/models/cms-page.model.ts b/src/app/shared/models/cms-page.model.ts index 9c84a9c1..49254ac9 100644 --- a/src/app/shared/models/cms-page.model.ts +++ b/src/app/shared/models/cms-page.model.ts @@ -4,6 +4,7 @@ export interface IPageHeaderInfo { surtitle?: string; subtitle?: string; hasBetaStyle?: boolean; + hasCopyLinkBtn?: boolean } export interface ICMSPageLinks { diff --git a/src/i18n/traductions.fr.ts b/src/i18n/traductions.fr.ts index 9b158ebe..c26dfe31 100644 --- a/src/i18n/traductions.fr.ts +++ b/src/i18n/traductions.fr.ts @@ -308,3 +308,8 @@ export const reusesTypes = { web: 'Site web', article: 'Article', }; + +export const buttonCopyLinkToCliboardMessages = { + hover: 'Copier le lien', + copied: 'CopiƩ !' +}; diff --git a/src/i18n/traductions.ts b/src/i18n/traductions.ts index 307b72d9..84dfc34c 100644 --- a/src/i18n/traductions.ts +++ b/src/i18n/traductions.ts @@ -308,3 +308,8 @@ export const reusesTypes = { web: 'Website', article: 'Article', }; + +export const buttonCopyLinkToCliboardMessages = { + hover: 'Copy the link', + copied: 'Copied!' +}; -- GitLab