1
// kate: space-indent on; indent-width 4; replace-tabs on;
4
* Copyright © 2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
6
* Mumble-Django is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This package is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* Documentation for this channel viewer can be found here:
17
* http://mumble-django.org/docs/api/channelviewer.html
20
Ext.namespace('Ext.ux');
22
if( typeof gettext == "undefined" ){
23
// Cope with Django's jsi18n not being available by adding dummy gettext
24
gettext = function( text ){
27
gettext_noop = gettext;
30
Ext.ux.MumbleChannelNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
31
renderElements : function(n, a, targetNode, bulkRender){
32
Ext.ux.MumbleUserNodeUI.superclass.renderElements.call( this, n, a, targetNode, bulkRender );
33
Ext.DomHelper.applyStyles( this.elNode, 'position: relative' );
34
var tpl = new Ext.DomHelper.createTemplate(
35
'<img style="position: absolute; top: 0px; right: {pos}px;" src="{imageurl}/{icon}.png"/>'
38
if( a.chandata.description != "" ) icons.push( "comment_seen" );
40
for( var i = 0; i < icons.length; i++ ){
41
tpl.append( this.elNode, {'imageurl': a.imageurl, 'icon': icons[i], 'pos': pos} );
47
Ext.ux.MumbleUserNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
48
renderElements : function(n, a, targetNode, bulkRender){
49
Ext.ux.MumbleUserNodeUI.superclass.renderElements.call( this, n, a, targetNode, bulkRender );
50
Ext.DomHelper.applyStyles( this.elNode, 'position: relative' );
51
var tpl = new Ext.DomHelper.createTemplate(
52
'<img style="position: absolute; top: 0px; right: {pos}px;" src="{imageurl}/{icon}.png"/>'
55
if( a.userdata.userid != -1 ) icons.push( "authenticated" );
56
if( a.userdata.selfDeaf ) icons.push( "deafened_self" );
57
if( a.userdata.deaf ) icons.push( "deafened_server" );
58
if( a.userdata.selfMute ) icons.push( "muted_self" );
59
if( a.userdata.suppress ) icons.push( "muted_suppressed" );
60
if( a.userdata.mute ) icons.push( "muted_server" );
61
if( a.userdata.comment != "" ) icons.push( "comment_seen" );
62
if( a.userdata.prioritySpeaker ) icons.push( "priority_speaker" );
63
if( a.userdata.recording ) icons.push( "recording" );
65
for( var i = 0; i < icons.length; i++ ){
66
tpl.append( this.elNode, {'imageurl': a.imageurl, 'icon': icons[i], 'pos': pos} );
72
function cmp_channels( left, rite ){
73
// Compare two channels, first by position, and if that equals, by name.
74
if( typeof left.position != "undefined" && typeof rite.position != "undefined" ){
75
byorder = left.position - rite.position;
79
return left.name.localeCompare(rite.name);
82
function cmp_names( left, rite ){
83
return left.name.localeCompare(rite.name);
86
Ext.ux.MumbleChannelViewer = function( config ){
87
Ext.apply( this, config );
90
title: gettext("Channel Viewer"),
91
refreshInterval: 30000,
93
usersAboveChannels: false,
95
enableDD: false, // Users need to enable this explicitly
97
text: gettext("Loading..."),
103
Ext.applyIf( this.listeners, {
104
dragdrop: function( tree, node, targetdd, ev ){
105
if( typeof node.attributes.userdata != "undefined" )
106
tree.fireEvent("moveUser", tree, node.attributes.userdata, targetdd.dragOverData.target.attributes.chandata);
107
else if( typeof node.attributes.chandata != "undefined" )
108
tree.fireEvent("moveChannel", tree, node.attributes.chandata, targetdd.dragOverData.target.attributes.chandata);
113
// This stuff needs the above applied already
114
bbar: [ gettext("Auto-Refresh")+':', {
116
ref: "../cbAutoRefresh",
118
handler: this.setAutoRefresh,
119
checked: (this.refreshInterval > 0),
121
xtype: "numberfield",
123
value: this.refreshInterval / 1000,
124
ref: "../nfAutoRefreshInterval",
128
render: function(c) {
129
Ext.QuickTips.register({
131
text: gettext('Enter the interval in seconds in which the channel viewer should refresh and hit Enter.')
134
specialkey: function( field, ev ){
135
if( ev.getKey() == ev.ENTER ){
136
this.scope.setAutoRefresh(); // lawl
141
}, gettext("Seconds"), '->', {
143
text: gettext("Refresh"),
144
handler: this.refresh,
149
Ext.ux.MumbleChannelViewer.superclass.constructor.call( this );
156
this.autoRefreshId = 0;
157
this.setAutoRefresh();
158
if( this.refreshInterval == 0 )
162
Ext.extend( Ext.ux.MumbleChannelViewer, Ext.tree.TreePanel, {
163
setAutoRefresh: function(){
164
if( this.autoRefreshId != 0 ){
165
clearTimeout( this.autoRefreshId );
167
if( this.cbAutoRefresh.getValue() ){
168
this.refreshInterval = this.nfAutoRefreshInterval.getValue() * 1000;
172
this.refreshInterval = 0;
176
autoRefresh: function(){
178
if( this.refreshInterval > 0 ){
179
this.autoRefreshId = this.autoRefresh.defer( this.refreshInterval, this );
184
var conn = new Ext.data.Connection();
186
url: this.source_url,
188
success: function( resp, opt ){
189
var respdata = Ext.decode( resp.responseText );
195
icon: this.imageurl+'/mumble.16x16.png',
197
chandata: respdata.root,
198
uiProvider: Ext.ux.MumbleChannelNodeUI,
199
imageurl: this.imageurl
202
function populateNode( node, json ){
203
var subchan_users = 0;
204
var popChannels = function(){
205
json.channels.sort(cmp_channels);
206
for( var i = 0; i < json.channels.length; i++ ){
208
text: json.channels[i].name,
209
id: ("channel_" + json.channels[i].id),
214
icon: tree.imageurl+'/channel.png',
216
uiProvider: Ext.ux.MumbleChannelNodeUI,
217
chandata: json.channels[i],
218
imageurl: tree.imageurl
220
node.children.push( child );
221
subchan_users += populateNode( child, json.channels[i] );
224
var popUsers = function(){
225
json.users.sort(cmp_names);
226
for( var i = 0; i < json.users.length; i++ ){
228
text: json.users[i].name,
229
id: ("user_" + json.users[i].session),
234
uiProvider: Ext.ux.MumbleUserNodeUI,
235
userdata: json.users[i],
236
imageurl: tree.imageurl
238
if( json.users[i].idlesecs <= tree.idleInterval )
239
child.icon = tree.imageurl+'/talking_on.png';
241
child.icon = tree.imageurl+'/talking_off.png';
243
node.children.push( child );
246
if( tree.usersAboveChannels ){
254
if( json.id == 0 || json.users.length > 0 || subchan_users )
255
node.expanded = true;
256
return subchan_users + json.users.length;
258
populateNode( root, respdata.root );
259
this.setRootNode( root );
261
failure: function( resp, opt ){
262
if( resp.isTimeout === true )
263
// Ignore, happens from time to time
265
if( this.refreshInterval > 0 )
266
this.cbAutoRefresh.setValue(false);
268
title: gettext("Update error"),
269
msg: gettext("Querying the server failed, so the channel viewer has not been updated."),
270
icon: Ext.MessageBox.ERROR,
271
buttons: Ext.MessageBox.OK
278
Ext.reg( 'mumblechannelviewer', Ext.ux.MumbleChannelViewer );