实现textarea拖放

cap*_*ono 1 javascript jquery knockout.js

(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);
}());
Run Code Online (Sandbox Code Playgroud)
.move-pointer {
  cursor: move;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

我正在设计一个用户界面,用于使用淘汰赛编辑和创建电子邮件模板内容。

我已经实现了这个:

我有一个 textarea 和一个预览 div。在文本区域中添加文本时,它会显示在预览区域中。在 textarea 下是可接受的标签,其行为具有占位符。此占位符将在运行时替换为实际值。

我现在遇到的问题是,如果将标签拖入 textarea,则contentobservable 不会立即更新,我必须在文本区域中键入以触发 observable 更新。

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

我试过textInput绑定和 valueUpdate: 'input'事件,没有一个工作

MVG*_*984 5

做这个

$(this).insertAtCaret(ui.draggable.text()).change();
Run Code Online (Sandbox Code Playgroud)

拖后。

我编辑了你的例子 - https://jsfiddle.net/qskxzh0e/3/

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