void WContainerWidget::addWidget(WWidget *widget) { if (widget->parent()) { if (widget->parent() != this) { LOG_WARN("addWidget(): reparenting widget"); widget->setParentWidget(0); } else return; } if (!transientImpl_) { transientImpl_ = new TransientImpl(); // A TD/TH node cannot be stubbed if (domElementType() != DomElement_TD && domElementType() != DomElement_TH) setLoadLaterWhenInvisible(true); } transientImpl_->addedChildren_.push_back(widget); flags_.set(BIT_ADJUST_CHILDREN_ALIGN); // children margins hacks repaint(RepaintInnerHtml); widget->setParentWidget(this); }
std::string WAbstractToggleButton::formName() const { if (domElementType() == DomElement_LABEL) return "in" + id(); else return WFormWidget::formName(); }
DomElement *WTable::createDomElement(WApplication *app) { bool withIds = !app->environment().agentIsSpiderBot(); DomElement *table = DomElement::createNew(domElementType()); setId(table, app); DomElement *thead = 0; if (headerRowCount_ != 0) { thead = DomElement::createNew(DomElement_THEAD); if (withIds) thead->setId(id() + "th"); } DomElement *tbody = DomElement::createNew(DomElement_TBODY); if (withIds) tbody->setId(id() + "tb"); DomElement *colgroup = DomElement::createNew(DomElement_COLGROUP); for (unsigned col = 0; col < columns_.size(); ++col) { DomElement *c = DomElement::createNew(DomElement_COL); if (withIds) c->setId(columns_[col]->id()); columns_[col]->updateDom(*c, true); colgroup->addChild(c); } table->addChild(colgroup); flags_.reset(BIT_COLUMNS_CHANGED); for (unsigned row = 0; row < (unsigned)rowCount(); ++row) for (unsigned col = 0; col < (unsigned)columnCount(); ++col) itemAt(row, col).overSpanned = false; for (unsigned row = 0; row < (unsigned)rowCount(); ++row) { DomElement *tr = createRowDomElement(row, withIds, app); if (row < static_cast<unsigned>(headerRowCount_)) thead->addChild(tr); else tbody->addChild(tr); } rowsAdded_ = 0; if (thead) table->addChild(thead); table->addChild(tbody); updateDom(*table, true); flags_.reset(BIT_GRID_CHANGED); delete rowsChanged_; rowsChanged_ = 0; return table; }
DomElement *Widget::createDomElement(WApplication *app) { DomElement *result = DomElement::createNew(domElementType()); setId(result, app); std::stringstream js; createExtElement(js, result); result->callJavaScript(js.str()); return result; }
void WLineEdit::getDomChanges(std::vector<DomElement *>& result, WApplication *app) { if (app->environment().agentIsIE() && flags_.test(BIT_ECHO_MODE_CHANGED)) { DomElement *e = DomElement::getForUpdate(this, domElementType()); DomElement *d = createDomElement(app); e->replaceWith(d); result.push_back(e); } else WFormWidget::getDomChanges(result, app); }
DomElement *WPaintedWidget::createDomElement(WApplication *app) { createPainter(); DomElement *result = DomElement::createNew(domElementType()); setId(result, app); DomElement *wrap = result; if (width().isAuto() && height().isAuto()) { result->setProperty(PropertyStylePosition, "relative"); wrap = DomElement::createNew(DomElement_DIV); wrap->setProperty(PropertyStylePosition, "absolute"); wrap->setProperty(PropertyStyleLeft, "0"); wrap->setProperty(PropertyStyleRight, "0"); } DomElement *canvas = DomElement::createNew(DomElement_DIV); if (!app->environment().agentIsSpiderBot()) canvas->setId('p' + id()); WPaintDevice *device = painter_->getPaintDevice(false); //handle the widget correctly when inline and using VML if (painter_->renderType() == WWidgetPainter::InlineVml && isInline()) { result->setProperty(PropertyStyle, "zoom: 1;"); canvas->setProperty(PropertyStyleDisplay, "inline"); canvas->setProperty(PropertyStyle, "zoom: 1;"); } if (renderWidth_ != 0 && renderHeight_ != 0) { paintEvent(device); #ifdef WT_TARGET_JAVA if (device->painter()) device->painter()->end(); #endif // WT_TARGET_JAVA } painter_->createContents(canvas, device); needRepaint_ = false; wrap->addChild(canvas); if (wrap != result) result->addChild(wrap); updateDom(*result, true); return result; }
void WTable::getDomChanges(std::vector<DomElement *>& result, WApplication *app) { DomElement *e = DomElement::getForUpdate(this, domElementType()); if (!isStubbed() && flags_.test(BIT_GRID_CHANGED)) { DomElement *newE = createDomElement(app); e->replaceWith(newE); } else { if (rowsChanged_) { for (std::set<WTableRow *>::iterator i = rowsChanged_->begin(); i != rowsChanged_->end(); ++i) { DomElement *e2 = DomElement::getForUpdate(*i, DomElement_TR); (*i)->updateDom(*e2, false); result.push_back(e2); } delete rowsChanged_; rowsChanged_ = 0; } if (rowsAdded_) { DomElement *etb = DomElement::getForUpdate(id() + "tb", DomElement_TBODY); for (unsigned i = 0; i < static_cast<unsigned>(rowsAdded_); ++i) { DomElement *tr = createRowDomElement(rowCount() - rowsAdded_ + i, true, app); etb->addChild(tr); } result.push_back(etb); rowsAdded_ = 0; } if (flags_.test(BIT_COLUMNS_CHANGED)) { for (unsigned i = 0; i < columns_.size(); ++i) { DomElement *e2 = DomElement::getForUpdate(columns_[i], DomElement_COL); columns_[i]->updateDom(*e2, false); result.push_back(e2); } flags_.reset(BIT_COLUMNS_CHANGED); } updateDom(*e, false); } result.push_back(e); }
DomElement *WGLWidget::createDomElement(WApplication *app) { DomElement *result = nullptr; if (!pImpl_) { // no GL support whatsoever result = DomElement::createNew(DomElementType::DIV); result->addChild(alternative_->createSDomElement(app)); webGlNotAvailable_ = true; } else { result = DomElement::createNew(domElementType()); repaintGL(GLClientSideRenderer::PAINT_GL | GLClientSideRenderer::RESIZE_GL); } setId(result, app); updateDom(*result, true); return result; }
void Widget::getDomChanges(std::vector<DomElement *>& result, WApplication *app) { std::string el = elRef() + ".el.dom"; DomElement *e = DomElement::updateGiven(el, domElementType()); updateExt(); if (!jsUpdates_.empty()) { e->callJavaScript("var " + elVar() + "=" + elRef() + ";" + jsUpdates_); jsUpdates_.clear(); } updateDom(*e, false); e->removeProperty(PropertyStyleDisplay); result.push_back(e); }
void WFormWidget::validatorChanged() { std::string validateJS = validator_->javaScriptValidate(); if (!validateJS.empty()) { setJavaScriptMember("wtValidate", validateJS); if (!validateJs_) { validateJs_ = new JSlot(); validateJs_->setJavaScript("function(o){" WT_CLASS ".validate(o)}"); keyWentUp().connect(*validateJs_); changed().connect(*validateJs_); if (domElementType() != DomElement_SELECT) clicked().connect(*validateJs_); } else if (isRendered()) validateJs_->exec(jsRef()); } else { delete validateJs_; validateJs_ = 0; } std::string inputFilter = validator_->inputFilter(); if (!inputFilter.empty()) { if (!filterInput_) { filterInput_ = new JSlot(); keyPressed().connect(*filterInput_); } Wt::Utils::replace(inputFilter, '/', "\\/"); filterInput_->setJavaScript ("function(o,e){" WT_CLASS ".filter(o,e," + jsStringLiteral(inputFilter) + ")}"); } else { delete filterInput_; filterInput_ = 0; } validate(); }
void WContainerWidget::getDomChanges(std::vector<DomElement *>& result, WApplication *app) { DomElement *e = DomElement::getForUpdate(this, domElementType()); #ifndef WT_NO_LAYOUT if (!app->session()->renderer().preLearning()) { if (flags_.test(BIT_LAYOUT_NEEDS_RERENDER)) { e->removeAllChildren(firstChildIndex()); createDomChildren(*e, app); flags_.reset(BIT_LAYOUT_NEEDS_RERENDER); flags_.reset(BIT_LAYOUT_NEEDS_UPDATE); } } #endif // WT_NO_LAYOUT updateDomChildren(*e, app); updateDom(*e, false); result.push_back(e); }
std::string Widget::createExtElement(std::stringstream& alljs, DomElement *inContainer) { if (inContainer) { updateDom(*inContainer, true); inContainer->removeProperty(PropertyStyleDisplay); } setRendered(false); alljs << "var " << elVar() << ";" << createJS(inContainer) << elRef() << "=" << elVar() << ";"; if (isHidden()) alljs << elVar() << ".hide();"; jsUpdates_.clear(); if (!inContainer) { DomElement *e = DomElement::updateGiven(elVar() + ".getEl().dom", domElementType()); updateDom(*e, true); { EscapeOStream out(alljs); e->asJavaScript(out, DomElement::Update); } delete e; } setRendered(true); return elVar(); }
DomElement *WFileUpload::createDomElement(WApplication *app) { DomElement *result = DomElement::createNew(domElementType()); if (result->type() == DomElement_FORM) result->setId(id()); else result->setName(id()); EventSignal<> *change = voidEventSignal(CHANGE_SIGNAL, false); if (fileUploadTarget_) { DomElement *i = DomElement::createNew(DomElement_IFRAME); i->setProperty(PropertyClass, "Wt-resource"); i->setProperty(PropertySrc, fileUploadTarget_->url()); i->setName("if" + id()); if (app->environment().agentIsIE()) { // http://msdn.microsoft.com/en-us/library/ms536474%28v=vs.85%29.aspx // HTA's (started by mshta.exe) have a different security model than // a normal web app, and therefore a HTA browser does not allow // interaction from iframes to the parent window unless this // attribute is set. If omitted, this causes the 'uploaded()' // signal to be blocked when a Wt app is executed as a HTA. i->setAttribute("APPLICATION", "yes"); } DomElement *form = result; form->setAttribute("method", "post"); form->setAttribute("action", fileUploadTarget_->url()); form->setAttribute("enctype", "multipart/form-data"); form->setProperty(PropertyStyle, "margin:0;padding:0;display:inline"); form->setProperty(PropertyTarget, "if" + id()); /* * wrap iframe in an extra span to work around bug in IE which does * not set the name use DOM methods */ DomElement *d = DomElement::createNew(DomElement_SPAN); d->addChild(i); form->addChild(d); DomElement *input = DomElement::createNew(DomElement_INPUT); input->setAttribute("type", "file"); if (flags_.test(BIT_MULTIPLE)) input->setAttribute("multiple", "multiple"); input->setAttribute("name", "data"); input->setAttribute("size", boost::lexical_cast<std::string>(textSize_)); input->setId("in" + id()); if (!isEnabled()) input->setProperty(Wt::PropertyDisabled, "true"); if (change) updateSignalConnection(*input, *change, "change", true); form->addChild(input); } else { result->setAttribute("type", "file"); if (flags_.test(BIT_MULTIPLE)) result->setAttribute("multiple", "multiple"); result->setAttribute("size", boost::lexical_cast<std::string>(textSize_)); if (!isEnabled()) result->setProperty(Wt::PropertyDisabled, "true"); if (change) updateSignalConnection(*result, *change, "change", true); } updateDom(*result, true); flags_.reset(BIT_ENABLE_AJAX); return result; }
void WContainerWidget::updateDom(DomElement& element, bool all) { if (all && element.type() == DomElement_LI && isInline()) element.setProperty(PropertyStyleDisplay, "inline"); if (flags_.test(BIT_CONTENT_ALIGNMENT_CHANGED) || all) { AlignmentFlag hAlign = contentAlignment_ & AlignHorizontalMask; bool ltr = WApplication::instance()->layoutDirection() == LeftToRight; switch (hAlign) { case AlignLeft: if (flags_.test(BIT_CONTENT_ALIGNMENT_CHANGED)) element.setProperty(PropertyStyleTextAlign, ltr ? "left" : "right"); break; case AlignRight: element.setProperty(PropertyStyleTextAlign, ltr ? "right" : "left"); break; case AlignCenter: element.setProperty(PropertyStyleTextAlign, "center"); break; case AlignJustify: #ifndef WT_NO_LAYOUT if (!layout_) #endif // WT_NO_LAYOUT element.setProperty(PropertyStyleTextAlign, "justify"); break; default: break; } if (domElementType() == DomElement_TD) { AlignmentFlag vAlign = contentAlignment_ & AlignVerticalMask; switch (vAlign) { case AlignTop: if (flags_.test(BIT_CONTENT_ALIGNMENT_CHANGED)) element.setProperty(PropertyStyleVerticalAlign, "top"); break; case AlignMiddle: element.setProperty(PropertyStyleVerticalAlign, "middle"); break; case AlignBottom: element.setProperty(PropertyStyleVerticalAlign, "bottom"); default: break; } } } if (flags_.test(BIT_ADJUST_CHILDREN_ALIGN) || flags_.test(BIT_CONTENT_ALIGNMENT_CHANGED) || all) { /* * Welcome to CSS hell. * * Apparently, the text-align property only applies to inline elements. * To center non-inline children, the standard says to set its left and * right margin to 'auto'. * * I assume the same applies for aligning to the right ? */ for (unsigned i = 0; i < children_->size(); ++i) { WWidget *child = (*children_)[i]; if (!child->isInline()) { AlignmentFlag ha = contentAlignment_ & AlignHorizontalMask; if (ha == AlignCenter) { if (!child->margin(Left).isAuto()) child->setMargin(WLength::Auto, Left); if (!child->margin(Right).isAuto()) child->setMargin(WLength::Auto, Right); } else if (ha == AlignRight) { if (!child->margin(Left).isAuto()) child->setMargin(WLength::Auto, Left); } } } flags_.reset(BIT_CONTENT_ALIGNMENT_CHANGED); flags_.reset(BIT_ADJUST_CHILDREN_ALIGN); } if (flags_.test(BIT_PADDINGS_CHANGED) || (all && padding_ && !( padding_[0].isAuto() && padding_[1].isAuto() && padding_[2].isAuto() && padding_[3].isAuto()))) { if ((padding_[0] == padding_[1]) && (padding_[0] == padding_[2]) && (padding_[0] == padding_[3])) element.setProperty(PropertyStylePadding, padding_[0].cssText()); else element.setProperty(PropertyStylePadding, padding_[0].cssText() + " " + padding_[1].cssText() + " " + padding_[2].cssText() + " " + padding_[3].cssText()); flags_.reset(BIT_PADDINGS_CHANGED); } WInteractWidget::updateDom(element, all); if (flags_.test(BIT_OVERFLOW_CHANGED) || (all && overflow_ && !(overflow_[0] == OverflowVisible && overflow_[1] == OverflowVisible))) { static const char *cssText[] = { "visible", "auto", "hidden", "scroll" }; element.setProperty(PropertyStyleOverflowX, cssText[overflow_[0]]); element.setProperty(PropertyStyleOverflowY, cssText[overflow_[1]]); flags_.reset(BIT_OVERFLOW_CHANGED); /* If a container widget has overflow, then, if ever something * inside it has position scheme relative/absolute, it will not * scroll properly unless every element up to the container and including * the container itself has overflow: relative. * * The following fixes the common case: * container (overflow) - container - layout */ WApplication *app = WApplication::instance(); if (app->environment().agentIsIE() && (overflow_[0] == OverflowAuto || overflow_[0] == OverflowScroll)) if (positionScheme() == Static) element.setProperty(PropertyStylePosition, "relative"); } }