Drag and drop <span> to paragraph using JQuery

让人想犯罪 __ 提交于 2020-01-06 02:23:45

问题


I need to drag and drop <span> to <p>. My code works, but I have 3 problems,

  1. When I edit <p> content by typing something(suppose three words) and after drag <span> to <p> newly typed words acting as one word. So cannot drop draggable components between those newly typed content.

  2. After the close, the added draggable components(by clicking X) two spaces are remaining between two words.

  3. Cannot drop the draggable component as the 1 word of the paragraph.

To sort out the 3rd issue I added &nbsp; to the 1st of the paragraph. and it's sorted.

<p class="given" contenteditable="true">&nbsp; Lorem Ipsum is simply dummy</p>

How can I sort out the other two issues? Please help

$(function() {
  function textWrapper(str, sp) {
    if (sp == undefined) {
      sp = [0, 0];
    }
    var txt = "<span class='w'>" + str + "</span>";
    
    if (sp[0]) {
      txt = "&nbsp;" + txt;
    }
    
    if (sp[1]) {
      txt = txt + "&nbsp;";
    }
    
    return txt;
  }

  function chunkWords(p) {
    var words = p.split(" ");
    words[0] = textWrapper(words[0], [0, 1]);
    var i;
    for (i = 1; i < words.length; i++) {
      if (words[0].indexOf(".")) {
        words[i] = textWrapper(words[i], [1, 0]);
      } else {
        words[i] = textWrapper(words[i], [1, 1]);
      }
    }
    return words.join("");
  }

  function makeBtn(tObj) {
    var btn = $("<span>", {
      class: "ui-icon ui-icon-close"
    }).appendTo(tObj);
    btn.click(function(e) {
      $(this).parent().remove();
    });
  }

  function makeDropText(obj) {
    return obj.droppable({
      drop: function(e, ui) {
        var txt = ui.draggable.text();
        var newSpan = textWrapper(txt, [1, 0]);
        $(this).after(newSpan);
        makeBtn($(this).next("span.w"));
        makeDropText($(this).next("span.w"));
        $("span.w.ui-state-highlight").removeClass("ui-state-highlight");
      },
      over: function(e, ui) {
        $(this).add($(this).next("span.w")).addClass("ui-state-highlight");
      },
      out: function() {
        $(this).add($(this).next("span.w")).removeClass("ui-state-highlight");
      }
    });
  }

  $("p.given").html(chunkWords($("p.given").text()));

  $("span.given").draggable({
    helper: "clone",
    revert: "invalid"
  });

  makeDropText($("p.given span.w"));
});
p.given {
  display: flex;
  flex-wrap: wrap;
}

p.given span.w span.ui-icon {
  cursor: pointer;
}

div.blanks {
  display: inline-block;
  min-width: 50px;
  border-bottom: 2px solid #000000;
  color: #000000;
}

div.blanks.ui-droppable-active {
  min-height: 20px;
}

span.answers>b {
  border-bottom: 2px solid #000000;
}

span.given {
  margin: 5px;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class="row">
  <p class="given" contenteditable="true">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
</div>

<div class="divider"></div>
<div class="section">
  <section>
    <div class="card blue-grey ">
      <div class="card-content white-text">
        <div class="row">
          <div id="walkinDiv" class="col s12">
            <span class="given btn-flat white-text red lighten-1" rel="1">the Santee, thDakota</span>
            <span class="given btn-flat white-text red lighten-1" rel="2">America</span>
            <span class="given btn-flat white-text red lighten-1" rel="3">Qatar</span>
            <span class="given btn-flat white-text red lighten-1" rel="4">Philippines</span>
          </div>
        </div>
      </div>
    </div>
  </section>
</div>

Updated: 2019-10-22

I updated the question because I faced a problem when I generate draggable components <span> from code. I generated draggable components as follows, Its generate fine and able drag and drop to <p>. but when I click the <p> and click outside from the <p>(which means in the blur event) dropped component not showing the close button. it showing as [Ameriaca] , [Qatatr] Why it happen so? how can I avoid it. I called this GetAllParameters() inside $(function() {});

function GetAllParameters() {
    $.ajax({
        type: "POST",
        url: SERVER_PATH + '/service/TestService.asmx/GetAllParameters',
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: GetAllNotificationParametersComplete,
        error: GetAllNotificationParameterFailed
    });
}

function GetAllNotificationParametersComplete(result, status) {
    NotificationParameters = JSON.parse(result.d);
    getTemplateparameters(NotificationParameters,'ShowIn');
}

function GetAllNotificationParameterFailed(result) {
    //console.log(result);
}


function getTemplateparameters(data,field) {

    var filtered = data.filter(function(item) {
         return item[field] == true;
    });
 populateTemplateParameters(filtered);
}

function populateTemplateParameters(data) {  
     var obj = data;
     var stringlist = "";
     $.each(obj, function (index, item) {
         stringlist = stringlist + ' <span class="given btn-flat white-text red lighten-1 parameter-wrapper">' +item.ParameterName+ '</span>';
     });
    $("#walkinDiv").html(stringlist);

    $("span.given").draggable({
      helper: "clone",
      revert: "invalid"
    });

  makeDropText($("p.given span.w"));
}

Updated: 2019-10-23

The previously mentioned problem occurs when the draggable component has two words such as "Hello World" And one thing I Identified. When I typing something Inside editable <p> and click the outside of the <p> typed words removing.this is a big issue. please help me to solve this


回答1:


You should only ask practical, answerable questions based on actual problems that you face. Chatty, open-ended questions diminish the usefulness of our site and push other questions off the front page.

Your questions should be reasonably scoped. If you can imagine an entire book that answers your question, you’re asking too much.

$(function() {
  function textWrapper(str, sp, btn) {
    if (sp == undefined) {
      sp = [0, 0];
    }
    var txt = "";
    if (btn) {
      txt = "<span class='w b'>" + str + "</span>";
    } else {
      txt = "<span class='w'>" + str + "</span>";
    }

    if (sp[0]) {
      txt = "&nbsp;" + txt;
    }

    if (sp[1]) {
      txt = txt + "&nbsp;";
    }

    return txt;
  }

  function chunkWords(p) {
    var words = p.split(" ");
    words[0] = textWrapper(words[0], [0, 1]);
    var i;
    for (i = 1; i < words.length; i++) {
      var re = /\[.+\]/;
      if (re.test(words[i])) {
        var b = makeTextBox(words[i].slice(1, -1));
        words[i] = "&nbsp;" + b.prop("outerHTML") + "&nbsp;";
      } else {
        if (words[0].indexOf(".")) {
          words[i] = textWrapper(words[i], [1, 0]);
        } else {
          words[i] = textWrapper(words[i], [1, 1]);
        }
      }
    }
    return words.join("");
  }

  function unChunkWords(tObj) {
    var words = [];
    $(".w", tObj).each(function(i, el) {
      console.log($(el).text(), $(el).attr("class"));
      if ($(el).hasClass("b")) {
        words.push("[" + $(el).text().trim() + "]");
      } else {
        words.push($(el).text().trim());
      }
    });
    return words.join(" ");
  }

  function makeBtn(tObj) {
    var btn = $("<span>", {
      class: "ui-icon ui-icon-close"
    }).appendTo(tObj);
  }

  function makeTextBox(txt) {
    var sp = $("<span>", {
      class: "w b"
    }).html(txt);
    makeBtn(sp);
    return sp;
  }

  function makeDropText(obj) {
    return obj.droppable({
      drop: function(e, ui) {
        var txt = ui.draggable.text();
        var newSpan = textWrapper(txt, [1, 0], 1);
        $(this).after(newSpan);
        makeBtn($(this).next("span.w"));
        makeDropText($(this).next("span.w"));
        $("span.w.ui-state-highlight").removeClass("ui-state-highlight");
      },
      over: function(e, ui) {
        $(this).add($(this).next("span.w")).addClass("ui-state-highlight");
      },
      out: function() {
        $(this).add($(this).next("span.w")).removeClass("ui-state-highlight");
      }
    });
  }

  $("p.given").html(chunkWords($("p.given").text()));

  $("p.given").on("click", ".b > .ui-icon", function() {
    $(this).parent().remove();
  });

  $("p.given").blur(function() {
    var w = unChunkWords($(this));
    console.log(w);
    $(this).html(chunkWords(w));
    makeDropText($("p.given span.w"));
  });

  $("span.given").draggable({
    helper: "clone",
    revert: "invalid"
  });

  makeDropText($("p.given span.w"));
});
p.given {
  display: flex;
  flex-wrap: wrap;
}

p.given span.w span.ui-icon {
  cursor: pointer;
}

div.blanks {
  display: inline-block;
  min-width: 50px;
  border-bottom: 2px solid #000000;
  color: #000000;
}

div.blanks.ui-droppable-active {
  min-height: 20px;
}

span.answers>b {
  border-bottom: 2px solid #000000;
}

span.given {
  margin: 5px;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class="row">
  <p class="given" contenteditable="true">Lorem Ipsum is simply dummy text of the printing and typesetting industry. [Lorem] Ipsum has been the industry's standard dummy text ever since the 1500s, Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
</div>

<div class="divider"></div>
<div class="section">
  <section>
    <div class="card blue-grey ">
      <div class="card-content white-text">
        <div class="row">
          <div class="col s12">
            <span class="given btn-flat white-text red lighten-1" rel="1">the Santee, thDakota</span>
            <span class="given btn-flat white-text red lighten-1" rel="2">America</span>
            <span class="given btn-flat white-text red lighten-1" rel="3">Qatar</span>
            <span class="given btn-flat white-text red lighten-1" rel="4">Philippines</span>
          </div>
        </div>
      </div>
    </div>
  </section>
</div>

Using the blur event, we can can revert the wrapped elements back into text and then chunk them back up again with the new content. To maintain the buttons, I used [ and ].

I used .on() and .blur() for specific reasons.

The .on() method attaches event handlers to the currently selected set of elements in the jQuery object. As of jQuery 1.7, the .on() method provides all functionality required for attaching event handlers.

Delegated event handlers have the advantage that they can process events from descendant elements that are added to the document at a later time. By picking an element that is guaranteed to be present at the time the delegated event handler is attached, you can use delegated event handlers to avoid the need to frequently attach and remove event handlers. This element could be the container element of a view in a Model-View-Controller design, for example, or document if the event handler wants to monitor all bubbling events in the document. The document element is available in the head of the document before loading any other HTML, so it is safe to attach events there without waiting for the document to be ready.

See More: .on()

This is important as we're dynamically creating elements and want to ensure the callback is delegated to these elements even if they do not exist yet.

This method is a shortcut for .on( "blur", handler )

The blur event is sent to an element when it loses focus. Originally, this event was only applicable to form elements, such as <input>. In recent browsers, the domain of the event has been extended to include all element types. An element can lose focus via keyboard commands, such as the Tab key, or by mouse clicks elsewhere on the page.

See More: .blur()




回答2:


To solve the first problem, you could "recut" the words every time the user enters text or defocusses on the text area. I would recommend you remap/cut your words every time the user stops editing the text area or every time the user enters a space (this will run a lot more often though).

The second problem could be fixed by simply looping through the text and removing   if you detected there are multiple in a row (for example, with regex).



来源:https://stackoverflow.com/questions/58215677/drag-and-drop-span-to-paragraph-using-jquery

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!