Wordpress custom image upload - javascript

I need to use custom image field in wp plugin, everything works fine with upload/set function but have problem, when changing image:
Problem:
When i already have a image and need to replace i pick up new image from media library and submit, old one image stay visible so i have two images in view.
I asume that problem is with select function and append part, obviously i'm using wrong logic here, bellow are jquery+html of my code and screenshot of problem:
Problem(two images):
First one should replaced with new selection image (second image)
Two images screenshot
This is my code:
$('#btn-upload-image').on('click', function(e) {
e.preventDefault();
var button = $(this);
var figure = button.siblings("figure");
var custom_uploader = wp.media({
title: 'Insert image',
library: { type : 'image' },
button: { text: 'Use this image' },
id: 'library-' + (Math.random() * 10),
multiple: false
}).on('select', function() {
var attachment = custom_uploader.state().get('selection').first().toJSON();
figure.append( $('<img/>', { 'src': attachment.url }) );
inputImage.val(attachment.url);
inputImageId.val(attachment.id);
})
.open();
});
and html:
<div class="form-group">
<label>Image</label>
<figure></figure>
<button type="button" class="btn btn-primary" id="btn-upload-image">Upload Image</button>
<input type="hidden" name="image" id="input-image" />
<input type="hidden" name="image_id" id="input-image-id" />
</div>

Here's the problem:
figure.append( $('<img/>', { 'src': attachment.url }) );
append inserts content at the end of the target element, maintaining existing content in place. What you want in this case is to replace whatever is in there with new content (the new image), so:
figure.html( $('<img/>', { 'src': attachment.url }) );
html replaces any content that was in the targeted element(s) with the new one.
Hope that helps!

Related

Preload images from more then one file input

I find an methode to preload an image before uploading, but i have more then one file input. And i want for each input file to preload the image. In generell not a big problem but the amount how many file inputs are used on the website is not stable. An user can addan upload image block so he can add 2 or 3 and i want for each he ads the possibility to preload the image.
But my experience dont reach this level what it needs.
So my question is it possible to realilze it?
My code for preload the image for one specific file input is this:
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#blah')
.attr('src', e.target.result)
.height(50);
};
reader.readAsDataURL(input.files[0]);
}
}
If an user adds one image block this is how it looks like:
<div id="divImage-1" class="form-group form-file-upload">
<label id="labelImage-1" for="labelImage2-1">New Picture</label>
<div></div>
<label id="labelImage2-1" for="inputImage-1" class="form-file-upload1">Upload Image</label>
<input id="inputImage-1" type="file" onchange="readURL(this);">
<img id="blah" height="50" alt="Image preview">
</div>
If the user create an second one all IDs ae count to 2 (divImage-2).
Lets assume you this in your HTML
<button class="btn btn-primary" id="addBtn">Add Image Block</button>
<div class="container"></div>
Then, as first step you need to create two global variables:
let imageBlockCout = 0 for counting number of image blocks.
let addedPicSet = nnew Set() a set of pic names which are being used by other blocks.
Then for every click on add button we will add a new block of image with code lets say:
$(
$.parseHTML(
`<div class="row">
<input type="file" multiple id="photos-${imageBlockCount}">
<div id="gallery-${imageBlockCount}" class="row"></div>
</div>`
)
).appendTo(".container");
Now, for every file input added you need to attach an on-change listener:
let currentBlockCount = imageBlockCount;
$("#photos-" + imageBlockCount).on("change", function () {
let input = this;
if (!input.files) {
return;
}
//for every image that has been read by FileReader we show it
//in its own card inside its button gallery
let onFileLoaded = function (event) {
$(
$.parseHTML(
`<div class="col-sm-3">
<div class="card">
<img
class="card-img-top"
src="${event.target.result}">
</div>
</div`
)
).appendTo("#gallery-" + currentBlockCount);
};
//input.files is an array like object, so we convert it to array
Array.from(input.files)
.filter(
//first we filter images which are already in use
(file) => !addedPicSet.has(file.name)
)
.forEach((file) => {
let reader = new FileReader();
//we attach an onLoad listener for each reader
reader.onload = onFileLoaded;
//then we tell the reader object which file to read
reader.readAsDataURL(file);
//add the image name in the set of used image names
addedPicSet.add(file.name);
});
});
I have also made a pen for your help: https://codepen.io/abdullah-shabaz/pen/qBdvZMQ

set data-options html attribute

I have the following HTML
<div id="tabPanelContainer">
<div id="Tab1" data-options="dxItem: { title: 'Tab1' }">
<div id="gridContainer1"></div>
</div>
<div id="Tab2" data-options="dxItem: { title: 'Tab2' }" >
<div id="gridContainer2"></div>
</div>
</div>
I want to create this using js or jquery I have tried the following:
A.
var tabs = $('#tabPanelContainer').data("options","dxItem: { title: "+tabId+" }");
$(tabs).append('<div id='+gridId+'></div>');
B.
var tabs = $('#tabPanelContainer').attr({ 'data-options': 'dxItem: { title: "+tabId+" }' });
$(tabs).append('<div id='+gridId+'></div>');
I have looked at multiple threads on how to do this and tried multiple things but nothing is working....
I have found this: How to set data attributes in HTML elements , and other similar threads but not quite the same or enough to figure it out.
This creates multiple grids but not the tabs. So to be clear if I create the HTML elements on the PHP file (hardcoded) then my tabs load correctly but if I try to dynamically create the tabs based on a for loop my tabs don't get created.
Instead of
You are setting the data attribute of #tabPanelContainer instead of each div element. Use this code instead:
var tabs = $("#tabPanelContainer"); // <div id="tabPanelContainer">
var tab = $("<div>", { id: tabId }); // <div id="Tab1">
tab.attr("data-options", "dxItem: { title: '" + tabId + "' }");
tab.append($("<div>", { id: gridId })); // <div id="gridContainer2">
$(tabs).append(tab);

Select File. Submit. Cannot select file again

I have a form with different fields and with input type="file". I use fileupload jQuery library.
Select file
Call
$('#some_id').fileupload().fileupload(
'send',
{
files: file,
url: widget.options.saveVideoUrl,
}
).success(
//...
(first fileupload called for init)
Try again to select file. Got: No files selected, clear console, etc..
Upd.1
The problem appear in E-commerce framework Magento2 in admin area.
The described form appear in such entity like 'slide-out panel'. It means that there is div block and this block wrapped in aside block using javascript.
<button onclick="jQuery('#new').modal('openModal')" .... >
<span>New</span>
</button>
Here is demo example:
Admin URL: https://iwdagency.com/magento2/admin
Username: admin
Password: admin123
Open Products / Catalog / select any product / click on New category
You should see following panel:
On such panel I've added by php constructor fields:
<div class="admin__field field field-new_video_screenshot " data-ui-id="product-tabs-tab-google-experiment-fieldset-element-form-field-new-video-screenshot">
<label class="label admin__field-label" for="..." data-ui-id="product-tabs-tab-google-experiment-fieldset-element-file-image-label"><span>Preview Image</span></label>
<div class="admin__field-control control">
<input id="...." name="image" data-ui-id="product-tabs-tab-google-experiment-fieldset-element-file-image" value="" title="Preview Image" type="file">
</div>
</div>
Script:
define([
'jquery',
'jquery/ui',
'Magento_Ui/js/modal/modal',
'mage/translate',
'mage/backend/tree-suggest',
'mage/backend/validation'
], function ($) {
'use strict';
$.widget('mage.newDialog', {
_create: function () {
var widget = this;
var newVideoForm = $('#new');
this.element.modal({
type: 'slide',
modalClass: 'mage-new-dialog form-inline',
title: $.mage.__('Create'),
buttons: [{
text: $.mage.__('Create'),
class: 'action-primary',
click: function (e) {
var file = $('#new_screenshot').get(0).files[0];
var result = $('#new_screenshot').fileupload().fileupload(
'send',
{
files: file,
url: widget.options.saveUrl,
}
).success(
function(result, textStatus, jqXHR)
{
var data = JSON.parse(result);
data['url'] = $('#new_url').val();
data['name'] = $('#new_name').val();
data['description'] = $('#new_description').val();
$('#media_gallery_content').trigger('addItem', data);
$('#new').modal('closeModal')
}
);
}
}],
});
}
});
return $.mage.newDialog;
});
I found the problem.
In my case the problem appear after initialization fileUpload library.
When I selected input:file, the library wasn't initialized (read as infected). When I pressed the button, initialization ran and any operations with this input become unavailable.
Solution is following: clone our input before it become infected, than do our operations and at the end replace existing infected input with its healthy copy, created before.

bootstrap popover update content

how do you update the content of bootstrap popover after ajax success, I specifically need to change the value of the input field that I have but once I close the popover and click on it, the original value of the input field shows up? can someone help me out?
<button class="btn btn-primary edit" data-content='<input type="text" id="name" value="some value">
<button class="btn btn-primary save">Save</button>'>Edit</button>
JavaScript:
$('.edit').popover({
placement: 'left',
html: true,
});
$('body').on("click", ".save", function() {
var name = $('#name').val();
$.ajax({
type: "POST",
url: "test.php",
data: {
name: name
},
cache: false,
success: function(response) {
if (response.indexOf("success") != -1) {
$('#name').val(name);
$('.edit').popover('hide').next('.popover').remove();
}
}
});
});
after the data is saved the popover is closed and when I click edit again the old value shows in the input box.
Please find enclosed a working demo of a popover that will be updated with the response from an ajax request.
I've removed your request parameters just for the demo to be able to do the request with mocky.io.
The trick was to use .attr('value', text) instead of .val(text). I'm not exactly sure what's going on here. Maybe someone can explain why that's different.
But with attr it changes the popover and it works.
Another thing that is required is to recreate the popover. I also wanted to destroy the first popover but that doesn't work. So I created the same popover again.
You can also find the same code here at jsFiddle.
There is a bug in the code here at SO. If you get the data from the server and then close the popover, the data will be reset to initial value.
Don't know what's wrong, because it works at jsFiddle with-out that bug.
Update 04.12.2014:
I've improved the code a bit. Now there is a close button in the popover and the data is stored so the data from server is still available when the popover is re-opened.
The bug mentioned above was probably not a SO issue, it was because the data from server was not properly stored. That is also fixed now.
I've also removed some not needed script tags in the demo because tooltip and popover are already included in bootstrap 3.
Update 05.12.2014:
I have another improvement to the code.
The line $(this).parent().find('.close').click(...) is not working like I wanted it. I wanted to add the handler only to the close button of the current popover. But it adds it to all elements with class .close.
Because $(this).parent() is the body element. I think it is better to do it like this:
var current_popover = '#' + $(e.target).attr('aria-describedby');
var $cur_pop = $(current_popover);
$cur_pop.find('.close').click({});
With aria-describedby you'll get the id of the current popover and then you can find the close button of that popover.
$(function () {
var editData = 'new value';
var doPopover = function (item, text) {
$('#name').attr('value',text); // use set attr and not val()
//$('#name').val(text); //<<<< not working here doesn't set DOM properly
var $pop = $(item);
$pop.popover({
placement: 'right',
title: 'edit <a class="close" href="#">×</a>',
trigger: 'click',
html: true,
content: function () {
return $('#popup-content').html();
}
}).on('shown.bs.popover', function(e) {
// console.log('triggered');
// 'aria-describedby' is the id of the current popover
var current_popover = '#' + $(e.target).attr('aria-describedby');
var $cur_pop = $(current_popover);
$cur_pop.find('.close').click(function(){
//console.log('close triggered');
$pop.popover('hide');
});
});
return $pop;
};
// enable popover
doPopover('.edit', editData);
// edit button click handler to show popover
$('.edit').click(function() {
doPopover('.edit', editData);
});
$('body').on("click", ".save", function (e) {
e.preventDefault();
var name = $('#name').val();
//console.log($popover);
$.ajax({
type: "GET", //"POST",
url: "http://www.mocky.io/v2/547f86501713955b0a8ed4da", //"test.php",
data: {
//name: name
},
cache: false,
success: function (response) {
editData = response.data;
doPopover('.edit', editData);
console.log('response: ', editData);
}
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
<button class="btn btn-primary edit" data-html="true" data-toggle="popover" class="edit" data-title="Edit">Edit</button>
<div id="popup-content" class="hide">
<input type="text" id="name" value="some value" />
<button class="btn btn-primary save">Save</button>
</div>

How do I change the default text in dropzone.js?

I am using dropzone.js to upload files. However, I'm having difficulty changing the default text.
I've tried instantiating the dropzone class:
$(document).ready(function(){
$(".foo").dropzone({ dictDefaultMessage: "hello" });
});
With this markup:
<div class="span4">
<form action="http://localhost/post" method="post" accept-charset="utf-8" id="drop3" class="foo" enctype="multipart/form-data"> </form>
</div>
<div class="span4">
<form action="http://localhost/post" method="post" accept-charset="utf-8" id="drop4" class="foo" enctype="multipart/form-data"> </form>
</div>
This certainly gives me the ability to upload files but the default text is blank.
I tested the following:
$(".foo").dropzone();
and I appear to get the same result - no default text. So.. how do I change the default text?
Add an element within your dropzone form as follows:
<div class="dz-message" data-dz-message><span>Your Custom Message</span></div>
You can change all default messages with this:
Dropzone.prototype.defaultOptions.dictDefaultMessage = "Drop files here to upload";
Dropzone.prototype.defaultOptions.dictFallbackMessage = "Your browser does not support drag'n'drop file uploads.";
Dropzone.prototype.defaultOptions.dictFallbackText = "Please use the fallback form below to upload your files like in the olden days.";
Dropzone.prototype.defaultOptions.dictFileTooBig = "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.";
Dropzone.prototype.defaultOptions.dictInvalidFileType = "You can't upload files of this type.";
Dropzone.prototype.defaultOptions.dictResponseError = "Server responded with {{statusCode}} code.";
Dropzone.prototype.defaultOptions.dictCancelUpload = "Cancel upload";
Dropzone.prototype.defaultOptions.dictCancelUploadConfirmation = "Are you sure you want to cancel this upload?";
Dropzone.prototype.defaultOptions.dictRemoveFile = "Remove file";
Dropzone.prototype.defaultOptions.dictMaxFilesExceeded = "You can not upload any more files.";
When creating the dropzone you can set the default message like this.
var dropzone = new Dropzone("form.dropzone", {
dictDefaultMessage: "Put your custom message here"
});
Then
$('div.dz-default.dz-message > span').show(); // Show message span
$('div.dz-default.dz-message').css({'opacity':1, 'background-image': 'none'});
First add an id to your form, say mydz, then add this js:
Dropzone.options.mydz = {
dictDefaultMessage: "your custom message"
};
The whole page (index.php in this case):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="dropzone.js"></script>
<link rel="stylesheet" type="text/css" href="./dropzone.css">
<title></title>
</head>
<body>
<form action="upload.php" class="dropzone" id="mydz"></form>
<script type="text/javascript">
Dropzone.options.mydz = {
dictDefaultMessage: "Put your custom message here"
};
</script>
</body>
</html>
this text is in dropzone's default config, You can overwrite like this:
Dropzone.prototype.defaultOptions.dictDefaultMessage = "Your text";
myDropzonePhotos = new Dropzone('#dropzone-test',
{
url : 'upload_usuario.php?id_usuario=' + id_usuario,
maxFiles : 1,
thumbnailWidth : 1200,
thumbnailHeight : 300,
dictDefaultMessage : 'Change the text here!',
init: function()
{
....
I fiddled with this for hours.
For some reason, these 3 things needed to be done:
My dropzone tags could not be on the same page I was using dropzone on. I had to reference them on the template page
The element you are turning into a dropzone has to have a class of 'dropzone'
You have to add the following to the top of the js file for the page i was working on.
Dropzone.autoDiscover = false;
To Initialize:
var myDropzone = new Dropzone("#id-upload-dropzone", {
url: "/home/Upload",
dictDefaultMessage: 'Drop image here (or click) to capture/upload'
});
Once I had all 3 in order, the dictDefaultMessage option worked.
For localizing Dropzone in Asp.Net Razor Pages I use the below method to avoid decoded chars :
Create HTML element for all messages
<!-- localization elements -->
<div class="modal" aria-hidden="true">
<span id="dictDefaultMessage">#_localizer["Drop files here or click to upload."]</span>
<span id="dictFallbackMessage">#_localizer["Your browser does not support drag'n'drop file uploads."]</span>
<span id="dictFallbackText">#_localizer["Please use the fallback form below to upload your files like in the olden days."]</span>
<span id="dictFileTooBig">#_localizer["File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB."]</span>
<span id="dictInvalidFileType">#_localizer["You can't upload files of this type."]</span>
<span id="dictResponseError">#_localizer["Server responded with {{statusCode}} code."]</span>
<span id="dictCancelUpload">#_localizer["Cancel upload"]</span>
<span id="dictCancelUploadConfirmation">#_localizer["Are you sure you want to cancel this upload?"]</span>
<span id="dictUploadCanceled">#_localizer["Upload canceled."]</span>
<span id="dictRemoveFile">#_localizer["Delete"]</span>
<span id="dictRemoveFileConfirmation">#_localizer["Are you sure you want to delete this file?"]</span>
<span id="dictMaxFilesExceeded">#_localizer["You can not upload any more files."]</span>
<span id="dictFileSizeUnits_TB">#_localizer["TB"]</span>
<span id="dictFileSizeUnits_GB">#_localizer["GB"]</span>
<span id="dictFileSizeUnits_MB">#_localizer["MB"]</span>
<span id="dictFileSizeUnits_KB">#_localizer["KB"]</span>
<span id="dictFileSizeUnits_b">#_localizer["b"]</span>
</div>
Then bind messages to Dropzone element:
<script>
// get elements for localization
with (Dropzone.prototype.defaultOptions) {
dictDefaultMessage = document.getElementById("dictDefaultMessage").innerText;
dictFallbackMessage = document.getElementById("dictFallbackMessage").innerText;
dictFallbackText = document.getElementById("dictFallbackText").innerText;
dictFileTooBig = document.getElementById("dictFileTooBig").innerText;
dictInvalidFileType = document.getElementById("dictInvalidFileType").innerText;
dictResponseError = document.getElementById("dictResponseError").innerText;
dictCancelUpload = document.getElementById("dictCancelUpload").innerText;
dictCancelUploadConfirmation = document.getElementById("dictCancelUploadConfirmation").innerText;
dictUploadCanceled = document.getElementById("dictUploadCanceled").innerText;
dictRemoveFile = document.getElementById("dictRemoveFile").innerText;
dictRemoveFileConfirmation = document.getElementById("dictRemoveFileConfirmation").innerText; // if this is null, the user will not be prompted when deleting file.
dictMaxFilesExceeded = document.getElementById("dictMaxFilesExceeded").innerText;
dictFileSizeUnits = {
tb: document.getElementById("dictFileSizeUnits_TB").innerText,
gb: document.getElementById("dictFileSizeUnits_GB").innerText,
mb: document.getElementById("dictFileSizeUnits_MB").innerText,
kb: document.getElementById("dictFileSizeUnits_KB").innerText,
b: document.getElementById("dictFileSizeUnits_b").innerText
};
};
</script>
for a complete drag-drop file upload sample using Dropzone see this GitHub repository : https://github.com/LazZiya/FileUpload
If you aren't adverse to JQuery, this will hide the default image:
$('form.dropzone').find('div.default.message').css('background-image','none');
and, this will show the default span which you can change to be whatever you want:
$('form.dropzone').find('div.default.message').find('span').show();
$('form.dropzone').find('div.default.message').find('span').empty();
$('form.dropzone').find('div.default.message').find('span').append('Drop files here or click here to upload an image.');
in the css of dropzone look for
.dropzone .dz-default.dz-message
in this class delete
background-image: url("../images/spritemap.png");
the next thing to do is search this class
.dropzone .dz-default.dz-message span {
display: none;
}
and change it to display:block
If you are creating Dropzones Programmatically then you have to set your options like below:
Dropzone.autoDiscover = false;
profilePicture = new Dropzone('#profile-picture', {
url: "/uploadPicture.php",
// if you are using laravel ..., you dont need to put csrf in meta tag
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
dictDefaultMessage: "Your default message Will work 100%",
/other options
paramName: "profile_picture",
addRemoveLinks: true,
maxFilesize: 1,
maxFiles: 10,
dictRemoveFile: "Remove",
});
If you are using it like this, It wont work ...
let myDropzone = new Dropzone("#profile-picture", {
url: "/uploadPicture.php",
// if you are using laravel ..., you dont need to put csrf in meta tag
headers: {
'X-CSRF-TOKEN': "{{ csrf_token() }}"
},
});
myDropzone.options.profilePicture = {
dictDefaultMessage: "This message not gonna work",
paramName: "profile_picture",
};

Categories