@Override
  public void decode(FacesContext facesContext, UIComponent uiComponent) {

    ExternalContext externalContext = facesContext.getExternalContext();
    Map<String, String> requestParameterMap = externalContext.getRequestParameterMap();
    String clientId = uiComponent.getClientId();
    char separatorChar = UINamingContainer.getSeparatorChar(facesContext);
    String escapedEditorName = clientId.replace(separatorChar, '_').concat("_jsptag");

    String submittedValue = requestParameterMap.get(escapedEditorName + "_bbcodeInput");

    if (submittedValue == null) {
      submittedValue = requestParameterMap.get(escapedEditorName);
    }

    InputRichText inputRichText = (InputRichText) uiComponent;
    inputRichText.setSubmittedValue(submittedValue);
  }
  protected String getEditorType(InputRichText inputRichText) {

    String editorType = PropsUtil.get(PropsKeys.EDITOR_WYSIWYG_DEFAULT);
    String editorKey = inputRichText.getEditorKey();

    if (editorKey != null) {
      editorType = PropsUtil.get(editorKey);
    }

    return editorType;
  }
  @Override
  public void copyFrameworkAttributes(
      FacesContext facesContext, InputRichText inputRichText, InputEditorTag inputEditorTag) {

    inputEditorTag.setCssClass(inputRichText.getStyleClass());

    // When ckeditor.jsp renders a hidden textarea, the name is rendered as the id and name
    // attributes of the
    // textarea element. Since this renderer creates its own textarea, it is necessary to set a name
    // that will
    // not interfere when decoding.
    String editorType = getEditorType(inputRichText);
    String escapedEditorName = inputRichText.getClientId();

    char separatorChar = UINamingContainer.getSeparatorChar(facesContext);
    escapedEditorName = escapedEditorName.replace(separatorChar, '_').concat("_jsptag");

    if ("bbcode".equals(editorType)) {
      inputEditorTag.setName(escapedEditorName + "_bbcodeInput");
    } else {
      inputEditorTag.setName(escapedEditorName + "_nonInput");
    }
  }
  @Override
  public void copyNonFrameworkAttributes(
      FacesContext facesContext, InputRichText inputRichText, InputEditorTag inputEditorTag) {

    inputEditorTag.setConfigParams(inputRichText.getConfigParams());
    inputEditorTag.setContentsLanguageId(inputRichText.getContentsLanguageId());
    inputEditorTag.setEditorImpl(inputRichText.getEditorKey());
    inputEditorTag.setFileBrowserParams(inputRichText.getFileBrowserParams());

    char separatorChar = UINamingContainer.getSeparatorChar(facesContext);
    String clientId = inputRichText.getClientId();
    String functionNamespace = clientId.replace(separatorChar, '_');
    inputEditorTag.setInitMethod(functionNamespace + "init");
    inputEditorTag.setOnBlurMethod(functionNamespace + "blur");
    inputEditorTag.setOnChangeMethod(functionNamespace + "change");
    inputEditorTag.setOnFocusMethod(functionNamespace + "focus");
    inputEditorTag.setResizable(inputRichText.isResizable());
    inputEditorTag.setSkipEditorLoading(inputRichText.isSkipEditorLoading());
    inputEditorTag.setToolbarSet(inputRichText.getToolbarSet());
  }
  @Override
  public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException {

    // Encode the starting <div> element that represents the rich text editor.
    ResponseWriter responseWriter = facesContext.getResponseWriter();
    responseWriter.startElement(StringPool.DIV, uiComponent);

    String clientId = uiComponent.getClientId();
    char separatorChar = UINamingContainer.getSeparatorChar(facesContext);
    String escapedEditorName = clientId.replace(separatorChar, '_').concat("_jsptag");
    responseWriter.writeAttribute(StringPool.ID, clientId, null);
    RendererUtil.encodeStyleable(responseWriter, (Styleable) uiComponent);

    // Encode the starting <textarea> element.
    InputRichText inputRichText = (InputRichText) uiComponent;

    responseWriter.startElement("textarea", uiComponent);
    responseWriter.writeAttribute(StringPool.ID, clientId + "_input", null);
    responseWriter.writeAttribute(StringPool.NAME, escapedEditorName, null);
    responseWriter.writeAttribute(Styleable.STYLE, "display:none;", null);

    // Encode the onblur/onchange/onfocus attributes and any associated client behavior scripts.
    String onblur = inputRichText.getOnblur();
    String onchange = inputRichText.getOnchange();
    String onfocus = inputRichText.getOnfocus();
    Map<String, List<ClientBehavior>> clientBehaviorMap = inputRichText.getClientBehaviors();

    for (String eventName : inputRichText.getEventNames()) {
      List<ClientBehavior> clientBehaviorsForEvent = clientBehaviorMap.get(eventName);

      if (clientBehaviorsForEvent != null) {

        for (ClientBehavior clientBehavior : clientBehaviorsForEvent) {

          ClientBehaviorContext clientBehaviorContext =
              ClientBehaviorContext.createClientBehaviorContext(
                  facesContext, inputRichText, eventName, clientId, null);
          String clientBehaviorScript = clientBehavior.getScript(clientBehaviorContext);

          if (clientBehaviorScript != null) {

            if ("valueChange".equals(eventName) || "change".equals(eventName)) {

              if (onchange != null) {
                clientBehaviorScript = onchange.concat(";").concat(clientBehaviorScript);
                onchange = null;
              }

              responseWriter.writeAttribute("onchange", clientBehaviorScript, null);
            } else if ("blur".equals(eventName)) {

              if (onblur != null) {
                clientBehaviorScript = onblur.concat(";").concat(clientBehaviorScript);
                onblur = null;
              }

              responseWriter.writeAttribute("onblur", clientBehaviorScript, null);
            } else if ("focus".equals(eventName)) {

              if (onfocus != null) {
                clientBehaviorScript = onfocus.concat(";").concat(clientBehaviorScript);
                onfocus = null;
              }

              responseWriter.writeAttribute("onfocus", clientBehaviorScript, null);
            }
          }
        }
      }
    }

    if (onblur != null) {
      responseWriter.writeAttribute("onblur", onblur, null);
    }

    if (onchange != null) {
      responseWriter.writeAttribute("onchange", onchange, null);
    }

    if (onfocus != null) {
      responseWriter.writeAttribute("onfocus", onfocus, null);
    }

    // Encode the value of the component as a child of the textarea element.
    Object value = inputRichText.getValue();

    if (value != null) {
      responseWriter.writeText(value, null);
    }

    // Encode the closing </textarea> element.
    responseWriter.endElement("textarea");

    // Encode the script that contains functions with names specific to this component, so that they
    // can be
    // invoked directly by the JavaScript generated by the JSP tag.
    String formattedTemplate = wysiwygTemplate.format(facesContext, inputRichText);
    responseWriter.startElement(StringPool.SCRIPT, uiComponent);
    responseWriter.writeAttribute(StringPool.TYPE, ContentTypes.TEXT_JAVASCRIPT, null);
    responseWriter.write(formattedTemplate);
    responseWriter.endElement(StringPool.SCRIPT);

    // Begin the JSP tag lifecycle and write the output to the response.
    super.encodeBegin(facesContext, uiComponent);
  }