]> git.proxmox.com Git - mirror_xterm.js.git/commitdiff
Merge remote-tracking branch 'ups/master' into 591_element_on_validation
authorDaniel Imms <daimms@microsoft.com>
Tue, 4 Apr 2017 16:50:04 +0000 (09:50 -0700)
committerDaniel Imms <daimms@microsoft.com>
Tue, 4 Apr 2017 16:50:04 +0000 (09:50 -0700)
1  2 
src/Linkifier.test.ts
src/Linkifier.ts
src/xterm.js

index 97750c946651c27a720adf7d5b2f1c517a851737,f4dc9f4dd1e79f01af2ae513ed0a7475c0ec0f01..2450ffb94c2815846b95bbb699eb6d11940d22a6
@@@ -43,57 -40,148 +40,148 @@@ describe('Linkifier', () => 
      rows.push(element);
    }
  
-   function clickElement(element: Node) {
-     const event = document.createEvent('MouseEvent');
-     event.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-     element.dispatchEvent(event);
-   }
-   describe('validationCallback', () => {
-     it('should enable link if true', done => {
-       addRow('test');
-       linkifier.registerLinkMatcher(/test/, () => done(), {
-         validationCallback: (url, element, cb) => {
-           cb(true);
-           assert.equal((<HTMLElement>rows[0].firstChild).tagName, 'A');
-           setTimeout(() => clickElement(rows[0].firstChild), 0);
-         }
+   describe('before attachToDom', () => {
+     it('should allow link matcher registration', done => {
+       assert.doesNotThrow(() => {
+         const linkMatcherId = linkifier.registerLinkMatcher(/foo/, () => {});
+         assert.isTrue(linkifier.deregisterLinkMatcher(linkMatcherId));
+         done();
        });
-       linkifier.linkifyRow(0);
+     });
+   });
+   describe('after attachToDom', () => {
+     beforeEach(() => {
+       rows = [];
+       linkifier.attachToDom(document, rows);
+       container = document.createElement('div');
+       document.body.appendChild(container);
      });
  
-     it('should disable link if false', done => {
-       addRow('test');
-       linkifier.registerLinkMatcher(/test/, () => assert.fail(), {
-         validationCallback: (url, element, cb) => {
-           cb(false);
+     function clickElement(element: Node) {
+       const event = document.createEvent('MouseEvent');
+       event.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+       element.dispatchEvent(event);
+     }
+     function assertLinkifiesEntireRow(uri: string, done: MochaDone) {
+         addRow(uri);
+         linkifier.linkifyRow(0);
+         setTimeout(() => {
            assert.equal((<HTMLElement>rows[0].firstChild).tagName, 'A');
-           setTimeout(() => clickElement(rows[0].firstChild), 0);
-         }
-       });
-       linkifier.linkifyRow(0);
-       // Allow time for the click to be performed
-       setTimeout(() => done(), 10);
+           assert.equal((<HTMLElement>rows[0].firstChild).textContent, uri);
+           done();
+         }, 0);
+     }
+     describe('http links', () => {
+       function assertLinkifiesEntireRow(uri: string, done: MochaDone) {
+         addRow(uri);
+         linkifier.linkifyRow(0);
+         setTimeout(() => {
+           assert.equal((<HTMLElement>rows[0].firstChild).tagName, 'A');
+           assert.equal((<HTMLElement>rows[0].firstChild).textContent, uri);
+           done();
+         }, 0);
+       }
+       it('should allow ~ character in URI path', done => assertLinkifiesEntireRow('http://foo.com/a~b#c~d?e~f', done));
      });
-   });
  
-   describe('priority', () => {
-     it('should order the list from highest priority to lowest #1', () => {
-       const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: 1 });
-       const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: -1 });
-       assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [aId, 0, bId]);
+     describe('link matcher', () => {
+       function assertLinkifiesRow(rowText: string, linkMatcherRegex: RegExp, expectedHtml: string, done: MochaDone) {
+         addRow(rowText);
+         linkifier.registerLinkMatcher(linkMatcherRegex, () => {});
+         linkifier.linkifyRow(0);
+         // Allow linkify to happen
+         setTimeout(() => {
+           assert.equal(rows[0].innerHTML, expectedHtml);
+           done();
+         }, 0);
+       }
+       it('should match a single link', done => {
+         assertLinkifiesRow('foo', /foo/, '<a>foo</a>', done);
+       });
+       it('should match a single link at the start of a text node', done => {
+         assertLinkifiesRow('foo bar', /foo/, '<a>foo</a> bar', done);
+       });
+       it('should match a single link in the middle of a text node', done => {
+         assertLinkifiesRow('foo bar baz', /bar/, 'foo <a>bar</a> baz', done);
+       });
+       it('should match a single link at the end of a text node', done => {
+         assertLinkifiesRow('foo bar', /bar/, 'foo <a>bar</a>', done);
+       });
+       it('should match a link after a link at the start of a text node', done => {
+         assertLinkifiesRow('foo bar', /foo|bar/, '<a>foo</a> <a>bar</a>', done);
+       });
+       it('should match a link after a link in the middle of a text node', done => {
+         assertLinkifiesRow('foo bar baz', /bar|baz/, 'foo <a>bar</a> <a>baz</a>', done);
+       });
+       it('should match a link immediately after a link at the end of a text node', done => {
+         assertLinkifiesRow('<span>foo bar</span>baz', /bar|baz/, '<span>foo <a>bar</a></span><a>baz</a>', done);
+       });
      });
  
-     it('should order the list from highest priority to lowest #2', () => {
-       const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: -1 });
-       const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: 1 });
-       assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [bId, 0, aId]);
+     describe('validationCallback', () => {
+       it('should enable link if true', done => {
+         addRow('test');
+         linkifier.registerLinkMatcher(/test/, () => done(), {
 -          validationCallback: (url, cb) => {
++          validationCallback: (url, element, cb) => {
+             cb(true);
+             assert.equal((<HTMLElement>rows[0].firstChild).tagName, 'A');
+             setTimeout(() => clickElement(rows[0].firstChild), 0);
+           }
+         });
+         linkifier.linkifyRow(0);
+       });
+       it('should disable link if false', done => {
+         addRow('test');
+         linkifier.registerLinkMatcher(/test/, () => assert.fail(), {
 -          validationCallback: (url, cb) => {
++          validationCallback: (url, element, cb) => {
+             cb(false);
+             assert.equal((<HTMLElement>rows[0].firstChild).tagName, 'A');
+             setTimeout(() => clickElement(rows[0].firstChild), 0);
+           }
+         });
+         linkifier.linkifyRow(0);
+         // Allow time for the click to be performed
+         setTimeout(() => done(), 10);
+       });
+       it('should trigger for multiple link matches on one row', done => {
+         addRow('test test');
+         let count = 0;
+         linkifier.registerLinkMatcher(/test/, () => assert.fail(), {
 -          validationCallback: (url, cb) => {
++          validationCallback: (url, element, cb) => {
+             count += 1;
+             if (count === 2) {
+               done();
+             }
+             cb(false);
+           }
+         });
+         linkifier.linkifyRow(0);
+       });
      });
  
-     it('should order items of equal priority in the order they are added', () => {
-       const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: 0 });
-       const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: 0 });
-       assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [0, aId, bId]);
+     describe('priority', () => {
+       it('should order the list from highest priority to lowest #1', () => {
+         const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: 1 });
+         const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: -1 });
+         assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [aId, 0, bId]);
+       });
+       it('should order the list from highest priority to lowest #2', () => {
+         const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: -1 });
+         const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: 1 });
+         assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [bId, 0, aId]);
+       });
+       it('should order items of equal priority in the order they are added', () => {
+         const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: 0 });
+         const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: 0 });
+         assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [0, aId, bId]);
+       });
      });
    });
  });
index e7fbcb50c03308b5f9566761b516882283fa830b,6f93a897a0e1b8e4a06bb9c564255e524fa10b7c..f99cdaa43c0b485548f1ea1d0ce2fe08da420883
@@@ -164,16 -168,17 +177,18 @@@ export class Linkifier 
      const text = row.textContent;
      for (let i = 0; i < this._linkMatchers.length; i++) {
        const matcher = this._linkMatchers[i];
-       const uri = this._findLinkMatch(text, matcher.regex, matcher.matchIndex);
-       if (uri) {
-         const linkElement = this._doLinkifyRow(rowIndex, uri, matcher.handler, matcher.id === HYPERTEXT_LINK_MATCHER_ID);
+       const linkElements = this._doLinkifyRow(row, matcher);
+         if (linkElements.length > 0) {
          // Fire validation callback
-         if (linkElement && matcher.validationCallback) {
-           matcher.validationCallback(uri, linkElement, isValid => {
-             if (!isValid) {
-               linkElement.classList.add(INVALID_LINK_CLASS);
-             }
-           });
+         if (matcher.validationCallback) {
+           for (let j = 0; j < linkElements.length; j++) {
 -            matcher.validationCallback(linkElements[j].textContent, isValid => {
++            const element = linkElements[j];
++            matcher.validationCallback(element.textContent, element, isValid => {
+               if (!isValid) {
 -                linkElements[j].classList.add(INVALID_LINK_CLASS);
++                element.classList.add(INVALID_LINK_CLASS);
+               }
+             });
+           }
          }
          // Only allow a single LinkMatcher to trigger on any given row.
          return;
diff --cc src/xterm.js
Simple merge