As we know, in the social media integration solution of SAP CRM call center, if a Twitter account is configured in the system, all tweets with this account on the Twitter website will be automatically captured in SAP CRM call center for agents to process.

The test tweet from the @AndrewPang6 account is captured in the SAP CRM call center and looks like this. An agent in the call center can click the Reply button in the CRM system to Reply.

The customer opens the tweeter site and sees the response.

Here is the code for this function:

<%@page language="abap" %>
<%@extension name="thtmlb" prefix="thtmlb" %>
<%@extension name="chtmlb" prefix="chtmlb" %>
<%@extension name="bsp" prefix="bsp" %>
<%
  data: lv_send_btn type string.
  data: lv_title_prefix type string,
  lv_replyid type string.
  lv_send_btn = cl_wd_utilities=>get_otr_text_by_alias( 'CRM_UIU_SOC_SMC/SEND_BUTTON' ). "#EC NOTEXT.
  lv_replyid = '_socialpost_struct.content'.
  lv_title_prefix = cl_wd_utilities=>get_otr_text_by_alias( 'CRM_UIU_SOC_SMC/COUNTER_TXT' ). "#EC NOTEXT.
  lv_title_prefix = lv_title_prefix && ':'.
  lv_replyid = controller->component_id && lv_replyid.
%>
<chtmlb:config displayMode = "<%= controller->view_group_context->is_view_in_display_mode( controller ) %>"
               mode        = "RUNTIME"
               xml         = "<%= controller->configuration_descr->get_config_data( ) %>" />
<p id="COUNTER_TXT"  style="margin-left: 8px; margin-top: 1px; margin-bottom: 4px; margin-right: 8px; color:rgb(102,102,102)"></p>
<p>
   
<thtmlb:button design  = "EMPHASIZED"
               id      = "SEND_BTN"
               onClick = "send"
               text    = "<%= lv_send_btn %>" />
  </P>
<script type="text/javascript">
  var content;
  var counter;
  var cur_pos;
  function forwardStdResponseText(reqObj) {
   insertText(reqObj);
  }
  function forwardStdResponseTextDelayed(reqObj) {
   insertText(reqObj, true);
}
function insertText(reqObj, delayed) {
var textcontent = reqObj.request.responseText;
 if(! delayed){ insertTextIntoTextEditor( textcontent); }else{ <%--restoreBTFCursorPosition(); insertTextIntoTextEditor( textcontent); - % >document.getElementById( "<%= lv_replyid %>" ).value = document.getElementById( "<%= lv_replyid %>" ).value + reqObj.request.responseText;
  }
  refreshCounter();
}

function TrimLeadingSpace(texttotrim)
{
  var currchar;
 var spaceindex = 0;
 currchar = texttotrim.substr(0.1);
 while(currchar=="")
 {
   spaceindex = spaceindex + 1;
   currchar = texttotrim.substr(spaceindex, 1);

 }
 var substrlen = texttotrim.length - spaceindex;

 var trimmedtext = texttotrim.substr(spaceindex, substrlen);
 alert(trimmedtext);
 return trimmedtext;
}

 function storeBTFCursorPosition(){
     var cursorPos = 0;
     var textarea1 = document.getElementById("<%= lv_replyid %>");
     var range;
     var textvalue;
     textvalue = textarea1.value;
     textarea1.focus();
     range = document.selection.createRange();
     range.moveStart('character', -textarea1.value.length);
     var trimmedtxt = TrimLeadingSpace(range.text);
     var spacefromuser = textvalue.search(trimmedtxt);     
     cursorPos = spacefromuser + trimmedtxt.length;
     alert(spacefromuser);
     alert(trimmedtxt.length);
     return cursorPos;
   }

function restoreBTFCursorPosition(){
   var texta1 = document.getElementById("<%= lv_replyid %>");
   var range;
   var curpos = cur_pos;
   texta1.focus();
   range = document.selection.createRange();
   range.moveStart( 'character', texta1.value.length );
   range.moveEnd( 'character', texta1.value.length );
   range.moveStart( 'character', curpos );
   range.moveEnd( 'character'.0 );
   range.select();
  }
function insertTextIntoTextEditor( textToInsert ){
     var text_area = document.getElementById( "<%= lv_replyid %>" );
     text_area.focus();
     if(document.selection)
     {
     document.selection.createRange().text = textToInsert;
     }     
}
<%-- below functions are for, reply text counter implementation --%>
  function refreshCounter()
  {
    var sCount = "<%= lv_title_prefix %>" + content.value.length;
    counter.innerHTML = sCount;
  }
  function fillTitle()
  {
    var textvalue;
    textvalue = document.getElementById("<%= lv_replyid %>").value;
    counter.innerHTML = "<%= lv_title_prefix %>" + textvalue.length;
  }
  if( "<%= controller->mv_switch_on %>"= ="X" )
  {
      content = document.getElementById("<%= lv_replyid %>");
      counter = document.getElementById("COUNTER_TXT");
      if( content ! =null )
      {
        content.onkeyup = refreshCounter;
        content.onmouseout = refreshCounter;
        content.onmousemove = refreshCounter;
      }
      fillTitle();
  }
</script>
<%
  DATA: ls_header type CRMT_THTMLB_AREA_FRAME_HEAD.
  ls_header-title = 'Conversation History'.
%>
<thtmlb:splitter splitterPosition = "65%"
                 height           = "100%" >
  <thtmlb:grid cellSpacing = "0"
               columnSize  = "2"
               height      = "100%"
               rowSize     = "1"
               width       = "100%" >
    <thtmlb:gridCell colSpan     = "1"
                     columnIndex = "1"
                     rowIndex    = "1"
                     height      = "100%"
                     rowSpan     = "1" >
      <thtmlb:splitterCell minSize = "20%"
                           vAlign  = "top"
                           align   = "left" >
        <bsp:call comp_id = "<%= controller->GET_VIEWAREA_CONTENT_ID( 'PostDetails' ) %>"
                  url     = "<%= controller->GET_VIEWAREA_CONTENT_URL( 'PostDetails' ) %>" />
        <bsp:call comp_id = "<%= controller->GET_VIEWAREA_CONTENT_ID( 'OverviewPage' ) %>"
                  url     = "<%= controller->GET_VIEWAREA_CONTENT_URL( 'OverviewPage' ) %>" />
        <div id = "div1" style="display:block; margin-top: 10px">
        <thtmlb:areaFrame id            = "areaFrame1"
                          header        = "<%= ls_header %>"
                          isCollapsible = "true"
                          checkContent  = "true"
                          lateRendering = "true" >
          <thtmlb:areaFrameBody contentBorder="false" >
            <bsp:call comp_id = "<%= controller->GET_VIEWAREA_CONTENT_ID( 'ConversationHistory' ) %>"
                      url     = "<%= controller->GET_VIEWAREA_CONTENT_URL( 'ConversationHistory' ) %>" />
          </thtmlb:areaFrameBody>
        </thtmlb:areaFrame>
        </div>
      </thtmlb:splitterCell>
    </thtmlb:gridCell>
    <thtmlb:gridCell colSpan     = "1"
                     columnIndex = "2"
                     rowIndex    = "1"
                     height      = "100%"
                     rowSpan     = "1" >
      <thtmlb:splitterCell minSize = "20%"
                           vAlign  = "top"
                           align   = "left" >
        <bsp:call comp_id = "<%= controller->GET_VIEWAREA_CONTENT_ID( 'PostDetails' ) %>"
                  url     = "<%= controller->GET_VIEWAREA_CONTENT_URL( 'PostDetails' ) %>" />
      </thtmlb:splitterCell>
    </thtmlb:gridCell>
  </thtmlb:grid>
</thtmlb:splitter>

<%@page language="abap" %>
<%@extension name="thtmlb" prefix="thtmlb" %>
<%@extension name="chtmlb" prefix="chtmlb" %>
<%@extension name="bsp" prefix="bsp" %>
<%
  DATA: ls_header type CRMT_THTMLB_AREA_FRAME_HEAD.
  IF controller->MV_CONV_HISTORY_SWITCH_ON = abap_true.
  ls_header-title = cl_wd_utilities=>get_otr_text_by_alias( 'CRM_UIU_SOC_SMC/REPLY_CONV_HISTORY' ).
  ENDIF.
%>
<thtmlb:grid cellSpacing = "0"
             columnSize  = "1"
             height      = "100%"
             rowSize     = "3"
             width       = "100%" >
  <thtmlb:gridCell colSpan     = "1"
                   columnIndex = "1"
                   rowIndex    = "1"
                   height      = "100%"
                   rowSpan     = "1" >
    <bsp:call comp_id = "<%= controller->GET_VIEWAREA_CONTENT_ID( 'PostDetails' ) %>"
              url     = "<%= controller->GET_VIEWAREA_CONTENT_URL( 'PostDetails' ) %>" />
  </thtmlb:gridCell>
  <thtmlb:gridCell colSpan     = "1"
                   columnIndex = "1"
                   rowIndex    = "2"
                   height      = "100%"
                   rowSpan     = "1" >
    <bsp:call comp_id = "<%= controller->GET_VIEWAREA_CONTENT_ID( 'OverviewPage' ) %>"
              url     = "<%= controller->GET_VIEWAREA_CONTENT_URL( 'OverviewPage' ) %>" />
  </thtmlb:gridCell>
  <%
  IF controller->MV_CONV_HISTORY_SWITCH_ON eq abap_true.
  %>
  <thtmlb:gridCell colSpan     = "1"
                   columnIndex = "1"
                   rowIndex    = "3"
                   height      = "100%"
                   rowSpan     = "1" >
    <div style="display:block; margin-top: 5px">
    <thtmlb:areaFrame id            = "areaFrame1"
                      header        = "<%= ls_header %>"
                      isCollapsible = "true"
                      checkContent  = "true"
                      lateRendering = "true" >
      <thtmlb:areaFrameBody contentBorder="false" >
        <bsp:call comp_id = "<%= controller->GET_VIEWAREA_CONTENT_ID( 'ConversationHistory' ) %>"
                  url     = "<%= controller->GET_VIEWAREA_CONTENT_URL( 'ConversationHistory' ) %>" />
      </thtmlb:areaFrameBody>
    </thtmlb:areaFrame>
  </thtmlb:gridCell>
  <%
  ENDIF.
  %>
</thtmlb:grid>
Copy the code

When using the Reply page, standard Response’s Search button searches and applies the mail Form content to the middle of the existing text in the Editor, You need to save the location of the search button by clicking on storeBTFCursorPosition. This position is the insertion out of the mail Form content.

Use range. MoveStart in the initial design to calculate cursor position. The assumption is that when the value of move exceeds the length of text, this method only returns the actual move position, that is, the distance between the cursor and the starting position of text. In actual testing, the return value of this method is found to be uncertain. When the cursor is in certain positions, the return value matches the expected value. But in some places, the return value is different from what is expected. Through the content of alert range.text, it is found that the reason for the inconsistency is that range.text contains a large number of Spaces, which are also calculated as the text length of range.text. This results in inaccurate values.

The solution

  1. Still use Movestart to get the text content of the range (including Spaces)
  2. Remove leading space from range’s text. Note that the leading space will be removed if the user enters Spaces at the beginning of the text.
  3. Use the string search method to find the position of the original text in step 2 after whitespace is removed. This is essentially counting the number of Spaces the user enters himself at the beginning of the text.
  4. Add the length of range’s text (minus leading space) to the cursor position

For more of Jerry’s original articles, please follow the public account “Wang Zixi “: