animationUtils: Group together various animation helpers
The environment module is used to initialize the environment, yet it currently also defines the adjustAnimationTime() function. Ideally it should not export any utility functions, in particular once converted to ESM. The function cannot be moved to the existing Utils module, as that depends on an initialized environment, and can therefore not be imported from environment.js, so use that opportunity to group together several animation helpers in a new animationUtils module. Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2822>
This commit is contained in:
parent
3c9857abad
commit
87d1248dc1
@ -15,7 +15,7 @@ const GdmUtil = imports.gdm.util;
|
|||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
const UserWidget = imports.ui.userWidget;
|
const UserWidget = imports.ui.userWidget;
|
||||||
const Util = imports.misc.util;
|
const {wiggle} = imports.misc.animationUtils;
|
||||||
|
|
||||||
var DEFAULT_BUTTON_WELL_ICON_SIZE = 16;
|
var DEFAULT_BUTTON_WELL_ICON_SIZE = 16;
|
||||||
var DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1000;
|
var DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1000;
|
||||||
@ -391,7 +391,7 @@ var AuthPrompt = GObject.registerClass({
|
|||||||
this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED;
|
this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED;
|
||||||
|
|
||||||
if (wasQueryingService)
|
if (wasQueryingService)
|
||||||
Util.wiggle(this._entry);
|
wiggle(this._entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onVerificationComplete() {
|
_onVerificationComplete() {
|
||||||
@ -566,7 +566,7 @@ var AuthPrompt = GObject.registerClass({
|
|||||||
this._message.opacity = 0;
|
this._message.opacity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.wiggle(this._message, wiggleParameters);
|
wiggle(this._message, wiggleParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSensitivity(sensitive) {
|
updateSensitivity(sensitive) {
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
<file>gdm/realmd.js</file>
|
<file>gdm/realmd.js</file>
|
||||||
<file>gdm/util.js</file>
|
<file>gdm/util.js</file>
|
||||||
|
|
||||||
|
<file>misc/animationUtils.js</file>
|
||||||
<file>misc/config.js</file>
|
<file>misc/config.js</file>
|
||||||
<file>misc/extensionUtils.js</file>
|
<file>misc/extensionUtils.js</file>
|
||||||
<file>misc/fileUtils.js</file>
|
<file>misc/fileUtils.js</file>
|
||||||
|
117
js/misc/animationUtils.js
Normal file
117
js/misc/animationUtils.js
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/* exported adjustAnimationTime, ensureActorVisibleInScrollView, wiggle */
|
||||||
|
|
||||||
|
const St = imports.gi.St;
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
|
|
||||||
|
const Params = imports.misc.params;
|
||||||
|
|
||||||
|
var SCROLL_TIME = 100;
|
||||||
|
|
||||||
|
const WIGGLE_OFFSET = 6;
|
||||||
|
const WIGGLE_DURATION = 65;
|
||||||
|
const N_WIGGLES = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adjustAnimationTime:
|
||||||
|
*
|
||||||
|
* @param {number} msecs - time in milliseconds
|
||||||
|
*
|
||||||
|
* Adjust `msecs` to account for St's enable-animations
|
||||||
|
* and slow-down-factor settings
|
||||||
|
*/
|
||||||
|
function adjustAnimationTime(msecs) {
|
||||||
|
const settings = St.Settings.get();
|
||||||
|
|
||||||
|
if (!settings.enable_animations)
|
||||||
|
return 0;
|
||||||
|
return settings.slow_down_factor * msecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animate scrolling a scrollview until an actor is visible.
|
||||||
|
*
|
||||||
|
* @param {St.ScrollView} scrollView - the scroll view the actor is in
|
||||||
|
* @param {Clutter.Actor} actor - the actor
|
||||||
|
*/
|
||||||
|
function ensureActorVisibleInScrollView(scrollView, actor) {
|
||||||
|
const {adjustment} = scrollView.vscroll;
|
||||||
|
let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values();
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
const vfade = scrollView.get_effect('fade');
|
||||||
|
if (vfade)
|
||||||
|
offset = vfade.fade_margins.top;
|
||||||
|
|
||||||
|
let box = actor.get_allocation_box();
|
||||||
|
let y1 = box.y1, y2 = box.y2;
|
||||||
|
|
||||||
|
let parent = actor.get_parent();
|
||||||
|
while (parent !== scrollView) {
|
||||||
|
if (!parent)
|
||||||
|
throw new Error('actor not in scroll view');
|
||||||
|
|
||||||
|
box = parent.get_allocation_box();
|
||||||
|
y1 += box.y1;
|
||||||
|
y2 += box.y1;
|
||||||
|
parent = parent.get_parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y1 < value + offset)
|
||||||
|
value = Math.max(0, y1 - offset);
|
||||||
|
else if (y2 > value + pageSize - offset)
|
||||||
|
value = Math.min(upper, y2 + offset - pageSize);
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
adjustment.ease(value, {
|
||||||
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||||
|
duration: SCROLL_TIME,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Wiggles" a clutter actor. A "wiggle" is an animation the moves an actor
|
||||||
|
* back and forth on the X axis a specified amount of times.
|
||||||
|
*
|
||||||
|
* @param {Clutter.Actor} actor - an actor to animate
|
||||||
|
* @param {object} params - options for the animation
|
||||||
|
* @param {number} params.offset - the offset to move the actor by per-wiggle
|
||||||
|
* @param {number} params.duration - the amount of time to move the actor per-wiggle
|
||||||
|
* @param {number} params.wiggleCount - the number of times to wiggle the actor
|
||||||
|
*/
|
||||||
|
function wiggle(actor, params) {
|
||||||
|
if (!St.Settings.get().enable_animations)
|
||||||
|
return;
|
||||||
|
|
||||||
|
params = Params.parse(params, {
|
||||||
|
offset: WIGGLE_OFFSET,
|
||||||
|
duration: WIGGLE_DURATION,
|
||||||
|
wiggleCount: N_WIGGLES,
|
||||||
|
});
|
||||||
|
actor.translation_x = 0;
|
||||||
|
|
||||||
|
// Accelerate before wiggling
|
||||||
|
actor.ease({
|
||||||
|
translation_x: -params.offset,
|
||||||
|
duration: params.duration,
|
||||||
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||||
|
onComplete: () => {
|
||||||
|
// Wiggle
|
||||||
|
actor.ease({
|
||||||
|
translation_x: params.offset,
|
||||||
|
duration: params.duration,
|
||||||
|
mode: Clutter.AnimationMode.LINEAR,
|
||||||
|
repeatCount: params.wiggleCount,
|
||||||
|
autoReverse: true,
|
||||||
|
onComplete: () => {
|
||||||
|
// Decelerate and return to the original position
|
||||||
|
actor.ease({
|
||||||
|
translation_x: 0,
|
||||||
|
duration: params.duration,
|
||||||
|
mode: Clutter.AnimationMode.EASE_IN_QUAD,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
@ -1,9 +1,8 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
|
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
|
||||||
createTimeLabel, insertSorted, ensureActorVisibleInScrollView,
|
createTimeLabel, insertSorted, lerp, GNOMEversionCompare,
|
||||||
wiggle, lerp, GNOMEversionCompare, DBusSenderChecker, Highlighter */
|
DBusSenderChecker, Highlighter */
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
@ -11,15 +10,8 @@ const St = imports.gi.St;
|
|||||||
const GnomeDesktop = imports.gi.GnomeDesktop;
|
const GnomeDesktop = imports.gi.GnomeDesktop;
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
|
||||||
const {formatTime} = imports.misc.dateUtils;
|
const {formatTime} = imports.misc.dateUtils;
|
||||||
|
|
||||||
var SCROLL_TIME = 100;
|
|
||||||
|
|
||||||
const WIGGLE_OFFSET = 6;
|
|
||||||
const WIGGLE_DURATION = 65;
|
|
||||||
const N_WIGGLES = 3;
|
|
||||||
|
|
||||||
// http://daringfireball.net/2010/07/improved_regex_for_matching_urls
|
// http://daringfireball.net/2010/07/improved_regex_for_matching_urls
|
||||||
const _balancedParens = '\\([^\\s()<>]+\\)';
|
const _balancedParens = '\\([^\\s()<>]+\\)';
|
||||||
const _leadingJunk = '[\\s`(\\[{\'\\"<\u00AB\u201C\u2018]';
|
const _leadingJunk = '[\\s`(\\[{\'\\"<\u00AB\u201C\u2018]';
|
||||||
@ -241,79 +233,6 @@ function insertSorted(array, val, cmp) {
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureActorVisibleInScrollView(scrollView, actor) {
|
|
||||||
let adjustment = scrollView.vscroll.adjustment;
|
|
||||||
let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values();
|
|
||||||
|
|
||||||
let offset = 0;
|
|
||||||
let vfade = scrollView.get_effect("fade");
|
|
||||||
if (vfade)
|
|
||||||
offset = vfade.fade_margins.top;
|
|
||||||
|
|
||||||
let box = actor.get_allocation_box();
|
|
||||||
let y1 = box.y1, y2 = box.y2;
|
|
||||||
|
|
||||||
let parent = actor.get_parent();
|
|
||||||
while (parent != scrollView) {
|
|
||||||
if (!parent)
|
|
||||||
throw new Error("actor not in scroll view");
|
|
||||||
|
|
||||||
box = parent.get_allocation_box();
|
|
||||||
y1 += box.y1;
|
|
||||||
y2 += box.y1;
|
|
||||||
parent = parent.get_parent();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y1 < value + offset)
|
|
||||||
value = Math.max(0, y1 - offset);
|
|
||||||
else if (y2 > value + pageSize - offset)
|
|
||||||
value = Math.min(upper, y2 + offset - pageSize);
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
|
|
||||||
adjustment.ease(value, {
|
|
||||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
|
||||||
duration: SCROLL_TIME,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function wiggle(actor, params) {
|
|
||||||
if (!St.Settings.get().enable_animations)
|
|
||||||
return;
|
|
||||||
|
|
||||||
params = Params.parse(params, {
|
|
||||||
offset: WIGGLE_OFFSET,
|
|
||||||
duration: WIGGLE_DURATION,
|
|
||||||
wiggleCount: N_WIGGLES,
|
|
||||||
});
|
|
||||||
actor.translation_x = 0;
|
|
||||||
|
|
||||||
// Accelerate before wiggling
|
|
||||||
actor.ease({
|
|
||||||
translation_x: -params.offset,
|
|
||||||
duration: params.duration,
|
|
||||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
|
||||||
onComplete: () => {
|
|
||||||
// Wiggle
|
|
||||||
actor.ease({
|
|
||||||
translation_x: params.offset,
|
|
||||||
duration: params.duration,
|
|
||||||
mode: Clutter.AnimationMode.LINEAR,
|
|
||||||
repeatCount: params.wiggleCount,
|
|
||||||
autoReverse: true,
|
|
||||||
onComplete: () => {
|
|
||||||
// Decelerate and return to the original position
|
|
||||||
actor.ease({
|
|
||||||
translation_x: 0,
|
|
||||||
duration: params.duration,
|
|
||||||
mode: Clutter.AnimationMode.EASE_IN_QUAD,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function lerp(start, end, progress) {
|
function lerp(start, end, progress) {
|
||||||
return start + progress * (end - start);
|
return start + progress * (end - start);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ const MessageList = imports.ui.messageList;
|
|||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
const Mpris = imports.ui.mpris;
|
const Mpris = imports.ui.mpris;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
const Util = imports.misc.util;
|
const {ensureActorVisibleInScrollView} = imports.misc.animationUtils;
|
||||||
|
|
||||||
const {formatDateWithCFormatString, formatTimeSpan} = imports.misc.dateUtils;
|
const {formatDateWithCFormatString, formatTimeSpan} = imports.misc.dateUtils;
|
||||||
const {loadInterfaceXML} = imports.misc.fileUtils;
|
const {loadInterfaceXML} = imports.misc.fileUtils;
|
||||||
@ -1016,7 +1016,7 @@ class CalendarMessageList extends St.Widget {
|
|||||||
'notify::can-clear', this._sync.bind(this),
|
'notify::can-clear', this._sync.bind(this),
|
||||||
'destroy', () => this._sectionList.remove_actor(section),
|
'destroy', () => this._sectionList.remove_actor(section),
|
||||||
'message-focused', (_s, messageActor) => {
|
'message-focused', (_s, messageActor) => {
|
||||||
Util.ensureActorVisibleInScrollView(this._scrollView, messageActor);
|
ensureActorVisibleInScrollView(this._scrollView, messageActor);
|
||||||
}, this);
|
}, this);
|
||||||
this._sectionList.add_actor(section);
|
this._sectionList.add_actor(section);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ const Dialog = imports.ui.dialog;
|
|||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
const CheckBox = imports.ui.checkBox;
|
const CheckBox = imports.ui.checkBox;
|
||||||
const Util = imports.misc.util;
|
const {wiggle} = imports.misc.animationUtils;
|
||||||
|
|
||||||
var KeyringDialog = GObject.registerClass(
|
var KeyringDialog = GObject.registerClass(
|
||||||
class KeyringDialog extends ModalDialog.ModalDialog {
|
class KeyringDialog extends ModalDialog.ModalDialog {
|
||||||
@ -83,7 +83,7 @@ class KeyringDialog extends ModalDialog.ModalDialog {
|
|||||||
});
|
});
|
||||||
this.prompt.connect('notify::warning', () => {
|
this.prompt.connect('notify::warning', () => {
|
||||||
if (this._passwordEntry && this.prompt.warning !== '')
|
if (this._passwordEntry && this.prompt.warning !== '')
|
||||||
Util.wiggle(this._passwordEntry);
|
wiggle(this._passwordEntry);
|
||||||
});
|
});
|
||||||
warningBox.add_child(warning);
|
warningBox.add_child(warning);
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ const Main = imports.ui.main;
|
|||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
const UserWidget = imports.ui.userWidget;
|
const UserWidget = imports.ui.userWidget;
|
||||||
const Util = imports.misc.util;
|
const {wiggle} = imports.misc.animationUtils;
|
||||||
|
|
||||||
const DialogMode = {
|
const DialogMode = {
|
||||||
AUTH: 0,
|
AUTH: 0,
|
||||||
@ -267,7 +267,7 @@ var AuthenticationDialog = GObject.registerClass({
|
|||||||
this._infoMessageLabel.hide();
|
this._infoMessageLabel.hide();
|
||||||
this._nullMessageLabel.hide();
|
this._nullMessageLabel.hide();
|
||||||
|
|
||||||
Util.wiggle(this._passwordEntry);
|
wiggle(this._passwordEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try and authenticate again */
|
/* Try and authenticate again */
|
||||||
|
@ -44,6 +44,7 @@ const Shell = imports.gi.Shell;
|
|||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Gettext = imports.gettext;
|
const Gettext = imports.gettext;
|
||||||
const SignalTracker = imports.misc.signalTracker;
|
const SignalTracker = imports.misc.signalTracker;
|
||||||
|
const {adjustAnimationTime} = imports.misc.animationUtils;
|
||||||
|
|
||||||
Gio._promisify(Gio.DataInputStream.prototype, 'fill_async');
|
Gio._promisify(Gio.DataInputStream.prototype, 'fill_async');
|
||||||
Gio._promisify(Gio.DataInputStream.prototype, 'read_line_async');
|
Gio._promisify(Gio.DataInputStream.prototype, 'read_line_async');
|
||||||
@ -389,17 +390,3 @@ function init() {
|
|||||||
// Prevent extensions from opening a display connection to ourselves
|
// Prevent extensions from opening a display connection to ourselves
|
||||||
Gdk.set_allowed_backends('');
|
Gdk.set_allowed_backends('');
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjustAnimationTime:
|
|
||||||
// @msecs: time in milliseconds
|
|
||||||
//
|
|
||||||
// Adjust @msecs to account for St's enable-animations
|
|
||||||
// and slow-down-factor settings
|
|
||||||
function adjustAnimationTime(msecs) {
|
|
||||||
let settings = St.Settings.get();
|
|
||||||
|
|
||||||
if (!settings.enable_animations)
|
|
||||||
return 0;
|
|
||||||
return settings.slow_down_factor * msecs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ const MessageTray = imports.ui.messageTray;
|
|||||||
const ShellDBus = imports.ui.shellDBus;
|
const ShellDBus = imports.ui.shellDBus;
|
||||||
const SmartcardManager = imports.misc.smartcardManager;
|
const SmartcardManager = imports.misc.smartcardManager;
|
||||||
|
|
||||||
const { adjustAnimationTime } = imports.ui.environment;
|
const {adjustAnimationTime} = imports.misc.animationUtils;
|
||||||
|
|
||||||
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
|
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
|
||||||
const LOCK_ENABLED_KEY = 'lock-enabled';
|
const LOCK_ENABLED_KEY = 'lock-enabled';
|
||||||
|
@ -14,7 +14,7 @@ const IconGrid = imports.ui.iconGrid;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const ParentalControlsManager = imports.misc.parentalControlsManager;
|
const ParentalControlsManager = imports.misc.parentalControlsManager;
|
||||||
const RemoteSearch = imports.ui.remoteSearch;
|
const RemoteSearch = imports.ui.remoteSearch;
|
||||||
const Util = imports.misc.util;
|
const {ensureActorVisibleInScrollView} = imports.misc.animationUtils;
|
||||||
|
|
||||||
const { Highlighter } = imports.misc.util;
|
const { Highlighter } = imports.misc.util;
|
||||||
|
|
||||||
@ -746,7 +746,7 @@ var SearchResultsView = GObject.registerClass({
|
|||||||
}
|
}
|
||||||
|
|
||||||
_focusChildChanged(provider) {
|
_focusChildChanged(provider) {
|
||||||
Util.ensureActorVisibleInScrollView(this._scrollView, provider.focusChild);
|
ensureActorVisibleInScrollView(this._scrollView, provider.focusChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ensureProviderDisplay(provider) {
|
_ensureProviderDisplay(provider) {
|
||||||
@ -877,7 +877,7 @@ var SearchResultsView = GObject.registerClass({
|
|||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
result.add_style_pseudo_class('selected');
|
result.add_style_pseudo_class('selected');
|
||||||
Util.ensureActorVisibleInScrollView(this._scrollView, result);
|
ensureActorVisibleInScrollView(this._scrollView, result);
|
||||||
} else {
|
} else {
|
||||||
result.remove_style_pseudo_class('selected');
|
result.remove_style_pseudo_class('selected');
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ const Params = imports.misc.params;
|
|||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
|
|
||||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||||
const Util = imports.misc.util;
|
const {wiggle} = imports.misc.animationUtils;
|
||||||
|
|
||||||
var LIST_ITEM_ICON_SIZE = 48;
|
var LIST_ITEM_ICON_SIZE = 48;
|
||||||
var WORK_SPINNER_ICON_SIZE = 16;
|
var WORK_SPINNER_ICON_SIZE = 16;
|
||||||
@ -421,7 +421,7 @@ var ShellMountPasswordDialog = GObject.registerClass({
|
|||||||
this._errorMessageLabel.text = _('Sorry, that didn’t work. Please try again.');
|
this._errorMessageLabel.text = _('Sorry, that didn’t work. Please try again.');
|
||||||
this._errorMessageLabel.opacity = 255;
|
this._errorMessageLabel.opacity = 255;
|
||||||
|
|
||||||
Util.wiggle(this._passwordEntry);
|
wiggle(this._passwordEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCancelButton() {
|
_onCancelButton() {
|
||||||
|
Loading…
Reference in New Issue
Block a user