1
1
import { sha256 } from 'js-sha256' ;
2
- import showQuickEditor from '../shared/show- quick-editor' ;
2
+ import { GravatarQuickEditorCore } from '@gravatar-com/ quick-editor' ;
3
3
import { Hovercards } from '@gravatar-com/hovercards' ;
4
+ import trackEvent from '../shared/analytics' ;
5
+ import updateAvatars from '../shared/update-avatars' ;
6
+ import { adjustGravatarPosition , fetchUserProfile , suggestProfile , hideProfile , showProfile } from './profile' ;
7
+ import { GRAVATAR_CONTAINER , COMMENT_EMAIL_WRAPPER , COMMENT_EMAIL_FIELD } from './constants' ;
4
8
import './style.scss' ;
5
9
6
- const BASE_API_URL = 'https://api.gravatar.com/v3/profiles' ;
7
- const GRAVATAR_CONTAINER = '.gravatar-enhanced-profile' ;
8
- const COMMENT_EMAIL_WRAPPER = '.comment-form-email' ;
9
- const COMMENT_EMAIL_FIELD = '#email' ;
10
10
const INPUT_TIMEOUT = 1000 ;
11
11
12
- const hovercards = new Hovercards ( ) ;
13
-
14
- function isEmail ( email ) {
12
+ function isEmail ( email : string ) {
15
13
const emailRegex = / ^ [ ^ \s @ ] + @ [ ^ \s @ ] + \. [ ^ \s @ ] + $ / ;
16
14
return emailRegex . test ( email ) ;
17
15
}
18
16
19
- async function fetchUserProfile ( email ) {
20
- const hash = sha256 ( email . trim ( ) . toLowerCase ( ) ) ;
21
-
22
- try {
23
- // Get profile data
24
- const response = await fetch ( `${ BASE_API_URL } /${ hash } ?source=hovercard` ) ;
25
- if ( ! response . ok ) {
26
- return null ;
27
- }
28
-
29
- return await response . json ( ) ;
30
- } catch ( error ) {
31
- // eslint-disable-next-line no-console
32
- console . error ( error ) ;
33
- }
34
-
35
- return null ;
36
- }
37
-
38
- function suggestProfile ( profile ) {
39
- const author = document . getElementById ( 'author' ) as HTMLInputElement ;
40
- const url = document . getElementById ( 'url' ) as HTMLInputElement ;
41
- const profileUrl = profile . profile_url ;
42
-
43
- if ( author && author . value === '' ) {
44
- author . value = profile . display_name ;
45
- }
46
-
47
- if ( url && url . value === '' && profileUrl ) {
48
- url . value = profileUrl ;
49
- }
50
- }
51
-
52
- function hideProfile ( ) {
53
- const emailContainer = document . querySelector ( '.comment-form-email' ) as HTMLInputElement ;
54
- const emailField = document . querySelector ( COMMENT_EMAIL_FIELD ) as HTMLInputElement ;
55
-
56
- if ( ! emailField || ! emailContainer ) {
57
- return ;
58
- }
59
-
60
- emailContainer . classList . remove ( 'gravatar-enhanced-comments' ) ;
61
- emailField . style . paddingLeft = '' ;
62
- }
63
-
64
- function adjustGravatarPosition ( ) {
65
- const gravatarProfile = document . querySelector ( GRAVATAR_CONTAINER ) as HTMLSpanElement ;
66
- const emailContainer = document . querySelector ( '.comment-form-email' ) as HTMLInputElement ;
67
- const emailField = document . querySelector ( COMMENT_EMAIL_FIELD ) as HTMLInputElement ;
68
-
69
- if ( ! gravatarProfile || ! emailField || ! emailContainer ) {
70
- return ;
71
- }
72
-
73
- // Measure the email field
74
- const computedStyle = getComputedStyle ( emailField ) ;
75
- const padding = parseInt ( computedStyle . paddingTop , 10 ) + parseInt ( computedStyle . borderTopWidth , 10 ) ;
76
- const emailFieldRect = emailField . getBoundingClientRect ( ) ;
77
- const emailContainerRect = emailContainer . getBoundingClientRect ( ) ;
78
- const topRectOffset = emailFieldRect . top - emailContainerRect . top ;
79
- const leftRectOffset = emailFieldRect . left - emailContainerRect . left ;
80
- const height = parseFloat ( ( emailFieldRect . height * 0.8 ) . toFixed ( 1 ) ) ;
81
- const heightDifference = parseFloat ( ( emailFieldRect . height - height ) . toFixed ( 1 ) ) ;
82
- const leftOffset = parseFloat (
83
- ( leftRectOffset + padding / 2 + parseInt ( computedStyle . borderLeftWidth ) ) . toFixed ( 1 )
84
- ) ;
85
- const topOffset = parseFloat ( ( topRectOffset + heightDifference / 2 ) . toFixed ( 1 ) ) ;
86
-
87
- // Position the Gravatar inside the text field
88
- gravatarProfile . style . height = height + 'px' ;
89
- gravatarProfile . style . width = height + 'px' ;
90
- gravatarProfile . style . top = topOffset + 'px' ;
91
- gravatarProfile . style . left = leftOffset + 'px' ;
92
-
93
- // Move the text up to allow the Gravatar to fit
94
- emailField . style . paddingLeft = parseFloat ( ( height + padding * 1.3 ) . toFixed ( 1 ) ) + 'px' ;
95
- }
96
-
97
- function showProfile ( profile , isShowingEditor ) {
98
- const gravatarImg = document . querySelector ( GRAVATAR_CONTAINER + ' img' ) as HTMLImageElement ;
99
- const emailContainer = document . querySelector ( COMMENT_EMAIL_WRAPPER ) as HTMLInputElement ;
100
-
101
- if ( ! gravatarImg || ! emailContainer ) {
102
- return ;
103
- }
104
-
105
- gravatarImg . src = profile . avatar_url ;
106
- emailContainer . classList . add ( 'gravatar-enhanced-comments' ) ;
107
-
108
- adjustGravatarPosition ( ) ;
109
-
110
- // Hook up to hovercard
111
- hovercards . attach ( gravatarImg , {
112
- onCanShowHovercard : ( ) => {
113
- return ! isShowingEditor ( ) ;
114
- } ,
115
- } ) ;
116
- }
117
-
118
17
document . addEventListener ( 'DOMContentLoaded' , ( ) => {
119
18
const email = document . querySelector ( COMMENT_EMAIL_FIELD ) as HTMLInputElement ;
120
19
const qeButton = document . querySelector ( GRAVATAR_CONTAINER + ' img' ) ;
121
20
let lastRequestEmail = '' ;
21
+ let lastRequestUrl = '' ;
22
+ let lastRequestName = '' ;
122
23
let debounceProfileTimeout : NodeJS . Timeout ;
123
- let isShowingEditor = false ;
24
+ let quickEditor = null ;
25
+
26
+ const hovercards = new Hovercards ( {
27
+ onCanShowHovercard : ( ) => {
28
+ return quickEditor === null || ! quickEditor . isOpen ( ) ;
29
+ } ,
30
+ } ) ;
124
31
125
32
const loadProfile = async ( event ) => {
126
33
clearTimeout ( debounceProfileTimeout ) ;
@@ -141,16 +48,19 @@ document.addEventListener( 'DOMContentLoaded', () => {
141
48
lastRequestEmail = emailValue ;
142
49
143
50
if ( profile ) {
144
- suggestProfile ( profile ) ;
145
- showProfile ( profile , ( ) => isShowingEditor ) ;
51
+ suggestProfile ( profile , lastRequestUrl , lastRequestName ) ;
52
+ showProfile ( profile , hovercards ) ;
53
+
54
+ lastRequestUrl = profile . profile_url ;
55
+ lastRequestName = profile . display_name ;
146
56
} else {
147
57
showProfile (
148
58
{
149
59
display_name : '' ,
150
60
profile_url : '' ,
151
61
avatar_url : 'https://gravatar.com/avatar/' + sha256 ( emailValue . trim ( ) . toLowerCase ( ) ) ,
152
62
} ,
153
- ( ) => isShowingEditor
63
+ hovercards
154
64
) ;
155
65
}
156
66
} ;
@@ -159,21 +69,29 @@ document.addEventListener( 'DOMContentLoaded', () => {
159
69
email ?. addEventListener ( 'input' , ( ev ) => {
160
70
clearTimeout ( debounceProfileTimeout ) ;
161
71
debounceProfileTimeout = setTimeout ( ( ) => loadProfile ( ev ) , INPUT_TIMEOUT ) ;
72
+
73
+ // If the email is changed then close any QE and clear the instance
74
+ if ( quickEditor ) {
75
+ quickEditor . close ( ) ;
76
+ quickEditor = null ;
77
+ }
162
78
} ) ;
163
79
164
80
// Hook up the image to the QE
165
81
qeButton ?. addEventListener ( 'click' , ( ) => {
166
- isShowingEditor = true ;
167
-
168
- showQuickEditor (
169
- email ?. value || gravatarEnhancedComments ?. email || '' ,
170
- gravatarEnhancedComments ?. locale || 'en' ,
171
- [ 'avatars' ] ,
172
- GRAVATAR_CONTAINER + ' img' ,
173
- ( ) => {
174
- isShowingEditor = false ;
175
- }
176
- ) ;
82
+ if ( ! quickEditor ) {
83
+ quickEditor = new GravatarQuickEditorCore ( {
84
+ email : email ?. value || gravatarEnhancedComments ?. email || '' ,
85
+ scope : [ 'avatars' ] ,
86
+ locale : gravatarEnhancedComments ?. locale || 'en' ,
87
+ onProfileUpdated : ( ) => {
88
+ trackEvent ( 'gravatar_enhanced_qe_avatar_updated' ) ;
89
+ updateAvatars ( GRAVATAR_CONTAINER + ' img' ) ;
90
+ } ,
91
+ } ) ;
92
+ }
93
+
94
+ quickEditor . open ( ) ;
177
95
} ) ;
178
96
179
97
// Reposition the avatar on resize - it can get slightly out of place
0 commit comments