Good day, dear habrovchane.
For several months now I have been actively using
AngularJS in one of the work projects. I will not sing “meritorious songs” or offer this framework because there are no ideal things (and it would probably be very boring to live in peace with such things that do not leave the possibility of overcoming their shortcomings with their “creativity”). I can only say a few words about the results: the ideology of AngularJS copes very well with the organization of the code in my face and gives the magic tool Directives. By the way, recently there was a note about
CornerJS , in which directives were
sent to the technology center, and on Google I / O this year, there was news about possible support for
custom-elements (not just tags, but complex html components embedded in the page).
At the next stage of development, the question of integration with an advanced WYSIWYG editor
arose , and my gaze immediately fell on
ckEditor , as I have repeatedly used it in DotNetNuke-based projects and the impressions were very positive (or let's say differently: there are strong flaws in the component not found and the integration took a few hours).
Appealing to Google for help in integration magic, I received several links to Stackoverflow and other private blogs, where the
pasteState event is a solution to all the problems and the directive as a whole looks simple and accessible:
')
app.directive('ckEditor', [function () { return { require: '?ngModel', link: function ($scope, elm, attr, ngModel) { var ck = CKEDITOR.replace(elm[0]); ck.on('pasteState', function () { $scope.$apply(function () { ngModel.$setViewValue(ck.getData()); }); }); ngModel.$render = function (value) { ck.setData(ngModel.$modelValue); }; } }; }]);
But after another mailstone and deployment, the customer began to notice that sometimes the edited text is not fully preserved or the component generally crashes with Access Violation, in the case of earlier versions of InternetExplorer (<9). The problem was reproduced, the ideal conditions were obtained and I went to look for a solution to the problem.
After re-reading the documentation and poking around the page for the overall picture, I came to the conclusion that this event works fine with the keyboard, but completely ignores the insertion of elements (whether text, pictures, etc.) from the plug-ins that come with it. Immediately, it was decided to look for a new event that is more global. But the search results led to this “non-Orthodox”
method , which is also a plug-in in the appendix (which is fraught with migration or updates of the ckEditor itself). Therefore, it was decided to raise the version of the editor to the latest available (CKEditor 4.2.1 at that time), risking stability and get a magic
change event at the level of the native api (maybe they just integrated the above-mentioned plugin into the kernel, I honestly did not follow the story). Replacing the event with change helped resolve the issue of saving changed content, but did not solve the problem with Access Violation.
Having learned the bitter experience of
popup windows for IE <9 (IE spreads the execution of different windows, on different threads with a full reset of cookies, etc.) I came to the conclusion that the problem is in the iframe component and the sequence of creating and accessing it within ckEditor itself, as well as the life cycle
scope within AngularJS. The problem is that the CKEDITOR.replace (...) method works asynchronously in old IE and “releasing” the AngularJS execution context tries to make the model binding and call
setData , which tries to access the still unprepared iframe, which causes Access Violation. I didn’t come up with a “better” and “safer” queue, so the result was the following directive code:
app.directive('ckEditor', [function () { return { require: '?ngModel', restrict: 'C', link: function (scope, elm, attr, model) { var isReady = false; var data = []; var ck = CKEDITOR.replace(elm[0]); function setData() { if (!data.length) { return; } var d = data.splice(0, 1); ck.setData(d[0] || '<span></span>', function () { setData(); isReady = true; }); } ck.on('instanceReady', function (e) { if (model) { setData(); } }); elm.bind('$destroy', function () { ck.destroy(false); }); if (model) { ck.on('change', function () { scope.$apply(function () { var data = ck.getData(); if (data == '<span></span>') { data = null; } model.$setViewValue(data); }); }); model.$render = function (value) { if (model.$viewValue === undefined) { model.$setViewValue(null); model.$viewValue = null; } data.push(model.$viewValue); if (isReady) { isReady = false; setData(); } }; } } }; }]);
There are ambiguous points in the code associated with the queue and model. $ ViewValue values (in particular, these were attempts to cope with the sinking of the component in modal dialogs, which was solved by the twitter bootstrap modal component patch, but this is another story).
I also did not fully disclose the points related to setData (..., callback), which is essentially one of the synchronization mechanisms, but it seems to me that the code looks informative in this context and replaces words.
I will once hear suggestions and criticisms about this approach.
PS
Working example of what happened with me
http://jsfiddle.net/jWANb/2/Working example of what is advised on the Internet
http://jsfiddle.net/fvApg/1/Try inserting a picture in the second example and look at “result html”. It will be seen that the context has not changed.