CKeditor save event - events

I was following the steps written in this topic: CKEditor, AJAX Save
I tried to fire a custom 'saved.ckeditor' event if anybody press the AjaxSave button. But I did not succeeded.
ckeditor/plugins/ajaxsave/plugin.js:
(function(){
var saveCmd =
{
modes : { wysiwyg:1, source:1 },
exec : function( editor )
{
editor.fire('saved.ckeditor');
$(editor).trigger('saved.ckeditor', editor.getData());
alert(editor.getData());
}
}
var pluginName = 'ajaxsave';
CKEDITOR.plugins.add( pluginName,
{
init : function( editor )
{
var command = editor.addCommand( pluginName, saveCmd );
command.modes = { wysiwyg : !!( editor.element.$.form ) };
editor.ui.addButton( 'AjaxSave',
{
label : editor.lang.save,
command : pluginName,
className : 'cke_button_save'
});
}
});
})();
If I get or set the editor data in the function, the get and set events will automatically be fired. But I could not even fire a 'getData.ckeditor' event manually.
Any tips?
An other thing: how can I disable the button if the editor's content haven't changed since the last save (it is not dirty)?

I have a workaround.
Outside I can listen to the set event:
window.onload = function()
{
var ckparams={width: 500, height: 400, resize_enabled:false, extraPlugins: 'ajaxsave',toolbar:[['AjaxSave','Source','-','Bold','Italic','Underline','-','Undo','Redo','-','Find','Replace','-','SelectAll','-','SpellChecker','Scayt','-','About']]};
//CKEDITOR.replace('editor', ckparams);
var editor = $('textarea.editor').ckeditor(ckparams);
$(editor).bind('setData.ckeditor', function() {
//do what I want
});
};
...and when the button is pressed, set the data with its current value:
var saveCmd =
{
modes : { wysiwyg:1, source:1 },
exec : function( editor )
{
editor.setData(editor.getData());
}
}
This way at least an event is fired...
But I shold be careful when I manually set the content from outside...

try this, you need to finish the exec() function
(function() {
var saveCmd = {
modes:{wysiwyg:1,source:1 },
readOnly: 1,
exec: function( editor ) {
var data = editor.getData();
console.info(data);
}
};
var pluginName = 'ajaxSave';
// Register a plugin named "save".
CKEDITOR.plugins.add( pluginName, {
lang: 'af,ar,bg,bn,bs,ca,cs,cy,da,de,el,en-au,en-ca,en-gb,en,eo,es,et,eu,fa,fi,fo,fr-ca,fr,gl,gu,he,hi,hr,hu,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,pl,pt-br,pt,ro,ru,sk,sl,sq,sr-latn,sr,sv,th,tr,ug,uk,vi,zh-cn,zh', // %REMOVE_LINE_CORE%
icons: 'save', // %REMOVE_LINE_CORE%
init: function( editor ) {
// Save plugin is for replace mode only.
if ( editor.elementMode != CKEDITOR.ELEMENT_MODE_REPLACE ) return;
editor.ui.addButton && editor.ui.addButton( 'Save', {
label: editor.lang.save.toolbar,
command: pluginName,
toolbar: 'document,10'
});
}
});
})();
and don't forget to enable the plugin in config.js
config.extraPlugins = 'ajaxSave';

You can edit the functionality of the regular save button to do what you want:
html:
<textarea id="CKEditor1"></textarea>
javascript:
<script>
// Need to wait for the ckeditor instance to finish initialization
// because CKEDITOR.instances.editor.commands is an empty object
// if you try to use it immediately after CKEDITOR.replace('editor');
CKEDITOR.on('instanceReady', function (ev) {
// Create a new command with the desired exec function
var overridecmd = new CKEDITOR.command(editor, {
exec: function(editor){
// Replace this with your desired save button code
alert(editor.document.getBody().getHtml());
}
});
// Replace the old save's exec function with the new one
ev.editor.commands.save.exec = overridecmd.exec;
});
CKEDITOR.replace('CKEditor1');
</script>

Related

Cannot creating a config file in Laravel File Manager

I was tried to use a Laravel File Manager and i reach the step when i have to create a config file by typing:
php artisan vendor:publish --tag=lfm_config
php artisan vendor:publish --tag=lfm_public
It said successful but i can't find in config/lpm.php. When I click the button it give me a 404 in this address:
http://blog.dev/file-manager?type=image
so what can i do to fix this problems? heres javascript file if it needed:
<script type="text/javascript">
$(document).ready(function() {
// Define function to open filemanager window
var lfm = function(options, cb) {
var route_prefix = (options && options.prefix) ? options.prefix : '/laravel-filemanager';
window.open(route_prefix + '?type=' + options.type || 'file', 'FileManager', 'width=900, height=600');
window.SetUrl = cb;
};
// Define LFM summernote button
var LFMButton = function(context) {
var ui = $.summernote.ui;
var button = ui.button({
contents: '<i class="note-icon-picture"></i> ',
tooltip: 'Insert image with filemanager',
click: function() {
lfm({type: 'image', prefix: '/file-manager'}, function(url, path) {
context.invoke('insertImage', url);
});
}
});
return button.render();
};
// Initialize summernote with LFM button in the popover button group
// Please note that you can add this button to any other button group you'd like
$('#summernote-editor').summernote({
toolbar: [
['popovers', ['lfm']],
],
buttons: {
lfm: LFMButton
}
})
});
</script>

Prepend CKEditor element with another element

Whenever a table-element is inserted (through the table-icon), I would like to prepend it with another element. Eg.
<div>Hello World!</div> <!-- this was automatically added -->
<table>
<tr>
<td>A</td>
<td>A</td>
<td>A</td>
</tr>
</table>
Trying to achieve this with a custom plugin, but I just can't get it to work:
(function ($) {
CKEDITOR.plugins.add('hello_world', {
init: function (editor) {
editor.on('insertElement', function(ev) {
if (ev.data.getName() === 'table') {
var helloWorld = new CKEDITOR.dom.element('div');
helloWorld.appendText('Hello World!');
ev.data.insertBeforeMe(helloWorld);
}
});
}
});
})(jQuery);
Console returns an "Uncaught TypeError: Cannot read property 'insertBefore' of null" error. The API documentation (http://docs.ckeditor.com/#!/api/CKEDITOR.dom.element) however states that the insertBefore and insertBeforeMe functions are available.
You are getting this error because at this stage, the element is not yet added to the CKEditor (therefore its parent is null).
If you don't mind adding the comment right after the element, you may use the following code instead:
CKEDITOR.plugins.add('hello_world', {
init: function (editor) {
editor.on('insertElement', function(ev) {
if (ev.data.getName() === 'table') {
ev.data.append(new CKEDITOR.dom.comment(' this was automatically added '), true );
}
});
}
});
Then you will get the following output:
<table><!-- this was automatically added -->
See JSFiddle here.
Note: if you must add the comment before the table and you're feeling brave, you may delay the addition of the comment by using a timer:
CKEDITOR.plugins.add('hello_world', {
init: function (editor) {
editor.on('insertElement', function(ev) {
if (ev.data.getName() === 'table') {
var table = ev.data;
setTimeout(function () { table.insertBeforeMe(new CKEDITOR.dom.comment(' this was automatically added '))}, 0);
}
});
}
});
You will then get the desired output:
<!-- this was automatically added -->
<table>
See JSFiddle here
May be this solution of you problem:
CKEDITOR.editorConfig = function( config ) {
config.extraPlugins = 'responsivetables';
};
CKEDITOR.plugins.add('responsivetables', {
init: function (editor) {
editor.on('insertElement', function (event) {
if (event.data.getName() === 'table') {
var div = new CKEDITOR.dom.element('div').addClass('table-scroll'); // Create a new div element to use as a wrapper.
div.append(event.data); // Append the original element to the new wrapper.
event.data = div; // Replace the original element with the wrapper.
}
}, null, null, 1);
}
});

mithril.js issues with CKEditor

I've written this code using mithril.js + CKEditor
<body>
<script>
var frm = {};
frm.vm = (function () {
var vm = {};
vm.afterLoad = function () {
CKEDITOR.replace( 'editor1' );
};
vm.btnClick = function () {
console.log(document.getElementById('editor1').value);
};
return vm;
})();
frm.controller = function () {
};
frm.view = function (controller) {
return m("div", {config: frm.vm.afterLoad}, [
m("textarea", {id: "editor1"}),
m("button", {onclick: frm.vm.btnClick}, "Click here to see the text you've typed")
])
;
};
m.mount(document.body, frm);
</script>
</body>
but when I click the button, I see this error:
Uncaught The editor instance "editor1" is already attached to the provided element.
and console.log() prints a blank line.
What am I doing wrong?
I found the problem. To get the value of the CKEditor, one needs to use
CKEditor.instance.nameoftextarea.getData()

Ckeditor Get Content From Iframe

I have a iframe and i'm trying to use Dialog to get data in Iframe and output to current html, but i don't know how to get Ckeditor Content from the Iframe.
I tried to using CKEDITOR.instances['editor'].getData(); but look like cannot get it.
This is my code:
<textarea class='editor' name='description' id='description'></textarea>
$( "#dialog_custom" ).dialog({
autoOpen: false,
modal: true,
height: 768,
width: 1024,
buttons: {
Add: function() {
var model = $('.dialog_custom').contents().find('#model').val();
var product_id = $('.dialog_custom').contents().find('#product_id').val();
var product_name = $('.dialog_custom').contents().find('#product_name').val();
var qty = $('.dialog_custom').contents().find('#qty').val();
var total = $('.dialog_custom').contents().find('#total').val();
var category = $('.dialog_custom').contents().find('#category').val();
if(qty=='') { qty = '0'; }
if(total=='') { total = '0.00'; }
if(model=='') {
alert('Please input the correct Model Number.');
} else {
$(".product").append(InsertTableGetFromIframe);
$('.delete_custom_row').click(function() {
if(confirm("Are you sure want to delete this data?")) {
$(this).parents('.custom_row').next('.parts_row').remove();
$(this).parents('.custom_row').remove();
}
});
$('.dialog_custom').contents().find('#model').val('');
$('.dialog_custom').contents().find('#product_id').val('');
$('.dialog_custom').contents().find('#product_name').val('');
$('.dialog_custom').contents().find('#qty').val('');
$('.dialog_custom').contents().find('#total').val('');
$('.dialog_custom').contents().find('#category').val('');
$(this).dialog("close");
i++;
}
},
Close: function() {
$(this).dialog("close");
}
}
});
$( "#open_custom" ).click(function() {
$( "#dialog_custom" ).dialog( "open" );
});
</script>
Finally, I found out the solution to get the content in the iframe, i used jquery to submit the form then POST the value on the field and get it by Jquery again.
It's the most simple way that i found, actually I think we have another way better to do it...

Bootstrap typeahead suggestions replaced when navigation

I'm using Bootstrap Typeahead to suggest som search results. The results are returned from a ajax ressource, and since this resource creates a delay, I'm experiencing a unfortunate effect.
Example:
If typing a 4 letter word, the suggestions will appear after 2 letters, I can then go through the results with the keys up/down, but suddenly the suggestions will reload because the last request has finished.
Is there any way to "cancel" any remaining, if user is currently using the keys up/down to go through the suggestions?
('#query').typeahead({
items: 4,
source: function (query,process) {
map = {};
$.getJSON('/app_dev.php/ajax/autosuggest/'+query, function (data) {
vehicles = [];
$.each(data, function(i,vehicle){
map[vehicle.full] = vehicle;
vehicles.push(vehicle.full);
});
process(vehicles);
});
},
updater: function (item) {
// do something here when item is selected
},
highlighter: function (item) {
return item;
},
matcher: function (item) {
return true;
}
});
I think the following will satisfy your needs (its hard to reproduce exactly) :
There is no easy way to abort a delayed response, but you could extend typeahead as I figured out here (without modifying bootstrap.js)
The concept is to catch keydown, detect if the event is KEY_UP or KEY_DOWN, set a flag is_browsing, and then abort process if is_browsing is true (that is, if the user has hitted KEY_UP or KEY_DOWN and no other keys afterwards).
Extending typeahead :
// save the original function object
var _superTypeahead = $.fn.typeahead;
// add is_browsing as a new flag
$.extend( _superTypeahead.defaults, {
is_browsing: false
});
// create a new constructor
var Typeahead = function(element, options) {
_superTypeahead.Constructor.apply( this, arguments )
}
// extend prototype and add a _super function
Typeahead.prototype = $.extend({}, _superTypeahead.Constructor.prototype, {
constructor: Typeahead
, _super: function() {
var args = $.makeArray(arguments)
// call bootstrap core
_superTypeahead.Constructor.prototype[args.shift()].apply(this, args)
}
//override typeahead original keydown
, keydown: function (e) {
this._super('keydown', e)
this.options.is_browsing = ($.inArray(e.keyCode, [40,38])>-1)
}
//override process, abort if user is browsing
, process: function (items) {
if (this.options.is_browsing) return
this._super('process', items)
}
});
// override the old initialization with the new constructor
$.fn.typeahead = $.extend(function(option) {
var args = $.makeArray(arguments),
option = args.shift()
// this is executed everytime element.modal() is called
return this.each(function() {
var $this = $(this)
var data = $this.data('typeahead'),
options = $.extend({}, _superTypeahead.defaults, $this.data(), typeof option == 'object' && option)
if (!data) {
$this.data('typeahead', (data = new Typeahead(this, options)))
}
if (typeof option == 'string') {
data[option].apply( data, args )
}
});
}, $.fn.typeahead);
This typeahead-extension could be placed anywhere, eg in a <script type="text/javascript"> -section
Testing the extension :
<input type="text" id="test" name="test" placeholder="type some text" data-provide="typeahead">
<script type="text/javascript">
$(document).ready(function() {
var url='typeahead.php';
$("#test").typeahead({
items : 10,
source: function (query, process) {
return $.get(url, { query: query }, function (data) {
return process(data.options);
});
}
});
});
</script>
A "serverside" PHP script that returns a lot of randomized options with forced delay, typeahead.php :
<?
header('Content-type: application/json');
$JSON='';
sleep(3); //delay execution in 3 secs
for ($count=0;$count<30000;$count++) {
if ($JSON!='') $JSON.=',';
//create random strings
$s=str_shuffle("abcdefghijklmnopq");
$JSON.='"'.$s.'"';
}
$JSON='{ "options": ['.$JSON.'] }';
echo $JSON;
?>
It really seems to work for me. But I cannot be sure that it will work in your case. Let me now if you have success or not.

Resources