codedance / jquery.AreYouSure

A light-weight jQuery "dirty forms" Plugin - it monitors html forms and alerts users to unsaved changes if they attempt to close the browser or navigate away from the page. (Are you sure?)
508 stars 145 forks source link

CKeditor support #62

Open ghost opened 9 years ago

ghost commented 9 years ago

Hi,

You can add CKeditor support. Just simply add following code into your solution.

checkForm()

(...) // ckeditor if (typeof (evt.editor) !== 'undefined') { if (CKEDITOR.instances[evt.editor.name].checkDirty()) { setDirtyStatus($("#" + evt.editor.name).parents('form'), true); return; } }

(...)

initForm()

(...) //ckeditor if (typeof(CKEDITOR) !== 'undefined') { CKEDITOR.on('instanceReady', function () { for (var instanceName in CKEDITOR.instances) { CKEDITOR.instances[instanceName].removeListener("change", checkForm); CKEDITOR.instances[instanceName].on("change", checkForm); CKEDITOR.instances[instanceName].removeListener("keyup", checkForm); CKEDITOR.instances[instanceName].document.on("keyup", checkForm); } }); } (...)

paulofreitas commented 9 years ago

+1, that would be awesome! :+1:

lagseeing commented 9 years ago

You should make a pull request.

codedance commented 9 years ago

That's good information. Would you be willing to submit a demo page to the repo? I'm thinking an example HTML file located at:

~demo/integration/ckeditor-ays-example.html

Just a simple page that demonstrates this integration I'm sure would be a great help to others.

robme commented 8 years ago

I tried this and it doesn't work for changes made to the text, only changes made via the toolbar.

I've narrowed down the problem to a race condition. The event for the form fires, and sets dirty to false. And then the event for CKEditor fires and sets dirty to true. If it happens the other way round then it works (such as while debugging), but without a breakpoint set, I found it was setting dirty and then immediately unsetting it.

robme commented 8 years ago

I got it working. I was using tyama's commit above, which didn't work. You need to put the initForm code at the end, not above, and tweak it slightly. Here is my initForm:

var initForm = function($form) {
  var fields = $form.find(settings.fieldSelector);
  $(fields).each(function() { storeOrigValue($(this)); });
  $(fields).unbind(settings.fieldEvents, checkForm);
  $(fields).bind(settings.fieldEvents, checkForm);
  $form.data("ays-orig-field-count", $(fields).length);
  setDirtyStatus($form, false);

  //CKEditor
  if (typeof(CKEDITOR) !== 'undefined') {
    CKEDITOR.on('instanceReady', function () {
      for (var instanceName in CKEDITOR.instances) {
        $('#' + instanceName).unbind(settings.fieldEvents, checkForm);
        CKEDITOR.instances[instanceName].on("change", checkForm);
        CKEDITOR.instances[instanceName].document.on("keyup", checkForm);
      }
    });
  }
};

Explanation: The CKEditor part has to come afterwards because we want to unbind the events added. And in order to unbind them, I just use the instanceName as a selector and call it in the same way they were bound above. This means the change/keyup events are not firing on the hidden textarea (the contents of which does not change), and instead, CKEditor's events will fire.

jfcartier commented 8 years ago

This worked for me :

  function beforeUnload(evt) {
    for (var name in CKEDITOR.instances) {
      if (CKEDITOR.instances[name].checkDirty())
        return evt.returnValue = "messageUnsaved";
    }
  }

  if (window.addEventListener)
    window.addEventListener('beforeunload', beforeUnload, false);
  else
    window.attachEvent('onbeforeunload', beforeUnload);
cmanley commented 7 years ago

I'm using v4 of CKEditor so ymmv... but this is how I do it without modifying jquery.are-you-sure.js:

$('#my_happy_little_form')
.areYouSure({'message': "Your changes haven't been saved."} )
.on('dirty.areYouSure', function() {
    $(this).find('input[type="reset"], input[type="submit"]').prop('disabled', false);
})
.on('clean.areYouSure', function() {
    $(this).find('input[type="reset"], input[type="submit"]').prop('disabled', true);
});

CKEDITOR.on('instanceCreated', function(e) {
    e.editor.on('change', function(event) {
        var textarea = event.editor.element.$;
        $(textarea).val(event.editor.getData().trim());
        $(textarea.form).trigger('checkform.areYouSure');
    });
})
CKEDITOR.replace('body_xhtml', { 
    // place options here
});
bryanjamesmiller commented 7 years ago

@cmanley Thanks for getting me started on this. I'm wondering why not just this:

        CKEDITOR.on("instanceReady", function (event) {
                $('form').areYouSure();
                event.editor.on('change', function(event) {
                    $('form').trigger('checkform.areYouSure');
                });
            });
cmanley commented 6 years ago

@bryanjamesmiller It won't work like that because you need to copy the CKEDITOR data into the textarea element before triggering checkform.areYouSure. However, you can use either instanceCreated or instanceReady as both seem to work, and you can initialize areYouSure either inside the instanceCreated or instanceReady or outside as I did. The latter makes more sense to me as areYouSure depends on the textarea existing and not a CKEditor instance.

LiamDawe commented 6 years ago

Just wanted to pop along to say thank you @cmanley

Slotting in:

CKEDITOR.on('instanceCreated', function(e) {
    e.editor.on('change', function(event) {
        var textarea = event.editor.element.$;
        $(textarea).val(event.editor.getData().trim());
        $(textarea.form).trigger('checkform.areYouSure');
    });
})

Makes it work perfectly as far as I can tell :+1: