DomElement *WFileUpload::createDomElement() { if (methodIframe_) { DomElement *form = DomElement::createNew(DomElement::FORM); form->setId(this, true); form->setAttribute("method", "post"); form->setAttribute("action", generateUrl()); form->setAttribute("enctype", "multipart/form-data"); form->setAttribute("style", "margin:0;padding:0;display:inline"); DomElement *input = DomElement::createNew(DomElement::INPUT); input->setAttribute("type", "file"); input->setAttribute("name", "data"); input->setAttribute("size", boost::lexical_cast<std::string>(textSize_)); input->setId("in" + formName()); updateSignalConnection(*input, changed, "change", true); form->addChild(input); updateDom(*form, true); return form; } else { DomElement *result = DomElement::createNew(DomElement::INPUT); result->setAttribute("type", "file"); result->setAttribute("size", boost::lexical_cast<std::string>(textSize_)); result->setId(this, true); updateSignalConnection(*result, changed, "change", true); updateDom(*result, true); return result; } }
void WWidgetCanvasPainter::createContents(DomElement *result, WPaintDevice *device) { std::string wstr = boost::lexical_cast<std::string>(widget_->renderWidth_); std::string hstr = boost::lexical_cast<std::string>(widget_->renderHeight_); result->setProperty(PropertyStylePosition, "relative"); result->setProperty(PropertyStyleOverflowX, "hidden"); DomElement *canvas = DomElement::createNew(DomElement_CANVAS); canvas->setId('c' + widget_->id()); canvas->setProperty(PropertyStyleDisplay, "block"); canvas->setAttribute("width", wstr); canvas->setAttribute("height", hstr); result->addChild(canvas); WCanvasPaintDevice *canvasDevice = dynamic_cast<WCanvasPaintDevice *>(device); DomElement *text = 0; if (canvasDevice->textMethod() == WCanvasPaintDevice::DomText) { text = DomElement::createNew(DomElement_DIV); text->setId('t' + widget_->id()); text->setProperty(PropertyStylePosition, "absolute"); text->setProperty(PropertyStyleZIndex, "1"); text->setProperty(PropertyStyleTop, "0px"); text->setProperty(PropertyStyleLeft, "0px"); } canvasDevice->render("c" + widget_->id(), text ? text : result); if (text) result->addChild(text); delete device; }
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; }
void WWidgetCanvasPainter::createContents(DomElement *result, WPaintDevice *device) { std::string wstr = boost::lexical_cast<std::string>(widget_->renderWidth_); std::string hstr = boost::lexical_cast<std::string>(widget_->renderHeight_); result->setProperty(PropertyStylePosition, "relative"); result->setProperty(PropertyStyleOverflowX, "hidden"); result->setProperty(PropertyStyleOverflowY, "hidden"); DomElement *canvas = DomElement::createNew(DomElement_CANVAS); canvas->setId('c' + widget_->id()); canvas->setProperty(PropertyStyleDisplay, "block"); canvas->setAttribute("width", wstr); canvas->setAttribute("height", hstr); result->addChild(canvas); widget_->sizeChanged_ = false; WCanvasPaintDevice *canvasDevice = dynamic_cast<WCanvasPaintDevice *>(device); DomElement *text = 0; if (canvasDevice->textMethod() == WCanvasPaintDevice::DomText) { text = DomElement::createNew(DomElement_DIV); text->setId('t' + widget_->id()); text->setProperty(PropertyStylePosition, "absolute"); text->setProperty(PropertyStyleZIndex, "1"); text->setProperty(PropertyStyleTop, "0px"); text->setProperty(PropertyStyleLeft, "0px"); } DomElement *el = text ? text : result; bool hasJsObjects = widget_->jsObjects_.size() > 0; if (hasJsObjects) { WStringStream ss; WApplication *app = WApplication::instance(); ss << "new " WT_CLASS ".WPaintedWidget(" << app->javaScriptClass() << "," << widget_->jsRef() << ");"; widget_->jsObjects_.updateJs(ss); el->callJavaScript(ss.str()); } canvasDevice->render('c' + widget_->id(), el); if (hasJsObjects) { WStringStream ss; ss << widget_->objJsRef() << ".repaint=function(){"; ss << canvasDevice->recordedJs_.str(); ss << "};"; el->callJavaScript(ss.str()); } if (text) result->addChild(text); delete device; }
void WAbstractMedia::getDomChanges(std::vector<DomElement *>& result, WApplication *app) { if (!mediaId_.empty()) { DomElement *media = DomElement::getForUpdate(mediaId_, DomElement_DIV); updateMediaDom(*media, false); if (sourcesChanged_) { // Updating source elements seems to be ill-supported in at least FF, // so we delete them all and reinsert them. // Delete source elements that are no longer required for (std::size_t i = 0; i < sourcesRendered_; ++i) media->callJavaScript (WT_CLASS ".remove('" + mediaId_ + "s" + boost::lexical_cast<std::string>(i) + "');", true); sourcesRendered_ = 0; for (std::size_t i = 0; i < sources_.size(); ++i) { DomElement *src = DomElement::createNew(DomElement_SOURCE); src->setId(mediaId_ + "s" + boost::lexical_cast<std::string>(i)); renderSource(src, *sources_[i], i + 1 >= sources_.size()); media->addChild(src); } sourcesRendered_ = sources_.size(); sourcesChanged_ = false; // Explicitly request rerun of media selection algorithm // 4.8.9.2 says it should happen automatically, but FF doesn't media->callJavaScript(jsMediaRef() + ".load();"); } result.push_back(media); } WInteractWidget::getDomChanges(result, app); }
DomElement *WGroupBox::createDomElement() { DomElement *result = DomElement::createNew(DomElement::FIELDSET); result->setId(this); DomElement *legend = DomElement::createNew(DomElement::LEGEND); legend->setId(formName() + "l"); legend->setProperty(Wt::PropertyInnerHTML, toUTF8(escapeText(title_.value()))); result->addChild(legend); createDomChildren(*result); updateDom(*result, true); return result; }
DomElement *WScrollArea::createDomElement() { DomElement *result = DomElement::createNew(DomElement::DIV); result->setId(this, true); updateDom(*result, true); return result; }
DomElement *WComboBox::createDomElement() { DomElement *result = DomElement::createNew(DomElement::SELECT); result->setId(this, true); updateDom(*result, true); return result; }
DomElement *WImage::createDomElement() { DomElement *result = DomElement::createNew(DomElement::IMG); result->setId(this); updateDom(*result, true); return result; }
DomElement *WPushButton::createDomElement() { DomElement *result = DomElement::createNew(DomElement::BUTTON); result->setAttribute("type", "button"); // default button result->setId(this); updateDom(*result, true); return result; }
DomElement *WTable::createDomElement() { //printDebug(); DomElement *table = DomElement::createNew(DomElement::TABLE); table->setId(this); DomElement *tbody = DomElement::createNew(DomElement::TBODY); for (unsigned row = 0; row < (unsigned)numRows(); ++row) for (unsigned col = 0; col < (unsigned)numColumns(); ++col) itemAt(row, col).overSpanned = false; for (unsigned row = 0; row < (unsigned)numRows(); ++row) { DomElement *tr = DomElement::createNew(DomElement::TR); tr->setId(rows_[row]); for (unsigned col = 0; col < (unsigned)numColumns(); ++col) { WTableRow::TableData& d = itemAt(row, col); if (!d.overSpanned) { DomElement *td = d.cell->createSDomElement(); tr->addChild(td); for (int i = 0; i < d.cell->rowSpan(); ++i) for (int j = 0; j < d.cell->columnSpan(); ++j) if (i + j > 0) itemAt(row + i, col + j).overSpanned = true; } } tbody->addChild(tr); } table->addChild(tbody); updateDom(*table, true); gridChanged_ = false; return table; }
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 WPushButton::updateDom(DomElement& element, bool all) { if (all && element.type() == DomElement_BUTTON) element.setAttribute("type", "button"); bool updateInnerHtml = !icon_.isNull() && flags_.test(BIT_TEXT_CHANGED); if (updateInnerHtml || flags_.test(BIT_ICON_CHANGED) || (all && !icon_.isNull())) { DomElement *image = DomElement::createNew(DomElement_IMG); image->setProperty(PropertySrc, icon_.resolveUrl(WApplication::instance())); image->setId("im" + formName()); element.insertChildAt(image, 0); flags_.set(BIT_ICON_RENDERED); flags_.reset(BIT_ICON_CHANGED); } if (flags_.test(BIT_TEXT_CHANGED) || all) { element.setProperty(Wt::PropertyInnerHTML, text_.formattedText()); flags_.reset(BIT_TEXT_CHANGED); } // bool needsUrlResolution = false; if (flags_.test(BIT_LINK_CHANGED) || all) { if (element.type() == DomElement_A) { /* needsUrlResolution = */ WAnchor::renderHRef(this, linkState_, element); WAnchor::renderHTarget(linkState_, element, all); } else renderHRef(element); flags_.reset(BIT_LINK_CHANGED); } if (isCheckable()) { if (flags_.test(BIT_CHECKED_CHANGED) || all) { if (!all || flags_.test(BIT_IS_CHECKED)) { toggleStyleClass("active", flags_.test(BIT_IS_CHECKED), true); } flags_.reset(BIT_CHECKED_CHANGED); } } if (!all) WApplication::instance()->theme()->apply(this, element, MainElementThemeRole); WFormWidget::updateDom(element, all); }
void WGroupBox::updateDom(DomElement& element, bool all) { if (all || titleChanged_) { DomElement *legend; if (all) { legend = DomElement::createNew(DomElement_LEGEND); legend->setId(id() + "l"); } else legend = DomElement::getForUpdate(id() + "l", DomElement_LEGEND); legend->setProperty(Wt::PropertyInnerHTML, escapeText(title_).toUTF8()); element.addChild(legend); titleChanged_ = false; } WContainerWidget::updateDom(element, all); }
void WProgressBar::updateDom(DomElement& element, bool all) { DomElement *bar = 0, *label = 0; if (all) { WApplication *app = WApplication::instance(); bar = DomElement::createNew(DomElement_DIV); bar->setId("bar" + id()); bar->setProperty(PropertyClass, valueStyleClass_); app->theme()->apply(this, *bar, ProgressBarBarRole); label = DomElement::createNew(DomElement_DIV); label->setId("lbl" + id()); app->theme()->apply(this, *label, ProgressBarLabelRole); } if (changed_ || all) { if (!bar) bar = DomElement::getForUpdate("bar" + id(), DomElement_DIV); if (!label) label = DomElement::getForUpdate("lbl" + id(), DomElement_DIV); bar->setProperty(PropertyStyleWidth, boost::lexical_cast<std::string>(percentage()) + "%"); WString s = text(); removeScript(s); label->setProperty(PropertyInnerHTML, s.toUTF8()); changed_ = false; } if (bar) element.addChild(bar); if (label) element.addChild(label); WInteractWidget::updateDom(element, all); }
void WWidgetRasterPainter::createContents(DomElement *result, WPaintDevice *device) { std::string wstr = boost::lexical_cast<std::string>(widget_->renderWidth_); std::string hstr = boost::lexical_cast<std::string>(widget_->renderHeight_); DomElement *img = DomElement::createNew(DomElement_IMG); img->setId('i' + widget_->id()); img->setAttribute("width", wstr); img->setAttribute("height", hstr); img->setAttribute("class", "unselectable"); img->setAttribute("unselectable", "on"); img->setAttribute("onselectstart", "return false;"); img->setAttribute("onmousedown", "return false;"); WResource *resource = dynamic_cast<WResource *>(device); img->setAttribute("src", resource->generateUrl()); result->addChild(img); }
DomElement *WWebWidget::createSDomElement() { if (hidden_ && wApp && wApp->loading()) { /* * just create a stub, but let the element believe that it is * up-to-date so that static slots are loaded correctly. */ DomElement *real = createDomElement(); delete real; stubbed_ = true; DomElement *stub = DomElement::createNew(DomElement::SPAN); stub->setId(this); return stub; } else { stubbed_ = false; return createDomElement(); } }
DomElement * WContainerWidget::createDomElement() { DomElement *result; result = DomElement::createNew(isInline() ? DomElement::SPAN : DomElement::DIV); result->setId(this); if (addedChildren_) { delete addedChildren_; addedChildren_ = 0; } updateDom(*result, true); createDomChildren(*result); renderOk(); return result; }
DomElement *WTable::createRowDomElement(int row, bool withIds, WApplication *app) { DomElement *tr = DomElement::createNew(DomElement_TR); if (withIds) tr->setId(rows_[row]->id()); rows_[row]->updateDom(*tr, true); // because of the mix of addChild() and insertChildAt() tr->setWasEmpty(false); int spanCounter = 0; for (int col = 0; col < columnCount(); ++col) { WTableRow::TableData& d = itemAt(row, col); if (!d.overSpanned) { DomElement *td = d.cell->createSDomElement(app); /* * So, IE gets confused when doing appendChild() for TH followed by * insertCell(-1) for TD. But, we cannot insertChild() for element 0, * so we do TH with appendChild, and insertCell(col). */ if (col < headerColumnCount_ || row < headerRowCount_) tr->addChild(td); else tr->insertChildAt(td, col - spanCounter); for (int i = 0; i < d.cell->rowSpan(); ++i) for (int j = 0; j < d.cell->columnSpan(); ++j) if (i + j > 0) { itemAt(row + i, col + j).overSpanned = true; itemAt(row + i, col + j).cell->setRendered(false); } } else { spanCounter++; } } return tr; }
void WImage::updateDom(DomElement& element, bool all) { DomElement *img = &element; if (all && element.type() == DomElement_SPAN) { DomElement *map = map_->createSDomElement(WApplication::instance()); element.addChild(map); img = DomElement::createNew(DomElement_IMG); img->setId("i" + id()); } if (flags_.test(BIT_IMAGE_LINK_CHANGED) || all) { if (!imageLink_.isNull()) { std::string url = resolveRelativeUrl(imageLink_.url()); WApplication *app = WApplication::instance(); url = app->encodeUntrustedUrl(url); img->setProperty(Wt::PropertySrc, url); } else img->setProperty(Wt::PropertySrc, "#"); flags_.reset(BIT_IMAGE_LINK_CHANGED); } if (flags_.test(BIT_ALT_TEXT_CHANGED) || all) { img->setAttribute("alt", altText_.toUTF8()); flags_.reset(BIT_ALT_TEXT_CHANGED); } if (flags_.test(BIT_MAP_CREATED) || (all && map_)) { img->setAttribute("usemap", '#' + map_->id()); flags_.reset(BIT_MAP_CREATED); } WInteractWidget::updateDom(*img, all); if (&element != img) element.addChild(img); }
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::createDomChildren(DomElement& parent, WApplication *app) { if (layout_) { #ifndef WT_NO_LAYOUT bool fitWidth = contentAlignment_ & AlignJustify; bool fitHeight = !(contentAlignment_ & AlignVerticalMask); DomElement *c = layoutImpl()->createDomElement(fitWidth, fitHeight, app); /* * Take the hint: if the container is relative, then we can use an absolute * layout for its contents, under the assumption that a .wtResize or * auto-javascript sets the width too (like in WTreeView, WTableView) */ if (positionScheme() == Relative || positionScheme() == Absolute) { c->setProperty(PropertyStylePosition, "absolute"); c->setProperty(PropertyStyleLeft, "0"); c->setProperty(PropertyStyleRight, "0"); } else if (app->environment().agentIsIE()) { /* * position: relative element needs to be in a position: relative * parent otherwise scrolling is broken */ if (app->environment().agentIsIE() && this->parent()->positionScheme() != Static) parent.setProperty(PropertyStylePosition, "relative"); } switch (contentAlignment_ & AlignHorizontalMask) { case AlignCenter: { DomElement *itable = DomElement::createNew(DomElement_TABLE); itable->setProperty(PropertyClass, "Wt-hcenter"); if (fitHeight) itable->setProperty(PropertyStyle, "height:100%;"); DomElement *irow = DomElement::createNew(DomElement_TR); DomElement *itd = DomElement::createNew(DomElement_TD); if (fitHeight) itd->setProperty(PropertyStyle, "height:100%;"); itd->addChild(c); irow->addChild(itd); itable->addChild(irow); itable->setId(id() + "l"); c = itable; break; } case AlignLeft: break; case AlignRight: c->setProperty(PropertyStyleFloat, "right"); break; default: break; } parent.addChild(c); flags_.reset(BIT_LAYOUT_NEEDS_RERENDER); #endif // WT_NO_LAYOUT } else { for (unsigned i = 0; i < children_->size(); ++i) parent.addChild((*children_)[i]->createSDomElement(app)); } if (transientImpl_) transientImpl_->addedChildren_.clear(); }
DomElement *WAbstractMedia::createDomElement(WApplication *app) { DomElement *result = 0; if (isInLayout()) { // It's easier to set WT_RESIZE_JS after the following code, // but if it's not set, the alternative content will think that // it is not included in a layout manager. Set some phony function // now, which will be overwritten later in this method. setJavaScriptMember(WT_RESIZE_JS, "function() {}"); } if (app->environment().agentIsIElt(9) || app->environment().agent() == WEnvironment::MobileWebKitAndroid) { // Shortcut: IE misbehaves when it encounters a media element result = DomElement::createNew(DomElement_DIV); if (alternative_) result->addChild(alternative_->createSDomElement(app)); } else { DomElement *media = createMediaDomElement(); DomElement *wrap = 0; if (isInLayout()) { media->setProperty(PropertyStylePosition, "absolute"); media->setProperty(PropertyStyleLeft, "0"); media->setProperty(PropertyStyleRight, "0"); wrap = DomElement::createNew(DomElement_DIV); wrap->setProperty(PropertyStylePosition, "relative"); } result = wrap ? wrap : media; if (wrap) { mediaId_ = id() + "_media"; media->setId(mediaId_); } else { mediaId_ = id(); } updateMediaDom(*media, true); // Create the 'source' elements for (std::size_t i = 0; i < sources_.size(); ++i) { DomElement *src = DomElement::createNew(DomElement_SOURCE); src->setId(mediaId_ + "s" + boost::lexical_cast<std::string>(i)); renderSource(src, *sources_[i], i + 1 >= sources_.size()); media->addChild(src); } sourcesRendered_ = sources_.size(); sourcesChanged_ = false; if (wrap) { wrap->addChild(media); } } if (isInLayout()) { std::stringstream ss; ss << """function(self, w, h) {"; if (!mediaId_.empty()) { ss << "" "v=" + jsMediaRef() + ";" "" "if (v) {" "" "if (w >= 0) " "" "v.setAttribute('width', w);" "" "if (h >= 0) " "" "v.setAttribute('height', h);" "" "}"; } if (alternative_) { ss << """a=" + alternative_->jsRef() + ";" "" "if (a && a." << WT_RESIZE_JS <<")" "" "a." << WT_RESIZE_JS << "(a, w, h);"; } ss <<"}"; setJavaScriptMember(WT_RESIZE_JS, ss.str()); } setId(result, app); updateDom(*result, true); if (isInLayout()) { result->setEvent(PLAYBACKSTARTED_SIGNAL, std::string()); result->setEvent(PLAYBACKPAUSED_SIGNAL, std::string()); result->setEvent(ENDED_SIGNAL, std::string()); result->setEvent(TIMEUPDATED_SIGNAL, std::string()); result->setEvent(VOLUMECHANGED_SIGNAL, std::string()); } setJavaScriptMember("mediaId", "'" + mediaId_ + "'"); return result; }
/* * fitWidth, fitHeight: * - from setLayout(AlignLeft | AlignTop) * is being deprecated but still needs to be implemented * - nested layouts: handles as other layout items */ DomElement *StdGridLayoutImpl2::createDomElement(bool fitWidth, bool fitHeight, WApplication *app) { needAdjust_ = needConfigUpdate_ = needRemeasure_ = false; addedItems_.clear(); removedItems_.clear(); const unsigned colCount = grid_.columns_.size(); const unsigned rowCount = grid_.rows_.size(); int margin[] = { 0, 0, 0, 0}; int maxWidth = 0, maxHeight = 0; if (layout()->parentLayout() == 0) { #ifndef WT_TARGET_JAVA layout()->getContentsMargins(margin + 3, margin, margin + 1, margin + 2); #else // WT_TARGET_JAVA margin[3] = layout()->getContentsMargin(Left); margin[0] = layout()->getContentsMargin(Top); margin[1] = layout()->getContentsMargin(Right); margin[2] = layout()->getContentsMargin(Bottom); #endif // WT_TARGET_JAVA maxWidth = pixelSize(container()->maximumWidth()); maxHeight = pixelSize(container()->maximumHeight()); } WStringStream js; js << app->javaScriptClass() << ".layouts2.add(new " WT_CLASS ".StdLayout2(" << app->javaScriptClass() << ",'" << id() << "',"; if (layout()->parentLayout()) js << "'" << getImpl(layout()->parentLayout())->id() << "',"; else js << "null,"; bool progressive = !app->environment().ajax(); js << (fitWidth ? '1' : '0') << "," << (fitHeight ? '1' : '0') << "," << (progressive ? '1' : '0') << ","; js << maxWidth << "," << maxHeight << ",[" << grid_.horizontalSpacing_ << "," << margin[3] << "," << margin[1] << "],[" << grid_.verticalSpacing_ << "," << margin[0] << "," << margin[2] << "],"; streamConfig(js, app); DomElement *div = DomElement::createNew(DomElement_DIV); div->setId(id()); div->setProperty(PropertyStylePosition, "relative"); DomElement *table = 0, *tbody = 0, *tr = 0; if (progressive) { table = DomElement::createNew(DomElement_TABLE); WStringStream style; if (maxWidth) style << "max-width: " << maxWidth << "px;"; if (maxHeight) style << "max-height: " << maxHeight << "px;"; style << "width: 100%;"; table->setProperty(PropertyStyle, style.str()); int totalColStretch = 0; for (unsigned col = 0; col < colCount; ++col) totalColStretch += std::max(0, grid_.columns_[col].stretch_); for (unsigned col = 0; col < colCount; ++col) { DomElement *c = DomElement::createNew(DomElement_COL); int stretch = std::max(0, grid_.columns_[col].stretch_); if (stretch || totalColStretch == 0) { char buf[30]; double pct = totalColStretch == 0 ? 100.0 / colCount : (100.0 * stretch / totalColStretch); WStringStream ss; ss << "width:" << Utils::round_css_str(pct, 2, buf) << "%;"; c->setProperty(PropertyStyle, ss.str()); } table->addChild(c); } tbody = DomElement::createNew(DomElement_TBODY); } #ifndef WT_TARGET_JAVA std::vector<bool> overSpanned(colCount * rowCount, false); #else std::vector<bool> overSpanned; overSpanned.insert(0, colCount * rowCount, false); #endif // WT_TARGET_JAVA int prevRowWithItem = -1; for (unsigned row = 0; row < rowCount; ++row) { if (table) tr = DomElement::createNew(DomElement_TR); bool rowVisible = false; int prevColumnWithItem = -1; for (unsigned col = 0; col < colCount; ++col) { Impl::Grid::Item& item = grid_.items_[row][col]; if (!overSpanned[row * colCount + col]) { for (int i = 0; i < item.rowSpan_; ++i) for (int j = 0; j < item.colSpan_; ++j) if (i + j > 0) overSpanned[(row + i) * colCount + col + j] = true; AlignmentFlag hAlign = item.alignment_ & AlignHorizontalMask; AlignmentFlag vAlign = item.alignment_ & AlignVerticalMask; DomElement *td = 0; if (table) { bool itemVisible = hasItem(row, col); rowVisible = rowVisible || itemVisible; td = DomElement::createNew(DomElement_TD); if (itemVisible) { int padding[] = { 0, 0, 0, 0 }; int nextRow = nextRowWithItem(row, col); int prevRow = prevRowWithItem; int nextCol = nextColumnWithItem(row, col); int prevCol = prevColumnWithItem; if (prevRow == -1) padding[0] = margin[0]; else padding[0] = (grid_.verticalSpacing_+1) / 2; if (nextRow == (int)rowCount) padding[2] = margin[2]; else padding[2] = grid_.verticalSpacing_ / 2; if (prevCol == -1) padding[3] = margin[3]; else padding[3] = (grid_.horizontalSpacing_ + 1)/2; if (nextCol == (int)colCount) padding[1] = margin[1]; else padding[1] = (grid_.horizontalSpacing_)/2; WStringStream style; if (app->layoutDirection() == RightToLeft) std::swap(padding[1], padding[3]); if (padding[0] == padding[1] && padding[0] == padding[2] && padding[0] == padding[3]) { if (padding[0] != 0) style << "padding:" << padding[0] << "px;"; } else style << "padding:" << padding[0] << "px " << padding[1] << "px " << padding[2] << "px " << padding[3] << "px;"; if (vAlign != 0) switch (vAlign) { case AlignTop: style << "vertical-align:top;"; break; case AlignMiddle: style << "vertical-align:middle;"; break; case AlignBottom: style << "vertical-align:bottom;"; default: break; } td->setProperty(PropertyStyle, style.str()); if (item.rowSpan_ != 1) td->setProperty(PropertyRowSpan, boost::lexical_cast<std::string>(item.rowSpan_)); if (item.colSpan_ != 1) td->setProperty(PropertyColSpan, boost::lexical_cast<std::string>(item.colSpan_)); prevColumnWithItem = col; } } DomElement *c = 0; if (!table) { if (item.item_) { c = createElement(item.item_, app); div->addChild(c); } } else if (item.item_) c = getImpl(item.item_)->createDomElement(true, true, app); if (table) { if (c) { if (!app->environment().agentIsIElt(9)) c->setProperty(PropertyStyleBoxSizing, "border-box"); if (hAlign == 0) hAlign = AlignJustify; switch (hAlign) { case AlignCenter: { DomElement *itable = DomElement::createNew(DomElement_TABLE); itable->setProperty(PropertyClass, "Wt-hcenter"); if (vAlign == 0) itable->setProperty(PropertyStyle, "height:100%;"); DomElement *irow = DomElement::createNew(DomElement_TR); DomElement *itd = DomElement::createNew(DomElement_TD); if (vAlign == 0) itd->setProperty(PropertyStyle, "height:100%;"); bool haveMinWidth = !c->getProperty(PropertyStyleMinWidth).empty(); itd->addChild(c); if (app->environment().agentIsIElt(9)) { // IE7 and IE8 do support min-width but do not enforce it // properly when in a table. // see http://stackoverflow.com/questions/2356525 // /css-min-width-in-ie6-7-and-8 if (haveMinWidth) { DomElement *spacer = DomElement::createNew(DomElement_DIV); spacer->setProperty(PropertyStyleWidth, c->getProperty(PropertyStyleMinWidth)); spacer->setProperty(PropertyStyleHeight, "1px"); itd->addChild(spacer); } } irow->addChild(itd); itable->addChild(irow); c = itable; break; } case AlignRight: if (!c->isDefaultInline()) c->setProperty(PropertyStyleFloat, "right"); else td->setProperty(PropertyStyleTextAlign, "right"); break; case AlignLeft: if (!c->isDefaultInline()) c->setProperty(PropertyStyleFloat, "left"); else td->setProperty(PropertyStyleTextAlign, "left"); break; default: break; } td->addChild(c); if (app->environment().agentIsIElt(9)) { // IE7 and IE8 do support min-width but do not enforce it properly // when in a table. // see http://stackoverflow.com/questions/2356525 // /css-min-width-in-ie6-7-and-8 if (!c->getProperty(PropertyStyleMinWidth).empty()) { DomElement *spacer = DomElement::createNew(DomElement_DIV); spacer->setProperty(PropertyStyleWidth, c->getProperty(PropertyStyleMinWidth)); spacer->setProperty(PropertyStyleHeight, "1px"); td->addChild(spacer); } } } tr->addChild(td); } } } if (tr) { if (!rowVisible) tr->setProperty(PropertyStyleDisplay, "hidden"); else prevRowWithItem = row; tbody->addChild(tr); } } js << "));"; if (table) { table->addChild(tbody); div->addChild(table); } div->callJavaScript(js.str()); return div; }
DomElement *FlexLayoutImpl::createElement(Orientation orientation, unsigned index, int totalStretch, WApplication *app) { Impl::Grid::Item& it = item(orientation, index); Impl::Grid::Section& s = section(orientation, index); DomElement *el = getImpl(it.item_.get())->createDomElement(nullptr, true, true, app); if (dynamic_cast<StdGridLayoutImpl2*>(getImpl(it.item_.get()))) { DomElement *wrapEl = DomElement::createNew(DomElementType::DIV); wrapEl->addChild(el); el = wrapEl; } int m[] = { 0, 0, 0, 0 }; if (FlexLayoutImpl *flexImpl = dynamic_cast<FlexLayoutImpl*>(getImpl(it.item_.get()))) { Orientation elOrientation = flexImpl->getOrientation(); if (elOrientation == Orientation::Horizontal) { m[3] -= (flexImpl->grid_.horizontalSpacing_) / 2; m[1] -= (flexImpl->grid_.horizontalSpacing_ + 1) / 2; } else { m[0] -= (flexImpl->grid_.verticalSpacing_) / 2; m[2] -= (flexImpl->grid_.horizontalSpacing_ + 1) / 2; } } AlignmentFlag hAlign = it.alignment_ & AlignHorizontalMask; AlignmentFlag vAlign = it.alignment_ & AlignVerticalMask; /* * If not justifying along main axis, then we need to wrap inside * an additional (flex) element */ if (orientation == Orientation::Horizontal) { if (hAlign != static_cast<AlignmentFlag>(0)) { el->setProperty(Property::StyleFlex, "0 0 auto"); DomElement *wrap = DomElement::createNew(DomElementType::DIV); wrap->setId("w" + el->id()); wrap->setProperty(Property::StyleDisplay, styleDisplay()); wrap->setProperty(Property::StyleFlexFlow, styleFlex()); wrap->addChild(el); el = wrap; switch (hAlign) { case AlignmentFlag::Left: el->setProperty(Property::StyleJustifyContent, "flex-start"); break; case AlignmentFlag::Center: el->setProperty(Property::StyleJustifyContent, "center"); break; case AlignmentFlag::Right: el->setProperty(Property::StyleJustifyContent, "flex-end"); default: break; } } if (vAlign != static_cast<AlignmentFlag>(0)) switch (vAlign) { case AlignmentFlag::Top: el->setProperty(Property::StyleAlignSelf, "flex-start"); break; case AlignmentFlag::Middle: el->setProperty(Property::StyleAlignSelf, "center"); break; case AlignmentFlag::Bottom: el->setProperty(Property::StyleAlignSelf, "flex-end"); break; case AlignmentFlag::Baseline: el->setProperty(Property::StyleAlignSelf, "baseline"); default: break; } } else { if (vAlign != static_cast<AlignmentFlag>(0)) { el->setProperty(Property::StyleFlex, "0 0 auto"); DomElement *wrap = DomElement::createNew(DomElementType::DIV); wrap->setId("w" + el->id()); wrap->setProperty(Property::StyleDisplay, styleDisplay()); wrap->setProperty(Property::StyleFlexFlow, styleFlex()); wrap->addChild(el); el = wrap; switch (vAlign) { case AlignmentFlag::Top: el->setProperty(Property::StyleJustifyContent, "flex-start"); break; case AlignmentFlag::Middle: el->setProperty(Property::StyleJustifyContent, "center"); break; case AlignmentFlag::Bottom: el->setProperty(Property::StyleJustifyContent, "flex-end"); default: break; } } if (hAlign != static_cast<AlignmentFlag>(0)) switch (hAlign) { case AlignmentFlag::Left: el->setProperty(Property::StyleAlignSelf, "flex-start"); break; case AlignmentFlag::Center: el->setProperty(Property::StyleAlignSelf, "center"); break; case AlignmentFlag::Right: el->setProperty(Property::StyleAlignSelf, "flex-end"); break; default: break; } } { WStringStream flexProperty; int flexGrow = totalStretch == 0 ? 1 : s.stretch_; int flexShrink = totalStretch == 0 ? 1 : (s.stretch_ == 0 ? 0 : 1); flexProperty << flexGrow << ' ' << flexShrink << ' ' << s.initialSize_.cssText(); if (s.stretch_ == 0) el->setAttribute("flg", "0"); el->setProperty(Property::StyleFlex, flexProperty.str()); } switch (getDirection()) { case LayoutDirection::LeftToRight: m[3] += (grid_.horizontalSpacing_ + 1) / 2; m[1] += (grid_.horizontalSpacing_) / 2; break; case LayoutDirection::RightToLeft: m[1] += (grid_.horizontalSpacing_ + 1) / 2; m[3] += (grid_.horizontalSpacing_) / 2; break; case LayoutDirection::TopToBottom: m[0] += (grid_.horizontalSpacing_ + 1) / 2; m[2] += (grid_.horizontalSpacing_) / 2; break; case LayoutDirection::BottomToTop: m[2] += (grid_.horizontalSpacing_ + 1) / 2; m[0] += (grid_.horizontalSpacing_) / 2; break; } if (m[0] != 0 || m[1] != 0 || m[2] != 0 || m[3] != 0) { WStringStream marginProperty; marginProperty << m[0] << "px " << m[1] << "px " << m[2] << "px " << m[3] << "px"; el->setProperty(Property::StyleMargin, marginProperty.str()); } return el; }
DomElement *FlexLayoutImpl::createDomElement(DomElement *parent, bool fitWidth, bool fitHeight, WApplication *app) { addedItems_.clear(); removedItems_.clear(); int margin[] = { 0, 0, 0, 0 }; DomElement *result; if (layout()->parentLayout() == nullptr) { /* * If it is a top-level layout (as opposed to a nested layout), * configure overflow of the container. */ if (container() == app->root()) { /* * Reset body,html default paddings and so on if we are doing layout * in the entire document. */ app->setBodyClass(app->bodyClass() + " Wt-layout"); app->setHtmlClass(app->htmlClass() + " Wt-layout"); parent->setProperty(Property::StyleBoxSizing, "border-box"); } #ifndef WT_TARGET_JAVA layout()->getContentsMargins(margin + 3, margin, margin + 1, margin + 2); #else // WT_TARGET_JAVA margin[3] = layout()->getContentsMargin(Side::Left); margin[0] = layout()->getContentsMargin(Side::Top); margin[1] = layout()->getContentsMargin(Side::Right); margin[2] = layout()->getContentsMargin(Side::Bottom); #endif // WT_TARGET_JAVA Orientation orientation = getOrientation(); if (orientation == Orientation::Horizontal) { margin[3] = std::max(0, margin[3] - (grid_.horizontalSpacing_) / 2); margin[1] = std::max(0, margin[1] - (grid_.horizontalSpacing_ + 1) / 2); } else { margin[0] = std::max(0, margin[0] - (grid_.verticalSpacing_) / 2); margin[2] = std::max(0, margin[2] - (grid_.horizontalSpacing_ + 1) / 2); } ResizeSensor::applyIfNeeded(container()); container()->setFlexBox(true); result = parent; elId_ = container()->id(); } else { result = DomElement::createNew(DomElementType::DIV); elId_ = id(); result->setId(elId_); } if (margin[0] != 0 || margin[1] != 0 || margin[2] != 0 || margin[3] != 0) { WStringStream paddingProperty; paddingProperty << margin[0] << "px " << margin[1] << "px " << margin[2] << "px " << margin[3] << "px"; result->setProperty(Property::StylePadding, paddingProperty.str()); } // FIXME minsize/maxsize result->setProperty(Property::StyleDisplay, styleDisplay()); result->setProperty(Property::StyleFlexFlow, styleFlex()); Orientation orientation = getOrientation(); int c = count(orientation); int totalStretch = getTotalStretch(orientation); for (int i = 0; i < c; ++i) { DomElement *el = createElement(orientation, i, totalStretch, app); result->addChild(el); } WStringStream js; js << "layout=new " WT_CLASS ".FlexLayout(" << app->javaScriptClass() << ",'" << elId_ << "');"; result->callMethod(js.str()); return result; }
void WPushButton::updateDom(DomElement& element, bool all) { if (all) { element.setAttribute("type", "button"); element.setProperty(PropertyClass, "Wt-btn"); } if (flags_.test(BIT_ICON_CHANGED) || (all && !icon_.isNull())) { DomElement *image = DomElement::createNew(DomElement_IMG); image->setProperty(PropertySrc, icon_.url()); image->setId("im" + formName()); element.insertChildAt(image, 0); flags_.set(BIT_ICON_RENDERED); } if (flags_.test(BIT_TEXT_CHANGED) || all) { element .setProperty(Wt::PropertyInnerHTML, text_.literal() ? escapeText(text_, true).toUTF8() : text_.toUTF8()); flags_.reset(BIT_TEXT_CHANGED); } if (flags_.test(BIT_LINK_CHANGED) || (all && !link_.isNull())) { if (!link_.isNull()) { WApplication *app = WApplication::instance(); if (!redirectJS_) { redirectJS_ = new JSlot(); clicked().connect(*redirectJS_); if (!app->environment().ajax()) clicked().connect(this, &WPushButton::doRedirect); } if (link_.type() == WLink::InternalPath) redirectJS_->setJavaScript ("function(){" WT_CLASS ".history.navigate(" + jsStringLiteral(link_.internalPath()) + ",true);" "}"); else if (linkTarget_ == TargetNewWindow) redirectJS_->setJavaScript ("function(){" "window.open(" + jsStringLiteral(link_.url()) + ");" "}"); else redirectJS_->setJavaScript ("function(){" "window.location=" + jsStringLiteral(link_.url()) + ";" "}"); clicked().senderRepaint(); // XXX only for Java port necessary } else { delete redirectJS_; redirectJS_ = 0; } } WFormWidget::updateDom(element, all); }