OscarGodson / EpicEditor

EpicEditor is an embeddable JavaScript Markdown editor with split fullscreen editing, live previewing, automatic draft saving, offline support, and more. For developers, it offers a robust API, can be easily themed, and allows you to swap out the bundled Markdown parser with anything you throw at it.
http://epiceditor.com
MIT License
4.25k stars 334 forks source link

Callback/function for inserting en image #282

Open mbodlund opened 11 years ago

mbodlund commented 11 years ago

Would like to integrate an insert media button to an implementation of the EpicEditor. Would like to be able to click button Insert media and the select an image from a library and then when the image is clicked insert it where the cursor was in the editor.

Is there any way of hooking up to a callback with the markdown that is the image and inserting it where the cursor was?

jpdevries commented 11 years ago

On a somewhat similar note, I'd like to add insert image via pasting from clipboard

OscarGodson commented 11 years ago

EpicEditor wouldn't ever support things like file uploads as this is all front-end. Maybe later we'll have an extension. As for writing something yourself where the cursor position is saved, I'm not sure. I tried a few quick things and couldn't get it to work (mostly because selection APIs in JS are janky). I'll play with it some more and get back to you!

jpdevries commented 11 years ago

I hadn't expected EpicEditor to support file uploads, more so because the user interface is so simple as is. Pasting & drag n' drop, having an invisible UI could be a nice extension.

mbodlund commented 11 years ago

@oskar - to clarify. I wasnøt looking for file upload. Only to be abel to mark something in the editor and then being able to insert a text at the current cursor position.

OscarGodson commented 11 years ago

@mbodlund I see, ok, so something along the lines of these tickets then?

https://github.com/OscarGodson/EpicEditor/issues/162 https://github.com/OscarGodson/EpicEditor/issues/172

There's been attempts and I worked on a simple solution after reading this ticket. Problem is getting the cursor position and manipulating it in a contenteditable is actually a pain. I'm thinking about making a some module just for dealing with contenteditable and dealing with cursors and text placement which I'll include into EpicEditor.

cc: @hongymagic

mbodlund commented 11 years ago

In a dream world it would be possible to hook up your own buttons to an event handler which on trigger return an object with the selected text and position. If there also was a callback you could trigger to insert/replace the selection/cursor position then all sorts of fun could begin. Realy like the simple editor but to be able to use it more extensively I really need to be able to have some custom buttons for handling formatting/links/media

OscarGodson commented 11 years ago

@mbodlund Indeed. This is sort of the rough spec we want to implement: https://gist.github.com/hongymagic/5363135

shanemcd commented 10 years ago

I hacked something together that allows me to insert images at the caret position.

Until something like this is implemented, here is what I did in case it helps anyone. I used FormData to upload the image, which returns the URL after uploading to S3.

Here is the relevant coffeeescript:

setUpPhotoUploads = ->
  $('body.admin_posts input#add_photo').change (e) ->
    formData = new FormData()
    formData.append "file", @files[0]
    $.ajax
      type: "post"
      url: $(e.target).data('upload-url')
      cache: false
      contentType: false
      success: (url) ->
        container = $("#epiceditor iframe").
                    contents().
                    find("iframe#epiceditor-editor-frame").
                    contents().
                    find("body").
                    get(0) # http://goo.gl/fLMbt
        txtToAdd = "![Image Description](#{url})"
        insertAtCaret(container, txtToAdd)
      error: (response) ->
        alert(response.responseText)
      processData: false
      data: formData

insertAtCaret = (element, text) ->
  _window = element.ownerDocument.defaultView
  selection = _window.getSelection()
  if selection.rangeCount
    range = selection.getRangeAt()
    range.deleteContents()
    node = document.createTextNode(text)
    frag = document.createDocumentFragment()
    nodeToInsert = frag.appendChild(node)
    range.insertNode(frag)
  else
    $(element).append(text)
OscarGodson commented 10 years ago

Anyway you can post that in JavaScript since we can't use CS?

shanemcd commented 10 years ago

Sure, I didnt convert it by hand, but used http://js2coffee.org/. The output looks pretty readable.

var insertAtCaret, setUpPhotoUploads;

setUpPhotoUploads = function() {
  return $('body.admin_posts input#add_photo').change(function(e) {
    var formData;
    formData = new FormData();
    formData.append("file", this.files[0]);
    return $.ajax({
      type: "post",
      url: $(e.target).data('upload-url'),
      cache: false,
      contentType: false,
      success: function(url) {
        var container, txtToAdd;
        container = $("#epiceditor iframe").contents().find("iframe#epiceditor-editor-frame").contents().find("body").get(0);
        txtToAdd = "![Image Description](" + url + ")";
        return insertAtCaret(container, txtToAdd);
      },
      error: function(response) {
        return alert(response.responseText);
      },
      processData: false,
      data: formData
    });
  });
};

insertAtCaret = function(element, text) {
  var frag, node, nodeToInsert, range, selection, _window;
  _window = element.ownerDocument.defaultView;
  selection = _window.getSelection();
  if (selection.rangeCount) {
    range = selection.getRangeAt();
    range.deleteContents();
    node = document.createTextNode(text);
    frag = document.createDocumentFragment();
    nodeToInsert = frag.appendChild(node);
    return range.insertNode(frag);
  } else {
    return $(element).append(text);
  }
};
kstenschke commented 9 years ago

thank you for the practical solution! To make it work in firefox i changed:

selection = _window.getSelection();

into:

selection = _window.getSelection & window.getSelection();