Custom wp.media with arguments support - javascript

How to setup a [add media] button, with:
proper wordpress [media] UI
has size and alignments UI in popup right hand side
can custom popup title and button
size and alignments arguments can send back to be use

Just try to cover most solutions:
use tb_show("", "media-upload.php?type=image&TB_iframe=true"); and window.send_to_editor
problem: has no standard wp.media UI
in js code:
jQuery("#my_button").click(function() {
tb_show("", "media-upload.php?type=image&TB_iframe=true");
return false;
});
window.send_to_editor = function(html) {
console.log(html);
tb_remove();
}
use wp.media({frame: 'post'})
problem: cannot custom UI elements, such as: title, button
in js code:
function clearField(){
#remove file nodes
#...
}
var frame = wp.media({frame: 'post'});
frame.on('close',function() {
var selection = frame.state().get('selection');
if(!selection.length){
clearField();
}
});
frame.on( 'select',function() {
var state = frame.state();
var selection = state.get('selection');
if ( ! selection ) return;
clearField();
selection.each(function(attachment) {
console.log(attachment.attributes);
});
});
frame.open();
use wp.media.editor with wp.media.editor.open( editor_id )
problem: cannot custom UI elements, such as: title, button
in js code: https://wordpress.stackexchange.com/questions/75808/using-wordpress-3-5-media-uploader-in-meta-box#75823
use wp.media with rewrite wp.media.controller.Library and retrieve attachment in select
problem: complicated ..., but once you understand it, it all make sense, and it is my finial solution
in js code:
/**
* Please attach all the code below to a button click event
**/
//create a new Library, base on defaults
//you can put your attributes in
var insertImage = wp.media.controller.Library.extend({
defaults : _.defaults({
id: 'insert-image',
title: 'Insert Image Url',
allowLocalEdits: true,
displaySettings: true,
displayUserSettings: true,
multiple : true,
type : 'image'//audio, video, application/pdf, ... etc
}, wp.media.controller.Library.prototype.defaults )
});
//Setup media frame
var frame = wp.media({
button : { text : 'Select' },
state : 'insert-image',
states : [
new insertImage()
]
});
//on close, if there is no select files, remove all the files already selected in your main frame
frame.on('close',function() {
var selection = frame.state('insert-image').get('selection');
if(!selection.length){
#remove file nodes
#such as: jq("#my_file_group_field").children('div.image_group_row').remove();
#...
}
});
frame.on( 'select',function() {
var state = frame.state('insert-image');
var selection = state.get('selection');
var imageArray = [];
if ( ! selection ) return;
#remove file nodes
#such as: jq("#my_file_group_field").children('div.image_group_row').remove();
#...
//to get right side attachment UI info, such as: size and alignments
//org code from /wp-includes/js/media-editor.js, arround `line 603 -- send: { ... attachment: function( props, attachment ) { ... `
selection.each(function(attachment) {
var display = state.display( attachment ).toJSON();
var obj_attachment = attachment.toJSON()
var caption = obj_attachment.caption, options, html;
// If captions are disabled, clear the caption.
if ( ! wp.media.view.settings.captions )
delete obj_attachment.caption;
display = wp.media.string.props( display, obj_attachment );
options = {
id: obj_attachment.id,
post_content: obj_attachment.description,
post_excerpt: caption
};
if ( display.linkUrl )
options.url = display.linkUrl;
if ( 'image' === obj_attachment.type ) {
html = wp.media.string.image( display );
_.each({
align: 'align',
size: 'image-size',
alt: 'image_alt'
}, function( option, prop ) {
if ( display[ prop ] )
options[ option ] = display[ prop ];
});
} else if ( 'video' === obj_attachment.type ) {
html = wp.media.string.video( display, obj_attachment );
} else if ( 'audio' === obj_attachment.type ) {
html = wp.media.string.audio( display, obj_attachment );
} else {
html = wp.media.string.link( display );
options.post_title = display.title;
}
//attach info to attachment.attributes object
attachment.attributes['nonce'] = wp.media.view.settings.nonce.sendToEditor;
attachment.attributes['attachment'] = options;
attachment.attributes['html'] = html;
attachment.attributes['post_id'] = wp.media.view.settings.post.id;
//do what ever you like to use it
console.log(attachment.attributes);
console.log(attachment.attributes['attachment']);
console.log(attachment.attributes['html']);
});
});
//reset selection in popup, when open the popup
frame.on('open',function() {
var selection = frame.state('insert-image').get('selection');
//remove all the selection first
selection.each(function(image) {
var attachment = wp.media.attachment( image.attributes.id );
attachment.fetch();
selection.remove( attachment ? [ attachment ] : [] );
});
//add back current selection, in here let us assume you attach all the [id] to <div id="my_file_group_field">...<input type="hidden" id="file_1" .../>...<input type="hidden" id="file_2" .../>
jq("#my_file_group_field").find('input[type="hidden"]').each(function(){
var input_id = jq(this);
if( input_id.val() ){
attachment = wp.media.attachment( input_id.val() );
attachment.fetch();
selection.add( attachment ? [ attachment ] : [] );
}
});
});
//now open the popup
frame.open();

I would like to add to ZAC's option 4 because when I used his code, the image src="" was missing.
Here is the fix
if ( 'image' === obj_attachment.type ) {
html = wp.media.string.image( display );
_.each({
align: 'align',
size: 'image-size',
alt: 'image_alt'
}, function( option, prop ) {
if ( display[ prop ] )
options[ option ] = display[ prop ];
});
html = wp.media.string.image( display, obj_attachment );
}

This way you can call the new media uploader with custom title and button and right side bar.
var custom_uploader;
jQuery('#fileform').on('click','.select-files', function(e) {
var button = jQuery(this);
custom_uploader = wp.media.frames.file_frame = wp.media({
title: 'Choose File',
library: {
author: userSettings.uid // specific user-posted attachment
},
button: {
text: 'Choose File'
},
multiple: false
});
//When a file is selected, grab the URL and set it as the text field's value
custom_uploader.on('select', function() {
attachment = custom_uploader.state().get('selection').first().toJSON();
console.log(attachment.url);
console.log(attachment.id); // use them the way you want
});
//Open the uploader dialog
// Set post id
wp.media.model.settings.post.id = jQuery('#post_ID').val();
custom_uploader.open();
});

Check this link -> https://github.com/phpcodingmaster/WordPress-Media-Modal-Image-Uploads
It will show you how to:
Open the admin media modal
Get single image info
Get multiple images info
Tested with WordPress Version 6.0

Related

CKEditor - Image Properties dialog is blank

I am using the default Image plugin with the usual values:
CKEDITOR.replace( 'editor',
{
filebrowserBrowseUrl: '/app/myimages.html',
filebrowserUploadUrl: '/app/myfiles.html',
filebrowserImageBrowseUrl: '/app/myimages.html'
}
The image shows up correctly in the editor after selection via image select dialog box.
But when i right-click on the image and select Image Properties menu.
The dialog that opens does not contain the image URL or width or height etc. It essentially has no values.
See my comments. But for me it was overridding onShow().
CKEDITOR.on('dialogDefinition', function( ev ) {
// Take the dialog window name and its definition from the event data.
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
if ( dialogName == 'image' ) {
/*dialogDefinition.onShow = function() {
this.selectPage( 'info' );
};*/ // do not override this function, it will cause a JS on save (setCustomData can not be found on null object), and the edit image will not fill in its fields.
dialogDefinition.removeContents( 'Link' ); // remove these tabs
dialogDefinition.removeContents( 'advanced' );
dialogDefinition.removeContents( 'Upload' );
var contents = dialogDefinition.getContents( 'info' );
//contents.remove( 'htmlPreview' ); // will cause a JS error if disabled.
contents.remove( 'ratioLock' );
contents.remove( 'txtHSpace' );
contents.remove( 'txtVSpace' );
contents.remove( 'txtAlt' );
contents.remove( 'txtBorder' );
contents.get('txtWidth').width = 'auto';
contents.get('txtHeight').width = 'auto';
contents.get('txtUrl').disabled = 'disabled';
}
});

Uploading a pic doesn't just work on android native browser

I've been having problem with this code that uploads an image. It doesn't work on native android browser(Tried on galaxy note 2). It works fine on all other browsers on different machines. Please help if anyone has ever come across this problem before or can figure out what went wrong.
Here is the template -> image_upload_view.hbs
<label>
<div class='label-text'>{{t label }}:</div>
<div class="input-prepend">
<div class="preview" style="background-image: url('{{src}}');"></div>
<i class="icon-arrow-up"></i>
<span class="input-description">{{t description}}</span>
<span class="change-notification hide">{{t 'COMPONENT_IMAGE_UPLOAD_IMAGE_CHANGED'}}</span>
<i class="icons"></i>
<input class="input hide" type="file" name="image_file_name" accept="image/gif, image/jpeg, image/jpg, image/png"></input>
</div>
</label>
Here is the logic -> image_upload_view.js
var Base = require( '../../base' ),
_ = require( 'underscore' ),
oldBrowserPreviewImage = '/images/profiles/edit/default_cover_image_preview.jpg';
module.exports = Base.extend( {
className: 'component-image-upload',
events: {
'change input[type=file]': 'onChange',
'click .remove-image': 'onRemove'
},
getTemplateData: function () {
return _( this._super() ).extend( {
description: this.description,
label: this.label,
src: this.src
} );
},
postRender: function () {
// TODO: Let parent instantiate and pass in models once new hydration logic is merged.
var ModelType = require( '../../../models/image_upload/' + this.type );
this._super();
this.model = new ModelType( {
file_url: this.src
}, {
app: this.app
} );
this.renderImagePreview();
},
onChange: function ( evt ) {
this.updateFile( this.$( evt.currentTarget ) );
},
onRemove: function ( evt ) {
var fileInput = this.$( 'input[type=file]' );
// Prevent remove click from also triggering input's file selection.
this.disableEvent( evt );
// Quirky, but correct way to clear the file input.
// http://stackoverflow.com/questions/1043957/clearing-input-type-file-using-jquery#answer-13351234
fileInput.wrap( '<form>' ).closest( 'form' ).get( 0 ).reset();
fileInput.unwrap();
this.updateFile( fileInput );
},
updateFile: function ( fileInput ) {
this.model.setFile( fileInput );
this.renderImagePreview();
// TODO: Need to let parent know which model type this is until the parent
// can instantiate the model itself (pending hydration).
this.$el.trigger( 'imageUploadComponent:changed', [ this.model, this.type ] );
},
renderImagePreview: function () {
var self = this;
this.model.getFileUrl().done( function ( url ) {
var backgroundImage,
hasFile = self.model.hasFile(),
// If we have a file set but got a null URL back, it means we're using an old browser
// that doesn't support generating local file URLs via the FileReader API.
isOldBrowser = hasFile && url === null;
if ( url ) {
backgroundImage = 'url(\'' + url + '\')';
} else if ( isOldBrowser ) {
// For old browsers, show a generic preview image.
backgroundImage = 'url(\'' + oldBrowserPreviewImage + '\')';
} else {
backgroundImage = 'none';
}
self.$( '.preview' ).css( 'background-image', backgroundImage );
// If we can't show a preview of the selected image (old browsers), display a change notification message
// to let the user know that the selection "took".
self.$( '.change-notification' ).toggleClass( 'hide', !( hasFile && isOldBrowser ) );
self.toggleActionIcon( !url );
} );
},
toggleActionIcon: function ( toggle ) {
var input = this.$( '.icons' );
input.toggleClass( 'icon-add', toggle );
input.toggleClass( 'remove-image icon-close', !toggle );
}
} );
module.exports.id = 'shared/components/image_upload_view';
If you use <file accept="image/*"/> it should also work on older (Android) browser versions.
<file accept="image/jpeg"/> is only supported on newer browsers.
I don't know from which Chrome version it is supported (chrome://version), but:
Chrome v18: doesn't support it.
Chrome v38: supports it.

Dynamically add UI Elements in CKEditor Dialog

I'm trying to trigger a callback to dynamically populate a CKEditor dialog with checkboxes when the dialog is opened. I've read other solutions that use iframes, but this won't work for me because the dialog needs to be populated based on other elements on the same page.
Here is what I have so far. There are no errors, but the dialog is just empty when it opens. I expect the addContents function to fill in the dialog. I've confirmed that dialog.definition.contents does include the contents and elements that I want, but it's just not filling in the actual dialog. What am I missing?
(function() {
CKEDITOR.plugins.add( 'embeds', {
icons: 'embed',
init: function(editor) {
var self = this,
elements = [];
CKEDITOR.dialog.add('EmbedsDialog', function (instance) {
return {
title : 'Embeds',
minWidth : 550,
minHeight : 200,
contents: [],
onShow: function() {
var dialog = this,
elements = [];
$('#embeds-fields tr').each(function() {
var title = $(this).find('input[type=text]').val(),
url = $(this).find('input[type=url]').val();
if(url != "") {
elements.push({
label : "embed",
title : url,
type : 'checkbox'
});
}
});
dialog.definition.removeContents('embeds');
dialog.definition.addContents({
id : 'embeds',
expand : true,
elements : elements
});
},
}; // return
});
editor.addCommand('Embeds',
new CKEDITOR.dialogCommand('EmbedsDialog', {
allowedContent: 'a[*](*)'
})
);
editor.ui.addButton('Embeds', {
label : 'Embeds',
command : 'Embeds',
toolbar : 'embeds'
});
} // init
}); // add
})(); // closure
Based off of this example, I ended up with this solution, where "main" is the ID of the original content.
CKEDITOR.on('dialogDefinition', function(ev) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
if (dialogName == 'EmbedsDialog') {
var main = dialogDefinition.getContents('main');
$('#embeds-fields tr').each(function() {
var title = $(this).find('input[type=text]').val(),
url = $(this).find('input[type=url]').val();
if(url != "") {
main.add({
type : 'checkbox',
label : title,
});
}
});
}
});

Insert iframe in div from onOk of CKEDITOR.dialog

I use CKEditor and I have got problem for insert iframe in div element in my editor when the user click on the OK button in my Dialog. This does not work. When the user clicks on the button does nothing happen (I have no error message). So he should shut my popup and insert a div containing my iframe inside my editor
Can you help me ?
this is my code
:
CKEDITOR.dialog.add( 'postVideoDialog', function( editor ) {
return {
title : 'Add Video',
minWidth : 400,
minHeight : 80,
contents :
[
{
id : 'video',
label : 'Add Video',
elements :
[
{
type : 'text',
id : 'url',
label : 'Enter a URL from Vimeo :',
validate : function()
{
var url = this.getValue();
var regex1=/^(http:\/\/)vimeo.com\/[0-9]{3,}$/g;
var regex2=/^(http:\/\/)player.vimeo.com\/video\/[0-9]{3,}$/g;
if(regex1.test(url) || regex2.test(url)){
return true
}else{
alert("Url incorrect");
return false;
}
},
required : true,
commit : function( data )
{
data.url = this.getValue();
}
},
]
}
],
onOk : function()
{
var dialog = this,
data = {},
iframe = editor.document.createElement( 'iframe' ),
div = editor.document.createElement('div');
this.commitContent( data );
var regex=/^(http:\/\/)vimeo.com\/[0-9]{3,}$/g; //http://vimeo.com/25329849
if(regex.test(data.url)){
var idVideo = data.url.match(/[0-9]{3,}$/g);
data.url = "http://player.vimeo.com/video/" + idVideo;
}
div.setAttribute('class', 'video');
iframe.setAttribute( 'src', data.url + "?byline=0&portrait=0&color=ffffff");
iframe.setAttribute( 'width', '620' );
iframe.setAttribute( 'width', '349' );
iframe.setAttribute( 'frameborder', '0');
div.insertElement(iframe); //problem is here !
editor.insertElement(div);
}
}; });
Found it..
Read the documentation please: docs.ckeditor.com/#!/api/CKEDITOR.dom.element
Elements don't have a insertElement method. This is a method of the editor try this:
iframe.appendTo(div); //problem is solved here!
editor.insertElement(div);
Instead of your previous code:
div.insertElement(iframe); //problem is here !
editor.insertElement(div);

Adding a custom context menu item to elFinder

I'm using elfinder and I would like to add new functionality by adding a command to the context menu. I found a solution on the github issue tracker of the project but I can't get it to work. Here's what I do:
var elf;
jQuery().ready(function() {
elFinder.prototype._options.commands.push('editimage');
elFinder.prototype._options.contextmenu.files.push('editimage');
elFinder.prototype.i18.en.messages['cmdeditimage'] = 'Edit Image';
elFinder.prototype.i18.de.messages['cmdeditimage'] = 'Bild bearbeiten';
elFinder.prototype.commands.editimage = function() {
this.exec = function(hashes) {
console.log('hallo');
}
}
elf = jQuery('#elfinder').elfinder({
...
//elfinder initialization
The context menu item does not show up, no error message is to be found in the console. I also tried putting editimage under contextmenu->"files" in the init part in case that was overwritten by the initialization.
I found the solution: The examples don't show the fact that you need to have a function called this.getstate inside of the elFinder.prototype.commands.yourcommand function. It shall return 0 when the icon is enabled and -1 when it's disabled.
So the full code for adding your own menu item or context menu item looks like this:
var elf;
jQuery().ready(function() {
elFinder.prototype.i18.en.messages['cmdeditimage'] = 'Edit Image';
elFinder.prototype.i18.de.messages['cmdeditimage'] = 'Bild bearbeiten';
elFinder.prototype._options.commands.push('editimage');
elFinder.prototype.commands.editimage = function() {
this.exec = function(hashes) {
//do whatever
}
this.getstate = function() {
//return 0 to enable, -1 to disable icon access
return 0;
}
}
...
elf = jQuery('#elfinder').elfinder({
lang: 'de', // language (OPTIONAL)
url : '/ext/elfinder-2.0-rc1/php/connector.php', //connector URL
width:'100%',
uiOptions : {
// toolbar configuration
toolbar : [
...
['quicklook', 'editimage'],
/*['copy', 'cut', 'paste'],*/
...
]},
contextmenu : {
...
// current directory file menu
files : [
'getfile', '|','open', 'quicklook', 'editimage', ...
]
}
}).elfinder('instance');
});
Hope this helps someone with the same problem.
Thanks for the answer, great!
One thing that wasn't clear was how the variables pass through.
So, for anyone else who finds this page....
elFinder.prototype.commands.editpres = function() {
this.exec = function(hashes) {
var file = this.files(hashes);
var hash = file[0].hash;
var fm = this.fm;
var url = fm.url(hash);
var scope = angular.element("body").scope();
scope.openEditorEdit(url);
}
// Getstate configured to only light up button if a file is selected.
this.getstate = function() {
var sel = this.files(sel),
cnt = sel.length;
return !this._disabled && cnt ? 0 : -1;
}
}
To get your icon to show up, add the following to your css file:
.elfinder-button-icon-editpres { background:url('../img/icons/editpres.png') no-repeat; }

Categories

Resources