Why is CKEditor refusing my custom tag? - plugins

With a custom CKEditor plugin I am trying to insert a custom HTML tag, but the tag gets removed as soon as it is inserted into the editor. My plugin.js file:
CKEDITOR.plugins.add( 'tweet', {
icons: 'tweet',
init: function( editor ) {
editor.addCommand( 'insertTweet', {
allowedContent: 'tweet[:id]',
requiredContent: 'tweet',
exec: function( editor ) {
console.log('inserting');
editor.insertHtml( '<tweet :id="\'123\'" />' ); // also tried <tweet />
// editor.insertHtml( '[tweet :id="\'123\'" /]' ); // this works
}
});
editor.ui.addButton( 'tweet', {
label: 'Insert tweet',
command: 'insertTweet',
toolbar: 'insert,0'
});
}
});
The way I am adding the plugin for Bolt CMS backend:
function run() {
var extrasAdded = false;
if (typeof(CKEDITOR) == 'undefined') return;
CKEDITOR.plugins.addExternal('tweet', '/assets/plugins/tweet/plugin.js', '');
CKEDITOR.on('instanceReady', function (event, instance) {
if (extrasAdded === true) return;
var config = event.editor.config;
config.toolbar.push(
{ name: 'insert', items: [ 'tweet' ] }
);
config.extraPlugins += (config.extraPlugins ? ',' : '') + 'tweet';
config.extraAllowedContent = 'tweet'; // also tried 'tweet[:id]'
CKEDITOR.instances['body'].destroy();
CKEDITOR.replace('body', config);
extrasAdded = true;
});
}
if (document.readyState!='loading') run();
else document.addEventListener('DOMContentLoaded', run);
Can someone smart see why my tag is rejected?

So it turns out that we don't need the allowedContent or requiredContent properties in the plugin.js script. What did the trick was to tweak the editor's HTML DTD rules. In my case I got a reference to the editor in the instanceReady callback and tweeked it like this:
// name = 'tweet'
editor.filter.allow(name + "[!*]", name, true);
CKEDITOR.dtd[name] = CKEDITOR.dtd;
CKEDITOR.dtd.$empty[name] = 1; // allow self-closing tag
CKEDITOR.dtd.$blockLimit[name] = 1;
CKEDITOR.dtd.$nonEditable[name] = 1;
CKEDITOR.dtd.$object[name] = 1;
CKEDITOR.dtd.$inline[name] = 1; // $block won't work!
You can also see a full gist of it.

Related

TinyMCE 5.7 failure callback returns "[object Object]" no matter what

Seemingly strange problem here: I've got TinyMCE 5.7 up and running with the images_upload_handler function configured per the docs. If the upload is a success, everything works great. However, if the upload is a failure, then the dialog box that should output the failure message simply outputs "[object Object]".
Screenshot: Failure callback output
I find that this is the case whether I invoke the failure callback in the images_upload_handler function just as the docs dictate...
function gg_image_upload_handler (blobInfo, success, failure, progress) {
[...]
if (xhr.status < 200 || xhr.status >= 300) {
failure('HTTP Error: ' + xhr.status);
return;
}
[...]
}
...or if I make the entire images_upload_handler function a failure callback with a simple string, taking all the other variables (including the PHP upload handler) out of it:
function gg_image_upload_handler (blobInfo, success, failure, progress) {
failure('hello!');
return;
}
Notably, if I change the second example from "failure('hello!');" to "success('hello!');" then there is no problem: When I upload a photo in that case, "hello!" appears in the dialog box where the path to the uploaded image would normally appear.
I can't find anyone else who's had an issue with the failure callback, so I fear I've done something silly, but it seems weird that everything else works and this part does not. Any thoughts? Full Javascript code follows:
function gg_image_upload_handler (blobInfo, success, failure, progress) {
var xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST', 'handlers/tinymce_photo_handler.php');
xhr.upload.onprogress = function (e) {
progress(e.loaded / e.total * 100);
};
xhr.onload = function() {
var json;
if (xhr.status === 403) {
failure('HTTP Error: ' + xhr.status, { remove: true });
return;
}
if (xhr.status < 200 || xhr.status >= 300) {
failure('HTTP Error: ' + xhr.status);
return;
}
json = JSON.parse(xhr.responseText);
if (!json || typeof json.location != 'string') {
failure('Invalid JSON: ' + xhr.responseText);
return;
}
success(json.location);
};
xhr.onerror = function () {
failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
};
formData = new FormData();
formData.append('file', blobInfo.blob(), blobInfo.filename());
xhr.send(formData);
};
tinymce.init({
selector: "textarea#editor",
images_upload_handler: gg_image_upload_handler,
images_reuse_filename: true,
skin: "oxide",
plugins: "lists, link, image, media, image code",
relative_urls: false,
remove_script_host: false,
toolbar:
"h1 h2 h3 h4 h5 h6 bold italic strikethrough blockquote bullist numlist backcolor | link image media | removeformat help",
image_caption: true,
image_advtab: true,
image_class_list: [
{title: 'Responsive', value: 'img-fluid'}
],
content_style: 'img { max-width: 75%; height: auto; }',
menubar: false,
setup: (editor) => {
// Apply the focus effect
editor.on("init", () => {
editor.getContainer().style.transition =
"border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out";
});
editor.on("focus", () => {
(editor.getContainer().style.boxShadow =
"0 0 0 .2rem rgba(0, 123, 255, .25)"),
(editor.getContainer().style.borderColor = "#80bdff");
});
editor.on("blur", () => {
(editor.getContainer().style.boxShadow = ""),
(editor.getContainer().style.borderColor = "");
});
}
});
Unfortunately, this is a bug introduced in TinyMCE 5.7.0 as reported here: https://github.com/tinymce/tinymce/issues/6579. This will be fixed in the upcoming TinyMCE 5.7.1 patch release, however for now the best workaround is to downgrade to TinyMCE 5.6.2 sorry.

How to close a window in Shopware backend in my Plugin

I have a Plugin where I can create a shipping label. After i created it the window closes with win.destroy(); which is fine and i get back to the window that was open before. I would like to know
if i can close the window i get to after creating my label when i m doing the action? So I would like to close both windows that were open before.
here is the code
saveDpdconflist: function(orderid,win) {
var me = this;
dpdform = me.getDpdConf().getForm();
var dpdvalue = dpdform.getFieldValues();
dpdtabform = me.getDpdtabConf().getForm();
if (!dpdtabform.isValid()) {
Shopware.Notification.createGrowlMessage('',me.snippets.requireError,'');
return;
}
var dpdtabvalue = dpdtabform.getFieldValues();
var newstore = Ext.create('Shopware.apps.Order.DxOrderDpdtab.store.Dxorderlabel');
newstore.load({
params: {
dxorderid: orderid,
dxsalutation: dpdvalue.salutation,
dxfirstname: dpdvalue.firstName,
dxlastname: dpdvalue.lastName,
dxcompany: dpdvalue.company,
dxdepartment: '',
dxstreet: dpdvalue.street,
dxstreetno: dpdvalue.streetNumber,
dxcity: dpdvalue.city,
dxzipcode: dpdvalue.zipCode,
dxcountry: dpdvalue.countryname,
dxphone: dpdvalue.phone,
dxdpdproduct: dpdtabvalue.dxdpdshipname,
dxlabelpos: dpdtabvalue.labelposition_cmbx,
dxexportdoc: '1',
dxpayment: '1',
dxnoofgenpdf: dpdtabvalue.anzahlaversand,
dxcodtext: dpdtabvalue.nachnahmereferenz,
dxbyhand: '0',
dxweight: '5',
dxlblchgdpd: dpdvalue.dpdchngshipadd,
dxemail: dpdvalue.email,
dxshipdate: dpdtabvalue.from_date,
dxparcelshopid: win.record.raw.dxparcelshopid,
},
callback: function(data, operation) {
var records = operation.getRecords(),
record = records[0],
rawData = record.getProxy().getReader().rawData;
if(operation.success === true && rawData.data.error == '') {
if(rawData.data.number == '1'){
if(rawData.data.retoureOption == 1){
url = "{url controller='DxOrderDpdtab' action='getExportPDF'}";
url = url+'/id/'+(rawData.data.id-1);
window.open(url,'_blank');
}
url = "{url controller='DxOrderDpdtab' action='getExportPDF'}";
url = url+'/id/'+rawData.data.id;
window.open(url,'_blank');
}
Shopware.Notification.createGrowlMessage(me.snippets.successTitle,me.snippets.labelSuccessMessage,me.snippets.growlMessage);
win.destroy();
}
else{
Shopware.Notification.createGrowlMessage(me.snippets.failureTitle,rawData.data.error,me.snippets.growlMessage);
}
}
});
},

How do I extend loader widget in Magento 2 so that a background image is shown everytime the loader appears

I have been trying to extend magento 2's $.mage.loader widget. I have have a requirejs-config.js file with the following lines
var config = {
map: {
'*': {
'mage/loader' : 'Youssuph_Bakerscheckout/js/custom-mage-loader'
}
}
};
And the content of custom-mage-loader.js file is
define([
'jquery',
'mage/template',
'jquery/ui',
'mage/translate'],
function ($, mageTemplate) {
'use strict';
$.widget("bakers.loader", $.mage.loader, {
options: {
icon: '',
texts: {
loaderText: $.mage.__('Please wait...'),
imgAlt: $.mage.__('Loading...')
},
template:
'<div class="loading-mask" data-role="loader">' +
'<div class="loader">' +
'<img alt="<%- data.texts.imgAlt %>" src="'+loadingBakersLogo+'">' +
'<p><%- data.texts.loaderText %></p>' +
'</div>' +
'</div>'
}
});
return $.bakers.loader;
});
i have confirmed that this file loads in the browser but it just doesn't work. The loader works normally during page load and I see error message -
Base is not a function
What am I doing wrong?
Your requirejs-config.js it's right, but your js file no, change the params like this:
define([
'jquery',
'jquery/ui',
'mage/loader'],
function ($) {
$.widget('your_namespace.loader', $.mage.loader, {
options: {
texts: {
loaderText: $.mage.__('Foo')
},
template:
'<div>Your template</div>'
}
});
return $.your_namespace.loader;
});
Now use: jQuery('body').loader('show') and see your new custom loader!
Its been a while but if anybody else stumbles upon this answer.
vjurado is not correct. The mistake lays in requirejs-config.js. Correct will be a reference withouth the "mage/", like this:
var config = {
map: {
'*': {
'loader' : 'Youssuph_Bakerscheckout/js/custom-mage-loader'
}
}
};
The custom-mage-loader.js is correct as posted in the initial question.

Display Media Uploader in Own Plugin on Wordpress 3.5

I have little problem with Media Uploader in new WordPress 3.5. I created own plugin which is upload the picture. I'm using this code JS:
<script type="text/javascript">
var file_frame;
jQuery('.button-secondary').live('click', function( event ){
event.preventDefault();
if ( file_frame ) {
file_frame.open();
return;
}
file_frame = wp.media.frames.file_frame = wp.media(
{
title: 'Select File',
button: {
text: jQuery( this ).data( 'uploader_button_text' )
},
multiple: false
}
);
file_frame.on('select', function() {
attachment = file_frame.state().get('selection').first().toJSON();
jQuery('#IMGsrc').val(attachment.url);
});
file_frame.open();
});
</script>
The code works fine, but unfortunately forms appears incomplete. When I select any picture doesn't show me 'Attachment Display Settings' on right side. I don't know why. I try add options to media:
displaySettings: true,
displayUserSettings: true
But it also doesn't work.
Does the page have the <script type="text/html" id="tmpl-attachment-details">... template in the source? If not, you'll need to call wp_print_media_templates(), to write the styles from wp-includes/media-template.php
This is the code I use. Source: http://mikejolley.com/2012/12/using-the-new-wordpress-3-5-media-uploader-in-plugins/ It seems to work pretty well, but the sidebar on the left is missing. (Intentional, but I don't want it anyways).
<?php wp_enqueue_media(); ?>
<script>
function showAddPhotos() {
// Uploading files
var file_frame;
// event.preventDefault();
// If the media frame already exists, reopen it.
if ( file_frame ) {
file_frame.open();
return;
}
// Create the media frame.
file_frame = wp.media.frames.file_frame = wp.media({
title: jQuery( this ).data( 'uploader_title' ),
button: {
text: jQuery( this ).data( 'uploader_button_text' ),
},
multiple: false // Set to true to allow multiple files to be selected
});
// When an image is selected, run a callback.
file_frame.on( 'select', function() {
// We set multiple to false so only get one image from the uploader
attachment = file_frame.state().get('selection').first().toJSON();
// Do something with attachment.id and/or attachment.url here
});
// Finally, open the modal
file_frame.open();
}
</script>

adding external plugin in CKEditor 3.6

I am trying to add an external plugin in ckeditor but it looks that I am not registering correctly my plugin and it isn' showing.
1.- I tried adding it directly to the CKEditor config file and it didn't work.
CKEDITOR.editorConfig = function(config) {
config.toolbar = [
['Bold'],['Italic'],['myplugin']
]
};
2.- Tried adding it to the html file when initiating CKEditor and also didn't work.
var editor = CKEDITOR.replace( 'editor1',
{
removePlugins : 'forms,table,tabletools',
extraPlugins : 'msugetprop,msuforms,msutable,msutabletools,msumobile',
toolbar :
[
['Cut','Copy','PasteText','Preview'],
['Undo','Redo','-','SelectAll'],
['MsuForm','MsuGetProp','MsuCheckbox', 'MsuRadio', 'MsuTextField', 'MsuTextarea', 'MsuSelect', 'MsuButton', 'MsuTable', 'MsuHiddenField'],
'/',
['Styles','-','NumberedList','BulletedList','-','CreateDiv'],
['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],
['Link','Unlink','Anchor'],
['Source','-','About'],
['myplugin'],
]
});
3.- My plugin is under /ckeditor/plugins/myplugin with filename plugin.js
(function() {
var o = { exec: function(p) {
url = baseUrl + "/GetSomeData";
$.post(url, function(response) {
alert(response)
});
}
};
CKEDITOR.plugins.add('myplugin', {
init: function(editor) {
editor.addCommand('myplugin', o);
editor.ui.addButton('myplugin', {
label: 'myplugin',
icon: this.path + 'myplugin.png',
command: 'myplugin'
});
}
});
})();
What am I missing ?
Solved.
forgot to add 'myplugin" under extraPlugins.