Exemple #1
0
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;

  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);
  }
}
Exemple #3
0
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);
    }
  }
}
Exemple #4
0
void WInteractWidget::updateDom(DomElement& element, bool all)
{
  bool updateKeyDown = false;

  WApplication *app = WApplication::instance();

  /*
   * -- combine enterPress, escapePress and keyDown signals
   */
  EventSignal<> *enterPress = voidEventSignal(ENTER_PRESS_SIGNAL, false);
  EventSignal<> *escapePress = voidEventSignal(ESCAPE_PRESS_SIGNAL, false);
  EventSignal<WKeyEvent> *keyDown = keyEventSignal(KEYDOWN_SIGNAL, false);

  updateKeyDown = (enterPress && enterPress->needsUpdate(all))
    || (escapePress && escapePress->needsUpdate(all))
    || (keyDown && keyDown->needsUpdate(all));

  if (updateKeyDown) {
    std::vector<DomElement::EventAction> actions;

    if (enterPress) {
      if (enterPress->needsUpdate(true)) {
	/*
	 * prevent enterPressed from triggering a changed event on all
	 * browsers except for Opera and IE
	 */
	std::string extraJS;

	const WEnvironment& env = app->environment();

	if (dynamic_cast<WFormWidget *>(this)
	    && !env.agentIsOpera() && !env.agentIsIE())
	  extraJS = "var g=this.onchange;"
	    ""      "this.onchange=function(){this.onchange=g;};";

	actions.push_back
	  (DomElement::EventAction("e.keyCode && (e.keyCode == 13)",
				   enterPress->javaScript() + extraJS,
				   enterPress->encodeCmd(),
				   enterPress->isExposedSignal()));
      }
      enterPress->updateOk();
    }

    if (escapePress) {
      if (escapePress->needsUpdate(true)) {
	actions.push_back
	  (DomElement::EventAction("e.keyCode && (e.keyCode == 27)",
				   escapePress->javaScript(),
				   escapePress->encodeCmd(),
				   escapePress->isExposedSignal()));
      }
      escapePress->updateOk();
    }

    if (keyDown) {
      if (keyDown->needsUpdate(true)) {
	actions.push_back
	  (DomElement::EventAction(std::string(),
				   keyDown->javaScript(),
				   keyDown->encodeCmd(),
				   keyDown->isExposedSignal()));
      }
      keyDown->updateOk();
    }

    if (!actions.empty())
      element.setEvent("keydown", actions);
    else if (!all)
      element.setEvent("keydown", std::string(), std::string());
  }

  /*
   * -- allow computation of dragged mouse distance
   */
  EventSignal<WMouseEvent> *mouseDown
    = mouseEventSignal(MOUSE_DOWN_SIGNAL, false);
  EventSignal<WMouseEvent> *mouseUp
    = mouseEventSignal(MOUSE_UP_SIGNAL, false);
  EventSignal<WMouseEvent> *mouseMove
    = mouseEventSignal(MOUSE_MOVE_SIGNAL, false);
  EventSignal<WMouseEvent> *mouseDrag
    = mouseEventSignal(MOUSE_DRAG_SIGNAL, false);

  bool updateMouseMove
    = (mouseMove && mouseMove->needsUpdate(all))
    || (mouseDrag && mouseDrag->needsUpdate(all));

  bool updateMouseDown
    = (mouseDown && mouseDown->needsUpdate(all))
    || updateMouseMove;

  bool updateMouseUp
    = (mouseUp && mouseUp->needsUpdate(all))
    || updateMouseMove;

  std::string CheckDisabled = "if($(o).hasClass('" +
    app->theme()->disabledClass() +
    "')){" WT_CLASS ".cancelEvent(e);return;}";

  if (updateMouseDown) {
    /*
     * when we have a mouseUp event, we also need a mouseDown event
     * to be able to compute dragDX/Y.
     *
     * When we have:
     *  - a mouseDrag
     *  - or a mouseDown + (mouseMove or mouseUp),
     * we need to capture everything after on mouse down, and keep track of the
     * down button if we have a mouseMove or mouseDrag
     */
    WStringStream js;

    js << CheckDisabled;

    if (mouseUp && mouseUp->isConnected())
      js << app->javaScriptClass() << "._p_.saveDownPos(event);";

    if ((mouseDrag && mouseDrag->isConnected())
	|| (mouseDown && mouseDown->isConnected()
	    && ((mouseUp && mouseUp->isConnected())
		|| (mouseMove && mouseMove->isConnected()))))
      js << WT_CLASS ".capture(this);";

    if ((mouseMove && mouseMove->isConnected())
	|| (mouseDrag && mouseDrag->isConnected()))
      js << WT_CLASS ".mouseDown(e);";

    if (mouseDown) {
      js << mouseDown->javaScript();
      element.setEvent("mousedown", js.str(),
		       mouseDown->encodeCmd(), mouseDown->isExposedSignal());
      mouseDown->updateOk();
    } else
      element.setEvent("mousedown", js.str(), std::string(), false);
  }

  if (updateMouseUp) {
    WStringStream js;

    /*
     * when we have a mouseMove or mouseDrag event, we need to keep track
     * of unpressing the button.
     */
    js << CheckDisabled;

    if ((mouseMove && mouseMove->isConnected())
	|| (mouseDrag && mouseDrag->isConnected()))
      js << WT_CLASS ".mouseUp(e);";
      
    if (mouseUp) {
      js << mouseUp->javaScript();
      element.setEvent("mouseup", js.str(),
		       mouseUp->encodeCmd(), mouseUp->isExposedSignal());
      mouseUp->updateOk();
    } else
      element.setEvent("mouseup", js.str(), std::string(), false);
  }

  if (updateMouseMove) {
    /*
     * We need to mix mouseDrag and mouseMove events.
     */
    std::vector<DomElement::EventAction> actions;
    
    if (mouseMove) {
      actions.push_back
	(DomElement::EventAction(std::string(),
				 mouseMove->javaScript(),
				 mouseMove->encodeCmd(),
				 mouseMove->isExposedSignal()));
      mouseMove->updateOk();
    }

    if (mouseDrag) {
      actions.push_back
	(DomElement::EventAction(WT_CLASS ".buttons",
				 mouseDrag->javaScript()
				 + WT_CLASS ".drag(e);",
				 mouseDrag->encodeCmd(),
				 mouseDrag->isExposedSignal()));
      mouseDrag->updateOk();
    }

    element.setEvent("mousemove", actions);
  }

  /*
   * -- mix mouseClick and mouseDblClick events in mouseclick since we
   *    only want to fire one of both
   */
  EventSignal<WMouseEvent> *mouseClick
    = mouseEventSignal(M_CLICK_SIGNAL, false);
  EventSignal<WMouseEvent> *mouseDblClick
    = mouseEventSignal(DBL_CLICK_SIGNAL, false);  

  bool updateMouseClick
    = (mouseClick && mouseClick->needsUpdate(all))
    || (mouseDblClick && mouseDblClick->needsUpdate(all));

  if (updateMouseClick) {
    WStringStream js;

    js << CheckDisabled;

    if (mouseDrag)
      js << "if (" WT_CLASS ".dragged()) return;";

    if (mouseDblClick && mouseDblClick->needsUpdate(all)) {
      /*
       * Click: if timer is running:
       *  - clear timer, dblClick()
       *  - start timer, clear timer and click()
       */

      /* We have to prevent this immediately ! */
      if (mouseClick) {
	if (mouseClick->defaultActionPrevented() ||
	    mouseClick->propagationPrevented()) {
	  js << WT_CLASS ".cancelEvent(e";
	  if (mouseClick->defaultActionPrevented() &&
	      mouseClick->propagationPrevented())
	    js << ");";
	  else if (mouseClick->defaultActionPrevented())
	    js << ",0x2);";
	  else
	    js << ",0x1);";
	}
      }

      js << "if(" WT_CLASS ".isDblClick(o, e)) {"
	 << mouseDblClick->javaScript();

      if (mouseDblClick->isExposedSignal())
	js << app->javaScriptClass()
		 << "._p_.update(o,'" << mouseDblClick->encodeCmd()
		 << "',e,true);";

      mouseDblClick->updateOk();

      js <<
	"}else{"
	"""if (" WT_CLASS ".isIElt9 && document.createEventObject) "
	""  "e = document.createEventObject(e);"
	"""o.wtE1 = e;"
	"""o.wtClickTimeout = setTimeout(function() {"
	""   "o.wtClickTimeout = null; o.wtE1 = null;";

      if (mouseClick) {
	js << mouseClick->javaScript();

	if (mouseClick->isExposedSignal()) {
	  js << app->javaScriptClass()
		   << "._p_.update(o,'" << mouseClick->encodeCmd()
		   << "',e,true);";
	}

	mouseClick->updateOk();
      }

      const Configuration& conf = app->environment().server()->configuration();
      js << "}," << conf.doubleClickTimeout() << ");}";
    } else {
      if (mouseClick && mouseClick->needsUpdate(all)) {
	js << mouseClick->javaScript();

	if (mouseClick->isExposedSignal()) {
	  js << app->javaScriptClass()
	     << "._p_.update(o,'" << mouseClick->encodeCmd()
	     << "',e,true);";
	}

	mouseClick->updateOk();
      }
    }

    element.setEvent(CLICK_SIGNAL, js.str(),
		     mouseClick ? mouseClick->encodeCmd() : "");

    if (mouseDblClick) {
      if (app->environment().agentIsIElt(9))
	element.setEvent("dblclick", "this.onclick()");
    }
  }

  /*
   * -- mouseOver with delay
   */
  EventSignal<WMouseEvent> *mouseOver
    = mouseEventSignal(MOUSE_OVER_SIGNAL, false);
  EventSignal<WMouseEvent> *mouseOut
    = mouseEventSignal(MOUSE_OUT_SIGNAL, false); 

  bool updateMouseOver = mouseOver && mouseOver->needsUpdate(all);

  if (mouseOverDelay_) {
    if (updateMouseOver) {
      WStringStream js;
      js << "o.over=setTimeout(function() {"
	 << "o.over = null;"
	 << mouseOver->javaScript();

      if (mouseOver->isExposedSignal()) {
	js << app->javaScriptClass()
	   << "._p_.update(o,'" << mouseOver->encodeCmd() << "',e,true);";
      }

      js << "}," << mouseOverDelay_ << ");";

      element.setEvent("mouseover", js.str(), "");

      mouseOver->updateOk();

      if (!mouseOut)
	mouseOut = mouseEventSignal(MOUSE_OUT_SIGNAL, true);

      element.setEvent("mouseout",
		       "clearTimeout(o.over); o.over=null;"
		       + mouseOut->javaScript(),
		       mouseOut->encodeCmd(), mouseOut->isExposedSignal());
      mouseOut->updateOk();
    }
  } else {
    if (updateMouseOver) {
      element.setEventSignal("mouseover", *mouseOver);
      mouseOver->updateOk();
    }

    bool updateMouseOut = mouseOut && mouseOut->needsUpdate(all);

    if (updateMouseOut) {
      element.setEventSignal("mouseout", *mouseOut);
      mouseOut->updateOk();
    }
  }

  updateEventSignals(element, all);

  WWebWidget::updateDom(element, all);
}