capiono
capiono

Reputation: 2997

Implementing textarea Drag and drop

(function() {
  'use strict';

  var data = JSON.stringify({
    "tags": [{
      "id": 1,
      "name": "HELPDESKPHONE",
      "value": "{{helpdeskphone}}",
      "description": null
    }, {
      "id": 3,
      "name": "HELPDESKEMAIL",
      "value": "{{helpdeskemail}}",
      "description": null
    }, {
      "id": 4,
      "name": "CODE",
      "value": "{{code}}",
      "description": null
    }, {
      "id": 7,
      "name": "CALLBACKURL",
      "value": "{{callbackurl}}",
      "description": null
    }],
    "templates": [{
      "id": 1,
      "key": "securitycode",
      "description": null,
      "content": "<p>Your credentials have been identified in the system and a request to authenticate your account by email has been made.</p><p>To continue the  2-Factor Authentication process, enter this single-use code on the verification page.</p>{{code}}<p>PLEASE NOTE THAT THIS CODE EXPIRES WITHIN 1 HOUR OF SENDING THIS EMAIL.</p><p>If you did not initiate this request, please contact the Helpdesk via email at {{helpdeskemail}} or by calling (toll-free) {{helpdeskphone}}</p>",
      "subject": "Security Code"
    }, {
      "id": 3,
      "key": "resetpassword",
      "description": null,
      "content": "<p>A request to change your password has been made. To continue the password change process, click on the link below.</p><a href=\"{{callbackurl}}\">Click here to reset your password.</a></p>\n<p>PLEASE NOTE THAT THIS LINK EXPIRES WITHIN 1 HOUR OF SENDING THIS EMAIL.</p><p>If you did not initiate this request, please contact the Helpdesk via email at {{helpdeskemail}}; or by calling (toll-free) {{helpdeskphone}}</p> ",
      "subject": "FWIMS Password Change Request"
    }]
  });

  var Tag = function(id, name, value, description) {
    var self = this;
    self.id = ko.observable(id);
    self.name = ko.observable(name);
    self.value = ko.observable(value);
    self.description = ko.observable(description);
  };

  var Template = function(id, key, description, content, subject, tags) {
    var self = this;
    self.id = ko.observable(id);
    self.key = ko.observable(key);
    self.description = ko.observable(description);
    self.content = ko.observable(content);
    self.subject = ko.observable(subject);
  };

  var ViewModel = function(data) {
    var self = this;

    self.templates = ko.observableArray(data.templates.map(function(item) {
      return new Template(
        item.id,
        item.key,
        item.description,
        item.content,
        item.subject
      );
    }));

    self.tags = ko.observableArray(data.tags.map(function(item) {
      return new Tag(
        item.id,
        item.name,
        item.value,
        item.description
      );
    }));

    self.makeDraggable = function() {
      $("li").draggable({
        helper: 'clone'
      });
    };

    self.makeDroppable = function(elements) {
      $(".txtDropTarget").droppable({
        accept: "li",
        drop: function(ev, ui) {
          $(this).insertAtCaret(ui.draggable.text());
        }
      });
    };


    $.fn.insertAtCaret = function(myValue) {
      return this.each(function() {
        //IE support
        if (document.selection) {
          this.focus();
          sel = document.selection.createRange();
          sel.text = myValue;
          this.focus();
        }
        //MOZILLA / NETSCAPE support
        else if (this.selectionStart || this.selectionStart == '0') {
          var startPos = this.selectionStart;
          var endPos = this.selectionEnd;
          var scrollTop = this.scrollTop;
          this.value = this.value.substring(0, startPos) + myValue + this.value.substring(endPos, this.value.length);
          this.focus();
          this.selectionStart = startPos + myValue.length;
          this.selectionEnd = startPos + myValue.length;
          this.scrollTop = scrollTop;
        } else {
          this.value += myValue;
          this.focus();
        }
      });
    };
  };

  var viewModel = new ViewModel(ko.utils.parseJson(data) || []);
  ko.applyBindings(viewModel);
}());
.move-pointer {
  cursor: move;
}
<div data-bind="foreach: {data: templates, afterRender: makeDroppable } ">
  <div class="card">
    <div class="d-flex justify-content-between align-content-center">
      <textarea rows="10" style="height: auto" aria-label="Content" class="txtDropTarget form-control m-3" aria-describedby="Template Content" data-bind="textInput: content"></textarea>
      <div data-bind="html: content" class="m-3"></div>
    </div>
    <div class="d-flex justify-content-between align-content-center">
      <ul class="dragList nav" data-bind="foreach: { data: $parent.tags, afterRender: $root.makeDraggable }">
        <li data-bind="text: value" class="nav-item m-3 h5 move-pointer"></li>
      </ul>
    </div>
  </div>
</div>

I'm designing a UI for editing and creating email template content using knockout.

I've implemented this:

I have a textarea and a preview div. when text is add in the text area it shows up in the preview area. under the textarea are acceptable tags which acts has placeholders. this placeholders will be replaced at runtime with actual values.

The problem I'm having right now is, If a tag is dragged into the textarea, the content observable is not updated immediately, I have to type in the text area to trigger an observable update.

<textarea rows="10" style="height: auto" aria-label="Content" class="txtDropTarget form-control m-3" aria-describedby="Template Content" data-bind="textInput: content"></textarea>

I've tried the textInput binding and valueUpdate: 'input' event, none of that worked

Upvotes: 1

Views: 6461

Answers (1)

MVG1984
MVG1984

Reputation: 645

do this

$(this).insertAtCaret(ui.draggable.text()).change();

after drag.

I edited your example - https://jsfiddle.net/qskxzh0e/3/

 self.makeDroppable = function(elements) {
      $(".txtDropTarget").droppable({
        accept: "li",
        drop: function(ev, ui) {
          $(this).insertAtCaret(ui.draggable.text()).change();
        }
      });
    };

Upvotes: 5

Related Questions