How to handle song removal event in jPlayer with jPlayerPlaylist add-on - jplayer

This is my code:
var myPlaylist = new jPlayerPlaylist({
jPlayer: "#jquery_jplayer_1",
cssSelectorAncestor: "#jp_container_1"
}, [
{
title:"Right Now(Na Na Na)",
artist:"akon",
mp3: "http://7xiaao.com1.z0.glb.clouddn.com/Akon - Right Now(Na Na Na).mp3"
//oga: "/music/",
//poster: "images/m0.jpg"
}
], {
playlistOptions: {
enableRemoveControls: true,
autoPlay: false
},
swfPath: "/res/plugin/jPlayer/dist/jplayer",
supplied: "mp3",
smoothPlayBar: true,
useStateClassSkin: true,
keyEnabled: true,
audioFullScreen: false,
});

jPlayerPlaylist add-on doesn't seem to provide a way to handle song removal event.
The workaround is to handle click events on x yourself, for example:
$('.jp-playlist').on('click', '.jp-playlist-item-remove', function(){
// Determine song index if necessary
var index = $(this).parents('li').index('.jp-playlist li');
// Retrieve song information, if necessary
var song = myPlaylist.playlist[index];
});

Related

FabricJs: Limit grouping to only 1 level deep - Ungroup all objects before grouping

I do not want the user to be able to group a grouped item within another group. My solution to achieve this is basically when the user clicks on the 'Group' button, I am ungrouping everything and then grouping the selection again.
My problem is that when this happens, the items that are ungrouped, become duplicates. One set on the canvas, and one set within the new group.
Here is a video of what I mean...
https://screencast-o-matic.com/watch/cbXQfa2lJg
Here is my code...
export function groupSelectedItems() {
canvas = document.getElementById("c").fabric;
var activegroup = canvas.getActiveGroup();
var objectsInGroup = activegroup.getObjects();
//Ungroup all items first. This will limit grouping to only one level deep.
objectsInGroup.forEach(function(o) {
if(o.type=="group"){
//ungroup items within this group
var items = o.getObjects();
o.destroy();
canvas.remove(o);
items.forEach(function(i) {
canvas.add(i);
activegroup.addWithUpdate(i)
canvas.renderAll();
});
}
});
//Create the group
activegroup.clone(function(newgroup) {
canvas.discardActiveGroup();
objectsInGroup.forEach(function(object) {
canvas.remove(object);
});
canvas.add(newgroup);
newgroup.setControlsVisibility({'tl': false, 'tr': false, 'bl': false, 'br': false, 'ml': false, 'mr': false, 'mb': false, 'mt': false});
}, ['id', 'componentType', 'shape']);
canvas.renderAll();
}
function groupSelectedItems() {
canvas = document.getElementById("c").fabric;
var activegroup = canvas.getActiveGroup();
activegroup.clone(function(newgroup) {
canvas.discardActiveGroup();
activegroup.forEachObject(function(object) {
canvas.remove(object);
});
newgroup.forEachObject(function(object) {
if (object.type == 'group') {
object.destroy();
newgroup.removeWithUpdate(object);
object.forEachObject(function(obj) {
newgroup.addWithUpdate(obj);
})
}
});
canvas.add(newgroup);
}, ['id', 'componentType', 'shape']);
}
Check all the object in group, if any group object is present then ungroup all the object and then add to canvas.

How do you query data with Bookshelf with a lot of relations?

So, I have the following:
var Device = services.bookshelf.Model.extend({
tableName: 'device',
calendar: function() {
return this.belongsToMany(Calendar, 'calendar_device', 'deviceId', 'calendarId');
}
});
var Calendar = module.exports = services.bookshelf.Model.extend({
tableName: 'calendar',
device: function() {
return this.belongsToMany(Device, 'calendar_device', 'calendarId', 'deviceId');
},
schedule: function() {
return this.hasMany(Schedule);
}
});
var Schedule = module.exports = services.bookshelf.Model.extend({
tableName: 'schedule',
calendar: function() {
return this.belongsTo(Calendar);
},
channel: function() {
return this.hasMany(Channel);
}
});
var Channel = module.exports = services.bookshelf.Model.extend({
tableName: 'channel',
schedule: function() {
return this.belongsTo(Schedule);
},
screenItem: function() {
return this.hasMany(ScreenItem);
}
});
And the relations keep going...
How am I supposed to make a query to get, for example, the channels of a device? I don't know if I'm missing something but y I haven't found much information on this...
Device.where('id', id).fetch({withRelated: ['calendar.schedule.channel']}).then(function(devices) {
...
})
What I do is to fetch the Device with 'id' = id specifying the relations of the model that I want to return to (that are declared as it can be seen in the models declaration in my question).
So, saying:
{withRelated: ['calendar']} returns a Device with its Calendars
{withRelated: ['calendar.schedule']} returns a Device with its Calendars with its Schedules
{withRelated: ['calendar.schedule.channel']} returns a Device with its Calendars with its Schedules with its Channels
and so on if there are more related models you want to get.
The response is something like:
{
id: 1,
...,
calendars: [
id: 1,
...,
schedules: [
...
]
]
}

Q promises and mongo db q.all

I'm making calls to a mongodb database - pulling data out... reading it, and then making further requests based on that data. Once all the data has been received, I wish to process it.
I've been using Q.promises library but don't know what I'm doing. I thought that q.all would only trigger once everything has completed? However, my processPlaylist function runs twice. I've commented the code below:
Thanks,
Rob
var PlaylistCollection = require('./models/playlist');
var AssetCollection = require('./models/asset');
var screenID = '############';
var playerData = [];
// array continaing playlistys which have been synced
var alreadySynced = [];
// Process our playlist once downloaded
var processPlaylist = function (playerData) {
console.log('----Processing Playerlist-----')
console.log(playerData);
// DO STUFF
}
// Get playlist by id. Return playlist Data
var getSubLists = function (id) {
return PlaylistCollection.findById(id);
}
// Get sub-playlist function
function getSubListRecursive(id) {
return getSubLists(id).then(function (playlist) {
// store all our returned playlist data into a playlist array
playerData.push(playlist)
// an Array to keep tabs on what we've already pulled down
alreadySynced.push(playlist.id)
// get all our playlist.resources, and only return those which are unique
var playlistResources = _.uniq(playlist.resources, 'rid');
// console.log('Playlist Resources: ', playlistResources)
// console.log(alreadySynced);
var sublists = _.pluck(_.filter(playlistResources, { 'type': 'playlist' }), 'rid');
// remove playlists which have already been synced. We don't want to pull them down twice
sublists = _.difference(sublists, alreadySynced);
// console.log('sublists: ', sublists)
// Get the next playlist and so on...
var dbops = sublists.map(function (sublist) {
// console.log(sublist)
return getSubListRecursive(sublist)
});
q.all(dbops).then(function () {
console.log('All Done - so process the playlist')
return processPlaylist(playerData);
});
})
}
// Trigger the whole process..... grab our first playlist / ScreenID
getSubListRecursive(screenID);
and I get the following output:
----Processing Playerlist-----
[ { _id: 554d1df16ce4c438f8e2225b,
title: 'list 1',
__v: 29,
daily: true,
endTime: '',
startTime: '',
resources:
[ { rid: '55650cebef204ab70302a4d9',
title: 'list 4',
type: 'playlist' },
{ rid: '554d1df16ce4c438f8e2225b',
title: 'list 1',
type: 'playlist' } ] },
{ _id: 55650cebef204ab70302a4d9,
title: 'list 4',
__v: 1,
daily: false,
endTime: '',
startTime: '',
resources:
[ { rid: '55650647ef204ab70302a4d8',
title: 'list 3',
type: 'playlist' } ] } ]
All Done - so process the playlist
----Processing Playerlist-----
[ { _id: 554d1df16ce4c438f8e2225b,
title: 'list 1',
__v: 29,
daily: true,
endTime: '',
startTime: '',
resources:
[ { rid: '55650cebef204ab70302a4d9',
title: 'list 4',
type: 'playlist' },
{ rid: '554d1df16ce4c438f8e2225b',
title: 'list 1',
type: 'playlist' } ] },
{ _id: 55650cebef204ab70302a4d9,
title: 'list 4',
__v: 1,
daily: false,
endTime: '',
startTime: '',
resources:
[ { rid: '55650647ef204ab70302a4d8',
title: 'list 3',
type: 'playlist' } ] },
{ _id: 55650647ef204ab70302a4d8,
title: 'list 3',
__v: 5,
daily: false,
endTime: '',
startTime: '',
resources:
[ { rid: '55650637ef204ab70302a4d7',
title: 'list 2',
type: 'playlist' },
{ rid: '554d1df16ce4c438f8e2225b',
title: 'list 1',
type: 'playlist' },
{ rid: '55650cebef204ab70302a4d9',
title: 'list 4',
type: 'playlist' } ] } ]
EDIT
There were a number of things wrong with what I wrote. I discussed it with a buddy of mine - who pointed out that getSubListRecursive is being invoked recursively several times so the q.all statement is being executed several times...
So I refactored...
// Get sub-playlist function
function getSubListRecursive(id) {
console.log(id)
return getSubLists(id).then(function (playlist) {
if (playlist) {
// store all our returned playlist data into a playlist array
playerData.push(playlist)
// an Array to keep tabs on what we've already pulled down
alreadySynced.push(playlist.id)
// get all our playlist.resources, and only return those which are unique
var playlistResources = _.uniq(playlist.resources, 'rid');
// console.log('Playlist Resources: ', playlistResources)
// console.log(alreadySynced);
var sublists = _.pluck(_.filter(playlistResources, { 'type': 'playlist' }), 'rid');
// remove playlists which have already been synced. We don't want to pull them down twice
sublists = _.difference(sublists, alreadySynced);
// console.log('sublists: ', sublists)
return sublists.map(function (sublist) {
// console.log(sublist)
if (sublists.length > 0) {
return getSubListRecursive(sublist)
} else {
return processPlaylist(playerData);
}
});
} else {
return processPlaylist(playerData);
}
});
}
this works. I'm basically using promises to control the flow here - which probably isn't the best way of doing it? I no longer use an all statement, and ultimately end up with array populated with all the playlist data - which I can manipulate in my processPlaylist function.
However, I've not marked the question as solved, as I'd really like to know how I can do this with Q.all (properly use promises)
Thanks,
Rob
I think you were just confused about when the entire process was finished. You need to wait until the entire recursive promise chain has resolved. I think you could use the original code with a slight change to where processPlaylist() is called:
var PlaylistCollection = require('./models/playlist');
var AssetCollection = require('./models/asset');
var screenID = '############';
var playerData = [];
// array continaing playlistys which have been synced
var alreadySynced = [];
// Process our playlist once downloaded
var processPlaylist = function (playerData) {
console.log('----Processing Playerlist-----')
console.log(playerData);
// DO STUFF
}
// Get playlist by id. Return playlist Data
var getSubLists = function (id) {
return PlaylistCollection.findById(id);
}
// Get sub-playlist function
function getSubListRecursive(id) {
return getSubLists(id).then(function (playlist) {
// store all our returned playlist data into a playlist array
playerData.push(playlist)
// an Array to keep tabs on what we've already pulled down
alreadySynced.push(playlist.id)
// get all our playlist.resources, and only return those which are unique
var playlistResources = _.uniq(playlist.resources, 'rid');
// console.log('Playlist Resources: ', playlistResources)
// console.log(alreadySynced);
var sublists = _.pluck(_.filter(playlistResources, { 'type': 'playlist' }), 'rid');
// remove playlists which have already been synced. We don't want to pull them down twice
sublists = _.difference(sublists, alreadySynced);
// console.log('sublists: ', sublists)
// Get the next playlist and so on...
var dbops = sublists.map(function (sublist) {
// console.log(sublist)
return getSubListRecursive(sublist)
});
return q.all(dbops);
});
}
// Trigger the whole process..... grab our first playlist / ScreenID
getSubListRecursive(screenID).then(function() {
console.log('All Done - so process the playlist')
return processPlaylist(playerData);
});

Are Mongoose virtuals messed up?

Ok, so I have this SchemaOptions, Schema, Constructor and virtual.
var schemaOptions = {
toObject: { virtuals: true }, toJSON: { virtuals: true }
};
var clientSchema = mongoose.Schema ({
company: { type: String, trim: true, required: true, unique: true },
monthly_cost: { type: Number, trim: true, required: true },
sms_cost: { type: Number, trim: true, required: true },
...
}, schemaOptions);
var Client = mongoose.model('Client', clientSchema);
clientSchema.virtual('creationDate').get(function () {
return dateFormat(this._id.getTimestamp(), 'isoDate');
});
Further down I have this route:
(Note the commented code in the for-loop, we will remove this comment later)
app.get('/superadmin', function(req, res) {
Client.find({}, 'company monthly_cost sms_cost', function (err, docs) {
if (err) return handleError(err);
for (var i = 0, tot=docs.length; i < tot; i++) {
// docs[i].creationDate = 'strange variable ' + i;
}
console.log(docs);
res.render('superadmin/index', {
title: 'Superadmin',
docs: docs,
path: req.route.path,
});
});
});
and in my Jade view I have the following pieces of code:
p #{docs};
each client in docs
tr
td #{client.company}
td #{client.creationDate}
...
But here come the problems:
In my route I have: console.log(docs); which output a string similar to 'YYYY-MM-DD', which is expected and good.
Early in my view I have: console.log(docs); which also output the right string: 'YYYY-MM-DD', which is expected and good.
BUT the: #{client.creationDate} in my view doenst output anything!! I dont understand why.
If we now activate the commented line in my for loop like this:
for (var i = 0, tot=docs.length; i < tot; i++) {
docs[i].creationDate = 'strange variable ' + i;
}
... #{client.creationDate} WILL output 'strange variable [0-2]'. But my two earlier console.log(docs) will still output the expected creationDate string.
I dont understand this.. it seems that creationDate is two variables at the same time.
Mongoose Virtuals is driving me crazy, and I really dont understand WHY I'm complaining with them when it anyway seems that can add keyvalues on the fly to a fetched mongoose object. Ok, they dont show up in a console.log... but they are there somehow and I can use them like this: #{client.creationDate} in my view.
This code is out of order:
var Client = mongoose.model('Client', clientSchema);
clientSchema.virtual('creationDate').get(function () {
return dateFormat(this._id.getTimestamp(), 'isoDate');
});
You must completely configure your schema BEFORE you "compile" it to a model. It's not dynamic. Once the model is compiled, further changes to the schema don't take affect.

YUI dialog - what's the equivalent of postdata when using "form" (not ('async")

I'm creating a dialog with YAHOO.widget.Dialog. The dialog is fired off by clicking on a link, and the function the link uses specifies parameters that finally get added to a postdata option like so:
var myDialog = new YAHOO.widget.Dialog("myDialog", {
fixedcenter: true,
// postmethod: "form",
postdata: propString
});
This works just fine, but now I need to do the same thing but using "form" instead of "async" - and there's no postdata for form submissions.
What's the right way to do this?
(YUI 2.7.0)
Here is an example:
var dlg= new YAHOO.widget.Dialog("objectDlg",{
close: false,
draggable: false,
hideaftersubmit: false,
modal: true,
fixedcenter: true,
visible: false,
constraintoviewport: true,
dataURL: saveObjectURL,
buttons: [{'text': 'Save',handler: function(){
var postdata= ...
this.cfg.setProperty("postdata", postdata); //this is important
this.submit();}, 'isDefault': false},
{'text': 'Cancel', handler: function() {this.cancel();}, 'isDefault': true}] });
dlg.render(document.body);
Hope it is helpful

Resources