I added wp.media via js to crop images. I've got it working for admin but not for any other role specifically 'subscriber'. It sounds crazy but there are no errors at all in the console or in debug and the only error I get is There has been an error cropping your image.
I don't think its a GC issue or Imagick etc as it does work for admin.
I've tried adding permissions to the 'subscriber' role: upload_files and edit_files (which seems to be deprecated anyways). Please help and thank you in advance! Here's the code. I unfortunately do not know who to credit for this, but majority of it is not my original code:
var mediaUploader;
function myTheme_calculateImageSelectOptions(attachment, controller) {
var control = controller.get( 'control' );
var flexWidth = !! parseInt( control.params.flex_width, 10 );
var flexHeight = !! parseInt( control.params.flex_height, 10 );
var realWidth = attachment.get( 'width' );
var realHeight = attachment.get( 'height' );
var xInit = parseInt(control.params.width, 10);
var yInit = parseInt(control.params.height, 10);
var ratio = xInit / yInit;
controller.set( 'canSkipCrop', ! control.mustBeCropped( flexWidth, flexHeight, xInit, yInit, realWidth, realHeight ) );
var xImg = xInit;
var yImg = yInit;
if ( realWidth / realHeight > ratio ) {
yInit = realHeight;
xInit = yInit * ratio;
} else {
xInit = realWidth;
yInit = xInit / ratio;
}
var x1 = ( realWidth - xInit ) / 2;
var y1 = ( realHeight - yInit ) / 2;
var imgSelectOptions = {
handles: true,
keys: true,
instance: true,
persistent: true,
imageWidth: realWidth,
imageHeight: realHeight,
minWidth: xImg > xInit ? xInit : xImg,
minHeight: yImg > yInit ? yInit : yImg,
x1: x1,
y1: y1,
x2: xInit + x1,
y2: yInit + y1
};
return imgSelectOptions;
}
function myTheme_setImageFromURL(url, attachmentId, width, height) {
var choice, data = {};
data.url = url;
data.thumbnail_url = url;
data.timestamp = _.now();
if (attachmentId) {
data.attachment_id = attachmentId;
}
if (width) {
data.width = width;
}
if (height) {
data.height = height;
}
// $("#heading_picture").val( url );
// $("#heading_picture_preview").prop("src", url);
$('[name="entry-img"]').val(attachmentId)
$('.activity-add-image').css({ 'background-image': `url(${url})` }).addClass('has-image')
$('.activity-remove-image').css('display', 'block');
fieldValidation.image.validated = true
validateNewLetter()
}
function myTheme_setImageFromAttachment(attachment) {
// $("#heading_picture").val( attachment.url );
// $("#heading_picture_preview").prop("src", attachment.url);
$('[name="entry-img"]').val(attachment.id)
$('.activity-add-image').css({ 'background-image': `url(${attachement.url})` }).addClass('has-image')
$('.activity-remove-image').css('display', 'block');
fieldValidation.image.validated = true
validateNewLetter()
}
$('.activity-remove-image').on('click', function(e){
e.preventDefault();
$('.activity-add-image').css({ 'background-image': 'none' }).removeClass('has-image')
$('.activity-remove-image').hide();
$('[name="entry-img"]').val(null)
fieldValidation.image.validated = false
validateNewLetter()
});
$(".activity-upload-image").on("click", function(e) {
e.preventDefault();
/* We need to setup a Crop control that contains a few parameters
and a method to indicate if the CropController can skip cropping the image.
In this example I am just creating a control on the fly with the expected properties.
However, the controls used by WordPress Admin are api.CroppedImageControl and api.SiteIconControl
*/
var cropControl = {
id: "control-id",
params : {
flex_width : false, // set to true if the width of the cropped image can be different to the width defined here
flex_height : false, // set to true if the height of the cropped image can be different to the height defined here
width : 1100, // set the desired width of the destination image here
height : 460, // set the desired height of the destination image here
}
};
cropControl.mustBeCropped = function(flexW, flexH, dstW, dstH, imgW, imgH) {
// If the width and height are both flexible
// then the user does not need to crop the image.
if ( true === flexW && true === flexH ) {
return false;
}
// If the width is flexible and the cropped image height matches the current image height,
// then the user does not need to crop the image.
if ( true === flexW && dstH === imgH ) {
return false;
}
// If the height is flexible and the cropped image width matches the current image width,
// then the user does not need to crop the image.
if ( true === flexH && dstW === imgW ) {
return false;
}
// If the cropped image width matches the current image width,
// and the cropped image height matches the current image height
// then the user does not need to crop the image.
if ( dstW === imgW && dstH === imgH ) {
return false;
}
// If the destination width is equal to or greater than the cropped image width
// then the user does not need to crop the image...
if ( imgW <= dstW ) {
return false;
}
return true;
};
/* NOTE: Need to set this up every time instead of reusing if already there
as the toolbar button does not get reset when doing the following:
mediaUploader.setState('library');
mediaUploader.open();
*/
console.log('control', cropControl)
mediaUploader = wp.media({
button: {
text: 'Select', // l10n.selectAndCrop,
close: false
},
states: [
new wp.media.controller.Library({
title: 'Select and Crop', // l10n.chooseImage,
library: wp.media.query({ type: 'image' }),
multiple: false,
date: false,
priority: 20,
suggestedWidth: 1100,
suggestedHeight: 460
}),
new wp.media.controller.CustomizeImageCropper({
imgSelectOptions: myTheme_calculateImageSelectOptions,
control: cropControl
})
]
});
mediaUploader.on('cropped', function(croppedImage) {
console.log('cropped', croppedImage)
var url = croppedImage.url,
attachmentId = croppedImage.attachment_id,
w = croppedImage.width,
h = croppedImage.height;
myTheme_setImageFromURL(url, attachmentId, w, h);
});
mediaUploader.on('skippedcrop', function(selection) {
console.log('skipped', selection)
var url = selection.get('url'),
w = selection.get('width'),
h = selection.get('height');
myTheme_setImageFromURL(url, selection.id, w, h);
});
mediaUploader.on("select", function() {
var attachment = mediaUploader.state().get( 'selection' ).first().toJSON();
console.log('select', attachment)
if ( cropControl.params.width === attachment.width
&& cropControl.params.height === attachment.height
&& ! cropControl.params.flex_width
&& ! cropControl.params.flex_height ) {
myTheme_setImageFromAttachment( attachment );
mediaUploader.close();
} else {
console.log(mediaUploader)
mediaUploader.setState( 'cropper' );
}
});
mediaUploader.open();
});```
My editor contains custom elements, created like this:
this.editor.model.change( writer => {
const id = `a${ Math.random().toString().replace('.', '') }`;
const autocomplete = writer.createElement( 'autocomplete', { 'data-id': id );
this.editor.model.insertContent( autocomplete );
} );
I want to get all 'autocomplete' elements at a later time in my plugin so I can read their content (they're editable elements).
Is there something like querySelectorAll('autocomplete') for the model of the editor?
It's possible using range.getWalker.
const findNodes = function(writer, type, root) {
const nodes = [];
const range = writer.createRangeIn( root );
for ( const value of range.getWalker({ ignoreElementEnd: true }) ) {
const node = value.item;
if ( node.is( type ) ) {
nodes.push(node);
}
}
return nodes;
};
this.editor.model.change( writer => {
const autocompletes = findNodes(writer, 'autocomplete', this.editor.model.document.getRoot());
} );
I'm trying to find a reliable way to perform a callback when certain text is typed into the editor. I want to run certain code when an # is typed (to then allow a selection of user's to link to).
Currently I am doing it by using the "change" event and then trying to look back at what is before the current selection:
CKEDITOR.plugins.add( 'ipsmentions', {
init: function( editor ) {
/* When the content of the editor is changed, check if it was an # */
editor.on( 'change', function(e) {
/* If we currently have just normal text selected, we're typing normally and there might be an # */
var selection = editor.getSelection();
if ( selection.getType() == CKEDITOR.SELECTION_TEXT ) {
/* Loop the ranges... */
var ranges = selection.getRanges( true );
for ( var i = 0; i < ranges.length; i++ ) {
/* If the start container and end container are the same (meaning we just have a normal caret, indicating normal typing, nothing highlighted) and that is a text node... */
if ( ranges[i].startContainer.equals( ranges[i].endContainer ) && ranges[i].endContainer instanceof CKEDITOR.dom.text ) {
if ( ranges[i].startContainer.getText().substr( ranges[i].startOffset - 1, 1 ) == '#' ) {
console.log('# pressed!');
}
}
}
}
});
}
});
But I'm guessing this isn't the best way. In particular, I notice that if I type # and then hit enter (to start a new paragraph) I get "# pressed" in the console again.
Is there a better way to go about this?
Asynchronous check should help with enter key. I would also use some backwards range.cloneContents because you never know in what type of node the selection might be anchored. JSFiddle.
CKEDITOR.replace( 'editor', {
on: {
change: function() {
CKEDITOR.tools.setTimeout( function() {
var sel = this.getSelection(),
range = sel.getRanges()[ 0 ];
if ( !range.collapsed ) {
console.warn( 'non–collapsed range' );
return;
}
if ( !range.startOffset ) {
console.warn( 'at the beginning of the node' );
return;
}
range.setStart( range.startContainer, 0 );
if ( range.cloneContents().$.textContent.substr( -1 ) == '#' ) {
console.log( '# inserted' );
}
}, 0, this );
}
}
} );
Friends, I need your help, the following code in three.js, all return null in this line:
_context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes );
function initGL() {
try {
var attributes = {
alpha: _alpha,
depth: _depth,
stencil: _stencil,
antialias: _antialias,
premultipliedAlpha: _premultipliedAlpha,
preserveDrawingBuffer: _preserveDrawingBuffer
};
_gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes );
if ( _gl === null ) {
throw 'Error creating WebGL context.';
}
} catch ( error ) {
console.error( error );
}
_glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' );
the attributes value:
this is canvas:
Thanks a lot!
~Rosone
I found the reason: It's because another context (canvas.getContext('2d') ) already occupied this same canvas.
How can i enable or disable the paragraph button of CKEditor on selection of an image. I did not want to remove it completely.
am currently using ckeditor version 4.4
Use editor.getCommand() + CKEDITOR.command API (enable and disable):
editor.getCommand( 'justifyleft' ).disable();
editor.getCommand( 'justifyleft' ).enable();
For example:
CKEDITOR.instances.editor1.on( 'selectionChange', function( evt ) {
var jLeftCommand = this.getCommand( 'justifyleft' ),
jRightCommand = this.getCommand( 'justifyright' );
if ( evt.data.path.lastElement.is( 'img' ) ) {
jLeftCommand.disable();
jRightCommand.disable();
} else {
jLeftCommand.enable();
jRightCommand.enable();
}
} );