tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

FormControlRange-geometry-basic.html (6533B)


      1 <!DOCTYPE html>
      2 <meta charset="utf-8">
      3 <script src="/resources/testharness.js"></script>
      4 <script src="/resources/testharnessreport.js"></script>
      5 <body></body>
      6 <script>
      7 'use strict';
      8 const controls = ['input','textarea'];
      9 
     10 function setupControl(control, value) {
     11  document.body.innerHTML = control === 'input' ? '<input type="text" id="test">'
     12                                                : '<textarea id="test"></textarea>';
     13  const element = document.getElementById('test');
     14  element.value = value;
     15  element.focus();
     16  // Stabilize layout.
     17  element.style.fontFamily = 'monospace';
     18  element.style.fontSize = '16px';
     19  element.style.lineHeight = '20px';
     20  element.style.padding = '0';
     21  element.style.border = '0';
     22  element.style.margin = '8px';
     23  element.style.boxSizing = 'content-box';
     24 
     25  // Zero scroll offsets so client rects are relative to a known origin.
     26  if ('scrollTop' in element) element.scrollTop = 0;
     27  if ('scrollLeft' in element) element.scrollLeft = 0;
     28  return element;
     29 }
     30 function setupFormControlRange(element, startOffset, endOffset){
     31  const range = new FormControlRange();
     32  range.setFormControlRange(element, startOffset, endOffset);
     33  return range;
     34 }
     35 
     36 function assert_rect_inside(inner, outer, msg = '') {
     37  const rounding = 0.5; // sub-pixel fuzz
     38  assert_greater_than_equal(inner.left + rounding, outer.left, msg + 'left inside');
     39  assert_less_than_equal(inner.right - rounding, outer.right, msg + 'right inside');
     40 }
     41 
     42 controls.forEach(controlType => {
     43  test(() => {
     44    // Collapsed range (caret): no client rects; bounding rect is a caret box
     45    // (zero width, non-zero height) positioned within the control.
     46    const element = setupControl(controlType, 'Hello');
     47    const range = setupFormControlRange(element, 2, 2);
     48    const caretRect = range.getBoundingClientRect();
     49    assert_equals(range.getClientRects().length, 0, 'collapsed: no client rects');
     50    assert_approx_equals(caretRect.width, 0, 0.05, 'caret width should be 0');
     51    assert_greater_than(caretRect.height, 0, 'caret height greater than 0');
     52    assert_rect_inside(caretRect, element.getBoundingClientRect(), 'caret inside ');
     53  }, `Collapsed caret geometry (${controlType})`);
     54 
     55  test(() => {
     56    // Non-collapsed selection: non-zero geometry, all rects contained in control.
     57    const element = setupControl(controlType, 'ABCDE');
     58    const range = setupFormControlRange(element, 1, 4);
     59    const boundingRect = range.getBoundingClientRect();
     60    const clientRects = Array.from(range.getClientRects());
     61    assert_greater_than(boundingRect.width, 0, 'selection width greater than 0');
     62    assert_greater_than(boundingRect.height, 0, 'selection height greater than 0');
     63    assert_rect_inside(boundingRect, element.getBoundingClientRect());
     64    assert_greater_than_equal(clientRects.length, 1);
     65    clientRects.forEach((clientRect, index) =>
     66      assert_rect_inside(clientRect, element.getBoundingClientRect(), 'rect[' + index + '] ')
     67    );
     68  }, `Simple selection geometry (${controlType})`);
     69 
     70  test(() => {
     71    // If the control is removed from the DOM, geometry should be empty.
     72    const element = setupControl(controlType, 'ABCDE');
     73    const range = setupFormControlRange(element, 0, element.value.length);
     74    assert_greater_than(range.getBoundingClientRect().width,0,'pre removal width greater than 0');
     75    element.remove();
     76    const boundingRect = range.getBoundingClientRect();
     77    assert_approx_equals(boundingRect.width, 0, 0.05, 'width should be 0 after removal');
     78    assert_equals(range.getClientRects().length, 0);
     79  }, `Geometry empty after control removal (${controlType})`);
     80 
     81  test(() => {
     82    const value = 'ABCDE';
     83    const element = setupControl(controlType, value);
     84    [0, Math.floor(value.length / 2), value.length].forEach(position => {
     85      const range = setupFormControlRange(element, position, position);
     86      const caretRect = range.getBoundingClientRect();
     87      assert_equals(range.getClientRects().length, 0, 'collapsed caret has no rects');
     88      assert_approx_equals(caretRect.width, 0, 0.05, 'caret width should be 0');
     89      assert_greater_than(caretRect.height, 0, 'caret height greater than 0');
     90    });
     91  }, `Collapsed caret at start/middle/end (${controlType})`);
     92 
     93  test(() => {
     94    // Full selection should yield a non-zero bounding box inside the control.
     95    // (For textarea, the string includes a hard newline to exercise multi-line.)
     96    const value = controlType === 'textarea' ? 'First line\nSecond line' : 'ABCDE';
     97    const element = setupControl(controlType, value);
     98    const range = setupFormControlRange(element, 0, element.value.length);
     99    const boundingRect = range.getBoundingClientRect();
    100    assert_greater_than(boundingRect.width, 0, 'full width greater than 0');
    101    assert_greater_than(boundingRect.height, 0, 'full height greater than 0');
    102    assert_rect_inside(boundingRect, element.getBoundingClientRect(), 'full selection inside');
    103  }, `Full selection bounding box inside element (${controlType})`);
    104 
    105  test(() => {
    106    // Backwards offsets are auto-collapsed by setFormControlRange; caret geometry applies.
    107    document.body.innerHTML = controlType === 'input' ? '<input type="text" value="Test">'
    108                                                    : '<textarea>Test</textarea>';
    109    const element = document.body.firstElementChild; const range = new FormControlRange();
    110    range.setFormControlRange(element, 3, 1);
    111    assert_true(range.collapsed, 'collapsed');
    112    const caretRect = range.getBoundingClientRect();
    113    assert_approx_equals(caretRect.width, 0, 0.05, 'caret width should be 0');
    114    assert_greater_than(caretRect.height, 0, 'caret height greater than 0');
    115  }, `Backwards offsets collapse (${controlType})`);
    116 
    117  test(() => {
    118    // Elements with display:none have no rendered geometry; ranges report empty rects.
    119    document.body.innerHTML = controlType === 'input'
    120      ? '<input type="text" id="displayNone" style="display:none" value="hidden">'
    121      : '<textarea id="displayNone" style="display:none">hidden</textarea>';
    122    const element = document.getElementById('displayNone');
    123    const range = setupFormControlRange(element, 0, element.value.length);
    124    const boundingRect = range.getBoundingClientRect();
    125    assert_approx_equals(boundingRect.width, 0, 0.05, 'width should be 0 (display:none)');
    126    assert_approx_equals(boundingRect.height, 0, 0.05, 'height should be 0 (display:none)');
    127    assert_equals(range.getClientRects().length, 0);
    128  }, `display:none empty geometry (${controlType})`);
    129 });
    130 </script>