/test/taBind/taBind.events.spec.js

https://gitlab.com/interteach-poolmanager/fork-angular-textangular · JavaScript · 363 lines · 333 code · 23 blank · 7 comment · 2 complexity · 8b8d0f3f6c96b2672e588a8c6437a92a MD5 · raw file

  1. describe('taBind.events', function () {
  2. 'use strict';
  3. beforeEach(module('textAngular'));
  4. afterEach(inject(function($document){
  5. $document.find('body').html('');
  6. }));
  7. var $rootScope;
  8. it('should prevent mousedown from propagating up from contenteditable', inject(function($compile, $rootScope){
  9. var element = $compile('<div ta-bind contenteditable="true" ng-model="test"></div>')($rootScope);
  10. var event;
  11. if(angular.element === jQuery){
  12. event = jQuery.Event('mousedown');
  13. element.triggerHandler(event);
  14. $rootScope.$digest();
  15. expect(event.isPropagationStopped()).toBe(true);
  16. }else{
  17. var _stopPropagation = false;
  18. event = {stopPropagation: function(){ _stopPropagation = true; }};
  19. element.triggerHandler('mousedown', event);
  20. $rootScope.$digest();
  21. expect(_stopPropagation).toBe(true);
  22. }
  23. }));
  24. describe('should update from cut and paste events', function () {
  25. // non-contenteditable is handled by the change event now
  26. describe('on content-editable', function () {
  27. var $rootScope, element, $timeout;
  28. beforeEach(inject(function (_$compile_, _$rootScope_, _$timeout_, $document, $window) {
  29. $rootScope = _$rootScope_;
  30. $timeout = _$timeout_;
  31. $rootScope.html = '<p>Test Contents</p>';
  32. element = _$compile_('<div contenteditable="true" ta-bind ng-model="html"></div>')($rootScope);
  33. $document.find('body').append(element);
  34. $rootScope.$digest();
  35. var sel = $window.rangy.getSelection();
  36. var range = $window.rangy.createRangyRange();
  37. range.selectNodeContents(element.find('p')[0]);
  38. sel.setSingleRange(range);
  39. }));
  40. afterEach(function(){
  41. element.remove();
  42. });
  43. // var text = (e.originalEvent || e).clipboardData.getData('text/plain') || $window.clipboardData.getData('Text');
  44. describe('should update model from paste', function () {
  45. it('non-ie based w/o jquery', inject(function($window){
  46. element.triggerHandler('paste', {clipboardData: {types: ['text/plain'], getData: function(){ return 'Test 3 Content'; }}});
  47. $timeout.flush();
  48. $rootScope.$digest();
  49. expect($rootScope.html).toBe('<p>Test 3 Content</p>');
  50. }));
  51. it('non-ie based w/ jquery', inject(function($window){
  52. element.triggerHandler('paste', {originalEvent: {clipboardData: {types: ['text/plain'], getData: function(){ return 'Test 3 Content'; } }}});
  53. $timeout.flush();
  54. $rootScope.$digest();
  55. expect($rootScope.html).toBe('<p>Test 3 Content</p>');
  56. }));
  57. it('non-ie based w/o paste content', inject(function($window){
  58. element.triggerHandler('paste');
  59. $timeout.flush();
  60. $rootScope.$digest();
  61. expect($rootScope.html).toBe('<p>Test Contents</p>');
  62. }));
  63. });
  64. it('should update model from cut', function () {
  65. element.html('<div>Test 2 Content</div>');
  66. element.triggerHandler('cut');
  67. $timeout.flush();
  68. $rootScope.$digest();
  69. expect($rootScope.html).toBe('<div>Test 2 Content</div>');
  70. });
  71. });
  72. describe('on content-editable with readonly', function () {
  73. var $rootScope, element, $timeout;
  74. beforeEach(inject(function (_$compile_, _$rootScope_, _$timeout_, $document, $window) {
  75. $rootScope = _$rootScope_;
  76. $timeout = _$timeout_;
  77. $rootScope.html = '<p>Test Contents</p>';
  78. element = _$compile_('<div contenteditable="true" ta-readonly="true" ta-bind ng-model="html"></div>')($rootScope);
  79. $document.find('body').append(element);
  80. $rootScope.$digest();
  81. var sel = $window.rangy.getSelection();
  82. var range = $window.rangy.createRangyRange();
  83. range.selectNodeContents(element.find('p')[0]);
  84. sel.setSingleRange(range);
  85. }));
  86. afterEach(function(){
  87. element.remove();
  88. });
  89. // var text = (e.originalEvent || e).clipboardData.getData('text/plain') || $window.clipboardData.getData('Text');
  90. describe('should not update model from paste', function () {
  91. it('ie based', inject(function($window){
  92. $window.clipboardData = {
  93. getData: function(){ return 'Test 2 Content'; }
  94. };
  95. element.triggerHandler('paste');
  96. $rootScope.$digest();
  97. $timeout.flush();
  98. expect($rootScope.html).toBe('<p>Test Contents</p>');
  99. $window.clipboardData = undefined;
  100. }));
  101. it('non-ie based', inject(function($window){
  102. element.triggerHandler('paste', {clipboardData: {types: ['text/plain'], getData: function(){ return 'Test 3 Content'; }}});
  103. $rootScope.$digest();
  104. $timeout.flush();
  105. expect($rootScope.html).toBe('<p>Test Contents</p>');
  106. }));
  107. });
  108. });
  109. describe('on content-editable with ta-unsafe-sanitizer=true attribute', function () {
  110. var $rootScope, element, $timeout;
  111. beforeEach(inject(function (_$compile_, _$rootScope_, _$timeout_, $document, $window) {
  112. $rootScope = _$rootScope_;
  113. $timeout = _$timeout_;
  114. $rootScope.html = '<p>Test Contents</p>';
  115. element = _$compile_('<div contenteditable="true" ta-unsafe-sanitizer="true" ta-bind ng-model="html"></div>')($rootScope);
  116. $document.find('body').append(element);
  117. $rootScope.$digest();
  118. var sel = $window.rangy.getSelection();
  119. var range = $window.rangy.createRangyRange();
  120. range.selectNodeContents(element.find('p')[0]);
  121. sel.setSingleRange(range);
  122. }));
  123. afterEach(function(){
  124. element.remove();
  125. });
  126. // var text = (e.originalEvent || e).clipboardData.getData('text/plain') || $window.clipboardData.getData('Text');
  127. describe('should update model from paste keeping all styles', function () {
  128. it('non-ie based w/o jquery', inject(function($window){
  129. element.triggerHandler('paste', {clipboardData: {types: ['text/html'], getData: function(){ return '<font style="font-size:10px">Test 4 Content</font>'; }}});
  130. $timeout.flush();
  131. $rootScope.$digest();
  132. expect($rootScope.html).toBe('<p><font style="font-size:10px">Test 4 Content</font></p>');
  133. }));
  134. it('non-ie based w/ jquery', inject(function($window){
  135. element.triggerHandler('paste', {originalEvent: {clipboardData: {types: ['text/html'], getData: function(){ return '<font style="font-size:10px">Test 4 Content</font>';} }}});
  136. $timeout.flush();
  137. $rootScope.$digest();
  138. expect($rootScope.html).toBe('<p><font style="font-size:10px">Test 4 Content</font></p>');
  139. }));
  140. });
  141. });
  142. });
  143. describe('handles the ta-paste event correctly', function(){
  144. it('allows conversion of html', inject(function($window, $rootScope, _$compile_, $document, $timeout){
  145. $rootScope.html = '<p>Test Contents</p>';
  146. $rootScope.converter = function(html){
  147. expect(html).toBe('<font>Test 4 Content</font>');
  148. return '<b>Changed Content</b>';
  149. };
  150. var element = _$compile_('<div contenteditable="true" ta-paste="converter($html)" ta-bind ng-model="html"></div>')($rootScope);
  151. $document.find('body').append(element);
  152. $rootScope.$digest();
  153. var sel = $window.rangy.getSelection();
  154. var range = $window.rangy.createRangyRange();
  155. range.selectNodeContents(element.find('p')[0]);
  156. sel.setSingleRange(range);
  157. element.triggerHandler('paste', {originalEvent: {clipboardData: {types: ['text/html'], getData: function(){ return '<font>Test 4 Content</font>';} }}});
  158. $timeout.flush();
  159. $rootScope.$digest();
  160. expect($rootScope.html).toBe('<p><b>Changed Content</b></p>');
  161. }));
  162. });
  163. describe('emits the ta-drop-event event correctly', function(){
  164. afterEach(inject(function($timeout){
  165. try{
  166. $timeout.flush();
  167. }catch(e){}
  168. }));
  169. describe('without read-only attr', function(){
  170. var $rootScope, element;
  171. beforeEach(inject(function (_$compile_, _$rootScope_) {
  172. $rootScope = _$rootScope_;
  173. $rootScope.html = '<p>Test Contents</p>';
  174. element = _$compile_('<div ta-bind contenteditable="contenteditable" ng-model="html"></div>')($rootScope);
  175. $rootScope.$digest();
  176. }));
  177. it('should fire on drop event', function(){
  178. var success = false;
  179. $rootScope.$on('ta-drop-event', function(){
  180. success = true;
  181. });
  182. element.triggerHandler('drop');
  183. $rootScope.$digest();
  184. expect(success).toBe(true);
  185. });
  186. it('should fire on drop event only once', function(){
  187. var count = 0;
  188. $rootScope.$on('ta-drop-event', function(){
  189. count++;
  190. });
  191. element.triggerHandler('drop');
  192. $rootScope.$digest();
  193. element.triggerHandler('drop');
  194. $rootScope.$digest();
  195. // as we don't flush the $timeout it should never reset to being able to send another event
  196. expect(count).toBe(1);
  197. });
  198. it('should fire on drop event again after timeout', inject(function($timeout){
  199. var count = 0;
  200. $rootScope.$on('ta-drop-event', function(){
  201. count++;
  202. });
  203. element.triggerHandler('drop');
  204. $rootScope.$digest();
  205. $timeout.flush();
  206. element.triggerHandler('drop');
  207. $rootScope.$digest();
  208. // as we don't flush the $timeout it should never reset to being able to send another event
  209. expect(count).toBe(2);
  210. }));
  211. });
  212. describe('with read-only attr initially false', function(){
  213. var $rootScope, element;
  214. beforeEach(inject(function (_$compile_, _$rootScope_) {
  215. $rootScope = _$rootScope_;
  216. $rootScope.html = '<p>Test Contents</p>';
  217. $rootScope.readonly = false;
  218. element = _$compile_('<div ta-bind contenteditable="contenteditable" ta-readonly="readonly" ng-model="html"></div>')($rootScope);
  219. $rootScope.$digest();
  220. }));
  221. it('should fire on drop event', function(){
  222. var success = false;
  223. $rootScope.$on('ta-drop-event', function(){
  224. success = true;
  225. });
  226. element.triggerHandler('drop');
  227. $rootScope.$digest();
  228. expect(success).toBe(true);
  229. });
  230. it('should not fire on drop event when changed to readonly mode', function(){
  231. $rootScope.readonly = true;
  232. $rootScope.$digest();
  233. var success = false;
  234. $rootScope.$on('ta-drop-event', function(){
  235. success = true;
  236. });
  237. element.triggerHandler('drop');
  238. $rootScope.$digest();
  239. expect(success).toBe(false);
  240. });
  241. });
  242. describe('with read-only attr initially true', function(){
  243. var $rootScope, element;
  244. beforeEach(inject(function (_$compile_, _$rootScope_) {
  245. $rootScope = _$rootScope_;
  246. $rootScope.html = '<p>Test Contents</p>';
  247. $rootScope.readonly = true;
  248. element = _$compile_('<div ta-bind contenteditable="contenteditable" ta-readonly="readonly" ng-model="html"></div>')($rootScope);
  249. $rootScope.$digest();
  250. }));
  251. it('should not fire on drop event', function(){
  252. var success = false;
  253. $rootScope.$on('ta-drop-event', function(){
  254. success = true;
  255. });
  256. element.triggerHandler('drop');
  257. $rootScope.$digest();
  258. expect(success).toBe(false);
  259. });
  260. it('should fire on drop event when changed to not readonly mode', function(){
  261. $rootScope.readonly = false;
  262. $rootScope.$digest();
  263. var success = false;
  264. $rootScope.$on('ta-drop-event', function(){
  265. success = true;
  266. });
  267. element.triggerHandler('drop');
  268. $rootScope.$digest();
  269. expect(success).toBe(true);
  270. });
  271. });
  272. });
  273. describe('emits the ta-element-select event correctly', function(){
  274. var $rootScope, element;
  275. beforeEach(inject(function (_$compile_, _$rootScope_) {
  276. $rootScope = _$rootScope_;
  277. $rootScope.html = '<p><a>Test Contents</a><img/></p>';
  278. element = _$compile_('<div ta-bind contenteditable="contenteditable" ng-model="html"></div>')($rootScope);
  279. $rootScope.$digest();
  280. }));
  281. it('on click of <a> element', function(){
  282. var targetElement = element.find('a');
  283. var test;
  284. $rootScope.$on('ta-element-select', function(event, element){
  285. test = element;
  286. });
  287. targetElement.triggerHandler('click');
  288. $rootScope.$digest();
  289. expect(test).toBe(targetElement[0]);
  290. });
  291. it('on click of <img> element', function(){
  292. var targetElement = element.find('img');
  293. var test;
  294. $rootScope.$on('ta-element-select', function(event, element){
  295. test = element;
  296. });
  297. targetElement.triggerHandler('click');
  298. $rootScope.$digest();
  299. expect(test).toBe(targetElement[0]);
  300. });
  301. });
  302. describe('handles tab key in textarea mode', function(){
  303. var $rootScope, element;
  304. beforeEach(inject(function (_$compile_, _$rootScope_) {
  305. $rootScope = _$rootScope_;
  306. $rootScope.html = '';
  307. element = _$compile_('<textarea ta-bind ng-model="html"></div>')($rootScope);
  308. $rootScope.html = '<p><a>Test Contents</a><img/></p>';
  309. $rootScope.$digest();
  310. }));
  311. it('should insert \\t on tab key', function(){
  312. element.val('<p><a>Test Contents</a><img/></p>');
  313. triggerEvent('keydown', element, {keyCode: 9});
  314. expect(element.val()).toBe('\t<p><a>Test Contents</a><img/></p>');
  315. });
  316. describe('should remove \\t on shift-tab', function(){
  317. it('should remove \\t at start of line', function(){
  318. element.val('\t<p><a>Test Contents</a><img/></p>');
  319. triggerEvent('keydown', element, {keyCode: 9, shiftKey: true});
  320. expect(element.val()).toBe('<p><a>Test Contents</a><img/></p>');
  321. });
  322. it('should remove only one \\t at start of line', function(){
  323. element.val('\t\t<p><a>Test Contents</a><img/></p>');
  324. triggerEvent('keydown', element, {keyCode: 9, shiftKey: true});
  325. expect(element.val()).toBe('\t<p><a>Test Contents</a><img/></p>');
  326. });
  327. it('should do nothing if no \\t at start of line', function(){
  328. element.val('<p><a>Test Contents</a><img/></p>');
  329. triggerEvent('keydown', element, {keyCode: 9, shiftKey: true});
  330. expect(element.val()).toBe('<p><a>Test Contents</a><img/></p>');
  331. });
  332. // Issue with phantomjs not setting target to end? It works just not in tests.
  333. it('should remove only one \\t at start of the current line', function(){
  334. element.val('\t\t<p><a>Test Contents</a><img/></p>\n\t\t<p><a>Test Contents</a><img/></p>');
  335. triggerEvent('keydown', element, {keyCode: 9, shiftKey: true});
  336. expect(element.val()).toBe('\t<p><a>Test Contents</a><img/></p>\n\t\t<p><a>Test Contents</a><img/></p>');
  337. });
  338. });
  339. });
  340. });