Ejemplo n.º 1
0
void HTMLTableElement::deleteRow(int index, ExceptionState& exceptionState) {
  if (index < -1) {
    exceptionState.throwDOMException(
        IndexSizeError,
        "The index provided (" + String::number(index) + ") is less than -1.");
    return;
  }

  HTMLTableRowElement* row = 0;
  int i = 0;
  if (index == -1) {
    row = HTMLTableRowsCollection::lastRow(*this);
  } else {
    for (i = 0; i <= index; ++i) {
      row = HTMLTableRowsCollection::rowAfter(*this, row);
      if (!row)
        break;
    }
  }
  if (!row) {
    exceptionState.throwDOMException(
        IndexSizeError,
        "The index provided (" + String::number(index) +
            ") is greater than the number of rows in the table (" +
            String::number(i) + ").");
    return;
  }
  row->remove(exceptionState);
}
void JSHTMLTableRowElement::putValueProperty(ExecState* exec, int token, JSValue* value)
{
    switch (token) {
    case AlignAttrNum: {
        HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(impl());
        imp->setAlign(valueToStringWithNullCheck(exec, value));
        break;
    }
    case BgColorAttrNum: {
        HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(impl());
        imp->setBgColor(valueToStringWithNullCheck(exec, value));
        break;
    }
    case ChAttrNum: {
        HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(impl());
        imp->setCh(valueToStringWithNullCheck(exec, value));
        break;
    }
    case ChOffAttrNum: {
        HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(impl());
        imp->setChOff(valueToStringWithNullCheck(exec, value));
        break;
    }
    case VAlignAttrNum: {
        HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(impl());
        imp->setVAlign(valueToStringWithNullCheck(exec, value));
        break;
    }
    }
}
Ejemplo n.º 3
0
void
HTMLTableCellElement::GetAlign(DOMString& aValue)
{
  if (!GetAttr(kNameSpaceID_None, nsGkAtoms::align, aValue)) {
    // There's no align attribute, ask the row for the alignment.
    HTMLTableRowElement* row = GetRow();
    if (row) {
      row->GetAlign(aValue);
    }
  }
}
JSValue* jsHTMLTableRowElementPrototypeFunctionDeleteCell(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
{
    if (!thisValue->isObject(&JSHTMLTableRowElement::s_info))
        return throwError(exec, TypeError);
    JSHTMLTableRowElement* castedThisObj = static_cast<JSHTMLTableRowElement*>(thisValue);
    HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(castedThisObj->impl());
    ExceptionCode ec = 0;
    int index = args.at(exec, 0)->toInt32(exec);

    imp->deleteCell(index, ec);
    setDOMException(exec, ec);
    return jsUndefined();
}
Ejemplo n.º 5
0
HTMLTableRowElement* HTMLTableElement::insertRow(
    int index,
    ExceptionState& exceptionState) {
  if (index < -1) {
    exceptionState.throwDOMException(
        IndexSizeError,
        "The index provided (" + String::number(index) + ") is less than -1.");
    return nullptr;
  }

  HTMLTableRowElement* lastRow = nullptr;
  HTMLTableRowElement* row = nullptr;
  if (index == -1) {
    lastRow = HTMLTableRowsCollection::lastRow(*this);
  } else {
    for (int i = 0; i <= index; ++i) {
      row = HTMLTableRowsCollection::rowAfter(*this, lastRow);
      if (!row) {
        if (i != index) {
          exceptionState.throwDOMException(
              IndexSizeError,
              "The index provided (" + String::number(index) +
                  ") is greater than the number of rows in the table (" +
                  String::number(i) + ").");
          return nullptr;
        }
        break;
      }
      lastRow = row;
    }
  }

  ContainerNode* parent;
  if (lastRow) {
    parent = row ? row->parentNode() : lastRow->parentNode();
  } else {
    parent = lastBody();
    if (!parent) {
      HTMLTableSectionElement* newBody =
          HTMLTableSectionElement::create(tbodyTag, document());
      HTMLTableRowElement* newRow = HTMLTableRowElement::create(document());
      newBody->appendChild(newRow, exceptionState);
      appendChild(newBody, exceptionState);
      return newRow;
    }
  }

  HTMLTableRowElement* newRow = HTMLTableRowElement::create(document());
  parent->insertBefore(newRow, row, exceptionState);
  return newRow;
}
JSValue* jsHTMLTableRowElementPrototypeFunctionInsertCell(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
{
    if (!thisValue->isObject(&JSHTMLTableRowElement::s_info))
        return throwError(exec, TypeError);
    JSHTMLTableRowElement* castedThisObj = static_cast<JSHTMLTableRowElement*>(thisValue);
    HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(castedThisObj->impl());
    ExceptionCode ec = 0;
    int index = args.at(exec, 0)->toInt32(exec);


    JSC::JSValue* result = toJS(exec, WTF::getPtr(imp->insertCell(index, ec)));
    setDOMException(exec, ec);
    return result;
}
static v8::Handle<v8::Value> deleteCellCallback(const v8::Arguments& args)
{
    HTMLTableRowElement* imp = V8HTMLTableRowElement::toNative(args.Holder());
    ExceptionCode ec = 0;
    {
    V8TRYCATCH(int, index, toInt32(MAYBE_MISSING_PARAMETER(args, 0, DefaultIsUndefined)));
    imp->deleteCell(index, ec);
    if (UNLIKELY(ec))
        goto fail;
    return v8Undefined();
    }
    fail:
    return setDOMException(ec, args.GetIsolate());
}
static v8::Handle<v8::Value> insertCellCallback(const v8::Arguments& args)
{
    HTMLTableRowElement* imp = V8HTMLTableRowElement::toNative(args.Holder());
    ExceptionCode ec = 0;
    {
    V8TRYCATCH(int, index, toInt32(MAYBE_MISSING_PARAMETER(args, 0, DefaultIsUndefined)));
    RefPtr<HTMLElement> result = imp->insertCell(index, ec);
    if (UNLIKELY(ec))
        goto fail;
    return toV8Fast(result.release(), args, imp);
    }
    fail:
    return setDOMException(ec, args.GetIsolate());
}
Ejemplo n.º 9
0
void HTMLTableElement::deleteRow(int index, ExceptionCode& ec)
{
    HTMLTableRowElement* row = 0;
    if (index == -1)
        row = HTMLTableRowsCollection::lastRow(this);
    else {
        for (int i = 0; i <= index; ++i) {
            row = HTMLTableRowsCollection::rowAfter(this, row);
            if (!row)
                break;
        }
    }
    if (!row) {
        ec = INDEX_SIZE_ERR;
        return;
    }
    row->remove(ec);
}
Ejemplo n.º 10
0
static inline RefPtr<HTMLCollection> findRows(const HTMLTableRowElement& row)
{
    auto* parent = row.parentNode();
    if (is<HTMLTableSectionElement>(parent))
        return downcast<HTMLTableSectionElement>(*parent).rows();
    if (is<HTMLTableElement>(parent))
        return downcast<HTMLTableElement>(*parent).rows();
    return nullptr;
}
Ejemplo n.º 11
0
bool AXTable::isDataTable() const
{
    if (!m_layoutObject || !node())
        return false;

    // Do not consider it a data table if it has an ARIA role.
    if (hasARIARole())
        return false;

    // When a section of the document is contentEditable, all tables should be
    // treated as data tables, otherwise users may not be able to work with rich
    // text editors that allow creating and editing tables.
    if (node() && node()->hasEditableStyle())
        return true;

    // This employs a heuristic to determine if this table should appear.
    // Only "data" tables should be exposed as tables.
    // Unfortunately, there is no good way to determine the difference
    // between a "layout" table and a "data" table.

    LayoutTable* table = toLayoutTable(m_layoutObject);
    Node* tableNode = table->node();
    if (!isHTMLTableElement(tableNode))
        return false;

    // Do not consider it a data table if any of its descendants have an ARIA role.
    HTMLTableElement* tableElement = toHTMLTableElement(tableNode);
    if (elementHasAriaRole(tableElement->tHead()))
        return false;
    if (elementHasAriaRole(tableElement->tFoot()))
        return false;

    RefPtrWillBeRawPtr<HTMLCollection> bodies = tableElement->tBodies();
    for (unsigned bodyIndex = 0; bodyIndex < bodies->length(); ++bodyIndex) {
        Element* bodyElement = bodies->item(bodyIndex);
        if (elementHasAriaRole(bodyElement))
            return false;
    }

    RefPtrWillBeRawPtr<HTMLTableRowsCollection> rows = tableElement->rows();
    unsigned rowCount = rows->length();
    for (unsigned rowIndex = 0; rowIndex < rowCount; ++rowIndex) {
        HTMLTableRowElement* rowElement = rows->item(rowIndex);
        if (elementHasAriaRole(rowElement))
            return false;
        RefPtrWillBeRawPtr<HTMLCollection> cells = rowElement->cells();
        for (unsigned cellIndex = 0; cellIndex < cells->length(); ++cellIndex) {
            if (elementHasAriaRole(cells->item(cellIndex)))
                return false;
        }
    }

    // If there is a caption element, summary, THEAD, or TFOOT section, it's most certainly a data table
    if (!tableElement->summary().isEmpty() || tableElement->tHead() || tableElement->tFoot() || tableElement->caption())
        return true;

    // if someone used "rules" attribute than the table should appear
    if (!tableElement->rules().isEmpty())
        return true;

    // if there's a colgroup or col element, it's probably a data table.
    if (Traversal<HTMLTableColElement>::firstChild(*tableElement))
        return true;

    // go through the cell's and check for tell-tale signs of "data" table status
    // cells have borders, or use attributes like headers, abbr, scope or axis
    table->recalcSectionsIfNeeded();
    LayoutTableSection* firstBody = table->firstBody();
    if (!firstBody)
        return false;

    int numCols = firstBody->numEffectiveColumns();
    int numRows = firstBody->numRows();

    // If there's only one cell, it's not a good AXTable candidate.
    if (numRows == 1 && numCols == 1)
        return false;

    // If there are at least 20 rows, we'll call it a data table.
    if (numRows >= 20)
        return true;

    // Store the background color of the table to check against cell's background colors.
    const ComputedStyle* tableStyle = table->style();
    if (!tableStyle)
        return false;
    Color tableBGColor = tableStyle->visitedDependentColor(CSSPropertyBackgroundColor);

    // check enough of the cells to find if the table matches our criteria
    // Criteria:
    //   1) must have at least one valid cell (and)
    //   2) at least half of cells have borders (or)
    //   3) at least half of cells have different bg colors than the table, and there is cell spacing
    unsigned validCellCount = 0;
    unsigned borderedCellCount = 0;
    unsigned backgroundDifferenceCellCount = 0;
    unsigned cellsWithTopBorder = 0;
    unsigned cellsWithBottomBorder = 0;
    unsigned cellsWithLeftBorder = 0;
    unsigned cellsWithRightBorder = 0;

    Color alternatingRowColors[5];
    int alternatingRowColorCount = 0;

    int headersInFirstColumnCount = 0;
    for (int row = 0; row < numRows; ++row) {

        int headersInFirstRowCount = 0;
        for (int col = 0; col < numCols; ++col) {
            LayoutTableCell* cell = firstBody->primaryCellAt(row, col);
            if (!cell)
                continue;
            Node* cellNode = cell->node();
            if (!cellNode)
                continue;

            if (cell->size().width() < 1 || cell->size().height() < 1)
                continue;

            validCellCount++;

            bool isTHCell = cellNode->hasTagName(thTag);
            // If the first row is comprised of all <th> tags, assume it is a data table.
            if (!row && isTHCell)
                headersInFirstRowCount++;

            // If the first column is comprised of all <th> tags, assume it is a data table.
            if (!col && isTHCell)
                headersInFirstColumnCount++;

            // in this case, the developer explicitly assigned a "data" table attribute
            if (isHTMLTableCellElement(*cellNode)) {
                HTMLTableCellElement& cellElement = toHTMLTableCellElement(*cellNode);
                if (!cellElement.headers().isEmpty() || !cellElement.abbr().isEmpty()
                    || !cellElement.axis().isEmpty() || !cellElement.scope().isEmpty())
                    return true;
            }

            const ComputedStyle* computedStyle = cell->style();
            if (!computedStyle)
                continue;

            // If the empty-cells style is set, we'll call it a data table.
            if (computedStyle->emptyCells() == HIDE)
                return true;

            // If a cell has matching bordered sides, call it a (fully) bordered cell.
            if ((cell->borderTop() > 0 && cell->borderBottom() > 0)
                || (cell->borderLeft() > 0 && cell->borderRight() > 0))
                borderedCellCount++;

            // Also keep track of each individual border, so we can catch tables where most
            // cells have a bottom border, for example.
            if (cell->borderTop() > 0)
                cellsWithTopBorder++;
            if (cell->borderBottom() > 0)
                cellsWithBottomBorder++;
            if (cell->borderLeft() > 0)
                cellsWithLeftBorder++;
            if (cell->borderRight() > 0)
                cellsWithRightBorder++;

            // If the cell has a different color from the table and there is cell spacing,
            // then it is probably a data table cell (spacing and colors take the place of borders).
            Color cellColor = computedStyle->visitedDependentColor(CSSPropertyBackgroundColor);
            if (table->hBorderSpacing() > 0 && table->vBorderSpacing() > 0
                && tableBGColor != cellColor && cellColor.alpha() != 1)
                backgroundDifferenceCellCount++;

            // If we've found 10 "good" cells, we don't need to keep searching.
            if (borderedCellCount >= 10 || backgroundDifferenceCellCount >= 10)
                return true;

            // For the first 5 rows, cache the background color so we can check if this table has zebra-striped rows.
            if (row < 5 && row == alternatingRowColorCount) {
                LayoutObject* layoutRow = cell->parent();
                if (!layoutRow || !layoutRow->isBoxModelObject() || !toLayoutBoxModelObject(layoutRow)->isTableRow())
                    continue;
                const ComputedStyle* rowComputedStyle = layoutRow->style();
                if (!rowComputedStyle)
                    continue;
                Color rowColor = rowComputedStyle->visitedDependentColor(CSSPropertyBackgroundColor);
                alternatingRowColors[alternatingRowColorCount] = rowColor;
                alternatingRowColorCount++;
            }
        }

        if (!row && headersInFirstRowCount == numCols && numCols > 1)
            return true;
    }

    if (headersInFirstColumnCount == numRows && numRows > 1)
        return true;

    // if there is less than two valid cells, it's not a data table
    if (validCellCount <= 1)
        return false;

    // half of the cells had borders, it's a data table
    unsigned neededCellCount = validCellCount / 2;
    if (borderedCellCount >= neededCellCount
        || cellsWithTopBorder >= neededCellCount
        || cellsWithBottomBorder >= neededCellCount
        || cellsWithLeftBorder >= neededCellCount
        || cellsWithRightBorder >= neededCellCount)
        return true;

    // half had different background colors, it's a data table
    if (backgroundDifferenceCellCount >= neededCellCount)
        return true;

    // Check if there is an alternating row background color indicating a zebra striped style pattern.
    if (alternatingRowColorCount > 2) {
        Color firstColor = alternatingRowColors[0];
        for (int k = 1; k < alternatingRowColorCount; k++) {
            // If an odd row was the same color as the first row, its not alternating.
            if (k % 2 == 1 && alternatingRowColors[k] == firstColor)
                return false;
            // If an even row is not the same as the first row, its not alternating.
            if (!(k % 2) && alternatingRowColors[k] != firstColor)
                return false;
        }
        return true;
    }

    return false;
}
Ejemplo n.º 12
0
JSValue* JSHTMLTableRowElement::getValueProperty(ExecState* exec, int token) const
{
    switch (token) {
    case RowIndexAttrNum: {
        HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(impl());
        return jsNumber(exec, imp->rowIndex());
    }
    case SectionRowIndexAttrNum: {
        HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(impl());
        return jsNumber(exec, imp->sectionRowIndex());
    }
    case CellsAttrNum: {
        HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(impl());
        return toJS(exec, WTF::getPtr(imp->cells()));
    }
    case AlignAttrNum: {
        HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(impl());
        return jsString(exec, imp->align());
    }
    case BgColorAttrNum: {
        HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(impl());
        return jsString(exec, imp->bgColor());
    }
    case ChAttrNum: {
        HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(impl());
        return jsString(exec, imp->ch());
    }
    case ChOffAttrNum: {
        HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(impl());
        return jsString(exec, imp->chOff());
    }
    case VAlignAttrNum: {
        HTMLTableRowElement* imp = static_cast<HTMLTableRowElement*>(impl());
        return jsString(exec, imp->vAlign());
    }
    case ConstructorAttrNum:
        return getConstructor(exec);
    }
    return 0;
}
static v8::Handle<v8::Value> cellsAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
    HTMLTableRowElement* imp = V8HTMLTableRowElement::toNative(info.Holder());
    return toV8Fast(imp->cells(), info, imp);
}
static v8::Handle<v8::Value> sectionRowIndexAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
    HTMLTableRowElement* imp = V8HTMLTableRowElement::toNative(info.Holder());
    return v8Integer(imp->sectionRowIndex(), info.GetIsolate());
}
Ejemplo n.º 15
0
static inline bool isInSection(HTMLTableRowElement& row, const HTMLQualifiedName& sectionTag)
{
    // Because we know that the parent is a table or a section, it's safe to cast it to an HTMLElement
    // giving us access to the faster hasTagName overload from that class.
    return toHTMLElement(row.parentNode())->hasTagName(sectionTag);
}