diff --git a/htdocs/js/buttoniframewindow.js b/htdocs/js/buttoniframewindow.js
new file mode 100644
index 0000000..c50259d
--- /dev/null
+++ b/htdocs/js/buttoniframewindow.js
@@ -0,0 +1,66 @@
+// kate: space-indent on; indent-width 4; replace-tabs on;
+
+Ext.namespace('Ext.ux');
+
+Ext.ux.IFrameComponent = Ext.extend(Ext.BoxComponent, {
+ // http://www.extjs.com/forum/showthread.php?p=54416#post54416
+ onRender : function(ct, position){
+ this.el = ct.createChild({tag: 'iframe', id: 'iframe-'+ this.id, frameBorder: 0, src: this.url});
+ }
+});
+
+
+Ext.ux.ButtonIframeWindow = function( config ){
+ Ext.apply( this, config );
+
+ Ext.apply( this, {
+ scope: this,
+ enableToggle: true,
+ toggleHandler: function(button, state){
+ if( !this.wnd ){
+ this.wnd = new Ext.Window({
+ title: this.windowTitle || this.text,
+ layout: 'fit',
+ items: new Ext.ux.IFrameComponent({ url: this.url }),
+ width: window.viewsize.width - 200,
+ height: window.viewsize.height - 100,
+ scope: this,
+ buttons: [{
+ text: gettext('Open in new window'),
+ scope: this,
+ handler: function(){
+ window.open( this.url );
+ this.toggle( false );
+ }
+ }],
+ listeners: {
+ beforeclose: function(){
+ this.toggle( false, false );
+ this.wnd = null;
+ }
+ },
+ });
+ this.wnd.ownerButton = this;
+ }
+ if( state ){
+ this.wnd.show();
+ mypos = this.getPosition();
+ mysize = this.getSize();
+ winsize = this.wnd.getSize();
+ this.wnd.setPosition(
+ mypos[0] + mysize.width - winsize.width,
+ mypos[1] - winsize.height
+ );
+ }
+ else
+ this.wnd.hide();
+ }
+ });
+ Ext.ux.ButtonIframeWindow.superclass.constructor.call( this );
+}
+
+Ext.extend( Ext.ux.ButtonIframeWindow, Ext.Button, {
+} );
+
+Ext.reg( 'buttonIframeWindow', Ext.ux.ButtonIframeWindow );
+
diff --git a/htdocs/js/loginout_buttons.js b/htdocs/js/loginout_buttons.js
new file mode 100644
index 0000000..14f1fd3
--- /dev/null
+++ b/htdocs/js/loginout_buttons.js
@@ -0,0 +1,86 @@
+// kate: space-indent on; indent-width 4; replace-tabs on;
+
+Ext.namespace('Ext.ux');
+
+Ext.ux.ButtonLogout = Ext.extend(Ext.Button, {
+ text: gettext('Logout'),
+ handler: function(){
+ Accounts.logout( function(provider, response){
+ if( response.result.success ){
+ window.location.reload();
+ }
+ else{
+ Ext.Msg.show({
+ title: gettext("Login error"),
+ msg: gettext("Unable to log out."),
+ icon: Ext.MessageBox.ERROR,
+ buttons: Ext.MessageBox.OK
+ });
+ }
+ } );
+ }
+});
+
+Ext.ux.ButtonLogin = Ext.extend(Ext.Button, {
+ text: gettext('Login'),
+ enableToggle: true,
+ toggleHandler: function(button, state){
+ if( !this.wnd ){
+ this.wnd = new Ext.Window({
+ title: gettext('Login'),
+ closable: false,
+ width: 300,
+ height: 130,
+ layout: 'fit',
+ items: {
+ layout: 'form',
+ border: false,
+ defaults: { anchor: '-20px' },
+ buttons: [{
+ text: gettext('Submit'),
+ handler: function(){
+ form = this.ownerCt.ownerCt.items.items;
+ Accounts.login(form[0].getValue(), form[1].getValue(),
+ function(provider, response){
+ if( response.result.success ){
+ window.location.reload();
+ }
+ else{
+ Ext.Msg.show({
+ title: gettext("Login error"),
+ msg: gettext("Unable to log in."),
+ icon: Ext.MessageBox.ERROR,
+ buttons: Ext.MessageBox.OK
+ });
+ }
+ });
+ }
+ }],
+ items: [{
+ xtype: "textfield",
+ width: 50,
+ fieldLabel: gettext("User name"),
+ name: "username"
+ }, {
+ xtype: 'textfield',
+ fieldLabel: gettext("Password"),
+ inputType: "password",
+ name: "password"
+ }],
+ },
+ });
+ }
+ if( state ){
+ this.wnd.show();
+ mypos = this.getPosition();
+ mysize = this.getSize();
+ winsize = this.wnd.getSize();
+ this.wnd.setPosition(
+ mypos[0] + mysize.width - winsize.width,
+ mypos[1] - winsize.height
+ );
+ }
+ else
+ this.wnd.hide();
+ }
+});
diff --git a/htdocs/js/logviewer.js b/htdocs/js/logviewer.js
new file mode 100644
index 0000000..4fa616c
--- /dev/null
+++ b/htdocs/js/logviewer.js
@@ -0,0 +1,67 @@
+// kate: space-indent on; indent-width 4; replace-tabs on;
+
+Ext.namespace('Ext.ux');
+
+Ext.ux.LogViewerPanel = function( config ){
+ Ext.apply( this, config );
+
+ Ext.applyIf( this, {
+ xtype: 'grid',
+ title: gettext('Log messages'),
+ colModel: new Ext.grid.ColumnModel([{
+ header: gettext('Timestamp'),
+ dataIndex: 'timestamp',
+ width: 100,
+ renderer: function( value ){
+ return new Date(value*1000).format( "Y-m-d H:i:s" );
+ }
+ }, {
+ header: gettext('Log entry'),
+ width: 500,
+ dataIndex: 'txt'
+ }]),
+ bbar: [{
+ text: gettext('Filter') + ':'
+ }, {
+ xtype: 'textfield',
+ name: 'filter',
+ listeners: {
+ render: function(c) {
+ Ext.QuickTips.register({
+ target: c.getEl(),
+ text: gettext('Enter a string to filter the logs by and press Enter. To display all log entries, empty this field.')
+ });
+ },
+ specialkey: function( field, ev ){
+ if( ev.getKey() == ev.ENTER ){
+ field.ownerCt.ownerCt.store.baseParams.filter = field.getValue();
+ field.ownerCt.ownerCt.store.reload();
+ }
+ }
+ }
+ }, '-', {
+ iconCls: 'x-tbar-loading',
+ tooltip: gettext('Refresh'),
+ handler: function(){
+ this.ownerCt.ownerCt.store.reload();
+ }
+ }],
+ store: new Ext.data.DirectStore({
+ baseParams: {'server': this.server, 'start': 0, 'limit': 100, 'filter': ''},
+ directFn: Mumble.log,
+ paramOrder: ['server', 'start', 'limit', 'filter'],
+ root: 'data',
+ fields: ['timestamp', 'txt'],
+ autoLoad: true,
+ remoteSort: false
+ }),
+ viewConfig: { forceFit: true }
+ });
+ Ext.ux.LogViewerPanel.superclass.constructor.call( this );
+}
+
+Ext.extend( Ext.ux.LogViewerPanel, Ext.grid.EditorGridPanel, {
+} );
+
+Ext.reg( 'logViewerPanel', Ext.ux.LogViewerPanel );
+
diff --git a/htdocs/js/usereditor.js b/htdocs/js/usereditor.js
index e25de86..015ac76 100644
--- a/htdocs/js/usereditor.js
+++ b/htdocs/js/usereditor.js
@@ -1,8 +1,4 @@
-// {% load mumble_extras %}
-// {% load i18n %}
-// {% comment %}
-// kate: space-indent on; indent-width 2; replace-tabs on;
-// {% endcomment %}
+// kate: space-indent on; indent-width 2; replace-tabs on;
Ext.namespace('Ext.ux');
@@ -19,7 +15,7 @@ Ext.ux.UserEditorPanel = function( config ){
]);
userAdminStore = new Ext.data.DirectStore({
- baseParams: { server: 1 },
+ baseParams: { server: this.server },
directFn: Mumble.users,
fields: userRecord,
autoLoad: true,
diff --git a/pyweb/mumble/templates/mumble/mumble.html b/pyweb/mumble/templates/mumble/mumble.html
index 0af4725..d348f78 100644
--- a/pyweb/mumble/templates/mumble/mumble.html
+++ b/pyweb/mumble/templates/mumble/mumble.html
@@ -13,147 +13,35 @@
+
+
+