mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 23:27:26 +01:00
Debounce $scope updates when typing in chat. (#8485)
Fixes #6462, by saving a bunch of time per frame. See the issue for evidence of the win.
This commit is contained in:
committed by
Keith Holliday
parent
6d0df78441
commit
705a78e835
@@ -1,14 +1,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
describe("Chat Controller", function() {
|
describe("Chat Controller", function() {
|
||||||
var scope, ctrl, user, $rootScope, $controller;
|
var scope, ctrl, user, $rootScope, $controller, $httpBackend, html;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
module(function($provide) {
|
module(function($provide) {
|
||||||
$provide.value('User', {});
|
$provide.value('User', {});
|
||||||
});
|
});
|
||||||
|
|
||||||
inject(function(_$rootScope_, _$controller_){
|
inject(function(_$rootScope_, _$controller_, _$compile_, _$httpBackend_){
|
||||||
user = specHelper.newUser();
|
user = specHelper.newUser();
|
||||||
user._id = "unique-user-id";
|
user._id = "unique-user-id";
|
||||||
$rootScope = _$rootScope_;
|
$rootScope = _$rootScope_;
|
||||||
@@ -16,13 +16,20 @@ describe("Chat Controller", function() {
|
|||||||
scope = _$rootScope_.$new();
|
scope = _$rootScope_.$new();
|
||||||
|
|
||||||
$controller = _$controller_;
|
$controller = _$controller_;
|
||||||
|
$httpBackend = _$httpBackend_;
|
||||||
|
|
||||||
// Load RootCtrl to ensure shared behaviors are loaded
|
// Load RootCtrl to ensure shared behaviors are loaded
|
||||||
$controller('RootCtrl', {$scope: scope, User: {user: user}});
|
$controller('RootCtrl', {$scope: scope, User: {user: user}});
|
||||||
|
|
||||||
ctrl = $controller('ChatCtrl', {$scope: scope});
|
html = _$compile_('<div><form ng-submit="postChat(group, message.content)"><textarea submit-on-meta-enter ng-model="message.content" ng-model-options="{debounce: 250}"></textarea></form></div>')(scope);
|
||||||
|
document.body.appendChild(html[0]);
|
||||||
|
ctrl = $controller('ChatCtrl', {$scope: scope, $element: html});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
html.remove();
|
||||||
|
});
|
||||||
|
|
||||||
describe('copyToDo', function() {
|
describe('copyToDo', function() {
|
||||||
it('when copying a user message it opens modal with information from message', function() {
|
it('when copying a user message it opens modal with information from message', function() {
|
||||||
@@ -68,5 +75,47 @@ describe("Chat Controller", function() {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('updates model on enter key press', function() {
|
||||||
|
// Set initial state of the page with some dummy data.
|
||||||
|
scope.group = { name: 'group' };
|
||||||
|
|
||||||
|
// The main controller is going to try to fetch the template right off.
|
||||||
|
// No big deal, just return an empty string.
|
||||||
|
$httpBackend.when('GET', 'partials/main.html').respond('');
|
||||||
|
|
||||||
|
// Let the page settle, and the controllers set their initial state.
|
||||||
|
$rootScope.$digest();
|
||||||
|
|
||||||
|
// Watch for calls to postChat & make sure it doesn't do anything.
|
||||||
|
let postChatSpy = sandbox.stub(scope, 'postChat');
|
||||||
|
|
||||||
|
// Pretend we typed 'aaa' into the textarea.
|
||||||
|
var textarea = html.find('textarea');
|
||||||
|
textarea[0].value = 'aaa';
|
||||||
|
let inputEvent = new Event('input');
|
||||||
|
textarea[0].dispatchEvent(inputEvent);
|
||||||
|
|
||||||
|
// Give a change for the ng-model watchers to notice that the value in the
|
||||||
|
// textarea has changed.
|
||||||
|
$rootScope.$digest();
|
||||||
|
|
||||||
|
// Since no time has elapsed and we debounce the model change, we should
|
||||||
|
// see no model update just yet.
|
||||||
|
expect(scope.message.content).to.equal('');
|
||||||
|
|
||||||
|
// Now, press the enter key in the textarea. We use jquery here to paper
|
||||||
|
// over browser differences with initializing the keyboard event.
|
||||||
|
var keyboardEvent = jQuery.Event('keydown', {keyCode: 13, key: 'Enter', metaKey: true});
|
||||||
|
jQuery(textarea).trigger(keyboardEvent);
|
||||||
|
|
||||||
|
// Now, allow the model to update given the changes to the page still
|
||||||
|
// without letting any time elapse...
|
||||||
|
$rootScope.$digest();
|
||||||
|
|
||||||
|
// ... and nevertheless seeing the desired call to postChat with the right
|
||||||
|
// data. Yay!
|
||||||
|
postChatSpy.should.have.been.calledWith(scope.group, 'aaa');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -60,12 +60,6 @@ habitrpg.controller('ChatCtrl', ['$scope', 'Groups', 'Chat', 'User', '$http', 'A
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.keyDownListener = function (e) {
|
|
||||||
if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {
|
|
||||||
$scope.postChat($scope.group, $scope.message.content);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.deleteChatMessage = function(group, message){
|
$scope.deleteChatMessage = function(group, message){
|
||||||
if(message.uuid === User.user.id || (User.user.backer && User.user.contributor.admin)){
|
if(message.uuid === User.user.id || (User.user.backer && User.user.contributor.admin)){
|
||||||
var previousMsg = (group.chat && group.chat[0]) ? group.chat[0].id : false;
|
var previousMsg = (group.chat && group.chat[0]) ? group.chat[0].id : false;
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
angular
|
||||||
|
.module('habitrpg')
|
||||||
|
.directive('submitOnMetaEnter', submitOnMetaEnter);
|
||||||
|
|
||||||
|
function submitOnMetaEnter() {
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
link: function($scope, element, attrs) {
|
||||||
|
element.on('keydown', function(event) {
|
||||||
|
if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {
|
||||||
|
// Note that we use the normal browser way to invoke the submit
|
||||||
|
// event, because jquery's triggerHandler executes events in a
|
||||||
|
// strange order!
|
||||||
|
var event = new Event('submit');
|
||||||
|
element[0].form.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}());
|
||||||
@@ -76,13 +76,14 @@
|
|||||||
"js/directives/close-menu.directive.js",
|
"js/directives/close-menu.directive.js",
|
||||||
"js/directives/expand-menu.directive.js",
|
"js/directives/expand-menu.directive.js",
|
||||||
"js/directives/from-now.directive.js",
|
"js/directives/from-now.directive.js",
|
||||||
|
"js/directives/focus-element.directive.js",
|
||||||
"js/directives/habitrpg-tasks.directive.js",
|
"js/directives/habitrpg-tasks.directive.js",
|
||||||
"js/directives/hrpg-sort-checklist.directive.js",
|
"js/directives/hrpg-sort-checklist.directive.js",
|
||||||
"js/directives/hrpg-sort-tags.directive.js",
|
"js/directives/hrpg-sort-tags.directive.js",
|
||||||
"js/directives/hrpg-sort-tasks.directive.js",
|
"js/directives/hrpg-sort-tasks.directive.js",
|
||||||
"js/directives/popover-html-popup.directive.js",
|
"js/directives/popover-html-popup.directive.js",
|
||||||
"js/directives/popover-html.directive.js",
|
"js/directives/popover-html.directive.js",
|
||||||
"js/directives/focus-element.directive.js",
|
"js/directives/submit-form-on-enter.directive.js",
|
||||||
"js/directives/when-scrolled.directive.js",
|
"js/directives/when-scrolled.directive.js",
|
||||||
|
|
||||||
"js/controllers/authCtrl.js",
|
"js/controllers/authCtrl.js",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ div.chat-form.guidelines-not-accepted(ng-if='!user.flags.communityGuidelinesAcce
|
|||||||
|
|
||||||
form.chat-form(ng-if='user.flags.communityGuidelinesAccepted' ng-submit='postChat(group,message.content)')
|
form.chat-form(ng-if='user.flags.communityGuidelinesAccepted' ng-submit='postChat(group,message.content)')
|
||||||
div(ng-controller='AutocompleteCtrl')
|
div(ng-controller='AutocompleteCtrl')
|
||||||
textarea.form-control(rows=4, ng-keydown='keyDownListener($event)', ng-model='message.content', updateinterval='250', flag='@', at-user, auto-complete placeholder="{{group._id == TAVERN_ID ? env.t('tavernCommunityGuidelinesPlaceholder') : ''}}", ng-disabled='_sending == true')
|
textarea.form-control(rows=4, submit-on-meta-enter, ng-model='message.content', ng-model-options='{debounce: 250}', updateinterval='250', flag='@', at-user, auto-complete placeholder="{{group._id == TAVERN_ID ? env.t('tavernCommunityGuidelinesPlaceholder') : ''}}", ng-disabled='_sending == true')
|
||||||
span.user-list
|
span.user-list
|
||||||
ul.list-at-user(ng-show="query")
|
ul.list-at-user(ng-show="query")
|
||||||
li(ng-repeat='msg in response | filter:filterUser | limitTo: 5', ng-click='performCompletion(msg)')
|
li(ng-repeat='msg in response | filter:filterUser | limitTo: 5', ng-click='performCompletion(msg)')
|
||||||
|
|||||||
Reference in New Issue
Block a user