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; }
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"); 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); table->addChild(c); } 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 = createRow(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 *WGLWidget::createDomElement(WApplication *app) { DomElement *result = 0; if (app->environment().agentIsIElt(9) || app->environment().agent() == WEnvironment::MobileWebKitAndroid) { // Shortcut: IE misbehaves when it encounters a canvas element result = DomElement::createNew(DomElement_DIV); if (alternative_) result->addChild(alternative_->createSDomElement(app)); } else { result = DomElement::createNew(DomElement_CANVAS);; if (alternative_) { result->addChild(alternative_->createSDomElement(app)); } } setId(result, app); std::stringstream tmp; tmp << "{\n" """var o = new " WT_CLASS ".WGLWidget(" << app->javaScriptClass() << "," << jsRef() << ");\n" """o.discoverContext(function(){" << webglNotAvailable_.createCall() << "});\n"; js_.str(""); initializeGL(); tmp << """o.initializeGL=function(){\n" //"""debugger;\n" """var obj=" << glObjJsRef() << ";\n" """var ctx=obj.ctx; if(!ctx) return;\n" << "" << js_.str() << """obj.initialized = true;\n" // updates are queued until initialization is complete """var key;\n" """for(key in obj.updates) obj.updates[key]();\n" """obj.updates = new Array();\n" // Similar, resizeGL is not executed until initialized """obj.resizeGL();\n" "};\n" "}\n"; tmp << delayedJavaScript_.str(); delayedJavaScript_.str(""); result->callJavaScript(tmp.str()); repaintGL(PAINT_GL | RESIZE_GL); updateDom(*result, true); return result; }
void WFileUpload::updateDom(DomElement& element, bool all) { bool containsProgress = progressBar_ && progressBar_->parent() == this; DomElement *inputE = 0; if (element.type() != DomElement_INPUT && flags_.test(BIT_DO_UPLOAD) && containsProgress && !progressBar_->isRendered()) element.addChild(progressBar_->createSDomElement(WApplication::instance())); // upload() + disable() does not work. -- fix after this release, // change order of javaScript_ and properties rendering in DomElement if (fileUploadTarget_ && flags_.test(BIT_DO_UPLOAD)) { element.callMethod("submit()"); flags_.reset(BIT_DO_UPLOAD); if (containsProgress) { inputE = DomElement::getForUpdate("in" + id(), DomElement_INPUT); inputE->setProperty(PropertyStyleDisplay, "none"); } } if (flags_.test(BIT_ENABLED_CHANGED)) { if (!inputE) inputE = DomElement::getForUpdate("in" + id(), DomElement_INPUT); if (isDisabled()) inputE->callMethod("disabled=true"); else inputE->callMethod("disabled=false"); flags_.reset(BIT_ENABLED_CHANGED); } EventSignal<> *change = voidEventSignal(CHANGE_SIGNAL, false); if (change && change->needsUpdate(all)) { if (!inputE) inputE = DomElement::getForUpdate("in" + id(), DomElement_INPUT); updateSignalConnection(*inputE, *change, "change", all); } if (inputE) element.addChild(inputE); WWebWidget::updateDom(element, all); }
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 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); }
void WComboBox::updateDom(DomElement& element, bool all) { if (itemsChanged_ || all) { if (!all) element.removeAllChildren(); for (unsigned i = 0; i < items_.size(); ++i) { DomElement *item = DomElement::createNew(DomElement::OPTION); item->setAttribute("value", boost::lexical_cast<std::string>(i)); item->setProperty(Wt::PropertyInnerHTML, items_[i]); if ((int)i == currentIndex_) item->setProperty(Wt::PropertySelected, "true"); element.addChild(item); } itemsChanged_ = false; } if (selectionChanged_) { element.setProperty(Wt::PropertySelectedIndex, boost::lexical_cast<std::string>(currentIndex_)); selectionChanged_ = false; } const WSignalInstance_ *s1 = getSignal(SIGNAL(activated(int))); const WSignalInstance_ *s2 = getSignal(SIGNAL(activated(const std::string))); if (isConnected(s1) || isConnected(s2)) connect(this, SIGNAL(changed()), this, SLOT(propagateChanged())); WFormWidget::updateDom(element, all); renderOk(); }
void WComboBox::updateDom(DomElement& element, bool all) { if (itemsChanged_ || all) { if (!all) element.removeAllChildren(); for (unsigned i = 0; i < items_.size(); ++i) { DomElement *item = DomElement::createNew(DomElement::OPTION); item->setAttribute("value", boost::lexical_cast<std::string>(i)); item->setProperty(Wt::PropertyInnerHTML, toUTF8(escapeText(items_[i].value()))); if ((int)i == currentIndex_) item->setProperty(Wt::PropertySelected, "true"); element.addChild(item); } itemsChanged_ = false; } if (selectionChanged_) { element.setProperty(Wt::PropertySelectedIndex, boost::lexical_cast<std::string>(currentIndex_)); selectionChanged_ = false; } if (activated.isConnected() || sactivated.isConnected()) changed.connect(SLOT(this, WComboBox::propagateChange)); WFormWidget::updateDom(element, all); renderOk(); }
void PaintedSlider::doUpdateDom(DomElement& element, bool all) { if (all) { WApplication *app = WApplication::instance(); element.addChild(createSDomElement(app)); element.addChild(((WWebWidget *)handle_)->createSDomElement(app)); DomElement *west = DomElement::createNew(DomElement_DIV); west->setProperty(PropertyClass, "Wt-w"); element.addChild(west); DomElement *east = DomElement::createNew(DomElement_DIV); east->setProperty(PropertyClass, "Wt-e"); element.addChild(east); } }
void WPaintedWidget::updateDom(DomElement& element, bool all) { if ((all && areaImage_) || areaImageAdded_) { element.addChild(areaImage_->createSDomElement(WApplication::instance())); areaImageAdded_ = false; } WInteractWidget::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); }
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; }
void WContainerWidget::createDomChildren(DomElement& parent) { for (unsigned i = 0; i < children().size(); ++i) { DomElement *c = children()[i]->webWidget()->createSDomElement(); parent.addChild(c); } if (addedChildren_) { delete addedChildren_; addedChildren_ = 0; } }
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); }
void WAbstractMedia::updateMediaDom(DomElement& element, bool all) { // Only if not IE if (all && alternative_) { element.setAttribute("onerror", """if(event.target.error && event.target.error.code==" "" "event.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED){" "" "while (this.hasChildNodes())" "" "if (" WT_CLASS ".hasTag(this.firstChild,'SOURCE')){" "" "this.removeChild(this.firstChild);" "" "}else{" "" "this.parentNode.insertBefore(this.firstChild, this);" "" "}" "" "this.style.display= 'none';" """}" ); } if (all || flagsChanged_) { if ((!all) || flags_.test(PlayerOption::Controls)) element.setAttribute("controls", flags_.test(PlayerOption::Controls) ? "controls" : ""); if ((!all) || flags_.test(PlayerOption::Autoplay)) element.setAttribute("autoplay", flags_.test(PlayerOption::Autoplay) ? "autoplay" : ""); if ((!all) || flags_.test(PlayerOption::Loop)) element.setAttribute("loop", flags_.test(PlayerOption::Loop) ? "loop" : ""); } if (all || preloadChanged_) { switch (preloadMode_) { case MediaPreloadMode::None: element.setAttribute("preload", "none"); break; default: case MediaPreloadMode::Auto: element.setAttribute("preload", "auto"); break; case MediaPreloadMode::Metadata: element.setAttribute("preload", "metadata"); break; } } updateEventSignals(element, all); if (all) if (alternative_) { element.addChild(alternative_->createSDomElement(wApp)); } flagsChanged_ = preloadChanged_ = false; }
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 *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; }
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); }
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 WContainerWidget::updateDomChildren(DomElement& parent, WApplication *app) { if (!app->session()->renderer().preLearning() && !layout_) { if (parent.mode() == DomElement::ModeUpdate) parent.setWasEmpty(wasEmpty()); if (transientImpl_) { std::vector<int> orderedInserts; std::vector<WWidget *>& ac = transientImpl_->addedChildren_; for (unsigned i = 0; i < ac.size(); ++i) orderedInserts.push_back(Utils::indexOf(*children_, ac[i])); Utils::sort(orderedInserts); int addedCount = transientImpl_->addedChildren_.size(); int totalCount = children_->size(); int insertCount = 0; for (unsigned i = 0; i < orderedInserts.size(); ++i) { int pos = orderedInserts[i]; DomElement *c = (*children_)[pos]->createSDomElement(app); if (pos + (addedCount - insertCount) == totalCount) parent.addChild(c); else parent.insertChildAt(c, pos + firstChildIndex()); ++insertCount; } transientImpl_->addedChildren_.clear(); } } #ifndef WT_NO_LAYOUT if (flags_.test(BIT_LAYOUT_NEEDS_UPDATE)) { if (layout_) layoutImpl()->updateDom(parent); flags_.reset(BIT_LAYOUT_NEEDS_UPDATE); } #endif // WT_NO_LAYOUT }
void WScrollArea::updateDom(DomElement& element, bool all) { if (widgetChanged_ || all) { if (widget_) element.addChild(widget_->webWidget()->createDomElement()); widgetChanged_ = false; } if (scrollBarChanged_ || all) { if ((horizontalScrollBar_->tiesChanged_) || (verticalScrollBar_->tiesChanged_)) { horizontalScrollBar_->tiesChanged_ = true; verticalScrollBar_->tiesChanged_ = true; } horizontalScrollBar_->updateDom(element, all); verticalScrollBar_->updateDom(element, all); scrollBarChanged_ = false; } if (scrollBarPolicyChanged_ || all) { switch (scrollBarPolicy_) { case ScrollBarAsNeeded: element.setProperty(Wt::PropertyStyleOverflowX, "auto"); break; case ScrollBarAlwaysOff: element.setProperty(Wt::PropertyStyleOverflowX, "hidden"); break; case ScrollBarAlwaysOn: element.setProperty(Wt::PropertyStyleOverflowX, "scroll"); break; } //result->setProperty(Wt::PropertyStyleOverflowY, "auto"); scrollBarPolicyChanged_ = false; } WWebWidget::updateDom(element, all); renderOk(); }
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 WComboBox::updateDom(DomElement& element, bool all) { if (itemsChanged_ || all) { if (!all) element.removeAllChildren(); for (int i = 0; i < count(); ++i) { DomElement *item = DomElement::createNew(DomElement_OPTION); item->setProperty(PropertyValue, boost::lexical_cast<std::string>(i)); item->setProperty(PropertyInnerHTML, escapeText(asString(model_->data(i, modelColumn_))) .toUTF8()); if (isSelected(i)) item->setProperty(PropertySelected, "true"); WString sc = asString(model_->data(i, modelColumn_, StyleClassRole)); if (!sc.empty()) item->setProperty(PropertyClass, sc.toUTF8()); element.addChild(item); } itemsChanged_ = false; selectionChanged_ = false; } if (selectionChanged_) { element.setProperty(PropertySelectedIndex, boost::lexical_cast<std::string>(currentIndex_)); selectionChanged_ = false; } if (!currentlyConnected_ && (activated_.isConnected() || sactivated_.isConnected())) { currentlyConnected_ = true; changed().connect(this, &WComboBox::propagateChange); } WFormWidget::updateDom(element, all); }
void FlexLayoutImpl::updateDom(DomElement& parent) { WApplication *app = WApplication::instance(); DomElement *div = DomElement::getForUpdate(elId_, DomElementType::DIV); Orientation orientation = getOrientation(); std::vector<int> orderedInserts; for (unsigned i = 0; i < addedItems_.size(); ++i) orderedInserts.push_back(indexOf(addedItems_[i], orientation)); Utils::sort(orderedInserts); int totalStretch = getTotalStretch(orientation); for (unsigned i = 0; i < orderedInserts.size(); ++i) { int pos = orderedInserts[i]; DomElement *el = createElement(orientation, pos, totalStretch, app); div->insertChildAt(el, pos); } addedItems_.clear(); for (unsigned i = 0; i < removedItems_.size(); ++i) div->callJavaScript(WT_CLASS ".remove('" + removedItems_[i] + "');", true); removedItems_.clear(); WStringStream js; js << "layout.adjust(" << grid_.horizontalSpacing_ << ")"; div->callMethod(js.str()); parent.addChild(div); }
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; }
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; }
void WAbstractToggleButton::updateDom(DomElement& element, bool all) { WApplication *app = WApplication::instance(); const WEnvironment& env = app->environment(); DomElement *input = 0; DomElement *span = 0; DomElement *label = 0; // Already apply theme here because it may determine its organization if (all) app->theme()->apply(this, element, 1); if (element.type() == DomElement_INPUT) input = &element; else { if (all) { input = DomElement::createNew(DomElement_INPUT); input->setName("in" + id()); span = DomElement::createNew(DomElement_SPAN); span->setName("t" + id()); if (element.type() != DomElement_LABEL) { label = DomElement::createNew(DomElement_LABEL); label->setName("l" + id()); } } else { input = DomElement::getForUpdate("in" + id(), DomElement_INPUT); span = DomElement::getForUpdate("t" + id(), DomElement_SPAN); } } if (all) updateInput(*input, all); EventSignal<> *check = voidEventSignal(CHECKED_SIGNAL, false); EventSignal<> *uncheck = voidEventSignal(UNCHECKED_SIGNAL, false); EventSignal<> *change = voidEventSignal(CHANGE_SIGNAL, false); EventSignal<WMouseEvent> *click = mouseEventSignal(M_CLICK_SIGNAL, false); /* * We piggy-back the checked and uncheck signals on the change signal. * * If agent is IE, then we piggy-back the change on the clicked signal. */ bool piggyBackChangeOnClick = env.agentIsIE(); bool needUpdateChangeSignal = (change && change->needsUpdate(all)) || (check && check->needsUpdate(all)) || (uncheck && uncheck->needsUpdate(all)); bool needUpdateClickedSignal = (click && click->needsUpdate(all)) || (piggyBackChangeOnClick && needUpdateChangeSignal); WFormWidget::updateDom(*input, all); /* * Copy all properties to the exterior element, as they relate to style, * etc... We ignore here attributes (except for tooltip), * see WWebWidget: other attributes need not be moved. * * But -- bug #423, disabled and readonly are properties that should be * kept on the interior element. */ if (&element != input) { if (element.properties().find(PropertyClass) != element.properties().end()) input->addPropertyWord(PropertyClass, element.getProperty(PropertyClass)); element.setProperties(input->properties()); input->clearProperties(); std::string v = element.getProperty(Wt::PropertyDisabled); if (!v.empty()) { input->setProperty(Wt::PropertyDisabled, v); element.removeProperty(Wt::PropertyDisabled); } v = element.getProperty(Wt::PropertyReadOnly); if (!v.empty()) { input->setProperty(Wt::PropertyReadOnly, v); element.removeProperty(Wt::PropertyReadOnly); } v = input->getAttribute("title"); if (!v.empty()) element.setAttribute("title", v); } if (flags_.test(BIT_STATE_CHANGED) || all) { input->setProperty(Wt::PropertyChecked, state_ == Unchecked ? "false" : "true"); if (supportsIndeterminate(env)) input->setProperty(Wt::PropertyIndeterminate, state_ == PartiallyChecked ? "true" : "false"); else input->setProperty(Wt::PropertyStyleOpacity, state_ == PartiallyChecked ? "0.5" : ""); flags_.reset(BIT_STATE_CHANGED); } std::vector<DomElement::EventAction> changeActions; if (needUpdateChangeSignal || (piggyBackChangeOnClick && needUpdateClickedSignal) || all) { std::string dom = "o"; if (check) { if (check->isConnected()) changeActions.push_back (DomElement::EventAction(dom + ".checked", check->javaScript(), check->encodeCmd(), check->isExposedSignal())); check->updateOk(); } if (uncheck) { if (uncheck->isConnected()) changeActions.push_back (DomElement::EventAction("!" + dom + ".checked", uncheck->javaScript(), uncheck->encodeCmd(), uncheck->isExposedSignal())); uncheck->updateOk(); } if (change) { if (change->isConnected()) changeActions.push_back (DomElement::EventAction(std::string(), change->javaScript(), change->encodeCmd(), change->isExposedSignal())); change->updateOk(); } if (!piggyBackChangeOnClick) { if (!(all && changeActions.empty())) input->setEvent("change", changeActions); } } if (needUpdateClickedSignal || all) { if (piggyBackChangeOnClick) { if (click) { changeActions.push_back (DomElement::EventAction(std::string(), click->javaScript(), click->encodeCmd(), click->isExposedSignal())); click->updateOk(); } if (!(all && changeActions.empty())) input->setEvent(CLICK_SIGNAL, changeActions); } else if (click) updateSignalConnection(*input, *click, CLICK_SIGNAL, all); } if (span) { if (all || flags_.test(BIT_TEXT_CHANGED)) { span->setProperty(PropertyInnerHTML, text_.formattedText()); if(all || flags_.test(BIT_WORD_WRAP_CHANGED)) { span->setProperty(PropertyStyleWhiteSpace, flags_.test(BIT_WORD_WRAP) ? "normal" : "nowrap"); flags_.reset(BIT_WORD_WRAP_CHANGED); } flags_.reset(BIT_TEXT_CHANGED); } } if (&element != input) { if (label) { label->addChild(input); label->addChild(span); element.addChild(label); } else { element.addChild(input); element.addChild(span); } } }
void WAbstractToggleButton::updateDom(DomElement& element, bool all) { WApplication *app = WApplication::instance(); const WEnvironment& env = app->environment(); DomElement *input = 0; DomElement *span = 0; if (element.type() == DomElement_LABEL) { if (all) { input = DomElement::createNew(DomElement_INPUT); input->setName("in" + id()); span = DomElement::createNew(DomElement_SPAN); span->setName("l" + id()); } else { input = DomElement::getForUpdate("in" + id(), DomElement_INPUT); span = DomElement::getForUpdate("l" + id(), DomElement_SPAN); } } else input = &element; if (all) updateInput(*input, all); EventSignal<> *check = voidEventSignal(CHECKED_SIGNAL, false); EventSignal<> *uncheck = voidEventSignal(UNCHECKED_SIGNAL, false); EventSignal<> *change = voidEventSignal(CHANGE_SIGNAL, false); EventSignal<WMouseEvent> *click = mouseEventSignal(M_CLICK_SIGNAL, false); /* * We piggy-back the checked and uncheck signals on the change signal. * * If agent is IE, then we piggy-back the change on the clicked signal. */ bool piggyBackChangeOnClick = env.agentIsIE(); bool needUpdateChangeSignal = (change && change->needsUpdate(all)) || (check && check->needsUpdate(all)) || (uncheck && uncheck->needsUpdate(all)); bool needUpdateClickedSignal = (click && click->needsUpdate(all)) || (piggyBackChangeOnClick && needUpdateChangeSignal); WFormWidget::updateDom(*input, all); /* * Copy all properties to the exterior element, as they relate to style, * etc... We ignore here attributes, see WWebWidget: there seems not to * be attributes that sensibly need to be moved. * * But -- bug #423, disabled and readonly are properties that should be * kept on the interior element. */ if (&element != input) { element.setProperties(input->properties()); input->clearProperties(); std::string v = element.getProperty(Wt::PropertyDisabled); if (!v.empty()) { input->setProperty(Wt::PropertyDisabled, v); element.removeProperty(Wt::PropertyDisabled); } v = element.getProperty(Wt::PropertyReadOnly); if (!v.empty()) { input->setProperty(Wt::PropertyReadOnly, v); element.removeProperty(Wt::PropertyReadOnly); } } if (stateChanged_ || all) { input->setProperty(Wt::PropertyChecked, state_ == Unchecked ? "false" : "true"); if (supportsIndeterminate(env)) input->setProperty(Wt::PropertyIndeterminate, state_ == PartiallyChecked ? "true" : "false"); else input->setProperty(Wt::PropertyStyleOpacity, state_ == PartiallyChecked ? "0.5" : ""); stateChanged_ = false; } std::vector<DomElement::EventAction> changeActions; if (needUpdateChangeSignal || (piggyBackChangeOnClick && needUpdateClickedSignal) || all) { std::string dom = "o"; if (check) { if (check->isConnected()) changeActions.push_back (DomElement::EventAction(dom + ".checked", check->javaScript(), check->encodeCmd(), check->isExposedSignal())); check->updateOk(); } if (uncheck) { if (uncheck->isConnected()) changeActions.push_back (DomElement::EventAction("!" + dom + ".checked", uncheck->javaScript(), uncheck->encodeCmd(), uncheck->isExposedSignal())); uncheck->updateOk(); } if (change) { if (change->needsUpdate(all)) changeActions.push_back (DomElement::EventAction(std::string(), change->javaScript(), change->encodeCmd(), change->isExposedSignal())); change->updateOk(); } if (!piggyBackChangeOnClick) { if (!(all && changeActions.empty())) input->setEvent("change", changeActions); } } if (needUpdateClickedSignal || all) { if (piggyBackChangeOnClick) { if (click) { changeActions.push_back (DomElement::EventAction(std::string(), click->javaScript(), click->encodeCmd(), click->isExposedSignal())); click->updateOk(); } if (!(all && changeActions.empty())) input->setEvent(CLICK_SIGNAL, changeActions); } else if (click) updateSignalConnection(*input, *click, CLICK_SIGNAL, all); } if (span) { if (all || textChanged_) { span->setProperty(PropertyInnerHTML, text_.formattedText()); textChanged_ = false; } } if (&element != input) { element.addChild(input); element.addChild(span); } }
/* * 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; }
void StdGridLayoutImpl2::updateDom(DomElement& parent) { WApplication *app = WApplication::instance(); if (needConfigUpdate_) { needConfigUpdate_ = false; DomElement *div = DomElement::getForUpdate(this, DomElement_DIV); for (unsigned i = 0; i < addedItems_.size(); ++i) { WLayoutItem *item = addedItems_[i]; DomElement *c = createElement(item, app); div->addChild(c); } addedItems_.clear(); for (unsigned i = 0; i < removedItems_.size(); ++i) parent.callJavaScript(WT_CLASS ".remove('" + removedItems_[i] + "');", true); removedItems_.clear(); parent.addChild(div); WStringStream js; js << app->javaScriptClass() << ".layouts2.updateConfig('" << id() << "',"; streamConfig(js, app); js << ");"; app->doJavaScript(js.str()); } if (needRemeasure_) { needRemeasure_ = false; WStringStream js; js << app->javaScriptClass() << ".layouts2.setDirty('" << id() << "');"; app->doJavaScript(js.str()); } if (needAdjust_) { needAdjust_ = false; WStringStream js; js << app->javaScriptClass() << ".layouts2.adjust('" << id() << "', ["; bool first = true; const unsigned colCount = grid_.columns_.size(); const unsigned rowCount = grid_.rows_.size(); for (unsigned row = 0; row < rowCount; ++row) for (unsigned col = 0; col < colCount; ++col) if (grid_.items_[row][col].update_) { grid_.items_[row][col].update_ = false; if (!first) js << ","; first = false; js << "[" << (int)row << "," << (int)col << "]"; } js << "]);"; app->doJavaScript(js.str()); } const unsigned colCount = grid_.columns_.size(); const unsigned rowCount = grid_.rows_.size(); for (unsigned i = 0; i < rowCount; ++i) { for (unsigned j = 0; j < colCount; ++j) { WLayoutItem *item = grid_.items_[i][j].item_; if (item) { WLayout *nested = item->layout(); if (nested) (dynamic_cast<StdLayoutImpl *>(nested->impl()))->updateDom(parent); } } } }