From e35f2d629241bea2cbe9aa458451d1afaf0ad400 Mon Sep 17 00:00:00 2001 From: Nick Gordon Date: Tue, 12 Nov 2013 16:37:06 -0800 Subject: [PATCH 1/7] properly inject dependencies to support minification correctly see http://docs.angularjs.org/tutorial/step_05#controller_a-note-on-minification --- src/at.js | 8 ++++---- src/caret.js | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/at.js b/src/at.js index f5869a2..ec55e0f 100644 --- a/src/at.js +++ b/src/at.js @@ -104,7 +104,7 @@ angular.module('At', ['ngCaret']) }; }) - .directive('atUser', function ( + .directive('atUser', ['$http', '$timeout', 'Caret', 'AtUtils', function ( $http, $timeout, Caret, @@ -179,9 +179,9 @@ angular.module('At', ['ngCaret']) }); } }; - }) + }]) - .directive('autoComplete', function ( + .directive('autoComplete', ['Caret', 'AtUtils', function ( Caret, AtUtils ) { @@ -245,5 +245,5 @@ angular.module('At', ['ngCaret']) }); } }; - }); + }]); diff --git a/src/caret.js b/src/caret.js index ec7deae..8821a08 100644 --- a/src/caret.js +++ b/src/caret.js @@ -1,5 +1,5 @@ angular.module('ngCaret', []) - .factory('EditableCaret', function ( + .factory('EditableCaret', ['CaretUtils', function ( CaretUtils ) { 'use strict'; @@ -83,9 +83,9 @@ angular.module('ngCaret', []) }; } }; - }) + }]) - .factory('InputCaret', function ( + .factory('InputCaret', ['Mirror', 'CaretUtils', function ( Mirror, CaretUtils ) { @@ -198,7 +198,7 @@ angular.module('ngCaret', []) }; } }; - }) + }]) .factory('Mirror', function () { 'use strict'; @@ -282,7 +282,7 @@ angular.module('ngCaret', []) }; }) - .factory('Caret', function ( + .factory('Caret', ['InputCaret', 'EditableCaret', function ( InputCaret, EditableCaret ) { @@ -312,4 +312,4 @@ angular.module('ngCaret', []) } } }; - }); + }]); From dde550622b7e0d38e6a926ccb4086a251a3d890d Mon Sep 17 00:00:00 2001 From: Nick Gordon Date: Tue, 12 Nov 2013 19:57:59 -0800 Subject: [PATCH 2/7] Add a delay for performance reasons so that the caret position is only checked a few times per second, the 'updateinterval' attribute on the linked element will allow users to modify this value. --- src/at.js | 91 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/src/at.js b/src/at.js index ec55e0f..53d8383 100644 --- a/src/at.js +++ b/src/at.js @@ -118,58 +118,71 @@ angular.module('At', ['ngCaret']) var subtext, caretOffset; var flag = attrs.flag || '@'; var lineHeight = scope.lineHeight || 16; + var updateInterval = attrs.updateinterval || 5; //ms scope.isAtListHidden = true; + + scope.watchDelayIdle = updateInterval; //ms + scope.watchDelayActive = 5; //ms + scope.watchDelay = scope.watchDelayIdle; + scope.watchTimer = false; scope.$watch(function () { return scope.caretPos; }, function (nowCaretPos) { + if(scope.watchTimer){ + $timeout.cancel(scope.watchTimer) + } + scope.watchTimer = $timeout(function(){ + if (angular.isDefined(nowCaretPos)) { + scope.content = AtUtils.getContent(element); + subtext = scope.content.slice(0, nowCaretPos); + scope.query = AtUtils.query(subtext, flag); + caretOffset = Caret.getOffset(element); + + if (scope.query === null) { + scope.isAtListHidden = true; + scope.watchDelay = scope.watchDelayIdle; + } - if (angular.isDefined(nowCaretPos)) { - scope.content = AtUtils.getContent(element); - subtext = scope.content.slice(0, nowCaretPos); - scope.query = AtUtils.query(subtext, flag); - caretOffset = Caret.getOffset(element); - - if (scope.query === null) { - scope.isAtListHidden = true; - } - - if (angular.isString(scope.query) && scope.query.length <= 10) { - if (scope.query === '' && element.next().attr('auto-follow') === 'true') { - element.next().find('ul').css({ - left: caretOffset.left, - top: caretOffset.top + lineHeight - }); + if (angular.isString(scope.query) && scope.query.length <= 10) { + if (scope.query === '' && element.next().attr('auto-follow') === 'true') { + element.next().find('ul').css({ + left: caretOffset.left, + top: caretOffset.top + lineHeight + }); + } + scope.query = { + 'text': scope.query, + 'headPos': nowCaretPos - scope.query.length, + 'endPos': nowCaretPos + }; } - scope.query = { - 'text': scope.query, - 'headPos': nowCaretPos - scope.query.length, - 'endPos': nowCaretPos - }; - } - if (angular.isObject(scope.query)) { - scope.users = scope.response; - scope.isAtListHidden = false; - - // $http.get('data/user.json').success(function (response) { - // scope.users = response.users; - - // if (scope.users.length === 0) { - // scope.isAtListHidden = true; - // } else { - // scope.isAtListHidden = false; - // $timeout(function () { - // element.next().find('li').first().addClass('list-cur'); - // }); - // } - // }); + if (angular.isObject(scope.query)) { + scope.users = scope.response; + scope.isAtListHidden = false; + scope.watchDelay = scope.watchDelayActive; + + // $http.get('data/user.json').success(function (response) { + // scope.users = response.users; + + // if (scope.users.length === 0) { + // scope.isAtListHidden = true; + // } else { + // scope.isAtListHidden = false; + // $timeout(function () { + // element.next().find('li').first().addClass('list-cur'); + // }); + // } + // }); + } } - } + },scope.watchDelay); }); element.bind('blur', function () { scope.isAtListHidden = true; + scope.watchDelay = scope.watchDelayIdle; }); element.bind('click touch keyup', function () { From a463dd1453636cfa0473f4f32756aab4861bb31f Mon Sep 17 00:00:00 2001 From: Nick Gordon Date: Tue, 12 Nov 2013 19:59:57 -0800 Subject: [PATCH 3/7] Fix issue with the model not updating after inserting an autocomplete by properly using ngModel.$setViewValue --- src/at.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/at.js b/src/at.js index 53d8383..a3f3a4f 100644 --- a/src/at.js +++ b/src/at.js @@ -39,7 +39,7 @@ angular.module('At', ['ngCaret']) } }, - insert: function (element, content, data, query, range) { + insert: function (element, content, data, query, range, ngModel) { var insertNode, pos, sel, source, startStr, text; if (element.attr('contenteditable') === 'true') { insertNode = angular.element('@' + data + ' '); @@ -65,6 +65,7 @@ angular.module('At', ['ngCaret']) startStr = source.slice(0, Math.max(query.headPos - 1, 0)); text = startStr + '@' + data + ' ' + (source.slice(query.endPos || 0)); element.val(text); + ngModel.$setViewValue(text); } }, @@ -202,7 +203,8 @@ angular.module('At', ['ngCaret']) return { restrict: 'EA', - link: function (scope, element) { + require: 'ngModel', + link: function (scope, element, attrs, ngModel) { var range; var span = element.next(); var keyCode = { @@ -213,7 +215,7 @@ angular.module('At', ['ngCaret']) scope.autoComplete = function (object) { element[0].focus(); - AtUtils.insert(element, scope.content, object.username, scope.query, range); + AtUtils.insert(element, scope.content, object.username, scope.query, range, ngModel); Caret.setPos(element, scope.query.headPos + object.username.length + 1); }; @@ -247,7 +249,7 @@ angular.module('At', ['ngCaret']) scope.$apply(function () { range = AtUtils.markRange(); - AtUtils.insert(element, scope.content, insertContent, scope.query, range); + AtUtils.insert(element, scope.content, insertContent, scope.query, range, ngModel); scope.isAtListHidden = true; }); Caret.setPos(element, scope.query.headPos + insertContent.length + 1); From 07eaccf72f1b06504dd28f133dbd8e574a09fffb Mon Sep 17 00:00:00 2001 From: Nick Gordon Date: Tue, 12 Nov 2013 21:37:58 -0800 Subject: [PATCH 4/7] support for tab completion and auto-selection of first element in list on tab or enter --- src/at.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/at.js b/src/at.js index a3f3a4f..37e3ae4 100644 --- a/src/at.js +++ b/src/at.js @@ -210,7 +210,8 @@ angular.module('At', ['ngCaret']) var keyCode = { up: 38, down: 40, - enter: 13 + enter: 13, + tab: 9 }; scope.autoComplete = function (object) { @@ -244,7 +245,12 @@ angular.module('At', ['ngCaret']) break; case keyCode.enter: + case keyCode.tab: e.originalEvent.preventDefault(); + if(cur.length == 0) { + AtUtils.select.next(cur,lists); + cur = ul.children('.list-cur'); + } var insertContent = AtUtils.select.choose(cur); scope.$apply(function () { From 69ef701d9e49f1859dbaaf2cfa416f58b7927843 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Sun, 22 Dec 2013 15:21:07 -0700 Subject: [PATCH 5/7] remove $scope.users. Don't seem to be referenced elswhere, and from some basic testing this commit didn't hurt anything. --- src/at.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/at.js b/src/at.js index 37e3ae4..d1811de 100644 --- a/src/at.js +++ b/src/at.js @@ -160,7 +160,7 @@ angular.module('At', ['ngCaret']) } if (angular.isObject(scope.query)) { - scope.users = scope.response; + //scope.users = scope.response; scope.isAtListHidden = false; scope.watchDelay = scope.watchDelayActive; From 1b80185e5dbcf19efb701daaa7eecfc37b906688 Mon Sep 17 00:00:00 2001 From: snicker Date: Mon, 6 Jan 2014 22:59:32 -0800 Subject: [PATCH 6/7] put scope.users back in... --- src/at.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/at.js b/src/at.js index d1811de..37e3ae4 100644 --- a/src/at.js +++ b/src/at.js @@ -160,7 +160,7 @@ angular.module('At', ['ngCaret']) } if (angular.isObject(scope.query)) { - //scope.users = scope.response; + scope.users = scope.response; scope.isAtListHidden = false; scope.watchDelay = scope.watchDelayActive; From c27bae207aa06d1ec302246d8575655ce8dab554 Mon Sep 17 00:00:00 2001 From: snicker Date: Mon, 6 Jan 2014 23:38:57 -0800 Subject: [PATCH 7/7] ...and back to the way it was before! --- src/at.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/at.js b/src/at.js index 37e3ae4..8405902 100644 --- a/src/at.js +++ b/src/at.js @@ -160,7 +160,6 @@ angular.module('At', ['ngCaret']) } if (angular.isObject(scope.query)) { - scope.users = scope.response; scope.isAtListHidden = false; scope.watchDelay = scope.watchDelayActive;