How to add events to Google Calendar using FullCalendar? - fullcalendar

I'm trying in my FullCalendar add events to my google calendar, followed the example below,
How to add events to Google Calendar using FullCalendar
but does not work me, if anyone knows how to do please help.
this my code
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'/>
<link href='../fullcalendar.css' rel='stylesheet'/>
<link href='../fullcalendar.print.css' rel='stylesheet' media='print'/>
<script src='../lib/moment.min.js'></script>
<script src='../lib/jquery.min.js'></script>
<script src='../fullcalendar.min.js'></script>
<script src='../gcal.js'></script>
<script>
$(document).ready(function () {
$('#calendar').fullCalendar({
selectable: true,
selectHelper: true,
var eventData, title;
select: function(start, end) {
title = prompt('Event Title:');
},
editable: true
}
if (title) {
$('#calendar').fullCalendar('renderEvent',
{
title: title,
start: start,
end: end
},
true // make the event "stick"
);
// Now we push it to Google also :
add_event_gcal(title,start,end);
}
}
$('#calendar').fullCalendar('unselect');
});
});
/****** NOW WE ASK THE EVENT TO BE PUSHED TO GOOGLE **************/
function add_event_gcal(title,start,end) {
alert(title);
// I will create the eventInsert script in a new page, and I name it here :
var url = "php/calendrier_add.php",
data = {'titre_event' :title, 'start' : start, 'end' :end};
// I want to check in the page the result of what happened
$('#gcal_loader').load(url,data,function(responseTxt,statusTxt,xhr){
if(statusTxt == "error") alert("Error: " + xhr.status + ": " + xhr.statusText);
});
}
</script>
<style>
body {
margin: 40px 10px;
padding: 0;
font-family: "Lucida Grande", Helvetica, Arial, Verdana, sans-serif;
font-size: 14px;
}
#loading {
display: none;
position: absolute;
top: 10px;
right: 10px;
}
#calendar {
max-width: 900px;
margin: 0 auto;
}
</style>
</head>
<body>
<div id='loading'>loading...</div>
<div id='calendar'></div>
</body>
</html>
this is file php
<?php
// variables can only be got with $_REQUEST ?
$titre_event = $_REQUEST['titre_event'];
$start = $_REQUEST['start'];
$end = $_REQUEST['end'];
$allday = $_REQUEST['allday'];
/*$where_event = $_REQUEST['where_event'];
$content_event = $_REQUEST['content_event'];*/
/********************************************
GOOGLE API CONNECTION
********************************************/
/************************************************
Make an API request authenticated with a service account.
************************************************/
require_once realpath(dirname(__FILE__) . '/../google/autoload.php');// or wherever autoload.php is located
$path = realpath(dirname(__FILE__) . '/../google/autoload.php');
/************************************************
The name is the email address value provided as part of the service account (not your address!)
cf. : https://console.developers.google.com/project/<your account>
************************************************/
$client_id = '1020443454327******'; // YOUR Client ID
$service_account_name ='102044345*****'; // Email Address in the console account
$key_file_location = realpath(dirname(__FILE__) . '/../google/Mi proyecto-edc74d9206de.p12'); // key.p12 to create in the Google API console
echo "key".$key_file_location;
if (strpos($client_id, "googleusercontent") == false || !strlen($service_account_name) || !strlen($key_file_location)) {
echo "no credentials were set.";
exit;
}
/** We create service access ***/
$client = new Google_Client();
/************************************************
If we have an access token, we can carry on. (Otherwise, we'll get one with the help of an assertion credential.)
Here we have to list the scopes manually. We also supply the service account
************************************************/
if (isset($_SESSION['service_token'])) {
$client->setAccessToken($_SESSION['service_token']);
}
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
$service_account_name,
array('https://www.googleapis.com/auth/calendar'), // ou calendar_readonly
$key
);
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$_SESSION['service_token'] = $client->getAccessToken();
/********************************************
END OF GOOGLE API CONNECTION
********************************************/
/*********** AT LAAAAST, WE PUSH THE EVENT IN GOOGLE CALENDAR ***************/
// Get the API client and construct the service object.
$service = new Google_Service_Calendar($client);
// We get the calendar
$calendarId = 'qv8rv593gn5g8pumu0bid6bco0#group.calendar.google.com'; // or whatever calendar you like where you have editable rights
/************* INSERT ****************/
$event = new Google_Service_Calendar_Event(array(
'summary' => $titre_event,
//'location' => $where_event,
// 'description' => $content_event,
'start' => array(
'dateTime' => $start, //'2015-06-08T15:00:00Z'
'timeZone' => 'Europe/Paris',
),
'end' => array(
'dateTime' => $end,
'timeZone' => 'Europe/Paris',
),
/* in case you need that :
'attendees' => array(
array('email' => 'lpage#example.com'),
array('email' => 'sbrin#example.com'),
),*/
'reminders' => array(
'useDefault' => FALSE,
'overrides' => array(
array('method' => 'email', 'minutes' => 20)
),
),
));
$event = $service->events->insert($calendarId, $event);
printf('Event created: %s', $event->htmlLink);
?>

I found the answer
https://developers.google.com/google-apps/calendar/v3/reference/events/insert#examples
1)
//Global variables to access the calendar
clientId = 'Your cliendID',
scopes = 'https://www.googleapis.com/auth/calendar',
calendarId = 'Your google calendar id',
eventsList = [];
//Autorice the user
checkAuth();
//authorization in google
function checkAuth() {
gapi.auth.authorize(
{
'client_id': clientId,
'scope': scopes,
'immediate': true
}, handleAuthResult);
}
//checks if authorized
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
loadCalendarApi();
} else {
handleAuthClick();
}
}
//request credentials
function handleAuthClick() {
gapi.auth.authorize(
{
client_id: clientId,
scope: scopes,
immediate: false
}, handleAuthResult);
return false;
}
function loadCalendarApi() {
gapi.client.load('calendar', 'v3', makeApiCall);
}`
2)
// Load the API and make an API call. Display the results on the screen.
function makeApiCall() {
requestList = gapi.client.calendar.events.list({
'calendarId': calendarId
});
console.log('--- eventsList ---');
console.log(eventsList);
uiCalendarConfig.calendars['myCalendar'].fullCalendar('removeEventSource', eventsList);
eventsList = [];
// Step 6: Execute the API request
requestList
.then(function (resp) {
if (resp.result.error) {
reportError('Google Calendar API: ' + data.error.message, data.error.errors);
} else if (resp.result.items) {
resp.result.items.forEach(function (entry, index) {
eventsList.push({
id: entry.id,
title: entry.summary,
start: entry.start.dateTime || entry.start.date, // try timed. will fall back to all-day
end: entry.end.dateTime || entry.end.date, // same
url: url,
location: entry.location,
description: entry.description
});
});
}
if (eventsList.length > 0) {
uiCalendarConfig.calendars['myCalendar'].fullCalendar('addEventSource', eventsList, true);
}
}, function (reason) {
console.log('Error: ' + reason.result.error.message);
});
}`
3)
//insert into calendar
function makeRpcRequest(eventData) {
gapi
.client
.load('calendar', 'v3')
.then(function () {
request = gapi.client.calendar.events.insert({
'calendarId': calendarId,
'resource': eventData
});
request.then(function (resp) {
if (resp.result.error) {
reportError('Google Calendar API: ' + data.error.message, data.error.errors);
} else {
makeApiCall();
console.log(resp);
var creator = resp.result.creator.email;
var calendarEntry = resp.result.htmlLink;
console.log('--- Calendar entry successfully created by---');
console.log(creator);
console.log('--- dd ---');
console.log(calendarEntry);
}
}, function (reason) {
console.log('Error: ' + reason.result.error.message);
});
});
}`

Related

Ionic 4, Firebase-x and FCM Push notification with action buttons

I am trying to add action buttons to the push notifications sent via the firebase admin SDK to my Ionic 4 app using the Firebase-X native plugin to handle push notifications. My app is running on android and ios.
Here's my current script that sends me successfully a push notification:
exports.sendDebugPush = functions.pubsub.schedule('* * * * *').onRun((context) => {
let promises: Promise<any>[] = [];
return admin.database().ref('/users/******').once("value")
.then( user => {
let todos = [];
for(let key in user.val().nextActions) {
if(user.val().nextActions[key].active != false) {
let todo = user.val().nextActions[key]
todo['todoid'] = key;
todos.push(todo);
}
}
if(todos.length > 0) {
//currently we pick a random todo, later on the one with the highest priority
//todos.sort((a, b) => (a.priority/1 < b.priority/1) ? 1 : -1);
let randomTodo = todos[Math.floor(Math.random()*todos.length)]
let payload: any = {
notification: {
title: "Gossik",
body: "Hoiiiii " + new Date().toISOString()
},
data: {
title: "Gossik",
body: "Hoiiiii " + new Date().toISOString(),
target: 'todo',
todoid: randomTodo.todoid
}
};
Object.values(user.val().devices).forEach( (device) => {
promises.push(admin.messaging().sendToDevice(String(device), payload));
});
}
return Promise.all(promises)
.then( () => {
console.log('success!');
})
.catch( error => {
console.log('failed :(');
console.log(error);
});
});
});
Of course, without action buttons. And this function handles the push notifications in my app (this.firebase = FirebaseX plugin imported from 'import { FirebaseX } from "#ionic-native/firebase-x/ngx";'):
initPushNotifications() {
this.firebase.getToken().then(token => {
this.db.saveDeviceToken(this.auth.userid, token);
});
this.firebase.onMessageReceived().subscribe(data => {
if(!data.target) {
let title = '';
if(data.title) {
title = data.title;
} else if(data.notification && data.notification.title) {
title = data.notification.title;
} else if(data.aps && data.aps.alert && data.aps.alert.title) {
title = data.aps.alert.title;
}
let body = '';
if(data.body){
body = data.body;
} else if(data.notification && data.notification.body){
body = data.notification.body;
} else if(data.aps && data.aps.alert && data.aps.alert.body){
body = data.aps.alert.body;
}
this.alertCtrl.create({
message: title + ' ' + body,
buttons: [
{
text: "Ok"
}
]
}).then( alert => {
alert.present();
});
} else {
this.goToToDoPage(data.todoid);
}
});
}
It does this also successfully. I achieved to handle the click on the push notification such that it redirects to my To-Do page for this kind of push notification (one with a 'target' property). But now I'd like to add two action buttons 'Start' and 'Skip' on the push notification to start or skip the corresponding to-do. To be clear, I am talking about a background push notification, so the app is not open. The user then gets a standard push notification on his phone and there I'd like two action buttons to take an action without opening the app itself.
I tried various things with the payload to first even show me action buttons, but didn't achieve it. For example, the following is not working for me:
let payload: any = {
notification: {
title: "Gossik",
body: "Hoiiiii " + new Date().toISOString()
},
data: {
title: "Gossik",
body: "Hoiiiii " + new Date().toISOString(),
target: 'todo',
todoid: randomTodo.todoid,
"actions": [
{ "icon": "approve_icon", "title": "APPROVE", "callback": "AppComponent.approve", "foreground": true},
{ "icon": "reject_icon", "title": "REJECT", "callback": "AppComponent.reject", "foreground": true}
]
}
};
Thanks a lot in advance for your help and let me know if something is still unclear. :)

ASP.NET MVC many to many relationship error

This is my controller :
public ActionResult PPKPIChart()
{
return View();
}
public ActionResult PPKPI()
{
var dt = db.Sales
.Where(ol => ol.SaleId != null)
.GroupBy(ol => ol.PPUsers.Where(p => p.Name != null))
.ToList()
.Select(g => new object[] {
g.Key,
g.Count()
}); ;
return Json(dt, JsonRequestBehavior.AllowGet);
}
Here is my view :
#section foot {
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script>
google.charts.load('current', { packages: ['corechart'] });
google.charts.setOnLoadCallback(init);
let dt, opt, cht;
function init() {
dt = new google.visualization.DataTable();
// TODO: Data table columns
dt.addColumn('string', 'Name');
dt.addColumn('number', 'KPI');
let style = { bold: true, italic: false, fontSize: 20, color: 'purple' };
opt = {
title: 'Prepress Personnel KPI',
fontName: 'calibri',
fontSize: 14,
titleTextStyle: { fontSize: 20 },
chartArea: {
width: '80%',
height: '70%',
top: 60,
left: 80
},
// TODO: vAxis, hAxis, legend, animation, orientation
vAxis: {
title: 'KPI',
titleTextStyle: style
},
hAxis: {
title: 'Name',
titleTextStyle: style
},
legend: 'none',
animation: {
duration: 500,
startup: true
},
orientation: 'horizontal',
};
cht = new google.visualization.ColumnChart($('#chart')[0]);
$('#reload').click();
}
$('#reload').click(function (e) {
e.preventDefault();
let url = '/Home/PPKPI';
let param = {};
$.getJSON(url, param, function (json) {
dt.removeRows(0, dt.getNumberOfRows());
dt.addRows(json);
cht.draw(dt, opt);
});
});
$('#toggle').click(function (e) {
e.preventDefault();
// TODO: Toggle orientation (horizontal <--> vertical)
opt.orientation = opt.orientation == 'horizontal' ?
'vertical' : 'horizontal';
[opt.vAxis, opt.hAxis] = [opt.hAxis, opt.vAxis];
cht.draw(dt, opt);
});
</script>
This is my entity framework which have many to many relationships
I want to show a bar chart but because of many to many relationships I cannot do so especially at
GroupBy(ol => ol.PPUsers.Where(p => p.Name != null)) -- > i guess this is the issues behind it.. my query in this line is not working
Basically the relationships look like this :
It seems related PPUsers entities could not be loaded into Sales entity.
You can follow Eagerly Loading approach:
Eager loading is the process whereby a query for one type of entity
also loads related entities as part of the query. Eager loading is
achieved by use of the Include method.
To do so you can use Include to load related entities as follows:
var dt = db.Sales
.Include(s => s.PPUsers)
.Where(ol => ol.SaleId != null)
.GroupBy(ol => ol.PPUsers.Where(p => p.Name != null))
.ToList()
.Select(g => new object[] {
g.Key,
g.Count()
});
Entity Framework supports three ways to load related data - eager loading, lazy loading and explicit loading. Have a look at Loading Related Entities.
`public ActionResult TotalJobAssignedData()<br/>
{
var dt = db.PPUsers
.ToList()
.Select(g => new object[] {
g.Name,
g.Sales.Count()
});
return Json(dt, JsonRequestBehavior.AllowGet);
}

WP Media Insert into Text Editor

I have this code that does open Wordpress Media Uploader upon my custom button click and I have everything working from uploading image to selecting an image ... but how do I send the image/attachment to Text editor
jQuery(document).ready( function($){
var mediaUploader;
$('#_button').on('click',function(e) {
e.preventDefault();
if( mediaUploader ){
mediaUploader.open();
return;
}
mediaUploader = wp.media.frames.file_frame = wp.media( {
title : 'My Custom Library',
multiple : false,
library : { type : 'image' },
button : { text : 'Select Image' },
frame : 'post',
state : 'insert',
} );
mediaUploader.on('insert', function() {
var attachment = mediaUploader.state().get('selection').first().toJSON();
//WHAT TO DO HERE TO SEND THIS TO TEXT EDITOR??????
});
mediaUploader.open();
}); });
Found the answer myself from
https://core.trac.wordpress.org/browser/tags/4.9.8/src/wp-includes/js/media-editor.js#L852
mediaUploader.on('insert', function() {
var embed = mediaUploader.state().get( 'selection' ).first().toJSON();
_.defaults( embed, {
title: embed.url,
linkUrl: '',
align: 'none',
link: 'none'
});
if ( 'none' === embed.link ) {
embed.linkUrl = '';
} else if ( 'file' === embed.link ) {
embed.linkUrl = embed.url;
}
wp.media.editor.insert( wp.media.string.image( embed ) );
});

Youtube-Js-Api / How can I include the request’s response in my actual webpage?

I'm working on an app with both Firebase (web app) and the youtube API. The idea is to let users share their playlists and interact.
1) First, the user must identify himself. This part works very well (firebase part)
2) Then, the user must accept some conditions (the scopes) from the youtube API.
3) The Youtube API return the result of the request.
The issue is that youtube API recreate for every item of the array the HTML structure : HTML > HEAD > BODY. Plus, the response skips my header and display the all thing in a blank page instead of reacting like an include PHP (i know this is javascript but still.. ).
I know the solution rest in the function executerequest but i can't figurate how to do it.
The code of the request is in the middle of the body but for the purpose of my post, i did separate it.
var GoogleAuth;
var SCOPE = 'https://www.googleapis.com/auth/youtube.force-ssl';
function handleClientLoad() {
// Load the API's client and auth2 modules.
// Call the initClient function after the modules load.
gapi.load('client:auth2', initClient);
}
function initClient() {
// Retrieve the discovery document for version 3 of YouTube Data API.
// In practice, your app can retrieve one or more discovery documents.
var discoveryUrl = 'https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest';
// Initialize the gapi.client object, which app uses to make API requests.
// Get API key and client ID from API Console.
// 'scope' field specifies space-delimited list of access scopes.
gapi.client.init({
'apiKey': '...',
'discoveryDocs': [discoveryUrl],
'clientId': '....',
'scope': SCOPE
}).then(function () {
GoogleAuth = gapi.auth2.getAuthInstance();
// Listen for sign-in state changes.
GoogleAuth.isSignedIn.listen(updateSigninStatus);
// Handle initial sign-in state. (Determine if user is already signed in.)
var user = GoogleAuth.currentUser.get();
setSigninStatus();
// Call handleAuthClick function when user clicks on
// "Sign In/Authorize" button.
$('#sign-in-or-out-button').click(function() {
handleAuthClick();
});
$('#revoke-access-button').click(function() {
revokeAccess();
});
});
}
function handleAuthClick() {
if (GoogleAuth.isSignedIn.get()) {
// User is authorized and has clicked 'Sign out' button.
$('#sign-in-or-out-button').html('Sign out');
$('#revoke-access-button').css('display', 'inline-block');
GoogleAuth.signOut();
} else {
// User is not signed in. Start Google auth flow.
GoogleAuth.signIn();
}
}
function revokeAccess() {
GoogleAuth.disconnect();
}
function setSigninStatus(isSignedIn) {
var user = GoogleAuth.currentUser.get();
var isAuthorized = user.hasGrantedScopes(SCOPE);
if (isAuthorized) {
$('#sign-in-or-out-button').html('Sign out');
$('#revoke-access-button').css('display', 'inline-block');
$('#auth-status').html('Connecté ' +
' Granted');
defineRequest();
console.log('connecté');
} else {
$('#roomRed').html('display', 'block');
$('#sign-in-or-out-button').html('Sign In/Authorize');
$('#revoke-access-button').css('display', 'none');
$('#auth-status').html('Déconnecté' +
' Denied');
console.log('déconnecté');
}
// This helper method displays a message on the page.
}
function updateSigninStatus(isSignedIn) {
setSigninStatus();
}
function createResource(properties) {
var resource = {};
var normalizedProps = properties;
for (var p in properties) {
var value = properties[p];
if (p && p.substr(-2, 2) == '[]') {
var adjustedName = p.replace('[]', '');
if (value) {
normalizedProps[adjustedName] = value.split(',');
}
delete normalizedProps[p];
}
}
for (var p in normalizedProps) {
// Leave properties that don't have values out of inserted resource.
if (normalizedProps.hasOwnProperty(p) && normalizedProps[p]) {
var propArray = p.split('.');
var ref = resource;
for (var pa = 0; pa < propArray.length; pa++) {
var key = propArray[pa];
if (pa == propArray.length - 1) {
ref[key] = normalizedProps[p];
} else {
ref = ref[key] = ref[key] || {};
}
}
};
}
return resource;
}
function removeEmptyParams(params) {
for (var p in params) {
if (!params[p] || params[p] == 'undefined') {
delete params[p];
}
}
return params;
}
function executeRequest(request) {
request.execute(function(response) {
console.log(response);
for(var i = 0; i< response.items.length; i++){
console.log(response.items[i].player.embedHtml);
document.write(response.items[i].player.embedHtml);
}
});
}
function buildApiRequest(requestMethod, path, params, properties) {
params = removeEmptyParams(params);
var request;
if (properties) {
var resource = createResource(properties);
request = gapi.client.request({
'body': resource,
'method': requestMethod,
'path': path,
'params': params
});
} else {
request = gapi.client.request({
'method': requestMethod,
'path': path,
'params': params
});
}
executeRequest(request);
}
/***** END BOILERPLATE CODE *****/
function defineRequest() {
// See full sample for buildApiRequest() code, which is not
// specific to a particular youtube or youtube method.
buildApiRequest('GET',
'/youtube/v3/playlists',
{
'mine': 'true',
'maxResults': '25',
'part': 'snippet,contentDetails,player',
'onBehalfOfContentOwner': '',
'onBehalfOfContentOwnerChannel': ''
});
/*
buildApiRequest('GET',
'/youtube/v3/playlistItems',
{
'playlistId': "PLsvlo6Soc2pc2ZlereiehdPRhm0eKjSxI",
'maxResults': '25',
'part': 'snippet,contentDetails'
});
*/
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Mes vidéo </title>
<style>
</style>
</head>
<body>
<button id="sign-in-or-out-button"
style="margin-left: 25px">Sign In/Authorize</button>
<button id="revoke-access-button"
style="display: none; margin-left: 25px">Revoke access</button>
<div id="auth-status" style="display: inline; padding-left: 25px"></div><hr>
<div id="video-container"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script async defer src="https://apis.google.com/js/api.js"
onload="this.onload=function(){};handleClientLoad()"
onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
</body>
</html>
Thank you by advance

Improving FrontEnd Uploads in Wordpress

I want to improve the process of uploading pictures in a Real Estate Website. This website is running WordPress 3.8. The theme offers front end submission with a very simple interface. The user selects the images (one by one) and then clicks to add. Finally when the user submit the listing all the images are uploaded at once. This is the screenshot of how it looks: Original Option: Listing Images.
This is the JQuery Plugin I am currently using,
/*!
* jQuery imagesLoaded plugin v2.1.1
* http://github.com/desandro/imagesloaded
*
* MIT License. by Paul Irish et al.
*/
/*jshint curly: true, eqeqeq: true, noempty: true, strict: true, undef: true, browser: true */
/*global jQuery: false */
;(function($, undefined) {
'use strict';
// blank image data-uri bypasses webkit log warning (thx doug jones)
var BLANK = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==';
$.fn.imagesLoaded = function( callback ) {
var $this = this,
deferred = $.isFunction($.Deferred) ? $.Deferred() : 0,
hasNotify = $.isFunction(deferred.notify),
$images = $this.find('img').add( $this.filter('img') ),
loaded = [],
proper = [],
broken = [];
// Register deferred callbacks
if ($.isPlainObject(callback)) {
$.each(callback, function (key, value) {
if (key === 'callback') {
callback = value;
} else if (deferred) {
deferred[key](value);
}
});
}
function doneLoading() {
var $proper = $(proper),
$broken = $(broken);
if ( deferred ) {
if ( broken.length ) {
deferred.reject( $images, $proper, $broken );
} else {
deferred.resolve( $images );
}
}
if ( $.isFunction( callback ) ) {
callback.call( $this, $images, $proper, $broken );
}
}
function imgLoadedHandler( event ) {
imgLoaded( event.target, event.type === 'error' );
}
function imgLoaded( img, isBroken ) {
// don't proceed if BLANK image, or image is already loaded
if ( img.src === BLANK || $.inArray( img, loaded ) !== -1 ) {
return;
}
// store element in loaded images array
loaded.push( img );
// keep track of broken and properly loaded images
if ( isBroken ) {
broken.push( img );
} else {
proper.push( img );
}
// cache image and its state for future calls
$.data( img, 'imagesLoaded', { isBroken: isBroken, src: img.src } );
// trigger deferred progress method if present
if ( hasNotify ) {
deferred.notifyWith( $(img), [ isBroken, $images, $(proper), $(broken) ] );
}
// call doneLoading and clean listeners if all images are loaded
if ( $images.length === loaded.length ) {
setTimeout( doneLoading );
$images.unbind( '.imagesLoaded', imgLoadedHandler );
}
}
// if no images, trigger immediately
if ( !$images.length ) {
doneLoading();
} else {
$images.bind( 'load.imagesLoaded error.imagesLoaded', imgLoadedHandler )
.each( function( i, el ) {
var src = el.src;
// find out if this image has been already checked for status
// if it was, and src has not changed, call imgLoaded on it
var cached = $.data( el, 'imagesLoaded' );
if ( cached && cached.src === src ) {
imgLoaded( el, cached.isBroken );
return;
}
// if complete is true and browser supports natural sizes, try
// to check for image status manually
if ( el.complete && el.naturalWidth !== undefined ) {
imgLoaded( el, el.naturalWidth === 0 || el.naturalHeight === 0 );
return;
}
// cached images don't fire load sometimes, so we reset src, but only when
// dealing with IE, or image is complete (loaded) and failed manual check
// webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f
if ( el.readyState || el.complete ) {
el.src = BLANK;
el.src = src;
}
});
}
return deferred ? deferred.promise( $this ) : $this;
};
})(jQuery);
My goal is to have a more flexible system, where all the images can be selected at the same time and it starts loading right away. This will speed up the process and improve user experience. Also to arrange them in any order by moving them around. This is an example I found on another website. See screenshot: New Option: Multiple Image Upload
What programing language is good for this development? Any recommendations of where I can find code snippets for this application? Thanks in advance for your help!!
rough draft.....you need jquery and wordpress media js..just watch the js variable names below if there are errors it will be with these...
php in functions file:
if(function_exists( 'wp_enqueue_media' )){
wp_enqueue_media();
}
javascript...add to the page header..wp_enqueue_scripts or to your template (do this first to make sure its working!) you'll need your element called upload_image_button or change accordinely
// Uploading files
var media_uploader;
jQuery('.upload_image_button').live('click', function( event ){
var button = jQuery( this );
// If the media uploader already exists, reopen it.
if ( media_uploader ) {
media_uploader.open();
return;
}
// Create the media uploader.
media_uploader = wp.media.frames.media_uploader = wp.media({
title: button.data( 'uploader-title' ),
// Tell the modal to show only images.
library: {
type: 'image',
query: false
},
button: {
text: button.data( 'uploader-button-text' ),
},
multiple: button.data( 'uploader-allow-multiple' )
});
// Create a callback when the uploader is called
media_uploader.on( 'select', function() {
var selection = media_uploader.state().get('selection'),
input_name = button.data( 'input-name' ),
bucket = $( '#' + input_name + '-thumbnails');
selection.map( function( attachment ) {
attachment = attachment.toJSON();
// console.log(attachment);
bucket.append(function() {
return '<img src="'+attachment.sizes.thumbnail.url+'" width="'+attachment.sizes.thumbnail.width+'" height="'+attachment.sizes.thumbnail.height+'" class="submission_thumb thumbnail" /><input name="'+input_name+'[]" type="hidden" value="'+attachment.id+'" />'
});
});
});
// Open the uploader
media_uploader.open();
});
template file:
<span class="upload_image_button alt_button" data-input-name="images" data-uploader- title="Upload Images" data-uploader-button-text="Add to Submission" data-uploader-allow-multiple="true">Upload</span>
php $_POST return
if ( !empty( $_POST['submission_images'] ) ) {
// do something with the files, set featured img, add to content or save post_meta
}
or..............i came across a plugin that does this a lot better........sorry its in OOP and designed on back end but you can modify for front end! The problem with multi file uploader from WP is it required users to hit "CTRL" + click with no guidance....massive problem on front-end forms...this one you can add more guidance to easily...sorry i havent a frontend sample yet, i have yet to create :)
"Multi File Upload"
e.g.
public function render_meta_box_content($post)
{
// Add an nonce field so we can check for it later.
wp_nonce_field('miu_inner_custom_box', 'miu_inner_custom_box_nonce');
// Use get_post_meta to retrieve an existing value from the database.
$value = get_post_meta($post->ID, '_ad_images', true);
$metabox_content = '<div id="miu_images"></div><input type="button" onClick="addRow()" value="Add Image" class="button" />';
echo $metabox_content;
$images = unserialize($value);
$script = "<script>
itemsCount= 0;";
if (!empty($images))
{
foreach ($images as $image)
{
$script.="addRow('{$image}');";
}
}
$script .="</script>";
echo $script;
}
save function
public function save_image($post_id)
{
/*
* We need to verify this came from the our screen and with proper authorization,
* because save_post can be triggered at other times.
*/
// Check if our nonce is set.
if (!isset($_POST['miu_inner_custom_box_nonce']))
return $post_id;
$nonce = $_POST['miu_inner_custom_box_nonce'];
// Verify that the nonce is valid.
if (!wp_verify_nonce($nonce, 'miu_inner_custom_box'))
return $post_id;
// If this is an autosave, our form has not been submitted,
// so we don't want to do anything.
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
return $post_id;
// Check the user's permissions.
if ('page' == $_POST['post_type'])
{
if (!current_user_can('edit_page', $post_id))
return $post_id;
} else
{
if (!current_user_can('edit_post', $post_id))
return $post_id;
}
/* OK, its safe for us to save the data now. */
// Validate user input.
$posted_images = $_POST['miu_images'];
$miu_images = array();
foreach ($posted_images as $image_url)
{
if(!empty ($image_url))
$miu_images[] = esc_url_raw($image_url);
}
// Update the miu_images meta field.
update_post_meta($post_id, '_ad_images', serialize($miu_images));
}
js file
jQuery(document).ready(function(){
jQuery('.miu-remove').live( "click", function(e) {
e.preventDefault();
var id = jQuery(this).attr("id")
var btn = id.split("-");
var img_id = btn[1];
jQuery("#row-"+img_id ).remove();
});
var formfield;
var img_id;
jQuery('.Image_button').live( "click", function(e) {
e.preventDefault();
var id = jQuery(this).attr("id")
var btn = id.split("-");
img_id = btn[1];
jQuery('html').addClass('Image');
formfield = jQuery('#img-'+img_id).attr('name');
tb_show('', 'media-upload.php?type=image&TB_iframe=true');
return false;
});
window.original_send_to_editor = window.send_to_editor;
window.send_to_editor = function(html){
if (formfield) {
fileurl = jQuery('img',html).attr('src');
jQuery('#img-'+img_id).val(fileurl);
tb_remove();
jQuery('html').removeClass('Image');
} else {
window.original_send_to_editor(html);
}
};
});
function addRow(image_url){
if(typeof(image_url)==='undefined') image_url = "";
itemsCount+=1;
var emptyRowTemplate = '<div id=row-'+itemsCount+'> <input style=\'width:70%\' id=img- '+itemsCount+' type=\'text\' name=\'miu_images['+itemsCount+']\' value=\''+image_url+'\' />'
+'<input type=\'button\' href=\'#\' class=\'Image_button button\' id=\'Image_button- '+itemsCount+'\' value=\'Upload\'>'
+'<input class="miu-remove button" type=\'button\' value=\'Remove\' id=\'remove-'+itemsCount+'\' /></div>';
jQuery('#miu_images').append(emptyRowTemplate);
}

Resources