1

I generate dynamic span elements on "Link", "FistName", "LastName" buttons thanks to onclick event. The problem is that I would like to create these spans based on cursor position. I found a script on Internet and changed it to adapt in my function editTag() but no success. Did I miss something in this script or?

Edit: I just founded a similar question, tried to adapt my code, but I still get the problem, impossible to add the span based on cursor position! :/

Inserting a text where cursor is using Javascript/jquery

var area = document.getElementById("template");
var message = document.getElementById("message");
var maxLength = 160;
var re = new RegExp("ô|â|ê|ç");

var myTags = new Object();
var cursorPosition = 0;
var smsNode = null;

myTags['company'] = '#ENTREPRISE#';
myTags['city'] = '#VILLE#';
myTags['link'] = '#LIEN#';
myTags['firstname'] = '#PRENOM#';
myTags['lastname'] = '#NOM#';
myTags['title'] = '#TITRE#';

$("#smsArea").on('keyup mouseup',function(e)
{ 
 //console.log(window.getSelection().anchorOffset);

 /*if(this.hasChildNodes())
 {
  var node = this.childNodes;
  console.log(node);
 }*/

 /*smsNode = this.textContent;
 console.log(smsNode);*/
    /*if($(window.getSelection().anchorNode).is($(this)))
    {
     cursorPosition = 0;
    }
    else
    {*/
        cursorPosition = window.getSelection().getRangeAt(0);
        var smsNode = cursorPosition;
        console.log(cursorPosition);
    //}
 });

function insertAfter(referenceNode, newNode) 
{
    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

function editTag(zoneId,tag,button)
{

 var btnSms = document.getElementById(button.id);
 var zoneDiv  = document.getElementById(zoneId + 'Area');
 var myButton  = document.getElementById(zoneId + tag.ucfirst());
 var myLabel  = document.createElement('span');

 var labels   = zoneDiv.getElementsByTagName('span');
 var spanSize = labels.length;

 var delflag  = 0;
 var delIndex = 0;

 var textNode    = document.createTextNode('\u00A0');

 //var spanSpace = " ";

 /*if(btnSms)
 {
  btnSms.classList.toggle("btn-danger");
 }
 else
 {
  btnSms.classList.toggle("btn-success");
 }*/

 if(spanSize != 0)
 {

  for (myLabId = 0; myLabId < spanSize; myLabId++)
  {
   var currentLabel = labels[myLabId];
   if(currentLabel.innerHTML === myButton.innerHTML)
   {
    delflag = 1;
    delIndex = myLabId;
   }
  }
 }

 if(delflag == 1)
    {
     btnSms.classList.remove("btn-danger");
        btnSms.classList.add("btn-default");
        zoneDiv.removeChild(labels[delIndex]);
    }
 else
 {
  myLabel.setAttribute('class', 'label label-info');
  myLabel.setAttribute('data-effect', 'pop');
  myLabel.setAttribute('contentEditable', 'false');
  myLabel.setAttribute('style','cursor:move;font-size:100%;');
  myLabel.setAttribute('name', tag);
  myLabel.setAttribute('id', 'tag');
  myLabel.setAttribute('draggable', 'true');
  myLabel.innerHTML = myButton.innerHTML;

  zoneDiv.appendChild(myLabel);
  //zoneDiv.appendChild(textNode);
  //document.getElementById(myLabel).insertAfter(textNode);
  insertAfter(myLabel, textNode);
  btnSms.classList.add("btn-danger");
 }

 //Clean breaklines;
 var bks  = zoneDiv.getElementsByTagName('br');
 var brSize  = bks.length;
 
 if(brSize != 0)
 {
  zoneDiv.removeChild(bks[0]);
 }

 //Event keyboard on deleted elements
 $("span").dblclick(function(handler)
 {
  myLabel.remove(labels[delIndex]);
  btnSms.classList.remove("btn-danger");
  btnSms.classList.add("btn-default");
 });
}

String.prototype.ucfirst = function() {
  return this.charAt(0).toUpperCase() + this.substr(1);
}
#smsArea {
  -moz-appearance: textfield-multiline;
  -webkit-appearance: textarea;
  height: 150px;
  overflow: auto;
  padding: 5px;
  resize: both;
  width: 100%;
}

.smstext {
  /*  margin-top: 100px;*/
  margin-left: 60px;
  margin-right: 20px;
  padding-top: 30px;
  font-family: verdana, sans-serif;
}

#mailArea {
  -moz-appearance: textfield-multiline;
  -webkit-appearance: textarea;
  height: 200px;
  overflow: auto;
  padding: 5px;
  resize: both;
  width: 500px;
  font-size: 12px;
  margin-top: 5px;
}

.mailInput {
  -moz-appearance: textfield-multiline;
  -webkit-appearance: textarea;
  overflow: auto;
  padding: 5px;
  resize: both;
  font-size: 12px;
  margin-top: 5px;
  width: 300px;
  height: 85px;
  margin-left: 100px;
  margin-top: -20px;
}

.mailtext {
  /*      margin-top: 100px;*/
  margin-left: 60px;
  margin-right: 20px;
  padding-top: 30px;
  font-family: verdana, sans-serif;
}

#webtag {
  margin-top: -392px;
  margin-left: 555px;
  width: 569px;
}

#result {
  display: none;
}

#interaction {
  margin-top: 30px;
  visibility: hidden;
}

#cd-popup {
  background-color: rgba(94, 110, 141, 0.9);
  opacity: 1;
  -webkit-transition: opacity 0.3s 0s, visibility 0s 0.3s;
  -moz-transition: opacity 0.3s 0s, visibility 0s 0.3s;
  transition: opacity 0.3s 0s, visibility 0s 0.3s;
  position: relative;
  width: 100%;
  max-width: 800px;
  height: 350px;
  margin: 4em auto;
  border-radius: .25em .25em .4em .4em;
  text-align: center;
  box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
  -webkit-transform: translateY(-40px);
  -moz-transform: translateY(-40px);
  -ms-transform: translateY(-40px);
  -o-transform: translateY(-40px);
  transform: translateY(-40px);
  /* Force Hardware Acceleration in WebKit */
  -webkit-backface-visibility: hidden;
  -webkit-transition-property: -webkit-transform;
  -moz-transition-property: -moz-transform;
  transition-property: transform;
  -webkit-transition-duration: 0.3s;
  -moz-transition-duration: 0.3s;
  transition-duration: 0.3s;
  z-index: 1;
}

#cd-popup.is-visible {
  opacity: 1;
  visibility: visible;
  -webkit-transition: opacity 0.3s 0s, visibility 0s 0s;
  -moz-transition: opacity 0.3s 0s, visibility 0s 0s;
  transition: opacity 0.3s 0s, visibility 0s 0s;
}

#cd-popup p {
  padding: 3em 1em;
  margin-left: -250px;
  height: 100px;
}

#cd-popup div {
  float: left;
  width: 30%;
  list-style: none;
  display: block;
  height: 60px;
  line-height: 60px;
  text-transform: uppercase;
  color: #FFF;
  -webkit-transition: background-color 0.2s;
  -moz-transition: background-color 0.2s;
  transition: background-color 0.2s;
}

#object {
  background: #fc7169;
  border-radius: 0 0 0 .25em;
  width: 175px;
  margin-left: -400px;
  cursor: pointer;
  padding: 3px 6px;
  display: inline-block;
}

#object:hover {
  background-color: #fc8982;
}

#body {
  background: #6495ED;
  border-radius: 0 0 0 .25em;
  width: 175px;
  cursor: pointer;
  padding: 3px 6px;
  display: inline-block;
  margin-left: -150px;
}

#body:hover {
  background-color: #fc8982;
}

#titre {
  background: #A52A2A;
  border-radius: 0 0 0 .25em;
  width: 175px;
  margin-left: 10px;
  cursor: pointer;
  padding: 3px 6px;
  display: inline-block;
}

#titre:hover {
  background-color: #fc8982;
}

#note {
  background: #006400;
  border-radius: 0 0 0 .25em;
  width: 175px;
  margin-left: 10px;
  cursor: pointer;
  padding: 3px 6px;
  display: inline-block;
}

#cd-popup #note:hover {
  background-color: lightsteelblue;
}

#cd-popup .cd-popup-close {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 30px;
  height: 30px;
}

#cd-popup .cd-popup-close::before,
#cd-popup .cd-popup-close::after {
  content: '';
  position: absolute;
  top: 12px;
  width: 14px;
  height: 3px;
  background-color: #8f9cb5;
}

#cd-popup .cd-popup-close::before {
  -webkit-transform: rotate(45deg);
  -moz-transform: rotate(45deg);
  -ms-transform: rotate(45deg);
  -o-transform: rotate(45deg);
  transform: rotate(45deg);
  left: 8px;
}

#cd-popup .cd-popup-close::after {
  -webkit-transform: rotate(-45deg);
  -moz-transform: rotate(-45deg);
  -ms-transform: rotate(-45deg);
  -o-transform: rotate(-45deg);
  transform: rotate(-45deg);
  right: 8px;
}

@media only screen and (min-width: 1170px) {
  #cd-popup {
    margin: 8em auto;
  }
}

.webArea {
  -moz-appearance: textfield-multiline;
  -webkit-appearance: textarea;
  height: 520px;
  /*overflow: auto;*/
  padding: 5px;
  /*resize: both;*/
  width: 630px;
  font-size: 12px;
  /*margin-top: 55px;*/
  border: 2px dashed #D9D9D9;
  border-radius: 5px;
  text-align: center;
  margin-top: 12%;
}

.webArea>div {
  background-color: #FAEBD7;
  border: 3px dashed #D9D9D9;
  margin-bottom: 15px;
  height: 120px;
  width: 612px;
  overflow: auto;
  overflow-x: hidden;
  /*    margin-left: -1.5%;*/
}

.webArea>div>div {
  transition: all .5s;
  text-align: center;
  float: left;
  padding: 1em;
  margin: 0 1em 1em 0;
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
  border-radius: 5px;
  border: 2px solid black;
  /*background: #F7F7F7;*/
  transition: all .5s ease;
  width: 582px;
  /*background-color: #F8F8FF;*/
  height: 110px;
}

.dropTarget>div>div>span {
  font-style: italic;
  margin-right: 5%;
  font-size: 16px;
}

.webArea>div>div>input {
  margin-right: 25%;
  width: 250px;
  height: 40px;
  background-color: white;
}

.webArea>div>div:active {
  /*-webkit-animation: wiggle 0.3s 0s infinite ease-in;
    animation: wiggle 0.3s 0s infinite ease-in;*/
  opacity: .6;
  border: 2px solid #000;
}

#mailArea {
  -moz-appearance: textfield-multiline;
  -webkit-appearance: textarea;
  height: 200px;
  overflow: auto;
  padding: 5px;
  resize: both;
  width: 500px;
  font-size: 12px;
  margin-top: 5px;
}

#containerZone {
  border: 1px solid;
  border-radius: 25px;
  */ margin: 3%;
  width: 70%;
  height: 40px;
  text-align: center;
  font-weight: bold;
  color: #000000;
  margin: auto;
  margin-top: 8%;
  margin-left: -450px;
}

#containerZone2 {
  border: 1px solid;
  border-radius: 25px;
  width: 70%;
  height: 40px;
  text-align: center;
  font-weight: bold;
  color: #000000;
  margin: auto;
  margin-top: 100%;
  margin-left: -450px;
}

#webtags {
  margin-top: -40px;
}

#webtags>div {
  margin-left: 20px;
}

#modalTagBody {
  height: 120px;
}

#btnTag {
  margin-top: 20px;
  margin-right: 15px;
}
<html>

<head>
  <meta charset="utf-8">
  <title>Drag & drop Tag</title>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <!-- Latest compiled and minified CSS -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

  <!-- Optional theme -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">

  <!-- Latest compiled and minified JavaScript -->
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.0/jquery-confirm.min.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.0/jquery-confirm.min.js"></script>
</head>

<body>
  <div class="container mtb">
    <div class="row">
      <TMPL_IF NAME="PROFILE">
        <form role="form" action="<TMPL_VAR NAME=MYURL>?rm=saveTemplate" method="POST" enctype="application/x-www-form-urlencoded">
          <TMPL_LOOP NAME="DATA">
            <input type="hidden" id='id' name="id" value="<TMPL_VAR NAME=ID>" />
            <TMPL_IF NAME="TEMPLATE">
              <div class="panel panel-primary" id="panels" data-effect="helix">
                <div class="panel-heading">SMS Message</div>
                <div class="panel-body">
                  <div class="col-lg-6">
                    <div class="form-group">
                    </div>
                    <input type="hidden" name="rm" value="saveTemplate" />
                    <div id="smsArea" class="form-control" contenteditable="true">
                      <p id="smsDraft">
                        <TMPL_VAR NAME=TEMPLATE>
                      </p>
                    </div><br />
                    <div>position: <span id="position"></span></div>
                    <a href="#" class="btn btn-primary" onClick="saveMessage('sms');">Save</a>
                    <a href="#" class="btn btn-primary" onClick="previewMessage('sms');" data-toggle="modal" data-target="#myModal2">Preview</a>
                    <a href="#" class="btn btn-primary" onClick="testMessage('sms');" data-toggle="modal" data-target="#myModal">SMS Costs</a>
                    <br>
                  </div>
                  <div class="col-lg-6" id='smsTags'>
                    <h4 for="template">Personnalization</h4>
                    <span class="btn btn-default" onClick="editTag('sms','link', this)" id="smsLink" title="link of your website" draggable="true">Link</span>
                    <span class="btn btn-default" onClick="editTag('sms','firstname',this)" id="smsFirstname" title="your firstname" draggable="true">Firstname</span>
                    <span class="btn btn-default" onClick="editTag('sms','lastname',this)" id="smsLastname" title="your lastname" draggable="true">Lastname</span>
                  </div>
                  <div class="col-lg-6" style="margin-top: 30px">
                  </div>
                </div>
          </TMPL_LOOP>
          </div>
          <! --/row -->
    </div>
    <! --/container -->
  </div>
</body>

</html>
  • it is not possible to debug such a big code. hopefully you will able to pinpoint the exact snippet – brk Mar 06 '18 at 06:03
  • `zoneDiv` seems to be a `
    ` element and you're doing `(zoneDiv.value).substring`, `
    ` elements don't have a `value` property.
    – Titus Mar 06 '18 at 06:06
  • Oh ok, I just edited the js to have a little less script –  Mar 06 '18 at 06:19
  • Yeah indeed thanks for the comment @Titus, but I'm still trying to understand this script globally, and it's a little hard. –  Mar 06 '18 at 06:22
  • Try to use `zoneDiv.innerHTML` instead of `zoneDiv.value`. – Titus Mar 06 '18 at 06:24
  • hum @Titus, I replaced all zoneDiv.value by zoneDiv.innerHTMl, but this thime, it's creating me a copy of the span in the area –  Mar 06 '18 at 06:32
  • It should be `substring(strPos, zoneDiv.innerHTML.length)` instead of `substring(strPos, zoneDiv.innerHTML)` (*you're missing `.length`*) – Titus Mar 06 '18 at 06:34
  • oh thx @Titus, I edited again the script, but it show me a new error : " zoneDiv.innerHTML.length.substring is not a function". I surely did a mistake somewhere –  Mar 06 '18 at 06:52
  • It should be `zoneDiv.innerHTML.substring(strPos, zoneDiv.innerHTML.length)` or `zoneDiv.innerHTML.substr(strPos)` – Titus Mar 06 '18 at 06:54
  • Hum tried it @Titus, but still getting error like "zoneDiv.innerHTML.length is not a function" otherwise, it's a copy of the span which is displaying :/ –  Mar 06 '18 at 07:08
  • I added in the subject a new script which I tried to work on, but still no success @Titus. Maybe, with these new scripts, the problem will be solved a little faster –  Mar 06 '18 at 08:04
  • It's possible to use a global variable to get cursor position and after add this variable in editTag() function? –  Mar 06 '18 at 11:05
  • I saw that to get cursor position in JQuery, we can simply use this in a global variable : $('#element').prop('selectionStart'). But where can I add this variable into editTag() function? –  Mar 06 '18 at 11:47
  • Hum @Titus, I edited the script, the one that I found on Internet, I deleted it, and found an other one simpler; in my function : $("#smsArea").on('keyup mouseup',function(e) ..... , I recover in cursorPosition variable, thanks to window.getSelection().getRangeAt(0) method, cursor position in the text which is in the area. However, I cannot use cursorPosition variable in my function editTag() :/ –  Mar 07 '18 at 07:23

2 Answers2

1

Get cursor position with pageX, pageY. Here is the demo:

stage = document.querySelector('.stage')
    stage.addEventListener('click', e => {
      let spanEl = document.createElement('span')
      spanEl.style.top = e.pageY + 'px'
      spanEl.style.left = e.pageX + 'px'
      spanEl.style.background = '#'+(Math.random()*0xFFFFFF<<0).toString(16)
      stage.appendChild(spanEl)
      e.preventDefault()
    })
body {
      margin: 0;
    }
    div.stage {
    background: yellow;
      width: 100%;
      min-height: 300px;
      padding: 0;
      overflow: hidden;
      position: relative;
    }
  span {
    position: absolute;
    width: 30px;
    height: 20px;
    background-color:teal;
  }
<div class="stage">
click to add
</div>
sfy
  • 2,810
  • 1
  • 20
  • 22
  • Thanks for your demo @Jacob even if I found the solution before ! ;) I will study your demo :) –  Mar 07 '18 at 10:54
0

Finally, I have found a solution to my problem !

I have to replace the method window.getSelection().anchorOffset by window.getSelection().getRangeAt(0) to get the cursor position when entering text in the area and to get also the node on which I was working on, to save these results into cursorPosition variable. And after, I had to use again this variable in editTag() function to insert the span tag according to the cursor position, by doing : cursorPosition.insertNode(myLabel);

var area = document.getElementById("template");
var message = document.getElementById("message");
var maxLength = 160;
var re = new RegExp("ô|â|ê|ç");

var myTags = new Object();
var cursorPosition = 0;
var smsNode = null;

myTags['company'] = '#ENTREPRISE#';
myTags['city'] = '#VILLE#';
myTags['link'] = '#LIEN#';
myTags['firstname'] = '#PRENOM#';
myTags['lastname'] = '#NOM#';
myTags['title'] = '#TITRE#';

$("#smsArea").on('keyup mouseup',function(e)
{ 
 //console.log(window.getSelection().anchorOffset);

 /*if(this.hasChildNodes())
 {
  var node = this.childNodes;
  console.log(node);
 }*/

 /*smsNode = this.textContent;
 console.log(smsNode);*/
    /*if($(window.getSelection().anchorNode).is($(this)))
    {
     cursorPosition = 0;
    }
    else
    {*/
        cursorPosition = window.getSelection().getRangeAt(0);
        //console.log(cursorPosition);
    //}
 });

function insertAfter(referenceNode, newNode) 
{
    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

function editTag(zoneId,tag,button)
{

 var btnSms = document.getElementById(button.id);
 var zoneDiv  = document.getElementById(zoneId + 'Area');
 var myButton  = document.getElementById(zoneId + tag.ucfirst());
 var myLabel  = document.createElement('span');

 var labels   = zoneDiv.getElementsByTagName('span');
 var spanSize = labels.length;

 var delflag  = 0;
 var delIndex = 0;

 var textNode    = document.createTextNode('\u00A0');

 /*if(btnSms)
 {
  btnSms.classList.toggle("btn-danger");
 }
 else
 {
  btnSms.classList.toggle("btn-success");
 }*/

 if(spanSize != 0)
 {

  for (myLabId = 0; myLabId < spanSize; myLabId++)
  {
   var currentLabel = labels[myLabId];
   if(currentLabel.innerHTML === myButton.innerHTML)
   {
    delflag = 1;
    delIndex = myLabId;
   }
  }
 }
  
 if(delflag == 1)
    {
     btnSms.classList.remove("btn-danger");
        btnSms.classList.add("btn-default");
        zoneDiv.removeChild(labels[delIndex]);
    }
 else
 {
  myLabel.setAttribute('class', 'label label-info');
  myLabel.setAttribute('data-effect', 'pop');
  myLabel.setAttribute('contentEditable', 'false');
  myLabel.setAttribute('style','cursor:move;font-size:100%;');
  myLabel.setAttribute('name', tag);
  myLabel.setAttribute('id', 'tag');
  myLabel.setAttribute('draggable', 'true');
  myLabel.innerHTML = myButton.innerHTML;

  //zoneDiv.appendChild(myLabel);
  cursorPosition.insertNode(myLabel);
  console.log(cursorPosition);
  //zoneDiv.appendChild(textNode);
  //document.getElementById(myLabel).insertAfter(textNode);
  insertAfter(myLabel, textNode);
  btnSms.classList.add("btn-danger");
 }

 //Clean breaklines;
 var bks  = zoneDiv.getElementsByTagName('br');
 var brSize  = bks.length;
 
 if(brSize != 0)
 {
  zoneDiv.removeChild(bks[0]);
 }

 //Event keyboard on deleted elements
 $("span").dblclick(function(handler)
 {
  myLabel.remove(labels[delIndex]);
  btnSms.classList.remove("btn-danger");
  btnSms.classList.add("btn-default");
 });
}

String.prototype.ucfirst = function() {
  return this.charAt(0).toUpperCase() + this.substr(1);
}
#smsArea {
  -moz-appearance: textfield-multiline;
  -webkit-appearance: textarea;
  height: 150px;
  overflow: auto;
  padding: 5px;
  resize: both;
  width: 100%;
}

.smstext {
  /*    margin-top: 100px;*/
  margin-left: 60px;
  margin-right: 20px;
  padding-top: 30px;
  font-family: verdana, sans-serif;
}

#mailArea {
  -moz-appearance: textfield-multiline;
  -webkit-appearance: textarea;
  height: 200px;
  overflow: auto;
  padding: 5px;
  resize: both;
  width: 500px;
  font-size: 12px;
  margin-top: 5px;
}

.mailInput {
  -moz-appearance: textfield-multiline;
  -webkit-appearance: textarea;
  overflow: auto;
  padding: 5px;
  resize: both;
  font-size: 12px;
  margin-top: 5px;
  width: 300px;
  height: 85px;
  margin-left: 100px;
  margin-top: -20px;
}

.mailtext {
  /*      margin-top: 100px;*/
  margin-left: 60px;
  margin-right: 20px;
  padding-top: 30px;
  font-family: verdana, sans-serif;
}

#webtag {
  margin-top: -392px;
  margin-left: 555px;
  width: 569px;
}

#result {
  display: none;
}

#interaction {
  margin-top: 30px;
  visibility: hidden;
}

#cd-popup {
  background-color: rgba(94, 110, 141, 0.9);
  opacity: 1;
  -webkit-transition: opacity 0.3s 0s, visibility 0s 0.3s;
  -moz-transition: opacity 0.3s 0s, visibility 0s 0.3s;
  transition: opacity 0.3s 0s, visibility 0s 0.3s;
  position: relative;
  width: 100%;
  max-width: 800px;
  height: 350px;
  margin: 4em auto;
  border-radius: .25em .25em .4em .4em;
  text-align: center;
  box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
  -webkit-transform: translateY(-40px);
  -moz-transform: translateY(-40px);
  -ms-transform: translateY(-40px);
  -o-transform: translateY(-40px);
  transform: translateY(-40px);
  /* Force Hardware Acceleration in WebKit */
  -webkit-backface-visibility: hidden;
  -webkit-transition-property: -webkit-transform;
  -moz-transition-property: -moz-transform;
  transition-property: transform;
  -webkit-transition-duration: 0.3s;
  -moz-transition-duration: 0.3s;
  transition-duration: 0.3s;
  z-index: 1;
}

#cd-popup.is-visible {
  opacity: 1;
  visibility: visible;
  -webkit-transition: opacity 0.3s 0s, visibility 0s 0s;
  -moz-transition: opacity 0.3s 0s, visibility 0s 0s;
  transition: opacity 0.3s 0s, visibility 0s 0s;
}

#cd-popup p {
  padding: 3em 1em;
  margin-left: -250px;
  height: 100px;
}

#cd-popup div {
  float: left;
  width: 30%;
  list-style: none;
  display: block;
  height: 60px;
  line-height: 60px;
  text-transform: uppercase;
  color: #FFF;
  -webkit-transition: background-color 0.2s;
  -moz-transition: background-color 0.2s;
  transition: background-color 0.2s;
}

#object {
  background: #fc7169;
  border-radius: 0 0 0 .25em;
  width: 175px;
  margin-left: -400px;
  cursor: pointer;
  padding: 3px 6px;
  display: inline-block;
}

#object:hover {
  background-color: #fc8982;
}

#body {
  background: #6495ED;
  border-radius: 0 0 0 .25em;
  width: 175px;
  cursor: pointer;
  padding: 3px 6px;
  display: inline-block;
  margin-left: -150px;
}

#body:hover {
  background-color: #fc8982;
}

#titre {
  background: #A52A2A;
  border-radius: 0 0 0 .25em;
  width: 175px;
  margin-left: 10px;
  cursor: pointer;
  padding: 3px 6px;
  display: inline-block;
}

#titre:hover {
  background-color: #fc8982;
}

#note {
  background: #006400;
  border-radius: 0 0 0 .25em;
  width: 175px;
  margin-left: 10px;
  cursor: pointer;
  padding: 3px 6px;
  display: inline-block;
}

#cd-popup #note:hover {
  background-color: lightsteelblue;
}

#cd-popup .cd-popup-close {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 30px;
  height: 30px;
}

#cd-popup .cd-popup-close::before,
#cd-popup .cd-popup-close::after {
  content: '';
  position: absolute;
  top: 12px;
  width: 14px;
  height: 3px;
  background-color: #8f9cb5;
}

#cd-popup .cd-popup-close::before {
  -webkit-transform: rotate(45deg);
  -moz-transform: rotate(45deg);
  -ms-transform: rotate(45deg);
  -o-transform: rotate(45deg);
  transform: rotate(45deg);
  left: 8px;
}

#cd-popup .cd-popup-close::after {
  -webkit-transform: rotate(-45deg);
  -moz-transform: rotate(-45deg);
  -ms-transform: rotate(-45deg);
  -o-transform: rotate(-45deg);
  transform: rotate(-45deg);
  right: 8px;
}

@media only screen and (min-width: 1170px) {
  #cd-popup {
    margin: 8em auto;
  }
}

.webArea {
  -moz-appearance: textfield-multiline;
  -webkit-appearance: textarea;
  height: 520px;
  /*overflow: auto;*/
  padding: 5px;
  /*resize: both;*/
  width: 630px;
  font-size: 12px;
  /*margin-top: 55px;*/
  border: 2px dashed #D9D9D9;
  border-radius: 5px;
  text-align: center;
  margin-top: 12%;
}

.webArea>div {
  background-color: #FAEBD7;
  border: 3px dashed #D9D9D9;
  margin-bottom: 15px;
  height: 120px;
  width: 612px;
  overflow: auto;
  overflow-x: hidden;
  /*    margin-left: -1.5%;*/
}

.webArea>div>div {
  transition: all .5s;
  text-align: center;
  float: left;
  padding: 1em;
  margin: 0 1em 1em 0;
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
  border-radius: 5px;
  border: 2px solid black;
  /*background: #F7F7F7;*/
  transition: all .5s ease;
  width: 582px;
  /*background-color: #F8F8FF;*/
  height: 110px;
}

.dropTarget>div>div>span {
  font-style: italic;
  margin-right: 5%;
  font-size: 16px;
}

.webArea>div>div>input {
  margin-right: 25%;
  width: 250px;
  height: 40px;
  background-color: white;
}

.webArea>div>div:active {
  /*-webkit-animation: wiggle 0.3s 0s infinite ease-in;
    animation: wiggle 0.3s 0s infinite ease-in;*/
  opacity: .6;
  border: 2px solid #000;
}

#mailArea {
  -moz-appearance: textfield-multiline;
  -webkit-appearance: textarea;
  height: 200px;
  overflow: auto;
  padding: 5px;
  resize: both;
  width: 500px;
  font-size: 12px;
  margin-top: 5px;
}

#containerZone {
  border: 1px solid;
  border-radius: 25px;
  */ margin: 3%;
  width: 70%;
  height: 40px;
  text-align: center;
  font-weight: bold;
  color: #000000;
  margin: auto;
  margin-top: 8%;
  margin-left: -450px;
}

#containerZone2 {
  border: 1px solid;
  border-radius: 25px;
  width: 70%;
  height: 40px;
  text-align: center;
  font-weight: bold;
  color: #000000;
  margin: auto;
  margin-top: 100%;
  margin-left: -450px;
}

#webtags {
  margin-top: -40px;
}

#webtags>div {
  margin-left: 20px;
}

#modalTagBody {
  height: 120px;
}

#btnTag {
  margin-top: 20px;
  margin-right: 15px;
}
<html>

<head>
  <meta charset="utf-8">
  <title>Drag & drop Tag</title>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <!-- Latest compiled and minified CSS -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

  <!-- Optional theme -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">

  <!-- Latest compiled and minified JavaScript -->
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.0/jquery-confirm.min.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.0/jquery-confirm.min.js"></script>
</head>

<body>
  <div class="container mtb">
    <div class="row">
      <TMPL_IF NAME="PROFILE">
        <form role="form" action="<TMPL_VAR NAME=MYURL>?rm=saveTemplate" method="POST" enctype="application/x-www-form-urlencoded">
          <TMPL_LOOP NAME="DATA">
            <input type="hidden" id='id' name="id" value="<TMPL_VAR NAME=ID>" />
            <TMPL_IF NAME="TEMPLATE">
              <div class="panel panel-primary" id="panels" data-effect="helix">
                <div class="panel-heading">SMS Message</div>
                <div class="panel-body">
                  <div class="col-lg-6">
                    <div class="form-group">
                    </div>
                    <input type="hidden" name="rm" value="saveTemplate" />
                    <div id="smsArea" class="form-control" contenteditable="true">
                      <p id="smsDraft">
                        <TMPL_VAR NAME=TEMPLATE>
                      </p>
                    </div><br />
                    <div>position: <span id="position"></span></div>
                    <a href="#" class="btn btn-primary" onClick="saveMessage('sms');">Save</a>
                    <a href="#" class="btn btn-primary" onClick="previewMessage('sms');" data-toggle="modal" data-target="#myModal2">Preview</a>
                    <a href="#" class="btn btn-primary" onClick="testMessage('sms');" data-toggle="modal" data-target="#myModal">SMS Costs</a>
                    <br>
                  </div>
                  <div class="col-lg-6" id='smsTags'>
                    <h4 for="template">Personnalization</h4>
                    <span class="btn btn-default" onClick="editTag('sms','link', this)" id="smsLink" title="link of your website" draggable="true">Link</span>
                    <span class="btn btn-default" onClick="editTag('sms','firstname',this)" id="smsFirstname" title="your firstname" draggable="true">Firstname</span>
                    <span class="btn btn-default" onClick="editTag('sms','lastname',this)" id="smsLastname" title="your lastname" draggable="true">Lastname</span>
                  </div>
                  <div class="col-lg-6" style="margin-top: 30px">
                  </div>
                </div>
          </TMPL_LOOP>
          </div>
          <! --/row -->
    </div>
    <! --/container -->
  </div>
</body>

</html>