Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(821)

Side by Side Diff: ui/login/account_picker/user_pod_row.js

Issue 446743003: Hook up new API for easy unlock to update lock screen (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @fileoverview User pod row implementation. 6 * @fileoverview User pod row implementation.
7 */ 7 */
8 8
9 cr.define('login', function() { 9 cr.define('login', function() {
10 /** 10 /**
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 * Variables used for pod placement processing. Width and height should be 48 * Variables used for pod placement processing. Width and height should be
49 * synced with computed CSS sizes of pods. 49 * synced with computed CSS sizes of pods.
50 */ 50 */
51 var POD_WIDTH = 180; 51 var POD_WIDTH = 180;
52 var PUBLIC_EXPANDED_BASIC_WIDTH = 500; 52 var PUBLIC_EXPANDED_BASIC_WIDTH = 500;
53 var PUBLIC_EXPANDED_ADVANCED_WIDTH = 610; 53 var PUBLIC_EXPANDED_ADVANCED_WIDTH = 610;
54 var CROS_POD_HEIGHT = 213; 54 var CROS_POD_HEIGHT = 213;
55 var DESKTOP_POD_HEIGHT = 226; 55 var DESKTOP_POD_HEIGHT = 226;
56 var POD_ROW_PADDING = 10; 56 var POD_ROW_PADDING = 10;
57 var DESKTOP_ROW_PADDING = 15; 57 var DESKTOP_ROW_PADDING = 15;
58 var CUSTOM_ICON_CONTAINER_SIZE = 40;
58 59
59 /** 60 /**
60 * Minimal padding between user pod and virtual keyboard. 61 * Minimal padding between user pod and virtual keyboard.
61 * @type {number} 62 * @type {number}
62 * @const 63 * @const
63 */ 64 */
64 var USER_POD_KEYBOARD_MIN_PADDING = 20; 65 var USER_POD_KEYBOARD_MIN_PADDING = 20;
65 66
66 /** 67 /**
67 * Maximum time for which the pod row remains hidden until all user images 68 * Maximum time for which the pod row remains hidden until all user images
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 * Stops event propagation from the any user pod child element. 153 * Stops event propagation from the any user pod child element.
153 * @param {Event} e Event to handle. 154 * @param {Event} e Event to handle.
154 */ 155 */
155 function stopEventPropagation(e) { 156 function stopEventPropagation(e) {
156 // Prevent default so that we don't trigger a 'focus' event. 157 // Prevent default so that we don't trigger a 'focus' event.
157 e.preventDefault(); 158 e.preventDefault();
158 e.stopPropagation(); 159 e.stopPropagation();
159 } 160 }
160 161
161 /** 162 /**
163 * Creates an element for custom icon shown in a user pod next to the input
164 * field.
165 * @constructor
166 * @extends {HTMLDivElement}
167 */
168 var UserPodCustomIcon = cr.ui.define(function() {
169 var node = document.createElement('div');
170 node.classList.add('custom-icon-container');
171 node.hidden = true;
172
173 // Create the actual icon element and add it as a child to the container.
174 var iconNode = document.createElement('div');
175 iconNode.classList.add('custom-icon');
176 node.appendChild(iconNode);
177 return node;
178 });
179
180 UserPodCustomIcon.prototype = {
181 __proto__: HTMLDivElement.prototype,
182
183 /**
184 * The icon height.
185 * @type {number}
186 * @private
187 */
188 height_: 0,
189
190 /**
191 * The icon width.
192 * @type {number}
193 * @private
194 */
195 width_: 0,
196
197 /**
198 * Tooltip to be shown when the user hovers over the icon. The icon
199 * properties may be set so the tooltip is shown automatically when the icon
200 * is updated. The tooltip is shown in a bubble attached to the icon
201 * element.
202 * @type {string}
203 * @private
204 */
205 tooltip_: '',
206
207 /**
208 * Whether the tooltip is shown and the user is hovering over the icon.
209 * @type {boolean}
210 * @private
211 */
212 tooltipActive_: false,
213
214 /**
215 * Whether the icon has been shown as a result of |autoshow| parameter begin
216 * set rather than user hovering over the icon.
217 * If this is set, the tooltip will not be removed when the mouse leaves the
218 * icon.
219 * @type {boolean}
220 * @private
221 */
222 tooltipAutoshown_: false,
223
224 /**
225 * A reference to the timeout for showing tooltip after mouse enters the
226 * icon.
227 * @type {?number}
228 * @private
229 */
230 showTooltipTimeout_: null,
231
232 /**
233 * If animation is set, the current horizontal background offset for the
234 * icon resource.
235 * @type {number}
236 * @private
237 */
238 lastAnimationOffset_: 0,
239
240 /**
241 * The reference to interval for progressing the animation.
242 * @type {?number}
243 * @private
244 */
245 animationInterval_: null,
246
247 /**
248 * The width of the resource that contains representations for different
249 * animation stages.
250 * @type {number}
251 * @private
252 */
253 animationResourceSize_: 0,
254
255 /** @override */
256 decorate: function() {
257 this.iconElement.addEventListener('mouseover',
258 this.showTooltipSoon_.bind(this));
259 this.iconElement.addEventListener('mouseout',
260 this.hideTooltip_.bind(this, false));
261 this.iconElement.addEventListener('mousedown',
262 this.hideTooltip_.bind(this, false));
263 },
264
265 /**
266 * Getter for the icon element's div.
267 * @return {HTMLDivElement}
268 */
269 get iconElement() {
270 return this.querySelector('.custom-icon');
271 },
272
273 /**
274 * Set the icon's background image as image set with different
275 * representations for available screen scale factors.
276 * @param {!{scale1x: string, scale2x: string}} icon The icon
277 * representations.
278 */
279 setIconAsImageSet: function(icon) {
280 this.iconElement.style.backgroundImage =
281 '-webkit-image-set(' +
282 'url(' + icon.scale1x + ') 1x,' +
283 'url(' + icon.scale2x + ') 2x)';
284 },
285
286 /**
287 * Sets the icon background image to a chrome://theme URL.
288 * @param {!string} iconUrl The icon's background image URL.
289 */
290 setIconAsResourceUrl: function(iconUrl) {
291 this.iconElement.style.backgroundImage =
292 '-webkit-image-set(' +
293 'url(' + iconUrl + '@1x) 1x,' +
294 'url(' + iconUrl + '@2x) 2x)';
295 },
296
297 /**
298 * Shows the icon.
299 */
300 show: function() {
301 this.hidden = false;
302 },
303
304 /**
305 * Hides the icon. Makes sure the tooltip is hidden and animation reset.
306 */
307 hide: function() {
308 this.hideTooltip_(true);
309 this.setAnimation(null);
310 this.hidden = true;
311 },
312
313 /**
314 * Sets the icon size element size.
315 * @param {!{width: number, height: number}} size The icon size.
316 */
317 setSize: function(size) {
318 this.height_ = size.height < CUSTOM_ICON_CONTAINER_SIZE ?
319 size.height : CUSTOM_ICON_COTAINER_SIZE;
320 this.iconElement.style.height = this.height_ + 'px';
321
322 this.width_ = size.width < CUSTOM_ICON_CONTAINER_SIZE ?
323 size.width : CUSTOM_ICON_COTAINER_SIZE;
324 this.iconElement.style.width = this.width_ + 'px';
325 },
326
327 /**
328 * Sets the icon opacity.
329 * @param {number} opacity The icon opacity in [0-100] scale.
330 */
331 setOpacity: function(opacity) {
332 if (opacity > 100) {
333 this.style.opacity = 1;
334 } else if (opacity < 0) {
335 this.style.opacity = 0;
336 } else {
337 this.style.opacity = opacity / 100;
338 }
339 },
340
341 /**
342 * Updates the icon tooltip. If {@code autoshow} parameter is set the
343 * tooltip is immediatelly shown. If tooltip text is not set, the method
344 * ensures the tooltip gets hidden. If tooltip is shown prior to this call,
345 * it remains shown, but the tooltip text is updated.
346 * @param {!{text: string, autoshow: boolean}} tooltip The tooltip
347 * parameters.
348 */
349 setTooltip: function(tooltip) {
350 if (this.tooltip_ == tooltip.text && !tooltip.autoshow)
351 return;
352 this.tooltip_ = tooltip.text;
353
354 // If tooltip is already shown, just update the text.
355 if (tooltip.text && this.tooltipActive_ && !$('bubble').hidden) {
356 // If both previous and the new tooltip are supposed to be shown
357 // automatically, keep the autoshown flag.
358 var markAutoshown = this.tooltipAutoshown_ && tooltip.autoshow;
359 this.hideTooltip_(true);
360 this.showTooltip_();
361 this.tooltipAutoshown_ = markAutoshown;
362 return;
363 }
364
365 // If autoshow flag is set, make sure the tooltip gets shown.
366 if (tooltip.text && tooltip.autoshow) {
367 this.hideTooltip_(true);
368 this.showTooltip_();
369 this.tooltipAutoshown_ = true;
370 // Reset the tooltip active flag, which gets set in |showTooltip_|.
371 this.tooltipActive_ = false;
372 return;
373 }
374
375 this.hideTooltip_(true);
376
377 if (this.tooltip_)
378 this.iconElement.setAttribute('aria-lablel', this.tooltip_);
379 },
380
381 /**
382 * Sets the icon animation parameter and starts the animation.
383 * The animation is set using the resource containing all animation frames
384 * concatenated horizontally. The animator offsets the background image in
385 * regural intervals.
386 * @param {?{resourceWidth: number, frameLengthMs: number}} animation
387 * |resourceWidth|: Total width for the resource containing the
388 * animation frames.
389 * |frameLengthMs|: Time interval for which a single animation frame is
390 * shown.
391 */
392 setAnimation: function(animation) {
393 if (this.animationInterval_)
394 clearInterval(this.animationInterval_);
395 this.iconElement.style.backgroundPosition = 'center';
396 if (!animation)
397 return;
398 this.lastAnimationOffset_ = 0;
399 this.animationResourceSize_ = animation.resourceWidth;
400 this.animationInterval_ = setInterval(this.progressAnimation_.bind(this),
401 animation.frameLengthMs);
402 },
403
404 /**
405 * Called when mouse enters the icon. It sets timeout for showing the
406 * tooltip.
407 * @private
408 */
409 showTooltipSoon_: function() {
410 if (this.showTooltipTimeout_ || this.tooltipActive_)
411 return;
412 this.showTooltipTimeout_ =
413 setTimeout(this.showTooltip_.bind(this), 1000);
414 },
415
416 /**
417 * Shows the current tooltip, if one is set.
418 * @private
419 */
420 showTooltip_: function() {
421 if (this.hidden || !this.tooltip_ || this.tooltipActive_)
422 return;
423
424 // If autoshown bubble got hidden, clear the autoshown flag.
425 if ($('bubble').hidden && this.tooltipAutoshown_)
426 this.tooltipAutoshown_ = false;
427
428 // Show the tooltip bubble.
429 var bubbleContent = document.createElement('div');
430 bubbleContent.textContent = this.tooltip_;
431
432 /** @const */ var BUBBLE_OFFSET = CUSTOM_ICON_CONTAINER_SIZE / 2;
433 /** @const */ var BUBBLE_PADDING = 8;
434 $('bubble').showContentForElement(this,
435 cr.ui.Bubble.Attachment.RIGHT,
436 bubbleContent,
437 BUBBLE_OFFSET,
438 BUBBLE_PADDING);
439 this.ensureTooltipTimeoutCleared_();
440 this.tooltipActive_ = true;
441 },
442
443 /**
444 * Hides the tooltip. If the current tooltip was automatically shown, it
445 * will be hidden only if |force| is set.
446 * @param {boolean} Whether the tooltip should be hidden if it got shown
447 * because autoshow flag was set.
448 * @private
449 */
450 hideTooltip_: function(force) {
451 this.tooltipActive_ = false;
452 this.ensureTooltipTimeoutCleared_();
453 if (!force && this.tooltipAutoshown_)
454 return;
455 $('bubble').hideForElement(this);
456 this.tooltipAutoshown_ = false;
457 this.iconElement.removeAttribute('aria-label');
458 },
459
460 /**
461 * Clears timaout for showing the tooltip if it's set.
462 * @private
463 */
464 ensureTooltipTimeoutCleared_: function() {
465 if (this.showTooltipTimeout_) {
466 clearTimeout(this.showTooltipTimeout_);
467 this.showTooltipTimeout_ = null;
468 }
469 },
470
471 /**
472 * Horizontally offsets the animated icon's background for a single icon
473 * size width.
474 * @private
475 */
476 progressAnimation_: function() {
477 this.lastAnimationOffset_ += this.width_;
478 if (this.lastAnimationOffset_ >= this.animationResourceSize_)
479 this.lastAnimationOffset_ = 0;
480 this.iconElement.style.backgroundPosition =
481 '-' + this.lastAnimationOffset_ + 'px center';
482 }
483 };
484
485 /**
162 * Unique salt added to user image URLs to prevent caching. Dictionary with 486 * Unique salt added to user image URLs to prevent caching. Dictionary with
163 * user names as keys. 487 * user names as keys.
164 * @type {Object} 488 * @type {Object}
165 */ 489 */
166 UserPod.userImageSalt_ = {}; 490 UserPod.userImageSalt_ = {};
167 491
168 UserPod.prototype = { 492 UserPod.prototype = {
169 __proto__: HTMLDivElement.prototype, 493 __proto__: HTMLDivElement.prototype,
170 494
171 /** @override */ 495 /** @override */
(...skipping 19 matching lines...) Expand all
191 this.actionBoxMenuRemoveElement.addEventListener('keydown', 515 this.actionBoxMenuRemoveElement.addEventListener('keydown',
192 this.handleRemoveCommandKeyDown_.bind(this)); 516 this.handleRemoveCommandKeyDown_.bind(this));
193 this.actionBoxMenuRemoveElement.addEventListener('blur', 517 this.actionBoxMenuRemoveElement.addEventListener('blur',
194 this.handleRemoveCommandBlur_.bind(this)); 518 this.handleRemoveCommandBlur_.bind(this));
195 this.actionBoxRemoveUserWarningButtonElement.addEventListener( 519 this.actionBoxRemoveUserWarningButtonElement.addEventListener(
196 'click', 520 'click',
197 this.handleRemoveUserConfirmationClick_.bind(this)); 521 this.handleRemoveUserConfirmationClick_.bind(this));
198 this.actionBoxRemoveUserWarningButtonElement.addEventListener( 522 this.actionBoxRemoveUserWarningButtonElement.addEventListener(
199 'keydown', 523 'keydown',
200 this.handleRemoveUserConfirmationKeyDown_.bind(this)); 524 this.handleRemoveUserConfirmationKeyDown_.bind(this));
525
526 var customIcon = this.customIconElement;
527 customIcon.parentNode.replaceChild(new UserPodCustomIcon(), customIcon);
201 }, 528 },
202 529
203 /** 530 /**
204 * Initializes the pod after its properties set and added to a pod row. 531 * Initializes the pod after its properties set and added to a pod row.
205 */ 532 */
206 initialize: function() { 533 initialize: function() {
207 this.passwordElement.addEventListener('keydown', 534 this.passwordElement.addEventListener('keydown',
208 this.parentNode.handleKeyDown.bind(this.parentNode)); 535 this.parentNode.handleKeyDown.bind(this.parentNode));
209 this.passwordElement.addEventListener('keypress', 536 this.passwordElement.addEventListener('keypress',
210 this.handlePasswordKeyPress_.bind(this)); 537 this.handlePasswordKeyPress_.bind(this));
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 get actionBoxRemoveUserWarningButtonElement() { 765 get actionBoxRemoveUserWarningButtonElement() {
439 return this.querySelector('.remove-warning-button'); 766 return this.querySelector('.remove-warning-button');
440 }, 767 },
441 768
442 /** 769 /**
443 * Gets the custom icon. This icon is normally hidden, but can be shown 770 * Gets the custom icon. This icon is normally hidden, but can be shown
444 * using the chrome.screenlockPrivate API. 771 * using the chrome.screenlockPrivate API.
445 * @type {!HTMLDivElement} 772 * @type {!HTMLDivElement}
446 */ 773 */
447 get customIconElement() { 774 get customIconElement() {
448 return this.querySelector('.custom-icon'); 775 return this.querySelector('.custom-icon-container');
449 }, 776 },
450 777
451 /** 778 /**
452 * Updates the user pod element. 779 * Updates the user pod element.
453 */ 780 */
454 update: function() { 781 update: function() {
455 this.imageElement.src = 'chrome://userimage/' + this.user.username + 782 this.imageElement.src = 'chrome://userimage/' + this.user.username +
456 '?id=' + UserPod.userImageSalt_[this.user.username]; 783 '?id=' + UserPod.userImageSalt_[this.user.username];
457 784
458 this.nameElement.textContent = this.user_.displayName; 785 this.nameElement.textContent = this.user_.displayName;
(...skipping 1377 matching lines...) Expand 10 before | Expand all | Expand 10 after
1836 if (this.shouldShowApps_ == shouldShowApps) 2163 if (this.shouldShowApps_ == shouldShowApps)
1837 return; 2164 return;
1838 2165
1839 this.shouldShowApps_ = shouldShowApps; 2166 this.shouldShowApps_ = shouldShowApps;
1840 this.rebuildPods(); 2167 this.rebuildPods();
1841 }, 2168 },
1842 2169
1843 /** 2170 /**
1844 * Shows a custom icon on a user pod besides the input field. 2171 * Shows a custom icon on a user pod besides the input field.
1845 * @param {string} username Username of pod to add button 2172 * @param {string} username Username of pod to add button
1846 * @param {{scale1x: string, scale2x: string}} icon Dictionary of URLs of 2173 * @param {!{resourceUrl: (string | undefined),
1847 * the custom icon's representations for 1x and 2x scale factors. 2174 * data: ({scale1x: string, scale2x: string} | undefined),
2175 * size: ({width: number, height: number} | undefined),
2176 * animation: ({resourceWidth: number, frameLength: number} |
2177 * undefined),
2178 * opacity: (number | undefined),
2179 * tooltip: ({text: string, autoshow: boolean} | undefined)}} icon
2180 * The icon parameters.
1848 */ 2181 */
1849 showUserPodCustomIcon: function(username, icon) { 2182 showUserPodCustomIcon: function(username, icon) {
1850 var pod = this.getPodWithUsername_(username); 2183 var pod = this.getPodWithUsername_(username);
1851 if (pod == null) { 2184 if (pod == null) {
1852 console.error('Unable to show user pod button for ' + username + 2185 console.error('Unable to show user pod button for ' + username +
1853 ': user pod not found.'); 2186 ': user pod not found.');
1854 return; 2187 return;
1855 } 2188 }
1856 2189
1857 pod.customIconElement.hidden = false; 2190 if (icon.resourceUrl) {
1858 pod.customIconElement.style.backgroundImage = 2191 pod.customIconElement.setIconAsResourceUrl(icon.resourceUrl);
1859 '-webkit-image-set(' + 2192 } else if (icon.data) {
1860 'url(' + icon.scale1x + ') 1x,' + 2193 pod.customIconElement.setIconAsImageSet(icon.data);
1861 'url(' + icon.scale2x + ') 2x)'; 2194 } else {
2195 return;
2196 }
2197
2198 pod.customIconElement.setSize(icon.size || {width: 0, height: 0});
2199 pod.customIconElement.setAnimation(icon.animation || null);
2200 pod.customIconElement.setOpacity(icon.opacity || 100);
2201 pod.customIconElement.show();
2202 // This has to be called after |show| in case the tooltip should be shown
2203 // immediatelly.
2204 pod.customIconElement.setTooltip(
2205 icon.tooltip || {text: '', autoshow: false});
1862 }, 2206 },
1863 2207
1864 /** 2208 /**
1865 * Hides the custom icon in the user pod added by showUserPodCustomIcon(). 2209 * Hides the custom icon in the user pod added by showUserPodCustomIcon().
1866 * @param {string} username Username of pod to remove button 2210 * @param {string} username Username of pod to remove button
1867 */ 2211 */
1868 hideUserPodCustomIcon: function(username) { 2212 hideUserPodCustomIcon: function(username) {
1869 var pod = this.getPodWithUsername_(username); 2213 var pod = this.getPodWithUsername_(username);
1870 if (pod == null) { 2214 if (pod == null) {
1871 console.error('Unable to hide user pod button for ' + username + 2215 console.error('Unable to hide user pod button for ' + username +
1872 ': user pod not found.'); 2216 ': user pod not found.');
1873 return; 2217 return;
1874 } 2218 }
1875 2219
1876 pod.customIconElement.hidden = true; 2220 pod.customIconElement.hide();
1877 }, 2221 },
1878 2222
1879 /** 2223 /**
1880 * Sets the authentication type used to authenticate the user. 2224 * Sets the authentication type used to authenticate the user.
1881 * @param {string} username Username of selected user 2225 * @param {string} username Username of selected user
1882 * @param {number} authType Authentication type, must be one of the 2226 * @param {number} authType Authentication type, must be one of the
1883 * values listed in AUTH_TYPE enum. 2227 * values listed in AUTH_TYPE enum.
1884 * @param {string} value The initial value to use for authentication. 2228 * @param {string} value The initial value to use for authentication.
1885 */ 2229 */
1886 setAuthType: function(username, authType, value) { 2230 setAuthType: function(username, authType, value) {
1887 var pod = this.getPodWithUsername_(username); 2231 var pod = this.getPodWithUsername_(username);
1888 if (pod == null) { 2232 if (pod == null) {
1889 console.error('Unable to set auth type for ' + username + 2233 console.error('Unable to set auth type for ' + username +
1890 ': user pod not found.'); 2234 ': user pod not found.');
1891 return; 2235 return;
1892 } 2236 }
1893 pod.setAuthType(authType, value); 2237 pod.setAuthType(authType, value);
1894 }, 2238 },
1895 2239
1896 /** 2240 /**
1897 * Shows a tooltip bubble explaining Easy Unlock for the focused pod.
1898 */
1899 showEasyUnlockBubble: function() {
1900 if (!this.focusedPod_) {
1901 console.error('No focused pod to show Easy Unlock bubble.');
1902 return;
1903 }
1904
1905 var bubbleContent = document.createElement('div');
1906 bubbleContent.classList.add('easy-unlock-button-content');
1907 bubbleContent.textContent = loadTimeData.getString('easyUnlockTooltip');
1908
1909 var attachElement = this.focusedPod_.customIconElement;
1910 /** @const */ var BUBBLE_OFFSET = 20;
1911 /** @const */ var BUBBLE_PADDING = 8;
1912 $('bubble').showContentForElement(attachElement,
1913 cr.ui.Bubble.Attachment.RIGHT,
1914 bubbleContent,
1915 BUBBLE_OFFSET,
1916 BUBBLE_PADDING);
1917 },
1918
1919 /**
1920 * Updates the display name shown on a public session pod. 2241 * Updates the display name shown on a public session pod.
1921 * @param {string} userID The user ID of the public session 2242 * @param {string} userID The user ID of the public session
1922 * @param {string} displayName The new display name 2243 * @param {string} displayName The new display name
1923 */ 2244 */
1924 setPublicSessionDisplayName: function(userID, displayName) { 2245 setPublicSessionDisplayName: function(userID, displayName) {
1925 var pod = this.getPodWithUsername_(userID); 2246 var pod = this.getPodWithUsername_(userID);
1926 if (pod != null) 2247 if (pod != null)
1927 pod.setDisplayName(displayName); 2248 pod.setDisplayName(displayName);
1928 }, 2249 },
1929 2250
(...skipping 604 matching lines...) Expand 10 before | Expand all | Expand 10 after
2534 if (pod && pod.multiProfilesPolicyApplied) { 2855 if (pod && pod.multiProfilesPolicyApplied) {
2535 pod.userTypeBubbleElement.classList.remove('bubble-shown'); 2856 pod.userTypeBubbleElement.classList.remove('bubble-shown');
2536 } 2857 }
2537 } 2858 }
2538 }; 2859 };
2539 2860
2540 return { 2861 return {
2541 PodRow: PodRow 2862 PodRow: PodRow
2542 }; 2863 };
2543 }); 2864 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698