Fixed player not re-initializing

This commit is contained in:
Fergal Moran
2013-06-17 12:16:12 +01:00
parent dffab51dd6
commit f3f5bbb62a
24 changed files with 698 additions and 138 deletions

0
manage.py Executable file → Normal file
View File

View File

@@ -1,5 +1,6 @@
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.db.models import Count
import humanize
from tastypie import fields
from tastypie.authentication import Authentication
@@ -15,7 +16,7 @@ from spa.models import UserProfile, Mix
class UserProfileResource(BackboneCompatibleResource):
class Meta:
queryset = UserProfile.objects.all()
queryset = UserProfile.manager.annotate(fcount=Count('followers'))
resource_name = 'profile'
include_resource_uri = False
include_absolute_url = False
@@ -102,7 +103,8 @@ class UserResource(BackboneCompatibleResource):
def prepend_urls(self):
return [
url(r"^(?P<resource_name>%s)/(?P<userprofile__slug>[\w\d_.-]+)/favourites%s$" % (self._meta.resource_name, trailing_slash()),
url(r"^(?P<resource_name>%s)/(?P<userprofile__slug>[\w\d_.-]+)/favourites%s$" % (
self._meta.resource_name, trailing_slash()),
self.wrap_view('get_user_favourites'), name="api_get_user_favourites"),
url(r"^(?P<resource_name>%s)/(?P<pk>\d+)/$" % self._meta.resource_name,
self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
@@ -110,9 +112,13 @@ class UserResource(BackboneCompatibleResource):
self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
]
def get_object_list(self, request):
return super(UserResource, self).get_object_list(request)
def get_user_favourites(self, request, **kwargs):
try:
obj = self.cached_obj_get(bundle=self.build_bundle(request=request), **self.remove_api_resource_names(kwargs))
obj = self.cached_obj_get(bundle=self.build_bundle(request=request),
**self.remove_api_resource_names(kwargs))
except ObjectDoesNotExist:
return HttpGone()
except MultipleObjectsReturned:

View File

@@ -21,10 +21,16 @@ def avatar_name(instance, filename):
return generate_save_file_name(str(instance.id), 'avatars', filename)
class UserProfileManager(models.Manager):
def get_query_set(self):
return super(UserProfileManager, self).get_query_set().annotate(fcount=models.Count('followers'))
class UserProfile(_BaseModel):
class Meta:
app_label = 'spa'
manager = UserProfileManager()
ACTIVITY_SHARE_LIKES = 1
ACTIVITY_SHARE_FAVOURITES = 2
ACTIVITY_SHARE_COMMENTS = 4

View File

@@ -16,7 +16,7 @@ body {
padding-top: 45px;
padding-bottom: 40px;
padding-right: 32px;
background: url('../img/bg.gif');
/*background: url('../img/bg.gif');*/
}
/* IE/Chrome image fix */
@@ -480,4 +480,9 @@ div.event-content td {
width: 98%;
text-align: center;
margin-bottom: 8px;
}
dss-datatable{
cellpadding: 0;
cellspacing: 0;
border: 0;
}

View File

@@ -65,8 +65,6 @@ define ['backbone', 'marionette', 'app.lib/router', 'app.lib/panningRegion', 'ap
)
true
console.warn("Creating event aggregator shim")
window._eventAggregator = _.extend({}, Backbone.Events);
App.headerRegion.show(new HeaderView());
sidebarView = new SidebarView();
App.sidebarRegion.show(sidebarView)

View File

@@ -1,8 +1,8 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.3.3
(function() {
define(['backbone', 'marionette', 'app.lib/router', 'app.lib/panningRegion', 'app.lib/audioController', 'views/header', 'views/sidebar/sidebarView', 'models/mix/mixCollection'], function(Backbone, Marionette, DssRouter, PanningRegion, AudioController, HeaderView, SidebarView, MixCollection) {
var App, sidebarView;
Marionette.Region.prototype.open = function(view) {
this.$el.hide();
this.$el.html(view.el);
@@ -36,7 +36,6 @@
});
App.vent.on("routing:started", function() {
var enablePushState, pushState;
console.log("App(vent): routing:started");
enablePushState = true;
pushState = !!(enablePushState && window.history && window.history.pushState);
@@ -62,7 +61,6 @@
console.log("App: gobbling links");
$(document).on("click", "a[href]:not([data-bypass])", function(evt) {
var href, root;
href = {
prop: $(this).prop("href"),
attr: $(this).attr("href")
@@ -76,8 +74,6 @@
});
return true;
});
console.warn("Creating event aggregator shim");
window._eventAggregator = _.extend({}, Backbone.Events);
App.headerRegion.show(new HeaderView());
sidebarView = new SidebarView();
App.sidebarRegion.show(sidebarView);

View File

@@ -10,6 +10,7 @@ requirejs.config({
'backbone.wreqr': 'libs/backbone/backbone.wreqr',
ich: 'libs/ICanHaz',
underscore: 'libs/backbone/underscore',
backgrid: 'libs/backgrid/backgrid',
text: 'libs/text',
templates: '/templates',
app: 'app/appv2',

View File

@@ -1,7 +1,8 @@
define(['backbone'], function (Backbone) {
return Backbone.Collection.extend({
parse: function (response) {
this.recent_meta = response.meta || {};
this.meta = response.meta || {};
this.page_count = this.meta.total_count / this.meta.limit;
return response.objects || response;
}
});

View File

@@ -12,7 +12,7 @@ define(['backbone'], function (Backbone) {
var TastypieCollection = Backbone.Collection.extend({
parse: function (response) {
this.recent_meta = response.meta || {};
this.meta = response.meta || {};
return response.objects || response;
}
});

View File

@@ -4,5 +4,41 @@ define ['backbone', 'models/user/userItem', 'app.lib/backbone.dss.model.collecti
model: UserItem
url:com.podnoms.settings.urlRoot + "user/"
_columns: [
property: 'toponymName'
label: 'Name'
sortable: true
,
property: 'uploads'
label: 'Uploads'
sortable: true
,
property: 'likes'
label: 'Likes'
sortable: true
,
property: 'favourites'
label: 'Favourites'
sortable: true
,
property: 'followers'
label: 'Followers'
sortable: true
,
property: 'following'
label: 'Following'
sortable: true
,
property: 'lastseen'
label: 'Last seen'
sortable: true
]
columns: ->
@_columns
data: ->
@toJSON
UserCollection

View File

@@ -18,6 +18,46 @@
UserCollection.prototype.url = com.podnoms.settings.urlRoot + "user/";
UserCollection.prototype._columns = [
{
property: 'toponymName',
label: 'Name',
sortable: true
}, {
property: 'uploads',
label: 'Uploads',
sortable: true
}, {
property: 'likes',
label: 'Likes',
sortable: true
}, {
property: 'favourites',
label: 'Favourites',
sortable: true
}, {
property: 'followers',
label: 'Followers',
sortable: true
}, {
property: 'following',
label: 'Following',
sortable: true
}, {
property: 'lastseen',
label: 'Last seen',
sortable: true
}
];
UserCollection.prototype.columns = function() {
return this._columns;
};
UserCollection.prototype.data = function() {
return this.toJSON;
};
return UserCollection;
})(DssCollection);

View File

@@ -6,8 +6,8 @@
Code provided under the BSD License:
*/
define(['underscore', 'backbone', 'text!/tpl/HeaderView'],
function (_, Backbone, Template) {
define(['underscore', 'backbone', 'vent', 'text!/tpl/HeaderView'],
function (_, Backbone, vent, Template) {
return Backbone.View.extend({
template: _.template(Template),
events: {
@@ -17,12 +17,8 @@ define(['underscore', 'backbone', 'text!/tpl/HeaderView'],
},
initialize: function () {
this.render();
_.bindAll(this, "trackChanged");
_.bindAll(this, "trackPlaying");
_.bindAll(this, "trackPaused");
window._eventAggregator.bind("track_changed", this.trackChanged);
_eventAggregator.bind("track_playing", this.trackPlaying);
_eventAggregator.bind("track_paused", this.trackPaused);
this.listenTo(vent, 'mix:play', this.trackPlaying);
this.listenTo(vent, 'mix:pause', this.trackPaused);
},
login: function () {
com.podnoms.utils.modal('tpl/LoginView');

View File

@@ -34,13 +34,16 @@ define ['moment', 'app', 'vent', 'marionette', 'models/comment/commentCollection
totalDurationText = if totalDuration.hours() != 0 then moment(totalDuration).format("HH:mm:ss") else moment(totalDuration).format("mm:ss");
$('#player-duration-' + id, this.el).text(totalDurationText)
#check if we're currently playing
if com.podnoms.player.isPlayingId @model.id
com.podnoms.settings.setupPlayerWrapper @model.get('id')
@renderGenres()
return
onDomRefresh: ->
#check if we're currently playing
if com.podnoms.player.isPlayingId @model.id
com.podnoms.settings.setupPlayerWrapper @model.get('id'), com.podnoms.player.getStreamUrl(), @el
true
renderGenres: =>
el = @el
$.each @model.get("genre-list"), (data) ->

View File

@@ -1,26 +1,22 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.6.2
(function() {
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['moment', 'app', 'vent', 'marionette', 'models/comment/commentCollection', 'views/comment/commentListView', 'text!/tpl/MixListItemView'], function(moment, App, vent, Marionette, CommentsCollection, CommentsListView, Template) {
var MixItemView;
MixItemView = (function(_super) {
var MixItemView, _ref;
MixItemView = (function(_super) {
__extends(MixItemView, _super);
function MixItemView() {
this.doStart = __bind(this.doStart, this);
this.renderComments = __bind(this.renderComments, this);
this.renderGenres = __bind(this.renderGenres, this);
this.onRender = __bind(this.onRender, this);
this.initialize = __bind(this.initialize, this);
return MixItemView.__super__.constructor.apply(this, arguments);
this.initialize = __bind(this.initialize, this); _ref = MixItemView.__super__.constructor.apply(this, arguments);
return _ref;
}
MixItemView.prototype.template = _.template(Template);
@@ -54,20 +50,26 @@
MixItemView.prototype.onRender = function() {
var id, totalDuration, totalDurationText;
id = this.model.get('id');
if (this.model.get('duration')) {
totalDuration = moment.duration(this.model.get('duration'), "seconds");
totalDurationText = totalDuration.hours() !== 0 ? moment(totalDuration).format("HH:mm:ss") : moment(totalDuration).format("mm:ss");
$('#player-duration-' + id, this.el).text(totalDurationText);
}
if (com.podnoms.player.isPlayingId(this.model.id)) {
com.podnoms.settings.setupPlayerWrapper(this.model.get('id'));
}
this.renderGenres();
};
MixItemView.prototype.onDomRefresh = function() {
if (com.podnoms.player.isPlayingId(this.model.id)) {
com.podnoms.settings.setupPlayerWrapper(this.model.get('id'), com.podnoms.player.getStreamUrl(), this.el);
}
return true;
};
MixItemView.prototype.renderGenres = function() {
var el;
el = this.el;
$.each(this.model.get("genre-list"), function(data) {
$("#genre-list", el).append('<a href="/mixes/' + this.slug + '" class="dss-tag-button">' + this.text + '</a>');
@@ -78,6 +80,7 @@
MixItemView.prototype.renderComments = function() {
var comments;
comments = new CommentsCollection();
comments.url = this.model.get("resource_uri") + "comments/";
comments.mix_id = this.model.id;
@@ -85,6 +88,7 @@
comments.fetch({
success: function(data) {
var content;
console.log(data);
content = new CommentsListView({
collection: comments
@@ -128,6 +132,7 @@
MixItemView.prototype.mixFavourite = function() {
var app;
console.log("MixItemView: favouriteMix");
app = require('app');
app.vent.trigger("mix:favourite", this.model);
@@ -136,6 +141,7 @@
MixItemView.prototype.mixLike = function() {
var app;
console.log("MixItemView: likeMix");
app = require('app');
app.vent.trigger("mix:like", this.model);
@@ -144,6 +150,7 @@
MixItemView.prototype.mixShare = function(e) {
var app, mode;
console.log("MixItemView: shareMix");
mode = $(e.currentTarget).data("mode");
console.log("MixItemView: " + mode);

View File

@@ -1,26 +1,22 @@
define ['marionette', 'models/user/userCollection', 'views/user/userItemView', 'text!/tpl/UserListView', 'libs/jquery.dataTables'],
define ['marionette', 'models/user/userCollection', 'views/user/userItemView', 'text!/tpl/UserListView', 'libs/bootstrap/bootpag'],
(Marionette, UserCollection, UserItemView, Template) ->
class UserListView extends Marionette.CompositeView
template: _.template(Template)
tagName: "table"
className: "table table-hover"
itemView: UserItemView
initialize: ->
itemViewContainer: "tbody"
initialize: =>
console.log "UserListView: initialize"
@collection = new UserCollection()
@collection.fetch(
data: @options
success: =>
console.log("UserListView: Collection fetched")
$(@el).dataTable sDom: "<'row'<'span6'l><'span6'f>r>t<'row'<'span6'i><'span6'p>>"
console.log(@collection)
$("#page-selection").bootpag(total: @collection.page_count).on "page", (event, num) -> # page number here
$("#content").html "Insert content" # some ajax content loading...
return
)
return
onRender: ->
console.log("UserListView: onRender")
true
UserListView

View File

@@ -1,27 +1,26 @@
// Generated by CoffeeScript 1.6.2
(function() {
var __hasProp = {}.hasOwnProperty,
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['marionette', 'models/user/userCollection', 'views/user/userItemView', 'text!/tpl/UserListView', 'libs/jquery.dataTables'], function(Marionette, UserCollection, UserItemView, Template) {
define(['marionette', 'models/user/userCollection', 'views/user/userItemView', 'text!/tpl/UserListView', 'libs/bootstrap/bootpag'], function(Marionette, UserCollection, UserItemView, Template) {
var UserListView, _ref;
UserListView = (function(_super) {
__extends(UserListView, _super);
function UserListView() {
_ref = UserListView.__super__.constructor.apply(this, arguments);
this.initialize = __bind(this.initialize, this); _ref = UserListView.__super__.constructor.apply(this, arguments);
return _ref;
}
UserListView.prototype.template = _.template(Template);
UserListView.prototype.tagName = "table";
UserListView.prototype.className = "table table-hover";
UserListView.prototype.itemView = UserItemView;
UserListView.prototype.itemViewContainer = "tbody";
UserListView.prototype.initialize = function() {
var _this = this;
@@ -31,18 +30,16 @@
data: this.options,
success: function() {
console.log("UserListView: Collection fetched");
$(_this.el).dataTable({
sDom: "<'row'<'span6'l><'span6'f>r>t<'row'<'span6'i><'span6'p>>"
console.log(_this.collection);
$("#page-selection").bootpag({
total: _this.collection.page_count
}).on("page", function(event, num) {
return $("#content").html("Insert content");
});
}
});
};
UserListView.prototype.onRender = function() {
console.log("UserListView: onRender");
return true;
};
return UserListView;
})(Marionette.CompositeView);

View File

@@ -127,6 +127,9 @@ com.podnoms.player = {
isPlayingId: function (id) {
return this.isPlaying() && this.currentSound.sID == "com.podnoms.player-" + id;
},
getStreamUrl: function(){
return this.currentPath;
},
drawTimeline: function (el, boundingEl, duration) {
/*
Assume 10 markers

View File

@@ -1,58 +0,0 @@
Backbone.Validate = function (model, changedAttributes) {
return (function () {
this.errors = {};
this.attributes = _.clone(model.attributes);
_.extend(this.attributes, changedAttributes);
_.each(model.validates, function (value, rule) {
this.validators[rule](value);
});
this.validators = {
required: function (fields) {
_.each(fields, function (field) {
if (_.isEmpty(this.attributes[field]) === true) {
this.addError(field, I18n.t('errors.form.required'));
}
});
}
};
this.addError = function (field, message) {
if (_.isUndefined(this.errors[field])) {
this.errors[field] = [];
}
this.errors[field].push(message);
};
return this.errors;
})();
};
window.TastypieModel = Backbone.Model.extend({
base_url: function () {
var temp_url = Backbone.Model.prototype.url.call(this);
return (temp_url.charAt(temp_url.length - 1) == '/' ? temp_url : temp_url + '/');
},
url: function () {
return this.base_url();
}
});
window.TastypieCollection = Backbone.Collection.extend({
parse: function (response) {
this.recent_meta = response.meta || {};
return response.objects || response;
}
});
window.DSSModel = window.TastypieModel.extend({
addError: function (field, message) {
if (_.isUndefined(this.errors[field])) {
this.errors[field] = [];
}
this.errors[field].push(message);
return field;
}
});

View File

@@ -0,0 +1,19 @@
/*
bootpag - jQuery plugin for dynamic pagination
Copyright (c) 2013 botmonster@7items.com
Licensed under the MIT license:
http://www.opensource.org/licenses/mit-license.php
Project home:
http://botmonster.com/jquery-bootpag/
Version: 1.0.4
*/
(function(f,q){f.fn.bootpag=function(p){function k(e,b){var c,d=0==a.maxVisible?1:a.maxVisible,n=1==a.maxVisible?0:1,m=Math.floor((b-1)/d)*d,g=e.find("li");a.page=b=0>b?0:b>a.total?a.total:b;g.removeClass("disabled");c=1>b-1?1:a.leaps&&b-1>=a.maxVisible?Math.floor((b-1)/d)*d:b-1;g.first().toggleClass("disabled",1===b).attr("data-lp",c).find("a").attr("href",h(c));n=1==a.maxVisible?0:1;c=b+1>a.total?a.total:a.leaps&&b+1<a.total-a.maxVisible?m+a.maxVisible+n:b+1;g.last().toggleClass("disabled",b===
a.total).attr("data-lp",c).find("a").attr("href",h(c));d=g.filter("[data-lp="+b+"]");if(!d.not(".next,.prev").length){var k=b<=m?-a.maxVisible:0;g.not(".next,.prev").each(function(b){c=b+1+m+k;f(this).attr("data-lp",c).toggle(c<=a.total).find("a").html(c).attr("href",h(c))});d=g.filter("[data-lp="+b+"]")}d.addClass("disabled");l.trigger("page",b);l.data("settings",a)}function h(e){return a.href.replace(a.hrefVariable,e)}var l=this,a=f.extend({total:0,page:1,maxVisible:null,leaps:!0,href:"javascript:void(0);",
hrefVariable:"{{number}}",next:"&raquo;",prev:"&laquo;"},l.data("settings")||{},p||{});if(0>=a.total)return this;!f.isNumeric(a.maxVisible)&&!a.maxVisible&&(a.maxVisible=a.total);l.data("settings",a);return this.each(function(){var e,b,c=f(this),d=['<ul class="bootpag">'];a.prev&&d.push('<li data-lp="1" class="prev"><a href="'+h(1)+'">'+a.prev+"</a></li>");for(b=1;b<=Math.min(a.total,a.maxVisible);b++)d.push('<li data-lp="'+b+'"><a href="'+h(b)+'">'+b+"</a></li>");a.next&&(b=a.leaps&&a.total>a.maxVisible?
Math.min(a.maxVisible+1,a.total):2,d.push('<li data-lp="'+b+'" class="next"><a href="'+h(b)+'">'+a.next+"</a></li>"));d.push("</ul>");c.find("ul.bootpag").remove();c.append(d.join("")).addClass("pagination");e=c.find("ul.bootpag");c.find("li").click(function(){var a=f(this);a.hasClass("disabled")||k(e,parseInt(a.attr("data-lp"),10))});k(e,a.page)})}})(jQuery,window);

View File

@@ -0,0 +1,336 @@
/*
* Fuel UX Datagrid
* https://github.com/ExactTarget/fuelux
*
* Copyright (c) 2012 ExactTarget
* Licensed under the MIT license.
*/
define(['require','jquery'],function(require) {
var $ = require('jquery');
// Relates to thead .sorted styles in datagrid.less
var SORTED_HEADER_OFFSET = 22;
// DATAGRID CONSTRUCTOR AND PROTOTYPE
var Datagrid = function (element, options) {
this.$element = $(element);
this.$thead = this.$element.find('thead');
this.$tfoot = this.$element.find('tfoot');
this.$footer = this.$element.find('tfoot th');
this.$footerchildren = this.$footer.children().show().css('visibility', 'hidden');
this.$topheader = this.$element.find('thead th');
this.$searchcontrol = this.$element.find('.datagrid-search');
this.$filtercontrol = this.$element.find('.filter');
this.$pagesize = this.$element.find('.grid-pagesize');
this.$pageinput = this.$element.find('.grid-pager input');
this.$pagedropdown = this.$element.find('.grid-pager .dropdown-menu');
this.$prevpagebtn = this.$element.find('.grid-prevpage');
this.$nextpagebtn = this.$element.find('.grid-nextpage');
this.$pageslabel = this.$element.find('.grid-pages');
this.$countlabel = this.$element.find('.grid-count');
this.$startlabel = this.$element.find('.grid-start');
this.$endlabel = this.$element.find('.grid-end');
this.$tbody = $('<tbody>').insertAfter(this.$thead);
this.$colheader = $('<tr>').appendTo(this.$thead);
this.options = $.extend(true, {}, $.fn.datagrid.defaults, options);
// Shim until v3 -- account for FuelUX select or native select for page size:
if (this.$pagesize.hasClass('select')) {
this.options.dataOptions.pageSize = parseInt(this.$pagesize.select('selectedItem').value, 10);
} else {
this.options.dataOptions.pageSize = parseInt(this.$pagesize.val(), 10);
}
// Shim until v3 -- account for older search class:
if (this.$searchcontrol.length <= 0) {
this.$searchcontrol = this.$element.find('.search');
}
this.columns = this.options.dataSource.columns();
this.$nextpagebtn.on('click', $.proxy(this.next, this));
this.$prevpagebtn.on('click', $.proxy(this.previous, this));
this.$searchcontrol.on('searched cleared', $.proxy(this.searchChanged, this));
this.$filtercontrol.on('changed', $.proxy(this.filterChanged, this));
this.$colheader.on('click', 'th', $.proxy(this.headerClicked, this));
if(this.$pagesize.hasClass('select')) {
this.$pagesize.on('changed', $.proxy(this.pagesizeChanged, this));
} else {
this.$pagesize.on('change', $.proxy(this.pagesizeChanged, this));
}
this.$pageinput.on('change', $.proxy(this.pageChanged, this));
this.renderColumns();
if (this.options.stretchHeight) this.initStretchHeight();
this.renderData();
};
Datagrid.prototype = {
constructor: Datagrid,
renderColumns: function () {
var self = this;
this.$footer.attr('colspan', this.columns.length);
this.$topheader.attr('colspan', this.columns.length);
var colHTML = '';
$.each(this.columns, function (index, column) {
colHTML += '<th data-property="' + column.property + '"';
if (column.sortable) colHTML += ' class="sortable"';
colHTML += '>' + column.label + '</th>';
});
self.$colheader.append(colHTML);
},
updateColumns: function ($target, direction) {
this._updateColumns(this.$colheader, $target, direction);
if (this.$sizingHeader) {
this._updateColumns(this.$sizingHeader, this.$sizingHeader.find('th').eq($target.index()), direction);
}
},
_updateColumns: function ($header, $target, direction) {
var className = (direction === 'asc') ? 'icon-chevron-up' : 'icon-chevron-down';
$header.find('i.datagrid-sort').remove();
$header.find('th').removeClass('sorted');
$('<i>').addClass(className + ' datagrid-sort').appendTo($target);
$target.addClass('sorted');
},
updatePageDropdown: function (data) {
var pageHTML = '';
for (var i = 1; i <= data.pages; i++) {
pageHTML += '<li><a>' + i + '</a></li>';
}
this.$pagedropdown.html(pageHTML);
},
updatePageButtons: function (data) {
if (data.page === 1) {
this.$prevpagebtn.attr('disabled', 'disabled');
} else {
this.$prevpagebtn.removeAttr('disabled');
}
if (data.page === data.pages) {
this.$nextpagebtn.attr('disabled', 'disabled');
} else {
this.$nextpagebtn.removeAttr('disabled');
}
},
renderData: function () {
var self = this;
this.$tbody.html(this.placeholderRowHTML(this.options.loadingHTML));
this.options.dataSource.data(this.options.dataOptions, function (data) {
var itemdesc = (data.count === 1) ? self.options.itemText : self.options.itemsText;
var rowHTML = '';
self.$footerchildren.css('visibility', function () {
return (data.count > 0) ? 'visible' : 'hidden';
});
self.$pageinput.val(data.page);
self.$pageslabel.text(data.pages);
self.$countlabel.text(data.count + ' ' + itemdesc);
self.$startlabel.text(data.start);
self.$endlabel.text(data.end);
self.updatePageDropdown(data);
self.updatePageButtons(data);
$.each(data.data, function (index, row) {
rowHTML += '<tr>';
$.each(self.columns, function (index, column) {
rowHTML += '<td>' + row[column.property] + '</td>';
});
rowHTML += '</tr>';
});
if (!rowHTML) rowHTML = self.placeholderRowHTML('0 ' + self.options.itemsText);
self.$tbody.html(rowHTML);
self.stretchHeight();
self.$element.trigger('loaded');
});
},
placeholderRowHTML: function (content) {
return '<tr><td style="text-align:center;padding:20px;border-bottom:none;" colspan="' +
this.columns.length + '">' + content + '</td></tr>';
},
headerClicked: function (e) {
var $target = $(e.target);
if (!$target.hasClass('sortable')) return;
var direction = this.options.dataOptions.sortDirection;
var sort = this.options.dataOptions.sortProperty;
var property = $target.data('property');
if (sort === property) {
this.options.dataOptions.sortDirection = (direction === 'asc') ? 'desc' : 'asc';
} else {
this.options.dataOptions.sortDirection = 'asc';
this.options.dataOptions.sortProperty = property;
}
this.options.dataOptions.pageIndex = 0;
this.updateColumns($target, this.options.dataOptions.sortDirection);
this.renderData();
},
pagesizeChanged: function (e, pageSize) {
if(pageSize) {
this.options.dataOptions.pageSize = parseInt(pageSize.value, 10);
} else {
this.options.dataOptions.pageSize = parseInt($(e.target).val(), 10);
}
this.options.dataOptions.pageIndex = 0;
this.renderData();
},
pageChanged: function (e) {
var pageRequested = parseInt($(e.target).val(), 10);
pageRequested = (isNaN(pageRequested)) ? 1 : pageRequested;
var maxPages = this.$pageslabel.text();
this.options.dataOptions.pageIndex =
(pageRequested > maxPages) ? maxPages - 1 : pageRequested - 1;
this.renderData();
},
searchChanged: function (e, search) {
this.options.dataOptions.search = search;
this.options.dataOptions.pageIndex = 0;
this.renderData();
},
filterChanged: function (e, filter) {
this.options.dataOptions.filter = filter;
this.options.dataOptions.pageIndex = 0;
this.renderData();
},
previous: function () {
this.options.dataOptions.pageIndex--;
this.renderData();
},
next: function () {
this.options.dataOptions.pageIndex++;
this.renderData();
},
reload: function () {
this.options.dataOptions.pageIndex = 0;
this.renderData();
},
initStretchHeight: function () {
this.$gridContainer = this.$element.parent();
this.$element.wrap('<div class="datagrid-stretch-wrapper">');
this.$stretchWrapper = this.$element.parent();
this.$headerTable = $('<table>').attr('class', this.$element.attr('class'));
this.$footerTable = this.$headerTable.clone();
this.$headerTable.prependTo(this.$gridContainer).addClass('datagrid-stretch-header');
this.$thead.detach().appendTo(this.$headerTable);
this.$sizingHeader = this.$thead.clone();
this.$sizingHeader.find('tr:first').remove();
this.$footerTable.appendTo(this.$gridContainer).addClass('datagrid-stretch-footer');
this.$tfoot.detach().appendTo(this.$footerTable);
},
stretchHeight: function () {
if (!this.$gridContainer) return;
this.setColumnWidths();
var targetHeight = this.$gridContainer.height();
var headerHeight = this.$headerTable.outerHeight();
var footerHeight = this.$footerTable.outerHeight();
var overhead = headerHeight + footerHeight;
this.$stretchWrapper.height(targetHeight - overhead);
},
setColumnWidths: function () {
if (!this.$sizingHeader) return;
this.$element.prepend(this.$sizingHeader);
var $sizingCells = this.$sizingHeader.find('th');
var columnCount = $sizingCells.length;
function matchSizingCellWidth(i, el) {
if (i === columnCount - 1) return;
var $el = $(el);
var $sourceCell = $sizingCells.eq(i);
var width = $sourceCell.width();
// TD needs extra width to match sorted column header
if ($sourceCell.hasClass('sorted') && $el.prop('tagName') === 'TD') width = width + SORTED_HEADER_OFFSET;
$el.width(width);
}
this.$colheader.find('th').each(matchSizingCellWidth);
this.$tbody.find('tr:first > td').each(matchSizingCellWidth);
this.$sizingHeader.detach();
}
};
// DATAGRID PLUGIN DEFINITION
$.fn.datagrid = function (option) {
return this.each(function () {
var $this = $(this);
var data = $this.data('datagrid');
var options = typeof option === 'object' && option;
if (!data) $this.data('datagrid', (data = new Datagrid(this, options)));
if (typeof option === 'string') data[option]();
});
};
$.fn.datagrid.defaults = {
dataOptions: { pageIndex: 0, pageSize: 10 },
loadingHTML: '<div class="progress progress-striped active" style="width:50%;margin:auto;"><div class="bar" style="width:100%;"></div></div>',
itemsText: 'items',
itemText: 'item'
};
$.fn.datagrid.Constructor = Datagrid;
});

View File

@@ -0,0 +1,146 @@
/* Set the defaults for DataTables initialisation */
$.extend(true, $.fn.dataTable.defaults, {
"sDom": "<'row-fluid'<'span6'l><'span6'f>r>t<'row-fluid'<'span6'i><'span6'p>>",
"sPaginationType": "bootstrap",
"oLanguage": {
"sLengthMenu": "_MENU_ records per page"
}
});
/* Default class modification */
$.extend($.fn.dataTableExt.oStdClasses, {
"sWrapper": "dataTables_wrapper form-inline"
});
/* API method to get paging information */
$.fn.dataTableExt.oApi.fnPagingInfo = function (oSettings) {
return {
"iStart": oSettings._iDisplayStart,
"iEnd": oSettings.fnDisplayEnd(),
"iLength": oSettings._iDisplayLength,
"iTotal": oSettings.fnRecordsTotal(),
"iFilteredTotal": oSettings.fnRecordsDisplay(),
"iPage": oSettings._iDisplayLength === -1 ?
0 : Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength),
"iTotalPages": oSettings._iDisplayLength === -1 ?
0 : Math.ceil(oSettings.fnRecordsDisplay() / oSettings._iDisplayLength)
};
};
/* Bootstrap style pagination control */
$.extend($.fn.dataTableExt.oPagination, {
"bootstrap": {
"fnInit": function (oSettings, nPaging, fnDraw) {
var oLang = oSettings.oLanguage.oPaginate;
var fnClickHandler = function (e) {
e.preventDefault();
if (oSettings.oApi._fnPageChange(oSettings, e.data.action)) {
fnDraw(oSettings);
}
};
$(nPaging).addClass('pagination').append(
'<ul>' +
'<li class="prev disabled"><a href="#">&larr; ' + oLang.sPrevious + '</a></li>' +
'<li class="next disabled"><a href="#">' + oLang.sNext + ' &rarr; </a></li>' +
'</ul>'
);
var els = $('a', nPaging);
$(els[0]).bind('click.DT', { action: "previous" }, fnClickHandler);
$(els[1]).bind('click.DT', { action: "next" }, fnClickHandler);
},
"fnUpdate": function (oSettings, fnDraw) {
var iListLength = 5;
var oPaging = oSettings.oInstance.fnPagingInfo();
var an = oSettings.aanFeatures.p;
var i, ien, j, sClass, iStart, iEnd, iHalf = Math.floor(iListLength / 2);
if (oPaging.iTotalPages < iListLength) {
iStart = 1;
iEnd = oPaging.iTotalPages;
}
else if (oPaging.iPage <= iHalf) {
iStart = 1;
iEnd = iListLength;
} else if (oPaging.iPage >= (oPaging.iTotalPages - iHalf)) {
iStart = oPaging.iTotalPages - iListLength + 1;
iEnd = oPaging.iTotalPages;
} else {
iStart = oPaging.iPage - iHalf + 1;
iEnd = iStart + iListLength - 1;
}
for (i = 0, ien = an.length; i < ien; i++) {
// Remove the middle elements
$('li:gt(0)', an[i]).filter(':not(:last)').remove();
// Add the new list items and their event handlers
for (j = iStart; j <= iEnd; j++) {
sClass = (j == oPaging.iPage + 1) ? 'class="active"' : '';
$('<li ' + sClass + '><a href="#">' + j + '</a></li>')
.insertBefore($('li:last', an[i])[0])
.bind('click', function (e) {
e.preventDefault();
oSettings._iDisplayStart = (parseInt($('a', this).text(), 10) - 1) * oPaging.iLength;
fnDraw(oSettings);
});
}
// Add / remove disabled classes from the static elements
if (oPaging.iPage === 0) {
$('li:first', an[i]).addClass('disabled');
} else {
$('li:first', an[i]).removeClass('disabled');
}
if (oPaging.iPage === oPaging.iTotalPages - 1 || oPaging.iTotalPages === 0) {
$('li:last', an[i]).addClass('disabled');
} else {
$('li:last', an[i]).removeClass('disabled');
}
}
}
}
});
/*
* TableTools Bootstrap compatibility
* Required TableTools 2.1+
*/
if ($.fn.DataTable.TableTools) {
// Set the classes that TableTools uses to something suitable for Bootstrap
$.extend(true, $.fn.DataTable.TableTools.classes, {
"container": "DTTT btn-group",
"buttons": {
"normal": "btn",
"disabled": "disabled"
},
"collection": {
"container": "DTTT_dropdown dropdown-menu",
"buttons": {
"normal": "",
"disabled": "disabled"
}
},
"print": {
"info": "DTTT_print_info modal"
},
"select": {
"row": "active"
}
});
// Have the collection use a bootstrap compatible dropdown
$.extend(true, $.fn.DataTable.TableTools.DEFAULTS.oTags, {
"collection": {
"container": "ul",
"button": "li",
"liner": "a"
}
});
}

View File

@@ -16,15 +16,15 @@ com.podnoms.settings = {
urlArgs: {{ IS_DEBUG }} ? "" : "bust="+ (new Date()).getTime(),
currentUser: {{ CURRENT_USER_ID }},
/** simple helper to take an api JSON object and initialise a player item */
setupPlayerWrapper: function (id, stream_url) {
setupPlayerWrapper: function (id, stream_url, el) {
com.podnoms.player.setupPlayer({
id: id,
boundingEl: $('#mix-container-' + id),
waveFormEl: $('#waveform-' + id),
playHeadEl: $('#playhead-player-' + id),
loadingEl: $('#progress-player-' + id),
seekHeadEl: $('#player-seekhead'),
playButtonEl: $('#play-pause-button-small-' + id),
boundingEl: $('#mix-container-' + id, el),
waveFormEl: $('#waveform-' + id, el),
playHeadEl: $('#playhead-player-' + id, el),
loadingEl: $('#progress-player-' + id, el),
seekHeadEl: $('#player-seekhead', el),
playButtonEl: $('#play-pause-button-small-' + id, el),
url: stream_url || ""
});
}

View File

@@ -1,12 +1,23 @@
<thead>
<tr class="warning">
<th>Name</th>
<th>Uploads</th>
<th>Likes</th>
<th>Favourites</th>
<th>Followers</th>
<th>Following</th>
<th>Last seen</th>
</tr>
</thead>
<tbody></tbody>
<div class="span6">
<div id="page-selection"></div>
</div>
<div class="span6 pull-right">
<div id="MySearch" class="input-append search">
<input type="text" class="input-medium" placeholder="Search">
<button type="button" class="btn"><i class="icon-search"></i></button>
</div>
</div>
<table id="user-table" class="table table-striped table-bordered datagrid">
<thead>
<tr class="warning">
<th>Name</th>
<th>Uploads</th>
<th>Likes</th>
<th>Favourites</th>
<th>Followers</th>
<th>Following</th>
<th>Last seen</th>
</tr>
</thead>
<tbody></tbody>
</table>

View File

@@ -0,0 +1,15 @@
<div id="page-selection">Pagination goes here</div>
<table class="table table-striped table-bordered" id="user-table">
<thead>
<tr class="warning">
<th>Name</th>
<th>Uploads</th>
<th>Likes</th>
<th>Favourites</th>
<th>Followers</th>
<th>Following</th>
<th>Last seen</th>
</tr>
</thead>
<tbody></tbody>
</table>